diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..a843a85 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,60 @@ +name: Build + +on: + push: + branches: + - "**" + pull_request: + +permissions: + contents: read + +jobs: + gradle: + name: Gradle + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@v7 + + - name: Set up Java + uses: actions/setup-java@v5 + with: + distribution: temurin + java-version: 25 + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v6 + + - name: Build and test + run: ./gradlew build + + website: + name: Website + runs-on: ubuntu-latest + defaults: + run: + working-directory: docs + + steps: + - name: Check out repository + uses: actions/checkout@v7 + + - name: Set up pnpm + uses: pnpm/action-setup@v6 + with: + version: 11.10.0 + + - name: Set up Node.js + uses: actions/setup-node@v6 + with: + node-version: 24 + cache: pnpm + cache-dependency-path: docs/pnpm-lock.yaml + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build website + run: pnpm build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..340d922 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,21 @@ +name: Release + +on: + push: + tags: + - "**" + +permissions: + contents: read + +jobs: + release: + name: Release + if: ${{ vars.RELEASES_ENABLED == 'true' }} + runs-on: ubuntu-latest + + steps: + - name: Release is not configured + run: | + echo "Configure the release steps before setting RELEASES_ENABLED to true." + exit 1 diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml new file mode 100644 index 0000000..627154d --- /dev/null +++ b/.github/workflows/website.yml @@ -0,0 +1,45 @@ +name: Website release + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: github-pages + cancel-in-progress: true + +jobs: + build: + name: Build website + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@v7 + + - name: Build and upload website + uses: withastro/action@v6 + with: + path: docs + node-version: 24 + package-manager: pnpm@11.10.0 + + deploy: + name: Deploy website + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v5 diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..6f88dcd --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +twaddle.asorda.net \ No newline at end of file diff --git a/README.md b/README.md index 06d10f5..c5c43bc 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,6 @@ Tools and twaddle is built around a few strong opinions: - Server features should be isolated enough to develop, test, and replace independently. - The framework should make it easier to build actual projects, not just quick prototypes. -## What it provides -While the exact feature set depends on the current implementation, the intended shape of the framework is: -- A DI context for building and testing server software based on koin -- A structured bootstrap and lifecycle model for different elements -- Shared conventions for configuration, service registration, and cross-module communication. -- An opinionated developer experience on top of Minestom's low-level primitives. - - ## Design principles ### Pluggable by default @@ -51,14 +43,6 @@ mod loader; it is trying to give Minestom-based servers a better composition mod The framework should scale from isolated experiments to larger projects with multiple systems, contributors, and deployment environments. -## Getting started -Until the public API settles, the best way to approach Tools and twaddle is as a framework for experimentation: -1. Start with a small Minestom project. -2. Add Tools and twaddle as the organizational layer around it. -3. Keep gameplay logic in isolated modules. -4. Expect breaking changes while the architecture matures. -5. Use the project to validate patterns before committing to long-term APIs. - ## Who this is for Tools and twaddle is a good fit if you: - Build directly against Minestom. diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..6240da8 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,21 @@ +# build output +dist/ +# generated types +.astro/ + +# dependencies +node_modules/ + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store diff --git a/docs/AGENTS.md b/docs/AGENTS.md new file mode 100644 index 0000000..c5ff429 --- /dev/null +++ b/docs/AGENTS.md @@ -0,0 +1,22 @@ +## Development + +When starting the dev server, use background mode: + +``` +astro dev --background +``` + +Manage the background server with `astro dev stop`, `astro dev status`, and `astro dev logs`. + +## Documentation + +Full documentation: https://docs.astro.build + +Consult these guides before working on related tasks: + +- [Adding pages, dynamic routes, or middleware](https://docs.astro.build/en/guides/routing/) +- [Working with Astro components](https://docs.astro.build/en/basics/astro-components/) +- [Using React, Vue, Svelte, or other framework components](https://docs.astro.build/en/guides/framework-components/) +- [Adding or managing content](https://docs.astro.build/en/guides/content-collections/) +- [Adding styles or using Tailwind](https://docs.astro.build/en/guides/styling/) +- [Supporting multiple languages](https://docs.astro.build/en/guides/internationalization/) diff --git a/docs/CLAUDE.md b/docs/CLAUDE.md new file mode 120000 index 0000000..47dc3e3 --- /dev/null +++ b/docs/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs new file mode 100644 index 0000000..37301ec --- /dev/null +++ b/docs/astro.config.mjs @@ -0,0 +1,57 @@ +// @ts-check +import { defineConfig } from 'astro/config'; +import starlight from '@astrojs/starlight'; + +// https://astro.build/config +export default defineConfig({ + site: 'https://twaddle.asorda.net', + integrations: [ + starlight({ + title: 'Tools & twaddle', + description: 'An opinionated toolkit for building modular Minestom servers.', + favicon: '/favicon.png', + logo: { + src: './src/assets/icon.png', + alt: 'Tools & twaddle toolbox', + }, + customCss: ['./src/styles/custom.css'], + social: [ + { + icon: 'github', + label: 'GitHub', + href: 'https://github.com/everbuild-org/tools-and-twaddle', + }, + ], + sidebar: [ + { + label: 'Start here', + items: [ + { label: 'Overview', slug: 'index' }, + { label: 'Getting started', slug: 'getting-started' }, + ], + }, + { + label: 'Concepts', + items: [ + { label: 'Architecture', slug: 'concepts/architecture' }, + { label: 'Capability classification', slug: 'concepts/classification' }, + ], + }, + { + label: 'Foundation', + items: [ + { label: 'Core runtime', slug: 'core/runtime' }, + { label: 'Structured logging', slug: 'core/logging' }, + { label: 'Minestom helpers', slug: 'core/minestom-helpers' }, + ], + }, + { + label: 'Modules', + items: [ + { label: 'Inventory transfer rules', slug: 'modules/inventory-transfer' }, + ], + }, + ], + }), + ], +}); diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 0000000..a7bedc2 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,17 @@ +{ + "name": "docs", + "type": "module", + "version": "0.0.1", + "scripts": { + "dev": "astro dev", + "start": "astro dev", + "build": "astro build", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "@astrojs/starlight": "^0.41.6", + "astro": "^7.0.2", + "sharp": "^0.34.5" + } +} \ No newline at end of file diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml new file mode 100644 index 0000000..8b639ab --- /dev/null +++ b/docs/pnpm-lock.yaml @@ -0,0 +1,4356 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@astrojs/starlight': + specifier: ^0.41.6 + version: 0.41.6(@astrojs/markdown-remark@7.2.2)(astro@7.1.6(@astrojs/markdown-remark@7.2.2)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(@types/node@24.13.3)) + astro: + specifier: ^7.0.2 + version: 7.1.6(@astrojs/markdown-remark@7.2.2)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(@types/node@24.13.3) + sharp: + specifier: ^0.34.5 + version: 0.34.5 + +packages: + + '@astrojs/compiler-binding-darwin-arm64@0.3.2': + resolution: {integrity: sha512-MM8tn8CSimcfytaOla4b6acN8mKWiL/rlAA1fpT3/Wl7dNGSE4y8FjTN/zJVNnb63CsLWG5zZwCt01TXtDKh9g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@astrojs/compiler-binding-darwin-x64@0.3.2': + resolution: {integrity: sha512-2lXOlzf8xb7jLomRsf/aswh61/NnGusynB2OwFkK6k4pmOtpfXMYnG0PLfXrEvxXYj69NdCnmUYXtHDd+JOOag==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@astrojs/compiler-binding-linux-arm64-gnu@0.3.2': + resolution: {integrity: sha512-BmU3kWj7qnLrd4vzm49zFEPJ5oFnn1tCT4Vt9hZbqdU5Cmb8GZl7fn6VFsnNfe7B18a2gIFtVzbLINtYl5kBjQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@astrojs/compiler-binding-linux-arm64-musl@0.3.2': + resolution: {integrity: sha512-f0heT9ZZEseSu5bHCeb80eL2DH07ArE6U9xi1WT/PEusNjzPmEr3GJsjG1tRLo5VYUUYX7h3ScaqGmGrMOVGmw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@astrojs/compiler-binding-linux-x64-gnu@0.3.2': + resolution: {integrity: sha512-M8fOUt0itRpqiGyoEA/ij184s8O+hqbCz3+YozRusOOM3osgGljpDThhbKAJjqh82wOo6FioQ4w8PBvU1XMD5Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@astrojs/compiler-binding-linux-x64-musl@0.3.2': + resolution: {integrity: sha512-/Kebk8sO6HnLeSd691JkaAPfN7CqR9/KEXmWvyNPkaKNGmj8rTZ/lf2uXtnPu92Lan84UrKdIKVPy1fSo2encQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@astrojs/compiler-binding-wasm32-wasi@0.3.2': + resolution: {integrity: sha512-pUA6xbcOSB7DhfzIArB8BCAkFfAIqriiR7zl5zOStd6oU2G0kIKj+GUdGnyXyhfiv881Hffyk5tC0mR18sDjDw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@astrojs/compiler-binding-win32-arm64-msvc@0.3.2': + resolution: {integrity: sha512-ESruf+6Qkl1trHUFxI6GSf6t52j8yN2kCNSzMWdzt7V/T09tFHrYzrVaJQohb2C9bJUH76pNvX6Zb51+xCQc9Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@astrojs/compiler-binding-win32-x64-msvc@0.3.2': + resolution: {integrity: sha512-wzzVrEbOwbsLWOdEbocskjMRx2aZPxJ7ZbmL+jnpBamFwmigm+2M/wzuM6JWncocgYwLic1csSpalBh96kQKXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@astrojs/compiler-binding@0.3.2': + resolution: {integrity: sha512-8w/9CWmYrAJJ8N0SY3O43ws2BgxoW6u3QsD8u2mE140lMYAlwh+tlNoUeSBq22wVheFuiBbR212l6ixZ2IIgCQ==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@astrojs/compiler-rs@0.3.2': + resolution: {integrity: sha512-xlx/T7JovIKduu4ucbTQUxQ5+Q8wxkHxhLjnZk3VlJbhbQ9RLvvuDk1p2YYFYFQ5y14dVm3FGGO4isQXa4F+Tg==} + engines: {node: '>=22.12.0'} + + '@astrojs/internal-helpers@0.10.2': + resolution: {integrity: sha512-yt7fMgPYqSM4Tmr+taTW6Per+hjJ8Pk6lA1PAcDyqzOt8HzJ6Kje5WzCxA2Sd+9wsUW7uhkLeoTMK0cXPwH9rQ==} + + '@astrojs/markdown-remark@7.2.2': + resolution: {integrity: sha512-FGfmK84zSNcrsBd0dl1gXE9JvZYElp8EXQa2jpHVAxG4deGKAp43wspxFupjADJX7MSsMRHwYCnfT6EyVmgeFQ==} + + '@astrojs/markdown-satteri@0.3.5': + resolution: {integrity: sha512-CvWVEFAbay7YO+i9SaqDJubipA5ckiVB89QWoMJ5XC0m5CtFg8JwZ7Kau6X9sYY7FZURH0w2l03ISH2jOS/RDQ==} + + '@astrojs/mdx@7.0.5': + resolution: {integrity: sha512-wEM/HH1RiEntyPVagdiF+yArzfcYLKBB0C1RZspVidKZ97rRMbaqP1Nbl/GR0sJs8zwaceqxRymw8aOKKJRdYw==} + engines: {node: '>=22.12.0'} + peerDependencies: + '@astrojs/markdown-satteri': ^0.3.1 + astro: ^7.0.0 + peerDependenciesMeta: + '@astrojs/markdown-satteri': + optional: true + + '@astrojs/prism@4.0.2': + resolution: {integrity: sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==} + engines: {node: '>=22.12.0'} + + '@astrojs/sitemap@3.7.3': + resolution: {integrity: sha512-f8euLVsyeAmAkSm/1M2Kb8sL8byQmfgbvBNaHFItCheTj/IpiJYSEWVcqDHZ/yEHxiS7+w87mQkzwZaPHmk5GA==} + + '@astrojs/starlight@0.41.6': + resolution: {integrity: sha512-Dt0/wY2JbFGUpxMgclw1j2Iqks2GG0LHYKgP7TfBXsFrs4LIbKvQ596lzyhXLz6nFcnPdIB9ZRFyDJeuVcx3Ug==} + peerDependencies: + '@astrojs/markdown-remark': ^7.2.0 + astro: ^7.0.2 + peerDependenciesMeta: + '@astrojs/markdown-remark': + optional: true + + '@astrojs/telemetry@3.3.3': + resolution: {integrity: sha512-C1TLn5sPJr0x4vk56piHWKbnqlEB8BKyte5Y45V02U+D7BGO5eMqZDH5aPjnkXQWJggvmsTXxH03QMZ9NgWLzQ==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.8': + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} + engines: {node: '>=6.9.0'} + + '@bruits/satteri-darwin-arm64@0.9.5': + resolution: {integrity: sha512-iw4nZgx9v30lWo/MTngQqi1pI78KI0DnkSm+lVJGYdmPLgAyDNJigVhpG42/Iq55A6c1Ll8q66ljyyRiQUxwow==} + cpu: [arm64] + os: [darwin] + + '@bruits/satteri-darwin-x64@0.9.5': + resolution: {integrity: sha512-6T26Z5Kf3cFW2PSlk9p7zT7yVxvuBSiJvYyz9u8KjYwMTqZyIDOj2wDyNpxKV4+6yUVG7rddq2QwvG/8LJA2+Q==} + cpu: [x64] + os: [darwin] + + '@bruits/satteri-linux-arm64-gnu@0.9.5': + resolution: {integrity: sha512-u51id17uJwNEMK9nBlICsq6U31c+XVqQueVBkwRIzZG+gMpS8TOJctt5h5Wz33Z8xnMdTd+adtACVz0yHgGuOA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@bruits/satteri-linux-arm64-musl@0.9.5': + resolution: {integrity: sha512-v39HxiwGC5Rqm01HksP6+5Y+xKLPlsuVFgIgpEAo+SiQ22c+mJVhS3u7Z6ePAKdhL5NJoK1xq70kLz3L13AhpQ==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@bruits/satteri-linux-x64-gnu@0.9.5': + resolution: {integrity: sha512-F3uO8uFp3pAP5ZGXttwvh57GS7s0lL953tnNdyI2gRyP4kOOkp6pyGojNJzCjkDvWI2Cvb9iNrKok3aqQPauAw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@bruits/satteri-linux-x64-musl@0.9.5': + resolution: {integrity: sha512-bicEqglLlz++mWyADaZoP0JY20s4vDfLjaPYgQqC+NI4zZLTOOg1T4GB8aqtc822Pqji8SQBmSrTb7CrP8i08Q==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@bruits/satteri-wasm32-wasi@0.9.5': + resolution: {integrity: sha512-zauAuMwfPnKPUkd4AFixRFpXdgKwP2mKgxrIIo2gJzW0/ZneF9dbHnLkojSpaBnCCp7VUL1hIi5WWZvB1CqmAQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@bruits/satteri-win32-arm64-msvc@0.9.5': + resolution: {integrity: sha512-SrfE7NEsgZjBvU3c+RR6oQRu0ToXY5uVJEbieXEF0YTctIV2zAVlbaMjWLts074QCgh3a+XHWkR/lWh2VH2LUg==} + cpu: [arm64] + os: [win32] + + '@bruits/satteri-win32-x64-msvc@0.9.5': + resolution: {integrity: sha512-5Kw9ZAtTGS8WHizyn+CJhjjfIQrw+7jcZodpmpXJjefnO15M8UexIi6JR2E5thyvsmHyhL6ZDDMUNR4bKJPd4g==} + cpu: [x64] + os: [win32] + + '@capsizecss/unpack@4.0.1': + resolution: {integrity: sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==} + engines: {node: '>=18'} + + '@clack/core@1.4.3': + resolution: {integrity: sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==} + engines: {node: '>= 20.12.0'} + + '@clack/prompts@1.7.0': + resolution: {integrity: sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==} + engines: {node: '>= 20.12.0'} + + '@ctrl/tinycolor@4.2.0': + resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==} + engines: {node: '>=14'} + + '@emnapi/core@1.11.1': + resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} + + '@emnapi/core@2.0.0-alpha.3': + resolution: {integrity: sha512-AZypUeJ/yByuxyS7BlSNRDOMLMlROYtjYdIAuBmJssVz1UJDSeYxLrdizhXCFYhedC5bqd/ASy8EuNXbVVXp9g==} + + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + + '@emnapi/runtime@2.0.0-alpha.3': + resolution: {integrity: sha512-hFPAhMUjJD9BSyCANEISPOogeXC9Zo9ZQl7L6vKnaVsMkCtzznaW/naYypeyl0Gv5rYfWYsZbpixTMpjDJzQeA==} + + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} + + '@emnapi/wasi-threads@2.0.1': + resolution: {integrity: sha512-9DsSk+o5NBX0CCJT8s0EROGSGxjR/tKu6aBTaVyq+SjAEQH4XcdcRxPBRzsBLizTTJ49MJjF+jgu3qnO9GLQcQ==} + + '@esbuild/aix-ppc64@0.28.1': + resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.28.1': + resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.28.1': + resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.28.1': + resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.28.1': + resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.1': + resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.28.1': + resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.1': + resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.28.1': + resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.28.1': + resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.28.1': + resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.28.1': + resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.28.1': + resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.28.1': + resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.1': + resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.28.1': + resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.28.1': + resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.28.1': + resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.1': + resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.28.1': + resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.1': + resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.28.1': + resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.28.1': + resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.28.1': + resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.28.1': + resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.28.1': + resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@expressive-code/core@0.44.1': + resolution: {integrity: sha512-3dDo9N8D7hYrLNNMMWFovg3+aDUtnQm7c7z0GZc1c0LEFVBc0Q6lKG+tVT28gDadOvsgOANfCn35fgpe97Pmgg==} + + '@expressive-code/plugin-frames@0.44.1': + resolution: {integrity: sha512-HC/bdRao9225ApcgO/e3jn8ZOhldKO7ob1O/Tcipvtv7Vb5nMphZhMtD9uuywpvxkPYBHJi3504WhrKg05Dwqg==} + + '@expressive-code/plugin-shiki@0.44.1': + resolution: {integrity: sha512-YApiZt3buUzBwL5tqj8G+sYC5NjMjRCHgQwr9bmGl69rtcHy6fE9dooWUeKYB978fJT2BuxT5FeHcF47rA3SEg==} + + '@expressive-code/plugin-text-markers@0.44.1': + resolution: {integrity: sha512-B3BsJoJ8CFMlcIX9f+X9tcI3C4zPDO601+YuLi9GheSTNro7ZfqSjLptMQKBHOWZvxnAtY5zvIX7iO/qtBhNBg==} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@mdx-js/mdx@3.1.1': + resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} + + '@napi-rs/wasm-runtime@1.2.2': + resolution: {integrity: sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + peerDependencies: + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.3 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.3 + + '@oslojs/encoding@1.1.0': + resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + + '@oxc-project/types@0.142.0': + resolution: {integrity: sha512-7W+2q5AKQVU36fkaryontrHn3YDt1RyUYXatw9i5H8ocYe2sPKSFB6eS8WNPeRKiN1qAWWZUPm7gwFzJGrccqQ==} + + '@pagefind/darwin-arm64@1.5.2': + resolution: {integrity: sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ==} + cpu: [arm64] + os: [darwin] + + '@pagefind/darwin-x64@1.5.2': + resolution: {integrity: sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw==} + cpu: [x64] + os: [darwin] + + '@pagefind/default-ui@1.5.2': + resolution: {integrity: sha512-pm1LMnQg8N2B3n2TnjKlhaFihpz6zTiA4HiGQ6/slKO/+8K9CAU5kcjdSSPgpuk1PMuuN4hxLipUIifnrkl3Sg==} + + '@pagefind/freebsd-x64@1.5.2': + resolution: {integrity: sha512-7EVzo9+0w+2cbe671BtMj10UlNo83I+HrLVLfRxO731svHRJKUfJ/mo05gU14pe9PCfpKNQT8FS3Xc/oDN6pOA==} + cpu: [x64] + os: [freebsd] + + '@pagefind/linux-arm64@1.5.2': + resolution: {integrity: sha512-Ovt9+K35sqzn8H3ZMXGwls4TD/wMJuvRtShHIsmUQREmaxjrDEX7gHckRCrwYJ4XE1H1p6HkLz3wukrAnsfXQw==} + cpu: [arm64] + os: [linux] + + '@pagefind/linux-x64@1.5.2': + resolution: {integrity: sha512-V+tFqHKXhQKq/WqPBD67AFy7scn1/aZID00ws4fSDd+1daSi5UHR9VVlRrOUYKxn3VuFQYRD7lYXdZK1WED1YA==} + cpu: [x64] + os: [linux] + + '@pagefind/windows-arm64@1.5.2': + resolution: {integrity: sha512-hN9Nh90fNW61nNRCW9ZyQrAj/mD0eRvmJ8NlTUzkbuW8kIzGJUi3cxjFkEcMZ5h/8FsKWD/VcouZl4yo1F7B6g==} + cpu: [arm64] + os: [win32] + + '@pagefind/windows-x64@1.5.2': + resolution: {integrity: sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg==} + cpu: [x64] + os: [win32] + + '@rolldown/binding-android-arm64@1.2.1': + resolution: {integrity: sha512-02hOeOSryYxVrOIphmLAsqnCJWxwlzFk+pEt/N/i6OgT3lShHO7xGCU5cpgchRDHboAEbSjzgGh+O/u1GswQmA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.2.1': + resolution: {integrity: sha512-fMsTOnN0OjFm3CyppWPitKnc8UlliVARUULW6cfU6AIqjdtgmSFWSk9vecHzZduv/yMWIHDlRhM1e8Iff9uAfA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.2.1': + resolution: {integrity: sha512-1wjKdz/XLGKHaTNHjQveQ/B23TKx4ItAqm1JbyVuvNPc4Ze0Fb48s49TAd/2zcplPl8okE/UbTgmlVfwT7eFeQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.2.1': + resolution: {integrity: sha512-Fa0jHR07E7YBN4vOEsbVf2briYNsuOowfLJaXULZM0ldMlaCaj2LJgLMbMe4iacRyZmvR8efFhgR9wKuGclQUg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.2.1': + resolution: {integrity: sha512-pzkgu1SSHGgRRyRZ4fbmSgmajbVt+epaLP99NDjFft69v/ypfTi6swBMiVdh2EkQ0OSnHE1lZDM7DRGkyAzUpA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.2.1': + resolution: {integrity: sha512-QI5SEDY8cbiYWHx0VO4vIc3UlS6a32vXHjU8Qy/17adEmZIPuByJg13UEvo9c/UCiUkdcVWY83C+b+JrwnNyUg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.2.1': + resolution: {integrity: sha512-Sm41FyCeXqmYcERoYOCbGIL5hNfd8w9LQ7Y61Bev48HkcjaJqV/iiVOaiDxjVTRMS+QKrZmD8cfPt4uMVnvM+A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.2.1': + resolution: {integrity: sha512-2x+WhXTGl9yJYPbltW/BSEPTVz9OIWQyER4N+gJEDWkkn904eRcBzELqh/Hf7K0w/ubGbKNMv0ZC+94QK/IFEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.2.1': + resolution: {integrity: sha512-eEjmQpuRQayHPWWnywaWHkFT3ToPbP3RYy42VVd/B9aBGDA+Ol25EIWHxKQST3IiWJjikCWUF7KtbfqwZrzVwQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.2.1': + resolution: {integrity: sha512-/Orga1fZYkLc/56jBICcHrKchl8Z2UKdDSr3LG9ToWO1lQ6a4Livk9Xz+9WN91zsz5QR3XQz2NNoSDEvP6qadw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.2.1': + resolution: {integrity: sha512-xxBJRL+0q0Kce7orznGWLuylHDY65vuARXZRpX+hPdv+DqK2c3NlCsVA98tlWzWNEE7yPqA/1NQ5nnCrj49Y5A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.2.1': + resolution: {integrity: sha512-M6AdXIXw3s+/8XpKMzdGDEXGS1S7kwUsy+rcTIUIOx5Ge4nXKCtAFHFV9YKkXvGcC5WMoTjAteLzlsQROVI0Yw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.2.1': + resolution: {integrity: sha512-/TX0SoRGojHzSAHpfVBbavRVSazg5U3h3Y3VXfcc0cdugq6kxdqw8LPGFiPr+/7gE/60zRcsOY2Vi9b9eT0jww==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + + '@rolldown/binding-win32-arm64-msvc@1.2.1': + resolution: {integrity: sha512-EvRrivJieyHG+AO9lleZWgq+g0+S7oV2C51yuqlcyU/R9net+sI4Pj0F+lUoP2bEr6TWX3SqFaaS0SzfLxSzkw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.2.1': + resolution: {integrity: sha512-Z4eCmn5QJ/5+azF9knpLWKfVd9aidn0mAe9TpJgvBLId9Ax3t0+JVxBmT25Bv7NBbVW1TZyKjQjQReouMeH5UQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@rollup/pluginutils@5.4.0': + resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@shikijs/core@4.4.1': + resolution: {integrity: sha512-VeR2CY6Nn9/WbisoYLOQZ7HZOnwTrpBuOw4wExjqLnBCi62BNWynBUO6K2uPIASPFJwAv7cX1fUu+LrPlSstcw==} + engines: {node: '>=20'} + + '@shikijs/engine-javascript@4.4.1': + resolution: {integrity: sha512-6U4lJBh8LTvIkEVqRHv/rr3ruwtO6IweFQt1ME1ntHJMGHS+6N86vfYGO1o8c/DtOCTia2lfhdQBtBrps1sDfQ==} + engines: {node: '>=20'} + + '@shikijs/engine-oniguruma@4.4.1': + resolution: {integrity: sha512-p23RugMKss0r5DAtRJW1yAXUDl60JvhQYV20yuxei//26JyDSJefV3umyWzzwep2weblMnJGDYahuti6XkcMgA==} + engines: {node: '>=20'} + + '@shikijs/langs@4.4.1': + resolution: {integrity: sha512-xb2kCMloBCIraIy2fS5MW0t/BxVY3q2nDyQKBoeSeq6KNrQbShHetCFlw2n35fGIJ6t3+hXDLQogP5ir9O9bvA==} + engines: {node: '>=20'} + + '@shikijs/primitive@4.4.1': + resolution: {integrity: sha512-ko2OfDoG89YuQ7xL5LtcQiWKb7NIv1Ephb7g48TVU198OzAMLC8lXVEwaJGHK4sUMYrfAGJDqYmNLOLiW/Kz8w==} + engines: {node: '>=20'} + + '@shikijs/themes@4.4.1': + resolution: {integrity: sha512-wudOaoFro+/Zl9gQv2W1Ur5XlVduqvTuYLI483Xi0wgc1A+cy1hfB2r6ac6ufBgF+ID7KJEW7L41MHrzQ4wH+w==} + engines: {node: '>=20'} + + '@shikijs/types@4.4.1': + resolution: {integrity: sha512-GOwCLQDHM5EjGUWNPrhzJbr6JP8V/Dx/CDVkWvbZ1Avw5JFnNUckrgbLmE07qtg4WlW7Q7QFndhjIkeU9XMPvw==} + engines: {node: '>=20'} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/hast@3.0.5': + resolution: {integrity: sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==} + + '@types/js-yaml@4.0.9': + resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/mdx@2.0.14': + resolution: {integrity: sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/nlcst@2.0.3': + resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} + + '@types/node@24.13.3': + resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} + + '@types/sax@1.2.7': + resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@ungap/structured-clone@1.3.3': + resolution: {integrity: sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.18.0: + resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} + engines: {node: '>=0.4.0'} + hasBin: true + + am-i-vibing@0.4.0: + resolution: {integrity: sha512-MxT4XZL7pzLHpuvhDKdMaQHMGGkJDLluKBLsbstn+8wv9sWcFT6h+0ve9qkml95amVTZtZV83gQe2hY+ojgHLg==} + hasBin: true + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-iterate@2.0.1: + resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} + + astring@1.9.0: + resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} + hasBin: true + + astro-expressive-code@0.44.1: + resolution: {integrity: sha512-DT1LnCqbHasBKlvzJ3m6LR4VI94wwx3W9EV/YbP1te4rqjOHsvsezHYuqb5MeLWLftXms/1FA9QBbwCo43DnJQ==} + peerDependencies: + astro: ^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta || ^7.0.0 + + astro@7.1.6: + resolution: {integrity: sha512-83x9rYbHazMaZkYrAFRVZXSQx2moFkz0F7cjTDUF3GWfS0a3p2vZXG1ZdhV86rStHApQCodBJW+XTD37xISIrQ==} + engines: {node: '>=22.12.0', npm: '>=9.6.5', pnpm: '>=7.1.0'} + hasBin: true + peerDependencies: + '@astrojs/markdown-remark': 7.2.2 + peerDependenciesMeta: + '@astrojs/markdown-remark': + optional: true + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + bcp-47-match@2.0.3: + resolution: {integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==} + + bcp-47@2.1.1: + resolution: {integrity: sha512-KLw+H/gd2p4zly1X7Yh/qziuyae5/w/QFnvTng9eZL5fvszL7Whl3MBoWF8yxL7ksUjBfOD+OxkytiqbBpG+Fw==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + collapse-white-space@2.1.0: + resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + + common-ancestor-path@2.0.0: + resolution: {integrity: sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==} + engines: {node: '>= 18'} + + cookie-es@1.2.3: + resolution: {integrity: sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==} + + cookie@2.0.1: + resolution: {integrity: sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w==} + engines: {node: '>=22'} + + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + + css-selector-parser@3.3.0: + resolution: {integrity: sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==} + + css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devalue@5.9.0: + resolution: {integrity: sha512-RWrqdArjvPbsATEhOPUo6Wndc/iWnkWKlhIrdlF3zMMYo/c3CVtoaVAyLtWxz5h8nSlkHzxnzV2uLydPXmtF+A==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + + direction@2.0.1: + resolution: {integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==} + hasBin: true + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dset@3.1.4: + resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} + engines: {node: '>=4'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + es-module-lexer@2.3.1: + resolution: {integrity: sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==} + + esast-util-from-estree@2.0.0: + resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} + + esast-util-from-js@2.0.1: + resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==} + + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} + engines: {node: '>=18'} + hasBin: true + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + estree-util-attach-comments@3.0.0: + resolution: {integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==} + + estree-util-build-jsx@3.0.1: + resolution: {integrity: sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + estree-util-scope@1.0.0: + resolution: {integrity: sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==} + + estree-util-to-js@2.0.0: + resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==} + + estree-util-visit@2.0.0: + resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + + expressive-code@0.44.1: + resolution: {integrity: sha512-GakidxhapWDzpKLqEaFQ8wGk6gAqEtPQibu8+yPBfnDLgev5Vdsh1pasTxnrXL/mzIknyqeTwhMHTghdaiUrTg==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-string-truncated-width@3.0.3: + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} + + fast-string-width@3.0.2: + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} + + fast-wrap-ansi@0.2.2: + resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + flattie@1.1.1: + resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} + engines: {node: '>=8'} + + fontace@0.4.1: + resolution: {integrity: sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==} + + fontkitten@1.0.3: + resolution: {integrity: sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==} + engines: {node: '>=20'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + get-tsconfig@5.0.0-beta.4: + resolution: {integrity: sha512-7nF7C9fIPFEMHgEMEfgIlO9wDdZ8CyHw27rWciFZfHvHDReIiPhsYuzPRXsfvBCqFy1l8RRyyWV7QLM+ZhUJsQ==} + engines: {node: '>=20.20.0'} + + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + + h3@1.15.11: + resolution: {integrity: sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==} + + hast-util-embedded@3.0.0: + resolution: {integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==} + + hast-util-format@1.1.0: + resolution: {integrity: sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==} + + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-has-property@3.0.0: + resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} + + hast-util-is-body-ok-link@3.0.1: + resolution: {integrity: sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==} + + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-minify-whitespace@1.0.1: + resolution: {integrity: sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-phrasing@3.0.1: + resolution: {integrity: sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==} + + hast-util-raw@9.1.0: + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} + + hast-util-select@6.0.4: + resolution: {integrity: sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==} + + hast-util-to-estree@3.1.3: + resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-to-parse5@8.0.1: + resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} + + hast-util-to-string@3.0.1: + resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} + + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + + html-escaper@3.0.3: + resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + html-whitespace-sensitive-tag-names@3.0.1: + resolution: {integrity: sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==} + + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + + i18next@26.3.6: + resolution: {integrity: sha512-Bu5Z2nAXgfVyM8xvW3jk9EKRIuX37PudsrBViThNFx7CR7aaYTpP01cxNB/E4c4UUzTDiAZRstEhsRfPOL/8xA==} + peerDependencies: + typescript: ^5 || ^6 || ^7 + peerDependenciesMeta: + typescript: + optional: true + + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-docker@4.0.0: + resolution: {integrity: sha512-LHE+wROyG/Y/0ZnbktRCoTix2c1RhgWaZraMZ8o1Q7zCh0VSrICJQO5oqIIISrcSBtrXv0o233w1IYwsWCjTzA==} + engines: {node: '>=20'} + hasBin: true + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + js-yaml@4.3.1: + resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} + hasBin: true + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + + klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} + + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + engines: {node: '>= 12.0.0'} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} + engines: {node: 20 || >=22} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + magic-string@1.1.0: + resolution: {integrity: sha512-kS3VHe0nEPST2saQV4Rbkchcd3UBRkVTQHo1D3h/ZTwFDhai/mfKkmtPAtD129EOI7K3HlHIsFOt0WrI2/oU9g==} + + magicast@0.5.4: + resolution: {integrity: sha512-llBEhWm1SacoRwgHUoQJYtwp4PBLF4faQi5TCpIGyGs9n4y5+juI0tDgyKIfpqxckRHaHzouUEph3THklWh03w==} + + markdown-extensions@2.0.0: + resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} + engines: {node: '>=16'} + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + mdast-util-definitions@6.0.0: + resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} + + mdast-util-directive@3.1.0: + resolution: {integrity: sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdx@3.0.0: + resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-directive@4.0.0: + resolution: {integrity: sha512-/C2nqVmXXmiseSSuCdItCMho7ybwwop6RrrRPk0KbOHW21JKoCldC+8rFOaundDoRBUWBnJJcxeA/Kvi34WQXg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-extension-mdx-expression@3.0.1: + resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==} + + micromark-extension-mdx-jsx@3.0.2: + resolution: {integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==} + + micromark-extension-mdx-md@2.0.0: + resolution: {integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==} + + micromark-extension-mdxjs-esm@3.0.0: + resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==} + + micromark-extension-mdxjs@3.0.0: + resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-mdx-expression@2.0.3: + resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-events-to-acorn@2.0.3: + resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.16: + resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + neotraverse@1.0.1: + resolution: {integrity: sha512-WmmLty1YWwJl9yZi77v2dVIV6X2kuYV8YYBI/G3LWGKdGHmHUvL1z7FW0iDvEvGAwNEoc5x1tOOOyDnf5jJw/w==} + engines: {node: '>= 10'} + + nlcst-to-string@4.0.0: + resolution: {integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==} + + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + + node-mock-http@1.0.5: + resolution: {integrity: sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + obug@2.1.4: + resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} + engines: {node: '>=12.20.0'} + + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + + oniguruma-parser@0.12.2: + resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==} + + oniguruma-to-es@4.3.6: + resolution: {integrity: sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==} + + p-limit@7.3.1: + resolution: {integrity: sha512-0trZaiG7Y7kN/Egy9a8j47t9osC0Tch4PaIWd9yGF6bvmlk7muExRvGNYb8sXBwEKMoNKsbNN9P8EefuQekE4Q==} + engines: {node: '>=20'} + + p-queue@9.3.3: + resolution: {integrity: sha512-NXAOdnEe5FsZJfT4oK84lE1Y5cFFdWlRuOo5tww8DyNMxyRXwn39fIkUtNLKppcPC+UYU/bXujNCUGDv01y7CA==} + engines: {node: '>=20'} + + p-timeout@7.0.1: + resolution: {integrity: sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==} + engines: {node: '>=20'} + + package-manager-detector@1.8.0: + resolution: {integrity: sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==} + + pagefind@1.5.2: + resolution: {integrity: sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q==} + hasBin: true + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse-latin@7.0.0: + resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + piccolore@0.1.3: + resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + engines: {node: '>=12'} + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.1.4: + resolution: {integrity: sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==} + engines: {node: '>=4'} + + postcss@8.5.25: + resolution: {integrity: sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==} + engines: {node: ^10 || ^12 || >=14} + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + process-ancestry@0.1.0: + resolution: {integrity: sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg==} + engines: {node: '>=18.0.0'} + + property-information@7.2.0: + resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} + + recma-build-jsx@1.0.0: + resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==} + + recma-jsx@1.0.1: + resolution: {integrity: sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + recma-parse@1.0.0: + resolution: {integrity: sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==} + + recma-stringify@1.0.0: + resolution: {integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==} + + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + + rehype-expressive-code@0.44.1: + resolution: {integrity: sha512-+VZgs7Evw4LXRN3owpoBNSTpYuW6GeOdjqcUT1TuY8o/4MGPtbd0EU7Bgrju7X8KrQ6SslOBAuGWJ5fV5TriJQ==} + + rehype-format@5.0.1: + resolution: {integrity: sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==} + + rehype-parse@9.0.1: + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} + + rehype-raw@7.0.0: + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + + rehype-recma@1.0.0: + resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==} + + rehype-stringify@10.0.1: + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} + + rehype@13.0.2: + resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==} + + remark-directive@4.0.0: + resolution: {integrity: sha512-7sxn4RfF1o3izevPV1DheyGDD6X4c9hrGpfdUpm7uC++dqrnJxIZVkk7CoKqcLm0VUMAuOol7Mno3m6g8cfMuA==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-mdx@3.1.1: + resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-smartypants@3.0.3: + resolution: {integrity: sha512-gCaK+ndZ0hYezlqFegHFCVh2CQemsi0Npdh1qVM9bxlUFknjkbP6VmojWhddOCrbK0PbbacmYLWfTULRiT1eWA==} + engines: {node: '>=16.0.0'} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + retext-latin@4.0.0: + resolution: {integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==} + + retext-smartypants@6.2.0: + resolution: {integrity: sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==} + + retext-stringify@4.0.0: + resolution: {integrity: sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==} + + retext@9.0.0: + resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==} + + rolldown@1.2.1: + resolution: {integrity: sha512-4FKJhg8d3OiyQOA6Q1Q0hoFFpW9/OoX+VsHzpECsdsIZoOArrAK90gl59YK/Z+gnDel45bgJZK03ozH/9bCqEw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + satteri@0.9.5: + resolution: {integrity: sha512-ZuWVl+vnM64y+/TtX8Kosv2c00W+hLQiiwnEL6H0UKVVrxFqMw4D2CJHHQaouVd89OAhtBBfjWLqhKi3TVUV4w==} + + sax@1.6.1: + resolution: {integrity: sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==} + engines: {node: '>=11.0.0'} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shiki@4.4.1: + resolution: {integrity: sha512-rFP+iYKzjLEIqiMiKANhARqiAbk4deDhWnBtnUO/K0D0dPxMGDH4N0FVfBY/VeI+lPrV4wNGCHQZp7EOr7NNBw==} + engines: {node: '>=20'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + sitemap@9.0.1: + resolution: {integrity: sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ==} + engines: {node: '>=20.19.5', npm: '>=10.8.2'} + hasBin: true + + smol-toml@1.7.1: + resolution: {integrity: sha512-PPlsspAZ4jbMBu5DMFhfUGDQLu/vrL4SyBROVS37x8ynnVmFIs1VPBz1Co8Xks3TvpIaZXmU85y4DrQ+UyVFoQ==} + engines: {node: '>= 18'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + stream-replace-string@2.0.0: + resolution: {integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + + svgo@4.0.2: + resolution: {integrity: sha512-ekx94z1rRc5LDi6oSUaeRnYhd0UOJxdtQCL2rF8xpWxD3TPAsISWOrxezqGovqS38GRZOdpDfvQe3ts6F7nsng==} + engines: {node: '>=16'} + hasBin: true + + tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + + tinyclip@0.1.15: + resolution: {integrity: sha512-uo33abH+Ays0xYaDysoBt494Hb3hsEczMpcC0MwFl773pazORx4fmvKhclhR1wonUbB6vvpRsvVMwnhfqeMc+A==} + engines: {node: ^16.14.0 || >= 17.3.0} + + tinyexec@1.3.0: + resolution: {integrity: sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==} + engines: {node: '>=18'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + ultrahtml@1.7.0: + resolution: {integrity: sha512-2xRd0VHoAQE4M+vF/DvFFB7pUV0ZxTW1TLi7lHQWnF/Sb5TPeEUV/l+hxcNnGO00ZXGnR0voCMmYRKQf+rvJ2g==} + + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unifont@0.7.4: + resolution: {integrity: sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==} + + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-modify-children@4.0.0: + resolution: {integrity: sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==} + + unist-util-position-from-estree@2.0.0: + resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-remove-position@5.0.0: + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-children@3.0.0: + resolution: {integrity: sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + unstorage@1.17.5: + resolution: {integrity: sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6 || ^7 || ^8 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1 || ^2 || ^3 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + + url-extras@0.1.0: + resolution: {integrity: sha512-8tzwTeXFPuX/5PHuCDQE5Dd9Ts4rwoq2t9aIT+HS4iAVpmj5l4Ao7Q+BuuFjvWRqrLswBhQDk8O96ZicgCqQqw==} + engines: {node: '>=20'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite@8.2.0: + resolution: {integrity: sha512-pn+CFpM0lwDeKwmOq1ZaBK/9sjorZcgqxki6MbY/jPEVd9vichIlmlD4HmQ5wdP5EgqQCFRaACBxMC7uEGc6lQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.4.0 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitefu@1.1.3: + resolution: {integrity: sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + vite: + optional: true + + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + + xxhash-wasm@1.1.0: + resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@astrojs/compiler-binding-darwin-arm64@0.3.2': + optional: true + + '@astrojs/compiler-binding-darwin-x64@0.3.2': + optional: true + + '@astrojs/compiler-binding-linux-arm64-gnu@0.3.2': + optional: true + + '@astrojs/compiler-binding-linux-arm64-musl@0.3.2': + optional: true + + '@astrojs/compiler-binding-linux-x64-gnu@0.3.2': + optional: true + + '@astrojs/compiler-binding-linux-x64-musl@0.3.2': + optional: true + + '@astrojs/compiler-binding-wasm32-wasi@0.3.2(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)': + dependencies: + '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + optional: true + + '@astrojs/compiler-binding-win32-arm64-msvc@0.3.2': + optional: true + + '@astrojs/compiler-binding-win32-x64-msvc@0.3.2': + optional: true + + '@astrojs/compiler-binding@0.3.2(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)': + optionalDependencies: + '@astrojs/compiler-binding-darwin-arm64': 0.3.2 + '@astrojs/compiler-binding-darwin-x64': 0.3.2 + '@astrojs/compiler-binding-linux-arm64-gnu': 0.3.2 + '@astrojs/compiler-binding-linux-arm64-musl': 0.3.2 + '@astrojs/compiler-binding-linux-x64-gnu': 0.3.2 + '@astrojs/compiler-binding-linux-x64-musl': 0.3.2 + '@astrojs/compiler-binding-wasm32-wasi': 0.3.2(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3) + '@astrojs/compiler-binding-win32-arm64-msvc': 0.3.2 + '@astrojs/compiler-binding-win32-x64-msvc': 0.3.2 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + + '@astrojs/compiler-rs@0.3.2(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)': + dependencies: + '@astrojs/compiler-binding': 0.3.2(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + + '@astrojs/internal-helpers@0.10.2': + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + js-yaml: 4.3.1 + picomatch: 4.0.5 + retext-smartypants: 6.2.0 + shiki: 4.4.1 + smol-toml: 1.7.1 + unified: 11.0.5 + + '@astrojs/markdown-remark@7.2.2': + dependencies: + '@astrojs/internal-helpers': 0.10.2 + '@astrojs/prism': 4.0.2 + github-slugger: 2.0.0 + hast-util-from-html: 2.0.3 + hast-util-to-text: 4.0.2 + mdast-util-definitions: 6.0.0 + rehype-raw: 7.0.0 + rehype-stringify: 10.0.1 + remark-gfm: 4.0.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + remark-smartypants: 3.0.3 + unified: 11.0.5 + unist-util-remove-position: 5.0.0 + unist-util-visit: 5.1.0 + unist-util-visit-parents: 6.0.2 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@astrojs/markdown-satteri@0.3.5': + dependencies: + '@astrojs/internal-helpers': 0.10.2 + '@astrojs/prism': 4.0.2 + github-slugger: 2.0.0 + hast-util-from-html: 2.0.3 + satteri: 0.9.5 + + '@astrojs/mdx@7.0.5(@astrojs/markdown-satteri@0.3.5)(astro@7.1.6(@astrojs/markdown-remark@7.2.2)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(@types/node@24.13.3))': + dependencies: + '@astrojs/internal-helpers': 0.10.2 + '@astrojs/markdown-remark': 7.2.2 + '@mdx-js/mdx': 3.1.1 + acorn: 8.18.0 + astro: 7.1.6(@astrojs/markdown-remark@7.2.2)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(@types/node@24.13.3) + es-module-lexer: 2.3.1 + estree-util-visit: 2.0.0 + hast-util-to-html: 9.0.5 + piccolore: 0.1.3 + rehype-raw: 7.0.0 + remark-gfm: 4.0.1 + remark-smartypants: 3.0.3 + source-map: 0.7.6 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + optionalDependencies: + '@astrojs/markdown-satteri': 0.3.5 + transitivePeerDependencies: + - supports-color + + '@astrojs/prism@4.0.2': + dependencies: + prismjs: 1.30.0 + + '@astrojs/sitemap@3.7.3': + dependencies: + sitemap: 9.0.1 + stream-replace-string: 2.0.0 + zod: 4.4.3 + + '@astrojs/starlight@0.41.6(@astrojs/markdown-remark@7.2.2)(astro@7.1.6(@astrojs/markdown-remark@7.2.2)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(@types/node@24.13.3))': + dependencies: + '@astrojs/markdown-satteri': 0.3.5 + '@astrojs/mdx': 7.0.5(@astrojs/markdown-satteri@0.3.5)(astro@7.1.6(@astrojs/markdown-remark@7.2.2)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(@types/node@24.13.3)) + '@astrojs/sitemap': 3.7.3 + '@pagefind/default-ui': 1.5.2 + '@types/hast': 3.0.5 + '@types/js-yaml': 4.0.9 + '@types/mdast': 4.0.4 + astro: 7.1.6(@astrojs/markdown-remark@7.2.2)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(@types/node@24.13.3) + astro-expressive-code: 0.44.1(astro@7.1.6(@astrojs/markdown-remark@7.2.2)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(@types/node@24.13.3)) + bcp-47: 2.1.1 + hast-util-from-html: 2.0.3 + hast-util-select: 6.0.4 + hast-util-to-string: 3.0.1 + hastscript: 9.0.1 + i18next: 26.3.6 + js-yaml: 4.3.1 + klona: 2.0.6 + magic-string: 0.30.21 + mdast-util-directive: 3.1.0 + mdast-util-to-markdown: 2.1.2 + mdast-util-to-string: 4.0.0 + pagefind: 1.5.2 + rehype: 13.0.2 + rehype-format: 5.0.1 + remark-directive: 4.0.0 + satteri: 0.9.5 + ultrahtml: 1.7.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + optionalDependencies: + '@astrojs/markdown-remark': 7.2.2 + transitivePeerDependencies: + - supports-color + - typescript + + '@astrojs/telemetry@3.3.3': + dependencies: + ci-info: 4.4.0 + dset: 3.1.4 + is-docker: 4.0.0 + package-manager-detector: 1.8.0 + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/parser@7.29.8': + dependencies: + '@babel/types': 7.29.8 + + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@bruits/satteri-darwin-arm64@0.9.5': + optional: true + + '@bruits/satteri-darwin-x64@0.9.5': + optional: true + + '@bruits/satteri-linux-arm64-gnu@0.9.5': + optional: true + + '@bruits/satteri-linux-arm64-musl@0.9.5': + optional: true + + '@bruits/satteri-linux-x64-gnu@0.9.5': + optional: true + + '@bruits/satteri-linux-x64-musl@0.9.5': + optional: true + + '@bruits/satteri-wasm32-wasi@0.9.5': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + optional: true + + '@bruits/satteri-win32-arm64-msvc@0.9.5': + optional: true + + '@bruits/satteri-win32-x64-msvc@0.9.5': + optional: true + + '@capsizecss/unpack@4.0.1': + dependencies: + fontkitten: 1.0.3 + + '@clack/core@1.4.3': + dependencies: + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + + '@clack/prompts@1.7.0': + dependencies: + '@clack/core': 1.4.3 + fast-string-width: 3.0.2 + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + + '@ctrl/tinycolor@4.2.0': {} + + '@emnapi/core@1.11.1': + dependencies: + '@emnapi/wasi-threads': 1.2.2 + tslib: 2.8.1 + optional: true + + '@emnapi/core@2.0.0-alpha.3': + dependencies: + '@emnapi/wasi-threads': 2.0.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@2.0.0-alpha.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@2.0.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.28.1': + optional: true + + '@esbuild/android-arm64@0.28.1': + optional: true + + '@esbuild/android-arm@0.28.1': + optional: true + + '@esbuild/android-x64@0.28.1': + optional: true + + '@esbuild/darwin-arm64@0.28.1': + optional: true + + '@esbuild/darwin-x64@0.28.1': + optional: true + + '@esbuild/freebsd-arm64@0.28.1': + optional: true + + '@esbuild/freebsd-x64@0.28.1': + optional: true + + '@esbuild/linux-arm64@0.28.1': + optional: true + + '@esbuild/linux-arm@0.28.1': + optional: true + + '@esbuild/linux-ia32@0.28.1': + optional: true + + '@esbuild/linux-loong64@0.28.1': + optional: true + + '@esbuild/linux-mips64el@0.28.1': + optional: true + + '@esbuild/linux-ppc64@0.28.1': + optional: true + + '@esbuild/linux-riscv64@0.28.1': + optional: true + + '@esbuild/linux-s390x@0.28.1': + optional: true + + '@esbuild/linux-x64@0.28.1': + optional: true + + '@esbuild/netbsd-arm64@0.28.1': + optional: true + + '@esbuild/netbsd-x64@0.28.1': + optional: true + + '@esbuild/openbsd-arm64@0.28.1': + optional: true + + '@esbuild/openbsd-x64@0.28.1': + optional: true + + '@esbuild/openharmony-arm64@0.28.1': + optional: true + + '@esbuild/sunos-x64@0.28.1': + optional: true + + '@esbuild/win32-arm64@0.28.1': + optional: true + + '@esbuild/win32-ia32@0.28.1': + optional: true + + '@esbuild/win32-x64@0.28.1': + optional: true + + '@expressive-code/core@0.44.1': + dependencies: + '@ctrl/tinycolor': 4.2.0 + hast-util-select: 6.0.4 + hast-util-to-html: 9.0.5 + hast-util-to-text: 4.0.2 + hastscript: 9.0.1 + postcss: 8.5.25 + postcss-nested: 6.2.0(postcss@8.5.25) + unist-util-visit: 5.1.0 + unist-util-visit-parents: 6.0.2 + + '@expressive-code/plugin-frames@0.44.1': + dependencies: + '@expressive-code/core': 0.44.1 + + '@expressive-code/plugin-shiki@0.44.1': + dependencies: + '@expressive-code/core': 0.44.1 + shiki: 4.4.1 + + '@expressive-code/plugin-text-markers@0.44.1': + dependencies: + '@expressive-code/core': 0.44.1 + + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.11.3 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@mdx-js/mdx@3.1.1': + dependencies: + '@types/estree': 1.0.9 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdx': 2.0.14 + acorn: 8.18.0 + collapse-white-space: 2.1.0 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-util-scope: 1.0.0 + estree-walker: 3.0.3 + hast-util-to-jsx-runtime: 2.3.6 + markdown-extensions: 2.0.0 + recma-build-jsx: 1.0.0 + recma-jsx: 1.0.1(acorn@8.18.0) + recma-stringify: 1.0.0 + rehype-recma: 1.0.0 + remark-mdx: 3.1.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + source-map: 0.7.6 + unified: 11.0.5 + unist-util-position-from-estree: 2.0.0 + unist-util-stringify-position: 4.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@tybys/wasm-util': 0.10.3 + optional: true + + '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)': + dependencies: + '@emnapi/core': 2.0.0-alpha.3 + '@emnapi/runtime': 2.0.0-alpha.3 + '@tybys/wasm-util': 0.10.3 + optional: true + + '@oslojs/encoding@1.1.0': {} + + '@oxc-project/types@0.142.0': {} + + '@pagefind/darwin-arm64@1.5.2': + optional: true + + '@pagefind/darwin-x64@1.5.2': + optional: true + + '@pagefind/default-ui@1.5.2': {} + + '@pagefind/freebsd-x64@1.5.2': + optional: true + + '@pagefind/linux-arm64@1.5.2': + optional: true + + '@pagefind/linux-x64@1.5.2': + optional: true + + '@pagefind/windows-arm64@1.5.2': + optional: true + + '@pagefind/windows-x64@1.5.2': + optional: true + + '@rolldown/binding-android-arm64@1.2.1': + optional: true + + '@rolldown/binding-darwin-arm64@1.2.1': + optional: true + + '@rolldown/binding-darwin-x64@1.2.1': + optional: true + + '@rolldown/binding-freebsd-x64@1.2.1': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.2.1': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.2.1': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.2.1': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.2.1': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.2.1': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.2.1': + optional: true + + '@rolldown/binding-linux-x64-musl@1.2.1': + optional: true + + '@rolldown/binding-openharmony-arm64@1.2.1': + optional: true + + '@rolldown/binding-wasm32-wasi@1.2.1': + dependencies: + '@emnapi/core': 2.0.0-alpha.3 + '@emnapi/runtime': 2.0.0-alpha.3 + '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.2.1': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.2.1': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@rollup/pluginutils@5.4.0': + dependencies: + '@types/estree': 1.0.9 + estree-walker: 2.0.2 + picomatch: 4.0.5 + + '@shikijs/core@4.4.1': + dependencies: + '@shikijs/primitive': 4.4.1 + '@shikijs/types': 4.4.1 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@4.4.1': + dependencies: + '@shikijs/types': 4.4.1 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.6 + + '@shikijs/engine-oniguruma@4.4.1': + dependencies: + '@shikijs/types': 4.4.1 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@4.4.1': + dependencies: + '@shikijs/types': 4.4.1 + + '@shikijs/primitive@4.4.1': + dependencies: + '@shikijs/types': 4.4.1 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + '@shikijs/themes@4.4.1': + dependencies: + '@shikijs/types': 4.4.1 + + '@shikijs/types@4.4.1': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@tybys/wasm-util@0.10.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.9 + + '@types/estree@1.0.9': {} + + '@types/hast@3.0.5': + dependencies: + '@types/unist': 3.0.3 + + '@types/js-yaml@4.0.9': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdx@2.0.14': {} + + '@types/ms@2.1.0': {} + + '@types/nlcst@2.0.3': + dependencies: + '@types/unist': 3.0.3 + + '@types/node@24.13.3': + dependencies: + undici-types: 7.18.2 + + '@types/sax@1.2.7': + dependencies: + '@types/node': 24.13.3 + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@ungap/structured-clone@1.3.3': {} + + acorn-jsx@5.3.2(acorn@8.18.0): + dependencies: + acorn: 8.18.0 + + acorn@8.18.0: {} + + am-i-vibing@0.4.0: + dependencies: + process-ancestry: 0.1.0 + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + + arg@5.0.2: {} + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + array-iterate@2.0.1: {} + + astring@1.9.0: {} + + astro-expressive-code@0.44.1(astro@7.1.6(@astrojs/markdown-remark@7.2.2)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(@types/node@24.13.3)): + dependencies: + astro: 7.1.6(@astrojs/markdown-remark@7.2.2)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(@types/node@24.13.3) + rehype-expressive-code: 0.44.1 + url-extras: 0.1.0 + + astro@7.1.6(@astrojs/markdown-remark@7.2.2)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(@types/node@24.13.3): + dependencies: + '@astrojs/compiler-rs': 0.3.2(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3) + '@astrojs/internal-helpers': 0.10.2 + '@astrojs/markdown-satteri': 0.3.5 + '@astrojs/telemetry': 3.3.3 + '@capsizecss/unpack': 4.0.1 + '@clack/prompts': 1.7.0 + '@oslojs/encoding': 1.1.0 + '@rollup/pluginutils': 5.4.0 + am-i-vibing: 0.4.0 + aria-query: 5.3.2 + axobject-query: 4.1.0 + ci-info: 4.4.0 + clsx: 2.1.1 + common-ancestor-path: 2.0.0 + cookie: 2.0.1 + devalue: 5.9.0 + diff: 8.0.4 + dset: 3.1.4 + es-module-lexer: 2.3.1 + esbuild: 0.28.1 + flattie: 1.1.1 + fontace: 0.4.1 + get-tsconfig: 5.0.0-beta.4 + github-slugger: 2.0.0 + html-escaper: 3.0.3 + http-cache-semantics: 4.2.0 + js-yaml: 4.3.1 + jsonc-parser: 3.3.1 + magic-string: 1.1.0 + magicast: 0.5.4 + mrmime: 2.0.1 + neotraverse: 1.0.1 + obug: 2.1.4 + p-limit: 7.3.1 + p-queue: 9.3.3 + package-manager-detector: 1.8.0 + piccolore: 0.1.3 + picomatch: 4.0.5 + semver: 7.8.5 + shiki: 4.4.1 + smol-toml: 1.7.1 + svgo: 4.0.2 + tinyclip: 0.1.15 + tinyexec: 1.3.0 + tinyglobby: 0.2.17 + ultrahtml: 1.7.0 + unifont: 0.7.4 + unstorage: 1.17.5 + vite: 8.2.0(@types/node@24.13.3)(esbuild@0.28.1) + vitefu: 1.1.3(vite@8.2.0(@types/node@24.13.3)(esbuild@0.28.1)) + xxhash-wasm: 1.1.0 + yargs-parser: 22.0.0 + zod: 4.4.3 + optionalDependencies: + '@astrojs/markdown-remark': 7.2.2 + sharp: 0.34.5 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@emnapi/core' + - '@emnapi/runtime' + - '@netlify/blobs' + - '@planetscale/database' + - '@types/node' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - '@vitejs/devtools' + - aws4fetch + - db0 + - idb-keyval + - ioredis + - jiti + - less + - rollup + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - uploadthing + - yaml + + axobject-query@4.1.0: {} + + bail@2.0.2: {} + + bcp-47-match@2.0.3: {} + + bcp-47@2.1.1: + dependencies: + is-alphabetical: 2.0.1 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + + boolbase@1.0.0: {} + + ccount@2.0.1: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 + + ci-info@4.4.0: {} + + clsx@2.1.1: {} + + collapse-white-space@2.1.0: {} + + comma-separated-tokens@2.0.3: {} + + commander@11.1.0: {} + + common-ancestor-path@2.0.0: {} + + cookie-es@1.2.3: {} + + cookie@2.0.1: {} + + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-selector-parser@3.3.0: {} + + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + + css-what@6.2.2: {} + + cssesc@3.0.0: {} + + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + + defu@6.1.7: {} + + dequal@2.0.3: {} + + destr@2.0.5: {} + + detect-libc@2.1.2: {} + + devalue@5.9.0: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + diff@8.0.4: {} + + direction@2.0.1: {} + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dset@3.1.4: {} + + entities@4.5.0: {} + + entities@6.0.1: {} + + es-module-lexer@2.3.1: {} + + esast-util-from-estree@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + unist-util-position-from-estree: 2.0.0 + + esast-util-from-js@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + acorn: 8.18.0 + esast-util-from-estree: 2.0.0 + vfile-message: 4.0.3 + + esbuild@0.28.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.1 + '@esbuild/android-arm': 0.28.1 + '@esbuild/android-arm64': 0.28.1 + '@esbuild/android-x64': 0.28.1 + '@esbuild/darwin-arm64': 0.28.1 + '@esbuild/darwin-x64': 0.28.1 + '@esbuild/freebsd-arm64': 0.28.1 + '@esbuild/freebsd-x64': 0.28.1 + '@esbuild/linux-arm': 0.28.1 + '@esbuild/linux-arm64': 0.28.1 + '@esbuild/linux-ia32': 0.28.1 + '@esbuild/linux-loong64': 0.28.1 + '@esbuild/linux-mips64el': 0.28.1 + '@esbuild/linux-ppc64': 0.28.1 + '@esbuild/linux-riscv64': 0.28.1 + '@esbuild/linux-s390x': 0.28.1 + '@esbuild/linux-x64': 0.28.1 + '@esbuild/netbsd-arm64': 0.28.1 + '@esbuild/netbsd-x64': 0.28.1 + '@esbuild/openbsd-arm64': 0.28.1 + '@esbuild/openbsd-x64': 0.28.1 + '@esbuild/openharmony-arm64': 0.28.1 + '@esbuild/sunos-x64': 0.28.1 + '@esbuild/win32-arm64': 0.28.1 + '@esbuild/win32-ia32': 0.28.1 + '@esbuild/win32-x64': 0.28.1 + + escape-string-regexp@5.0.0: {} + + estree-util-attach-comments@3.0.0: + dependencies: + '@types/estree': 1.0.9 + + estree-util-build-jsx@3.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-walker: 3.0.3 + + estree-util-is-identifier-name@3.0.0: {} + + estree-util-scope@1.0.0: + dependencies: + '@types/estree': 1.0.9 + devlop: 1.1.0 + + estree-util-to-js@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + astring: 1.9.0 + source-map: 0.7.6 + + estree-util-visit@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/unist': 3.0.3 + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + eventemitter3@5.0.4: {} + + expressive-code@0.44.1: + dependencies: + '@expressive-code/core': 0.44.1 + '@expressive-code/plugin-frames': 0.44.1 + '@expressive-code/plugin-shiki': 0.44.1 + '@expressive-code/plugin-text-markers': 0.44.1 + + extend@3.0.2: {} + + fast-string-truncated-width@3.0.3: {} + + fast-string-width@3.0.2: + dependencies: + fast-string-truncated-width: 3.0.3 + + fast-wrap-ansi@0.2.2: + dependencies: + fast-string-width: 3.0.2 + + fdir@6.5.0(picomatch@4.0.5): + optionalDependencies: + picomatch: 4.0.5 + + flattie@1.1.1: {} + + fontace@0.4.1: + dependencies: + fontkitten: 1.0.3 + + fontkitten@1.0.3: + dependencies: + tiny-inflate: 1.0.3 + + fsevents@2.3.3: + optional: true + + get-tsconfig@5.0.0-beta.4: + dependencies: + resolve-pkg-maps: 1.0.0 + + github-slugger@2.0.0: {} + + h3@1.15.11: + dependencies: + cookie-es: 1.2.3 + crossws: 0.3.5 + defu: 6.1.7 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.5 + radix3: 1.1.2 + ufo: 1.6.4 + uncrypto: 0.1.3 + + hast-util-embedded@3.0.0: + dependencies: + '@types/hast': 3.0.5 + hast-util-is-element: 3.0.0 + + hast-util-format@1.1.0: + dependencies: + '@types/hast': 3.0.5 + hast-util-embedded: 3.0.0 + hast-util-minify-whitespace: 1.0.1 + hast-util-phrasing: 3.0.1 + hast-util-whitespace: 3.0.0 + html-whitespace-sensitive-tag-names: 3.0.1 + unist-util-visit-parents: 6.0.2 + + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.5 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.2.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-has-property@3.0.0: + dependencies: + '@types/hast': 3.0.5 + + hast-util-is-body-ok-link@3.0.1: + dependencies: + '@types/hast': 3.0.5 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.5 + + hast-util-minify-whitespace@1.0.1: + dependencies: + '@types/hast': 3.0.5 + hast-util-embedded: 3.0.0 + hast-util-is-element: 3.0.0 + hast-util-whitespace: 3.0.0 + unist-util-is: 6.0.1 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.5 + + hast-util-phrasing@3.0.1: + dependencies: + '@types/hast': 3.0.5 + hast-util-embedded: 3.0.0 + hast-util-has-property: 3.0.0 + hast-util-is-body-ok-link: 3.0.1 + hast-util-is-element: 3.0.0 + + hast-util-raw@9.1.0: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + '@ungap/structured-clone': 1.3.3 + hast-util-from-parse5: 8.0.3 + hast-util-to-parse5: 8.0.1 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-select@6.0.4: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + bcp-47-match: 2.0.3 + comma-separated-tokens: 2.0.3 + css-selector-parser: 3.3.0 + devlop: 1.1.0 + direction: 2.0.1 + hast-util-has-property: 3.0.0 + hast-util-to-string: 3.0.1 + hast-util-whitespace: 3.0.0 + nth-check: 2.1.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + hast-util-to-estree@3.1.3: + dependencies: + '@types/estree': 1.0.9 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-attach-comments: 3.0.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + zwitch: 2.0.4 + transitivePeerDependencies: + - supports-color + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.9 + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-to-parse5@8.0.1: + dependencies: + '@types/hast': 3.0.5 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-string@3.0.1: + dependencies: + '@types/hast': 3.0.5 + + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.5 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.5 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + + html-escaper@3.0.3: {} + + html-void-elements@3.0.0: {} + + html-whitespace-sensitive-tag-names@3.0.1: {} + + http-cache-semantics@4.2.0: {} + + i18next@26.3.6: {} + + inline-style-parser@0.2.7: {} + + iron-webcrypto@1.2.1: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-decimal@2.0.1: {} + + is-docker@4.0.0: {} + + is-hexadecimal@2.0.1: {} + + is-plain-obj@4.1.0: {} + + js-yaml@4.3.1: + dependencies: + argparse: 2.0.1 + + jsonc-parser@3.3.1: {} + + klona@2.0.6: {} + + lightningcss-android-arm64@1.33.0: + optional: true + + lightningcss-darwin-arm64@1.33.0: + optional: true + + lightningcss-darwin-x64@1.33.0: + optional: true + + lightningcss-freebsd-x64@1.33.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.33.0: + optional: true + + lightningcss-linux-arm64-gnu@1.33.0: + optional: true + + lightningcss-linux-arm64-musl@1.33.0: + optional: true + + lightningcss-linux-x64-gnu@1.33.0: + optional: true + + lightningcss-linux-x64-musl@1.33.0: + optional: true + + lightningcss-win32-arm64-msvc@1.33.0: + optional: true + + lightningcss-win32-x64-msvc@1.33.0: + optional: true + + lightningcss@1.33.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 + + longest-streak@3.1.0: {} + + lru-cache@11.5.2: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magic-string@1.1.0: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magicast@0.5.4: + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + source-map-js: 1.2.1 + + markdown-extensions@2.0.0: {} + + markdown-table@3.0.4: {} + + mdast-util-definitions@6.0.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + + mdast-util-directive@3.1.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-visit-parents: 6.0.2 + transitivePeerDependencies: + - supports-color + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.3: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx@3.0.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.3 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + mdn-data@2.0.28: {} + + mdn-data@2.27.1: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-directive@4.0.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + parse-entities: 4.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-expression@3.0.1: + dependencies: + '@types/estree': 1.0.9 + devlop: 1.1.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-jsx@3.0.2: + dependencies: + '@types/estree': 1.0.9 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-extension-mdx-md@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-mdxjs-esm@3.0.0: + dependencies: + '@types/estree': 1.0.9 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-extension-mdxjs@3.0.0: + dependencies: + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) + micromark-extension-mdx-expression: 3.0.1 + micromark-extension-mdx-jsx: 3.0.2 + micromark-extension-mdx-md: 2.0.0 + micromark-extension-mdxjs-esm: 3.0.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-mdx-expression@2.0.3: + dependencies: + '@types/estree': 1.0.9 + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-events-to-acorn@2.0.3: + dependencies: + '@types/estree': 1.0.9 + '@types/unist': 3.0.3 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + mrmime@2.0.1: {} + + ms@2.1.3: {} + + nanoid@3.3.16: {} + + neotraverse@1.0.1: {} + + nlcst-to-string@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + + node-fetch-native@1.6.7: {} + + node-mock-http@1.0.5: {} + + normalize-path@3.0.0: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + obug@2.1.4: {} + + ofetch@1.5.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.4 + + ohash@2.0.11: {} + + oniguruma-parser@0.12.2: {} + + oniguruma-to-es@4.3.6: + dependencies: + oniguruma-parser: 0.12.2 + regex: 6.1.0 + regex-recursion: 6.0.2 + + p-limit@7.3.1: + dependencies: + yocto-queue: 1.2.2 + + p-queue@9.3.3: + dependencies: + eventemitter3: 5.0.4 + p-timeout: 7.0.1 + + p-timeout@7.0.1: {} + + package-manager-detector@1.8.0: {} + + pagefind@1.5.2: + optionalDependencies: + '@pagefind/darwin-arm64': 1.5.2 + '@pagefind/darwin-x64': 1.5.2 + '@pagefind/freebsd-x64': 1.5.2 + '@pagefind/linux-arm64': 1.5.2 + '@pagefind/linux-x64': 1.5.2 + '@pagefind/windows-arm64': 1.5.2 + '@pagefind/windows-x64': 1.5.2 + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse-latin@7.0.0: + dependencies: + '@types/nlcst': 2.0.3 + '@types/unist': 3.0.3 + nlcst-to-string: 4.0.0 + unist-util-modify-children: 4.0.0 + unist-util-visit-children: 3.0.0 + vfile: 6.0.3 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + piccolore@0.1.3: {} + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.5: {} + + postcss-nested@6.2.0(postcss@8.5.25): + dependencies: + postcss: 8.5.25 + postcss-selector-parser: 6.1.4 + + postcss-selector-parser@6.1.4: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss@8.5.25: + dependencies: + nanoid: 3.3.16 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prismjs@1.30.0: {} + + process-ancestry@0.1.0: {} + + property-information@7.2.0: {} + + radix3@1.1.2: {} + + readdirp@5.0.0: {} + + recma-build-jsx@1.0.0: + dependencies: + '@types/estree': 1.0.9 + estree-util-build-jsx: 3.0.1 + vfile: 6.0.3 + + recma-jsx@1.0.1(acorn@8.18.0): + dependencies: + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) + estree-util-to-js: 2.0.0 + recma-parse: 1.0.0 + recma-stringify: 1.0.0 + unified: 11.0.5 + + recma-parse@1.0.0: + dependencies: + '@types/estree': 1.0.9 + esast-util-from-js: 2.0.1 + unified: 11.0.5 + vfile: 6.0.3 + + recma-stringify@1.0.0: + dependencies: + '@types/estree': 1.0.9 + estree-util-to-js: 2.0.0 + unified: 11.0.5 + vfile: 6.0.3 + + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + + rehype-expressive-code@0.44.1: + dependencies: + expressive-code: 0.44.1 + + rehype-format@5.0.1: + dependencies: + '@types/hast': 3.0.5 + hast-util-format: 1.1.0 + + rehype-parse@9.0.1: + dependencies: + '@types/hast': 3.0.5 + hast-util-from-html: 2.0.3 + unified: 11.0.5 + + rehype-raw@7.0.0: + dependencies: + '@types/hast': 3.0.5 + hast-util-raw: 9.1.0 + vfile: 6.0.3 + + rehype-recma@1.0.0: + dependencies: + '@types/estree': 1.0.9 + '@types/hast': 3.0.5 + hast-util-to-estree: 3.1.3 + transitivePeerDependencies: + - supports-color + + rehype-stringify@10.0.1: + dependencies: + '@types/hast': 3.0.5 + hast-util-to-html: 9.0.5 + unified: 11.0.5 + + rehype@13.0.2: + dependencies: + '@types/hast': 3.0.5 + rehype-parse: 9.0.1 + rehype-stringify: 10.0.1 + unified: 11.0.5 + + remark-directive@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-directive: 3.1.0 + micromark-extension-directive: 4.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-mdx@3.1.1: + dependencies: + mdast-util-mdx: 3.0.0 + micromark-extension-mdxjs: 3.0.0 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-smartypants@3.0.3: + dependencies: + retext: 9.0.0 + retext-smartypants: 6.2.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + resolve-pkg-maps@1.0.0: {} + + retext-latin@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + parse-latin: 7.0.0 + unified: 11.0.5 + + retext-smartypants@6.2.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unist-util-visit: 5.1.0 + + retext-stringify@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unified: 11.0.5 + + retext@9.0.0: + dependencies: + '@types/nlcst': 2.0.3 + retext-latin: 4.0.0 + retext-stringify: 4.0.0 + unified: 11.0.5 + + rolldown@1.2.1: + dependencies: + '@oxc-project/types': 0.142.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.2.1 + '@rolldown/binding-darwin-arm64': 1.2.1 + '@rolldown/binding-darwin-x64': 1.2.1 + '@rolldown/binding-freebsd-x64': 1.2.1 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.1 + '@rolldown/binding-linux-arm64-gnu': 1.2.1 + '@rolldown/binding-linux-arm64-musl': 1.2.1 + '@rolldown/binding-linux-ppc64-gnu': 1.2.1 + '@rolldown/binding-linux-s390x-gnu': 1.2.1 + '@rolldown/binding-linux-x64-gnu': 1.2.1 + '@rolldown/binding-linux-x64-musl': 1.2.1 + '@rolldown/binding-openharmony-arm64': 1.2.1 + '@rolldown/binding-wasm32-wasi': 1.2.1 + '@rolldown/binding-win32-arm64-msvc': 1.2.1 + '@rolldown/binding-win32-x64-msvc': 1.2.1 + + satteri@0.9.5: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + optionalDependencies: + '@bruits/satteri-darwin-arm64': 0.9.5 + '@bruits/satteri-darwin-x64': 0.9.5 + '@bruits/satteri-linux-arm64-gnu': 0.9.5 + '@bruits/satteri-linux-arm64-musl': 0.9.5 + '@bruits/satteri-linux-x64-gnu': 0.9.5 + '@bruits/satteri-linux-x64-musl': 0.9.5 + '@bruits/satteri-wasm32-wasi': 0.9.5 + '@bruits/satteri-win32-arm64-msvc': 0.9.5 + '@bruits/satteri-win32-x64-msvc': 0.9.5 + + sax@1.6.1: {} + + semver@7.8.5: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + + shiki@4.4.1: + dependencies: + '@shikijs/core': 4.4.1 + '@shikijs/engine-javascript': 4.4.1 + '@shikijs/engine-oniguruma': 4.4.1 + '@shikijs/langs': 4.4.1 + '@shikijs/themes': 4.4.1 + '@shikijs/types': 4.4.1 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + sisteransi@1.0.5: {} + + sitemap@9.0.1: + dependencies: + '@types/node': 24.13.3 + '@types/sax': 1.2.7 + arg: 5.0.2 + sax: 1.6.1 + + smol-toml@1.7.1: {} + + source-map-js@1.2.1: {} + + source-map@0.7.6: {} + + space-separated-tokens@2.0.2: {} + + stream-replace-string@2.0.0: {} + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + + svgo@4.0.2: + dependencies: + commander: 11.1.0 + css-select: 5.2.2 + css-tree: 3.2.1 + css-what: 6.2.2 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.6.1 + + tiny-inflate@1.0.3: {} + + tinyclip@0.1.15: {} + + tinyexec@1.3.0: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 + + trim-lines@3.0.1: {} + + trough@2.2.0: {} + + tslib@2.8.1: + optional: true + + ufo@1.6.4: {} + + ultrahtml@1.7.0: {} + + uncrypto@0.1.3: {} + + undici-types@7.18.2: {} + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unifont@0.7.4: + dependencies: + css-tree: 3.2.1 + ofetch: 1.5.1 + ohash: 2.0.11 + + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-modify-children@4.0.0: + dependencies: + '@types/unist': 3.0.3 + array-iterate: 2.0.1 + + unist-util-position-from-estree@2.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-remove-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-children@3.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unstorage@1.17.5: + dependencies: + anymatch: 3.1.3 + chokidar: 5.0.0 + destr: 2.0.5 + h3: 1.15.11 + lru-cache: 11.5.2 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.4 + + url-extras@0.1.0: {} + + util-deprecate@1.0.2: {} + + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite@8.2.0(@types/node@24.13.3)(esbuild@0.28.1): + dependencies: + lightningcss: 1.33.0 + picomatch: 4.0.5 + postcss: 8.5.25 + rolldown: 1.2.1 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 24.13.3 + esbuild: 0.28.1 + fsevents: 2.3.3 + + vitefu@1.1.3(vite@8.2.0(@types/node@24.13.3)(esbuild@0.28.1)): + optionalDependencies: + vite: 8.2.0(@types/node@24.13.3)(esbuild@0.28.1) + + web-namespaces@2.0.1: {} + + xxhash-wasm@1.1.0: {} + + yargs-parser@22.0.0: {} + + yocto-queue@1.2.2: {} + + zod@4.4.3: {} + + zwitch@2.0.4: {} diff --git a/docs/pnpm-workspace.yaml b/docs/pnpm-workspace.yaml new file mode 100644 index 0000000..dbb26c8 --- /dev/null +++ b/docs/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +allowBuilds: + esbuild: true + sharp: true diff --git a/docs/public/favicon.png b/docs/public/favicon.png new file mode 100644 index 0000000..449bbdb Binary files /dev/null and b/docs/public/favicon.png differ diff --git a/docs/src/assets/icon.png b/docs/src/assets/icon.png new file mode 100644 index 0000000..449bbdb Binary files /dev/null and b/docs/src/assets/icon.png differ diff --git a/docs/src/components/Classification.astro b/docs/src/components/Classification.astro new file mode 100644 index 0000000..5108b59 --- /dev/null +++ b/docs/src/components/Classification.astro @@ -0,0 +1,154 @@ +--- +import { Icon } from "@astrojs/starlight/components"; + +type Placement = "Foundation" | "Bridge" | "Module"; +type Maturity = "Experimental" | "Incubating" | "Supported"; + +interface Props { + placement: Placement; + concern: string; + maturity: Maturity; +} + +const { placement, concern, maturity } = Astro.props; +--- + + + + diff --git a/docs/src/content.config.ts b/docs/src/content.config.ts new file mode 100644 index 0000000..d9ee8c9 --- /dev/null +++ b/docs/src/content.config.ts @@ -0,0 +1,7 @@ +import { defineCollection } from 'astro:content'; +import { docsLoader } from '@astrojs/starlight/loaders'; +import { docsSchema } from '@astrojs/starlight/schema'; + +export const collections = { + docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }), +}; diff --git a/docs/src/content/docs/concepts/architecture.md b/docs/src/content/docs/concepts/architecture.md new file mode 100644 index 0000000..722c8e7 --- /dev/null +++ b/docs/src/content/docs/concepts/architecture.md @@ -0,0 +1,57 @@ +--- +title: Architecture +description: How Tools & twaddle divides framework-wide responsibilities from optional server features. +--- + +Tools & twaddle is a layer on Minestom, not a replacement for it. Applications continue to create Minestom servers, +inventories, event nodes, and items directly. + +## Dependency direction + +```text +application + โ”œโ”€ depends on โ†’ twaddle-core + โ”œโ”€ depends on โ†’ selected feature modules + โ””โ”€ depends on โ†’ Minestom + +feature module + โ”œโ”€ may depend on โ†’ twaddle-core + โ””โ”€ integrates with โ†’ Minestom + +twaddle-core + โ””โ”€ extends โ†’ Minestom primitives +``` + +The application is the composition root. It chooses modules and controls Minestom initialization. Modules should not +need a central registry merely to exist. + +## What belongs in the foundation + +Foundation code must represent a concern shared by essentially every server or required by many unrelated modules: + +- application lifetime and resource ownership; +- coroutine lifetime; +- framework-wide observability conventions; +- tiny Minestom interoperability helpers. + +Gameplay rules, content systems, persistence, commands, and other optional behavior belong in modules. Their public API +should normally live with the module that owns the concept. + +## Lifecycle model + +`TwaddleContext` is both a `CoroutineScope` and a lifetime owner. Installation code can launch work in that scope, hand +it `AutoCloseable` resources, and create named child contexts with `fork`. A parent shuts down its children alongside +its other owned work, in reverse acquisition order. + +`initialized(server)` exposes the same lifetime as a `TwaddleServerContext`. Modules that run after Minestom starts can +accept that narrower type when they require a `MinecraftServer`. + +Shutdown proceeds in a fixed order: + +1. reject and close newly offered resources; +2. cancel and join lifetime coroutine work; +3. shut down child contexts and close resources in reverse acquisition order; +4. preserve the first close failure and suppress subsequent failures. + +`AfterInit` describes work prepared before Minestom initialization that needs a `MinecraftServer` to finish. It is a +small lifecycle vocabulary type, not a module container. diff --git a/docs/src/content/docs/concepts/classification.md b/docs/src/content/docs/concepts/classification.md new file mode 100644 index 0000000..2712edc --- /dev/null +++ b/docs/src/content/docs/concepts/classification.md @@ -0,0 +1,32 @@ +--- +title: Capability classification +description: A practical vocabulary for locating, describing, and maturing framework capabilities. +--- + +Every capability can be described on three independent axes. A label should answer **where it belongs**, **what it +does**, and **how safe it is to adopt**. + +## 1. Placement + +| Label | Meaning | Dependency expectation | +| --- | --- | --- | +| **Foundation** | Universal process or framework concern | Lives in `twaddle-core` | +| **Bridge** | Small adaptation of a Minestom primitive | Lives in core only when broadly reused; otherwise beside its module | +| **Module** | Optional server or gameplay capability | Separate Gradle module with its own API | + +Placement is about ownership, not importance. A large, essential gameplay system can still be a module. + +## 2. Concern + +Use a concrete domain label such as **Runtime**, **Observability**, **Interop**, or **Gameplay policy**. New labels should +describe a user-visible responsibility rather than an implementation technology. + +## 3. Maturity + +| Label | Promise | +| --- | --- | +| **Experimental** | Works and is tested, but compatibility is not promised | +| **Incubating** | Shape exists, but an important execution path is incomplete | +| **Supported** | Documented behavior with an intentional compatibility policy | + +Nothing is classified as Supported yet. diff --git a/docs/src/content/docs/core/logging.mdx b/docs/src/content/docs/core/logging.mdx new file mode 100644 index 0000000..ef7760e --- /dev/null +++ b/docs/src/content/docs/core/logging.mdx @@ -0,0 +1,49 @@ +--- +title: Structured logging +description: Lazy SLF4J messages with key-value fields for Kotlin and Java. +--- + +import Classification from '../../../components/Classification.astro'; + + + +The logging helpers build on SLF4J 2's event API. They do not select a logging backend; the application provides one at +runtime. + +## Kotlin API + +Create a logger for the calling class and attach structured fields with the `field` infix function: + +```kotlin +import org.everbuild.twaddle.core.logging.field +import org.everbuild.twaddle.core.logging.info +import org.everbuild.twaddle.core.logging.logger + +private val log = logger() + +log.info( + "auth" field "online", + "port" field 25565, +) { + "Test server binding" +} +``` + +The message lambda is evaluated only when its level is enabled. `trace`, `debug`, `info`, `warn`, `error`, and the +general `log` function accept fields and an optional throwable. + +Logger construction is also available as `loggerFor()` and `logger(name)`. + +## Java API + +`StructuredLog` exposes static overloads accepting either a `String` or `Supplier`. Create fields with +`LogField.field(key, value)`: + +```java +StructuredLog.info(LOGGER, "Test server binding", + LogField.field("auth", "online"), + LogField.field("port", 25565) +); +``` + +Configure an SLF4J providerโ€”such as Log4j's SLF4J implementationโ€”in the application, not in the foundation library. diff --git a/docs/src/content/docs/core/minestom-helpers.mdx b/docs/src/content/docs/core/minestom-helpers.mdx new file mode 100644 index 0000000..b35b905 --- /dev/null +++ b/docs/src/content/docs/core/minestom-helpers.mdx @@ -0,0 +1,42 @@ +--- +title: Minestom helpers +description: Small interoperability helpers that keep Minestom APIs visible. +--- + +import Classification from '../../../components/Classification.astro'; + + + +## Event listeners + +The typed `listen` extension adds an event listener and returns the same `EventNode`, which keeps listener setup concise +and chainable: + +```kotlin +inventory.eventNode() + .listen { event: InventoryPreClickEvent -> + // Handle the event with its inferred concrete type. + } +``` + +The helper delegates directly to `EventNode.addListener`. It does not introduce a second event bus or change Minestom's +event propagation model. + +## Play packet listeners + +The reified `setPlayListener` extension removes the class token from Kotlin packet-listener setup: + +```kotlin +MinecraftServer.getPacketListenerManager() + .setPlayListener { packet, player -> + // Handle the packet with its concrete type. + } +``` + +This delegates to `PacketListenerManager.setPlayListener(Class, PacketPlayListenerConsumer)`. Like the Minestom method, +it replaces the listener for that packet type; it does not add another listener alongside the existing one. + +:::caution[Not composable] +Do note that this method brutally replaces the existing listener for the given packet type thus disabling any existing listeners and +minestom functionality +::: diff --git a/docs/src/content/docs/core/runtime.mdx b/docs/src/content/docs/core/runtime.mdx new file mode 100644 index 0000000..afc11de --- /dev/null +++ b/docs/src/content/docs/core/runtime.mdx @@ -0,0 +1,89 @@ +--- +title: Core runtime +description: Application lifetime, coroutine ownership, phased work, and deterministic shutdown. +--- + +import Classification from '../../../components/Classification.astro'; + + + +`TwaddleContext` owns coroutine work, resources, and child lifetimes. A root context normally lives as long as the server +application; child contexts can represent the lifetime of one module or feature. + +## Create the root context + +Kotlin applications normally use `runTwaddleApplication { ... }`, which creates the root context and shuts it down when +the application block finishes. Java applications can call `TwaddleContext.root()` and close it with `shutdownNow()` in +a `finally` block. + +## Own resources + +Pass an `AutoCloseable` to `own` as soon as the application creates it: + +```kotlin +val service = context.own(MyService()) +``` + +Resources close in reverse acquisition order. Offering another resource after shutdown has begun closes that resource +immediately and throws `IllegalStateException`, preventing an unowned resource from escaping. + +## Launch lifetime work + +Because `TwaddleContext` implements `CoroutineScope`, work launched on it is cancelled before resources close: + +```kotlin +context.launch { + refreshStateUntilCancelled() +} +``` + +The context uses `Dispatchers.Default` and a named lifetime job. A parent coroutine context can be supplied when the +application needs structured ownership by constructing `TwaddleContextImpl` directly. + +## Create child lifetimes + +`fork(name)` creates a named child context. The parent owns the child and shuts it down in the same reverse order as +other resources: + +```kotlin +val inventoryContext = context.fork("inventory") +inventoryContext.launch { + refreshInventoriesUntilCancelled() +} +``` + +A child can shut down without affecting its parent. Nested names retain their ownership path, such as +`twaddle/inventory/persistence`. `forked(name) { child -> ... }` is the expression form and returns the block's result; +the child remains owned by its parent after the block returns. + +## Add the initialized server + +`initialized(server)` returns a `TwaddleServerContext`. It exposes the supplied `MinecraftServer` and delegates lifetime +ownership to the same underlying context: + +```kotlin +val server = MinecraftServer.init(Auth.Online()) +val serverContext = context.initialized(server) +``` + +Use `TwaddleServerContext` as a module parameter when that module cannot be installed before Minestom initialization. + +## Shut down + +- `shutdown()` is suspending and safe to call more than once. +- Concurrent callers wait for the first shutdown to finish. +- `shutdownNow()` is the blocking Java-friendly adapter. +- `runTwaddleApplication { ... }` constructs and shuts down a context around a suspending application block. + +The application block defines the lifetime. Because `MinecraftServer.start(...)` returns after starting Minestom's +threads, a standalone application must keep the block alive until its shutdown signal arrives. + +## Work that needs Minestom + +`AfterInit` is an alias for a suspending function from `MinecraftServer` to `A`: + +```kotlin +typealias AfterInit = suspend (MinecraftServer) -> A +``` + +Use it when setup can be prepared before `MinecraftServer.init(...)` but can only complete with the initialized server. diff --git a/docs/src/content/docs/getting-started.mdx b/docs/src/content/docs/getting-started.mdx new file mode 100644 index 0000000..8d1cfc6 --- /dev/null +++ b/docs/src/content/docs/getting-started.mdx @@ -0,0 +1,91 @@ +--- +title: Getting started +description: Add the foundation to a Minestom server and give its work an explicit lifetime. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +Publication coordinates are not stable yet. The dependency examples assume your server is a project in this repository +and use its type-safe project accessors. + +Also, make sure you understand [Minestom](https://minestom.net) before continuing as this guide won't cover it. + +## Add the foundation + +Not all Twaddle features need a running core. Look at the page of your feature to see what it needs. + +```kotlin title="build.gradle.kts" +dependencies { + implementation(projects.twaddleCore) +} +``` + +The application lifecycle has four phases: + +1. Twaddle creates the root context. +2. Pre-init modules are installed. +3. Minestom is initialized. +4. Modules that need the server are installed. + + + +Create the server directly and wrap the process lifetime with `runTwaddleApplication`. +When the application block finishes or fails, the context cancels lifetime coroutine work and closes owned resources. +```kotlin +import kotlinx.coroutines.awaitCancellation +import net.minestom.server.Auth +import net.minestom.server.MinecraftServer +import org.everbuild.twaddle.core.runTwaddleApplication + +suspend fun main() = runTwaddleApplication { cx -> + // Install pre-init modules here + + val server = MinecraftServer.init(Auth.Online()) + val serverCx = cx.initialized(server) + + // Pass serverCx to post-init modules here + + server.start("0.0.0.0", 25565) + awaitCancellation() +} +``` + + +Create a TwaddleContext manually and wrap the process lifetime with `try`/`finally`. +```java +import net.minestom.server.Auth; +import net.minestom.server.MinecraftServer; +import org.everbuild.twaddle.core.TwaddleContext; +import java.util.concurrent.CountDownLatch; + +void main() throws InterruptedException { + var cx = TwaddleContext.root(); + + try { + // Install pre-init modules here + + var minecraftServer = MinecraftServer.init(new Auth.Online()); + var serverCx = cx.initialized(minecraftServer); + + // Pass serverCx to post-init modules here + + minecraftServer.start("0.0.0.0", 25565); + new CountDownLatch(1).await(); + } finally { + cx.shutdownNow(); + } +} +``` + + + +The wait after `start(...)` is deliberate. Minestom starts its server threads and returns, while the Twaddle context must +stay alive for as long as those threads do. Replace the indefinite wait with your application's shutdown signal when it +has one. + +## Adopt optional capabilities + +Continue with [Inventory transfer rules](../modules/inventory-transfer/) for the first optional capability. + +:::caution[Experimental API] +Lifecycle names, package boundaries, and module APIs may change while the framework is validated against real servers. +::: diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx new file mode 100644 index 0000000..61d6364 --- /dev/null +++ b/docs/src/content/docs/index.mdx @@ -0,0 +1,55 @@ +--- +title: Tools & twaddle +description: A small, opinionated toolkit for composing Minestom servers without hiding Minestom. +template: splash +--- + +import { Card, CardGrid } from '@astrojs/starlight/components'; +import { Image } from 'astro:assets'; +import icon from '../../assets/icon.png'; + +
+
+ + +
+ An open red toolbox filled with block-built tools +
+
+ + +
+ +

A small kit on purpose.

+

+ The foundation owns process-wide concerns. Modules own gameplay policy. + Take only what your server needs, keep what sticks. +

+ + + + A coroutine-aware context owns long-lived work and closes resources in a predictable order. + + + "Kotlin First, Java friendly." is the philosophy we put into our design. + + + Small conveniences extend Minestom instead of replacing it with another server abstraction. + + + Use these APIs in tandem to your existing server stack. Provide what you have, use what you need. + + +
+
diff --git a/docs/src/content/docs/modules/inventory-transfer.mdx b/docs/src/content/docs/modules/inventory-transfer.mdx new file mode 100644 index 0000000..b45f26a --- /dev/null +++ b/docs/src/content/docs/modules/inventory-transfer.mdx @@ -0,0 +1,123 @@ +--- +title: Inventory transfer rules +description: Resolve conditional slot routing into ordered destination tiers. +--- + +import Classification from '../../../components/Classification.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; + + + +The inventory transfer module describes where an item may be routed during a shift-click transfer. The ruleset itself only +resolves policy. Bind it to an inventory to obtain the Minestom-facing handler. + +## Define a ruleset + +Rules are evaluated from top to bottom. For each slot, the first matching rule that mentions it owns the decision: + + + +```kotlin +val furnaceTransfers = transferRuleset { + blockAt(SLOT_OUTPUT) { region != TransferRegion.OPEN_INVENTORY } + + routeTo(SLOT_FUEL) { + region != TransferRegion.OPEN_INVENTORY && item.material() == Material.COAL + } + blockAt(SLOT_FUEL) { region != TransferRegion.OPEN_INVENTORY } + + routeTo(SLOT_INPUT) { region != TransferRegion.OPEN_INVENTORY } + + vanillaBehaviour() +} +``` + + +```java +var furnaceTransfers = TransferRuleset.builder() + .blockAt(SLOT_OUTPUT, transfer -> transfer.getRegion() != TransferRegion.OPEN_INVENTORY) + .routeTo(SLOT_FUEL, transfer -> transfer.getRegion() != TransferRegion.OPEN_INVENTORY + && transfer.getItem().material() != Material.COAL) + .blockAt(SLOT_FUEL, transfer -> transfer.getRegion() != TransferRegion.OPEN_INVENTORY) + .blockAt(SLOT_INPUT, transfer -> transfer.getRegion() != TransferRegion.OPEN_INVENTORY) + .vanillaBehaviour() + .build(); +``` + + + +This reads as: + +1. never shift-click into the output; +2. prefer the fuel slot for coal; +3. keep non-coal items out of the fuel slot; +4. route everything else from the player to the input; +5. fall back to vanilla container routing for slots that earlier rules did not claim. + +`vanillaBehaviour()` should normally be the last declaration. Items leaving the open inventory are routed through the +player hotbar and then main inventory, both in vanilla reverse order and as one tier. Items leaving the player inventory +scan the open inventory from its first slot to its last. Earlier rules still override this fallback through the normal +first-match semantics. + +This generic fallback covers ordinary open inventories. Equipment, off-hand, and crafting-grid routing will require a +handler bound directly to a player inventory and are not part of this function yet. + +## Resolution semantics + +`resolve(context)` returns a `List>`. The outer list is an ordered set of routing tiers; each inner list is +the selector order for one matching `RouteTo` rule. + +- A matching `RouteTo` claims unclaimed slots and adds a non-empty tier. +- A matching `BlockAt` claims slots without adding a tier. +- A predicate that returns `false` claims nothing. +- Claimed and duplicate slots never appear in later tiers. +- Selector order is preserved. +- Empty and fully blocked rulesets resolve to an empty list. + +The context currently exposes the transfer action, player, inventory, source slot, item, and source region. The only +action currently defined is `SHIFT_CLICK`; regions distinguish the open inventory, player main inventory, and hotbar. + +## Slot selectors + +| Selector | Selection | +| --- | --- | +| `SingleSlot` | One slot index | +| `SlotRange` | Inclusive Java-friendly range, first-to-last or last-to-first | +| `SlotProgression` | Kotlin `IntProgression`, including direction and step | +| `SlotList` | Explicit slot order | + +Kotlin DSL overloads accept a slot index, an `IntProgression`, a `List`, or a selector. Java callers can use +`TransferRuleset.builder()` and the selector companion factories. + +## Bind to an inventory + + + +```kotlin +class FurnaceInventory : Inventory(InventoryType.FURNACE, "Furnace") { + private val transfers = furnaceTransfers.bindTo(this) + + override fun shiftClick(player: Player, slot: Int, button: Int): Boolean = + transfers.shiftClick(player, slot, button) +} +``` + + +```java +public class JavaFurnaceContainer extends Inventory { + private final InventoryTransferHandler transferHandler = RULESET.bindTo(this); + + public JavaFurnaceContainer() { super(InventoryType.FURNACE, "Furnace"); } + + @Override + public boolean shiftClick(@NonNull Player player, int slot, int button) { + return transferHandler.shiftClick(player, slot, button); + } +} +``` + + + +The bound handler translates Minestom window slots into a `TransferContext`, applies the resolved routing tiers, and +updates both the open and player inventories. Within each tier it merges compatible stacks before using empty slots. +Any remainder continues into the next tier. diff --git a/docs/src/styles/custom.css b/docs/src/styles/custom.css new file mode 100644 index 0000000..dfbed04 --- /dev/null +++ b/docs/src/styles/custom.css @@ -0,0 +1,497 @@ +:root { + --px-ink: #121315; + --px-panel: #1b1c1f; + --px-panel-soft: #24262a; + --px-line: #45474e; + --px-paper: #f0ead6; + --px-muted: #adaaa2; + --px-green: #8ebf54; + --px-green-dark: #47723c; + --px-orange: #e85d35; + --px-orange-dark: #8f3023; + --px-gold: #d9b44a; + --px-blue: #65a9bd; + --sl-color-accent-low: #3a2420; + --sl-color-accent: var(--px-orange); + --sl-color-accent-high: #ffd1bd; + --sl-color-white: var(--px-paper); + --sl-color-gray-1: #e4dfd3; + --sl-color-gray-2: var(--px-muted); + --sl-color-gray-3: #85827c; + --sl-color-gray-4: #626166; + --sl-color-gray-5: #44454a; + --sl-color-gray-6: #292a2e; + --sl-color-black: var(--px-ink); + --sl-font: ui-sans-serif, system-ui, sans-serif; + --sl-font-mono: 'Courier New', 'Liberation Mono', monospace; +} + +:root[data-theme='light'] { + --px-ink: #fffaf0; + --px-panel: #fffaf0; + --px-panel-soft: #eee6ce; + --px-line: #aaa393; + --px-paper: #242326; + --px-muted: #5e5b58; + --px-green: #4f7c38; + --px-green-dark: #315628; + --px-orange: #bd472a; + --px-orange-dark: #7a2c21; + --px-gold: #9a701c; + --px-blue: #27798a; + --sl-color-accent-low: #f2d8cc; + --sl-color-accent: var(--px-orange); + --sl-color-accent-high: #6f281f; + --sl-color-white: var(--px-paper); + --sl-color-gray-1: #302f31; + --sl-color-gray-2: #555255; + --sl-color-gray-3: #7c7876; + --sl-color-gray-4: #aaa498; + --sl-color-gray-5: #d5d0c3; + --sl-color-gray-6: #ebe7d5; + --sl-color-gray-7: #f6f0dc; + --sl-color-black: var(--px-ink); +} + +* { + text-decoration-thickness: 2px; + text-underline-offset: 3px; +} + +body { + background-color: var(--sl-color-black); + background-image: + linear-gradient(90deg, color-mix(in srgb, var(--px-line) 13%, transparent) 1px, transparent 1px), + linear-gradient(color-mix(in srgb, var(--px-line) 13%, transparent) 1px, transparent 1px); + background-size: 40px 40px; +} + +::selection { + background: var(--px-orange); + color: #111714; +} + +:where(.header, .sidebar-pane) { + background: color-mix(in srgb, var(--sl-color-black) 97%, transparent); + backdrop-filter: none; +} + +header.header { + border-bottom: 2px solid var(--px-line); +} + +.sidebar-pane { + border-inline-end: 2px solid var(--sl-color-gray-5); +} + +.site-title, +.sidebar-content summary, +.right-sidebar-panel h2, +.sl-markdown-content :is(h1, h2, h3), +.pagination-links a { + font-family: var(--sl-font-mono); +} + +.site-title { + color: var(--px-paper); + font-size: 0.92rem; + font-weight: 900; + letter-spacing: 0.04em; + text-transform: uppercase; +} + +.site-title img { + width: 2rem; + height: 2rem; + object-fit: contain; + filter: drop-shadow(2px 2px 0 color-mix(in srgb, var(--px-orange) 58%, transparent)); +} + +.sidebar-content summary { + color: var(--px-gold); + font-size: 0.7rem; + font-weight: 900; + letter-spacing: 0.1em; + text-transform: uppercase; +} + +.sidebar-content a[aria-current='page'] { + border-inline-start: 3px solid var(--px-orange); + background: var(--sl-color-accent-low); + color: var(--px-paper) !important; + font-weight: 750; +} + +.sidebar-content a[aria-current='page'] * { + color: inherit !important; +} + +.sidebar-content a:hover { + background: color-mix(in srgb, var(--sl-color-accent-low) 65%, transparent); +} + +.sl-markdown-content:has(.landing-shell) { + max-width: none; +} + +main:has(.landing-shell) > .content-panel:has(> .sl-container > h1:only-child) { + display: none; +} + +.landing-shell { + width: min(100%, 74rem); + margin-inline: auto; + padding: clamp(1.5rem, 4vw, 4rem) clamp(0.25rem, 2vw, 1.5rem) 5rem; +} + +.pixel-hero { + display: grid; + grid-template-columns: minmax(0, 1.35fr) minmax(17rem, 0.65fr); + align-items: center; + gap: clamp(2.5rem, 8vw, 7rem); + min-height: 26rem; +} + +.pixel-eyebrow, +.section-label { + margin: 0 0 1rem; + color: var(--px-gold); + font-family: var(--sl-font-mono); + font-size: 0.72rem; + font-weight: 900; + letter-spacing: 0.13em; +} + +.pixel-eyebrow::before, +.section-label::before { + content: '[ '; + color: var(--px-orange); +} + +.pixel-eyebrow::after, +.section-label::after { + content: ' ]'; + color: var(--px-orange); +} + +.pixel-hero h1 { + max-width: 14ch; + margin: 0; + color: var(--px-paper); + font-family: var(--sl-font-mono); + font-size: clamp(2.45rem, 5.5vw, 5rem); + font-weight: 900; + letter-spacing: -0.065em; + line-height: 0.98; +} + +.pixel-lede { + max-width: 42rem; + margin: 1.6rem 0 0; + color: var(--sl-color-gray-2); + font-size: clamp(1rem, 1.7vw, 1.18rem); + line-height: 1.7; +} + +.pixel-actions { + display: flex; + flex-wrap: wrap; + gap: 0.85rem; + margin-top: 2rem; +} + +.pixel-button { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 2.9rem; + border: 2px solid var(--sl-color-gray-3); + padding: 0.7rem 1rem; + color: var(--px-paper); + font-family: var(--sl-font-mono); + font-size: 0.76rem; + font-weight: 900; + letter-spacing: 0.035em; + box-shadow: 4px 4px 0 var(--px-line); + text-decoration: none; + text-transform: uppercase; + transition: translate 80ms steps(2, end), box-shadow 80ms steps(2, end); +} + +.pixel-button--primary { + border-color: var(--px-orange); + background: var(--px-orange); + color: #24130d; + box-shadow: 4px 4px 0 var(--px-orange-dark); +} + +.pixel-button span { + margin-inline-start: 0.75rem; + font-size: 1rem; +} + +.pixel-button:hover { + box-shadow: 2px 2px 0 var(--px-orange-dark); + translate: 2px 2px; +} + +.pixel-button:active { + box-shadow: none; + translate: 4px 4px; +} + +.toolbox-mark { + position: relative; + display: grid; + place-items: center; + width: min(100%, 25rem); + margin-inline: auto; +} + +.toolbox-mark::before { + position: absolute; + inset: 12% 2% 7% 11%; + border: 2px solid var(--px-line); + background-image: radial-gradient(var(--px-orange) 1.5px, transparent 1.5px); + background-size: 16px 16px; + content: ''; + opacity: 0.38; +} + +.toolbox-mark img { + position: relative; + z-index: 1; + display: block; + width: 100%; + height: auto; + filter: drop-shadow(10px 0 0 color-mix(in srgb, var(--px-line) 70%, transparent)) drop-shadow(10px 0 0 color-mix(in srgb, var(--px-line) 70%, transparent)); +} + +.toolbox-mark span { + position: absolute; + z-index: 2; + right: -0.5rem; + bottom: 5%; + border: 2px solid var(--px-gold); + background: var(--px-panel); + padding: 0.4rem 0.55rem; + color: var(--px-gold); + font-family: var(--sl-font-mono); + font-size: 0.62rem; + font-weight: 900; + letter-spacing: 0.08em; + box-shadow: 4px 4px 0 color-mix(in srgb, var(--px-line) 76%, transparent); +} + +.pixel-statusboard { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + margin: 3em 0 clamp(4rem, 8vw, 7rem); + border-block: 2px solid var(--px-line); +} + +.pixel-statusboard span { + padding: 0.85rem 1rem; + color: var(--sl-color-gray-2); + font-family: var(--sl-font-mono); + font-size: 0.72rem; + text-align: center; +} + +.pixel-statusboard span + span { + border-inline-start: 2px solid var(--px-line); +} + +.pixel-statusboard b { + margin-inline-end: 0.45rem; + color: var(--px-gold); + font-weight: 900; +} + +.pixel-statusboard span:first-child b { + color: var(--px-green); +} + +.pixel-statusboard span:last-child b { + color: var(--px-orange); +} + +.landing-section { + margin-top: 4em; +} + +.landing-section > h2, +.stack-section h2 { + max-width: 19ch; + margin: 0; + font-family: var(--sl-font-mono); + font-size: clamp(1.75rem, 3.5vw, 3rem); + letter-spacing: -0.05em; + line-height: 1.08; +} + +.section-intro { + max-width: 42rem; + margin: 1rem 0 2.25rem; + color: var(--sl-color-gray-2); + font-size: 1.05rem; +} + +.card-grid article { + position: relative; + border: 2px solid var(--px-line); + border-radius: 0; + background: var(--px-panel); + box-shadow: 5px 5px 0 color-mix(in srgb, var(--px-line) 68%, transparent); + transition: border-color 100ms steps(2, end), translate 100ms steps(2, end); +} + +.card-grid article:hover { + border-color: var(--px-orange-dark); + translate: 0 -2px; +} + +.card-grid article > p:first-child { + color: var(--px-paper); + font-family: var(--sl-font-mono); + font-weight: 900; +} + +.stack-section { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(18rem, 0.7fr); + align-items: center; + gap: 3rem; + margin-top: clamp(5rem, 10vw, 9rem); + border-top: 2px dashed var(--px-line); + padding-top: clamp(3rem, 6vw, 5rem); +} + +.stack-diagram { + margin: 0; + border: 2px solid var(--px-line); + border-radius: 0; + background: var(--px-panel); + padding: 1.5rem; + box-shadow: 6px 6px 0 var(--px-orange-dark); +} + +.stack-diagram code { + color: var(--px-blue); + font-family: var(--sl-font-mono); + font-size: 0.9rem; + line-height: 1.8; +} + +.sl-markdown-content:not(:has(.landing-shell)) :is(h1, h2, h3) { + font-weight: 900; + letter-spacing: -0.035em; +} + +.sl-markdown-content:not(:has(.landing-shell)) h2 { + border-bottom: 2px solid var(--sl-color-gray-5); + padding-bottom: 0.45rem; +} + +.sl-markdown-content code:not(:where(.not-content *)) { + border: 1px solid var(--sl-color-gray-5); + border-radius: 0; + background: var(--px-panel-soft); +} + +.expressive-code { + filter: drop-shadow(4px 4px 0 color-mix(in srgb, var(--px-line) 65%, transparent)); +} + +.expressive-code :is(.frame, pre), +.sl-markdown-content :is(table, blockquote), +.starlight-aside, +.pagination-links a, +button, +input, +[role='dialog'] { + border-radius: 0 !important; +} + +.sl-markdown-content table { + border: 2px solid var(--sl-color-gray-4); + background: var(--px-panel); +} + +.sl-markdown-content th { + background: var(--sl-color-accent-low); + color: var(--sl-color-accent-high); + font-family: var(--sl-font-mono); + font-size: 0.76rem; + letter-spacing: 0.04em; + text-transform: uppercase; +} + +.starlight-aside { + border-width: 0 0 0 3px; +} + +.pagination-links a { + border: 2px solid var(--px-line); + box-shadow: 4px 4px 0 color-mix(in srgb, var(--px-line) 68%, transparent); +} + +.right-sidebar-panel a[aria-current='true'] { + color: var(--px-orange); +} + +:focus-visible { + outline: 3px solid var(--px-orange); + outline-offset: 3px; +} + +@media (max-width: 62rem) { + .pixel-hero { + grid-template-columns: 1fr 14rem; + gap: 2.5rem; + } + + .toolbox-mark { + width: min(100%, 20rem); + } +} + +@media (max-width: 44rem) { + .landing-shell { + padding-top: 2.25rem; + } + + .pixel-hero { + grid-template-columns: 1fr; + min-height: auto; + } + + .toolbox-mark { + display: none; + } + + .pixel-statusboard, + .stack-section { + grid-template-columns: 1fr; + } + + .pixel-statusboard { + margin-top: 3rem; + } + + .pixel-statusboard span + span { + border-top: 2px solid var(--px-line); + border-inline-start: 0; + } + + .stack-section { + gap: 2rem; + } +} + +@media (prefers-reduced-motion: reduce) { + .pixel-button, + .card-grid article { + transition: none; + } +} diff --git a/docs/tsconfig.json b/docs/tsconfig.json new file mode 100644 index 0000000..8bf91d3 --- /dev/null +++ b/docs/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "astro/tsconfigs/strict", + "include": [".astro/types.d.ts", "**/*"], + "exclude": ["dist"] +} diff --git a/modules/twaddle-transfer-rules/build.gradle.kts b/modules/twaddle-transfer-rules/build.gradle.kts new file mode 100644 index 0000000..8bcc2a6 --- /dev/null +++ b/modules/twaddle-transfer-rules/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("buildsrc.convention.kotlin-jvm") +} + +dependencies { + implementation(libs.minestom) + implementation(projects.twaddleCore) +} + diff --git a/modules/twaddle-transfer-rules/src/main/kotlin/ChooseSlotOrder.kt b/modules/twaddle-transfer-rules/src/main/kotlin/ChooseSlotOrder.kt new file mode 100644 index 0000000..c773ea5 --- /dev/null +++ b/modules/twaddle-transfer-rules/src/main/kotlin/ChooseSlotOrder.kt @@ -0,0 +1,6 @@ +package org.everbuild.trwaddle.inventory_transfer + +enum class ChooseSlotOrder { + FIRST_TO_LAST, + LAST_TO_FIRST, +} \ No newline at end of file diff --git a/modules/twaddle-transfer-rules/src/main/kotlin/InventoryTransferHandler.kt b/modules/twaddle-transfer-rules/src/main/kotlin/InventoryTransferHandler.kt new file mode 100644 index 0000000..5440af1 --- /dev/null +++ b/modules/twaddle-transfer-rules/src/main/kotlin/InventoryTransferHandler.kt @@ -0,0 +1,85 @@ +package org.everbuild.trwaddle.inventory_transfer + +import net.minestom.server.entity.Player +import net.minestom.server.event.EventDispatcher +import net.minestom.server.event.inventory.InventoryClickEvent +import net.minestom.server.inventory.AbstractInventory +import net.minestom.server.inventory.Inventory +import net.minestom.server.inventory.click.ClickType + +private const val HOTBAR_SIZE = 9 + +class InventoryTransferHandler internal constructor( + private val inventory: Inventory, + private val ruleset: TransferRuleset, +) { + fun shiftClick(player: Player, slot: Int, @Suppress("unused") button: Int): Boolean { + val playerInventory = player.getInventory() + val isInWindow = slot in 0 until inventory.size + val sourceSlot = if (isInWindow) slot else slot - inventory.size + val sourceInventory: AbstractInventory = if (isInWindow) inventory else playerInventory + val targetInventory: AbstractInventory = if (isInWindow) playerInventory else inventory + val sourceSize = if (isInWindow) inventory.size else playerInventory.innerSize + if (sourceSlot !in 0 until sourceSize) return reject(player) + + val clicked = sourceInventory.getItemStack(sourceSlot) + if (clicked.isAir) return reject(player) + + val region = when { + isInWindow -> TransferRegion.OPEN_INVENTORY + sourceSlot < HOTBAR_SIZE -> TransferRegion.PLAYER_HOTBAR + else -> TransferRegion.PLAYER_MAIN + } + + // vanillaBehaviour() supplies the generic hotbar/main fallback. Equipment, off-hand, and + // crafting-grid routing can use the same model once PlayerInventory bindings are supported. + val context = TransferContext( + action = TransferAction.SHIFT_CLICK, + player = player, + inventory = inventory, + sourceSlot = sourceSlot, + item = clicked, + region = region, + ) + val transfer = TransferProcessor.plan( + item = clicked, + targetItems = targetInventory.itemStacks.asList(), + destinationTiers = ruleset.resolve(context), + ) + if (!transfer.moved) return reject(player) + + val cursor = playerInventory.cursorItem + transfer.changes.forEach { (destinationSlot, item) -> + targetInventory.setItemStack(destinationSlot, item) + EventDispatcher.call( + InventoryClickEvent( + targetInventory, + player, + destinationSlot, + ClickType.SHIFT_CLICK, + item, + cursor, + ) + ) + } + sourceInventory.setItemStack(sourceSlot, transfer.remainder) + inventory.updateAll(player) + return true + } + + private fun reject(player: Player): Boolean { + inventory.updateAll(player) + return false + } + + companion object { + @JvmStatic + fun bind(inventory: Inventory, ruleset: TransferRuleset): InventoryTransferHandler = + InventoryTransferHandler(inventory, ruleset) + } +} + +private fun Inventory.updateAll(player: Player) { + player.getInventory().update() + update(player) +} diff --git a/modules/twaddle-transfer-rules/src/main/kotlin/SlotSelector.kt b/modules/twaddle-transfer-rules/src/main/kotlin/SlotSelector.kt new file mode 100644 index 0000000..d9499d5 --- /dev/null +++ b/modules/twaddle-transfer-rules/src/main/kotlin/SlotSelector.kt @@ -0,0 +1,52 @@ +package org.everbuild.trwaddle.inventory_transfer + +/** + * Represents a strategy for selecting specific slots within an inventory. + */ +sealed interface SlotSelector { + data class SingleSlot(val slot: Int) : SlotSelector + + /** + * Only for use from Java, use [SlotProgression] in kotlin. + */ + data class SlotRange(val startInclusive: Int, val endInclusive: Int, val order: ChooseSlotOrder) : SlotSelector { + init { + require(startInclusive <= endInclusive) { "Start must be less than or equal to end" } + } + } + + data class SlotProgression(val progression: IntProgression) : SlotSelector + data class SlotList(val slots: IntArray) : SlotSelector { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as SlotList + + return slots.contentEquals(other.slots) + } + + override fun hashCode(): Int { + return slots.contentHashCode() + } + } + + companion object { + @JvmStatic + fun single(slot: Int) = SingleSlot(slot) + + @JvmStatic + fun range(startInclusive: Int, endInclusive: Int, order: ChooseSlotOrder = ChooseSlotOrder.FIRST_TO_LAST) = + SlotRange(startInclusive, endInclusive, order) + + @JvmStatic + fun progression(progression: IntProgression) = SlotProgression(progression) + + @JvmStatic + fun list(slots: IntArray) = SlotList(slots) + } +} + +internal class ContextualSlotSelector( + val select: (TransferContext) -> IntProgression, +) : SlotSelector diff --git a/modules/twaddle-transfer-rules/src/main/kotlin/TransferContext.kt b/modules/twaddle-transfer-rules/src/main/kotlin/TransferContext.kt new file mode 100644 index 0000000..c91b103 --- /dev/null +++ b/modules/twaddle-transfer-rules/src/main/kotlin/TransferContext.kt @@ -0,0 +1,24 @@ +package org.everbuild.trwaddle.inventory_transfer + +import net.minestom.server.entity.Player +import net.minestom.server.inventory.Inventory +import net.minestom.server.item.ItemStack + +enum class TransferAction { + SHIFT_CLICK +} + +enum class TransferRegion { + OPEN_INVENTORY, + PLAYER_MAIN, + PLAYER_HOTBAR, +} + +data class TransferContext( + val action: TransferAction, + val player: Player, + val inventory: Inventory, + val sourceSlot: Int, + val item: ItemStack, + val region: TransferRegion, +) \ No newline at end of file diff --git a/modules/twaddle-transfer-rules/src/main/kotlin/TransferPredicate.kt b/modules/twaddle-transfer-rules/src/main/kotlin/TransferPredicate.kt new file mode 100644 index 0000000..730ed6d --- /dev/null +++ b/modules/twaddle-transfer-rules/src/main/kotlin/TransferPredicate.kt @@ -0,0 +1,10 @@ +package org.everbuild.trwaddle.inventory_transfer + +fun interface TransferPredicate { + fun invoke(context: TransferContext): Boolean + + companion object { + @JvmField + val ALWAYS = TransferPredicate { true } + } +} \ No newline at end of file diff --git a/modules/twaddle-transfer-rules/src/main/kotlin/TransferProcessor.kt b/modules/twaddle-transfer-rules/src/main/kotlin/TransferProcessor.kt new file mode 100644 index 0000000..729bca6 --- /dev/null +++ b/modules/twaddle-transfer-rules/src/main/kotlin/TransferProcessor.kt @@ -0,0 +1,66 @@ +package org.everbuild.trwaddle.inventory_transfer + +import net.minestom.server.item.ItemStack + +internal data class TransferResult( + val remainder: ItemStack, + val changes: Map, +) { + val moved: Boolean + get() = changes.isNotEmpty() +} + +internal object TransferProcessor { + fun plan( + item: ItemStack, + targetItems: List, + destinationTiers: List>, + ): TransferResult { + if (item.isAir) return TransferResult(ItemStack.AIR, emptyMap()) + + val targetState = targetItems.toMutableList() + val changes = linkedMapOf() + var remainder = item + + for (tier in destinationTiers) { + for (slot in tier) { + if (slot !in targetState.indices) continue + + val target = targetState[slot] + if (target.isAir || !remainder.isSimilar(target)) continue + + val available = target.maxStackSize() - target.amount() + if (available <= 0) continue + + val movedAmount = minOf(remainder.amount(), available) + val updatedTarget = target.withAmount(target.amount() + movedAmount) + targetState[slot] = updatedTarget + changes[slot] = updatedTarget + remainder = remainder.afterMoving(movedAmount) + if (remainder.isAir) break + } + + if (remainder.isAir) break + + for (slot in tier) { + if (slot !in targetState.indices || !targetState[slot].isAir) continue + + val movedAmount = minOf(remainder.amount(), remainder.maxStackSize()) + val updatedTarget = remainder.withAmount(movedAmount) + targetState[slot] = updatedTarget + changes[slot] = updatedTarget + remainder = remainder.afterMoving(movedAmount) + if (remainder.isAir) break + } + + if (remainder.isAir) break + } + + return TransferResult(remainder, changes.toMap()) + } +} + +private fun ItemStack.afterMoving(amount: Int): ItemStack { + val remainingAmount = amount() - amount + return if (remainingAmount == 0) ItemStack.AIR else withAmount(remainingAmount) +} diff --git a/modules/twaddle-transfer-rules/src/main/kotlin/TransferRule.kt b/modules/twaddle-transfer-rules/src/main/kotlin/TransferRule.kt new file mode 100644 index 0000000..ba8428f --- /dev/null +++ b/modules/twaddle-transfer-rules/src/main/kotlin/TransferRule.kt @@ -0,0 +1,25 @@ +package org.everbuild.trwaddle.inventory_transfer + +/** + * Rules are evaluated from first to last. + * + * For each destination slot, the first applicable rule containing that slot + * decides whether it is routed to or blocked. Later rules cannot override that + * decision. + * + * Each applicable [TransferRule.RouteTo] forms an ordered routing tier. + */ +sealed interface TransferRule { + val slots: SlotSelector + val onlyIf: TransferPredicate + + data class RouteTo( + override val slots: SlotSelector, + override val onlyIf: TransferPredicate, + ) : TransferRule + + data class BlockAt( + override val slots: SlotSelector, + override val onlyIf: TransferPredicate, + ) : TransferRule +} \ No newline at end of file diff --git a/modules/twaddle-transfer-rules/src/main/kotlin/TransferRuleDsl.kt b/modules/twaddle-transfer-rules/src/main/kotlin/TransferRuleDsl.kt new file mode 100644 index 0000000..9d03147 --- /dev/null +++ b/modules/twaddle-transfer-rules/src/main/kotlin/TransferRuleDsl.kt @@ -0,0 +1,65 @@ +package org.everbuild.trwaddle.inventory_transfer + +@DslMarker +annotation class TransferRulesetDslMarker + +@TransferRulesetDslMarker +class TransferRulesetDsl { + private val rules = mutableListOf() + val always: TransferContext.() -> Boolean = { true } + + fun addRule(rule: TransferRule) { + rules += rule + } + + fun routeTo(slots: SlotSelector, onlyIf: TransferContext.() -> Boolean = always) { + rules += TransferRule.RouteTo(slots, onlyIf) + } + + fun routeTo(slot: Int, onlyIf: TransferContext.() -> Boolean = always) = routeTo( + slots = SlotSelector.SingleSlot(slot), + onlyIf = onlyIf + ) + + fun routeTo(progression: IntProgression, onlyIf: TransferContext.() -> Boolean = always) = routeTo( + slots = SlotSelector.SlotProgression(progression), + onlyIf = onlyIf + ) + + fun routeTo(slots: List, onlyIf: TransferContext.() -> Boolean = always) = routeTo( + slots = SlotSelector.SlotList(slots.toIntArray()), + onlyIf = onlyIf + ) + + fun blockAt(slots: SlotSelector, onlyIf: TransferContext.() -> Boolean = always) { + rules += TransferRule.BlockAt(slots, onlyIf) + } + + fun blockAt(slot: Int, onlyIf: TransferContext.() -> Boolean = always) = blockAt( + slots = SlotSelector.SingleSlot(slot), + onlyIf = onlyIf + ) + + fun blockAt(progression: IntProgression, onlyIf: TransferContext.() -> Boolean = always) = blockAt( + slots = SlotSelector.SlotProgression(progression), + onlyIf = onlyIf + ) + + fun blockAt(slots: List, onlyIf: TransferContext.() -> Boolean = always) = blockAt( + slots = SlotSelector.SlotList(slots.toIntArray()), + onlyIf = onlyIf + ) + + /** + * Adds the generic vanilla container routing as a fallback. + * + * Declare feature-specific routes and blocks before this call so they can claim their slots first. + */ + fun vanillaBehaviour() { + rules.addAll(vanillaBehaviourRules) + } + + internal fun build(): TransferRuleset = TransferRuleset(rules.toList()) +} + +fun transferRuleset(block: TransferRulesetDsl.() -> Unit) = TransferRulesetDsl().apply(block).build() diff --git a/modules/twaddle-transfer-rules/src/main/kotlin/TransferRuleset.kt b/modules/twaddle-transfer-rules/src/main/kotlin/TransferRuleset.kt new file mode 100644 index 0000000..0d383cd --- /dev/null +++ b/modules/twaddle-transfer-rules/src/main/kotlin/TransferRuleset.kt @@ -0,0 +1,86 @@ +package org.everbuild.trwaddle.inventory_transfer + +import net.minestom.server.inventory.Inventory + +class TransferRuleset( + private val rules: List, +) { + fun resolve(context: TransferContext): List> { + val claimedSlots = mutableSetOf() + val routingTiers = mutableListOf>() + + rules.forEach { rule -> + if (!rule.onlyIf.invoke(context)) return@forEach + + val unclaimedSlots = rule.slots + .slotsInOrder(context) + .filter(claimedSlots::add) + .toList() + + if (rule is TransferRule.RouteTo && unclaimedSlots.isNotEmpty()) { + routingTiers += unclaimedSlots + } + } + + return routingTiers + } + + fun bindTo(inventory: Inventory): InventoryTransferHandler = + InventoryTransferHandler.bind(inventory, this) + + class Builder { + private val rules = mutableListOf() + + fun addRule(rule: TransferRule): Builder { + rules += rule + return this + } + + @JvmOverloads + fun routeTo(slots: SlotSelector, onlyIf: TransferPredicate = TransferPredicate.ALWAYS): Builder { + rules += TransferRule.RouteTo(slots, onlyIf) + return this + } + + @JvmOverloads + fun routeTo(slot: Int, onlyIf: TransferPredicate = TransferPredicate.ALWAYS) = routeTo( + slots = SlotSelector.SingleSlot(slot), + onlyIf = onlyIf + ) + + @JvmOverloads + fun blockAt(slots: SlotSelector, onlyIf: TransferPredicate = TransferPredicate.ALWAYS): Builder { + rules += TransferRule.BlockAt(slots, onlyIf) + return this + } + + @JvmOverloads + fun blockAt(slot: Int, onlyIf: TransferPredicate = TransferPredicate.ALWAYS) = blockAt( + slots = SlotSelector.SingleSlot(slot), + onlyIf = onlyIf + ) + + fun vanillaBehaviour(): Builder { + rules.addAll(vanillaBehaviourRules) + return this + } + + fun build(): TransferRuleset = TransferRuleset(rules.toList()) + } + + companion object { + @JvmStatic + fun builder(): Builder = Builder() + } +} + +private fun SlotSelector.slotsInOrder(context: TransferContext): Sequence = when (this) { + is SlotSelector.SingleSlot -> sequenceOf(slot) + is SlotSelector.SlotRange -> when (order) { + ChooseSlotOrder.FIRST_TO_LAST -> (startInclusive..endInclusive).asSequence() + ChooseSlotOrder.LAST_TO_FIRST -> (endInclusive downTo startInclusive).asSequence() + } + is SlotSelector.SlotProgression -> progression.asSequence() + is SlotSelector.SlotList -> slots.asSequence() + is ContextualSlotSelector -> select(context).asSequence() +} diff --git a/modules/twaddle-transfer-rules/src/main/kotlin/Vanilla.kt b/modules/twaddle-transfer-rules/src/main/kotlin/Vanilla.kt new file mode 100644 index 0000000..9b4def1 --- /dev/null +++ b/modules/twaddle-transfer-rules/src/main/kotlin/Vanilla.kt @@ -0,0 +1,28 @@ +package org.everbuild.trwaddle.inventory_transfer + +internal const val PLAYER_HOTBAR_FIRST_SLOT = 0 +internal const val PLAYER_HOTBAR_LAST_SLOT = 8 +internal const val PLAYER_MAIN_FIRST_SLOT = 9 +internal const val PLAYER_MAIN_LAST_SLOT = 35 + +internal val PLAYER_MAIN_INVENTORY = (PLAYER_MAIN_FIRST_SLOT..PLAYER_MAIN_LAST_SLOT).toList().toIntArray() +internal val PLAYER_HOTBAR = (PLAYER_HOTBAR_LAST_SLOT downTo PLAYER_HOTBAR_FIRST_SLOT).toList().toIntArray() + +internal val vanillaBehaviourRules = listOf( + TransferRule.RouteTo( + SlotSelector.SlotList(PLAYER_MAIN_INVENTORY + PLAYER_HOTBAR), + onlyIf = { it.region == TransferRegion.OPEN_INVENTORY } + ), + TransferRule.RouteTo( + ContextualSlotSelector { context -> 0 until context.inventory.size }, + onlyIf = { it.region == TransferRegion.PLAYER_MAIN || it.region == TransferRegion.PLAYER_HOTBAR } + ), + TransferRule.RouteTo( + SlotSelector.SlotList(PLAYER_MAIN_INVENTORY), + onlyIf = { it.region == TransferRegion.PLAYER_HOTBAR } + ), + TransferRule.RouteTo( + SlotSelector.SlotList(PLAYER_HOTBAR), + onlyIf = { it.region == TransferRegion.PLAYER_MAIN } + ), +) \ No newline at end of file diff --git a/modules/twaddle-transfer-rules/src/test/kotlin/TransferRulesetTest.kt b/modules/twaddle-transfer-rules/src/test/kotlin/TransferRulesetTest.kt new file mode 100644 index 0000000..e89fb13 --- /dev/null +++ b/modules/twaddle-transfer-rules/src/test/kotlin/TransferRulesetTest.kt @@ -0,0 +1,399 @@ +package org.everbuild.trwaddle.inventory_transfer + +import de.infix.testBalloon.framework.core.testSuite +import io.kotest.matchers.shouldBe +import net.kyori.adventure.text.Component +import net.minestom.server.MinecraftServer +import net.minestom.server.component.DataComponents +import net.minestom.server.entity.Player +import net.minestom.server.inventory.Inventory +import net.minestom.server.inventory.InventoryType +import net.minestom.server.inventory.PlayerInventory +import net.minestom.server.item.ItemStack +import net.minestom.server.item.Material +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock + +val transferRulesetTests by testSuite("Transfer ruleset") { + test("Rules are evaluated from top to bottom") { + val ruleset = transferRuleset { + routeTo(listOf(3)) { true } + blockAt(listOf(3)) { true } + routeTo(listOf(3, 4)) { true } + } + + ruleset.resolve(transferContext()) shouldBe listOf( + listOf(3), + listOf(4), + ) + } + + test("The first matching rule that mentions a slot claims it") { + val ruleset = transferRuleset { + routeTo(listOf(2, 1)) { true } + routeTo(listOf(1, 3)) { true } + } + + ruleset.resolve(transferContext()) shouldBe listOf( + listOf(2, 1), + listOf(3), + ) + } + + test("Each routing rule creates an ordered routing tier") { + val ruleset = transferRuleset { + routeTo(listOf(8, 6)) { true } + routeTo(listOf(4, 2)) { true } + } + + ruleset.resolve(transferContext()) shouldBe listOf( + listOf(8, 6), + listOf(4, 2), + ) + } + + test("A blocking rule keeps its slots out of every later tier") { + val ruleset = transferRuleset { + blockAt(listOf(2)) { true } + routeTo(listOf(1, 2)) { true } + routeTo(listOf(2, 3)) { true } + } + + ruleset.resolve(transferContext()) shouldBe listOf( + listOf(1), + listOf(3), + ) + } + + test("A matching conditional route overrides a later unconditional block") { + val ruleset = transferRuleset { + routeTo(listOf(4)) { sourceSlot == 9 } + blockAt(listOf(4)) { true } + routeTo(listOf(4, 5)) { true } + } + + ruleset.resolve(transferContext(sourceSlot = 9)) shouldBe listOf( + listOf(4), + listOf(5), + ) + } + + test("A non-matching predicate does not claim its slots") { + val ruleset = transferRuleset { + routeTo(listOf(4)) { sourceSlot == 9 } + routeTo(listOf(4)) { true } + } + + ruleset.resolve(transferContext(sourceSlot = 1)) shouldBe listOf(listOf(4)) + } + + test("Duplicate slots are removed from later rules without reordering selectors") { + val ruleset = transferRuleset { + routeTo(listOf(5, 2, 5)) { true } + routeTo(listOf(4, 2, 3, 5, 1)) { true } + } + + ruleset.resolve(transferContext()) shouldBe listOf( + listOf(5, 2), + listOf(4, 3, 1), + ) + } + + test("SingleSlot resolves its one slot") { + val ruleset = rulesetRoutingTo(SlotSelector.SingleSlot(7)) + + ruleset.resolve(transferContext()) shouldBe listOf(listOf(7)) + } + + test("SlotRange resolves in its configured order") { + val ascending = rulesetRoutingTo( + SlotSelector.SlotRange(2, 5, ChooseSlotOrder.FIRST_TO_LAST) + ) + val descending = rulesetRoutingTo( + SlotSelector.SlotRange(2, 5, ChooseSlotOrder.LAST_TO_FIRST) + ) + + ascending.resolve(transferContext()) shouldBe listOf(listOf(2, 3, 4, 5)) + descending.resolve(transferContext()) shouldBe listOf(listOf(5, 4, 3, 2)) + } + + test("SlotProgression preserves direction and step") { + val ruleset = rulesetRoutingTo(SlotSelector.SlotProgression(8 downTo 2 step 3)) + + ruleset.resolve(transferContext()) shouldBe listOf(listOf(8, 5, 2)) + } + + test("SlotList preserves its declared order") { + val ruleset = rulesetRoutingTo(SlotSelector.SlotList(intArrayOf(4, 1, 7))) + + ruleset.resolve(transferContext()) shouldBe listOf(listOf(4, 1, 7)) + } + + test("A built ruleset is unchanged when its builder is modified") { + val builder = TransferRuleset.builder() + builder.routeTo(1) + val built = builder.build() + + builder.routeTo(2) + + built.resolve(transferContext()) shouldBe listOf(listOf(1)) + builder.build().resolve(transferContext()) shouldBe listOf( + listOf(1), + listOf(2), + ) + } + + test("An empty ruleset produces no destinations") { + val ruleset = TransferRuleset.builder().build() + + ruleset.resolve(transferContext()) shouldBe emptyList() + } + + test("A fully blocked ruleset produces no destinations") { + val ruleset = transferRuleset { + blockAt(listOf(1, 2, 3)) { true } + } + + ruleset.resolve(transferContext()) shouldBe emptyList() + } + + test("Shift click moves a remainder through routing tiers in order") { + val fixture = transferFixture() + val cursor = ItemStack.of(Material.DIAMOND) + fixture.playerInventory.cursorItem = cursor + fixture.playerInventory.setItemStack(9, ItemStack.of(Material.STONE, 10)) + fixture.inventory.setItemStack(0, ItemStack.of(Material.STONE, 60)) + val ruleset = transferRuleset { + routeTo(0) { + region == TransferRegion.PLAYER_MAIN && sourceSlot == 9 + } + routeTo(1) { + region == TransferRegion.PLAYER_MAIN && sourceSlot == 9 + } + } + + val handled = ruleset.bindTo(fixture.inventory).shiftClick( + fixture.player, + fixture.inventory.size + 9, + 0, + ) + + handled shouldBe true + fixture.inventory.getItemStack(0) shouldBe ItemStack.of(Material.STONE, 64) + fixture.inventory.getItemStack(1) shouldBe ItemStack.of(Material.STONE, 6) + fixture.playerInventory.getItemStack(9) shouldBe ItemStack.AIR + fixture.playerInventory.cursorItem shouldBe cursor + } + + test("Shift click routes an open inventory source into player inventory slots") { + val fixture = transferFixture() + fixture.inventory.setItemStack(0, ItemStack.of(Material.STONE, 5)) + fixture.playerInventory.setItemStack(8, ItemStack.of(Material.STONE, 63)) + val ruleset = transferRuleset { + routeTo(listOf(8, 9)) { + region == TransferRegion.OPEN_INVENTORY && sourceSlot == 0 + } + } + + val handled = ruleset.bindTo(fixture.inventory).shiftClick(fixture.player, 0, 0) + + handled shouldBe true + fixture.inventory.getItemStack(0) shouldBe ItemStack.AIR + fixture.playerInventory.getItemStack(8) shouldBe ItemStack.of(Material.STONE, 64) + fixture.playerInventory.getItemStack(9) shouldBe ItemStack.of(Material.STONE, 4) + } + + test("A routing tier merges into existing stacks before filling empty slots") { + val fixture = transferFixture() + fixture.playerInventory.setItemStack(9, ItemStack.of(Material.STONE, 10)) + fixture.inventory.setItemStack(1, ItemStack.of(Material.STONE, 60)) + val ruleset = transferRuleset { + routeTo(listOf(0, 1)) { true } + } + + val handled = ruleset.bindTo(fixture.inventory).shiftClick( + fixture.player, + fixture.inventory.size + 9, + 0, + ) + + handled shouldBe true + fixture.inventory.getItemStack(0) shouldBe ItemStack.of(Material.STONE, 6) + fixture.inventory.getItemStack(1) shouldBe ItemStack.of(Material.STONE, 64) + fixture.playerInventory.getItemStack(9) shouldBe ItemStack.AIR + } + + test("Shift click distinguishes hotbar and main inventory source regions") { + val hotbarFixture = transferFixture() + hotbarFixture.playerInventory.setItemStack(3, ItemStack.of(Material.STONE)) + val mainFixture = transferFixture() + mainFixture.playerInventory.setItemStack(10, ItemStack.of(Material.STONE)) + val ruleset = transferRuleset { + routeTo(0) { region == TransferRegion.PLAYER_HOTBAR } + routeTo(1) { region == TransferRegion.PLAYER_MAIN } + } + + ruleset.bindTo(hotbarFixture.inventory).shiftClick( + hotbarFixture.player, + hotbarFixture.inventory.size + 3, + 0, + ) shouldBe true + ruleset.bindTo(mainFixture.inventory).shiftClick( + mainFixture.player, + mainFixture.inventory.size + 10, + 0, + ) shouldBe true + + hotbarFixture.inventory.getItemStack(0) shouldBe ItemStack.of(Material.STONE) + hotbarFixture.inventory.getItemStack(1) shouldBe ItemStack.AIR + mainFixture.inventory.getItemStack(0) shouldBe ItemStack.AIR + mainFixture.inventory.getItemStack(1) shouldBe ItemStack.of(Material.STONE) + } + + test("Shift click leaves the source untouched when no destination accepts the item") { + val fixture = transferFixture() + val source = ItemStack.of(Material.STONE, 5) + fixture.playerInventory.setItemStack(9, source) + fixture.inventory.setItemStack(0, ItemStack.of(Material.STONE, 64)) + val ruleset = transferRuleset { + routeTo(listOf(-1, 0, fixture.inventory.size)) { true } + } + + val handled = ruleset.bindTo(fixture.inventory).shiftClick( + fixture.player, + fixture.inventory.size + 9, + 0, + ) + + handled shouldBe false + fixture.playerInventory.getItemStack(9) shouldBe source + fixture.inventory.getItemStack(0) shouldBe ItemStack.of(Material.STONE, 64) + } + + test("Vanilla behaviour treats hotbar and main as one reverse-order tier") { + val fixture = transferFixture() + fixture.inventory.setItemStack(0, ItemStack.of(Material.STONE, 10)) + fixture.playerInventory.setItemStack(35, ItemStack.of(Material.STONE, 60)) + val ruleset = transferRuleset { + vanillaBehaviour() + } + + ruleset.bindTo(fixture.inventory).shiftClick(fixture.player, 0, 0) shouldBe true + fixture.inventory.getItemStack(0) shouldBe ItemStack.AIR + fixture.playerInventory.getItemStack(35) shouldBe ItemStack.of(Material.STONE, 64) + fixture.playerInventory.getItemStack(9) shouldBe ItemStack.of(Material.STONE, 6) + fixture.playerInventory.getItemStack(8) shouldBe ItemStack.AIR + } + + test("Vanilla behaviour routes player items through the open inventory in ascending order") { + val fixture = transferFixture(InventoryType.FURNACE) + fixture.playerInventory.setItemStack(9, ItemStack.of(Material.STONE, 10)) + fixture.inventory.setItemStack(1, ItemStack.of(Material.STONE, 60)) + val ruleset = transferRuleset { + vanillaBehaviour() + } + + ruleset.bindTo(fixture.inventory).shiftClick( + fixture.player, + fixture.inventory.size + 9, + 0, + ) shouldBe true + + fixture.playerInventory.getItemStack(9) shouldBe ItemStack.AIR + fixture.inventory.getItemStack(1) shouldBe ItemStack.of(Material.STONE, 64) + fixture.inventory.getItemStack(0) shouldBe ItemStack.of(Material.STONE, 6) + fixture.inventory.getItemStack(2) shouldBe ItemStack.AIR + } + + test("Rules declared before vanilla behaviour override its fallback routing") { + val fixture = transferFixture(InventoryType.FURNACE) + fixture.playerInventory.setItemStack(9, ItemStack.of(Material.STONE)) + val ruleset = transferRuleset { + routeTo(2) { region == TransferRegion.PLAYER_MAIN } + vanillaBehaviour() + } + + ruleset.bindTo(fixture.inventory).shiftClick( + fixture.player, + fixture.inventory.size + 9, + 0, + ) shouldBe true + + fixture.inventory.getItemStack(2) shouldBe ItemStack.of(Material.STONE) + fixture.inventory.getItemStack(0) shouldBe ItemStack.AIR + } + + test("Stacks with different components do not merge") { + val fixture = transferFixture(InventoryType.FURNACE) + val namedDiamonds = ItemStack.builder(Material.DIAMOND) + .amount(5) + .set(DataComponents.CUSTOM_NAME, Component.text("Named diamonds")) + .build() + fixture.playerInventory.setItemStack(9, namedDiamonds) + fixture.inventory.setItemStack(0, ItemStack.of(Material.DIAMOND, 60)) + val ruleset = transferRuleset { + vanillaBehaviour() + } + + ruleset.bindTo(fixture.inventory).shiftClick( + fixture.player, + fixture.inventory.size + 9, + 0, + ) shouldBe true + + fixture.playerInventory.getItemStack(9) shouldBe ItemStack.AIR + fixture.inventory.getItemStack(0) shouldBe ItemStack.of(Material.DIAMOND, 60) + fixture.inventory.getItemStack(1) shouldBe namedDiamonds + } + + test("Custom maximum stack size leaves the correct remainder for the next slot") { + val fixture = transferFixture(InventoryType.FURNACE) + val customStack = ItemStack.builder(Material.DIAMOND) + .set(DataComponents.MAX_STACK_SIZE, 99) + .build() + fixture.playerInventory.setItemStack(9, customStack.withAmount(20)) + fixture.inventory.setItemStack(0, customStack.withAmount(90)) + val ruleset = transferRuleset { + vanillaBehaviour() + } + + ruleset.bindTo(fixture.inventory).shiftClick( + fixture.player, + fixture.inventory.size + 9, + 0, + ) shouldBe true + + fixture.playerInventory.getItemStack(9) shouldBe ItemStack.AIR + fixture.inventory.getItemStack(0) shouldBe customStack.withAmount(99) + fixture.inventory.getItemStack(1) shouldBe customStack.withAmount(11) + } +} + +private fun rulesetRoutingTo(selector: SlotSelector): TransferRuleset = + TransferRuleset.builder().apply { + routeTo(selector) + }.build() + +private fun transferContext(sourceSlot: Int = 0): TransferContext = mock { + on { this.sourceSlot } doReturn sourceSlot +} + +private data class TransferFixture( + val inventory: Inventory, + val playerInventory: PlayerInventory, + val player: Player, +) + +private fun transferFixture(inventoryType: InventoryType = InventoryType.CHEST_1_ROW): TransferFixture { + if (MinecraftServer.process() == null) MinecraftServer.init() + + val playerInventory = PlayerInventory() + val player = mock { + on { inventory } doReturn playerInventory + } + return TransferFixture( + inventory = Inventory(inventoryType, "Transfer test"), + playerInventory = playerInventory, + player = player, + ) +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 278ac25..0a0f483 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,20 +5,21 @@ dependencyResolutionManagement { } } +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") + plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } include(":twaddle-core") -includeImmediateChildren("modules", "module") +includeImmediateChildren("modules") include(":testserver") -fun includeImmediateChildren(path: String, prefix: String) { - File(path).listFiles()?.forEach { file -> - if (file.isDirectory) { - include(":$path:${file.name}") - } - } +fun includeImmediateChildren(path: String) { + File(path) + .listFiles() + ?.filter { it.isDirectory } + ?.forEach { file -> include(":$path:${file.name}") } } -rootProject.name = "tools-and-twaddle" \ No newline at end of file +rootProject.name = "tools-and-twaddle" diff --git a/testserver/build.gradle.kts b/testserver/build.gradle.kts index a725a20..7f09b62 100644 --- a/testserver/build.gradle.kts +++ b/testserver/build.gradle.kts @@ -7,5 +7,7 @@ dependencies { implementation(libs.minestom) implementation(libs.kotlinx.coroutines) runtimeOnly(libs.bundles.log4j.runtime) - implementation(project(":twaddle-core")) + + implementation(projects.twaddleCore) + implementation(projects.modules.twaddleTransferRules) } \ No newline at end of file diff --git a/testserver/src/main/java/org/everbuild/twaddle/testserver_java/JavaFurnaceContainer.java b/testserver/src/main/java/org/everbuild/twaddle/testserver_java/JavaFurnaceContainer.java new file mode 100644 index 0000000..87892d0 --- /dev/null +++ b/testserver/src/main/java/org/everbuild/twaddle/testserver_java/JavaFurnaceContainer.java @@ -0,0 +1,36 @@ +package org.everbuild.twaddle.testserver_java; + +import net.minestom.server.entity.Player; +import net.minestom.server.inventory.Inventory; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import org.everbuild.trwaddle.inventory_transfer.InventoryTransferHandler; +import org.everbuild.trwaddle.inventory_transfer.TransferRegion; +import org.everbuild.trwaddle.inventory_transfer.TransferRuleset; +import org.jspecify.annotations.NonNull; + +public class JavaFurnaceContainer extends Inventory { + private static final int SLOT_INPUT = 0; + private static final int SLOT_FUEL = 1; + private static final int SLOT_OUTPUT = 2; + + private static final TransferRuleset RULESET = TransferRuleset.builder() + .blockAt(SLOT_OUTPUT, transfer -> transfer.getRegion() != TransferRegion.OPEN_INVENTORY) + .routeTo(SLOT_FUEL, transfer -> transfer.getRegion() != TransferRegion.OPEN_INVENTORY + && transfer.getItem().material() != Material.COAL) + .blockAt(SLOT_FUEL, transfer -> transfer.getRegion() != TransferRegion.OPEN_INVENTORY) + .blockAt(SLOT_INPUT, transfer -> transfer.getRegion() != TransferRegion.OPEN_INVENTORY) + .vanillaBehaviour() + .build(); + + private final InventoryTransferHandler transferHandler = RULESET.bindTo(this); + + public JavaFurnaceContainer() { + super(InventoryType.FURNACE, "Furnace"); + } + + @Override + public boolean shiftClick(@NonNull Player player, int slot, int button) { + return transferHandler.shiftClick(player, slot, button); + } +} diff --git a/testserver/src/main/java/org/everbuild/twaddle/testserver_java/JavaTwaddleTestserver.java b/testserver/src/main/java/org/everbuild/twaddle/testserver_java/JavaTwaddleTestserver.java index 49af68e..e8e3a7f 100644 --- a/testserver/src/main/java/org/everbuild/twaddle/testserver_java/JavaTwaddleTestserver.java +++ b/testserver/src/main/java/org/everbuild/twaddle/testserver_java/JavaTwaddleTestserver.java @@ -2,17 +2,19 @@ import net.minestom.server.Auth; import net.minestom.server.MinecraftServer; -import org.everbuild.twaddle.core.TwaddleContext; +import org.everbuild.twaddle.core.TwaddleContextImpl; import org.everbuild.twaddle.core.logging.LogField; import org.everbuild.twaddle.core.logging.StructuredLog; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.concurrent.CountDownLatch; + class JavaTwaddleTestserver { private static final Logger LOGGER = LoggerFactory.getLogger(JavaTwaddleTestserver.class); - static void main() { - var cx = new TwaddleContext(); + static void main() throws InterruptedException { + var cx = new TwaddleContextImpl(); try { var minecraftServer = MinecraftServer.init(new Auth.Online()); @@ -22,6 +24,7 @@ static void main() { ); minecraftServer.start("0.0.0.0", 25565); + new CountDownLatch(1).await(); } finally { cx.shutdownNow(); } diff --git a/testserver/src/main/kotlin/org/everbuild/twaddle/testserver/FurnaceContainer.kt b/testserver/src/main/kotlin/org/everbuild/twaddle/testserver/FurnaceContainer.kt new file mode 100644 index 0000000..f4ed14c --- /dev/null +++ b/testserver/src/main/kotlin/org/everbuild/twaddle/testserver/FurnaceContainer.kt @@ -0,0 +1,32 @@ +package org.everbuild.twaddle.testserver + +import net.minestom.server.entity.Player +import net.minestom.server.inventory.Inventory +import net.minestom.server.inventory.InventoryType +import net.minestom.server.item.Material +import org.everbuild.trwaddle.inventory_transfer.TransferRegion +import org.everbuild.trwaddle.inventory_transfer.transferRuleset + +class FurnaceContainer : Inventory(InventoryType.FURNACE, "Furnace") { + private val transfers = ruleset.bindTo(this) + + override fun shiftClick(player: Player, slot: Int, button: Int): Boolean = + transfers.shiftClick(player, slot, button) + + companion object { + const val SLOT_INPUT = 0 + const val SLOT_FUEL = 1 + const val SLOT_OUTPUT = 2 + + val ruleset = transferRuleset { + blockAt(SLOT_OUTPUT) { region != TransferRegion.OPEN_INVENTORY } + + routeTo(SLOT_FUEL) { region != TransferRegion.OPEN_INVENTORY && item.material() == Material.COAL } + blockAt(SLOT_FUEL) { region != TransferRegion.OPEN_INVENTORY } + + routeTo(SLOT_INPUT) { region != TransferRegion.OPEN_INVENTORY } + + vanillaBehaviour() + } + } +} diff --git a/testserver/src/main/kotlin/org/everbuild/twaddle/testserver/TwaddleTestserver.kt b/testserver/src/main/kotlin/org/everbuild/twaddle/testserver/TwaddleTestserver.kt index c28f56d..46bf7db 100644 --- a/testserver/src/main/kotlin/org/everbuild/twaddle/testserver/TwaddleTestserver.kt +++ b/testserver/src/main/kotlin/org/everbuild/twaddle/testserver/TwaddleTestserver.kt @@ -3,17 +3,90 @@ package org.everbuild.twaddle.testserver import net.minestom.server.Auth import net.minestom.server.MinecraftServer import kotlinx.coroutines.awaitCancellation +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.format.NamedTextColor +import net.minestom.server.command.builder.Command +import net.minestom.server.command.builder.arguments.Argument +import net.minestom.server.command.builder.arguments.ArgumentLiteral +import net.minestom.server.component.DataComponents +import net.minestom.server.coordinate.Pos +import net.minestom.server.entity.EquipmentSlot +import net.minestom.server.entity.GameMode +import net.minestom.server.entity.Player +import net.minestom.server.event.player.AsyncPlayerConfigurationEvent +import net.minestom.server.event.player.PlayerGameModeRequestEvent +import net.minestom.server.event.player.PlayerSpawnEvent +import net.minestom.server.event.server.ServerListPingEvent +import net.minestom.server.instance.LightingChunk +import net.minestom.server.instance.block.Block +import net.minestom.server.item.ItemStack +import net.minestom.server.item.Material +import net.minestom.server.network.player.ResolvableProfile +import net.minestom.server.ping.Status +import net.minestom.server.utils.chunk.ChunkSupplier import org.everbuild.twaddle.core.TwaddleContext +import org.everbuild.twaddle.core.TwaddleServerContext import org.everbuild.twaddle.core.logging.field import org.everbuild.twaddle.core.logging.info import org.everbuild.twaddle.core.logging.logger +import org.everbuild.twaddle.core.minestom.listen import org.everbuild.twaddle.core.runTwaddleApplication +import kotlin.time.Duration.Companion.seconds +import kotlin.time.toJavaDuration val logger = logger() -suspend fun main() = runTwaddleApplication { _ -> +class TestCommand : Command("test") { + init { + addSyntax({ sender, _ -> + if (sender !is Player) return@addSyntax + + sender.openInventory(FurnaceContainer()) + }, ArgumentLiteral("furnace-inventory")) + } +} + +suspend fun main() = runTwaddleApplication { cx -> val server = MinecraftServer.init(Auth.Online()) + val instance = MinecraftServer.getInstanceManager().createInstanceContainer() + instance.setGenerator { unit -> + unit.modifier().apply { + fillHeight(0, 64, Block.WHITE_CONCRETE) + fillHeight(64, 65, Block.LIME_STAINED_GLASS) + } + } + + instance.chunkSupplier = { x, y, i -> LightingChunk(x, y, i) } + + MinecraftServer.getCommandManager() + .register(TestCommand()) + + val pngFileBytes = TestCommand::class.java.classLoader.getResourceAsStream("server-icon.png")!!.readAllBytes() + + MinecraftServer.getGlobalEventHandler() + .listen { event: AsyncPlayerConfigurationEvent -> + event.spawningInstance = instance + event.player.respawnPoint = Pos(0.0, 66.0, 0.0) + event.player.gameMode = GameMode.CREATIVE + event.player.permissionLevel = 4 + } + .listen { event: PlayerGameModeRequestEvent -> + event.player.gameMode = event.requestedGameMode + } + .listen { event: ServerListPingEvent -> + event.status = Status.builder() + .favicon(pngFileBytes) + .description( + Component.text("Tools and Twaddle", NamedTextColor.RED) + .append(Component.newline()) + .append( + Component.text("ยป Kotlin Testserver", NamedTextColor.GRAY) + ) + ) + .build() + } + logger.info( "auth" field "online", "port" field 25565, @@ -21,5 +94,7 @@ suspend fun main() = runTwaddleApplication { _ -> "Testserver binding" } + server.start("0.0.0.0", 25565) + awaitCancellation() } diff --git a/testserver/src/main/resources/server-icon.png b/testserver/src/main/resources/server-icon.png new file mode 100644 index 0000000..d86cde6 Binary files /dev/null and b/testserver/src/main/resources/server-icon.png differ diff --git a/twaddle-core/build.gradle.kts b/twaddle-core/build.gradle.kts index 5b72973..c1b6c41 100644 --- a/twaddle-core/build.gradle.kts +++ b/twaddle-core/build.gradle.kts @@ -5,5 +5,5 @@ plugins { dependencies { implementation(libs.minestom) implementation(libs.slf4j) - implementation(libs.kotlinx.coroutines) + api(libs.kotlinx.coroutines) } diff --git a/twaddle-core/src/main/kotlin/TwaddleContext.kt b/twaddle-core/src/main/kotlin/TwaddleContext.kt index 8db6e03..2974c81 100644 --- a/twaddle-core/src/main/kotlin/TwaddleContext.kt +++ b/twaddle-core/src/main/kotlin/TwaddleContext.kt @@ -1,109 +1,44 @@ package org.everbuild.twaddle.core -import kotlinx.coroutines.CompletableDeferred -import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.NonCancellable -import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withContext import net.minestom.server.MinecraftServer -import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.EmptyCoroutineContext /** Work prepared before Minestom initialization and completed afterward. */ typealias AfterInit = suspend (MinecraftServer) -> A -/** Owns resources and coroutine work which live for the complete server lifetime. */ -class TwaddleContext @JvmOverloads constructor( - parentContext: CoroutineContext = EmptyCoroutineContext -) : CoroutineScope { - private val lifetimeJob = Job() - - override val coroutineContext: CoroutineContext = - parentContext + Dispatchers.Default + lifetimeJob + CoroutineName("twaddle") - - private val stateLock = Any() - private val resources = mutableListOf() - private val shutdownComplete = CompletableDeferred() - private var shuttingDown = false +/** A lifetime which owns resources and coroutine work. */ +interface TwaddleContext : CoroutineScope { + fun initialized(server: MinecraftServer): TwaddleServerContext = + TwaddleServerContext(server, this) /** Transfers ownership of [resource] to this context. */ - fun own(resource: A): A { - val accepted = synchronized(stateLock) { - if (shuttingDown) false - else { - resources += resource - true - } - } - - if (accepted) return resource - - val failure = IllegalStateException("TwaddleContext is shutting down") - try { - resource.close() - } catch (closeFailure: Throwable) { - failure.addSuppressed(closeFailure) - } - throw failure - } + fun own(resource: A): A - /** Cancels lifetime work and closes owned resources in reverse acquisition order. */ - suspend fun shutdown() { - val ownedResources = synchronized(stateLock) { - if (shuttingDown) null - else { - shuttingDown = true - resources.asReversed().toList().also { - resources.clear() - } - } - } + /** Creates a named child lifetime which is shut down with this context. */ + fun fork(name: String): TwaddleContext - if (ownedResources == null) { - shutdownComplete.await() - return - } + fun forked(name: String, block: (TwaddleContext) -> T): T = + block(fork(name)) - var failure: Throwable? = null - withContext(NonCancellable) { - lifetimeJob.cancelAndJoin() - ownedResources.forEach { resource -> - try { - resource.close() - } catch (closeFailure: Throwable) { - val previousFailure = failure - if (previousFailure == null) failure = closeFailure - else if (previousFailure !== closeFailure) previousFailure.addSuppressed(closeFailure) - } - } - } + /** Cancels lifetime work and shuts down owned lifetimes in reverse acquisition order. */ + suspend fun shutdown() - val shutdownFailure = failure - if (shutdownFailure == null) { - shutdownComplete.complete(Unit) - } else { - shutdownComplete.completeExceptionally(shutdownFailure) - throw shutdownFailure - } - } + fun shutdownNow() - fun shutdownNow() { - runBlocking { shutdown() } + companion object { + @JvmStatic + fun root(): TwaddleContext = TwaddleContextImpl() } } suspend inline fun runTwaddleApplication(crossinline block: suspend (TwaddleContext) -> Unit) { coroutineScope { - val context = TwaddleContext(this.coroutineContext) + val context: TwaddleContext = TwaddleContextImpl(this.coroutineContext) try { block(context) } finally { context.shutdown() } } -} \ No newline at end of file +} diff --git a/twaddle-core/src/main/kotlin/TwaddleContextImpl.kt b/twaddle-core/src/main/kotlin/TwaddleContextImpl.kt new file mode 100644 index 0000000..12dc248 --- /dev/null +++ b/twaddle-core/src/main/kotlin/TwaddleContextImpl.kt @@ -0,0 +1,128 @@ +package org.everbuild.twaddle.core + +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.NonCancellable +import kotlinx.coroutines.cancelAndJoin +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext +import org.everbuild.twaddle.core.logging.logger +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext + +/** Default [TwaddleContext] implementation. */ +class TwaddleContextImpl private constructor( + parentContext: CoroutineContext, + private val name: String, + private val parent: TwaddleContextImpl?, +) : TwaddleContext { + @JvmOverloads + constructor(parentContext: CoroutineContext = EmptyCoroutineContext) : this(parentContext, "twaddle", null) + + private val lifetimeJob = Job(parentContext[Job.Key]) + private val coroutineName = parent + ?.coroutineContext + ?.get(CoroutineName.Key) + ?.name + ?.let { "$it/$name" } + ?: name + + override val coroutineContext: CoroutineContext = + parentContext + Dispatchers.Default + lifetimeJob + CoroutineName(coroutineName) + + private val stateLock = Any() + private val shutdownActions = mutableListOf Unit>() + private val shutdownComplete = CompletableDeferred() + private var shuttingDown = false + + override fun own(resource: A): A { + val accepted = synchronized(stateLock) { + if (shuttingDown) false + else { + shutdownActions += { resource.close() } + true + } + } + + if (accepted) return resource + + val failure = IllegalStateException("TwaddleContext is shutting down") + try { + resource.close() + } catch (closeFailure: Throwable) { + failure.addSuppressed(closeFailure) + } + throw failure + } + + private fun tree(): String = + parent?.let { "${it.tree()}:$name" } ?: name + + override fun fork(name: String): TwaddleContext { + require(name.isNotBlank()) { "Fork name must not be blank" } + logger.debug("Installing ${tree()}:$name") + + val child = TwaddleContextImpl(coroutineContext, name, this) + val accepted = synchronized(stateLock) { + if (shuttingDown) false + else { + shutdownActions += { child.shutdown() } + true + } + } + + if (accepted) return child + + child.lifetimeJob.cancel() + throw IllegalStateException("TwaddleContext is shutting down") + } + + override suspend fun shutdown() { + val ownedActions = synchronized(stateLock) { + if (shuttingDown) null + else { + shuttingDown = true + shutdownActions.asReversed().toList().also { + shutdownActions.clear() + } + } + } + + if (ownedActions == null) { + shutdownComplete.await() + return + } + + var failure: Throwable? = null + withContext(NonCancellable) { + lifetimeJob.cancelAndJoin() + ownedActions.forEach { shutdown -> + try { + shutdown() + } catch (shutdownFailure: Throwable) { + val previousFailure = failure + if (previousFailure == null) failure = shutdownFailure + else if (previousFailure !== shutdownFailure) previousFailure.addSuppressed(shutdownFailure) + } + } + } + + val shutdownFailure = failure + if (shutdownFailure == null) { + shutdownComplete.complete(Unit) + } else { + shutdownComplete.completeExceptionally(shutdownFailure) + throw shutdownFailure + } + } + + override fun shutdownNow() { + runBlocking { shutdown() } + } + + companion object { + private val logger = logger() + } +} \ No newline at end of file diff --git a/twaddle-core/src/main/kotlin/TwaddleServerContext.kt b/twaddle-core/src/main/kotlin/TwaddleServerContext.kt new file mode 100644 index 0000000..984f2a5 --- /dev/null +++ b/twaddle-core/src/main/kotlin/TwaddleServerContext.kt @@ -0,0 +1,8 @@ +package org.everbuild.twaddle.core + +import net.minestom.server.MinecraftServer + +class TwaddleServerContext( + val server: MinecraftServer, + context: TwaddleContext, +) : TwaddleContext by context \ No newline at end of file diff --git a/twaddle-core/src/main/kotlin/minestom/EventExtensions.kt b/twaddle-core/src/main/kotlin/minestom/EventExtensions.kt new file mode 100644 index 0000000..f50c99a --- /dev/null +++ b/twaddle-core/src/main/kotlin/minestom/EventExtensions.kt @@ -0,0 +1,9 @@ +package org.everbuild.twaddle.core.minestom + +import net.minestom.server.event.Event +import net.minestom.server.event.EventNode + +inline fun > V.listen(noinline callback: (T) -> Unit): V { + this.addListener(T::class.java, callback) + return this +} diff --git a/twaddle-core/src/main/kotlin/minestom/PacketListenerExtensions.kt b/twaddle-core/src/main/kotlin/minestom/PacketListenerExtensions.kt new file mode 100644 index 0000000..9de5e7d --- /dev/null +++ b/twaddle-core/src/main/kotlin/minestom/PacketListenerExtensions.kt @@ -0,0 +1,9 @@ +package org.everbuild.twaddle.core.minestom + +import net.minestom.server.listener.manager.PacketListenerManager +import net.minestom.server.listener.manager.PacketPlayListenerConsumer +import net.minestom.server.network.packet.client.ClientPacket + +inline fun PacketListenerManager.setPlayListener(consumer: PacketPlayListenerConsumer) { + setPlayListener(T::class.java, consumer) +} \ No newline at end of file diff --git a/twaddle-core/src/test/kotlin/TwaddleContextTest.kt b/twaddle-core/src/test/kotlin/TwaddleContextTest.kt index 41e8215..0545df9 100644 --- a/twaddle-core/src/test/kotlin/TwaddleContextTest.kt +++ b/twaddle-core/src/test/kotlin/TwaddleContextTest.kt @@ -3,6 +3,7 @@ package org.everbuild.twaddle.core import de.infix.testBalloon.framework.core.testSuite import io.kotest.matchers.shouldBe import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.Job import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.launch @@ -10,7 +11,7 @@ import net.minestom.server.MinecraftServer val twaddleContextTests by testSuite("Twaddle context") { test("Ordinary module functions return their final value") { - val context = TwaddleContext() + val context = TwaddleContextImpl() val resource = OwnedTestResource("direct") val api = context.installDirect(resource) @@ -23,7 +24,7 @@ val twaddleContextTests by testSuite("Twaddle context") { } test("Phased module functions return work requiring an initialized server") { - val context = TwaddleContext() + val context = TwaddleContextImpl() val resource = OwnedTestResource("phased") val prepared = context.preparePhased(resource) @@ -40,7 +41,7 @@ val twaddleContextTests by testSuite("Twaddle context") { } test("Shutdown cancels lifetime work before closing resources") { - val context = TwaddleContext() + val context = TwaddleContextImpl() val events = mutableListOf() val started = CompletableDeferred() context.own(RecordingResource("resource", events)) @@ -61,7 +62,7 @@ val twaddleContextTests by testSuite("Twaddle context") { } test("Shutdown closes resources in reverse order and is idempotent") { - val context = TwaddleContext() + val context = TwaddleContextImpl() val events = mutableListOf() context.own(RecordingResource("first", events)) context.own(RecordingResource("second", events)) @@ -73,7 +74,7 @@ val twaddleContextTests by testSuite("Twaddle context") { } test("A resource offered after shutdown is closed and rejected") { - val context = TwaddleContext() + val context = TwaddleContextImpl() context.shutdown() val resource = OwnedTestResource("late") @@ -82,6 +83,78 @@ val twaddleContextTests by testSuite("Twaddle context") { (result.exceptionOrNull() is IllegalStateException) shouldBe true resource.closed shouldBe true } + + test("Forks are named child contexts owned by their parent") { + val events = mutableListOf() + val parent = TwaddleContextImpl() + parent.own(RecordingResource("parent-first", events)) + val child = parent.fork("inventory") + child.own(RecordingResource("child", events)) + parent.own(RecordingResource("parent-last", events)) + + child.coroutineContext[CoroutineName]?.name shouldBe "twaddle/inventory" + + parent.shutdown() + + events shouldBe listOf("parent-last", "child", "parent-first") + child.coroutineContext[Job]?.isActive shouldBe false + } + + test("A fork can shut down without shutting down its parent") { + val parent = TwaddleContextImpl() + val child = parent.fork("temporary") + + child.shutdown() + + parent.coroutineContext[Job]?.isActive shouldBe true + child.coroutineContext[Job]?.isActive shouldBe false + + parent.shutdown() + } + + test("A context is cancelled with its coroutine parent") { + val parentJob = Job() + val context = TwaddleContextImpl(parentJob) + + parentJob.cancel() + context.coroutineContext[Job]?.join() + + context.coroutineContext[Job]?.isActive shouldBe false + context.shutdown() + } + + test("Nested fork names describe their complete ownership path") { + val parent = TwaddleContextImpl() + val child = parent.fork("inventory") + val grandchild = child.fork("persistence") + + grandchild.coroutineContext[CoroutineName]?.name shouldBe "twaddle/inventory/persistence" + + parent.shutdown() + } + + test("A fork cannot be created after parent shutdown") { + val parent = TwaddleContextImpl() + parent.shutdown() + + val result = runCatching { parent.fork("late") } + + (result.exceptionOrNull() is IllegalStateException) shouldBe true + } + + test("An initialized context enriches the same lifetime with its server") { + val context: TwaddleContext = TwaddleContextImpl() + val server = MinecraftServer() + val initialized = context.initialized(server) + val resource = OwnedTestResource("initialized") + + initialized.server shouldBe server + initialized.own(resource) + initialized.shutdown() + + resource.closed shouldBe true + context.coroutineContext[Job]?.isActive shouldBe false + } } private suspend fun TwaddleContext.installDirect(