From ff96d300d7903fd19a363be022faa3658d012092 Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Mon, 21 Sep 2026 15:27:47 +0200 Subject: [PATCH 1/5] feat(website): Starlight docs site with Callstack-styled landing page and llms.txt --- .github/workflows/website.yaml | 83 + package.json | 3 +- pnpm-lock.yaml | 4527 ++++++++++++++++- pnpm-workspace.yaml | 1 + scripts/check-md-links.mjs | 9 +- website/.gitignore | 2 + website/README.md | 35 + website/astro.config.mjs | 103 + website/ec.config.mjs | 86 + website/llms-page-index.mjs | 58 + website/package.json | 26 + website/public/favicon.svg | 1 + website/public/robots.txt | 4 + website/src/assets/callstack-logo.svg | 1 + website/src/components/CallstackLogo.astro | 22 + website/src/components/Footer.astro | 64 + website/src/components/Head.astro | 12 + website/src/components/Hero.astro | 60 + website/src/components/SiteTitle.astro | 42 + website/src/components/SocialIcons.astro | 35 + website/src/components/ThemeProvider.astro | 13 + website/src/content.config.ts | 7 + website/src/content/docs/guides/agents.mdx | 153 + .../content/docs/guides/build-variants.mdx | 156 + website/src/content/docs/guides/cli.mdx | 238 + website/src/content/docs/guides/security.mdx | 196 + .../src/content/docs/guides/writing-tools.mdx | 265 + .../content/docs/reference/architecture.md | 99 + website/src/content/docs/reference/cli.md | 271 + .../src/content/docs/reference/protocol.md | 288 ++ .../docs/reference/react-native-api.md | 208 + website/src/content/docs/start/android.mdx | 194 + .../src/content/docs/start/introduction.mdx | 54 + website/src/content/docs/start/ios.mdx | 238 + website/src/content/docs/start/playground.mdx | 154 + .../src/content/docs/start/quick-start.mdx | 154 + .../src/content/docs/start/react-native.mdx | 180 + website/src/fonts/Switzer-Light.woff2 | Bin 0 -> 17932 bytes website/src/fonts/Switzer-Medium.woff2 | Bin 0 -> 19564 bytes website/src/fonts/Switzer-Regular.woff2 | Bin 0 -> 16728 bytes website/src/fonts/font-face.css | 26 + website/src/pages/[...slug].md.ts | 19 + website/src/pages/index.astro | 542 ++ website/src/styles/docs.css | 311 ++ website/src/styles/theme.css | 239 + website/tsconfig.json | 5 + 46 files changed, 9166 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/website.yaml create mode 100644 website/.gitignore create mode 100644 website/README.md create mode 100644 website/astro.config.mjs create mode 100644 website/ec.config.mjs create mode 100644 website/llms-page-index.mjs create mode 100644 website/package.json create mode 100644 website/public/favicon.svg create mode 100644 website/public/robots.txt create mode 100644 website/src/assets/callstack-logo.svg create mode 100644 website/src/components/CallstackLogo.astro create mode 100644 website/src/components/Footer.astro create mode 100644 website/src/components/Head.astro create mode 100644 website/src/components/Hero.astro create mode 100644 website/src/components/SiteTitle.astro create mode 100644 website/src/components/SocialIcons.astro create mode 100644 website/src/components/ThemeProvider.astro create mode 100644 website/src/content.config.ts create mode 100644 website/src/content/docs/guides/agents.mdx create mode 100644 website/src/content/docs/guides/build-variants.mdx create mode 100644 website/src/content/docs/guides/cli.mdx create mode 100644 website/src/content/docs/guides/security.mdx create mode 100644 website/src/content/docs/guides/writing-tools.mdx create mode 100644 website/src/content/docs/reference/architecture.md create mode 100644 website/src/content/docs/reference/cli.md create mode 100644 website/src/content/docs/reference/protocol.md create mode 100644 website/src/content/docs/reference/react-native-api.md create mode 100644 website/src/content/docs/start/android.mdx create mode 100644 website/src/content/docs/start/introduction.mdx create mode 100644 website/src/content/docs/start/ios.mdx create mode 100644 website/src/content/docs/start/playground.mdx create mode 100644 website/src/content/docs/start/quick-start.mdx create mode 100644 website/src/content/docs/start/react-native.mdx create mode 100644 website/src/fonts/Switzer-Light.woff2 create mode 100644 website/src/fonts/Switzer-Medium.woff2 create mode 100644 website/src/fonts/Switzer-Regular.woff2 create mode 100644 website/src/fonts/font-face.css create mode 100644 website/src/pages/[...slug].md.ts create mode 100644 website/src/pages/index.astro create mode 100644 website/src/styles/docs.css create mode 100644 website/src/styles/theme.css create mode 100644 website/tsconfig.json diff --git a/.github/workflows/website.yaml b/.github/workflows/website.yaml new file mode 100644 index 00000000..11ff6ce6 --- /dev/null +++ b/.github/workflows/website.yaml @@ -0,0 +1,83 @@ +name: Website + +on: + pull_request: + paths: + - "website/**" + - "docs/**" + - "package.json" + - "pnpm-lock.yaml" + - "pnpm-workspace.yaml" + - ".github/workflows/website.yaml" + push: + branches: [main] + paths: + - "website/**" + - "docs/**" + - "package.json" + - "pnpm-lock.yaml" + - "pnpm-workspace.yaml" + - ".github/workflows/website.yaml" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + # One deploy at a time on main, never cancelled mid-publish; PR builds supersede each other. + group: website-${{ github.event_name == 'pull_request' && github.ref || 'pages' }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Check out source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + # Full history so Starlight's "last updated" dates come from git. + fetch-depth: 0 + - name: Set up pnpm via corepack + # Same setup as lint.yaml: pnpm has to be on PATH before setup-node's `cache: pnpm` runs. + # withastro/action is not used because it installs pnpm its own way, bypassing the + # corepack-pinned pnpm 11 from package.json's packageManager field. + run: | + mkdir -p "$RUNNER_TEMP/corepack" + corepack enable --install-directory "$RUNNER_TEMP/corepack" pnpm + echo "$RUNNER_TEMP/corepack" >> "$GITHUB_PATH" + corepack prepare --activate + - name: Set up Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 24 + cache: pnpm + - name: Install dependencies + run: pnpm install --frozen-lockfile --ignore-scripts + - name: Type-check website + run: pnpm --filter @appduct/website typecheck + - name: Build website + # Also validates every internal docs link (starlight-links-validator) and fails on a broken one. + run: pnpm --filter @appduct/website build + - name: Upload Pages artifact + if: github.event_name != 'pull_request' + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 + with: + path: website/dist + + deploy: + if: github.event_name != 'pull_request' + needs: build + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 diff --git a/package.json b/package.json index 2a63c37a..8ca96e05 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ }, "workspaces": [ "packages/*", - "playground" + "playground", + "website" ], "devDependencies": { "turbo": "^2.8.20", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 76959ade..3e40ec40 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,7 +17,7 @@ importers: version: 2.10.5 vitest: specifier: ^4.1.6 - version: 4.1.10(@types/node@22.20.1)(vite@8.1.4(@types/node@22.20.1)(terser@5.49.0)(yaml@2.9.0)) + version: 4.1.10(@types/node@24.13.6)(vite@8.1.4(@types/node@24.13.6)(esbuild@0.28.2)(terser@5.49.0)(yaml@2.9.0)) packages/appduct: dependencies: @@ -26,7 +26,7 @@ importers: version: link:../shared '@modelcontextprotocol/sdk': specifier: ^1.29.0 - version: 1.29.0(zod@4.4.3) + version: 1.29.0(zod@4.6.5) '@peculiar/x509': specifier: ^2.0.0 version: 2.0.0 @@ -205,6 +205,37 @@ importers: specifier: ~5.9.2 version: 5.9.3 + website: + dependencies: + '@astrojs/markdown-remark': + specifier: ^7.3.1 + version: 7.3.1 + '@astrojs/starlight': + specifier: ^0.42.2 + version: 0.42.2(@astrojs/markdown-remark@7.3.1)(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0))(typescript@5.9.3) + '@fontsource/geist-mono': + specifier: ^5.3.0 + version: 5.3.0 + astro: + specifier: ^7.3.3 + version: 7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0) + sharp: + specifier: ^0.35.4 + version: 0.35.4(@types/node@24.13.6) + starlight-links-validator: + specifier: ^0.26.0 + version: 0.26.0(@astrojs/starlight@0.42.2(@astrojs/markdown-remark@7.3.1)(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0))(typescript@5.9.3))(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0)) + starlight-llms-txt: + specifier: ^0.12.0 + version: 0.12.0(@astrojs/markdown-remark@7.3.1)(@astrojs/markdown-satteri@0.4.1)(@astrojs/starlight@0.42.2(@astrojs/markdown-remark@7.3.1)(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0))(typescript@5.9.3))(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0)) + devDependencies: + '@astrojs/check': + specifier: ^0.9.10 + version: 0.9.10(@emnapi/runtime@1.11.3)(prettier@3.9.5)(typescript@5.9.3) + typescript: + specifier: ~5.9.2 + version: 5.9.3 + packages: '@0no-co/graphql.web@1.3.2': @@ -215,6 +246,142 @@ packages: graphql: optional: true + '@astrojs/astro2tsx@0.1.0': + resolution: {integrity: sha512-tgprkax8mcF+BiHJQBdoQ+REqtvvnLlYzV0yCeLMdcv3pJIutdlinWNHUzN1jMOT5VRlYTtMmDdaoPrtd3cBAQ==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@astrojs/check@0.9.10': + resolution: {integrity: sha512-zgx/UQMozdjOa3bOxjgeCFdtpE3c9rRX6xHwa+2QXvy8z8Akifu2AtubHyv/zzC2znO8dl8fFWL4K+Ba9kS8HQ==} + hasBin: true + peerDependencies: + typescript: ^5.0.0 || ^6.0.0 + + '@astrojs/compiler-binding-android-arm64@0.4.1': + resolution: {integrity: sha512-Wtx2DZORuNTLASLLZ8hlrjFaJe1LUloatcCn9EPq7knBhRpjMGXeJANIJMeBZG4igvz7x+3nyAJM2iwCSW9xog==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@astrojs/compiler-binding-darwin-arm64@0.4.1': + resolution: {integrity: sha512-7iwXcU+hB60Y1SvOfnWHNioT72gDsDQKaDipXh2Onwp/TvQMozhbvhy13wJR8Af940a0h6PbddCeJFpj791UDA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@astrojs/compiler-binding-darwin-x64@0.4.1': + resolution: {integrity: sha512-pifjICos49RXhSVKSDu5gDB0/8j0O7DmxSp1DaWW2PyLG5ekwSkcrfOZto5JqhdI7QYMZB3XOiXpsdOXpS4npA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@astrojs/compiler-binding-linux-arm64-gnu@0.4.1': + resolution: {integrity: sha512-hsZMlNWc6LqWHh9LlSwTq1/XCY7pxA5rkkKIdZRV8mgbOz9OwLvjEoe5Jry13eIZjMUQO8XnQyzk8o/Pjw2YFA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@astrojs/compiler-binding-linux-arm64-musl@0.4.1': + resolution: {integrity: sha512-a3EW27f+Z9uf57vYmpLgUriA1y9wDhKz57PT8D8XlFZt2HZEWhUxKuxI1jvKVI9p8okYee11WXEm/FHY1G9yoQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@astrojs/compiler-binding-linux-x64-gnu@0.4.1': + resolution: {integrity: sha512-XruPTKB/SS4DFzeAjQ1ZyM0ieHDjapHkOSnnzRApZ4FXY2YAI7UY3mETjfJiIS/acyZyrnPH5jObv1gATTdUJQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@astrojs/compiler-binding-linux-x64-musl@0.4.1': + resolution: {integrity: sha512-E8j7lGanqNpudtkUbsFaOLJhmwFe4Ecqux7K9hkj4wULIPNZRM2bYZNcMSj8r1oWvaUiwZl8LaaNwv3+14jqhw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@astrojs/compiler-binding-wasm32-wasi@0.4.1': + resolution: {integrity: sha512-vNLxIv41ZE+nmPFtw24cRW5ZXG+ZPcAGtgigtjCP8lvcxKI7u2GrXoMsCgEH5fMw8WCEJpwLvsVBg15rJKAkyA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@astrojs/compiler-binding-win32-arm64-msvc@0.4.1': + resolution: {integrity: sha512-/xTDgRsFDoTh0/+KFXJ74DY4Jqn8CoSHwa8UP5RAblHfnRHkenwfSl4zYDET61O9vXKLk09UzHjjq09yP20/AQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@astrojs/compiler-binding-win32-x64-msvc@0.4.1': + resolution: {integrity: sha512-0x5J6iHZO0Fjo/CVzoIbXKzWnGESftDbEUQ/oXQ61HhUAFoR7+T1jfToZSNAS+gYyBXHSTpMWYC7lzarbhClcg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@astrojs/compiler-binding@0.4.1': + resolution: {integrity: sha512-ZYVDW1P58OXyxqZbOMp+/2U9KA7y2esIx9r4pWdpZ/l6fCZhaw4ul+D7EgpRVxYLkyTWqzANbTTUFGPFP8zDHA==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@astrojs/compiler-rs@0.4.1': + resolution: {integrity: sha512-//NmAuRhy7eU9iP0ceI5Pymy55M+nUZ//kS6XeOyhBWdDib2KbJOyFaVJ52k7sDkJwTKVox7oPu3SpYiVnGm5A==} + engines: {node: '>=22.12.0'} + + '@astrojs/internal-helpers@0.11.0': + resolution: {integrity: sha512-3rzxJ+xbo0+8YyqOzLziIN32wmsHdCjEVz2sGOpRxJ+Ben/KiLph4ItxBy1abEL+E8fkRzqjg0rfXmaHJGw9JA==} + + '@astrojs/language-server@2.17.0': + resolution: {integrity: sha512-ZvT7UEo7/jBdfjXD3nNYssziEezNKM8G6FUYRnGUidAs7FmowqsQhQ0Xwl5Q4tjqlOjhnpxQuoEb4jwESL+nKQ==} + hasBin: true + peerDependencies: + prettier: ^3.0.0 + prettier-plugin-astro: '>=0.11.0' + peerDependenciesMeta: + prettier: + optional: true + prettier-plugin-astro: + optional: true + + '@astrojs/markdown-remark@7.3.1': + resolution: {integrity: sha512-QCjsjZQl0+Cgb91+T3Ip9hyUe1r5aLm4udi584rML9YO3syupbAYE+jWpAxYg+z4lFLNUugPrylFxZ+8qFTClg==} + + '@astrojs/markdown-satteri@0.4.1': + resolution: {integrity: sha512-EniHbFNa6SQHDih7JnpPos3NWXO6hdt4raBcOosfGmlfc3gP9CI/sESA3VOf1PgJZ7SFfewlZW9Livn0JugEZg==} + + '@astrojs/mdx@8.0.1': + resolution: {integrity: sha512-VKodp/f3+XE6L0950K+ZOAolY47vdt0R78Ao+L2RdJ1hfAdYffL7IEjc/MsoyuS7CPVvCsd5/I3RP0ZyAIewdQ==} + engines: {node: '>=22.12.0'} + peerDependencies: + '@astrojs/markdown-remark': ^7.3.0 + '@astrojs/markdown-satteri': ^0.4.0 + astro: ^7.2.6 + peerDependenciesMeta: + '@astrojs/markdown-remark': + 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.4': + resolution: {integrity: sha512-LbKNC24bdUWcQf/pThB6qLlSqHojxGjZDURIzFocY8rlWnAn2t74nnhnK6S5x0NHriHoAduLEpVjRykmeGiVvA==} + + '@astrojs/starlight@0.42.2': + resolution: {integrity: sha512-rDAgv3QCJOo0F4EoWeuFG31OdhQOrcipATl9+gCkOqpQiO7u7FR8uVam+HHNJO8Sl21TOAQKUSUEvCXv8jEgJA==} + peerDependencies: + '@astrojs/markdown-remark': ^7.3.0 + astro: ^7.2.10 + 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} + + '@astrojs/yaml2ts@0.2.4': + resolution: {integrity: sha512-8oddpOae35pJsXPQXhTkM0ypfKPskVsh2bCxRtbf7e+/Epw2nReakFYpLKjZMEr75CsoF203PMnCocpfz0s69A==} + '@babel/code-frame@7.10.4': resolution: {integrity: sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==} @@ -718,184 +885,435 @@ packages: resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} engines: {node: '>=6.9.0'} + '@bruits/satteri-darwin-arm64@0.10.5': + resolution: {integrity: sha512-27KTVl4TJkVahMy/ohyA7qd4938G5UNneFUz/PsScYfpIhj0IVAS23mpcJXdPF44sa6nva198lmV/cKIb2YPyA==} + cpu: [arm64] + os: [darwin] + + '@bruits/satteri-darwin-x64@0.10.5': + resolution: {integrity: sha512-IjnLe3nKspq6qaeqGgjT7MT8VrTV74yWRlaag7ZdNsI8TDAYZ0iPxMCo+9KQZHUk5EyVB+reBI/PFWL5KuFw9Q==} + cpu: [x64] + os: [darwin] + + '@bruits/satteri-linux-arm64-gnu@0.10.5': + resolution: {integrity: sha512-glkYXZCJywjP13v67eAyAMSJdF+ncvEbYvgi/wOtffL9tQ27lr/zsyzUfgs+ovjJ9d8JNQKiXeiArJcX8PJL9w==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@bruits/satteri-linux-arm64-musl@0.10.5': + resolution: {integrity: sha512-yWdgG1g17Nh2QyGVlFUxGRa3FEFwiMcpZEyMNWkbM3deC94cmVc+/i9OuyFpdKuWo3GkgoCtYVOoxk1uCnCZIA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@bruits/satteri-linux-x64-gnu@0.10.5': + resolution: {integrity: sha512-FVaLoPT1fBgGl0J+AYebyyXJYBachGl8Oyyrf1lye4RTqCB4S0Gwkj1uM9RJyThUOvx5VUmAT1CnNh1SFHA+kw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@bruits/satteri-linux-x64-musl@0.10.5': + resolution: {integrity: sha512-EHpVAx2bqW3GINHTKkljtxVfQmVDGWIuwOYOP5YghTj+0PkBa2o8oKPRtQ9Kbsr1Fye8jtUcDjhwj2jMNugZKg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@bruits/satteri-wasm32-wasi@0.10.5': + resolution: {integrity: sha512-ypz8c/Zmipxp4IoeDa228Gstv6TLzVmNs3yC6wKCoNSOjx1iwpgzu87Y3hTkXFdwChVGU85qeUDuOIarGUZQLw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@bruits/satteri-win32-arm64-msvc@0.10.5': + resolution: {integrity: sha512-siTV88nb0LRqNpkL2gXboqCwVdq95sLtzMHS1/3eONV2gLbB3NAK46wmSMvCO/yquBvI2lvaFIfd8P12ecsxBw==} + cpu: [arm64] + os: [win32] + + '@bruits/satteri-win32-x64-msvc@0.10.5': + resolution: {integrity: sha512-C3IfPvfvMXmlzBxaMPKFS1XiuV9pu2mC7YqkPk7PSvTgPZ8gbdASIpHpztDLvTTQjqZ0z1Ol8tK5X+V6XXC0wQ==} + cpu: [x64] + os: [win32] + + '@capsizecss/unpack@4.0.1': + resolution: {integrity: sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==} + engines: {node: '>=18'} + + '@clack/core@1.5.1': + resolution: {integrity: sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ==} + engines: {node: '>= 20.12.0'} + + '@clack/prompts@1.8.1': + resolution: {integrity: sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ==} + engines: {node: '>= 20.12.0'} + + '@ctrl/tinycolor@4.2.1': + resolution: {integrity: sha512-Vh5uy9Y1JBMId6J1f68TMXnZrTCvNdo9Fu2k0d1YnJngR+sM5kWTKl441c/3TFs+cG0NWOjRWgQ/iaWhbYx+7A==} + engines: {node: '>=14'} + '@egjs/hammerjs@2.0.17': resolution: {integrity: sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==} engines: {node: '>=0.8.0'} + '@emmetio/abbreviation@2.3.3': + resolution: {integrity: sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==} + + '@emmetio/css-abbreviation@2.1.8': + resolution: {integrity: sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==} + + '@emmetio/css-parser@0.4.1': + resolution: {integrity: sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ==} + + '@emmetio/html-matcher@1.3.0': + resolution: {integrity: sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==} + + '@emmetio/scanner@1.0.4': + resolution: {integrity: sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==} + + '@emmetio/stream-reader-utils@0.1.0': + resolution: {integrity: sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==} + + '@emmetio/stream-reader@2.2.0': + resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==} + '@emnapi/core@1.10.0': resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} '@emnapi/core@1.11.1': resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} + '@emnapi/core@1.11.3': + resolution: {integrity: sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==} + '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} '@emnapi/runtime@1.11.1': resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} '@emnapi/wasi-threads@1.2.2': resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} + '@emnapi/wasi-threads@1.2.3': + resolution: {integrity: sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==} + '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.25.12': resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.12': resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.12': resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.12': resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.12': resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.12': resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.12': resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.12': resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.12': resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.25.12': resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.25.12': resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.12': resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.12': resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.12': resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.12': resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.12': resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.12': resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.12': resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.12': resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.12': resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.25.12': resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.12': resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.12': resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.12': resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1044,6 +1462,21 @@ packages: resolution: {integrity: sha512-4aQzz9vgxcNXFfo/iyNgDDYfsU5XGKKxWxZopw0cVotHiW+U8IJbIxMaxsINs6bHhtkG3StKNPcOrn3eBuxKPw==} hasBin: true + '@expressive-code/core@0.44.2': + resolution: {integrity: sha512-Yw5KonQCD1HoOO2P89y4wifqS9qrJcGVY0LkVMUsVZjhi++bhz4WwQ37inenKFNOEVo50P7cjoVsCdaVnUbq8w==} + + '@expressive-code/plugin-frames@0.44.2': + resolution: {integrity: sha512-gVLm6TQMNIRWIaM7o+mCtxkGNjLZY5/2faSTLoXeo9wv/Pkj/0QAtZyXPVPrRsPARqiipATNFmfvQFLJudxPHQ==} + + '@expressive-code/plugin-shiki@0.44.2': + resolution: {integrity: sha512-ebWIvCDzXvjyD8rH6T6DfytYJw1GoArLR4nusIAE4VxXrCQf3d+owytiv010KU/dUg+SRLZskDn0N+HaFXeuSg==} + + '@expressive-code/plugin-text-markers@0.44.2': + resolution: {integrity: sha512-SNI7EgUSiADqbqUzzMbj1ZeC/r2pa5eg3KyFOGAd3a7EsIA4qzjXQLp+ODWQtHVDKFCdGs4J3ovSJUqvKIK96g==} + + '@fontsource/geist-mono@5.3.0': + resolution: {integrity: sha512-UtJ1BBBCVpMYdIcW7nEB45UAoAw5M53ZXs2t0ciPW+IokuAAIc56M8+kW5tXbRJCTpDw4XTtU7proT6NdQAHTg==} + '@hono/node-server@1.19.14': resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} engines: {node: '>=18.14.1'} @@ -1063,6 +1496,168 @@ packages: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.35.4': + resolution: {integrity: sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.35.4': + resolution: {integrity: sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [darwin] + + '@img/sharp-freebsd-wasm32@0.35.4': + resolution: {integrity: sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.3': + resolution: {integrity: sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.3.3': + resolution: {integrity: sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.3.3': + resolution: {integrity: sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.3.3': + resolution: {integrity: sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.3.3': + resolution: {integrity: sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.3.3': + resolution: {integrity: sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.3.3': + resolution: {integrity: sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.3.3': + resolution: {integrity: sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.3.3': + resolution: {integrity: sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.3.3': + resolution: {integrity: sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.35.4': + resolution: {integrity: sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.35.4': + resolution: {integrity: sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==} + engines: {node: '>=20.9.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.35.4': + resolution: {integrity: sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==} + engines: {node: '>=20.9.0'} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.35.4': + resolution: {integrity: sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==} + engines: {node: '>=20.9.0'} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.35.4': + resolution: {integrity: sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==} + engines: {node: '>=20.9.0'} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.35.4': + resolution: {integrity: sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.35.4': + resolution: {integrity: sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.35.4': + resolution: {integrity: sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.35.4': + resolution: {integrity: sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.4': + resolution: {integrity: sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==} + engines: {node: '>=20.9.0'} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.35.4': + resolution: {integrity: sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.35.4': + resolution: {integrity: sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==} + engines: {node: ^20.9.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.35.4': + resolution: {integrity: sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [win32] + '@isaacs/fs-minipass@4.0.1': resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} @@ -1119,9 +1714,15 @@ packages: '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@mdx-js/mdx@3.1.1': + resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} + '@modelcontextprotocol/sdk@1.29.0': resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} engines: {node: '>=18'} @@ -1138,6 +1739,13 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@napi-rs/wasm-runtime@1.2.4': + resolution: {integrity: sha512-AJxoUD2/15ESHbvpcyjU274nsAPLuOtPHCk0vKJM5pj//Fg/B1FXNWjPnXTT9PymCYYiHo4zPj0ZomXBKhoy7g==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + peerDependencies: + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1154,9 +1762,50 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} + '@oslojs/encoding@1.1.0': + resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + '@oxc-project/types@0.139.0': resolution: {integrity: sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==} + '@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] + '@peculiar/asn1-cms@2.8.0': resolution: {integrity: sha512-NgekZOrSJFSBFLFoLfwePguAWAx7z1+f2TEsWFUMyiqqfntZ4+S/S5hzqME3q4pCA0iOsFKdwiQ35dwY24eVqA==} @@ -1645,6 +2294,37 @@ packages: '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@shikijs/core@4.4.3': + resolution: {integrity: sha512-QCR4q2ZO/ILJEuwiBMel4wdcTDb1JGwfjKTxPDF6x8ixOaluPrVqIn06C99AcRPhmYlBR56d/Fb+GN58GzExpg==} + engines: {node: '>=20'} + + '@shikijs/engine-javascript@4.4.3': + resolution: {integrity: sha512-FbOjFJp9VLdo1Wevs10BBtVxiTWwNLqZh5Gkhjgda/ioL15YOgeSl9n+6XMa3qRlPQzfhFNe641SrynFHYG0nQ==} + engines: {node: '>=20'} + + '@shikijs/engine-oniguruma@4.4.3': + resolution: {integrity: sha512-EcOQkxdxGQrc1Row/cC2c96/v1dbZqGnEVu1qTuT/MJmp6+cXCvQussowVmCv5Tqr3KuY3c7IbM6HTW3LJ1k9w==} + engines: {node: '>=20'} + + '@shikijs/langs@4.4.3': + resolution: {integrity: sha512-ePic0yfAJGOF83D5wBHK/00EjK65oahBYxFk5epgq33WRv7X9UuxLEV8PtR0szC0z8dl7INIpIodB99JRFlR+A==} + engines: {node: '>=20'} + + '@shikijs/primitive@4.4.3': + resolution: {integrity: sha512-m0wBeLDQDeIxRdUmrCPdQqfuUamDwRL5isCfYbguKD6NiaKpVbsv+3J81DyIKgNW5h4WAIIr8T4EkgQrBBxvaQ==} + engines: {node: '>=20'} + + '@shikijs/themes@4.4.3': + resolution: {integrity: sha512-w8UHjeUnIR965KMWJHUPXOc2mNJUnK3vpVLYLvw5IYU2mnTTJ89E24OrJDBNiJDQ0qzb0tc4l7mrIXx5cFeIyw==} + engines: {node: '>=20'} + + '@shikijs/types@4.4.3': + resolution: {integrity: sha512-UEJxmRR++MAGR6hugn0vgVS2W/6lWAts84FFSrnlH9sP0LNol7E5+NQ792pH8liWUhyMyjhTgSUH3k7iD7tc5g==} + engines: {node: '>=20'} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@sinclair/typebox@0.27.10': resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} @@ -1702,12 +2382,21 @@ packages: '@types/babel__traverse@7.28.0': resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/braces@3.0.5': + resolution: {integrity: sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w==} + '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} @@ -1717,6 +2406,9 @@ packages: '@types/hammerjs@2.0.46': resolution: {integrity: sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==} + '@types/hast@3.0.5': + resolution: {integrity: sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==} + '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -1726,18 +2418,51 @@ packages: '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/js-yaml@4.0.9': + resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} + '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@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/micromatch@4.0.10': + resolution: {integrity: sha512-5jOhFDElqr4DKTrTEbnW8DZ4Hz5LRUEmyrGpCMrD/NphYv3nUnaF08xmSLx1rGGnyEs/kFnhiw6dCgcDqMr5PQ==} + + '@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@22.20.1': resolution: {integrity: sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==} + '@types/node@24.13.6': + resolution: {integrity: sha512-SGrw/h3KPFshy3OE6ZL53LMBG5vGQQ8/gIpiqz/kRZhPJ7HgwCEs8LBuNtWLa8dvGZVpSF7+Bf+c11HUrCb/yg==} + + '@types/picomatch@4.0.3': + resolution: {integrity: sha512-iG0T6+nYJ9FAPmx9SsUlnwcq1ZVRuCXcVEvWnntoPlrOpwtSTKNDC9uVAxTsC3PUvJ+99n4RpAcNgBbHX3JSnQ==} + '@types/react@19.1.17': resolution: {integrity: sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==} + '@types/sax@1.2.7': + resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} + '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@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==} + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} @@ -1966,6 +2691,32 @@ packages: '@vitest/utils@4.1.10': resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} + '@volar/kit@2.4.28': + resolution: {integrity: sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg==} + peerDependencies: + typescript: '*' + + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + + '@volar/language-server@2.4.28': + resolution: {integrity: sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw==} + + '@volar/language-service@2.4.28': + resolution: {integrity: sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw==} + + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} + + '@volar/typescript@2.4.28': + resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + + '@vscode/emmet-helper@2.11.0': + resolution: {integrity: sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw==} + + '@vscode/l10n@0.0.18': + resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==} + '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} engines: {node: '>=10.0.0'} @@ -2002,6 +2753,14 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + ajv-formats@3.0.1: resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: @@ -2010,12 +2769,21 @@ packages: ajv: optional: true + ajv-i18n@4.2.0: + resolution: {integrity: sha512-v/ei2UkCEeuKNXh8RToiFsUclmU+G57LO1Oo22OagNMENIw+Yb8eMwvHu7Vn9fmkjJyv6XclhJ8TbuigSglPkg==} + peerDependencies: + ajv: ^8.0.0-beta.0 + ajv@6.15.0: resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} ajv@8.20.0: resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + am-i-vibing@0.4.0: + resolution: {integrity: sha512-MxT4XZL7pzLHpuvhDKdMaQHMGGkJDLluKBLsbstn+8wv9sWcFT6h+0ve9qkml95amVTZtZV83gQe2hY+ojgHLg==} + hasBin: true + anser@1.4.10: resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} @@ -2023,6 +2791,10 @@ packages: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} + ansi-escapes@7.3.0: + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} + engines: {node: '>=18'} + ansi-regex@4.1.1: resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} engines: {node: '>=6'} @@ -2031,6 +2803,10 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + ansi-regex@6.3.0: + resolution: {integrity: sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==} + engines: {node: '>=12'} + ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -2043,6 +2819,10 @@ packages: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -2063,6 +2843,10 @@ packages: resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} engines: {node: '>=10'} + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + array-buffer-byte-length@1.0.2: resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} @@ -2071,6 +2855,9 @@ packages: resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} engines: {node: '>= 0.4'} + array-iterate@2.0.1: + resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} + array.prototype.findlast@1.2.5: resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} engines: {node: '>= 0.4'} @@ -2106,6 +2893,25 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + astring@1.9.0: + resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} + hasBin: true + + astro-expressive-code@0.44.2: + resolution: {integrity: sha512-avop7nZcRwC7quvIxVguhwEZ9Tp6IoTzKUCLwP30Fb7+er+pWQgcysP01dcuzRIJo81kLGg30q/YAI2Yb1Sdzg==} + peerDependencies: + astro: ^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta || ^7.0.0 + + astro@7.3.3: + resolution: {integrity: sha512-NF08hk3edFkVmr9avf9HW/rQyf6NrpbVDyYj2cVN3JfijDhfJYh1ivWVTY5PUd5+rRZn/Vtu4iaeyNlP0Iv6mg==} + engines: {node: '>=22.12.0', npm: '>=9.6.5', pnpm: '>=7.1.0'} + hasBin: true + peerDependencies: + '@astrojs/markdown-remark': ^7.3.0 + peerDependenciesMeta: + '@astrojs/markdown-remark': + optional: true + async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} @@ -2117,6 +2923,10 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + babel-jest@29.7.0: resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2181,6 +2991,9 @@ packages: peerDependencies: '@babel/core': ^7.0.0 + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -2196,6 +3009,12 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + 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==} + better-opn@3.0.2: resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} engines: {node: '>=12.0.0'} @@ -2208,6 +3027,9 @@ packages: resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} engines: {node: '>=18'} + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + bplist-creator@0.1.0: resolution: {integrity: sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==} @@ -2282,6 +3104,9 @@ packages: caniuse-lite@1.0.30001805: resolution: {integrity: sha512-52noaS3DubycKSXaU30TwPGIp+POyQSUVa5jBEq3vkRkY0kjyb3LQgvhU6WGyCcyXqVLWO0Cw0Q6BSdD0kUfVA==} + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} @@ -2294,6 +3119,26 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + 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@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + chownr@3.0.0: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} @@ -2313,6 +3158,10 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} + cli-cursor@2.1.0: resolution: {integrity: sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==} engines: {node: '>=4'} @@ -2328,10 +3177,21 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + cliui@9.0.1: + resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} + engines: {node: '>=20'} + clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + collapse-white-space@2.1.0: + resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} + color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -2352,6 +3212,13 @@ packages: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + commander@12.1.0: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} @@ -2367,6 +3234,10 @@ packages: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} + common-ancestor-path@2.0.0: + resolution: {integrity: sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==} + engines: {node: '>= 18'} + compressible@2.0.18: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} engines: {node: '>= 0.6'} @@ -2397,6 +3268,9 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-es@1.2.3: + resolution: {integrity: sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==} + cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} @@ -2405,6 +3279,10 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} + cookie@2.0.1: + resolution: {integrity: sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w==} + engines: {node: '>=22'} + core-js-compat@3.49.0: resolution: {integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==} @@ -2419,9 +3297,39 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + css-in-js-utils@3.1.0: resolution: {integrity: sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==} + css-select@6.0.0: + resolution: {integrity: sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==} + + 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@7.0.0: + resolution: {integrity: sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==} + 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'} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -2462,6 +3370,9 @@ packages: supports-color: optional: true + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + decode-uri-component@0.2.2: resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} engines: {node: '>=0.10'} @@ -2492,10 +3403,20 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -2507,6 +3428,20 @@ packages: detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + devalue@5.9.4: + resolution: {integrity: sha512-sPAT4pztbu6586/hrhOnMKS17IJrvg12mXiSPSS3W5qDeN2RGgvZ0diZCm31dBbnevfVmujNO3IM2wrS4Y2Rhg==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + diff@9.0.0: + resolution: {integrity: sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==} + engines: {node: '>=0.3.1'} + + direction@2.0.1: + resolution: {integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==} + hasBin: true + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -2515,6 +3450,19 @@ packages: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} + 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==} + dotenv-expand@11.0.7: resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} engines: {node: '>=12'} @@ -2523,6 +3471,10 @@ packages: resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} engines: {node: '>=12'} + dset@3.1.4: + resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} + engines: {node: '>=4'} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -2533,6 +3485,12 @@ packages: electron-to-chromium@1.5.392: resolution: {integrity: sha512-1yQq3VQCZRwsnYc67Oc+1fge6Lwtn0hzi6zmEVkB61Zx21kTbwJAW4dFLadl5Rc1tKhG/kSpYXnfiAhu0f0a1g==} + emmet@2.4.11: + resolution: {integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==} + + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2548,10 +3506,22 @@ packages: resolution: {integrity: sha512-rpsZEGT1jFuve6QlpyRp9ckQ+kN61hvF9BzCPyMdaKTm8UJce96KBn3sorXOFXlzjPrs3Vc4T1NsSroZ3PxlFw==} engines: {node: '>=10.13.0'} + 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'} + env-editor@0.4.2: resolution: {integrity: sha512-ObFo8v4rQJAE59M69QzwloxPZtd33TpYEIjtKD1rrFDcM1Gd7IkDxEBU+HriziN6HSHQnBJi8Dmy+JWkav5HKA==} engines: {node: '>=8'} + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + error-stack-parser@2.1.4: resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} @@ -2594,11 +3564,22 @@ packages: resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==} engines: {node: '>= 0.4'} + 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.25.12: resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} engines: {node: '>=18'} hasBin: true + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -2618,6 +3599,10 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + eslint-compat-utils@0.5.1: resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} engines: {node: '>=12'} @@ -2800,6 +3785,24 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + 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.1: + resolution: {integrity: sha512-B0np3dcdxqILX5e9nEi5/Fr4K7gL4oYFVPV1zRa2e9wRCbQoZZNWOZFYyoInvXUPJXBXjss+QXlWLJChDEHDkA==} + + 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@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -2815,6 +3818,9 @@ packages: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + eventsource-parser@3.1.0: resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==} engines: {node: '>=18.0.0'} @@ -2992,6 +3998,12 @@ packages: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} + expressive-code@0.44.2: + resolution: {integrity: sha512-MLNghkvhyFgVW4oCD5DxBuYnnTXIf0PygzGmfT6OZeOOYWh/D4sH1j931biElkA5RG/J9wY/iuSMGAPF5vzHOg==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -3004,9 +4016,18 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + 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-uri@3.1.3: resolution: {integrity: sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==} + fast-wrap-ansi@0.2.2: + resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} + fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -3048,6 +4069,10 @@ packages: resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} engines: {node: '>= 18.0.0'} + find-proc@0.2.0: + resolution: {integrity: sha512-a6h2nTrgB3g5Wrn4au9Ux4kMk7IJtyF6oA8uGn+mk3weLZssUtc1cp6meHIzzuW2o1srrBAxzkmXLbqjRkgB6w==} + engines: {node: ^20.19.0 || >=22.12.0} + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -3063,12 +4088,23 @@ packages: flatted@3.4.2: resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + flattie@1.1.1: + resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} + engines: {node: '>=8'} + flow-enums-runtime@0.0.6: resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} + fontace@0.4.1: + resolution: {integrity: sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==} + fontfaceobserver@2.3.0: resolution: {integrity: sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==} + fontkitten@1.0.3: + resolution: {integrity: sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==} + engines: {node: '>=20'} + for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} @@ -3119,6 +4155,10 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.7.0: + resolution: {integrity: sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==} + engines: {node: '>=18'} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -3142,10 +4182,17 @@ packages: get-tsconfig@4.14.0: resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} + get-tsconfig@5.0.0-beta.4: + resolution: {integrity: sha512-7nF7C9fIPFEMHgEMEfgIlO9wDdZ8CyHw27rWciFZfHvHDReIiPhsYuzPRXsfvBCqFy1l8RRyyWV7QLM+ZhUJsQ==} + engines: {node: '>=20.20.0'} + getenv@2.0.0: resolution: {integrity: sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==} engines: {node: '>=6'} + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} @@ -3187,6 +4234,9 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + h3@1.15.11: + resolution: {integrity: sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==} + has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -3199,6 +4249,10 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-flag@5.0.1: + resolution: {integrity: sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==} + engines: {node: '>=12'} + has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} @@ -3218,6 +4272,69 @@ packages: resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} + 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-mdast@10.1.2: + resolution: {integrity: sha512-FiCRI7NmOvM4y+f5w32jPRzcxDIz+PUqDwEqn1A+1q2cdp3B8Gx7aVrXORdOKjMNDQsD1ogOr896+0jJHW1EFQ==} + + 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==} + hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} @@ -3253,6 +4370,18 @@ packages: resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} engines: {node: ^16.14.0 || >=18.0.0} + 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==} + http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} @@ -3264,6 +4393,14 @@ packages: hyphenate-style-name@1.1.0: resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==} + i18next@26.4.2: + resolution: {integrity: sha512-RX+R0VLg13IbvRuJSxnqykUFS9vQZTl8wYpWPCIUDWVrSGjsQywB5Y+pjzrkboxGAuYfJZVH1InFTdgBdxq6ug==} + peerDependencies: + typescript: ^5 || ^6 || ^7 + peerDependenciesMeta: + typescript: + optional: true + iconv-lite@0.7.3: resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} engines: {node: '>=0.10.0'} @@ -3302,6 +4439,9 @@ packages: ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + inline-style-prefixer@7.0.1: resolution: {integrity: sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==} @@ -3320,6 +4460,19 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + + is-absolute-url@5.0.0: + resolution: {integrity: sha512-sdJyNpBnQHuVnBunfzjAecOhZr2+A30ywfFvu3EnxtKLUWfwGgyWUmqHbGZiU6vTfHpCPm5GvLe4BAvlU9n8VQ==} + engines: {node: '>=20'} + + 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-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -3358,11 +4511,19 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} hasBin: true + is-docker@4.0.0: + resolution: {integrity: sha512-LHE+wROyG/Y/0ZnbktRCoTix2c1RhgWaZraMZ8o1Q7zCh0VSrICJQO5oqIIISrcSBtrXv0o233w1IYwsWCjTzA==} + engines: {node: '>=20'} + hasBin: true + is-document.all@1.0.0: resolution: {integrity: sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==} engines: {node: '>= 0.4'} @@ -3387,6 +4548,9 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} @@ -3407,6 +4571,10 @@ packages: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} @@ -3553,6 +4721,12 @@ packages: engines: {node: '>=6'} hasBin: true + jsonc-parser@2.3.1: + resolution: {integrity: sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==} + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} @@ -3564,6 +4738,14 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} + lan-network@0.2.1: resolution: {integrity: sha512-ONPnazC96VKDntab9j9JKwIWhZ4ZUceB4A9Epu4Ssg0hYFmtHZSeQ+n15nIwTFmcBUKtExOer8WTJ4GF9MO64A==} hasBin: true @@ -3677,6 +4859,9 @@ packages: resolution: {integrity: sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==} engines: {node: '>=4'} + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -3694,9 +4879,22 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magic-string@1.4.1: + resolution: {integrity: sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==} + + magicast@0.5.5: + resolution: {integrity: sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA==} + makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + 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==} + marky@1.3.0: resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} @@ -3704,6 +4902,66 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + 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==} + media-typer@1.1.0: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} @@ -3837,6 +5095,114 @@ packages: engines: {node: '>=20.19.4'} hasBin: true + 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.2: + resolution: {integrity: sha512-pRzm4kDTu0MjlmBkxmS9yYhw60nncfcEwu9NNdPFSQEFXS95ZKyIIyTSHu/o3ReBUrLKYEq+7YaXCRn/bPB4MA==} + + 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==} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -3893,12 +5259,19 @@ packages: engines: {node: '>=10'} hasBin: true + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -3927,13 +5300,23 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} + neotraverse@1.0.1: + resolution: {integrity: sha512-WmmLty1YWwJl9yZi77v2dVIV6X2kuYV8YYBI/G3LWGKdGHmHUvL1z7FW0iDvEvGAwNEoc5x1tOOOyDnf5jJw/w==} + engines: {node: '>= 10'} + nested-error-stacks@2.0.1: resolution: {integrity: sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==} + nlcst-to-string@4.0.0: + resolution: {integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==} + node-exports-info@1.6.2: resolution: {integrity: sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag==} engines: {node: '>= 0.4'} + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -3950,6 +5333,9 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + node-mock-http@1.0.5: + resolution: {integrity: sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw==} + node-releases@2.0.51: resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==} engines: {node: '>=18'} @@ -3962,6 +5348,9 @@ packages: resolution: {integrity: sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==} engines: {node: ^16.14.0 || >=18.0.0} + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nullthrows@1.1.1: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} @@ -4009,6 +5398,12 @@ packages: resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} engines: {node: '>=12.20.0'} + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + + ohash@2.0.12: + resolution: {integrity: sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==} + on-finished@2.3.0: resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} engines: {node: '>= 0.8'} @@ -4028,6 +5423,12 @@ packages: resolution: {integrity: sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==} engines: {node: '>=4'} + 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==} + open@7.4.2: resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} engines: {node: '>=8'} @@ -4056,6 +5457,10 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-limit@7.3.3: + resolution: {integrity: sha512-SKgVvDU5TNIxQ4r30U75BNLC6a+6GOEjngrk/ysM5+Zu3oJuk1SC5ApzIzY/7PjCEjoVPMWJ0zho/4QUiEB7TQ==} + engines: {node: '>=20'} + p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -4064,22 +5469,49 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-queue@9.3.3: + resolution: {integrity: sha512-NXAOdnEe5FsZJfT4oK84lE1Y5cFFdWlRuOo5tww8DyNMxyRXwn39fIkUtNLKppcPC+UYU/bXujNCUGDv01y7CA==} + engines: {node: '>=20'} + + p-timeout@7.0.2: + resolution: {integrity: sha512-prbX4Z3YszrFNgH+MW5Zoeq3baXrMtP/MQnFeET90UB/GtGcGDQ5Usg9OCy6ETjTTntOw1SL2z9fMPUppN3Guw==} + engines: {node: '>=20'} + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + 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 + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse-latin@7.0.0: + resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==} + parse-png@2.1.0: resolution: {integrity: sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==} engines: {node: '>=10'} + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -4105,6 +5537,9 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + piccolore@0.1.3: + resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -4136,6 +5571,16 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} + 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-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} @@ -4168,10 +5613,18 @@ packages: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + proc-log@4.2.0: resolution: {integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + process-ancestry@0.1.0: + resolution: {integrity: sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg==} + engines: {node: '>=18.0.0'} + progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} @@ -4189,6 +5642,9 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + property-information@7.2.0: + resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -4222,6 +5678,9 @@ packages: queue@6.0.2: resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} @@ -4357,6 +5816,28 @@ packages: resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} engines: {node: '>=0.10.0'} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + readdirp@5.1.1: + resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==} + 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==} + reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} @@ -4374,6 +5855,15 @@ packages: regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + 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==} + regexp.prototype.flags@1.5.4: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} @@ -4393,6 +5883,55 @@ packages: resolution: {integrity: sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==} hasBin: true + rehype-expressive-code@0.44.2: + resolution: {integrity: sha512-jvjQpsfWKBquDrEl5YQA3CJybRRIuDOYsui1BJTs5oKDUK8pPkJSSxY8FjxNlIFIdtgrTjC1zuahuY4Cc1j9SQ==} + + rehype-minify-whitespace@6.0.2: + resolution: {integrity: sha512-Zk0pyQ06A3Lyxhe9vGtOtzz3Z0+qZ5+7icZ/PL/2x1SHPbKao5oB/g/rlc6BCTajqBb33JcOe71Ye1oFsuYbnw==} + + 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-remark@10.0.1: + resolution: {integrity: sha512-EmDndlb5NVwXGfUa4c9GPK+lXeItTilLhE6ADSaQuHr4JUlKw9MidzGzx4HpqZrNCt6vnHmEifXQiiA+CEnjYQ==} + + rehype-stringify@10.0.1: + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} + + 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==} + + request-light@0.5.8: + resolution: {integrity: sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==} + + request-light@0.7.0: + resolution: {integrity: sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -4440,6 +5979,18 @@ packages: resolution: {integrity: sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==} engines: {node: '>=4'} + 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==} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -4479,10 +6030,17 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + satteri@0.10.5: + resolution: {integrity: sha512-Ao1LKpAEa9Wdg0otgbVKViZHEq9ebdXe4DMrp3s9vQAU0HNIuHnFEuMuOcm0ZIXyV0Yzxj91NvhLpvXZJO/5ZQ==} + sax@1.6.0: resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} engines: {node: '>=11.0.0'} + sax@1.6.1: + resolution: {integrity: sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==} + engines: {node: '>=11.0.0'} + scheduler@0.26.0: resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} @@ -4553,6 +6111,15 @@ packages: shallowequal@1.1.0: resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} + sharp@0.35.4: + resolution: {integrity: sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -4565,6 +6132,10 @@ packages: resolution: {integrity: sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==} engines: {node: '>= 0.4'} + shiki@4.4.3: + resolution: {integrity: sha512-Mb/GvXPHBAXdgGIcnfU5L3ldpn1XcxrGkPHwqgRx17/I2XRfqlFKk2vGkHWINn1kdXvzJZeuO3is6I9KLPFm0g==} + engines: {node: '>=20'} + side-channel-list@1.0.1: resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} engines: {node: '>= 0.4'} @@ -4596,6 +6167,11 @@ packages: 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 + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -4604,6 +6180,10 @@ packages: resolution: {integrity: sha512-vZ7rfeehZui7wQs438JXBckYLkIIdfHOXsaVEUMyS5fHo1483l1bMdo0EDSWYclY0yZKFOipDy4KHuKs6ssvdg==} engines: {node: '>=8.0.0'} + smol-toml@1.8.0: + resolution: {integrity: sha512-kCZr2V3ch9i00x8zXRhjUNVcjG9ijES5dDudkXvUVCT5QlJNQWElSJdZqyPemffHoLNUYwOcou0Fy+ojN0uHSQ==} + engines: {node: '>= 18'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -4619,6 +6199,13 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 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==} + split-on-first@1.1.0: resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} engines: {node: '>=6'} @@ -4646,6 +6233,19 @@ packages: standard-navigation@0.0.7: resolution: {integrity: sha512-NCGLCNyuXrFOkGHxdNZFnpsehGtiq1oXbPhKl7ZuxFO5J//H2evqqOchmD4YwEUJnkjO4kH9Xp4hQX6hdAYCKQ==} + starlight-links-validator@0.26.0: + resolution: {integrity: sha512-b3JlzP5bczSDMQp10ST/Gldd6RNzcwpWfTrszzGPcqnuav2W31+MjyX92IXH+VCcG2pG9G1qyDcEcNuMRYi2ig==} + engines: {node: '>=22.12.0'} + peerDependencies: + '@astrojs/starlight': '>=0.42.0' + astro: '>=7.2.10' + + starlight-llms-txt@0.12.0: + resolution: {integrity: sha512-ya4c0ZoiPUXuHDzd3AYCKh78Y3II3EToSE9Yp6uVN0c2UUKoNpqTjijhW86W/4toZzSUhWSnxeYs7QBcXNIPGg==} + peerDependencies: + '@astrojs/starlight': '>=0.41.0' + astro: ^7.0.0 + statuses@1.5.0: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} @@ -4673,6 +6273,14 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string-width@8.2.2: + resolution: {integrity: sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==} + engines: {node: '>=20'} + string.prototype.matchall@4.0.12: resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} engines: {node: '>= 0.4'} @@ -4692,6 +6300,9 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + strip-ansi@5.2.0: resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} engines: {node: '>=6'} @@ -4700,6 +6311,10 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -4715,6 +6330,12 @@ packages: structured-headers@0.4.1: resolution: {integrity: sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==} + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + styleq@0.1.3: resolution: {integrity: sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==} @@ -4723,6 +6344,10 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -4739,10 +6364,19 @@ packages: resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} engines: {node: '>=8'} + supports-hyperlinks@4.5.0: + resolution: {integrity: sha512-ZW2OvfeCXrNTbLakPUzjQG922EeGCOteFSVoek5DKStTh898wf7zgtuFlzQN8HfZCxC3Eh02yJVrRW51hADf+w==} + engines: {node: '>=20'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + svgo@4.1.0: + resolution: {integrity: sha512-bkxnTg1kSU0guhIBmibA6UUhrQmPVA1XsQLN+ylCd+UWzbnLkySOcXpyk1mrl05f+pcaCx2eHb+sp6BgMZWX+Q==} + engines: {node: '>=16'} + hasBin: true + synckit@0.11.13: resolution: {integrity: sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==} engines: {node: ^14.18.0 || >=16.0.0} @@ -4759,6 +6393,10 @@ packages: resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} engines: {node: '>=8'} + terminal-link@5.0.0: + resolution: {integrity: sha512-qFAy10MTMwjzjU8U16YS4YoZD+NQLHzLssFMNqgravjbvIPNiqkGFR4yjhJfmY9R5OFU7+yHxc6y+uGHkKwLRA==} + engines: {node: '>=20'} + terser@5.49.0: resolution: {integrity: sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==} engines: {node: '>=10'} @@ -4781,9 +6419,16 @@ packages: throat@5.0.0: resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} + tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinyclip@0.1.15: + resolution: {integrity: sha512-uo33abH+Ays0xYaDysoBt494Hb3hsEczMpcC0MwFl773pazORx4fmvKhclhR1wonUbB6vvpRsvVMwnhfqeMc+A==} + engines: {node: ^16.14.0 || >= 17.3.0} + tinyexec@1.2.4: resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} engines: {node: '>=18'} @@ -4813,6 +6458,15 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trim-trailing-lines@2.1.0: + resolution: {integrity: sha512-5UR5Biq4VlVOtzqkm2AZlgvSlDJtME46uV0br0gENbwN4l5+mMKT4b9gJKqWtuL2zAIqajGJGuvbCbcAJUZqBg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-api-utils@2.5.0: resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} @@ -4884,6 +6538,12 @@ packages: resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} engines: {node: '>= 0.4'} + typesafe-path@0.2.2: + resolution: {integrity: sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==} + + typescript-auto-import-cache@0.3.6: + resolution: {integrity: sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==} + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -4893,17 +6553,33 @@ packages: resolution: {integrity: sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==} hasBin: true + 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==} + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici@6.27.0: resolution: {integrity: sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==} engines: {node: '>=18.17'} + undici@8.10.2: + resolution: {integrity: sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==} + engines: {node: '>=22.19.0'} + unicode-canonical-property-names-ecmascript@2.0.1: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} @@ -4920,6 +6596,45 @@ packages: resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==} engines: {node: '>=4'} + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unifont@0.7.5: + resolution: {integrity: sha512-ULe/Cs+ZIsq+dcFofNkhqielCrUJnb5mr+Yc4EBM2VlL+6OZR6+cjtI2mT1bJvRBrVncqHAbLURxmPLcCXzWMg==} + + 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-remove@4.0.0: + resolution: {integrity: sha512-b4gokeGId57UVRX/eVKej5gXqGlc9+trkORhFJpu9raqZkZhU0zm8Doi05+HaiBsMEIJowL+2WtQ5ItjsngPXg==} + + 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==} + unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -4927,6 +6642,68 @@ packages: unrs-resolver@1.12.2: resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} + 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 + update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true @@ -4936,6 +6713,10 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + url-extras@0.1.0: + resolution: {integrity: sha512-8tzwTeXFPuX/5PHuCDQE5Dd9Ts4rwoq2t9aIT+HS4iAVpmj5l4Ao7Q+BuuFjvWRqrLswBhQDk8O96ZicgCqQqw==} + engines: {node: '>=20'} + use-callback-ref@1.3.3: resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} engines: {node: '>=10'} @@ -4966,6 +6747,9 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} @@ -4989,6 +6773,19 @@ packages: react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + verkit@0.4.1: + resolution: {integrity: sha512-mMVzj0TXExtVdlDEq+Mzp0eyOuyznNpFobNM3uAqe3HVm/Ps2c+u17BligMkZjZCA6EiXpoon8iRTer3iu40SQ==} + engines: {node: '>=18.12.0'} + + 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.1.4: resolution: {integrity: sha512-bTT9PsdWO+MQMNG9ZXIP/qM9wGh37DFxTV/sPq9cFpHr3w4jkgef032PkAL9jAqhk3Nz8NQw3O8n6/xFkqO4QQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5032,6 +6829,14 @@ packages: 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 + vitest@4.1.10: resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -5076,6 +6881,108 @@ packages: vlq@1.0.1: resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} + volar-service-css@0.0.71: + resolution: {integrity: sha512-wRRFt9BpjMKCazcgOh67MSjUjiWUCAh99DyYSDIOTuxaRjEtDC7PpB0k1Y1wbJIW/pVtMUSVbpPo3UGSm0Byxw==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-emmet@0.0.71: + resolution: {integrity: sha512-zqjzt6bN95e3CUstBm0PBFAJnrfz0ZAARka87fart46/gNCLLuP3Vujy8V/J8HEziTFLnfkgIASLFYPUhonJcA==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-html@0.0.71: + resolution: {integrity: sha512-e8tHPhgQ7ooLfudAEIku+kgd9pWkq3SSz8RbnQDI1+Eb8wbenkLGHqoirLqz5ORLV6wIMr2Iv08RWBG5eOcgpw==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-prettier@0.0.71: + resolution: {integrity: sha512-Rz7JVH3qD108UCdmIEiZvOBNljMt2nLFdbN8AXcDfn7xD9F5I2aCIsDVqBbXw21PsnxG0b7MfwtNF+zPS/NKUg==} + peerDependencies: + '@volar/language-service': ~2.4.0 + prettier: ^2.2 || ^3.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + prettier: + optional: true + + volar-service-typescript-twoslash-queries@0.0.71: + resolution: {integrity: sha512-9K2k72s4n7rV9s4bX0MyjbX9iBribvKZbBJKuEmTCZfeWJXs6Yh7bGpY4eoc7UufAjvpheBqwyZCOIPBvxCv0A==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-typescript@0.0.71: + resolution: {integrity: sha512-yTtM/BVT6hoyEYnDtaCyAtNhdNeS/mhTTABlBOdw3NNiRBUin3IznFJpgfjer4c6RYopiPjjQjc9VFhxVl1mLw==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-yaml@0.0.71: + resolution: {integrity: sha512-qYGWGuVpUTnZGu5P/CR4KLK4aIR8RrcVnmfZ2eRcj9q/I8VZCoC5yy9FtEvfNvnDp4MU17yhdJcvpQPIqhJS2Q==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + vscode-css-languageservice@6.3.10: + resolution: {integrity: sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA==} + + vscode-html-languageservice@5.6.2: + resolution: {integrity: sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg==} + + vscode-json-languageservice@4.1.8: + resolution: {integrity: sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==} + engines: {npm: '>=7.0.0'} + + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-jsonrpc@9.0.2: + resolution: {integrity: sha512-SbQSV9yRemARxeXw6LU5sS6Zq0e9/DgCCX5yelH263ZQWukbTk8EF8fjTrr1dziasf4GwlJbvTwFnTrnQFWZXQ==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-protocol@3.18.3: + resolution: {integrity: sha512-DF49+WeV5py4zO5hhobp60jjsDSK0lAqA0OuKBLBvp423HPWQcCbhZz3JgyfIewsEz2f8U+X75xNIFHdiXZm2w==} + + vscode-languageserver-textdocument@1.0.14: + resolution: {integrity: sha512-EQyqJMi552E4ZTf46izQ4Fj6XquqxCySR3J5ZSD1SisMf6RfpeOWHxGBE8Gr6V0/3GHIGdAzDn8F8+1nTGCnoQ==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver-types@3.18.3: + resolution: {integrity: sha512-XIlzJ7Qp/jzSI1ds7/FwPAWrPeTZA7pAtlW4hdJ1J6xXWJL6dR9QYnDhJOdLzdKhUQ5Mm6mvUMw+3DcOQQasPw==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-nls@5.2.0: + resolution: {integrity: sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==} + + vscode-uri@3.2.0: + resolution: {integrity: sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg==} + walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} @@ -5085,6 +6992,9 @@ packages: wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -5139,6 +7049,10 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -5197,6 +7111,9 @@ packages: resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} engines: {node: '>=8.0'} + xxhash-wasm@1.1.0: + resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -5208,6 +7125,15 @@ packages: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} + yaml-language-server@1.23.0: + resolution: {integrity: sha512-3qVyCOexLCWw06PQa5kRPwvMWMZ/eZeCRWUvgD6a0OkqL/4iCnxy2WumbWifa937Uo5xhyWJ0uxlU39ljhNh7A==} + hasBin: true + + yaml@2.8.3: + resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} + engines: {node: '>= 14.6'} + hasBin: true + yaml@2.9.0: resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} engines: {node: '>= 14.6'} @@ -5217,14 +7143,26 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yargs@17.7.3: resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==} engines: {node: '>=12'} + yargs@18.1.0: + resolution: {integrity: sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + zod-to-json-schema@3.25.2: resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} peerDependencies: @@ -5242,10 +7180,229 @@ packages: zod@4.4.3: resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + zod@4.6.5: + resolution: {integrity: sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + snapshots: '@0no-co/graphql.web@1.3.2': {} + '@astrojs/astro2tsx@0.1.0(@emnapi/runtime@1.11.3)': + dependencies: + '@emnapi/core': 1.11.3 + '@napi-rs/wasm-runtime': 1.2.4(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + transitivePeerDependencies: + - '@emnapi/runtime' + + '@astrojs/check@0.9.10(@emnapi/runtime@1.11.3)(prettier@3.9.5)(typescript@5.9.3)': + dependencies: + '@astrojs/language-server': 2.17.0(@emnapi/runtime@1.11.3)(prettier@3.9.5)(typescript@5.9.3) + chokidar: 4.0.3 + kleur: 4.1.5 + typescript: 5.9.3 + yargs: 18.1.0 + transitivePeerDependencies: + - '@emnapi/runtime' + - prettier + - prettier-plugin-astro + + '@astrojs/compiler-binding-android-arm64@0.4.1': + optional: true + + '@astrojs/compiler-binding-darwin-arm64@0.4.1': + optional: true + + '@astrojs/compiler-binding-darwin-x64@0.4.1': + optional: true + + '@astrojs/compiler-binding-linux-arm64-gnu@0.4.1': + optional: true + + '@astrojs/compiler-binding-linux-arm64-musl@0.4.1': + optional: true + + '@astrojs/compiler-binding-linux-x64-gnu@0.4.1': + optional: true + + '@astrojs/compiler-binding-linux-x64-musl@0.4.1': + optional: true + + '@astrojs/compiler-binding-wasm32-wasi@0.4.1(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': + dependencies: + '@napi-rs/wasm-runtime': 1.2.4(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + optional: true + + '@astrojs/compiler-binding-win32-arm64-msvc@0.4.1': + optional: true + + '@astrojs/compiler-binding-win32-x64-msvc@0.4.1': + optional: true + + '@astrojs/compiler-binding@0.4.1(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': + optionalDependencies: + '@astrojs/compiler-binding-android-arm64': 0.4.1 + '@astrojs/compiler-binding-darwin-arm64': 0.4.1 + '@astrojs/compiler-binding-darwin-x64': 0.4.1 + '@astrojs/compiler-binding-linux-arm64-gnu': 0.4.1 + '@astrojs/compiler-binding-linux-arm64-musl': 0.4.1 + '@astrojs/compiler-binding-linux-x64-gnu': 0.4.1 + '@astrojs/compiler-binding-linux-x64-musl': 0.4.1 + '@astrojs/compiler-binding-wasm32-wasi': 0.4.1(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + '@astrojs/compiler-binding-win32-arm64-msvc': 0.4.1 + '@astrojs/compiler-binding-win32-x64-msvc': 0.4.1 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + + '@astrojs/compiler-rs@0.4.1(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': + dependencies: + '@astrojs/compiler-binding': 0.4.1(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + + '@astrojs/internal-helpers@0.11.0': + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + js-yaml: 4.3.0 + picomatch: 4.0.5 + retext-smartypants: 6.2.0 + shiki: 4.4.3 + smol-toml: 1.8.0 + unified: 11.0.5 + + '@astrojs/language-server@2.17.0(@emnapi/runtime@1.11.3)(prettier@3.9.5)(typescript@5.9.3)': + dependencies: + '@astrojs/astro2tsx': 0.1.0(@emnapi/runtime@1.11.3) + '@astrojs/yaml2ts': 0.2.4 + '@volar/kit': 2.4.28(typescript@5.9.3) + '@volar/language-core': 2.4.28 + '@volar/language-server': 2.4.28 + '@volar/language-service': 2.4.28 + muggle-string: 0.4.1 + tinyglobby: 0.2.17 + volar-service-css: 0.0.71(@volar/language-service@2.4.28) + volar-service-emmet: 0.0.71(@volar/language-service@2.4.28) + volar-service-html: 0.0.71(@volar/language-service@2.4.28) + volar-service-prettier: 0.0.71(@volar/language-service@2.4.28)(prettier@3.9.5) + volar-service-typescript: 0.0.71(@volar/language-service@2.4.28) + volar-service-typescript-twoslash-queries: 0.0.71(@volar/language-service@2.4.28) + volar-service-yaml: 0.0.71(@volar/language-service@2.4.28) + vscode-html-languageservice: 5.6.2 + vscode-uri: 3.2.0 + optionalDependencies: + prettier: 3.9.5 + transitivePeerDependencies: + - '@emnapi/runtime' + - typescript + + '@astrojs/markdown-remark@7.3.1': + dependencies: + '@astrojs/internal-helpers': 0.11.0 + '@astrojs/prism': 4.0.2 + '@mdx-js/mdx': 3.1.1 + acorn: 8.17.0 + estree-util-visit: 2.0.0 + github-slugger: 2.0.0 + hast-util-from-html: 2.0.3 + hast-util-to-html: 9.0.5 + 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 + source-map: 0.7.6 + 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.4.1': + dependencies: + '@astrojs/internal-helpers': 0.11.0 + '@astrojs/prism': 4.0.2 + github-slugger: 2.0.0 + satteri: 0.10.5 + + '@astrojs/mdx@8.0.1(@astrojs/markdown-remark@7.3.1)(@astrojs/markdown-satteri@0.4.1)(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0))': + dependencies: + '@astrojs/internal-helpers': 0.11.0 + '@astrojs/markdown-satteri': 0.4.1 + astro: 7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0) + es-module-lexer: 2.3.1 + optionalDependencies: + '@astrojs/markdown-remark': 7.3.1 + + '@astrojs/prism@4.0.2': + dependencies: + prismjs: 1.30.0 + + '@astrojs/sitemap@3.7.4': + dependencies: + sitemap: 9.0.1 + zod: 4.4.3 + + '@astrojs/starlight@0.42.2(@astrojs/markdown-remark@7.3.1)(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0))(typescript@5.9.3)': + dependencies: + '@astrojs/markdown-satteri': 0.4.1 + '@astrojs/mdx': 8.0.1(@astrojs/markdown-remark@7.3.1)(@astrojs/markdown-satteri@0.4.1)(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0)) + '@astrojs/sitemap': 3.7.4 + '@pagefind/default-ui': 1.5.2 + '@types/hast': 3.0.5 + '@types/js-yaml': 4.0.9 + '@types/mdast': 4.0.4 + astro: 7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0) + astro-expressive-code: 0.44.2(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0)) + bcp-47: 2.1.1 + hast-util-format: 1.1.0 + hast-util-select: 6.0.4 + hast-util-to-html: 9.0.5 + hast-util-to-string: 3.0.1 + hastscript: 9.0.1 + i18next: 26.4.2(typescript@5.9.3) + js-yaml: 4.3.0 + klona: 2.0.6 + magic-string: 1.4.1 + mdast-util-directive: 3.1.0 + mdast-util-to-markdown: 2.1.2 + mdast-util-to-string: 4.0.0 + pagefind: 1.5.2 + remark-directive: 4.0.0 + satteri: 0.10.5 + ultrahtml: 1.7.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + optionalDependencies: + '@astrojs/markdown-remark': 7.3.1 + 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 + + '@astrojs/yaml2ts@0.2.4': + dependencies: + yaml: 2.9.0 + '@babel/code-frame@7.10.4': dependencies: '@babel/highlight': 7.25.9 @@ -5856,10 +8013,82 @@ snapshots: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 + '@bruits/satteri-darwin-arm64@0.10.5': + optional: true + + '@bruits/satteri-darwin-x64@0.10.5': + optional: true + + '@bruits/satteri-linux-arm64-gnu@0.10.5': + optional: true + + '@bruits/satteri-linux-arm64-musl@0.10.5': + optional: true + + '@bruits/satteri-linux-x64-gnu@0.10.5': + optional: true + + '@bruits/satteri-linux-x64-musl@0.10.5': + optional: true + + '@bruits/satteri-wasm32-wasi@0.10.5': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@napi-rs/wasm-runtime': 1.2.4(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + optional: true + + '@bruits/satteri-win32-arm64-msvc@0.10.5': + optional: true + + '@bruits/satteri-win32-x64-msvc@0.10.5': + optional: true + + '@capsizecss/unpack@4.0.1': + dependencies: + fontkitten: 1.0.3 + + '@clack/core@1.5.1': + dependencies: + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + + '@clack/prompts@1.8.1': + dependencies: + '@clack/core': 1.5.1 + fast-string-width: 3.0.2 + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + + '@ctrl/tinycolor@4.2.1': {} + '@egjs/hammerjs@2.0.17': dependencies: '@types/hammerjs': 2.0.46 + '@emmetio/abbreviation@2.3.3': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/css-abbreviation@2.1.8': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/css-parser@0.4.1': + dependencies: + '@emmetio/stream-reader': 2.2.0 + '@emmetio/stream-reader-utils': 0.1.0 + + '@emmetio/html-matcher@1.3.0': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/scanner@1.0.4': {} + + '@emmetio/stream-reader-utils@0.1.0': {} + + '@emmetio/stream-reader@2.2.0': {} + '@emnapi/core@1.10.0': dependencies: '@emnapi/wasi-threads': 1.2.1 @@ -5872,6 +8101,11 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/core@1.11.3': + dependencies: + '@emnapi/wasi-threads': 1.2.3 + tslib: 2.8.1 + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 @@ -5882,6 +8116,10 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + '@emnapi/wasi-threads@1.2.1': dependencies: tslib: 2.8.1 @@ -5892,84 +8130,166 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/wasi-threads@1.2.3': + dependencies: + tslib: 2.8.1 + '@esbuild/aix-ppc64@0.25.12': optional: true + '@esbuild/aix-ppc64@0.28.2': + optional: true + '@esbuild/android-arm64@0.25.12': optional: true + '@esbuild/android-arm64@0.28.2': + optional: true + '@esbuild/android-arm@0.25.12': optional: true + '@esbuild/android-arm@0.28.2': + optional: true + '@esbuild/android-x64@0.25.12': optional: true + '@esbuild/android-x64@0.28.2': + optional: true + '@esbuild/darwin-arm64@0.25.12': optional: true + '@esbuild/darwin-arm64@0.28.2': + optional: true + '@esbuild/darwin-x64@0.25.12': optional: true + '@esbuild/darwin-x64@0.28.2': + optional: true + '@esbuild/freebsd-arm64@0.25.12': optional: true + '@esbuild/freebsd-arm64@0.28.2': + optional: true + '@esbuild/freebsd-x64@0.25.12': optional: true + '@esbuild/freebsd-x64@0.28.2': + optional: true + '@esbuild/linux-arm64@0.25.12': optional: true + '@esbuild/linux-arm64@0.28.2': + optional: true + '@esbuild/linux-arm@0.25.12': optional: true + '@esbuild/linux-arm@0.28.2': + optional: true + '@esbuild/linux-ia32@0.25.12': optional: true + '@esbuild/linux-ia32@0.28.2': + optional: true + '@esbuild/linux-loong64@0.25.12': optional: true + '@esbuild/linux-loong64@0.28.2': + optional: true + '@esbuild/linux-mips64el@0.25.12': optional: true + '@esbuild/linux-mips64el@0.28.2': + optional: true + '@esbuild/linux-ppc64@0.25.12': optional: true + '@esbuild/linux-ppc64@0.28.2': + optional: true + '@esbuild/linux-riscv64@0.25.12': optional: true + '@esbuild/linux-riscv64@0.28.2': + optional: true + '@esbuild/linux-s390x@0.25.12': optional: true + '@esbuild/linux-s390x@0.28.2': + optional: true + '@esbuild/linux-x64@0.25.12': optional: true + '@esbuild/linux-x64@0.28.2': + optional: true + '@esbuild/netbsd-arm64@0.25.12': optional: true + '@esbuild/netbsd-arm64@0.28.2': + optional: true + '@esbuild/netbsd-x64@0.25.12': optional: true + '@esbuild/netbsd-x64@0.28.2': + optional: true + '@esbuild/openbsd-arm64@0.25.12': optional: true + '@esbuild/openbsd-arm64@0.28.2': + optional: true + '@esbuild/openbsd-x64@0.25.12': optional: true + '@esbuild/openbsd-x64@0.28.2': + optional: true + '@esbuild/openharmony-arm64@0.25.12': optional: true + '@esbuild/openharmony-arm64@0.28.2': + optional: true + '@esbuild/sunos-x64@0.25.12': optional: true + '@esbuild/sunos-x64@0.28.2': + optional: true + '@esbuild/win32-arm64@0.25.12': optional: true + '@esbuild/win32-arm64@0.28.2': + optional: true + '@esbuild/win32-ia32@0.25.12': optional: true + '@esbuild/win32-ia32@0.28.2': + optional: true + '@esbuild/win32-x64@0.25.12': optional: true + '@esbuild/win32-x64@0.28.2': + optional: true + '@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)': dependencies: eslint: 8.57.1 @@ -6313,6 +8633,33 @@ snapshots: chalk: 4.1.2 js-yaml: 4.3.0 + '@expressive-code/core@0.44.2': + dependencies: + '@ctrl/tinycolor': 4.2.1 + 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.19 + postcss-nested: 6.2.0(postcss@8.5.19) + unist-util-visit: 5.1.0 + unist-util-visit-parents: 6.0.2 + + '@expressive-code/plugin-frames@0.44.2': + dependencies: + '@expressive-code/core': 0.44.2 + + '@expressive-code/plugin-shiki@0.44.2': + dependencies: + '@expressive-code/core': 0.44.2 + shiki: 4.4.3 + + '@expressive-code/plugin-text-markers@0.44.2': + dependencies: + '@expressive-code/core': 0.44.2 + + '@fontsource/geist-mono@5.3.0': {} + '@hono/node-server@1.19.14(hono@4.12.30)': dependencies: hono: 4.12.30 @@ -6329,6 +8676,112 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.35.4': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.3.3 + optional: true + + '@img/sharp-darwin-x64@0.35.4': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.3.3 + optional: true + + '@img/sharp-freebsd-wasm32@0.35.4': + dependencies: + '@img/sharp-wasm32': 0.35.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.3.3': + optional: true + + '@img/sharp-libvips-darwin-x64@1.3.3': + optional: true + + '@img/sharp-libvips-linux-arm64@1.3.3': + optional: true + + '@img/sharp-libvips-linux-arm@1.3.3': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.3.3': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.3.3': + optional: true + + '@img/sharp-libvips-linux-s390x@1.3.3': + optional: true + + '@img/sharp-libvips-linux-x64@1.3.3': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.3.3': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.3.3': + optional: true + + '@img/sharp-linux-arm64@0.35.4': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.3.3 + optional: true + + '@img/sharp-linux-arm@0.35.4': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.3.3 + optional: true + + '@img/sharp-linux-ppc64@0.35.4': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.3.3 + optional: true + + '@img/sharp-linux-riscv64@0.35.4': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.3.3 + optional: true + + '@img/sharp-linux-s390x@0.35.4': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.3.3 + optional: true + + '@img/sharp-linux-x64@0.35.4': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.3.3 + optional: true + + '@img/sharp-linuxmusl-arm64@0.35.4': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.3.3 + optional: true + + '@img/sharp-linuxmusl-x64@0.35.4': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.3.3 + optional: true + + '@img/sharp-wasm32@0.35.4': + dependencies: + '@emnapi/runtime': 1.11.3 + optional: true + + '@img/sharp-webcontainers-wasm32@0.35.4': + dependencies: + '@img/sharp-wasm32': 0.35.4 + optional: true + + '@img/sharp-win32-arm64@0.35.4': + optional: true + + '@img/sharp-win32-ia32@0.35.4': + optional: true + + '@img/sharp-win32-x64@0.35.4': + optional: true + '@isaacs/fs-minipass@4.0.1': dependencies: minipass: 7.1.3 @@ -6417,12 +8870,44 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/sourcemap-codec@1.6.0': {} + '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@modelcontextprotocol/sdk@1.29.0(zod@4.4.3)': + '@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.17.0 + collapse-white-space: 2.1.0 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-util-scope: 1.0.1 + 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.17.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 + + '@modelcontextprotocol/sdk@1.29.0(zod@4.6.5)': dependencies: '@hono/node-server': 1.19.14(hono@4.12.30) ajv: 8.20.0 @@ -6439,8 +8924,8 @@ snapshots: json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 raw-body: 3.0.2 - zod: 4.4.3 - zod-to-json-schema: 3.25.2(zod@4.4.3) + zod: 4.6.5 + zod-to-json-schema: 3.25.2(zod@4.6.5) transitivePeerDependencies: - supports-color @@ -6458,6 +8943,19 @@ snapshots: '@tybys/wasm-util': 0.10.3 optional: true + '@napi-rs/wasm-runtime@1.2.4(@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.4(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': + dependencies: + '@emnapi/core': 1.11.3 + '@emnapi/runtime': 1.11.3 + '@tybys/wasm-util': 0.10.3 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -6472,8 +8970,33 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} + '@oslojs/encoding@1.1.0': {} + '@oxc-project/types@0.139.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 + '@peculiar/asn1-cms@2.8.0': dependencies: '@peculiar/asn1-schema': 2.8.0 @@ -7005,6 +9528,46 @@ snapshots: '@rtsao/scc@1.1.0': {} + '@shikijs/core@4.4.3': + dependencies: + '@shikijs/primitive': 4.4.3 + '@shikijs/types': 4.4.3 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@4.4.3': + dependencies: + '@shikijs/types': 4.4.3 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.6 + + '@shikijs/engine-oniguruma@4.4.3': + dependencies: + '@shikijs/types': 4.4.3 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@4.4.3': + dependencies: + '@shikijs/types': 4.4.3 + + '@shikijs/primitive@4.4.3': + dependencies: + '@shikijs/types': 4.4.3 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + '@shikijs/themes@4.4.3': + dependencies: + '@shikijs/types': 4.4.3 + + '@shikijs/types@4.4.3': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + '@shikijs/vscode-textmate@10.0.2': {} + '@sinclair/typebox@0.27.10': {} '@sinonjs/commons@3.0.1': @@ -7038,7 +9601,6 @@ snapshots: '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 - optional: true '@types/babel__core@7.20.5': dependencies: @@ -7061,13 +9623,23 @@ snapshots: dependencies: '@babel/types': 7.29.7 + '@types/braces@3.0.5': {} + '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 assertion-error: 2.0.1 + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + '@types/deep-eql@4.0.2': {} + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.9 + '@types/estree@1.0.9': {} '@types/graceful-fs@4.1.9': @@ -7076,6 +9648,10 @@ snapshots: '@types/hammerjs@2.0.46': {} + '@types/hast@3.0.5': + dependencies: + '@types/unist': 3.0.3 + '@types/istanbul-lib-coverage@2.0.6': {} '@types/istanbul-lib-report@3.0.3': @@ -7086,18 +9662,50 @@ snapshots: dependencies: '@types/istanbul-lib-report': 3.0.3 + '@types/js-yaml@4.0.9': {} + '@types/json5@0.0.29': {} + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdx@2.0.14': {} + + '@types/micromatch@4.0.10': + dependencies: + '@types/braces': 3.0.5 + + '@types/ms@2.1.0': {} + + '@types/nlcst@2.0.3': + dependencies: + '@types/unist': 3.0.3 + '@types/node@22.20.1': dependencies: undici-types: 6.21.0 + '@types/node@24.13.6': + dependencies: + undici-types: 7.18.2 + + '@types/picomatch@4.0.3': {} + '@types/react@19.1.17': dependencies: csstype: 3.2.3 + '@types/sax@1.2.7': + dependencies: + '@types/node': 22.20.1 + '@types/stack-utils@2.0.3': {} + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + '@types/ws@8.18.1': dependencies: '@types/node': 22.20.1 @@ -7292,13 +9900,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.10(vite@8.1.4(@types/node@22.20.1)(terser@5.49.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.10(vite@8.1.4(@types/node@24.13.6)(esbuild@0.28.2)(terser@5.49.0)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.1.4(@types/node@22.20.1)(terser@5.49.0)(yaml@2.9.0) + vite: 8.1.4(@types/node@24.13.6)(esbuild@0.28.2)(terser@5.49.0)(yaml@2.9.0) '@vitest/pretty-format@4.1.10': dependencies: @@ -7324,6 +9932,56 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.0 + '@volar/kit@2.4.28(typescript@5.9.3)': + dependencies: + '@volar/language-service': 2.4.28 + '@volar/typescript': 2.4.28 + typesafe-path: 0.2.2 + typescript: 5.9.3 + vscode-languageserver-textdocument: 1.0.14 + vscode-uri: 3.2.0 + + '@volar/language-core@2.4.28': + dependencies: + '@volar/source-map': 2.4.28 + + '@volar/language-server@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + '@volar/language-service': 2.4.28 + '@volar/typescript': 2.4.28 + path-browserify: 1.0.1 + request-light: 0.7.0 + vscode-languageserver: 9.0.1 + vscode-languageserver-protocol: 3.18.3 + vscode-languageserver-textdocument: 1.0.14 + vscode-uri: 3.2.0 + + '@volar/language-service@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + vscode-languageserver-protocol: 3.18.3 + vscode-languageserver-textdocument: 1.0.14 + vscode-uri: 3.2.0 + + '@volar/source-map@2.4.28': {} + + '@volar/typescript@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + path-browserify: 1.0.1 + vscode-uri: 3.2.0 + + '@vscode/emmet-helper@2.11.0': + dependencies: + emmet: 2.4.11 + jsonc-parser: 2.3.1 + vscode-languageserver-textdocument: 1.0.14 + vscode-languageserver-types: 3.18.3 + vscode-uri: 3.2.0 + + '@vscode/l10n@0.0.18': {} + '@xmldom/xmldom@0.8.13': {} '@xmldom/xmldom@0.9.10': {} @@ -7350,10 +10008,18 @@ snapshots: agent-base@7.1.4: {} + ajv-draft-04@1.0.0(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + ajv-formats@3.0.1(ajv@8.20.0): optionalDependencies: ajv: 8.20.0 + ajv-i18n@4.2.0(ajv@8.20.0): + dependencies: + ajv: 8.20.0 + ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 @@ -7368,16 +10034,26 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + am-i-vibing@0.4.0: + dependencies: + process-ancestry: 0.1.0 + anser@1.4.10: {} ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 + ansi-escapes@7.3.0: + dependencies: + environment: 1.1.0 + ansi-regex@4.1.1: {} ansi-regex@5.0.1: {} + ansi-regex@6.3.0: {} + ansi-styles@3.2.1: dependencies: color-convert: 1.9.3 @@ -7388,6 +10064,8 @@ snapshots: ansi-styles@5.2.0: {} + ansi-styles@6.2.3: {} + any-promise@1.3.0: {} anymatch@3.1.3: @@ -7407,6 +10085,8 @@ snapshots: dependencies: tslib: 2.8.1 + aria-query@5.3.2: {} + array-buffer-byte-length@1.0.2: dependencies: call-bound: 1.0.4 @@ -7423,6 +10103,8 @@ snapshots: is-string: 1.1.1 math-intrinsics: 1.1.0 + array-iterate@2.0.1: {} + array.prototype.findlast@1.2.5: dependencies: call-bind: 1.0.9 @@ -7484,6 +10166,106 @@ snapshots: assertion-error@2.0.1: {} + astring@1.9.0: {} + + astro-expressive-code@0.44.2(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0)): + dependencies: + astro: 7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0) + rehype-expressive-code: 0.44.2 + url-extras: 0.1.0 + + astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0): + dependencies: + '@astrojs/compiler-rs': 0.4.1(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + '@astrojs/internal-helpers': 0.11.0 + '@astrojs/markdown-satteri': 0.4.1 + '@astrojs/telemetry': 3.3.3 + '@capsizecss/unpack': 4.0.1 + '@clack/prompts': 1.8.1 + '@oslojs/encoding': 1.1.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.4 + diff: 9.0.0 + dset: 3.1.4 + es-module-lexer: 2.3.1 + esbuild: 0.28.2 + find-proc: 0.2.0 + 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.0 + jsonc-parser: 3.3.1 + magic-string: 1.4.1 + magicast: 0.5.5 + mrmime: 2.0.1 + neotraverse: 1.0.1 + obug: 2.1.3 + p-limit: 7.3.3 + p-queue: 9.3.3 + package-manager-detector: 1.8.0 + piccolore: 0.1.3 + picomatch: 4.0.5 + shiki: 4.4.3 + smol-toml: 1.8.0 + svgo: 4.1.0 + tinyclip: 0.1.15 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 + ultrahtml: 1.7.0 + unifont: 0.7.5 + unstorage: 1.17.5 + verkit: 0.4.1 + vite: 8.1.4(@types/node@24.13.6)(esbuild@0.28.2)(terser@5.49.0)(yaml@2.9.0) + vitefu: 1.1.3(vite@8.1.4(@types/node@24.13.6)(esbuild@0.28.2)(terser@5.49.0)(yaml@2.9.0)) + xxhash-wasm: 1.1.0 + yargs-parser: 22.0.0 + zod: 4.6.5 + optionalDependencies: + '@astrojs/markdown-remark': 7.3.1 + sharp: 0.35.4(@types/node@24.13.6) + 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 + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - uploadthing + - yaml + async-function@1.0.0: {} async-limiter@1.0.1: {} @@ -7492,6 +10274,8 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 + axobject-query@4.1.0: {} + babel-jest@29.7.0(@babel/core@7.29.7): dependencies: '@babel/core': 7.29.7 @@ -7619,6 +10403,8 @@ snapshots: babel-plugin-jest-hoist: 29.6.3 babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) + bail@2.0.2: {} + balanced-match@1.0.2: {} balanced-match@4.0.4: {} @@ -7627,6 +10413,14 @@ snapshots: baseline-browser-mapping@2.10.43: {} + 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 + better-opn@3.0.2: dependencies: open: 8.4.2 @@ -7647,6 +10441,8 @@ snapshots: transitivePeerDependencies: - supports-color + boolbase@1.0.0: {} + bplist-creator@0.1.0: dependencies: stream-buffers: 2.2.0 @@ -7724,6 +10520,8 @@ snapshots: caniuse-lite@1.0.30001805: {} + ccount@2.0.1: {} + chai@6.2.2: {} chalk@2.4.2: @@ -7737,6 +10535,22 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + chokidar@5.0.0: + dependencies: + readdirp: 5.1.1 + chownr@3.0.0: {} chrome-launcher@0.15.2: @@ -7763,6 +10577,8 @@ snapshots: ci-info@3.9.0: {} + ci-info@4.4.0: {} + cli-cursor@2.1.0: dependencies: restore-cursor: 2.0.0 @@ -7777,8 +10593,18 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + cliui@9.0.1: + dependencies: + string-width: 7.2.0 + strip-ansi: 7.2.0 + wrap-ansi: 9.0.2 + clone@1.0.4: {} + clsx@2.1.1: {} + + collapse-white-space@2.1.0: {} + color-convert@1.9.3: dependencies: color-name: 1.1.3 @@ -7801,6 +10627,10 @@ snapshots: color-convert: 2.0.1 color-string: 1.9.1 + comma-separated-tokens@2.0.3: {} + + commander@11.1.0: {} + commander@12.1.0: {} commander@2.20.3: {} @@ -7809,6 +10639,8 @@ snapshots: commander@7.2.0: {} + common-ancestor-path@2.0.0: {} + compressible@2.0.18: dependencies: mime-db: 1.54.0 @@ -7844,10 +10676,14 @@ snapshots: convert-source-map@2.0.0: {} + cookie-es@1.2.3: {} + cookie-signature@1.2.2: {} cookie@0.7.2: {} + cookie@2.0.1: {} + core-js-compat@3.49.0: dependencies: browserslist: 4.28.6 @@ -7869,10 +10705,42 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + css-in-js-utils@3.1.0: dependencies: hyphenate-style-name: 1.1.0 + css-select@6.0.0: + dependencies: + boolbase: 1.0.0 + css-what: 7.0.0 + 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@7.0.0: {} + + cssesc@3.0.0: {} + + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + csstype@3.2.3: {} data-view-buffer@1.0.2: @@ -7905,6 +10773,10 @@ snapshots: dependencies: ms: 2.1.3 + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + decode-uri-component@0.2.2: {} deep-extend@0.6.0: {} @@ -7931,14 +10803,30 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + defu@6.1.7: {} + depd@2.0.0: {} + dequal@2.0.3: {} + + destr@2.0.5: {} + destroy@1.2.0: {} detect-libc@2.1.2: {} detect-node-es@1.1.0: {} + devalue@5.9.4: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + diff@9.0.0: {} + + direction@2.0.1: {} + doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -7947,12 +10835,32 @@ snapshots: dependencies: esutils: 2.0.3 + 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 + dotenv-expand@11.0.7: dependencies: dotenv: 16.4.7 dotenv@16.4.7: {} + dset@3.1.4: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -7963,6 +10871,13 @@ snapshots: electron-to-chromium@1.5.392: {} + emmet@2.4.11: + dependencies: + '@emmetio/abbreviation': 2.3.3 + '@emmetio/css-abbreviation': 2.1.8 + + emoji-regex@10.6.0: {} + emoji-regex@8.0.0: {} encodeurl@1.0.2: {} @@ -7974,8 +10889,14 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.3 + entities@4.5.0: {} + + entities@6.0.1: {} + env-editor@0.4.2: {} + environment@1.1.0: {} + error-stack-parser@2.1.4: dependencies: stackframe: 1.3.4 @@ -8093,6 +11014,20 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.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.17.0 + esast-util-from-estree: 2.0.0 + vfile-message: 4.0.3 + esbuild@0.25.12: optionalDependencies: '@esbuild/aix-ppc64': 0.25.12 @@ -8122,6 +11057,35 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 + esbuild@0.28.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -8132,6 +11096,8 @@ snapshots: escape-string-regexp@4.0.0: {} + escape-string-regexp@5.0.0: {} + eslint-compat-utils@0.5.1(eslint@8.57.1): dependencies: eslint: 8.57.1 @@ -8412,6 +11378,35 @@ snapshots: estraverse@5.3.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.1: + 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@3.0.3: dependencies: '@types/estree': 1.0.9 @@ -8422,6 +11417,8 @@ snapshots: event-target-shim@5.0.1: {} + eventemitter3@5.0.4: {} + eventsource-parser@3.1.0: {} eventsource@3.0.7: @@ -8660,6 +11657,15 @@ snapshots: transitivePeerDependencies: - supports-color + expressive-code@0.44.2: + dependencies: + '@expressive-code/core': 0.44.2 + '@expressive-code/plugin-frames': 0.44.2 + '@expressive-code/plugin-shiki': 0.44.2 + '@expressive-code/plugin-text-markers': 0.44.2 + + extend@3.0.2: {} + fast-deep-equal@3.1.3: {} fast-diff@1.3.0: {} @@ -8668,8 +11674,18 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-string-truncated-width@3.0.3: {} + + fast-string-width@3.0.2: + dependencies: + fast-string-truncated-width: 3.0.3 + fast-uri@3.1.3: {} + fast-wrap-ansi@0.2.2: + dependencies: + fast-string-width: 3.0.2 + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -8729,6 +11745,8 @@ snapshots: transitivePeerDependencies: - supports-color + find-proc@0.2.0: {} + find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -8747,10 +11765,20 @@ snapshots: flatted@3.4.2: {} + flattie@1.1.1: {} + flow-enums-runtime@0.0.6: {} + fontace@0.4.1: + dependencies: + fontkitten: 1.0.3 + fontfaceobserver@2.3.0: {} + fontkitten@1.0.3: + dependencies: + tiny-inflate: 1.0.3 + for-each@0.3.5: dependencies: is-callable: 1.2.7 @@ -8790,6 +11818,8 @@ snapshots: get-caller-file@2.0.5: {} + get-east-asian-width@1.7.0: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -8822,8 +11852,14 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + get-tsconfig@5.0.0-beta.4: + dependencies: + resolve-pkg-maps: 1.0.0 + getenv@2.0.0: {} + github-slugger@2.0.0: {} + glob-parent@6.0.2: dependencies: is-glob: 4.0.3 @@ -8864,12 +11900,26 @@ snapshots: graphemer@1.4.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 + has-bigints@1.1.0: {} has-flag@3.0.0: {} has-flag@4.0.0: {} + has-flag@5.0.1: {} + has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.1 @@ -8888,6 +11938,212 @@ snapshots: dependencies: function-bind: 1.1.2 + 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-mdast@10.1.2: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.3 + hast-util-phrasing: 3.0.1 + hast-util-to-html: 9.0.5 + hast-util-to-text: 4.0.2 + hast-util-whitespace: 3.0.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-hast: 13.2.1 + mdast-util-to-string: 4.0.0 + rehype-minify-whitespace: 6.0.2 + trim-trailing-lines: 2.1.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + + 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 + hermes-estree@0.25.1: {} hermes-estree@0.29.1: {} @@ -8922,6 +12178,14 @@ snapshots: dependencies: lru-cache: 10.4.3 + 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: {} + http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -8939,6 +12203,10 @@ snapshots: hyphenate-style-name@1.1.0: {} + i18next@26.4.2(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + iconv-lite@0.7.3: dependencies: safer-buffer: 2.1.2 @@ -8969,6 +12237,8 @@ snapshots: ini@1.3.8: {} + inline-style-parser@0.2.7: {} + inline-style-prefixer@7.0.1: dependencies: css-in-js-utils: 3.1.0 @@ -8987,6 +12257,17 @@ snapshots: ipaddr.js@1.9.1: {} + iron-webcrypto@1.2.1: {} + + is-absolute-url@5.0.0: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + is-array-buffer@3.0.5: dependencies: call-bind: 1.0.9 @@ -9033,8 +12314,12 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-decimal@2.0.1: {} + is-docker@2.2.1: {} + is-docker@4.0.0: {} + is-document.all@1.0.0: dependencies: call-bound: 1.0.4 @@ -9059,6 +12344,8 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-hexadecimal@2.0.1: {} + is-map@2.0.3: {} is-negative-zero@2.0.3: {} @@ -9072,6 +12359,8 @@ snapshots: is-path-inside@3.0.3: {} + is-plain-obj@4.1.0: {} + is-promise@4.0.0: {} is-regex@1.2.1: @@ -9249,6 +12538,10 @@ snapshots: json5@2.2.3: {} + jsonc-parser@2.3.1: {} + + jsonc-parser@3.3.1: {} + jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.9 @@ -9262,6 +12555,10 @@ snapshots: kleur@3.0.3: {} + kleur@4.1.5: {} + + klona@2.0.6: {} + lan-network@0.2.1: {} leven@3.1.0: {} @@ -9347,6 +12644,8 @@ snapshots: dependencies: chalk: 2.4.2 + longest-streak@3.1.0: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -9363,14 +12662,215 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + magic-string@1.4.1: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + + magicast@0.5.5: + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + source-map-js: 1.2.1 + makeerror@1.0.12: dependencies: tmpl: 1.0.5 + markdown-extensions@2.0.0: {} + + markdown-table@3.0.4: {} + marky@1.3.0: {} math-intrinsics@1.1.0: {} + 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: {} + media-typer@1.1.0: {} memoize-one@5.2.1: {} @@ -9730,6 +13230,280 @@ snapshots: - supports-color - utf-8-validate + 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.2: + 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.2 + 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.17.0 + acorn-jsx: 5.3.2(acorn@8.17.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 + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -9773,10 +13547,14 @@ snapshots: mkdirp@1.0.4: {} + mrmime@2.0.1: {} + ms@2.0.0: {} ms@2.1.3: {} + muggle-string@0.4.1: {} + mz@2.7.0: dependencies: any-promise: 1.3.0 @@ -9795,8 +13573,14 @@ snapshots: negotiator@1.0.0: {} + neotraverse@1.0.1: {} + nested-error-stacks@2.0.1: {} + nlcst-to-string@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + node-exports-info@1.6.2: dependencies: array.prototype.flatmap: 1.3.3 @@ -9804,6 +13588,8 @@ snapshots: object.entries: 1.1.9 semver: 6.3.1 + node-fetch-native@1.6.7: {} + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 @@ -9812,6 +13598,8 @@ snapshots: node-int64@0.4.0: {} + node-mock-http@1.0.5: {} + node-releases@2.0.51: {} normalize-path@3.0.0: {} @@ -9823,6 +13611,10 @@ snapshots: semver: 7.8.5 validate-npm-package-name: 5.0.1 + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + nullthrows@1.1.1: {} ob1@0.83.3: @@ -9877,6 +13669,14 @@ snapshots: obug@2.1.3: {} + ofetch@1.5.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.4 + + ohash@2.0.12: {} + on-finished@2.3.0: dependencies: ee-first: 1.1.1 @@ -9895,6 +13695,14 @@ snapshots: dependencies: mimic-fn: 1.2.0 + 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 + open@7.4.2: dependencies: is-docker: 2.2.1 @@ -9938,6 +13746,10 @@ snapshots: dependencies: yocto-queue: 0.1.0 + p-limit@7.3.3: + dependencies: + yocto-queue: 1.2.2 + p-locate@4.1.0: dependencies: p-limit: 2.3.0 @@ -9946,18 +13758,62 @@ snapshots: dependencies: p-limit: 3.1.0 + p-queue@9.3.3: + dependencies: + eventemitter3: 5.0.4 + p-timeout: 7.0.2 + + p-timeout@7.0.2: {} + p-try@2.2.0: {} + 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 + parent-module@1.0.1: dependencies: callsites: 3.1.0 + 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 + parse-png@2.1.0: dependencies: pngjs: 3.4.0 + parse5@7.3.0: + dependencies: + entities: 6.0.1 + parseurl@1.3.3: {} + path-browserify@1.0.1: {} + path-exists@4.0.0: {} path-is-absolute@1.0.1: {} @@ -9975,6 +13831,8 @@ snapshots: pathe@2.0.3: {} + piccolore@0.1.3: {} + picocolors@1.1.1: {} picomatch@2.3.2: {} @@ -9995,6 +13853,16 @@ snapshots: possible-typed-array-names@1.1.0: {} + postcss-nested@6.2.0(postcss@8.5.19): + dependencies: + postcss: 8.5.19 + postcss-selector-parser: 6.1.4 + + postcss-selector-parser@6.1.4: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss-value-parser@4.2.0: {} postcss@8.4.49: @@ -10025,8 +13893,12 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 + prismjs@1.30.0: {} + proc-log@4.2.0: {} + process-ancestry@0.1.0: {} + progress@2.0.3: {} promise@7.3.1: @@ -10048,6 +13920,8 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + property-information@7.2.0: {} + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -10081,6 +13955,8 @@ snapshots: dependencies: inherits: 2.0.4 + radix3@1.1.2: {} + range-parser@1.2.1: {} range-parser@1.3.0: {} @@ -10270,6 +14146,39 @@ snapshots: react@19.1.0: {} + readdirp@4.1.2: {} + + readdirp@5.1.1: {} + + 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.17.0): + dependencies: + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.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 + reflect-metadata@0.2.2: {} reflect.getprototypeof@1.0.10: @@ -10291,6 +14200,16 @@ snapshots: regenerator-runtime@0.13.11: {} + 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 + regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.9 @@ -10317,6 +14236,110 @@ snapshots: dependencies: jsesc: 3.1.0 + rehype-expressive-code@0.44.2: + dependencies: + expressive-code: 0.44.2 + + rehype-minify-whitespace@6.0.2: + dependencies: + '@types/hast': 3.0.5 + hast-util-minify-whitespace: 1.0.1 + + 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-remark@10.0.1: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + hast-util-to-mdast: 10.1.2 + unified: 11.0.5 + vfile: 6.0.3 + + rehype-stringify@10.0.1: + dependencies: + '@types/hast': 3.0.5 + hast-util-to-html: 9.0.5 + 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 + + request-light@0.5.8: {} + + request-light@0.7.0: {} + require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -10362,6 +14385,31 @@ snapshots: onetime: 2.0.1 signal-exit: 3.0.7 + 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 + reusify@1.1.0: {} rimraf@3.0.2: @@ -10426,8 +14474,27 @@ snapshots: safer-buffer@2.1.2: {} + satteri@0.10.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.10.5 + '@bruits/satteri-darwin-x64': 0.10.5 + '@bruits/satteri-linux-arm64-gnu': 0.10.5 + '@bruits/satteri-linux-arm64-musl': 0.10.5 + '@bruits/satteri-linux-x64-gnu': 0.10.5 + '@bruits/satteri-linux-x64-musl': 0.10.5 + '@bruits/satteri-wasm32-wasi': 0.10.5 + '@bruits/satteri-win32-arm64-msvc': 0.10.5 + '@bruits/satteri-win32-x64-msvc': 0.10.5 + sax@1.6.0: {} + sax@1.6.1: {} + scheduler@0.26.0: {} semver@6.3.1: {} @@ -10524,6 +14591,39 @@ snapshots: shallowequal@1.1.0: {} + sharp@0.35.4(@types/node@24.13.6): + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.4 + '@img/sharp-darwin-x64': 0.35.4 + '@img/sharp-freebsd-wasm32': 0.35.4 + '@img/sharp-libvips-darwin-arm64': 1.3.3 + '@img/sharp-libvips-darwin-x64': 1.3.3 + '@img/sharp-libvips-linux-arm': 1.3.3 + '@img/sharp-libvips-linux-arm64': 1.3.3 + '@img/sharp-libvips-linux-ppc64': 1.3.3 + '@img/sharp-libvips-linux-riscv64': 1.3.3 + '@img/sharp-libvips-linux-s390x': 1.3.3 + '@img/sharp-libvips-linux-x64': 1.3.3 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.3 + '@img/sharp-libvips-linuxmusl-x64': 1.3.3 + '@img/sharp-linux-arm': 0.35.4 + '@img/sharp-linux-arm64': 0.35.4 + '@img/sharp-linux-ppc64': 0.35.4 + '@img/sharp-linux-riscv64': 0.35.4 + '@img/sharp-linux-s390x': 0.35.4 + '@img/sharp-linux-x64': 0.35.4 + '@img/sharp-linuxmusl-arm64': 0.35.4 + '@img/sharp-linuxmusl-x64': 0.35.4 + '@img/sharp-webcontainers-wasm32': 0.35.4 + '@img/sharp-win32-arm64': 0.35.4 + '@img/sharp-win32-ia32': 0.35.4 + '@img/sharp-win32-x64': 0.35.4 + '@types/node': 24.13.6 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -10532,6 +14632,17 @@ snapshots: shell-quote@1.10.0: {} + shiki@4.4.3: + dependencies: + '@shikijs/core': 4.4.3 + '@shikijs/engine-javascript': 4.4.3 + '@shikijs/engine-oniguruma': 4.4.3 + '@shikijs/langs': 4.4.3 + '@shikijs/themes': 4.4.3 + '@shikijs/types': 4.4.3 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + side-channel-list@1.0.1: dependencies: es-errors: 1.3.0 @@ -10576,10 +14687,19 @@ snapshots: sisteransi@1.0.5: {} + sitemap@9.0.1: + dependencies: + '@types/node': 24.13.6 + '@types/sax': 1.2.7 + arg: 5.0.2 + sax: 1.6.0 + slash@3.0.0: {} slugify@1.6.9: {} + smol-toml@1.8.0: {} + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -10591,6 +14711,10 @@ snapshots: source-map@0.6.1: {} + source-map@0.7.6: {} + + space-separated-tokens@2.0.2: {} + split-on-first@1.1.0: {} sprintf-js@1.0.3: {} @@ -10611,6 +14735,46 @@ snapshots: standard-navigation@0.0.7: {} + starlight-links-validator@0.26.0(@astrojs/starlight@0.42.2(@astrojs/markdown-remark@7.3.1)(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0))(typescript@5.9.3))(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0)): + dependencies: + '@astrojs/markdown-satteri': 0.4.1 + '@astrojs/starlight': 0.42.2(@astrojs/markdown-remark@7.3.1)(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0))(typescript@5.9.3) + '@types/picomatch': 4.0.3 + astro: 7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0) + github-slugger: 2.0.0 + hast-util-from-html: 2.0.3 + is-absolute-url: 5.0.0 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-to-hast: 13.2.1 + picomatch: 4.0.5 + satteri: 0.10.5 + terminal-link: 5.0.0 + unist-util-visit: 5.1.0 + yaml: 2.9.0 + transitivePeerDependencies: + - supports-color + + starlight-llms-txt@0.12.0(@astrojs/markdown-remark@7.3.1)(@astrojs/markdown-satteri@0.4.1)(@astrojs/starlight@0.42.2(@astrojs/markdown-remark@7.3.1)(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0))(typescript@5.9.3))(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0)): + dependencies: + '@astrojs/mdx': 8.0.1(@astrojs/markdown-remark@7.3.1)(@astrojs/markdown-satteri@0.4.1)(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0)) + '@astrojs/starlight': 0.42.2(@astrojs/markdown-remark@7.3.1)(astro@7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0))(typescript@5.9.3) + '@types/hast': 3.0.5 + '@types/micromatch': 4.0.10 + astro: 7.3.3(@astrojs/markdown-remark@7.3.1)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.6)(terser@5.49.0)(yaml@2.9.0) + github-slugger: 2.0.0 + hast-util-select: 6.0.4 + micromatch: 4.0.8 + rehype-parse: 9.0.1 + rehype-remark: 10.0.1 + remark-gfm: 4.0.1 + remark-stringify: 11.0.0 + unified: 11.0.5 + unist-util-remove: 4.0.0 + transitivePeerDependencies: + - '@astrojs/markdown-remark' + - '@astrojs/markdown-satteri' + - supports-color + statuses@1.5.0: {} statuses@2.0.2: {} @@ -10632,6 +14796,17 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.7.0 + strip-ansi: 7.2.0 + + string-width@8.2.2: + dependencies: + get-east-asian-width: 1.7.0 + strip-ansi: 7.2.0 + string.prototype.matchall@4.0.12: dependencies: call-bind: 1.0.9 @@ -10677,6 +14852,11 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.2 + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + strip-ansi@5.2.0: dependencies: ansi-regex: 4.1.1 @@ -10685,6 +14865,10 @@ snapshots: dependencies: ansi-regex: 5.0.1 + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.3.0 + strip-bom@3.0.0: {} strip-json-comments@2.0.1: {} @@ -10693,6 +14877,14 @@ snapshots: structured-headers@0.4.1: {} + 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 + styleq@0.1.3: {} sucrase@3.35.1: @@ -10705,6 +14897,8 @@ snapshots: tinyglobby: 0.2.17 ts-interface-checker: 0.1.13 + supports-color@10.2.2: {} + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -10722,8 +14916,23 @@ snapshots: has-flag: 4.0.0 supports-color: 7.2.0 + supports-hyperlinks@4.5.0: + dependencies: + has-flag: 5.0.1 + supports-color: 10.2.2 + supports-preserve-symlinks-flag@1.0.0: {} + svgo@4.1.0: + dependencies: + commander: 11.1.0 + css-select: 6.0.0 + css-tree: 3.2.1 + css-what: 7.0.0 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.6.1 + synckit@0.11.13: dependencies: '@pkgr/core': 0.3.6 @@ -10743,6 +14952,11 @@ snapshots: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 + terminal-link@5.0.0: + dependencies: + ansi-escapes: 7.3.0 + supports-hyperlinks: 4.5.0 + terser@5.49.0: dependencies: '@jridgewell/source-map': 0.3.11 @@ -10768,8 +14982,12 @@ snapshots: throat@5.0.0: {} + tiny-inflate@1.0.3: {} + tinybench@2.9.0: {} + tinyclip@0.1.15: {} + tinyexec@1.2.4: {} tinyglobby@0.2.17: @@ -10791,6 +15009,12 @@ snapshots: tr46@0.0.3: {} + trim-lines@3.0.1: {} + + trim-trailing-lines@2.1.0: {} + + trough@2.2.0: {} + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -10877,10 +15101,20 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 + typesafe-path@0.2.2: {} + + typescript-auto-import-cache@0.3.6: + dependencies: + semver: 7.8.5 + typescript@5.9.3: {} ua-parser-js@1.0.41: {} + ufo@1.6.4: {} + + ultrahtml@1.7.0: {} + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -10888,10 +15122,16 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 + uncrypto@0.1.3: {} + undici-types@6.21.0: {} + undici-types@7.18.2: {} + undici@6.27.0: {} + undici@8.10.2: {} + unicode-canonical-property-names-ecmascript@2.0.1: {} unicode-match-property-ecmascript@2.0.0: @@ -10903,6 +15143,74 @@ snapshots: unicode-property-aliases-ecmascript@2.2.0: {} + 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.5: + dependencies: + css-tree: 3.2.1 + ohash: 2.0.12 + undici: 8.10.2 + + 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-remove@4.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + 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 + unpipe@1.0.0: {} unrs-resolver@1.12.2: @@ -10932,6 +15240,17 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 '@unrs/resolver-binding-win32-x64-msvc': 1.12.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 + update-browserslist-db@1.2.3(browserslist@4.28.6): dependencies: browserslist: 4.28.6 @@ -10942,6 +15261,8 @@ snapshots: dependencies: punycode: 2.3.1 + url-extras@0.1.0: {} + use-callback-ref@1.3.3(@types/react@19.1.17)(react@19.1.0): dependencies: react: 19.1.0 @@ -10965,6 +15286,8 @@ snapshots: dependencies: react: 19.1.0 + util-deprecate@1.0.2: {} + utils-merge@1.0.1: {} uuid@7.0.3: {} @@ -10982,7 +15305,24 @@ snapshots: - '@types/react' - '@types/react-dom' - vite@8.1.4(@types/node@22.20.1)(terser@5.49.0)(yaml@2.9.0): + verkit@0.4.1: {} + + 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.1.4(@types/node@24.13.6)(esbuild@0.28.2)(terser@5.49.0)(yaml@2.9.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.5 @@ -10990,15 +15330,20 @@ snapshots: rolldown: 1.1.5 tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 22.20.1 + '@types/node': 24.13.6 + esbuild: 0.28.2 fsevents: 2.3.3 terser: 5.49.0 yaml: 2.9.0 - vitest@4.1.10(@types/node@22.20.1)(vite@8.1.4(@types/node@22.20.1)(terser@5.49.0)(yaml@2.9.0)): + vitefu@1.1.3(vite@8.1.4(@types/node@24.13.6)(esbuild@0.28.2)(terser@5.49.0)(yaml@2.9.0)): + optionalDependencies: + vite: 8.1.4(@types/node@24.13.6)(esbuild@0.28.2)(terser@5.49.0)(yaml@2.9.0) + + vitest@4.1.10(@types/node@24.13.6)(vite@8.1.4(@types/node@24.13.6)(esbuild@0.28.2)(terser@5.49.0)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.1.4(@types/node@22.20.1)(terser@5.49.0)(yaml@2.9.0)) + '@vitest/mocker': 4.1.10(vite@8.1.4(@types/node@24.13.6)(esbuild@0.28.2)(terser@5.49.0)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.10 '@vitest/runner': 4.1.10 '@vitest/snapshot': 4.1.10 @@ -11015,15 +15360,121 @@ snapshots: tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.1.4(@types/node@22.20.1)(terser@5.49.0)(yaml@2.9.0) + vite: 8.1.4(@types/node@24.13.6)(esbuild@0.28.2)(terser@5.49.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.20.1 + '@types/node': 24.13.6 transitivePeerDependencies: - msw vlq@1.0.1: {} + volar-service-css@0.0.71(@volar/language-service@2.4.28): + dependencies: + vscode-css-languageservice: 6.3.10 + vscode-languageserver-textdocument: 1.0.14 + vscode-uri: 3.2.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-emmet@0.0.71(@volar/language-service@2.4.28): + dependencies: + '@emmetio/css-parser': 0.4.1 + '@emmetio/html-matcher': 1.3.0 + '@vscode/emmet-helper': 2.11.0 + vscode-uri: 3.2.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-html@0.0.71(@volar/language-service@2.4.28): + dependencies: + vscode-html-languageservice: 5.6.2 + vscode-languageserver-textdocument: 1.0.14 + vscode-uri: 3.2.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-prettier@0.0.71(@volar/language-service@2.4.28)(prettier@3.9.5): + dependencies: + vscode-uri: 3.2.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + prettier: 3.9.5 + + volar-service-typescript-twoslash-queries@0.0.71(@volar/language-service@2.4.28): + dependencies: + vscode-uri: 3.2.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-typescript@0.0.71(@volar/language-service@2.4.28): + dependencies: + path-browserify: 1.0.1 + semver: 7.8.5 + typescript-auto-import-cache: 0.3.6 + vscode-languageserver-textdocument: 1.0.14 + vscode-nls: 5.2.0 + vscode-uri: 3.2.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-yaml@0.0.71(@volar/language-service@2.4.28): + dependencies: + vscode-uri: 3.2.0 + yaml-language-server: 1.23.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + vscode-css-languageservice@6.3.10: + dependencies: + '@vscode/l10n': 0.0.18 + vscode-languageserver-textdocument: 1.0.14 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.2.0 + + vscode-html-languageservice@5.6.2: + dependencies: + '@vscode/l10n': 0.0.18 + vscode-languageserver-textdocument: 1.0.14 + vscode-languageserver-types: 3.18.3 + vscode-uri: 3.2.0 + + vscode-json-languageservice@4.1.8: + dependencies: + jsonc-parser: 3.3.1 + vscode-languageserver-textdocument: 1.0.14 + vscode-languageserver-types: 3.18.3 + vscode-nls: 5.2.0 + vscode-uri: 3.2.0 + + vscode-jsonrpc@8.2.0: {} + + vscode-jsonrpc@9.0.2: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-protocol@3.18.3: + dependencies: + vscode-jsonrpc: 9.0.2 + vscode-languageserver-types: 3.18.3 + + vscode-languageserver-textdocument@1.0.14: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver-types@3.18.3: {} + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-nls@5.2.0: {} + + vscode-uri@3.2.0: {} + walker@1.0.8: dependencies: makeerror: 1.0.12 @@ -11034,6 +15485,8 @@ snapshots: dependencies: defaults: 1.0.4 + web-namespaces@2.0.1: {} + webidl-conversions@3.0.1: {} webidl-conversions@5.0.0: {} @@ -11111,6 +15564,12 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.2.0 + wrappy@1.0.2: {} write-file-atomic@4.0.2: @@ -11140,16 +15599,37 @@ snapshots: xmlbuilder@15.1.1: {} + xxhash-wasm@1.1.0: {} + y18n@5.0.8: {} yallist@3.1.1: {} yallist@5.0.0: {} + yaml-language-server@1.23.0: + dependencies: + '@vscode/l10n': 0.0.18 + ajv: 8.20.0 + ajv-draft-04: 1.0.0(ajv@8.20.0) + ajv-i18n: 4.2.0(ajv@8.20.0) + prettier: 3.9.5 + request-light: 0.5.8 + vscode-json-languageservice: 4.1.8 + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.14 + vscode-languageserver-types: 3.18.3 + vscode-uri: 3.2.0 + yaml: 2.8.3 + + yaml@2.8.3: {} + yaml@2.9.0: {} yargs-parser@21.1.1: {} + yargs-parser@22.0.0: {} + yargs@17.7.3: dependencies: cliui: 8.0.1 @@ -11160,15 +15640,26 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yargs@18.1.0: + dependencies: + cliui: 9.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + string-width: 8.2.2 + y18n: 5.0.8 + yargs-parser: 22.0.0 + yocto-queue@0.1.0: {} + yocto-queue@1.2.2: {} + zod-to-json-schema@3.25.2(zod@3.25.76): dependencies: zod: 3.25.76 - zod-to-json-schema@3.25.2(zod@4.4.3): + zod-to-json-schema@3.25.2(zod@4.6.5): dependencies: - zod: 4.4.3 + zod: 4.6.5 zod-validation-error@4.0.2(zod@4.4.3): dependencies: @@ -11177,3 +15668,7 @@ snapshots: zod@3.25.76: {} zod@4.4.3: {} + + zod@4.6.5: {} + + zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index dbc4c01c..774491ac 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,6 +1,7 @@ packages: - "packages/*" - "playground" + - "website" allowBuilds: # esbuild works without its postinstall (it loads the platform binary from its optional # dependency), and CI installs with --ignore-scripts anyway. diff --git a/scripts/check-md-links.mjs b/scripts/check-md-links.mjs index dab965f0..0aa287fb 100644 --- a/scripts/check-md-links.mjs +++ b/scripts/check-md-links.mjs @@ -48,6 +48,13 @@ const IGNORED_DIRS = new Set([ "ios", ]); +/** + * Starlight content, as repo-relative paths. Its links are site URLs (`/appduct/start/…`), not + * file paths, so this checker cannot resolve them; starlight-links-validator checks them during + * the website build instead. + */ +const IGNORED_PATHS = new Set([join("website", "src", "content")]); + /** Schemes that are out of scope for an offline checker. */ const EXTERNAL = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i; @@ -77,7 +84,7 @@ function collectMarkdown(dir, out = []) { if (entry.name.startsWith(".") && entry.name !== ".github") continue; const full = join(dir, entry.name); if (entry.isDirectory()) { - if (IGNORED_DIRS.has(entry.name)) continue; + if (IGNORED_DIRS.has(entry.name) || IGNORED_PATHS.has(relative(ROOT, full))) continue; collectMarkdown(full, out); } else if (entry.isFile() && entry.name.endsWith(".md")) { out.push(full); diff --git a/website/.gitignore b/website/.gitignore new file mode 100644 index 00000000..b338faaa --- /dev/null +++ b/website/.gitignore @@ -0,0 +1,2 @@ +.astro/ +dist/ diff --git a/website/README.md b/website/README.md new file mode 100644 index 00000000..cbe5e33f --- /dev/null +++ b/website/README.md @@ -0,0 +1,35 @@ +# Appduct website + +The Appduct landing page and documentation, built with [Astro](https://astro.build) and [Starlight](https://starlight.astro.build). It is published at . + +## Run it + +From the repository root: + +```bash +pnpm install +pnpm --filter @appduct/website dev # http://localhost:4321/appduct/ +pnpm --filter @appduct/website build # static site in website/dist +pnpm --filter @appduct/website preview # serve the built site +pnpm --filter @appduct/website typecheck # astro check +``` + +The build fails on a broken internal link between docs pages (checked by `starlight-links-validator`). + +## Where things live + +| Path | What it is | +| --- | --- | +| `src/content/docs/` | Docs pages, one `.md`/`.mdx` file per page. The folder decides the sidebar group (`start`, `guides`, `reference`); `sidebar.order` in the frontmatter decides the position. Link between pages with site URLs such as `/appduct/start/quick-start/`. | +| `src/pages/index.astro` | The landing page. | +| `src/pages/[...slug].md.ts` | Serves every docs page as raw Markdown at `.md`. | +| `src/components/` | Starlight component overrides: header title and links, hero, footer, default dark theme. | +| `src/styles/` | The Callstack theme (`theme.css`) and docs styling (`docs.css`). | +| `ec.config.mjs` | Code block themes. | +| `astro.config.mjs` | Site config, sidebar, and the `llms.txt` setup. | + +The build also writes `llms.txt`, `llms-full.txt`, and `llms-small.txt` for LLMs, plus a sitemap. + +## Deploy + +[`.github/workflows/website.yaml`](../.github/workflows/website.yaml) builds the site on every pull request that touches it and deploys `website/dist` to GitHub Pages on each push to `main`. The repository's Pages source must be set to **GitHub Actions**. diff --git a/website/astro.config.mjs b/website/astro.config.mjs new file mode 100644 index 00000000..f7ab5f86 --- /dev/null +++ b/website/astro.config.mjs @@ -0,0 +1,103 @@ +// @ts-check +import starlight from '@astrojs/starlight'; +import { defineConfig } from 'astro/config'; +import starlightLinksValidator from 'starlight-links-validator'; +import starlightLlmsTxt from 'starlight-llms-txt'; + +import { llmsPageIndex } from './llms-page-index.mjs'; + +const site = 'https://callstackincubator.github.io'; +const base = '/appduct'; +const repo = 'https://github.com/callstackincubator/appduct'; + +const description = + 'Let agents and tests reach into your running app — without shipping a debug menu.'; + +// Starlight adds @astrojs/sitemap itself once `site` is set, so it is not listed here. +export default defineConfig({ + site, + base, + trailingSlash: 'ignore', + devToolbar: { enabled: false }, + integrations: [ + starlight({ + title: 'Appduct', + description, + favicon: '/favicon.svg', + social: [{ icon: 'github', label: 'GitHub', href: repo }], + editLink: { baseUrl: `${repo}/edit/main/website/` }, + lastUpdated: true, + credits: false, + customCss: [ + '@fontsource/geist-mono/latin-400.css', + '@fontsource/geist-mono/latin-500.css', + './src/fonts/font-face.css', + './src/styles/theme.css', + './src/styles/docs.css', + ], + head: [ + { + tag: 'link', + attrs: { + rel: 'alternate', + type: 'text/plain', + title: 'llms.txt', + href: `${base}/llms.txt`, + }, + }, + { tag: 'meta', attrs: { name: 'theme-color', content: '#000000' } }, + ], + components: { + Head: './src/components/Head.astro', + ThemeProvider: './src/components/ThemeProvider.astro', + SiteTitle: './src/components/SiteTitle.astro', + SocialIcons: './src/components/SocialIcons.astro', + Hero: './src/components/Hero.astro', + Footer: './src/components/Footer.astro', + }, + sidebar: [ + { label: 'Start here', items: [{ autogenerate: { directory: 'start' } }] }, + { label: 'Guides', items: [{ autogenerate: { directory: 'guides' } }] }, + { label: 'Reference', items: [{ autogenerate: { directory: 'reference' } }] }, + ], + plugins: [ + starlightLinksValidator({ + // The generated LLM files and per-page Markdown copies are build outputs, not docs pages. + exclude: [`${base}/llms*.txt`, `${base}/**/*.md`], + }), + starlightLlmsTxt({ + projectName: 'Appduct', + description: + 'Appduct lets a terminal, a test runner, or an AI agent call functions inside a running React Native, iOS, or Android app. The app registers a few functions ("tools") with a name, a description, and an input schema; the `appduct` CLI and its MCP server discover and invoke them over an encrypted connection. Nothing else in the app is reachable, and it is compiled out of release builds by default.', + details: [ + 'Key facts for answering questions about Appduct:', + '', + '- Packages: `appduct` (CLI, background service, and MCP server — `npm install -g appduct`), `@appduct/react-native` (app-side library and Expo config plugin, used with `zod` schemas via the `useAppductTool` hook), `AppductCore` (iOS, Swift Package Manager or CocoaPods), and `com.callstack.appduct:core` (Android, Maven Central, paired with `core-noop` for release builds).', + '- Agents connect over MCP (`{ "mcpServers": { "appduct": { "command": "appduct", "args": ["mcp"] } } }`) or through the CLI with the Appduct skill (`npx skills add callstackincubator/appduct --skill appduct`).', + '- Appduct is included in debug builds only unless a build opts in (see Build variants). Expo Go is not supported; use a development build.', + '- Every page is also available as raw Markdown by replacing the trailing slash of its URL with `.md`.', + '', + llmsPageIndex({ site, base }), + ].join('\n'), + promote: ['start/introduction', 'start/quick-start', 'start/**'], + demote: ['reference/protocol', 'reference/architecture'], + customSets: [ + { + label: 'Getting started', + description: 'installing Appduct and setting it up for React Native, iOS, or Android', + paths: ['start/**'], + }, + { + label: 'Reference', + description: 'CLI and React Native API reference, architecture, and wire protocol', + paths: ['reference/**'], + }, + ], + optionalLinks: [ + { label: 'GitHub repository', url: repo, description: 'source code, issues, and releases' }, + ], + }), + ], + }), + ], +}); diff --git a/website/ec.config.mjs b/website/ec.config.mjs new file mode 100644 index 00000000..b82268ac --- /dev/null +++ b/website/ec.config.mjs @@ -0,0 +1,86 @@ +// @ts-check +// Expressive Code config lives in its own file (rather than inline in astro.config.mjs) so the +// `` component on the landing page renders with the same custom themes as Markdown fences. +import { defineEcConfig, ExpressiveCodeTheme } from '@astrojs/starlight/expressive-code'; + +/** + * A minimal VS Code-style theme built from the Callstack code-block palette. + * @param {'dark' | 'light'} type + * @param {Record<'bg' | 'fg' | 'kw' | 'str' | 'fn' | 'num' | 'com' | 'punc' | 'type', string>} c + */ +function callstackTheme(type, c) { + const theme = { + name: `callstack-${type}`, + type, + colors: { + 'editor.background': c.bg, + 'editor.foreground': c.fg, + }, + tokenColors: [ + { scope: ['comment', 'punctuation.definition.comment'], settings: { foreground: c.com, fontStyle: 'italic' } }, + { + scope: ['keyword', 'storage', 'storage.type', 'keyword.operator.new', 'keyword.control', 'variable.language', 'constant.language'], + settings: { foreground: c.kw }, + }, + { scope: ['string', 'string.quoted', 'string.template', 'markup.inline.raw'], settings: { foreground: c.str } }, + { scope: ['entity.name.function', 'support.function', 'meta.function-call', 'entity.name.tag'], settings: { foreground: c.fn } }, + { scope: ['constant.numeric', 'constant.other', 'support.constant'], settings: { foreground: c.num } }, + { scope: ['entity.name.type', 'support.type', 'support.class', 'entity.other.attribute-name', 'support.type.property-name'], settings: { foreground: c.type } }, + { scope: ['punctuation', 'meta.brace', 'keyword.operator'], settings: { foreground: c.punc } }, + { scope: ['variable', 'variable.other', 'meta.object-literal.key'], settings: { foreground: c.fg } }, + ], + }; + return ExpressiveCodeTheme.fromJSONString(JSON.stringify(theme)); +} + +const dark = callstackTheme('dark', { + bg: '#131116', + fg: '#efedf5', + kw: '#c7a3ff', + str: '#addfc5', + fn: '#e2d0ff', + num: '#efc28f', + com: '#aaa5b4', + punc: '#bab4c7', + type: '#e2d0ff', +}); + +const light = callstackTheme('light', { + bg: '#f7f5fb', + fg: '#29232f', + kw: '#7222c9', + str: '#286345', + fn: '#5d388b', + num: '#9a4c19', + com: '#726a7d', + punc: '#766b84', + type: '#5d388b', +}); + +export default defineEcConfig({ + themes: [dark, light], + styleOverrides: { + borderRadius: '0', + borderWidth: '1px', + borderColor: ({ theme }) => (theme.type === 'dark' ? '#ffffff26' : '#ded7e8'), + codeFontFamily: "'Geist Mono', ui-monospace, monospace", + codeFontSize: '0.875rem', + codeLineHeight: '1.7', + uiFontFamily: "'Geist Mono', ui-monospace, monospace", + frames: { + shadowColor: 'transparent', + frameBoxShadowCssValue: 'none', + editorActiveTabIndicatorTopColor: '#8232ff', + editorActiveTabIndicatorBottomColor: 'transparent', + editorTabBarBackground: ({ theme }) => (theme.type === 'dark' ? '#0b0a0d' : '#efebf6'), + editorActiveTabBackground: ({ theme }) => (theme.type === 'dark' ? '#131116' : '#f7f5fb'), + terminalTitlebarBackground: ({ theme }) => (theme.type === 'dark' ? '#0b0a0d' : '#efebf6'), + terminalBackground: ({ theme }) => (theme.type === 'dark' ? '#131116' : '#f7f5fb'), + terminalTitlebarDotsOpacity: '0.35', + terminalTitlebarBorderBottomColor: ({ theme }) => (theme.type === 'dark' ? '#ffffff1a' : '#ded7e8'), + tooltipSuccessBackground: '#8232ff', + tooltipSuccessForeground: '#ffffff', + inlineButtonBorder: ({ theme }) => (theme.type === 'dark' ? '#ffffff40' : '#00000030'), + }, + }, +}); diff --git a/website/llms-page-index.mjs b/website/llms-page-index.mjs new file mode 100644 index 00000000..bbb7e181 --- /dev/null +++ b/website/llms-page-index.mjs @@ -0,0 +1,58 @@ +// Builds the per-page index that goes into llms.txt. starlight-llms-txt only links the +// concatenated files, so this lists every docs page (title, description, raw-Markdown URL) +// the way llmstxt.org expects. It reads frontmatter straight from disk at config time, which +// keeps it in step with the sidebar without a second source of truth. +import { existsSync, readdirSync, readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const docsDir = fileURLToPath(new URL('./src/content/docs/', import.meta.url)); + +/** Sidebar groups in display order: directory → label. */ +const groups = [ + ['start', 'Start here'], + ['guides', 'Guides'], + ['reference', 'Reference'], +]; + +/** @param {string} source */ +function frontmatter(source) { + const block = /^---\r?\n([\s\S]*?)\r?\n---/.exec(source)?.[1] ?? ''; + /** @param {RegExp} pattern */ + const field = (pattern) => { + const raw = pattern.exec(block)?.[1]?.trim() ?? ''; + return raw.replace(/^(['"])(.*)\1$/, '$2'); + }; + const order = Number(/^\s+order:\s*(-?\d+)/m.exec(block)?.[1]); + return { + title: field(/^title:\s*(.+)$/m), + description: field(/^description:\s*(.+)$/m), + order: Number.isFinite(order) ? order : Number.MAX_SAFE_INTEGER, + }; +} + +/** + * @param {{ site: string, base: string }} options + * @returns {string} Markdown lists (no headings — llms.txt `details` must not contain any). + */ +export function llmsPageIndex({ site, base }) { + const sections = []; + for (const [dir, label] of groups) { + const full = join(docsDir, dir); + if (!existsSync(full)) continue; + const pages = readdirSync(full) + .filter((name) => /\.mdx?$/.test(name)) + .map((name) => { + const slug = `${dir}/${name.replace(/\.mdx?$/, '')}`; + return { slug, ...frontmatter(readFileSync(join(full, name), 'utf8')) }; + }) + .sort((a, b) => a.order - b.order || a.slug.localeCompare(b.slug)); + if (pages.length === 0) continue; + const lines = pages.map( + ({ slug, title, description }) => + `- [${title || slug}](${site}${base}/${slug}.md)${description ? `: ${description}` : ''}`, + ); + sections.push(`**${label}**\n\n${lines.join('\n')}`); + } + return sections.join('\n\n'); +} diff --git a/website/package.json b/website/package.json new file mode 100644 index 00000000..4c0078d8 --- /dev/null +++ b/website/package.json @@ -0,0 +1,26 @@ +{ + "name": "@appduct/website", + "version": "0.0.0", + "private": true, + "type": "module", + "description": "The Appduct website and documentation, built with Astro Starlight.", + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview", + "typecheck": "astro check" + }, + "dependencies": { + "@astrojs/markdown-remark": "^7.3.1", + "@astrojs/starlight": "^0.42.2", + "@fontsource/geist-mono": "^5.3.0", + "astro": "^7.3.3", + "sharp": "^0.35.4", + "starlight-links-validator": "^0.26.0", + "starlight-llms-txt": "^0.12.0" + }, + "devDependencies": { + "@astrojs/check": "^0.9.10", + "typescript": "~5.9.2" + } +} diff --git a/website/public/favicon.svg b/website/public/favicon.svg new file mode 100644 index 00000000..c6956bc6 --- /dev/null +++ b/website/public/favicon.svg @@ -0,0 +1 @@ + diff --git a/website/public/robots.txt b/website/public/robots.txt new file mode 100644 index 00000000..2620ca38 --- /dev/null +++ b/website/public/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: / + +Sitemap: https://callstackincubator.github.io/appduct/sitemap-index.xml diff --git a/website/src/assets/callstack-logo.svg b/website/src/assets/callstack-logo.svg new file mode 100644 index 00000000..a2a38f81 --- /dev/null +++ b/website/src/assets/callstack-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/components/CallstackLogo.astro b/website/src/components/CallstackLogo.astro new file mode 100644 index 00000000..cc17c5aa --- /dev/null +++ b/website/src/components/CallstackLogo.astro @@ -0,0 +1,22 @@ +--- +import logo from '../assets/callstack-logo.svg?raw'; + +interface Props { + class?: string; +} +const { class: className } = Astro.props; +--- + + + + diff --git a/website/src/components/Footer.astro b/website/src/components/Footer.astro new file mode 100644 index 00000000..59936fba --- /dev/null +++ b/website/src/components/Footer.astro @@ -0,0 +1,64 @@ +--- +// Docs pages keep Starlight's footer (edit link, last updated, pagination); every page, the +// landing included, ends with the brand strip. +import Default from '@astrojs/starlight/components/Footer.astro'; +import CallstackLogo from './CallstackLogo.astro'; + +const isSplash = Astro.locals.starlightRoute.entry.data.template === 'splash'; +const base = import.meta.env.BASE_URL.replace(/\/$/, ''); +--- + +{!isSplash && } + + + diff --git a/website/src/components/Head.astro b/website/src/components/Head.astro new file mode 100644 index 00000000..ba03bf90 --- /dev/null +++ b/website/src/components/Head.astro @@ -0,0 +1,12 @@ +--- +// Adds a pointer to each docs page's raw-Markdown twin (served by src/pages/[...slug].md.ts) so +// agents that land on the HTML can fetch the source instead of scraping it. +import Default from '@astrojs/starlight/components/Head.astro'; + +const { entry } = Astro.locals.starlightRoute; +const isDocsEntry = 'filePath' in entry && typeof entry.filePath === 'string'; +const markdownHref = isDocsEntry && entry.id ? `${import.meta.env.BASE_URL.replace(/\/$/, '')}/${entry.id}.md` : null; +--- + + +{markdownHref && } diff --git a/website/src/components/Hero.astro b/website/src/components/Hero.astro new file mode 100644 index 00000000..eee37a79 --- /dev/null +++ b/website/src/components/Hero.astro @@ -0,0 +1,60 @@ +--- +// Splash-page hero in the keynote "cover" style: mono eyebrow, a big light two-beat headline, +// a short lede, and square CTAs. `hero.title` may carry an for the accented second beat. +import { Icon } from '@astrojs/starlight/components'; + +const { hero } = Astro.locals.starlightRoute.entry.data; +const { title = '', tagline, actions = [] } = hero ?? {}; +--- + +
+

Open source · React Native · iOS · Android

+

+ {tagline &&

} + { + actions.length > 0 && ( +

+ {actions.map(({ text, link, variant, icon, attrs }) => ( + + {text} + {icon?.type === 'icon' && } + + ))} +
+ ) + } +

+ + diff --git a/website/src/components/SiteTitle.astro b/website/src/components/SiteTitle.astro new file mode 100644 index 00000000..ff0fd881 --- /dev/null +++ b/website/src/components/SiteTitle.astro @@ -0,0 +1,42 @@ +--- +const { siteTitleHref } = Astro.locals.starlightRoute; +--- + + + appduct + by Callstack + + + diff --git a/website/src/components/SocialIcons.astro b/website/src/components/SocialIcons.astro new file mode 100644 index 00000000..2c096d40 --- /dev/null +++ b/website/src/components/SocialIcons.astro @@ -0,0 +1,35 @@ +--- +// Header links in the slide-chrome style: mono, uppercase, text only. +const base = import.meta.env.BASE_URL.replace(/\/$/, ''); +const links = [ + { label: 'Docs', href: `${base}/start/introduction/` }, + { label: 'GitHub', href: 'https://github.com/callstackincubator/appduct', external: true }, +]; +--- + +{ + links.map(({ label, href, external }) => ( + + {label} + {external && } + + )) +} + + diff --git a/website/src/components/ThemeProvider.astro b/website/src/components/ThemeProvider.astro new file mode 100644 index 00000000..f8835f2e --- /dev/null +++ b/website/src/components/ThemeProvider.astro @@ -0,0 +1,13 @@ +--- +// Dark is the default look. Starlight falls back to the system preference when nothing is +// stored, so seed "dark" for first-time visitors only. Choosing "Auto" in the picker stores "" +// (not null), so an explicit choice is never overwritten. +import Default from '@astrojs/starlight/components/ThemeProvider.astro'; +--- + + + diff --git a/website/src/content.config.ts b/website/src/content.config.ts new file mode 100644 index 00000000..d9ee8c9d --- /dev/null +++ b/website/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/website/src/content/docs/guides/agents.mdx b/website/src/content/docs/guides/agents.mdx new file mode 100644 index 00000000..5274a0bf --- /dev/null +++ b/website/src/content/docs/guides/agents.mdx @@ -0,0 +1,153 @@ +--- +title: Use Appduct with an agent +description: Connect Claude Code, Cursor, or another agent to your app over MCP or through the CLI, and require approval for risky tools. +sidebar: + order: 1 +--- + +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +An agent can list your app's tools, call them, and connect a simulator on its own. There are two ways to hook it up: + +- **Over MCP**, for Claude Code, Cursor, and any other MCP client. Nothing else to install. +- **Through the CLI**, for agents that work in a shell, and for scripts. Install the Appduct skill so the agent knows the commands. + +Both need the CLI installed on your computer (`npm install -g appduct`) and an app with Appduct set up. See the [Quick start](/appduct/start/quick-start/). + +## Add Appduct as an MCP server + +Add this entry to your agent's MCP config: + + + + In `.mcp.json` at your project root: + + ```json title=".mcp.json" + { + "mcpServers": { + "appduct": { "command": "appduct", "args": ["mcp"] } + } + } + ``` + + + In `.cursor/mcp.json` at your project root: + + ```json title=".cursor/mcp.json" + { + "mcpServers": { + "appduct": { "command": "appduct", "args": ["mcp"] } + } + } + ``` + + + Configure a stdio server that runs `appduct mcp`. There's no separate server to start: it starts Appduct's background service the same way the CLI does. + + + +**Name your app's scheme in the entry.** An MCP server usually starts in a directory you don't control, so Appduct may not find your app's scheme there. Run `appduct init` in your app's root: it prints an entry that includes the scheme, like this: + +```json +{ + "mcpServers": { + "appduct": { "command": "appduct", "args": ["mcp", "--scheme", "myapp"] } + } +} +``` + +Without a scheme, the server still starts, and the agent can use a device you've already connected from the terminal. Only connecting new devices fails. + +## What the agent sees + +Your app's tools aren't added to the agent's tool list one by one. Instead, the agent gets seven built-in tools. Three of them reach your app's tools, and work like the CLI: + +| Tool | What it does | CLI equivalent | +| --- | --- | --- | +| `appduct_list_tools` | Lists your app's tools as one-line signatures, with each tool's group and policy, and your app's groups with counts. Returns 50 at a time unless given `limit`; takes `group`, `filter`, and `offset`. | `appduct tools` | +| `appduct_describe_tool` | Shows one tool's full input and output schema. | `appduct tools ` | +| `appduct_call_tool` | Calls a tool by `name` with `args`. Progress and errors come through unchanged. | `appduct invoke` | + +So an app with hundreds of tools adds only these to the agent's context, and the list doesn't change when tools register or a device connects. + +The other four connect devices and read app events: + +| Tool | What it does | +| --- | --- | +| `appduct_connect` | Creates a connection link and opens it on a booted iOS Simulator or Android emulator it finds. If there's none, it returns a QR code for you to scan. | +| `appduct_wait_for_session` | Waits until the device connects. | +| `appduct_events` | Returns events your app posted with `postEvent`, since a cursor. | +| `appduct_wait_for_event` | Waits for a specific app event, checking events that already arrived first. | + +With more than one device connected, the agent passes `selector`, the session's alias or id, to pick one. + +### How an agent connects a device + +1. It calls `appduct_connect` with no arguments. If a simulator or emulator is running, the link is opened there and the result says `delivered: true`. +2. It calls `appduct_wait_for_session`, which returns once the app connects. +3. It lists, describes, and calls tools. + +If nothing is running, `appduct_connect` returns a QR code and instructions to show it to you. Scan it with your device's camera; the agent waits afterward. + +**Android needs your package name.** Record it once with `appduct init --android-app-id com.example.shop` in your app root, or the agent has to pass `appId` on every connect. Without one, connecting to Android fails before anything happens. + +**Physical iPhones are never picked automatically**, since a paired iPhone is often someone's personal phone. The agent can target one only if you ask it to (`target: "ios-device"` with `appId`); it's experimental and has [extra requirements](/appduct/guides/cli/#physical-iphone-or-ipad-experimental). + +## Require approval for risky tools + +Your MCP client asks permission for `appduct_call_tool` as a single tool. If you choose "always allow" there, you approve **every** tool your app registers, destructive ones included. + +To keep approving those calls yourself, set `policy.destructive` to `"prompt"` in Appduct's config file, `~/.appduct/config.json`: + +```json title="~/.appduct/config.json" +{ + "policy": { "destructive": "prompt" } +} +``` + +Each call to a tool marked `destructiveHint: true` then asks you to approve it, with the tool name, device, and arguments. Tools without that annotation follow `policy.default` instead. See [Annotate what a tool does](/appduct/guides/writing-tools/#annotate-what-a-tool-does). + +Things to know before you rely on it: + +- **Set it before you connect.** Appduct reads `config.json` only when its background service starts. To apply a change, run `appduct daemon stop`. This disconnects every device, so connect them again, and restart the MCP server in your client too. +- **The prompt needs a client that supports MCP elicitation.** In a client that doesn't, and from the CLI, a `"prompt"` tool is refused with `policy_denied` (reason `no_consent_channel`). It's never silently allowed. +- **Unattended runs can't approve anything.** In CI, or non-interactive Claude Code (`claude -p`), `"prompt"` tools are always refused. Set such tools to `"allow"` or `"deny"` for those pipelines. +- **A client set up to answer prompts automatically approves them** without showing you anything. Appduct can't tell that apart from you clicking approve. +- **If you decline, the agent gets an error** for that call. It shouldn't retry on its own. + +You can also allow, prompt, or deny individual tools. See [Limit what callers can run](/appduct/guides/security/#limit-what-callers-can-run). + +## Use the CLI from a shell agent + +Agents that run shell commands can use the CLI directly. Install the Appduct skill so the agent knows the workflow and the rules for tool schemas: + +```bash +npx skills add callstackincubator/appduct --skill appduct +``` + +Install it too if you're asking an agent to add Appduct to your app or to write tools: it covers setup. + +A typical session from an agent: + +```bash +appduct ls # is a device connected? +appduct link --open ios-sim # connect one if not +appduct tools --groups # large app: see the areas first +appduct tools --group cart # then list one area +appduct tools add_item # full schema for one tool +appduct invoke add_item --input '{"sku":"SKU-1042","quantity":2}' +``` + +Plain-text output is meant for reading, and may change between versions. Scripts should add `--json`. See the [CLI guide](/appduct/guides/cli/). + +## Troubleshooting + +**The MCP server fails to start after you upgraded Appduct.** The background service from the old version is still running with connected devices, and replacing it would disconnect them. The server's error output names both versions. Run `appduct daemon stop`, then restart the MCP server. + +**`appduct_connect` fails with `invalid_request` about the scheme.** The server couldn't find your app's scheme. Add `"--scheme", "myapp"` to the server's `args`, as `appduct init` prints. + +**`appduct_wait_for_session` seems to hang.** Nothing opened the link. If `appduct_connect` returned a QR code, it has to be scanned first. On Android, check that the app id is right. + +**Calls fail with `policy_denied`.** The tool's policy is `"deny"`, or `"prompt"` in a client that can't ask you. Retrying won't help; change the policy or use a client that supports elicitation. + +**The agent can't find a tool you just added.** The component that registers it isn't mounted, or the app hasn't reloaded. Ask the agent to list tools again after the change. diff --git a/website/src/content/docs/guides/build-variants.mdx b/website/src/content/docs/guides/build-variants.mdx new file mode 100644 index 00000000..db61e338 --- /dev/null +++ b/website/src/content/docs/guides/build-variants.mdx @@ -0,0 +1,156 @@ +--- +title: Build variants +description: Control which builds include Appduct, ship it in an internal release build, strip it completely, and verify the result. +sidebar: + order: 4 +--- + +import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; + +By default, Appduct is in your **debug** builds and not in your **release** builds. A release build doesn't contain its native code at all, rather than containing it switched off. This page covers changing that default and checking what actually shipped. + +Which builds include Appduct and what an included build trusts are separate decisions. For trust, see [Security](/appduct/guides/security/). + +## React Native: the `APPDUCT_ENABLED` variable + +One environment variable controls the native module on both platforms: + +| `APPDUCT_ENABLED` | Debug build | Release build | +| --- | --- | --- | +| not set (default) | Included | Not included | +| `1` or `true` | Included | Included | +| `0` or `false` | Not included | Not included | + +Values are case-insensitive. + +**Set it when native dependencies are resolved**, not only when compiling: during `expo prebuild`, `pod install`, and Gradle configuration. Changing it and rebuilding without re-running those steps does nothing. + +To include Appduct in a release build, for example an internal build your CI or an agent drives: + +```bash +APPDUCT_ENABLED=1 npx expo prebuild && APPDUCT_ENABLED=1 npx expo run:ios --configuration Release +``` + +To leave it out even of debug builds: + +```bash +APPDUCT_ENABLED=0 npx expo prebuild && APPDUCT_ENABLED=0 npx expo run:ios +``` + +:::caution[Build names matter] +The default applies to Xcode configurations named exactly `Debug` and `Release`, and Gradle build types named exactly `debug` and `release`. A custom name, such as a `staging` configuration, doesn't get Appduct unless you set `APPDUCT_ENABLED=1` for that pipeline. +::: + +**A misspelled value falls back to the default.** On Expo, prebuild fails with an error. In a bare React Native project, nothing reports it. Check the built app with [`appduct doctor`](#verify-the-built-app). + +When Appduct is included, `pod install` and Gradle print `[appduct] native module INCLUDED in this build`. Nothing prints when it's left out. Treat the line as an early warning; `appduct doctor` is the real check. + +## Strip Appduct's JavaScript too + +Leaving out the native module doesn't remove Appduct's JavaScript from the bundle: the library is still there, finds no native module, and does nothing. To remove the JavaScript as well, wrap your Metro config with `withAppduct`: + +```js title="metro.config.js" +const { getDefaultConfig } = require("expo/metro-config"); +const { withAppduct } = require("@appduct/react-native/metro"); + +const config = getDefaultConfig(__dirname); + +module.exports = withAppduct(config); +``` + +With no options, it reads `APPDUCT_ENABLED`, so `APPDUCT_ENABLED=0` removes both halves at once. To decide another way, pass `{ include: false }` or `{ include: someBoolean }`. + +When stripping, every import of `@appduct/react-native` resolves to `@appduct/react-native/noop`: the same API, with nothing running. + +**Call `withAppduct` last.** If something else sets `resolver.resolveRequest` after it, the strip is silently lost. `withAppduct` keeps any resolver set before it. + +Removing both the native module and the JavaScript is what an app store reviewer who expects no remote-control code at all will want to see. Either half alone still gives you a working app where Appduct does nothing. + +## Leave Appduct out permanently + +To make sure a project never includes Appduct on a platform, regardless of environment variables: + + + + ```js title="react-native.config.js" + module.exports = { + dependencies: { + "@appduct/react-native": { + platforms: { + ios: null, + android: null, + }, + }, + }, + }; + ``` + + + Add an `expo.autolinking` exclude to **`package.json`**: + + ```json title="package.json" + { + "expo": { + "autolinking": { + "ios": { "exclude": ["@appduct/react-native"] }, + "android": { "exclude": ["@appduct/react-native"] } + } + } + } + ``` + + + + If `package.json` also has an `expo.autolinking.apple` block, it replaces `ios` on iOS. Add the exclude to `apple` as well. + + Check that the exclusion worked. From your app root, after installing dependencies: + + ```bash + ./node_modules/.bin/expo-modules-autolinking react-native-config --json --platform ios + ``` + + `@appduct/react-native` must not appear under `dependencies`. + + + +## Plain iOS and Android apps + +Apps using Appduct without React Native get the same debug-only default through their dependency setup: + +- **iOS with Swift Package Manager:** Debug builds get the real library; Release builds get a version that does nothing. Enable the `AlwaysEnabled` package trait to include it in Release. See [iOS setup](/appduct/start/ios/#ship-appduct-in-a-release-build). +- **iOS with CocoaPods:** `pod 'AppductCore', :configurations => ['Debug']`. Remove the restriction to include it everywhere. +- **Android:** `debugImplementation` of `core`, `releaseImplementation` of `core-noop`. Depend on `core` for a variant to include it. See [Android setup](/appduct/start/android/#ship-appduct-in-a-release-build). + +`APPDUCT_ENABLED` doesn't apply to these apps. + +## Verify the built app + +Whatever your setup, check the artifact you're about to ship: + +```bash +appduct doctor build/Shop.ipa --assert-absent +appduct doctor app/build/outputs/apk/release/app-release.apk --assert-absent +``` + +`appduct doctor` inspects the `.app`, `.ipa`, `.apk`, or `.aab` itself, not the config that was supposed to produce it. Exit codes: + +| Code | Meaning | +| --- | --- | +| `0` | The assertion held | +| `3` | The assertion failed: Appduct is present when it shouldn't be, or the reverse | +| `66` | The file couldn't be inspected, for example a missing tool or a corrupt archive | + +Add it as a step in your release pipeline, run against the signed artifact. + +## What a build without Appduct does + +In a build without the native module — excluded, a default release build, or Expo Go — the JavaScript API still works and does nothing: + +- Registering tools and posting events do nothing, and never throw. +- `getAppductState()` returns `"idle"`. +- `connect()` rejects with `appduct_disabled`. +- A warning is logged once. + +Shared code doesn't need `if` checks around Appduct calls. diff --git a/website/src/content/docs/guides/cli.mdx b/website/src/content/docs/guides/cli.mdx new file mode 100644 index 00000000..9d2499bd --- /dev/null +++ b/website/src/content/docs/guides/cli.mdx @@ -0,0 +1,238 @@ +--- +title: Use the CLI +description: Connect devices, list and call tools, watch events, check build artifacts, and drive your app from end-to-end tests. +sidebar: + order: 2 +--- + +The `appduct` CLI connects to your running app, lists the tools it registered, and calls them. This page covers everyday tasks. For every command and flag, see the [CLI reference](/appduct/reference/cli/). + +Install it with `npm install -g appduct` (Node 20 or newer). There's no server to start: the first command starts Appduct's background service, which keeps running and holds your device connections. + +## Connect a device + +A device connects by opening a one-time link in your app. `appduct link` creates the link; how it reaches the device depends on the device. Run `appduct link` from your app's root directory, so it finds your deep-link scheme (see [How the CLI finds your scheme](#how-the-cli-finds-your-scheme)). + +| Device | Command | Needs | +| --- | --- | --- | +| iOS Simulator | `appduct link --open ios-sim` | A booted simulator | +| Android emulator or USB device | `appduct link --open android` | `adb`, and your app's package name | +| Any device on your local network | `appduct link --qr` | Scan the QR code with the device's camera | +| Physical iPhone or iPad (experimental) | `appduct link --open ios-device` | See [below](#physical-iphone-or-ipad-experimental) | + +The link expires after 5 minutes and works once. Run `appduct ls` to check the session's state; once the app opens the link, it shows `active`. + +**Android needs your app's package name**, so the link opens your app and not another one that declares the same scheme. Pass `--app-id com.example.shop`, or record it once in your project: + +```bash +appduct init --android-app-id com.example.shop --ios-app-id com.example.shop +``` + +**With several simulators or devices running**, `--open` lists them and stops instead of guessing. Pick one with `--device `. For Android, setting `ANDROID_SERIAL` also works. + +**A QR code needs the phone and computer on the same network.** The link carries your computer's local network address. If the detected address is wrong, set `advertisedIp` in `~/.appduct/config.json`. + +### Physical iPhone or iPad (experimental) + +`--open ios-device` opens the link on a connected iPhone without scanning a QR code. It relies on an undocumented Xcode feature, so if it fails, fall back to `--qr`. It needs: + +- iOS 17 or newer on the device, and Xcode 15 or newer on your Mac. +- The device connected, paired, and trusted, with Developer Mode on (Settings → Privacy & Security → Developer Mode). +- A development-signed build of your app already installed. +- The phone on the same network as your Mac. +- Your app's bundle id: `--app-id`, or `appId.ios` recorded by `appduct init --ios-app-id`. + +```bash +appduct link --open ios-device --app-id com.example.shop +``` + +If the app is already running and nothing happens, add `--relaunch` to restart it first. + +## Work with several devices + +One background service handles every connected device. Each session gets an alias based on the device model, such as `pixel-8` or `iphone15-2`: + +```bash +appduct ls +``` + +Every command that targets a device takes an optional **selector** — an alias or session id — as its first argument. Leave it out when only one device is connected; with several, the command fails with `ambiguous_session` and lists the aliases. + +```bash +appduct tools pixel-8 +appduct invoke pixel-8 seed_cart --input '{"items":3}' +``` + +## Find a tool + +```bash +appduct tools +``` + +This prints one call signature and a one-line description per tool: + +``` +Tools + seed_cart(items: int, sku?: string, clear?: bool = true) -> { added: int, cartId: string } + Fill the cart with test items for the current user. + set_flag(name: "dark_mode" | "new_checkout", enabled: bool) [prompt] + Toggle a feature flag. +``` + +- `name?:` marks an optional argument, and `= value` its default. +- `-> …` is the result, when the tool declares an output schema. +- `...` means the signature couldn't summarize that part. The full schema has it. +- `[prompt]` or `[deny]` marks a tool whose [policy](/appduct/guides/security/#limit-what-callers-can-run) isn't "allow". + +For one tool's full input and output schema: + +```bash +appduct tools seed_cart +``` + +**On an app with many tools**, look at its groups first, then list one: + +```bash +appduct tools --groups +appduct tools --group checkout # checkout and its subgroups +appduct tools --group checkout/payment # only that subgroup +``` + +You can also narrow by text with `--filter `, which matches names and descriptions, and page with `--limit ` and `--offset `. A cut-off listing ends with a line telling you how many tools were left out. + +## Call a tool + +```bash +appduct invoke seed_cart --input '{"items":3}' +``` + +`--input` is required and must be a JSON object. Use `--input '{}'` for a tool that takes no arguments. + +A call can run for the tool's own time limit: 10 seconds unless the tool declares `timeoutMs`. `--timeout ` can make that shorter, never longer. If a tool needs more time, raise its `timeoutMs` in the app. See [Long-running tools](/appduct/guides/writing-tools/#long-running-tools). + +Pressing Ctrl-C during a call cancels it in the app too. + +When a call fails, the error type comes from the app unchanged, for example `tool_input_validation_error`, `tool_execution_error`, or `tool_timeout`. See [Error types](/appduct/reference/protocol/#error-types). + +## Watch events + +Your app can post events with `postEvent`, and Appduct reports its own, such as a device connecting or a tool call finishing. To stream them: + +```bash +appduct events +``` + +This keeps running until you stop it. To print what already happened and exit, pass the cursor from an earlier result with `--since `. Add `--json` for one JSON object per line. + +## Disconnect a device + +```bash +appduct revoke pixel-8 +``` + +This ends one session and frees its alias. Other devices stay connected. + +## Script the CLI + +Plain-text output is for reading and can change between versions. For scripts, add `--json`: + +```bash +appduct invoke seed_cart --input '{"items":3}' --json +``` + +The result is one compact JSON line on stdout. Errors are JSON on stderr. Add `--pretty` to indent it. + +Exit codes tell failures apart without parsing: for example, `71` for a session problem (no device, or more than one), `72` for a tool error, `77` for a denied call. See [Exit codes](/appduct/reference/cli/#exit-codes). + +## Drive the app from a test suite + +The `appduct/client` module lets an end-to-end test call tools directly, instead of tapping through setup screens. It works with Jest, Vitest, Detox, or any Node test runner. + +Install `appduct` as a dev dependency of your test project, then connect in a global setup: + +```ts title="global-setup.ts" +import { link, waitForSession } from "appduct/client"; + +export default async function setup() { + const { sessionId } = await link({ target: "ios-sim" }); + await waitForSession(sessionId, { timeoutMs: 60_000 }); +} +``` + +For Android, use `link({ target: "android", appId: "com.example.shop" })`, or record the app id with `appduct init`. + +In a test, call tools and wait for events the app posts: + +```ts +import { connect } from "appduct/client"; + +type Tools = { + login: { args: { userId: string }; result: { ok: boolean } }; + seed_cart: { args: { items: number }; result: { added: number } }; +}; + +const app = await connect(); + +await app.call("login", { userId: "qa-user-17" }); +await app.call("seed_cart", { items: 3 }); +// ...drive the checkout screen with your UI test tool... +const { payload } = await app.waitForEvent("checkout_completed", { timeoutMs: 5_000 }); + +app.close(); +``` + +- `connect()` picks the only connected device. Pass `{ selector: "pixel-8" }` to choose one. +- The `Tools` type is optional. Without it, arguments and results aren't type-checked; Appduct can't infer them, because the app registers tools at runtime. +- Failures reject with an `AppductError` whose `type` is the error type, so you can assert on it: + + ```ts + await expect(app.call("checkout", {})).rejects.toMatchObject({ type: "policy_denied" }); + ``` + +- `waitForEvent` checks events that already arrived before waiting, so it's safe to call after the action that posts the event. To skip events you've already handled, pass `since` with the `cursor` from `app.events()`. + +:::note +A tool set can differ between builds, for example when a build [leaves out destructive tools](/appduct/guides/security/#keep-a-tool-out-of-some-builds). Have tests check `app.tools()` rather than assume a tool exists. +::: + +:::caution +A tool with policy `"prompt"` is always refused in CI, because nobody can approve it. Set such tools to `"allow"` in the CI machine's `~/.appduct/config.json`. +::: + +## Check a build artifact + +`appduct doctor` checks whether a built app contains Appduct. Use it in your release pipeline to make sure Appduct didn't ship by accident: + +```bash +appduct doctor build/Shop.ipa --assert-absent +appduct doctor app/build/outputs/apk/release/app-release.apk --assert-absent +``` + +It reads `.app`, `.ipa`, `.apk`, and `.aab` files. With `--assert-absent` or `--assert-present`, it exits `3` if the assertion fails, and `66` if it couldn't inspect the file, so "couldn't tell" never passes as "absent". See [Build variants](/appduct/guides/build-variants/). + +## How the CLI finds your scheme + +`appduct link`, `appduct mcp`, and the agent's `appduct_connect` need your app's deep-link scheme. They use the first of: + +1. The `--scheme` flag. +2. The `APPDUCT_SCHEME` environment variable. +3. The nearest `.appduct/config.json` with a `scheme`, searching up from the current directory. `appduct init` writes this file. +4. `scheme` in `~/.appduct/config.json`. +5. Your project files, in the current directory: `app.json` (`expo.scheme`), then Android (`appductScheme` in `app/build.gradle(.kts)`, or `AndroidManifest.xml`), then iOS (`CFBundleURLSchemes` in an `Info.plist`, or XcodeGen's `project.yml`). + +If none has a scheme, the error lists every place it looked. If your Android and iOS projects declare different schemes, it stops and names both rather than picking one. Appduct never runs `app.config.js` or a Gradle build to find the scheme; for dynamic config, use `appduct init --scheme`. + +## Keep the background service healthy + +You rarely need to manage it, but: + +- `appduct daemon status` shows its version, port, connected sessions, and policy. +- `appduct daemon stop` stops it and disconnects every device. The next command starts it again. + +**After upgrading Appduct**, the next command replaces the old service automatically if no device is connected. If one is, the command stops and tells you, rather than dropping your sessions. Run `appduct daemon stop`, or pass `--daemon-restart` to replace it anyway. + +Its files live in `~/.appduct`. To use a different directory, for example one per user on a shared CI machine, set `APPDUCT_STATE_DIR` or pass `--state-dir`. + +:::danger +Never point `--state-dir` at a project's `.appduct/` directory. The state directory holds a private key, and a project's `.appduct/` is committed. +::: diff --git a/website/src/content/docs/guides/security.mdx b/website/src/content/docs/guides/security.mdx new file mode 100644 index 00000000..29a7c690 --- /dev/null +++ b/website/src/content/docs/guides/security.mdx @@ -0,0 +1,196 @@ +--- +title: Security +description: What Appduct protects against, how to pin a build to your key, rotate keys, limit which tools callers can run, and keep tools out of some builds. +sidebar: + order: 5 +--- + +import { Steps, Tabs, TabItem } from '@astrojs/starlight/components'; + +With the defaults, Appduct is only in debug builds, so a release build has no Appduct code for anyone to attack. This page is for when you do ship it in a build that leaves your machine, such as an internal or QA build, and for anyone deciding whether that's safe. + +## What Appduct protects against + +- **Someone on the same Wi-Fi.** The connection is encrypted. +- **Someone who controls DNS or network routing.** The app checks the identity of your computer by its key, not its address. Answering on the right IP isn't enough to impersonate it. +- **Someone who intercepts a connection link.** A link is good for one connection, for 5 minutes, and stops working after 5 failed attempts. It's not a password. +- **Other users on your computer.** Appduct's local control socket is readable only by your user. + +## What it doesn't protect against + +- **A compromised computer.** Anything that can read your Appduct key or reach its control socket, including any process running as your user, can connect devices and call any tool. Your computer is the trust boundary. +- **Your own tools.** Appduct controls who can call a tool, not what the tool does. A destructive tool does whatever its handler does. +- **A leaked key.** If your key leaks, someone on the network can impersonate your computer to builds that trust it, until those builds are retired. [Rotate keys](#rotate-keys) to limit the damage. +- **Exposing Appduct to the internet.** Whether to do that is your decision. If you do, set up [policy](#limit-what-callers-can-run). + +## Choose what a build trusts + +Each build trusts your computer in one of two ways. + +**Link trust (`"link"`)** is the default when a build has no pins configured, in any build type. The connection link carries your computer's key fingerprint, and the app trusts it for that one session. It needs no setup, which is why the quick start works right away. It's weaker than pinned trust: someone on your local network who gets you to open their link or scan their QR code can stand in for your computer for that session. Links still expire and work once. + +**Pinned trust (`"pin"`)** embeds your key's fingerprint in the build. The app then refuses any other computer, whatever the link says. Use it for every build that goes to anyone outside your own machine. + +Once a build has pins, they always win, and the link's fingerprint is ignored. Configuration can only make trust stricter, never looser. A `trust` value other than `"link"` or `"pin"`, such as a typo, is an error, never treated as the default. + +:::caution +A new link also replaces a session the app already has. Under link trust, someone who can get a malicious link opened can interrupt your session as well as take its place. +::: + +## Pin a build to your key + + + +1. Generate a key and note the fingerprint it prints: + + ```bash + appduct keygen + ``` + + This writes `~/.appduct/key.pem` and prints a `sha256/...` value. Appduct's background service uses this key. If it already created one on first start, pass `--force` to replace it, or `--out ` to write elsewhere. It runs without prompts, so it works in CI. + +2. Add the fingerprint to your app: + + + + Add the config plugin to `app.json`: + + ```json title="app.json" + { + "expo": { + "scheme": "myapp", + "plugins": [ + [ + "@appduct/react-native", + { + "cliPins": ["sha256/REPLACE_WITH_KEYGEN_OUTPUT"] + } + ] + ] + } + } + ``` + + Setting `cliPins` switches the build to `"pin"` trust. See [Config plugin options](/appduct/reference/react-native-api/#expo-config-plugin). + + + Set these keys in `Info.plist`: + + | Key | Value | + | --- | --- | + | `AppductCliPins` | Array of `sha256/...` strings | + | `AppductTrust` | `"link"` or `"pin"` | + | `AppductAllowPrivateLanOnly` | Boolean, defaults to `true` | + + + Add `` to your `` in `AndroidManifest.xml`: + + | Name | Value | + | --- | --- | + | `com.callstack.appduct.CLI_PINS` | JSON array string of `sha256/...` pins | + | `com.callstack.appduct.TRUST` | `"link"` or `"pin"` | + | `com.callstack.appduct.ALLOW_PRIVATE_LAN_ONLY` | Boolean, defaults to `true` | + + + +3. Rebuild the app. For Expo, run prebuild again. These are native settings, so a reload isn't enough. + +4. Check what the build uses. In React Native, `getAppductBuildConfig()` returns `{ trust, hasEmbeddedPins, allowPrivateLanOnly }`; on iOS and Android, read `Appduct.shared.buildConfig` or `Appduct.buildConfig`. It never shows the pins themselves. + + + +`"pin"` trust with no pins is refused: the plugin fails at prebuild, and the app refuses to connect. + +### Local network only + +`allowPrivateLanOnly` defaults to `true`: the app only follows links that point to a local IPv4 address (private ranges like `192.168.x.x`, or `127.0.0.1`). It's a safety default for development, not a statement that Appduct works only on a LAN. Only native build settings can change it. + +## Rotate keys + +Builds accept a set of pins, so you can switch keys without breaking builds that are already out: + + + +1. Generate a new key: `appduct keygen --out new-key.pem`. Note its fingerprint. +2. Add the new fingerprint to `cliPins` **next to** the old one: + + ```json + "cliPins": ["sha256/OLD...", "sha256/NEW..."] + ``` + +3. Ship that build. It trusts either key. +4. Switch your computers to the new key, with `keyPath` in `~/.appduct/config.json` or by replacing `~/.appduct/key.pem`, then run `appduct daemon stop` so the next command picks it up. +5. Once every build in use has the new pin, ship a build without the old one, and delete the old key. + + + +Rotate on a schedule, not only after a suspected leak. It keeps the process practiced and limits how long any one key is exposed. + +## Handle keys safely + +- **Never commit a private key.** `git ls-files "*.pem"` should print nothing. +- **Keep `key.pem` at mode `0600`.** Appduct refuses to load a key that other users can read. Don't loosen the permissions to work around it. +- **Use one key per developer or environment.** Don't share one key across a team. +- **Keep the fingerprint.** It's what you ship in `cliPins`. Losing the key file just means generating a new one and shipping a new build, which is the rotation path anyway. +- **Never point `--state-dir` at a committed directory**, such as your project's `.appduct/`. The state directory holds the private key. +- **On shared machines**, such as CI runners, give each user their own `APPDUCT_STATE_DIR`. Anyone who can reach another user's control socket has that user's access. + +## Limit what callers can run + +Appduct can allow, deny, or ask about each tool call before it reaches your app. Set a policy in `~/.appduct/config.json`: + +```json title="~/.appduct/config.json" +{ + "policy": { + "default": "allow", + "destructive": "prompt", + "tools": { + "pixel-8/wipe_local_data": "deny" + } + } +} +``` + +| Key | Applies to | +| --- | --- | +| `default` | Every tool not covered below | +| `destructive` | Tools annotated `destructiveHint: true` | +| `tools["/"]` | One tool on one device, by session alias | + +Each value is `"allow"`, `"deny"`, or `"prompt"`: + +- `"deny"` refuses the call with `policy_denied`, and it never reaches the app. +- `"prompt"` asks a person to approve each call, through an MCP client that supports elicitation. Everywhere else, including the CLI and CI, the call is refused. See [Require approval for risky tools](/appduct/guides/agents/#require-approval-for-risky-tools). + +The background service reads this file when it starts. After changing it, run `appduct daemon stop`; this disconnects every device. + +Every call attempt is also recorded in `~/.appduct/audit/`, one file per day: time, device, tool, a hash of the arguments (never the arguments themselves), outcome, and who called (`cli`, `mcp`, or `client`). Files older than 30 days are deleted; change that with `auditRetentionDays`. + +:::note +Policy and the audit log run on your computer, so they help a trusted person working across many tools. They don't stop someone who already controls your computer. The protection that lives inside your app is which tools it registers at all, below. +::: + +## Keep a tool out of some builds + +Registering a tool is what makes it reachable, so the strongest control is not registering it. In React Native, pass `enabled` to `useAppductTool`: + +```ts +useAppductTool( + { + name: "wipe_local_db", + description: "Destructive: clear the local database.", + annotations: { destructiveHint: true }, + handler: async () => wipeLocalDb(), + }, + [], + { enabled: process.env.EXPO_PUBLIC_APPDUCT_TOOLS === "full" }, +); +``` + +Use a build flag your release pipeline sets, like an `EXPO_PUBLIC_*` variable. **Don't use `__DEV__` for this**: it's `false` in every release bundle, including the internal release builds agents drive in CI, so it removes the tool exactly where you need it. `__DEV__` is fine for tools that only make sense in local development. + +Because tools can differ between builds, automated flows should list tools rather than assume a fixed set. + +## Shipping to app store review + +A release build doesn't include Appduct by default. If you include it with `APPDUCT_ENABLED=1` in a build that goes to app store review, be ready to explain the trust model in your review notes, or [leave Appduct out](/appduct/guides/build-variants/) of that build. Check with `appduct doctor --assert-absent`. diff --git a/website/src/content/docs/guides/writing-tools.mdx b/website/src/content/docs/guides/writing-tools.mdx new file mode 100644 index 00000000..d2324d3e --- /dev/null +++ b/website/src/content/docs/guides/writing-tools.mdx @@ -0,0 +1,265 @@ +--- +title: Write tools +description: Register tools with schemas agents can read, name and group them, set time limits, and report progress. +sidebar: + order: 3 +--- + +A tool is a named function your app registers, with a description and a schema for its arguments. The CLI, agents, and tests can call only the tools you register. This page covers React Native; the same ideas apply to [iOS](/appduct/start/ios/#register-tools-in-swift) and [Android](/appduct/start/android/#register-tools-in-kotlin), where schemas are plain JSON Schema. + +## Register a tool + +In a component, use the `useAppductTool` hook: + +```tsx +import { useAppductTool } from "@appduct/react-native"; +import { z } from "zod"; + +function CartTools() { + const cart = useCart(); + + useAppductTool({ + name: "seed_cart", + description: "Fill the cart with test items.", + inputSchema: z.object({ items: z.number() }), + outputSchema: z.object({ added: z.number() }), + handler: async ({ items }) => ({ added: await cart.addTestItems(items) }), + }); + + return null; +} +``` + +The tool exists while the component is mounted. The hook registers once when it mounts: re-renders cost nothing and don't make agents reload the tool list. The handler always sees the latest state it closes over, so you don't need refs. + +Outside React, for example in a module that runs at startup, use `registerTool`. It returns an object whose `remove()` unregisters the tool: + +```ts +import { registerTool } from "@appduct/react-native"; + +const registration = registerTool({ + name: "clear_cache", + description: "Delete cached images and API responses.", + handler: async () => { + await cache.clear(); + return { cleared: true }; + }, +}); +``` + +**Give each tool one owner.** Two mounted components registering the same name isn't supported: the later one wins, with a warning in development. + +## Name and describe it + +- **Names** use letters, digits, `_`, and `-`, up to 64 characters. `seed_cart`, `set-flag`, and `openScreen` are all valid. +- **Descriptions** are required, up to 4,096 characters. Agents read them to decide what to call, so say what the tool does and anything a caller should know first, like "Signs out the current user". + +## Choose a schema form + +An agent can only call a tool correctly if it can see its arguments, so the schema has to describe itself as JSON Schema. `inputSchema` and `outputSchema` accept three forms: + +| You pass | Validated in the app | Agents see | +| --- | --- | --- | +| A schema with a JSON Schema exporter: **Zod 4**, ArkType | Yes | The exported JSON Schema | +| A `{ schema, jsonSchema }` pair: Zod 3, Valibot, or others | Yes | The JSON Schema you supply | +| A raw JSON Schema object | No, arguments reach the handler as sent | The object as written | + +**Zod 4** works as-is, as in the examples above. + +**Zod 3** — pair the schema with `zod-to-json-schema`: + +```ts +import { z } from "zod"; +import { zodToJsonSchema } from "zod-to-json-schema"; + +const sumInput = z.object({ a: z.number(), b: z.number() }); + +registerTool({ + name: "sum", + description: "Add two numbers.", + inputSchema: { + schema: sumInput, + jsonSchema: zodToJsonSchema(sumInput, { target: "jsonSchema2019-09" }), + }, + handler: async ({ a, b }) => ({ total: a + b }), +}); +``` + +**Valibot** — pair it with `@valibot/to-json-schema`: + +```ts +import * as v from "valibot"; +import { toJsonSchema } from "@valibot/to-json-schema"; + +const sumInput = v.object({ a: v.number(), b: v.number() }); +const inputSchema = { schema: sumInput, jsonSchema: toJsonSchema(sumInput) }; +``` + +**No schema library** — pass JSON Schema. `jsonSchema()` types the handler's arguments; it doesn't validate anything: + +```ts +import { jsonSchema, registerTool } from "@appduct/react-native"; + +registerTool({ + name: "weather", + description: "Current weather for a city.", + inputSchema: jsonSchema<{ city: string }>({ + type: "object", + properties: { city: { type: "string" } }, + required: ["city"], + additionalProperties: false, + }), + handler: async ({ city }) => fetchWeather(city), +}); +``` + +**What fails:** + +- A Zod 3 or plain Valibot schema on its own, with no pair, throws in development, because agents would see a tool that takes anything. Release builds register the tool without a schema and log one warning. +- A validator from a library without Standard Schema support (yup, joi, superstruct) throws a `TypeError`. Pass JSON Schema, or a pair. +- A malformed pair, such as `{ jsonSchema }` alone, throws a `TypeError`. + +Appduct passes your JSON Schema through unchanged. Libraries differ in what they emit (draft version, `additionalProperties`, defaults), so pick the target closest to draft 2020-12 your converter offers. + +:::tip +If your JSON Schema is typed as an interface, such as `JSONSchema7`, TypeScript won't accept it directly. Wrap it in `jsonSchema()` or cast it. +::: + +## Make the input schema accept an object + +Arguments are always a JSON object. An input schema whose root is a string, number, or array can never be satisfied, and logs a warning in development. Wrap the value: + +```ts +inputSchema: z.object({ sku: z.string() }) // not z.string() +``` + +Unions of objects (`z.union`, `z.discriminatedUnion`, `z.intersection`) work, but the tool list shows their arguments as `(...)`, so an agent has to fetch the full schema before calling. A single `z.object(...)` shows named arguments right in the list. + +`outputSchema` has no such limit: a result can be any JSON value. + +## Group tools in a large app + +Once your app has more tools than fit on a screen, give each a `group`. An agent then lists your app's areas with `appduct tools --groups` and one area with `--group cart`, instead of guessing search words. + +```ts +useAppductTool({ + name: "add_item", + description: "Add a product to the cart.", + group: "cart", + inputSchema: z.object({ sku: z.string(), quantity: z.number() }), + handler: async ({ sku, quantity }) => cart.add(sku, quantity), +}); +``` + +A group is a name (`cart`) or one subgroup below it (`checkout/payment`), using the same characters as tool names. Nothing deeper is allowed. Add a subgroup only when a group outgrows a screen: `--group checkout` lists `checkout` and all its subgroups, and `--group checkout/payment` lists only that subgroup. + +To put several tools in one group, bind it once: + +```ts +import { createToolGroup } from "@appduct/react-native"; + +const registerCartTool = createToolGroup("cart"); + +registerCartTool({ name: "add_item", description: "Add a product to the cart.", handler: addItem }); +registerCartTool({ name: "clear_cart", description: "Remove every item from the cart.", handler: clearCart }); +``` + +A malformed group, such as `"checkout/"`, `"a/b/c"`, or `"check out"`, throws. Groups only change how tools are listed; they don't change names or how tools are called. + +## Annotate what a tool does + +`annotations` tell agents and Appduct's policy what a tool does: + +```ts +useAppductTool({ + name: "wipe_local_data", + description: "Delete all local data and sign out.", + annotations: { destructiveHint: true }, + handler: async () => wipeLocalData(), +}); +``` + +| Annotation | Meaning | +| --- | --- | +| `readOnlyHint` | Doesn't change anything | +| `destructiveHint` | Changes or deletes something that's hard to undo | +| `idempotentHint` | Calling it twice has the same effect as once | + +`destructiveHint: true` matters beyond information: the [policy](/appduct/guides/security/#limit-what-callers-can-run) can require approval for, or deny, destructive tools as a class. Mark every tool that deletes data, signs out, or spends money. + +## Long-running tools + +A call gets **10 seconds** by default. For a tool that needs longer, like a real login or seeding data through your backend, declare `timeoutMs`: + +```ts +useAppductTool({ + name: "login", + description: "Sign a test user in against the staging backend.", + inputSchema: z.object({ userId: z.string() }), + timeoutMs: 60_000, + handler: async ({ userId }, { signal }) => loginAsUser(userId, { signal }), +}); +``` + +`timeoutMs` must be between 1,000 and 600,000; values outside are clamped, with a warning in development. It's the only way to give a tool more time: callers can shorten the limit (`appduct invoke --timeout`) but never extend it. + +When the time is up, the call fails with `tool_timeout`, and whatever the handler returns later is ignored. + +### Stop work when a call is cancelled + +The handler's second argument has a `signal`, an `AbortSignal` that fires when the call times out, the caller cancels, or the connection drops. Pass it on, for example to `fetch(url, { signal })`, or check `signal.aborted`. Ignoring it is fine: the handler then runs to the end. + +### Report progress + +Call `reportProgress(progress, message)` from the same argument. Both are optional: + +```ts +handler: async (_args, { reportProgress }) => { + await reportProgress(0.5, "Uploading fixtures"); + // ... + return { done: true }; +}, +``` + +Progress shows up in `appduct events` and as MCP progress notifications. + +## Tell callers something happened + +To signal something that isn't a tool result, such as "checkout finished", post an event: + +```ts +import { postEvent } from "@appduct/react-native"; + +await postEvent("checkout_completed", { orderId: "ord_4821" }); +``` + +Tests can wait for it with `app.waitForEvent("checkout_completed")`, and agents with `appduct_wait_for_event`. Events posted while no device is connected are dropped. + +## Handle errors + +If your handler throws, the call fails with `tool_execution_error` and your message. Validation failures report `tool_input_validation_error` or `tool_output_validation_error`. Callers see these types unchanged. See [Error types](/appduct/reference/protocol/#error-types). + +## Keep a tool out of some builds + +To leave a destructive tool out of some builds, pass `enabled` rather than wrapping the hook in an `if`: + +```ts +useAppductTool( + { + name: "wipe_local_db", + description: "Destructive: clear the local database.", + annotations: { destructiveHint: true }, + handler: async () => wipeLocalDb(), + }, + [], + { enabled: process.env.EXPO_PUBLIC_APPDUCT_TOOLS === "full" }, +); +``` + +See [Keep a tool out of some builds](/appduct/guides/security/#keep-a-tool-out-of-some-builds) for why a build flag works better here than `__DEV__`. + +## Advanced: the hook's `deps` argument + +The hook re-registers only when something about the registration changes: name, description, schemas, annotations, `timeoutMs`, `group`, or `enabled`. You rarely need the second `deps` argument. Pass it only to force a re-registration on something the tool definition doesn't capture, like a `.refine()` that reads component state. If you pass it, pass it on every render. + +Schemas defined at module scope, or in `useMemo`, are compared cheapest. Inline schemas work too, but are converted to JSON Schema on each render to compare them. A Zod 3 or plain Valibot schema can't be compared by shape, so an inline one re-registers on every render: hoist it, or move to Zod 4. diff --git a/website/src/content/docs/reference/architecture.md b/website/src/content/docs/reference/architecture.md new file mode 100644 index 00000000..39a921bd --- /dev/null +++ b/website/src/content/docs/reference/architecture.md @@ -0,0 +1,99 @@ +--- +title: How it works +description: The pieces of Appduct, how a device connects, what survives reloads and restarts, and how calls, timeouts, and policy behave. +sidebar: + order: 3 +--- + +This page explains what happens between your terminal and your app, as far as it affects how you use Appduct. The full design document, written for contributors, is [ARCHITECTURE.md](https://github.com/callstackincubator/appduct/blob/main/docs/ARCHITECTURE.md) on GitHub. + +## The pieces + +``` + your computer devices +┌───────────────────────────────────────────┐ +│ appduct CLI ─────┐ │ +│ MCP clients ─────┼──► background service ◄┼──── encrypted ──── iPhone (session A) +│ test runners ────┘ (the daemon) ◄┼──── connections ── Pixel (session B) +│ ~/.appduct/ ◄┼─────────────────── Simulator (session C) +└───────────────────────────────────────────┘ +``` + +- **The background service** (`appduct daemon`) runs on your computer, one per user. It holds the private key, listens for devices on one port (8443 by default), keeps every session, and applies policy. It starts on the first command that needs it and keeps running on its own; nothing a device does stops it. +- **The CLI, the MCP server, and `appduct/client`** don't connect to devices themselves. They send requests to the background service over a local socket that only your user can open. That's why they always agree: they make the same requests. +- **Your app** registers tools and connects *to* your computer, not the other way round. That's what makes physical phones work. + +## How a device connects + +1. `appduct link` (or `appduct_connect`) asks the background service for a **pending session** and gets back a link: `:///?appduct=&pin=`. The payload holds your computer's address and port, a session id, a one-time token, and an expiry time. +2. The link reaches the app: through `adb` or the simulator, or as a QR code you scan. +3. The app opens an encrypted connection to the address in the link and checks your computer's key against its pins, or, with no pins, against the fingerprint in the link. See [Security](/appduct/guides/security/#choose-what-a-build-trusts). +4. The app sends the token. If it matches, the session becomes **active**, gets an alias based on the device model (like `pixel-8`), and the app sends its tool list. + +For simulators and Android devices reached through `adb`, the link points to `127.0.0.1`. For QR codes and physical iPhones, it points to your computer's local network address, which the phone must be able to reach. + +A link can be used once and expires after 5 minutes (`linkTtlSeconds`). Five wrong tokens for the same session make it unusable. + +## What survives what + +| Event | What happens | +| --- | --- | +| Metro reload, Fast Refresh | The session resumes on its own, with the same alias. | +| App in the background | The session pauses and resumes when the app returns. | +| Network drop | The app reconnects with increasing delays, up to 30 seconds apart. | +| Disconnected for more than 10 minutes (`graceSeconds`) | The session expires. Connect again with a new link. | +| App process killed or relaunched | The session can't resume: resume credentials are kept only in memory. Connect again. | +| Background service stopped or restarted | Every session ends. Connect devices again. | +| `appduct revoke` | That session ends immediately. | + +While a session is disconnected, its alias and tool list are kept, and calls fail fast with `session_suspended`. After a resume, the app sends its full tool list again. + +Session states: **pending** (link created) → **active** → **suspended** (disconnected) → **active** again, or **expired**. A link nobody opened in time is **discarded**. `appduct revoke` moves any session to **revoked**. Ending a session frees its alias for the next device. + +## How a call runs + +1. The caller asks the background service to call a tool. +2. The service checks [policy](/appduct/guides/security/#limit-what-callers-can-run). A denied call never reaches the app. A `"prompt"` call over MCP first asks the person through the MCP client. +3. The service sends the call to the app, which validates the arguments, runs the handler, and replies with the result or an error. +4. The service records the attempt in the audit log and returns the result. Error types from the app, such as `tool_execution_error`, reach the caller unchanged. + +### Time limits + +- The app stops each call at the tool's `timeoutMs`, or 10 seconds if it declares none. This is the real limit. +- The tool's `timeoutMs` is also sent to the background service, so callers get the same budget without asking. +- A caller can pass a shorter limit, but not a longer one: the app stops the handler at its own limit anyway. +- All limits are clamped to 1–600 seconds. + +### Cancellation + +A call is cancelled when the caller goes away: Ctrl-C on `appduct invoke`, an MCP client cancelling a request, or a test process exiting. The app then aborts the handler's `signal`. A handler that ignores the signal runs to the end anyway. After a timeout, whatever it returns is ignored. + +## Events + +Apps post events with `postEvent`. The background service keeps the last 256 events per session (not counting progress updates), so a caller can ask what happened after the fact instead of having to listen beforehand. Each event carries a `seq` cursor; pass the last one you saw as `since` to read only newer events. A session's events are discarded when it ends. + +## Upgrades + +The background service keeps running after you upgrade the CLI. On its first command, each CLI or MCP process compares versions: + +- **Same version:** nothing happens. +- **The service is newer:** the command proceeds with a notice. Appduct never downgrades a running service. +- **The service is older and holds nothing:** it's replaced automatically. +- **The service is older and has connected devices or an unopened link:** the command stops and names both versions, instead of dropping your sessions. Run `appduct daemon stop`, or pass `--daemon-restart`. + +A long-running MCP server doesn't re-check after it starts; restart it after upgrading. + +## What Appduct doesn't do + +- Run arbitrary code in your app. Only tools you registered can be called. +- Replace UI testing. It skips setup; your UI test tool still drives the screens. +- Accept connections without a link and a matching key. +- Relay to computers other than the one running the background service. +- Run in a web browser. The web build is a stub that does nothing. +- Call a tool whose input schema can't accept a JSON object. Such tools are listed but can't be called. + +## For the details + +- [Wire protocol](/appduct/reference/protocol/): messages, the link payload, and close codes, for implementing a client. +- [ARCHITECTURE.md](https://github.com/callstackincubator/appduct/blob/main/docs/ARCHITECTURE.md): the full design document. +- [SECURITY.md](https://github.com/callstackincubator/appduct/blob/main/docs/SECURITY.md): the full threat model. diff --git a/website/src/content/docs/reference/cli.md b/website/src/content/docs/reference/cli.md new file mode 100644 index 00000000..0d35680d --- /dev/null +++ b/website/src/content/docs/reference/cli.md @@ -0,0 +1,271 @@ +--- +title: CLI reference +description: Every appduct command, flag, environment variable, config file key, exit code, MCP tool, and the appduct/client API. +sidebar: + order: 1 +--- + +For task-based instructions, see [Use the CLI](/appduct/guides/cli/). Run `appduct --help` for a command's flags on your installed version. + +Commands that target a device take an optional `[selector]`: a session alias or id from `appduct ls`. Leave it out when exactly one device is connected. + +## Commands + +### `appduct init` + +Sets up the current app directory: writes `.appduct/config.json` (mode `0600`) and prints an MCP config entry for this app. Safe to re-run. Never creates keys. + +| Flag | Description | +| --- | --- | +| `--scheme ` | Scheme to record. Without it, `init` looks in `app.json` and your native project files, never in `APPDUCT_SCHEME` or a parent directory. | +| `--ios-app-id ` | iOS bundle id, recorded as `appId.ios`. Needed for `--open ios-device`. | +| `--android-app-id ` | Android package name, recorded as `appId.android`. Needed for `--open android`. | +| `--force` | Replace a value that's already recorded. On its own, re-reads the scheme from `app.json`. Merges into the existing file rather than overwriting it. | + +A plain re-run keeps the recorded scheme and adds a note if your project files now declare a different one. + +### `appduct link` + +Creates a one-time connection link and prints it. + +| Flag | Description | +| --- | --- | +| `--open ` | Open the link on a device: `android`, `ios-sim`, or `ios-device` (experimental). | +| `--device ` | adb serial, simulator UDID, or device UDID, when more than one is available. | +| `--app-id ` | Installed app id for `android` and `ios-device`. Defaults to `appId.` in `.appduct/config.json`. Not allowed with `ios-sim`. | +| `--relaunch` | With `ios-device`: stop a running instance of the app first. | +| `--qr` | Also print the link as a QR code. | +| `--scheme ` | Deep-link scheme. See [scheme resolution](#scheme-resolution). | +| `--ttl ` | How long the link stays valid. Default: `linkTtlSeconds`, 300. | + +How each `--open` target delivers the link: + +| Target | Delivered with | Address in the link | +| --- | --- | --- | +| `android` | `adb reverse`, then `adb shell am start` for your app | `127.0.0.1`, forwarded to the device | +| `ios-sim` | `xcrun simctl openurl` | `127.0.0.1` | +| `ios-device` | `xcrun devicectl device process launch` | Your computer's local network address | + +Without `--device`, each target requires exactly one candidate and lists them otherwise. `ios-device` requires iOS 17+, Xcode 15+, a connected, trusted device with Developer Mode on, and your app installed. App ids may contain letters, digits, `.`, `_`, and `-`, and must start with a letter or digit. + +The link has the form `:///?appduct=&pin=`. Pass it on whole. + +### `appduct ls` + +Lists sessions with alias, state, device, and tool count. + +### `appduct tools [selector] [name]` + +Lists a device's tools as one-line signatures, or shows one tool's full schema when you pass `name`. + +| Flag | Description | +| --- | --- | +| `--groups` | List groups with tool counts instead of tools. | +| `--group ` | Only tools in this group. `checkout` includes `checkout/payment`. Case-sensitive. | +| `--filter ` | Only tools whose name or description contains the text (case-insensitive). | +| `--limit ` | Show at most `n` tools. | +| `--offset ` | Skip the first `n` tools of the name-sorted list. | +| `--full` | Print full schemas for every listed tool. | + +`--groups`, `--group`, `--filter`, `--limit`, and `--offset` can't be combined with `name`. With `--json`, the listing is `{ tools, total, groups }`, where `total` counts matches before `--limit` and `--offset`. + +Signature syntax: `name: type` for a required argument, `name?: type` for an optional one, `= value` for a default, `-> type` for the result. `...` marks a part the signature can't summarize. `[prompt]` or `[deny]` marks a tool whose policy isn't `"allow"`. + +### `appduct invoke [selector] ` + +Calls a tool. + +| Flag | Description | +| --- | --- | +| `--input ` | **Required.** Arguments as a JSON object. | +| `--timeout ` | Shorten the call's time limit. Clamped to 1,000–600,000. Can't extend past the tool's own limit (its `timeoutMs`, or 10,000). | + +Ctrl-C cancels the call in the app. + +### `appduct events [selector]` + +Streams events until you stop it. With `--json`, prints one JSON object per line. + +| Flag | Description | +| --- | --- | +| `--since ` | Print events retained since this cursor, then exit. | +| `--follow` | Accepted for readability; streaming is the default. | + +Event kinds: `daemon_started`, `link_created`, `link_expired`, `session_claimed`, `session_suspended`, `session_resumed`, `session_revoked`, `session_expired`, `tools_changed`, `app_event`, `tool_call_started`, `tool_call_progress`, `tool_call_finished`. + +Each device keeps its last 256 events (`eventBufferSize`), not counting progress events. They're discarded when the session ends. + +### `appduct revoke [selector]` + +Ends one session and frees its alias. + +### `appduct mcp` + +Starts an MCP server over stdio. See [MCP tools](#mcp-tools). + +| Flag | Description | +| --- | --- | +| `--scheme ` | Scheme for `appduct_connect`. | + +Unlike `link`, it starts even when no scheme is found; only `appduct_connect` fails. + +### `appduct doctor ` + +Reports whether a `.app`, `.ipa`, `.apk`, or `.aab` contains Appduct. Doesn't contact the background service. + +| Flag | Description | +| --- | --- | +| `--assert-present` | Exit `3` if Appduct isn't in the artifact. | +| `--assert-absent` | Exit `3` if Appduct is in the artifact. | + +### `appduct keygen` + +Generates a private key for the background service and prints the `sha256/...` fingerprint to put in `cliPins`. Runs without prompts. + +| Flag | Description | +| --- | --- | +| `--out ` | Where to write the key. Default: `/key.pem`. | +| `--force` | Overwrite an existing key. | + +### `appduct daemon ` + +Manages the background service. It starts on its own, so you rarely need these. + +| Action | Description | +| --- | --- | +| `status` | Version, process id, port, pinned keys, sessions, policy, and audit log size. | +| `stop` | Stops it and disconnects every device. | +| `start` | Starts it in the background. | +| `run` | Runs it in the foreground, for launchd or systemd. | + +## Global flags + +| Flag | Description | +| --- | --- | +| `--json` | Machine-readable output: one compact JSON line, or one line per event for streams. Errors go to stderr as JSON. | +| `--pretty` | Indent JSON output. Never applies to event lines. | +| `--verbose` | Include a `meta` block: command, timestamp, duration. | +| `--no-color` | Disable color. | +| `--state-dir ` | Use a different state directory. Default: `~/.appduct`. | +| `--daemon-restart` | After an upgrade, replace the running background service even if devices are connected. `--no-daemon-restart` overrides the variable and config setting for one command. | + +## Exit codes + +| Code | Meaning | Examples | +| --- | --- | --- | +| `0` | Success | | +| `1` | Unexpected error | | +| `3` | `doctor` assertion failed | | +| `64` | Usage error | Missing `--input`, unknown scheme, missing app id | +| `65` | Invalid input | `--input` isn't a JSON object, `invalid_request` | +| `66` | `doctor` couldn't inspect the artifact | | +| `70` | Couldn't reach the background service | Version mismatch with connected devices | +| `71` | Session problem | `no_session`, `ambiguous_session`, `unknown_session`, `session_suspended` | +| `72` | Tool error | `tool_not_found`, `tool_execution_error`, `tool_timeout` | +| `77` | Call denied | `policy_denied` | + +With `--json`, the error's `type` field names the exact error. See [Error types](/appduct/reference/protocol/#error-types). + +## Environment variables + +| Variable | Description | +| --- | --- | +| `APPDUCT_SCHEME` | Deep-link scheme, for every command in the shell. | +| `APPDUCT_STATE_DIR` | State directory. Same as `--state-dir`. | +| `APPDUCT_DAEMON_RESTART` | `1` behaves like `--daemon-restart` on every command. | +| `ANDROID_SERIAL` | Picks the Android device for `--open android`. | +| `APPDUCT_ENABLED` | Build-time only: which builds include Appduct. See [Build variants](/appduct/guides/build-variants/). | + +## Scheme resolution + +`link`, `mcp`, `appduct_connect`, and `appduct/client`'s `link()` use the first of: + +1. `--scheme` (or the `scheme` option). +2. `APPDUCT_SCHEME`. +3. The nearest `.appduct/config.json` with a `scheme`, searching up from the current directory. +4. `scheme` in `/config.json`. +5. Project files in the current directory, in order: + 1. `app.json`: `expo.scheme` (a string, or the first entry of an array). + 2. Android: the `appductScheme` manifest placeholder in `app/build.gradle.kts` or `app/build.gradle`, then the first `` in an intent filter with `android.intent.action.VIEW` in `app/src/main/AndroidManifest.xml`. + 3. iOS: the first `CFBundleURLSchemes` entry in any `Info.plist` up to two levels down (skipping `Pods`, `build`, `node_modules`, `DerivedData`), then XcodeGen's `project.yml`. + +If nothing is found, the error lists every location. If the Android and iOS projects disagree, the command fails and names both. Dynamic config (`app.config.js`, Gradle scripts) is never run. + +## Config files + +### Project: `.appduct/config.json` + +Written by `appduct init`, and meant to be committed. It holds only these keys; it can't change the state directory, key, or policy. + +```json +{ + "scheme": "myapp", + "appId": { "ios": "com.example.shop", "android": "com.example.shop" } +} +``` + +### Background service: `/config.json` + +Default location `~/.appduct/config.json`. Every key is optional. Read when the background service starts: after changing it, run `appduct daemon stop`. + +| Key | Default | Description | +| --- | --- | --- | +| `wssPort` | `8443` | Port devices connect to. `0` picks a free port. | +| `keyPath` | `/key.pem` | Private key file. Must be mode `0600`. | +| `graceSeconds` | `600` | How long a disconnected session can resume. | +| `linkTtlSeconds` | `300` | How long a new link stays valid. | +| `keepaliveIntervalSeconds` | `15` | Keepalive interval; two missed replies count as a disconnect. | +| `eventBufferSize` | `256` | Events kept per session. | +| `auditRetentionDays` | `30` | Days of audit log to keep. | +| `daemonLogMaxBytes` | `10485760` | Size at which `daemon.log` is rotated. | +| `policy` | `{ "default": "allow", "destructive": "allow" }` | See [Limit what callers can run](/appduct/guides/security/#limit-what-callers-can-run). | +| `advertisedIp` | detected | Address put in links for physical devices. | +| `scheme` | none | Fallback scheme. | +| `restartDaemonOnVersionMismatch` | `false` | Always replace an outdated background service, even with devices connected. | + +### State directory contents + +`~/.appduct/` (mode `0700`) holds `daemon.sock`, `daemon.pid`, `daemon.log`, `daemon.log.1`, `key.pem`, `config.json`, and `audit/.jsonl`, each mode `0600`. + +## MCP tools + +`appduct mcp` exposes these tools. Every tool that targets a device takes an optional `selector`. + +| Tool | Arguments | Result | +| --- | --- | --- | +| `appduct_list_tools` | `selector?`, `group?`, `filter?`, `limit?` (default 50), `offset?` | Tool signatures with group and policy, `total`, and the app's `groups` | +| `appduct_describe_tool` | `selector?`, `name` | One tool's full descriptor and policy | +| `appduct_call_tool` | `selector?`, `name`, `args?`, `timeoutMs?` (1,000–600,000; can only shorten) | The tool's result | +| `appduct_connect` | `target?` (`android`, `ios-sim`, `ios-device`, `none`), `device?`, `appId?`, `relaunch?`, `ttlSeconds?` | `{ sessionId, delivered: true }`, or a `qr`, `deepLink`, and `instructions` for a person | +| `appduct_wait_for_session` | `sessionId`, `timeoutMs?` | Resolves when the device connects | +| `appduct_events` | `selector?`, `since?`, `kinds?`, `limit?` | `{ events, cursor }` | +| `appduct_wait_for_event` | `selector?`, `name`, `match?`, `since?`, `timeoutMs?` (default 120,000; max 1,500,000) | The matching event | + +Unknown arguments are rejected. A tool with policy `"prompt"` asks for approval through MCP elicitation. + +## `appduct/client` + +A typed Node API for test runners, over the same background service. Install `appduct` as a dev dependency. + +```ts +import { connect, link, waitForSession, AppductError } from "appduct/client"; +``` + +| Function | Description | +| --- | --- | +| `link(options?)` | Creates a link, and opens it when `target` is set. Options: `target`, `device`, `appId`, `relaunch`, `scheme`, `ttlSeconds`, `cwd`, `stateDir`. Returns `{ sessionId, deepLink, endpoint, expiresAt, pin, delivered? }`. | +| `waitForSession(sessionId, options?)` | Resolves with an `AppClient` once the device connects. Option: `timeoutMs`. | +| `connect(options?)` | Returns an `AppClient` for a connected device. Options: `selector`, `stateDir`. | + +`AppClient`: + +| Member | Description | +| --- | --- | +| `sessionId` | The session this client targets. | +| `tools()` | The device's tool descriptors. | +| `call(name, args, { timeoutMs? })` | Calls a tool and returns its result. | +| `events({ since?, limit? })` | App events retained since a cursor: `{ events, cursor }`. | +| `waitForEvent(name, { timeoutMs?, match?, since? })` | Waits for an app event. Checks retained events first. `timeoutMs` defaults to 30,000. | +| `close()` | Closes the connection. | + +Failures reject with `AppductError`, whose `type` is the [error type](/appduct/reference/protocol/#error-types). diff --git a/website/src/content/docs/reference/protocol.md b/website/src/content/docs/reference/protocol.md new file mode 100644 index 00000000..9f79f24a --- /dev/null +++ b/website/src/content/docs/reference/protocol.md @@ -0,0 +1,288 @@ +--- +title: Wire protocol +description: The Appduct v2 protocol between an app and the background service — link payload, messages, tool descriptors, session states, error types, and close codes. +sidebar: + order: 4 +--- + +This page is for people implementing an Appduct client in a new language or framework. If you use the React Native, iOS, or Android library, you don't need it, except for [Error types](#error-types). + +The types and validators in [`@appduct/shared`](https://github.com/callstackincubator/appduct/tree/main/packages/shared/src/domains) are authoritative if this page and the code ever differ. The source for this page is [PROTOCOL.md](https://github.com/callstackincubator/appduct/blob/main/docs/PROTOCOL.md). + +## Overview + +- One background service on the operator's computer holds a TLS private key and listens on one `wss://` port. Any number of apps connect to it, each with its own session. +- The app connects **to** the service, using an address and one-time token from a deep link. +- The app trusts the service only if the SHA-256 hash of the TLS leaf certificate's SubjectPublicKeyInfo matches a pin: `sha256/`. Apps accept a *set* of pins, so keys can be rotated. +- The deep link isn't proof of authority, only data for one pending session. + +## The link + +``` +:///?appduct=&pin= +``` + +- `appduct` is the bootstrap payload, base64url without padding. +- `pin` is the service's current key fingerprint, percent-encoded. A build with embedded pins ignores it. A build without pins trusts it for this one session. + +When extracting the payload, **stop at the `&`**. Reading to the end of the string pulls the pin into the payload and corrupts it. + +### Payload layout + +All multi-byte integers are big-endian. + +| Bytes | Field | Notes | +| --- | --- | --- | +| 1 | `version` | Always `0x02`. Reject anything else, including `0x01`. | +| 1 | `family` | `0x04` (IPv4) or `0x06` (IPv6) | +| 4 or 16 | `address` | Per `family` | +| 2 | `port` | Never `0` | +| 1 + n | `sessionId` | 1-byte length (1–255), then UTF-8 bytes | +| 32 | `token` | Raw bytes. Sent in `session_claim.token` as base64url. | +| 8 | `expiresAt` | Unix **seconds** | + +Decode strictly: a wrong version, unknown family, wrong total length, empty or invalid UTF-8 session id, or port `0` makes the whole payload invalid. Also reject expired payloads. + +Connect to `wss://
:`, with IPv6 addresses in brackets: `wss://[fd00::1]:8443`. + +The reference clients also refuse, by default, a payload whose address isn't a local IPv4 address (RFC 1918 ranges or `127.0.0.1`). + +## Connection rules + +- **Text frames only.** A binary frame closes the socket (`1003`). +- **Maximum message size is 256 KiB**, in both directions. +- **One JSON object per frame.** Invalid JSON closes the socket. +- **The first message must be `session_claim` or `session_resume`**, within 10 seconds of connecting. +- **After that, every message carries the session's `session_id`.** A mismatch closes the socket. +- **Unknown message types close the socket.** They aren't ignored. +- **Keepalive uses WebSocket ping/pong**, not JSON. The service pings every 15 seconds; two missed pongs count as a lost connection. Clients should ping at the same interval and treat a missed pong as a connection error. + +## Messages + +### Connecting + +**`session_claim`**, app → service, first message on a new connection: + +```json +{ + "type": "session_claim", + "protocol_version": 2, + "session_id": "XzAERP54_Goh74hZ", + "token": "", + "device_manufacturer": "Apple", + "device_model": "iPhone15,2", + "device_os": "iOS 18.2" +} +``` + +`protocol_version` must be `2`. `session_id` and `token` are required, up to 128 characters. The `device_*` fields are optional strings up to 256 characters; one invalid field rejects the whole message. The alias is derived from `device_model`. + +**`session_resume`**, app → service, first message when reconnecting: + +```json +{ "type": "session_resume", "protocol_version": 2, "session_id": "XzAERP54_Goh74hZ", "resume_token": "" } +``` + +**`session_ack`**, service → app, success reply to either: + +```json +{ + "type": "session_ack", + "session_id": "XzAERP54_Goh74hZ", + "status": "ok", + "alias": "iphone15-2", + "resume_token": "", + "keepalive_interval_s": 15, + "grace_s": 600 +} +``` + +The `resume_token` changes on **every** successful claim and resume, and the previous one stops working. Always keep the latest. The reference clients keep it in memory only, never on disk. + +### Tool registry + +**`tool_registry_snapshot`**, app → service, after every claim and every resume. It replaces whatever the service had: + +```json +{ + "type": "tool_registry_snapshot", + "session_id": "XzAERP54_Goh74hZ", + "tools": [ + { + "name": "sum", + "description": "Add two numbers.", + "input_schema": { "type": "object", "properties": { "a": { "type": "number" }, "b": { "type": "number" } }, "required": ["a", "b"] }, + "output_schema": { "type": "object", "properties": { "total": { "type": "number" } } }, + "annotations": { "readOnlyHint": true }, + "timeout_ms": 60000, + "group": "math" + } + ] +} +``` + +One invalid descriptor invalidates the whole snapshot and closes the socket. + +**`tool_registry_delta`**, app → service, when a tool is added, changed, or removed: + +```json +{ "type": "tool_registry_delta", "session_id": "XzAERP54_Goh74hZ", "operation": "upsert", "tool": { "name": "sum", "description": "Add two numbers." } } +{ "type": "tool_registry_delta", "session_id": "XzAERP54_Goh74hZ", "operation": "remove", "name": "sum" } +``` + +### Calls + +**`tool_call`**, service → app. `args` is always a JSON object: + +```json +{ "type": "tool_call", "session_id": "XzAERP54_Goh74hZ", "id": "call_1", "name": "sum", "args": { "a": 2, "b": 3 } } +``` + +**`tool_result`**, app → service. `result` can be any JSON value, including `null`: + +```json +{ "type": "tool_result", "session_id": "XzAERP54_Goh74hZ", "id": "call_1", "result": { "total": 5 } } +``` + +**`tool_error`**, app → service. `error.type` must be one of the [app error types](#error-types): + +```json +{ + "type": "tool_error", + "session_id": "XzAERP54_Goh74hZ", + "id": "call_1", + "error": { "type": "tool_execution_error", "message": "Something went wrong", "details": { "stack": "…" } } +} +``` + +**`tool_call_progress`**, app → service, optional during a long call. Both fields are optional: + +```json +{ "type": "tool_call_progress", "session_id": "XzAERP54_Goh74hZ", "id": "call_1", "progress": 0.5, "message": "Halfway there" } +``` + +**`tool_cancel`**, service → app, when the caller goes away while the call is pending: + +```json +{ "type": "tool_cancel", "session_id": "XzAERP54_Goh74hZ", "id": "call_1", "reason": "client_cancelled" } +``` + +A cancel for an unknown or finished call is not an error. The app should abort the handler and reply with `tool_error` of type `tool_cancelled`. A handler that ignores the cancel may still reply normally. + +The app runs its own timer per call, using the tool's `timeout_ms` or 10 seconds. When it fires, the app replies `tool_timeout` and ignores the handler's later result. + +### App events + +**`event`**, app → service, outside the call cycle: + +```json +{ "type": "event", "session_id": "XzAERP54_Goh74hZ", "name": "screen_changed", "payload": { "screen": "Checkout" }, "ts": 1752600000000 } +``` + +`ts` is in milliseconds. `payload` is optional. + +## Tool descriptor + +```json +{ + "name": "sum", + "description": "Add two numbers.", + "input_schema": {}, + "output_schema": {}, + "annotations": { "readOnlyHint": true, "destructiveHint": false, "idempotentHint": true }, + "timeout_ms": 60000, + "group": "math/arithmetic" +} +``` + +| Field | Required | Rules | +| --- | --- | --- | +| `name` | Yes | `^[a-zA-Z0-9_-]{1,64}$`, unique per session | +| `description` | Yes | 1–4,096 characters | +| `input_schema` | No | A JSON object, documented as JSON Schema draft 2020-12. Must accept a JSON object to be callable. | +| `output_schema` | No | A JSON object | +| `annotations` | No | `readOnlyHint`, `destructiveHint`, `idempotentHint`. `destructiveHint: true` selects the `destructive` policy. | +| `timeout_ms` | No | Positive integer. The default time limit for calls; the service clamps it to 1,000–600,000. | +| `group` | No | `^[a-zA-Z0-9_-]{1,64}(/[a-zA-Z0-9_-]{1,64})?$`. Omit for an ungrouped tool; `null` and `""` are invalid. | + +Descriptor fields are snake_case. A camelCase `timeoutMs` on a descriptor is an unknown field, not a time limit. The service never inspects schema contents, only that they're objects. Services that don't know `group` ignore it. + +## Session states + +``` + link created + │ + ▼ + ┌─► PENDING ──TTL expired──► DISCARDED + │ │ + │ claim ok + │ ▼ + │ ACTIVE ◄──────────resume ok───────┐ + │ │ │ + │ connection lost │ + │ ▼ │ + │ SUSPENDED ──grace elapsed──► EXPIRED + │ └──────────────────────────────┘ + └─ revoke, from any state ──► REVOKED +``` + +- **Pending:** the token is single-use. Five failed claims make the session unclaimable. +- **Active → suspended:** on close, error, or missed pongs. The tool list, device info, and alias are kept. Pending calls fail with `session_suspended`. +- **Suspended → active:** a `session_resume` on a new, pinned connection within `grace_s` (default 600 seconds), with the latest resume token. The app then sends a full snapshot. +- **Discarded, expired, revoked** are final and free the alias. + +## Close codes + +| Code | Reason | When | +| --- | --- | --- | +| 1000 | `session_replaced` | A new claim or resume for the same session replaced this connection | +| 1000 | `revoked` | The session was revoked | +| 1003 | `binary_frame_not_supported` | A binary frame arrived | +| 1008 | `pre_claim_timeout` | No claim or resume within 10 seconds | +| 1008 | `invalid_json` | A frame wasn't valid JSON | +| 1008 | `expected_claim_or_resume` | The first message was something else | +| 1008 | `unknown_message_type` | Unknown `type` after the claim | +| 1008 | `session_mismatch` | Wrong `session_id` | +| 1008 | `already_claimed` | The session already has an active connection | +| 1008 | `unknown_session` | The service doesn't know this session, for example after it restarted | +| 1008 | `link_expired` | The link's expiry passed | +| 1008 | `claim_attempts_exceeded` | The fifth failed claim | +| 1008 | `invalid_token` | Wrong claim token | +| 1008 | `invalid_resume_token` | Wrong or outdated resume token | +| 1008 | `invalid_registry` | A snapshot or delta failed validation | +| 1008 | `invalid_message` | A known message type with invalid fields | +| 1011 | `send_failed` | The service couldn't write to the socket | + +**Treat `1008` as final:** no retry of the same message can succeed, so end the session and report the reason. Other closes, including `1011` and `1001` (service shutting down), are worth retrying with backoff while the grace period lasts. The reference clients back off from 0.5 up to 30 seconds, with jitter. + +## Error types + +These reach callers unchanged, as the `type` of a CLI `--json` error, an `AppductError` in `appduct/client`, or an MCP tool error. + +**Sent by the app** in `tool_error`: + +| Type | Meaning | +| --- | --- | +| `tool_not_found` | No tool with that name is registered | +| `tool_input_validation_error` | Arguments didn't match the input schema | +| `tool_output_validation_error` | The result didn't match the output schema | +| `tool_execution_error` | The handler threw | +| `tool_serialization_error` | The result couldn't be converted to JSON | +| `tool_timeout` | The call ran past its time limit | +| `tool_cancelled` | The caller cancelled the call | + +**Reported by the background service:** + +| Type | Meaning | +| --- | --- | +| `no_session` | No device is connected, and no selector was given | +| `ambiguous_session` | More than one device is connected; pass a selector | +| `unknown_session` | No session matches the selector | +| `session_not_active` | The session isn't active | +| `session_suspended` | The device disconnected during the call | +| `policy_denied` | [Policy](/appduct/guides/security/#limit-what-callers-can-run) refused the call. Changing config, not retrying, fixes it. | +| `invalid_request` | The request itself was malformed | + +## The local control interface + +The CLI, MCP server, and `appduct/client` talk to the background service with JSON-RPC 2.0 over a Unix domain socket at `/daemon.sock`, one message per line. It isn't part of the app protocol. Its methods are documented in [ARCHITECTURE.md §5](https://github.com/callstackincubator/appduct/blob/main/docs/ARCHITECTURE.md#5-control-plane-rpc-uds). diff --git a/website/src/content/docs/reference/react-native-api.md b/website/src/content/docs/reference/react-native-api.md new file mode 100644 index 00000000..82e3747c --- /dev/null +++ b/website/src/content/docs/reference/react-native-api.md @@ -0,0 +1,208 @@ +--- +title: React Native API +description: Entry points, functions, the useAppductTool hook, events, the Expo config plugin, and the Metro helper in @appduct/react-native. +sidebar: + order: 2 +--- + +Reference for `@appduct/react-native`. For setup, see [React Native setup](/appduct/start/react-native/); for how to design tools, see [Write tools](/appduct/guides/writing-tools/). + +## Entry points + +| Import | What it does | +| --- | --- | +| `@appduct/react-native` | The API below. Importing it does nothing on its own, and never crashes, even in Expo Go. | +| `@appduct/react-native/auto` | Same API, plus: listens for connection links and restores the session after a reload. Import it once at startup. Importing twice installs once. | +| `@appduct/react-native/noop` | Same API and types, with nothing running. Used when [stripping Appduct from a build](/appduct/guides/build-variants/#strip-appducts-javascript-too). | +| `@appduct/react-native/metro` | `withAppduct(config, options?)` for `metro.config.js`. | + +If the native module isn't in the build, every function behaves like `/noop`: it does nothing, never throws, and logs one warning. + +## Tools + +### `useAppductTool` + +```ts +useAppductTool(definition, deps?, options?) +``` + +Registers a tool while the component is mounted. Registers once per mount, and again only when the registration changes: `name`, `description`, the schemas' JSON Schema, `annotations`, `timeoutMs`, `group`, or `enabled`. Calls always run the handler from the latest render. + +| Argument | Description | +| --- | --- | +| `definition` | The same object as [`registerTool`](#registertool). | +| `deps` | Optional. Replaces the automatic change detection with your own dependency list. Rarely needed. | +| `options.enabled` | Default `true`. `false` doesn't register the tool, and removes an existing registration. Use this instead of wrapping the hook in `if`. | + +### `registerTool` + +```ts +const registration = registerTool({ + name, + description, + inputSchema?, + outputSchema?, + annotations?, + timeoutMs?, + group?, + handler, +}); + +registration.remove(); +``` + +| Field | Description | +| --- | --- | +| `name` | Required. Letters, digits, `_`, `-`; 1–64 characters. Unique per app: registering the same name again replaces the tool, with a warning in development. | +| `description` | Required. 1–4,096 characters. | +| `inputSchema` | Arguments schema. Must accept a JSON object. See [schema forms](#schema-forms). | +| `outputSchema` | Result schema. Any JSON value. | +| `annotations` | `{ readOnlyHint?, destructiveHint?, idempotentHint? }`. `destructiveHint` routes calls through the `destructive` [policy](/appduct/guides/security/#limit-what-callers-can-run). | +| `timeoutMs` | Time limit per call. Default 10,000. Clamped to 1,000–600,000. | +| `group` | `"cart"` or `"checkout/payment"`: one or two `/`-separated parts using name characters. | +| `handler` | `(args, context) => result`, sync or async. | + +`remove()` removes only this registration, even if the same name was registered again later. A malformed name or group throws. + +### `createToolGroup` + +```ts +const registerCartTool = createToolGroup("cart"); +registerCartTool({ name: "add_item", description: "Add a product to the cart.", handler }); +``` + +Returns a `registerTool` that puts every tool it registers in the given group. + +### Handler context + +The handler's second argument: + +| Field | Description | +| --- | --- | +| `signal` | An `AbortSignal`, aborted when the call times out, the caller cancels, or the connection drops. Uses `aborted` and the `"abort"` event. | +| `reportProgress(progress?, message?)` | Sends a progress update. Never throws; failures go to the `error` listener. | +| `sessionId` | The calling session. | +| `invocationId` | This call's id. | +| `receivedAt` | When the call arrived. | + +A thrown error fails the call with `tool_execution_error`. Results that fail `outputSchema` fail with `tool_output_validation_error`; arguments that fail `inputSchema` fail with `tool_input_validation_error` before the handler runs. + +### Schema forms + +| Form | Example | Validated | +| --- | --- | --- | +| Standard Schema with JSON Schema export | Zod 4, ArkType | Yes | +| `{ schema, jsonSchema }` pair | Zod 3 + `zod-to-json-schema`, Valibot + `@valibot/to-json-schema` | Yes | +| Raw JSON Schema (a plain object) | `{ type: "object", properties: { … } }` | No | + +`jsonSchema` in a pair can also be a converter `{ input, output }`. A Standard Schema with no JSON Schema export throws in development and registers without a schema in release builds. + +### `jsonSchema()` + +```ts +inputSchema: jsonSchema<{ city: string }>({ type: "object", properties: { city: { type: "string" } } }) +``` + +Types a raw JSON Schema object so the handler gets typed arguments. Doesn't validate. + +### `getRegisteredTools` + +Returns the tool descriptors currently registered, for example to show them in your app's UI. + +## Events + +### `postEvent` + +```ts +await postEvent("checkout_completed", { orderId: "ord_4821" }); +``` + +Sends an app event to connected callers (`appduct events`, `appduct_wait_for_event`, `app.waitForEvent`). Dropped, with a warning in development, when no session is connected. + +### `addAppductListener` + +```ts +const subscription = addAppductListener("stateChange", ({ state, reason }) => { + console.log(state, reason); +}); + +subscription.remove(); +``` + +| Kind | Event | +| --- | --- | +| `"stateChange"` | `{ state, reason? }`. `reason` is set on moves to `closed` or `reconnecting`, such as `revoked`, `grace_expired`, `socket_error`, or `background`. | +| `"sessionChange"` | `{ type, sessionId, alias, reason? }`. `type` is `"claimed"`, `"resumed"`, or `"lost"`; `sessionId` and `alias` are `null` once the session is gone. | +| `"error"` | `{ phase, message, code?, hint?, toolName?, … }`. `phase` is `"bootstrap"`, `"connect"`, `"socket"`, or `"tool"`: one channel for link parsing, connection, and handler failures. | + +## Connection + +### `getAppductState` + +Returns `"idle"`, `"connecting"`, `"active"`, `"reconnecting"`, or `"closed"`. `"idle"` when there's no session, and always in a build without Appduct. + +### `restoreSession` + +```ts +const restored = await restoreSession(); +``` + +Resumes a session that survived a JavaScript reload. `/auto` already calls it. If you don't use `/auto`, call it once at startup, before your own link handling, or every Metro reload drops the session. Resolves `true` when a resume started. A killed app process can't be restored. + +### `connect` + +```ts +import { connect, parseBootstrapUrl } from "@appduct/react-native"; + +await connect(parseBootstrapUrl(url)); +``` + +Connects from a link you received yourself. Most apps don't need this: `/auto` does it. `parseBootstrapUrl` throws `AppductBootstrapParseError` with `code` `invalid_url`, `missing_payload`, `invalid_payload`, or `expired_payload`. `connect` rejects with `AppductDisabledError` (`code: "appduct_disabled"`) in a build without Appduct. + +### `getAppductBuildConfig` + +Returns `{ trust, hasEmbeddedPins, allowPrivateLanOnly }`: the trust settings this build actually uses. `trust` is `"pin"` whenever pins are embedded, `"link"` otherwise, and `"absent"` in a build without Appduct. Never exposes the pins. + +## Expo config plugin + +Optional. Add it only to [pin a build to your key](/appduct/guides/security/#pin-a-build-to-your-key) or change the network setting: + +```json title="app.json" +{ + "expo": { + "scheme": "myapp", + "plugins": [ + ["@appduct/react-native", { "cliPins": ["sha256/REPLACE_WITH_KEYGEN_OUTPUT"] }] + ] + } +} +``` + +| Option | Default | Description | +| --- | --- | --- | +| `cliPins` | none | Array of `sha256/...` fingerprints from `appduct keygen`. Setting it makes `trust` default to `"pin"`. | +| `trust` | `"pin"` with `cliPins`, else `"link"` | `"link"` or `"pin"`. `"pin"` requires non-empty `cliPins`. Anything else fails prebuild. | +| `allowPrivateLanOnly` | `true` | Only follow links that point to a local IPv4 address. | +| `deepLinkScheme` | none | Warns at prebuild if this scheme isn't in `expo.scheme`. | + +Run prebuild again after changing these. The removed options `include` and `enableInReleaseBuilds` fail prebuild with a message naming the replacement, `APPDUCT_ENABLED`. + +For bare React Native, set the equivalent native keys: see [Security](/appduct/guides/security/#pin-a-build-to-your-key). + +## Metro helper + +```js title="metro.config.js" +const { withAppduct } = require("@appduct/react-native/metro"); + +module.exports = withAppduct(config, { include: false }); +``` + +| Option | Default | Description | +| --- | --- | --- | +| `include` | from `APPDUCT_ENABLED` | `false` resolves every `@appduct/react-native` import to `/noop`. | + +Call it last in `metro.config.js`. See [Build variants](/appduct/guides/build-variants/#strip-appducts-javascript-too). + +## Advanced exports + +`appductClient` is the default client the functions above use, and `createAppductClient` creates another. Most apps don't need either. The package also exports its TypeScript types, such as `AppductToolDefinition`, `AppductToolExecutionContext`, and `AppductClientState`. diff --git a/website/src/content/docs/start/android.mdx b/website/src/content/docs/start/android.mdx new file mode 100644 index 00000000..c54afb75 --- /dev/null +++ b/website/src/content/docs/start/android.mdx @@ -0,0 +1,194 @@ +--- +title: Android setup +description: Add Appduct to a Kotlin or Java Android app without React Native, register tools, and connect it to the CLI. +sidebar: + order: 5 +--- + +import { Steps } from '@astrojs/starlight/components'; + +This page adds Appduct to a plain Android app, with no React Native. You register tools in Kotlin, and the CLI or an agent calls them the same way as in a React Native app. Building with React Native instead? See [React Native setup](/appduct/start/react-native/). + +**Requirements** + +- Android 7.0 (API 24) or newer. +- The `appduct` CLI on your computer: `npm install -g appduct` (Node 20 or newer), and `adb` on your `PATH` to connect emulators and USB devices automatically. + +## Set up the app + + + +1. Add the two Appduct artifacts from Maven Central: + + ```kotlin title="app/build.gradle.kts" + dependencies { + debugImplementation("com.callstack.appduct:core:") + releaseImplementation("com.callstack.appduct:core-noop:") + } + ``` + + `core` is the real library. `core-noop` has the same API with every method doing nothing, and no network code. This pairing keeps Appduct out of your release build. + +2. Name the scheme Appduct opens your app with: + + ```kotlin title="app/build.gradle.kts" + android { + defaultConfig { + manifestPlaceholders["appductScheme"] = "myapp" + } + } + ``` + + If you forget this, the build fails with a manifest-merger error naming `appductScheme`. The scheme can differ from the one your app uses for its own deep links; see [Deep links](#deep-links). + +3. Make sure your app has the internet permission, in `AndroidManifest.xml`: + + ```xml + + ``` + + Appduct doesn't add permissions for you. Without this one, the app opens the link but never connects. + +4. Register tools in `Application.onCreate()`: + + ```kotlin + import com.callstack.appduct.Appduct + import org.json.JSONObject + + class ShopApp : Application() { + override fun onCreate() { + super.onCreate() + + Appduct.register( + name = "seed_cart", + description = "Fill the cart with test items.", + inputSchema = JSONObject( + """{"type":"object","properties":{"items":{"type":"number"}},"required":["items"]}""", + ), + ) { args -> + JSONObject().put("added", args.optInt("items")) + } + } + } + ``` + + There's no `init` call: Appduct starts itself before `onCreate()` runs. + +5. In your project directory, record your package name so the CLI can open links on a device: + + ```bash + appduct init --android-app-id com.example.shop + ``` + + This writes `.appduct/config.json`, which you commit, and prints an MCP config entry for this app. Use the `applicationId` of the variant you install, including any `applicationIdSuffix`. + + + +## Connect and check it works + +Install the debug build on an emulator or a USB-connected device, then, from your project directory: + +```bash +appduct link --open android +appduct tools +appduct invoke seed_cart --input '{"items":3}' +``` + +`--open android` forwards the connection through `adb`, so it works over USB without the device being on your network. To connect by QR code instead, run `appduct link --qr` and scan it with the device's camera; the device must then be on the same local network as your computer. + +The app restores its session on its own after a short network drop. If the app process is killed, connect again with a new link. + +## Register tools in Kotlin + +- **Schemas are plain JSON Schema**, as `org.json.JSONObject`. Appduct doesn't validate arguments against them: they tell agents what to send. Your handler receives the arguments as a `JSONObject`. +- **Return** `org.json` values, or plain `Map`, `List`, `String`, `Number`, `Boolean`, or `null`. Anything else fails the call with `tool_serialization_error`. +- **Handlers run on a background dispatcher**, never the main thread. Switch for UI work: + + ```kotlin + Appduct.register(name = "flash_screen", description = "Flash the screen once.") { _ -> + withContext(Dispatchers.Main) { + // touch a View or Compose state here + } + JSONObject() + } + ``` + +- **Progress:** use the overload whose handler also takes a `context`: + + ```kotlin + Appduct.register(name = "sync_catalog", description = "Download the product catalog.") { args, context -> + context.reportProgress(0.5, "halfway") + JSONObject().put("done", true) + } + ``` + +- **Cancellation:** when a caller cancels or the connection drops, the handler's coroutine is cancelled. Suspending calls then throw `CancellationException`. +- **Optional arguments:** `outputSchema`, `annotations` (`ToolAnnotations(readOnlyHint, destructiveHint, idempotentHint)`), `timeoutMs` (default 10 seconds), and `group`. See [Writing tools](/appduct/guides/writing-tools/) for what each one does. A malformed name or group throws `IllegalArgumentException`. +- **Unregistering:** `register` returns a `ToolRegistration`; call `.remove()`. + +To watch the connection, use `Appduct.addListener { event -> … }`, which reports state changes, session changes, and errors, and returns a subscription you can `remove()`. `Appduct.state` and `Appduct.sessionId` give the current values. To tell a test or agent that something happened, call `Appduct.postEvent(name, payload)` from a coroutine. The event is dropped if no session is connected. Read events with `appduct events`, or [wait for one from a test](/appduct/guides/cli/#watch-events). + +## Deep links + +Appduct includes an invisible activity that receives links with your `appductScheme` and hands them to Appduct. You don't need any code for this. + +If your app already handles its own links **on the same scheme**, that activity can't tell your links from Appduct's. Pick one: + +- Give Appduct its own scheme in `manifestPlaceholders["appductScheme"]`, or +- Remove Appduct's activity (below) and call `Appduct.handle(intent)` from your own activity's `onCreate` and `onNewIntent`. It returns `true` when the link was for Appduct, so you can handle the rest yourself. `Appduct.handle(uri)` also works. + +### Remove Appduct's activity or startup provider + +To handle links or startup yourself, remove the components in your app's manifest: + +```xml + + + + + + +``` + +:::caution +If you remove `AppductInitProvider`, every `Appduct` call throws `IllegalStateException`, because nothing gives Appduct your app's `Context`. Remove it only if you know you need to. +::: + +## Ship Appduct in a release build + +For an internal or QA build that needs Appduct, depend on `core` instead of `core-noop` for that variant. + +Pin that build to your key before it leaves your team. Add these `` entries to your ``: + +| Name | Value | +| --- | --- | +| `com.callstack.appduct.CLI_PINS` | JSON array string of `sha256/...` pins, printed by `appduct keygen` | +| `com.callstack.appduct.TRUST` | `"link"` or `"pin"`. Any other value fails every connection attempt. | +| `com.callstack.appduct.ALLOW_PRIVATE_LAN_ONLY` | Boolean. Defaults to `true`: links must point to a local network address. | + +See [Security](/appduct/guides/security/) for what each mode protects against. `Appduct.buildConfig` reports what a running build actually uses. + +Always check the built APK, not the Gradle config: + +```bash +appduct doctor app/build/outputs/apk/release/app-release.apk --assert-absent +appduct doctor app/build/outputs/apk/debug/app-debug.apk --assert-present +``` + +## Troubleshooting + +**Manifest-merger error naming `appductScheme`.** Set `manifestPlaceholders["appductScheme"]` in `build.gradle`. + +**`appduct link --open android` reports "unable to resolve Intent".** Either the app id isn't the installed build's `applicationId` (check for an `applicationIdSuffix`), or the scheme doesn't match `appductScheme` in the installed build. Placeholders are fixed at build time, so rebuild and reinstall after changing one. + +**The link opens the app, but it never connects, with a permission-style error.** Add the `INTERNET` permission to your manifest. + +**`IllegalStateException`: "Appduct is not initialized".** `AppductInitProvider` was removed from the manifest. + +**A handler crashes when it touches the UI.** Handlers run off the main thread. Use `withContext(Dispatchers.Main)`. + +For a complete example app, see the [native Android playground](/appduct/start/playground/#native-android-playground). diff --git a/website/src/content/docs/start/introduction.mdx b/website/src/content/docs/start/introduction.mdx new file mode 100644 index 00000000..c5bb7496 --- /dev/null +++ b/website/src/content/docs/start/introduction.mdx @@ -0,0 +1,54 @@ +--- +title: Introduction +description: Appduct lets a terminal, a test runner, or an AI agent call functions inside your running React Native, iOS, or Android app. +sidebar: + order: 1 +--- + +import { CardGrid, LinkCard } from '@astrojs/starlight/components'; + +Appduct lets a terminal, a test runner, or an AI agent call functions inside your app while it's running. You choose what's callable by registering a few functions, called **tools**. Nothing else in the app is reachable. + +It works with React Native apps, and with plain iOS (Swift) and Android (Kotlin) apps. + +## Who it's for + +- **Teams writing end-to-end tests** who are tired of tapping through login, onboarding, and seeding data before every test. +- **Developers working with coding agents** such as Claude Code or Cursor, who want the agent to flip a feature flag, jump to a screen, or read app state without clicking through the UI. +- **QA and internal-build workflows** that need a controlled way to put an app into a known state. + +## Why use it + +**Your E2E tests skip the setup.** Most of an end-to-end test isn't the thing you're testing. It's logging in, dismissing onboarding, seeding a cart. With Appduct, the test calls `login(userId)` or `seedCart(items)` directly and moves on to the part that matters. Runs get faster and less flaky, and an agent burns fewer screenshots. + +**Agents can drive your app.** Add Appduct to your agent's MCP config and it can list and call your app's tools. + +**There's no hidden debug UI.** No secret gestures, no long-press admin panel, nothing in the app for someone to go find. The only things reachable are the tools you registered. + +**Release builds don't include it.** Appduct is in debug builds only. A release build leaves it out at compile time rather than switching it off. You can opt in for internal builds, such as a TestFlight build your CI drives. See [Build variants](/appduct/guides/build-variants/). + +**Your dev loop keeps working.** Reloads, backgrounding the app, and flaky Wi-Fi don't end the session: it reconnects on its own. One background service on your machine handles every device you connect. + +## How the pieces fit + +You install the `appduct` CLI on your computer and add the Appduct library to your app. The CLI runs a background service (the daemon) that your app connects to over an encrypted connection. To connect a device, you open a one-time link in the app, either delivered automatically to a simulator or emulator or scanned as a QR code. After that, the CLI, your MCP-connected agent, and your test runner all talk to the same service and see the same tools. The service starts itself the first time you run a command. + +For more detail, see [How it works](/appduct/reference/architecture/). + +## Requirements + +| Where | Requirement | +| --- | --- | +| React Native app | iOS 15.1+ and Android, New Architecture. A development build or bare React Native app; Expo Go isn't supported. Web gets a stub that does nothing. | +| iOS app without React Native | iOS 15.1+. Installing with Swift Package Manager needs Xcode 16.3 or newer. | +| Android app without React Native | Android 7.0 (API 24) or newer. | +| CLI | Node 20 or newer, on macOS or Linux. Windows hasn't been verified. | + +## Where to go next + + + + + + + diff --git a/website/src/content/docs/start/ios.mdx b/website/src/content/docs/start/ios.mdx new file mode 100644 index 00000000..f538923a --- /dev/null +++ b/website/src/content/docs/start/ios.mdx @@ -0,0 +1,238 @@ +--- +title: iOS setup +description: Add Appduct to a SwiftUI or UIKit app without React Native, register tools in Swift, and connect it to the CLI. +sidebar: + order: 4 +--- + +import { Steps, Tabs, TabItem } from '@astrojs/starlight/components'; + +This page adds Appduct to a plain iOS app, with no React Native or Expo. You register tools in Swift, and the CLI or an agent calls them the same way as in a React Native app. Building with React Native instead? See [React Native setup](/appduct/start/react-native/). + +**Requirements** + +- iOS 15.1 or newer. +- Xcode 16.3 or newer if you install with Swift Package Manager. +- The `appduct` CLI on your Mac: `npm install -g appduct` (Node 20 or newer). + +## Set up the app + + + +1. Add the `AppductCore` library: + + + + ```swift title="Package.swift" + .package(url: "https://github.com/callstackincubator/appduct", from: "0.10.0") + ``` + + Add the `AppductCore` product to your app target. In Xcode: File → Add Package Dependencies, then paste the repository URL. + + `from: "0.10.0"` resolves to the newest `0.x` release. + + + ```ruby title="Podfile" + pod 'AppductCore', :configurations => ['Debug'] + ``` + + The `:configurations` restriction keeps the pod out of your Release build. + + + + With either option, your **Release** build doesn't contain Appduct's connection code. See [Ship Appduct in a Release build](#ship-appduct-in-a-release-build) to change that. + +2. Declare a URL scheme in `Info.plist` (Xcode: target → Info → URL Types): + + ```xml title="Info.plist" + CFBundleURLTypes + + + CFBundleURLSchemes + + myapp + + + + ``` + + Appduct connects by opening a link with this scheme. The CLI reads it from `Info.plist` when you run it from your project directory. + +3. Forward incoming links to Appduct: + + + + ```swift + import AppductCore + import SwiftUI + + @main + struct ShopApp: App { + var body: some Scene { + WindowGroup { + ContentView() + .onOpenURL { url in + _ = Appduct.shared.handle(url) + } + } + } + } + ``` + + + In your scene delegate, forward from `scene(_:openURLContexts:)`, and from `connectionOptions.urlContexts` in `scene(_:willConnectTo:options:)` for a launch from a link: + + ```swift + func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { + for context in URLContexts { + _ = Appduct.shared.handle(context.url) + } + } + ``` + + + + `handle(_:)` returns `true` when the link was meant for Appduct, so you can pass other links to your own handling: + + ```swift + .onOpenURL { url in + if !Appduct.shared.handle(url) { + router.open(url) + } + } + ``` + +4. Register a tool, for example at app startup: + + ```swift + import AppductCore + + try Appduct.shared.register( + name: "seed_cart", + description: "Fill the cart with test items.", + inputSchema: [ + "type": "object", + "properties": ["items": ["type": "number"]], + "required": ["items"], + ] + ) { args in + let items = (args["items"] as? NSNumber)?.intValue ?? 0 + return ["added": items] + } + ``` + + See [Register tools in Swift](#register-tools-in-swift) for the details. + +5. In your project directory, record the bundle id so the CLI can open links on a physical iPhone: + + ```bash + appduct init --ios-app-id com.example.shop + ``` + + This writes `.appduct/config.json`, which you commit, and prints an MCP config entry for this app. + + + +## Connect and check it works + +Build and run the **Debug** configuration on a simulator, then, from your project directory: + +```bash +appduct link --open ios-sim +appduct tools +appduct invoke seed_cart --input '{"items":3}' +``` + +For a physical device, run `appduct link --qr` and scan the code with the phone's camera. The phone must be on the same local network as your Mac. See [Connect a device](/appduct/guides/cli/#connect-a-device) for other options. + +The app restores its session on its own after a short network drop. If the app process is killed, connect again with a new link. + +## Register tools in Swift + +- **Schemas are plain JSON Schema**, written as `[String: Any]`. Appduct doesn't validate arguments against them: they tell agents what to send. Your handler receives the arguments as `[String: Any]`. +- **The handler is `async throws`.** Return any JSON-compatible value: `nil`, a number, string, or bool, an array, a dictionary, or nested combinations. Returning something else, such as `Date` or `Data`, fails the call with `tool_serialization_error`. Throwing fails the call with `tool_execution_error`. +- **Handlers run off the main actor.** Wrap UI work in `await MainActor.run { … }`: + + ```swift + try Appduct.shared.register(name: "show_alert", description: "Show a native alert.") { _ in + await MainActor.run { + // present UI here + } + return nil + } + ``` + +- **Optional arguments:** `outputSchema`, `annotations` (`ToolAnnotations(readOnlyHint:destructiveHint:idempotentHint:)`), `timeoutMs` (default 10 seconds), and `group`. See [Writing tools](/appduct/guides/writing-tools/) for what each one does. +- **Progress:** a handler that takes a second `ToolCallContext` argument can call `context.reportProgress(progress:message:)`. +- **Unregistering:** `register` returns a `ToolRegistration`. Call `.remove()` to unregister. Letting it go out of scope doesn't unregister the tool. +- **Registering the same name twice** replaces the first handler. +- A malformed name or group makes `register` throw. + +## Watch the connection and send events + +```swift +let subscription = Appduct.shared.addListener { event in + switch event { + case .stateChange(let change): + print("state ->", change.state.rawValue, change.reason ?? "") + case .sessionChange(let change): + print("session ->", change.sessionId ?? "none") + case .error(let error): + print("error [\(error.phase)]:", error.message) + } +} + +// Stop listening: +subscription.cancel() +``` + +`Appduct.shared.state` and `Appduct.shared.sessionId` give the current values without a listener. + +To tell a test or agent that something happened, post an event. It throws unless a session is connected: + +```swift +try await Appduct.shared.postEvent("checkout_completed", payload: ["orderId": "ord_4821"]) +``` + +Read events with `appduct events`, or wait for one from a test. See [Wait for app events](/appduct/guides/cli/#watch-events). + +## Ship Appduct in a Release build + +For an internal or QA build that needs Appduct in its Release configuration: + +- **Swift Package Manager:** enable the `AlwaysEnabled` package trait: + + ```swift + .package(url: "https://github.com/callstackincubator/appduct", from: "0.10.0", traits: ["AlwaysEnabled"]) + ``` + +- **CocoaPods:** remove the `:configurations` restriction. + +Pin that build to your key before it leaves your team. Set these `Info.plist` keys: + +| Key | Value | +| --- | --- | +| `AppductCliPins` | Array of `sha256/...` strings, printed by `appduct keygen` | +| `AppductTrust` | `"link"` or `"pin"`. Any other value fails every connection attempt. | +| `AppductAllowPrivateLanOnly` | Boolean. Defaults to `true`: links must point to a local network address. | + +See [Security](/appduct/guides/security/) for what each mode protects against. `Appduct.shared.buildConfig` reports what a running build actually uses. + +Always check the built app, not the build settings: + +```bash +appduct doctor build/Shop.app --assert-absent # a Release build that shouldn't have it +appduct doctor build/Shop.app --assert-present # a build that should +``` + +## Troubleshooting + +**`handle(_:)` always returns `false`.** The URL doesn't carry an Appduct link. Check that the scheme in `Info.plist` matches what `appduct link` used, and that you pass the URL you received, unchanged. + +**A tool call never reaches the handler.** Check that `Appduct.shared.state` is `.active`, and that `appduct tools` lists the tool's name. Calls to an unregistered name fail with `tool_not_found`. + +**A Release build still connects.** You enabled `AlwaysEnabled` or removed the CocoaPods restriction. Run `appduct doctor` on the artifact to confirm what shipped. + +**The app crashes or misbehaves when a tool updates the UI.** The handler touched UI off the main actor. Use `await MainActor.run`. + +For a complete example app, see the [native iOS playground](/appduct/start/playground/#native-ios-playground). diff --git a/website/src/content/docs/start/playground.mdx b/website/src/content/docs/start/playground.mdx new file mode 100644 index 00000000..4095c94f --- /dev/null +++ b/website/src/content/docs/start/playground.mdx @@ -0,0 +1,154 @@ +--- +title: Try the playground +description: Run one of Appduct's example apps — Expo, SwiftUI, or Jetpack Compose — and drive it from the CLI. +sidebar: + order: 6 +--- + +import { Steps } from '@astrojs/starlight/components'; + +The Appduct repository has three example apps. Each registers the same five tools, so you can see the whole loop — connect, list, call, watch events — before you touch your own project. + +| App | What it shows | +| --- | --- | +| [Expo playground](#expo-playground) | A React Native app with tools registered through `useAppductTool`, including groups | +| [Native iOS playground](#native-ios-playground) | A SwiftUI app with no React Native | +| [Native Android playground](#native-android-playground) | A Jetpack Compose app with no React Native | + +The tools: + +| Tool | What it does | +| --- | --- | +| `sum` | Adds two numbers | +| `call_count` | Reports how many times the counted tools have run | +| `reset_counter` | Resets the counter; marked destructive | +| `slow_task` | Takes about 1.5 seconds and reports progress | +| `throwing_tool` | Always fails, so you can see a `tool_execution_error` | + +**Requirements:** a clone of [the repository](https://github.com/callstackincubator/appduct), Node 20 or newer, and pnpm. Each app also needs its platform's tools: Xcode for iOS, the Android SDK and Java 17 for Android. + +## Expo playground + +The Expo app has two tabs: **Tools** lists the registered tools, and **Status** shows the connection state, recent errors, and a button that posts an event. It needs no keys, pins, or flags: its scheme and app ids are recorded in `playground/.appduct/config.json`. + + + +1. From the repository root, install dependencies and build the packages: + + ```bash + pnpm install + pnpm build + ``` + +2. Build and run the development build. This also starts Metro: + + ```bash + cd playground + pnpm exec expo run:ios # or: pnpm exec expo run:android + ``` + +3. Back in the repository root, connect the app: + + ```bash + pnpm run playground:appduct -- link --open ios-sim # iOS Simulator + pnpm run playground:appduct -- link --open android # Android emulator + pnpm run playground:appduct -- link --qr # physical device on your local network + ``` + + `playground:appduct` runs the repository's own build of the CLI. The **Status** tab switches to `active` and shows the session's alias. + +4. Drive it: + + ```bash + pnpm run playground:appduct -- tools + pnpm run playground:appduct -- invoke sum --input '{"a":1,"b":2}' + pnpm run playground:appduct -- invoke slow_task --input '{}' + pnpm run playground:appduct -- events --follow + ``` + + While `events --follow` runs, tap **Send playground_ping** on the Status tab to see the event arrive. + + + +Things to try: + +- **Groups:** `tools --groups`, then `tools --group diagnostics`. The playground puts its tools in `counter`, `diagnostics`, and `diagnostics/progress`, and leaves `sum` ungrouped. +- **Reloads:** press `r` in the Metro terminal. The Status tab shows `reconnecting`, then `active` with the same alias. No new link is needed as long as the app process stays alive. +- **Errors:** `invoke throwing_tool --input '{}'` fails with `tool_execution_error`. +- **Policy:** set `policy.destructive` to `"deny"` in `~/.appduct/config.json`, run `pnpm run playground:appduct -- daemon stop`, reconnect, and `reset_counter` is refused with `policy_denied`. See [Security](/appduct/guides/security/#limit-what-callers-can-run). + +## Native iOS playground + +A SwiftUI app that uses `AppductCore` directly. Its scheme, `appduct-native`, is recorded in `playground-native/.appduct/config.json`. + + + +1. Generate the Xcode project with [XcodeGen](https://github.com/yonaskolb/XcodeGen): + + ```bash + cd playground-native/ios + brew install xcodegen # once + xcodegen generate + ``` + +2. Build and launch on a booted simulator. Pick a simulator name from `xcrun simctl list devices available`: + + ```bash + xcodebuild build -project AppductPlayground.xcodeproj -scheme AppductPlayground \ + -configuration Debug -sdk iphonesimulator \ + -destination 'platform=iOS Simulator,name=iPhone 17' CODE_SIGNING_ALLOWED=NO + xcrun simctl install booted \ + ~/Library/Developer/Xcode/DerivedData/AppductPlayground-*/Build/Products/Debug-iphonesimulator/AppductPlayground.app + xcrun simctl launch booted com.callstack.appduct.playgroundnative + ``` + + Or open `AppductPlayground.xcodeproj` in Xcode and press Run. + +3. Connect and call a tool, from `playground-native/ios`: + + ```bash + appduct link --open ios-sim + appduct tools + appduct invoke sum --input '{"a":2,"b":3}' + ``` + + + +## Native Android playground + +A Jetpack Compose app that uses `com.callstack.appduct:core` directly. It builds against the repository's own sources. + + + +1. Build and install the debug APK on a booted emulator or connected device: + + ```bash + cd playground-native/android + ./gradlew :app:assembleDebug + adb install -r app/build/outputs/apk/debug/app-debug.apk + adb shell am start -n com.callstack.appduct.playground/.MainActivity + ``` + +2. Connect and call a tool, from inside `playground-native/`, where the scheme and app id are recorded: + + ```bash + appduct link --open android + appduct tools + appduct invoke sum --input '{"a":2,"b":3}' + appduct events + ``` + + + +## Check what a build contains + +The native playgrounds are also a quick way to see [build variants](/appduct/guides/build-variants/) in action. The Debug build contains Appduct and the Release build doesn't: + +```bash +./gradlew :app:assembleRelease +appduct doctor app/build/outputs/apk/release/app-release-unsigned.apk --assert-absent +``` + +:::note +If you have `appduct` installed globally, `pnpm exec appduct` inside the repository can run the global copy instead of the repository's build. To be sure you run the repository's build, use `node packages/appduct/dist/bin.js` from the repository root. +::: diff --git a/website/src/content/docs/start/quick-start.mdx b/website/src/content/docs/start/quick-start.mdx new file mode 100644 index 00000000..b5cf7890 --- /dev/null +++ b/website/src/content/docs/start/quick-start.mdx @@ -0,0 +1,154 @@ +--- +title: Quick start +description: Add Appduct to a React Native app, register one tool, call it from your terminal, and connect an agent. +sidebar: + order: 2 +--- + +import { Steps, Tabs, TabItem } from '@astrojs/starlight/components'; + +By the end of this page you'll have called a function inside your running app from your terminal, and handed the same function to an AI agent. + +This page uses an Expo app. For bare React Native, plain iOS, or plain Android, see [React Native setup](/appduct/start/react-native/), [iOS setup](/appduct/start/ios/), or [Android setup](/appduct/start/android/). + +**Before you start, you need:** + +- An Expo app that you run as a **development build** (`npx expo run:ios` or `npx expo run:android`). Expo Go can't load Appduct's native code. +- `expo.scheme` set in `app.json`. Appduct opens your app through this deep-link scheme. +- Node 20 or newer. +- A booted iOS Simulator or Android emulator. + + + +1. Install the CLI on your computer: + + ```bash + npm install -g appduct + ``` + +2. Add the library and a schema library to your app: + + + + ```bash + npm install @appduct/react-native zod + ``` + + + ```bash + pnpm add @appduct/react-native zod + ``` + + + ```bash + yarn add @appduct/react-native zod + ``` + + + +3. Import Appduct once, at the top of your app's entry file. In an Expo Router app, that's `app/_layout.tsx`: + + ```ts title="app/_layout.tsx" + import "@appduct/react-native/auto"; + ``` + + This import is what lets the app open the connection link. + +4. Register a tool. Put it in a component that's always mounted, such as your root layout: + + ```tsx title="app/_layout.tsx" + import { useAppductTool } from "@appduct/react-native"; + import { z } from "zod"; + + function AppductTools() { + useAppductTool({ + name: "seed_cart", + description: "Fill the cart with test items.", + inputSchema: z.object({ items: z.number() }), + handler: async ({ items }) => ({ added: items }), + }); + + return null; + } + ``` + + Render `` inside your root layout. + +5. Rebuild and run the development build, so the native part of Appduct is included: + + + + ```bash + npx expo run:ios + ``` + + + ```bash + npx expo run:android + ``` + + + +6. From your app's root directory, connect the running app: + + + + ```bash + appduct link --open ios-sim + ``` + + + Use your app's package name, `expo.android.package` in `app.json`: + + ```bash + appduct link --open android --app-id com.example.shop + ``` + + + + The CLI reads your scheme from `app.json`, starts its background service, and opens the link in the app. No keys or config are needed. + +7. List the app's tools, then call one: + + ```bash + appduct tools + appduct invoke seed_cart --input '{"items":3}' + ``` + + `appduct tools` prints one line per tool, such as `seed_cart(items: number)`. `appduct invoke` prints what the handler returned: `{"added":3}`. + + + +## Connect an agent + +Add Appduct to your agent's MCP config. For Claude Code, that's `.mcp.json` in your project root; for Cursor, `.cursor/mcp.json`: + +```json +{ + "mcpServers": { + "appduct": { "command": "appduct", "args": ["mcp"] } + } +} +``` + +Restart the agent and ask it to call `seed_cart` with 5 items. It finds the app's tools, and can connect a booted simulator on its own. See [Use Appduct with an agent](/appduct/guides/agents/) for what the agent sees and how to require approval for risky tools. + +:::tip[Save the app ids once] +Run `appduct init --ios-app-id com.example.shop --android-app-id com.example.shop` in your app root. It records your scheme and app ids in `.appduct/config.json`, so you can drop `--app-id`, and it prints an MCP config entry for this app. Commit the file. +::: + +## If something goes wrong + +**`appduct link` says it can't find a scheme.** You ran it outside the app root, or your app uses a dynamic `app.config.js`, which Appduct never runs. Pass `--scheme myapp`, or run `appduct init --scheme myapp` once. + +**`--open android` fails before doing anything.** It needs the installed app's package name. Pass `--app-id`, or record it with `appduct init --android-app-id`. + +**The app opens but `appduct tools` says there's no session.** Check that the app imports `@appduct/react-native/auto`, and that you rebuilt after installing the package. In Expo Go, or a release build, Appduct is inactive. + +**`appduct invoke` fails with `tool_not_found`.** The component that registers the tool isn't mounted. Tools exist only while their component is mounted. + +## Next steps + +- [Write more useful tools](/appduct/guides/writing-tools/): schemas, timeouts, and groups. +- [Use Appduct from E2E tests](/appduct/guides/cli/#drive-the-app-from-a-test-suite). +- [Keep Appduct out of your release builds](/appduct/guides/build-variants/), and verify it. diff --git a/website/src/content/docs/start/react-native.mdx b/website/src/content/docs/start/react-native.mdx new file mode 100644 index 00000000..e4a549a3 --- /dev/null +++ b/website/src/content/docs/start/react-native.mdx @@ -0,0 +1,180 @@ +--- +title: React Native setup +description: Add Appduct to an Expo or bare React Native app, register tools, and connect it to the CLI. +sidebar: + order: 3 +--- + +import { Steps, Tabs, TabItem } from '@astrojs/starlight/components'; + +This page sets up `@appduct/react-native` in an Expo or bare React Native app. When you're done, the CLI and your agents can call the tools your app registers. For the shortest version, see the [Quick start](/appduct/start/quick-start/). + +**Requirements** + +- React Native with the New Architecture, on iOS 15.1+ and Android. +- A development build (Expo) or a bare React Native app. Expo Go can't load native code, so Appduct is inactive there. +- The `appduct` CLI on your computer: `npm install -g appduct` (Node 20 or newer). + +You don't need keys, certificates, or a config plugin for a first run, in any build type. + +## Set up the app + + + +1. Install the library and a schema library: + + + + ```bash + npm install @appduct/react-native zod + ``` + + + ```bash + pnpm add @appduct/react-native zod + ``` + + + ```bash + yarn add @appduct/react-native zod + ``` + + + + Any schema library works. Zod 4 needs no extra setup; for others, see [Choose a schema form](/appduct/guides/writing-tools/#choose-a-schema-form). + +2. Give the app a deep-link scheme. Appduct connects by opening a link like `myapp:///?appduct=…` in your app. + + + + Set `expo.scheme` in `app.json`: + + ```json title="app.json" + { + "expo": { + "scheme": "myapp" + } + } + ``` + + If you use a dynamic `app.config.js` or `app.config.ts`, the CLI can't read it (it never runs project code). Record the scheme with `appduct init --scheme myapp` in step 5. + + + Declare the scheme on both platforms, and set up React Native's [Linking](https://reactnative.dev/docs/linking) so the app receives incoming URLs: + + - **iOS:** add the scheme under `CFBundleURLTypes` in `Info.plist` (Xcode: target → Info → URL Types). + - **Android:** add an intent filter with `android.intent.action.VIEW` and `` to your main activity in `AndroidManifest.xml`. + + The CLI finds the scheme in these files automatically when you run it from the project root. + + + +3. Import Appduct once, at the top of your app's entry file: + + ```ts + import "@appduct/react-native/auto"; + ``` + + This import listens for the connection link and restores the session after a reload. It's the only part of the library that does anything on import. + + To control when it runs, for example only in development builds, `require()` it instead: + + ```ts + if (__DEV__) { + require("@appduct/react-native/auto"); + } + ``` + +4. Register a tool: + + ```tsx + import { useAppductTool } from "@appduct/react-native"; + import { z } from "zod"; + + export function AppductTools() { + useAppductTool({ + name: "sum", + description: "Add two numbers.", + inputSchema: z.object({ a: z.number(), b: z.number() }), + outputSchema: z.object({ total: z.number() }), + handler: async ({ a, b }) => ({ total: a + b }), + }); + + return null; + } + ``` + + Mount it near the root of your app. A tool can be called only while its component is mounted. To register outside React, use [`registerTool`](/appduct/reference/react-native-api/#registertool). [Writing tools](/appduct/guides/writing-tools/) covers schemas, timeouts, and groups. + +5. In your app's root directory, record the scheme and app ids: + + ```bash + appduct init --ios-app-id com.example.shop --android-app-id com.example.shop + ``` + + This writes `.appduct/config.json`, which you commit, and prints an MCP config entry for this app. The app ids are your iOS bundle id and Android package name; the CLI needs them to open links on Android and on physical iPhones. Add `--scheme myapp` if the CLI can't find your scheme. + +6. Rebuild the app, so the native module is included: + + + + ```bash + npx expo run:ios + # or + npx expo run:android + ``` + + + Install pods (`cd ios && pod install`), then build and run the app as usual. + + + + + +## Connect and check it works + +Run these from your app's root directory: + +```bash +appduct link --open ios-sim # a booted iOS Simulator +appduct link --open android # an Android emulator or USB device +appduct link --qr # a physical device: scan the QR code with its camera +``` + +Then: + +```bash +appduct tools +appduct invoke sum --input '{"a":2,"b":3}' +``` + +A physical device must be on the same local network as your computer. For every way to connect, see [Connect a device](/appduct/guides/cli/#connect-a-device). + +Once connected, the session survives Metro reloads, backgrounding, and short network drops. If the app process is killed, connect again with a new link. + +## What's in each build + +By default, Appduct's native code is in **debug** builds only. In a release build the library is inactive: every function still exists, but does nothing and never throws. To ship Appduct in an internal release build, or to strip its JavaScript too, see [Build variants](/appduct/guides/build-variants/). + +With no configuration, a build trusts the computer whose link it opened, for that session. Before you give a build to anyone outside your team, [pin it to your key](/appduct/guides/security/#pin-a-build-to-your-key). + +## Handle links yourself + +If your app handles incoming links itself (custom routing, an in-app QR scanner), you can skip `/auto` and connect manually with [`parseBootstrapUrl` and `connect`](/appduct/reference/react-native-api/#connect). Call `restoreSession()` once at startup, before your own link handling. Without it, every Metro reload drops the session. + +## Troubleshooting + +**`appduct tools` fails with `no_session`.** No device has connected yet. Run `appduct ls` to see sessions, then connect with `appduct link`. + +**The link opens the app, but it never connects.** +- Check that the app imports `@appduct/react-native/auto`, or calls `connect()` itself. +- You're in Expo Go or a release build, where Appduct is inactive. Use a development build. +- On a physical device, the phone must reach your computer on the local network. By default, Appduct accepts only local network addresses. + +**Android shows an "Open with" chooser, or nothing happens.** More than one installed app declares your scheme. Pass `--app-id` with your package name, or record it with `appduct init --android-app-id`. + +**`appduct link` reports conflicting schemes.** Your `ios/` and `android/` projects declare different schemes. Pass `--scheme`, or record one with `appduct init --scheme`. + +**`registerTool` throws in development.** The schema can't describe itself to agents (for example, Zod 3 or plain Valibot on its own), or the tool name or group is malformed. The error says what to fix. See [Writing tools](/appduct/guides/writing-tools/). + +**`connect()` rejects with `appduct_disabled`.** The build has no Appduct native code: it's a release build, Expo Go, or Appduct was excluded. See [Build variants](/appduct/guides/build-variants/). diff --git a/website/src/fonts/Switzer-Light.woff2 b/website/src/fonts/Switzer-Light.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..1f4ee2a65b97c15385de4407f9b52b93864c516b GIT binary patch literal 17932 zcmY&Dkkwb!n_CG`Q zuUCQzh6Dhy1CxS8LW2^5#nMB>NZ{Dki_h4uqs8TKz#BQg``pX4Fg@5oNGhBpPr)xl zIsztWa|EBhzkTKAm`p%k0VB?;#S+*y+%7ZMiB`bfo@*el;0$5_E-Z z65NP|l1M5wt{1uapHoiRojJ#BG|BDr_m5h%_B{DU-P75tzSH=L-P~xS(K^)d5+F4q z7zG6;iL!wa`5c`Y`ZUn^jys1$_`Uh>hSNL~;OR2V&aP+kU7b~G)OQ;hHR2#TC6M1E z-^o*`S(K_)CNh|(9u}cbi~0nf?kJyS-lZ&x7pV78M%coTM4exH3< zxze%fXRrEkn7Z>T+g2GmW3*isTh5>%oOV)}X!`BP`~?1xNHwsT)|9^a#=!IfC2-h4 zWHEG>Q*F0x7fo6_Z7w;xY?9i%<85q~KjkU1S|n)kvt^<4_LIb#d)|(5*WQmE-cQu> z$PD?^nIpe|)i5K9GWP2O55;=jI^^)mW6u*bGC_l4FrFber3X$Ino|MjR+*cjUjpH3j2DVoJ7L! zRK+hks8$F7jYAX>DQs>o^$6Yb+YCb5QF@daO{P;0uB~h>z%@&9oq=EV_I*gJ`87)o zDuEaU`wh=rsnPUS0-8oO2JOtdltFr+BU)})P?L zAcya;>%FwR=j%KG2yy33onhy~6jJa4q&W|%kZ+N7RVYsoK+Mj^ORAxpLmtWHc(;+&?t9=S8;j#Ww&N>=Le9HCGf>$(vm8>z@$$>U^fTh0 zDEU^Yg|u}k0zrKmhv`Hhs2tl^P*vcuQHQcX~Y=ZW}q(Fz+nfFcK7v82#7^r;a-B9|3P<}uk^xM_EdgLCEU{PggkkZ8c52vZ@KXX?&E zZYhVeH7|HFVawkHl57F3ezqxdZp?;yedtuon?T2{=f!VE&9T zp$%NXPhh4wRntUdH0-S2hT6vZ@9|{Tj0vP;>bo{P$am=Qr#(^$(>qk>vHGnM>qWRv z-$|BTOJluMLYeqK7V}Ch00Lyfdb|v~`&Q1w_)=sAgFK% z=YK_@pvgCfP{qZL`{e& zXx5jcI&~DIlO7rU*YU`zY_4#!mH)eZ#*aP;^gg|l_I^K-SW1_i-^oS}Ce&G$)&ej3 zz>BG?iIoWzr{p>LX3CJoOLh$AaepB|9!5KOdNz8)&^+wTn#Y(XW2=`oJKl8%PFDiQ0>3wpWERCLvt;0AaU|0-64g9zkaMY4v`Ke-ETT9 z(f8W^wMsTPz6)6r_aMc+CoFsd2T6=))&WEOIk+HFkJ8 zdOLi6A0VMTY;sYr;AB~+By|N9B{?wF#)a9L1u2}G=&EcVaM=FNSW!yYe|-Dvk8M>@ z5gK^JI(YmNC1kcBuJo7*d5}~AODcPl+f(-@^TZ#gi$gb`oUi;zcb?b>G_=V*(zw4a znNrGr4zFrr7pauXdH;F>dHRT{Kmgi}V=@r7th1G}^6?Ik(hfuvRxaBRp@j-r@B*$k zA^*`4?n)8!Ge`f~VFHtid1?N;Z;uq<39|E4IC{p+tkVuJD9rBQ`t4yS$!!Hq*(SNIGj=rJ8Oc z+rIO8>sW>qzwWq?e)4g8-^nj%QqKAZPoeQ5$$J;X-Z?X}V4Rq6ZIYxWtgte)07MZ9 zk$-R#7oHycHx~Wl!qS40qJAetWQ54;C~1kQ$>|9xN@|L#%If}5md2?lC@;2WgvB6I zz{K?z$+HG44>_iQYCnE2p!}iqRYXJ!b=_kIPLy@RrS#*7f}s9~t9UF#?v*(nqy#*A zV3ac<+jC`ok2gHuI@at}k3R?mJg&{3Kv>04Nr_R~t(M&Htrbnnx7k#XIDL5B3Fs() zSd*Q8>{2Zmra{^$XbryWUw5-lnzc+0)c;J+lF734(4obdTIuFyOJQ6fWxlqyOmcFu z=6(5bw8^Le*DjC}lZW`wNISGp#+)UVc2XayLWx>VeT+2?N~)C*JArx($MO*%+22;WN@^3-ea`ztxbTq;O{D7HfUqU_wRmUh4SXbW-pv>cGnjxG$?%A zPr`}v5uCM_Pd?`H2JE^U9^QcFtLR^5I|iLeZ@*6u>e3IIs_VGgW~V61Du(<6LZVu( zTT;cpd5T@>y}Vqm?L*KW-vfO7n~t-J0Jc(j^7G!xSc|Pz<>=@LJ84X(V78+XS;`~8 z)m%ouY*l?)(Go0g{?vs#%Q;J~ScO{ic=>K0+p-z%2R^b`##Y*|huZs*A|FDd(3lBLGM{G%9;sfW8 zQK`cNG}NR-Wubq=iRKb3Q_kh_0S>lV{OTe5!q}T%)XgjJ8Xo3-VN?XaO zp_6i0I+ND))NXt26c)|zvc$%4{4wxe7+0L>btuaA{X%|mC4}H1&mhCJJR%xwncAe= zH39!6E%qp^jM)PU;~)lw3caLdRyj^#7qT&>lO(e>F)>k*s3b)N0Pq6*-VNWll9aj7 ze)k&utN-u;IrGBVvhE9n;)unA?30dH5Rr&Hsq}A|fKBMTtsXh^39$6^1bz;E;{#V>azPQWY9l_U@m;D;zI%`F3&_pbOpP<0+2 zIubFfMbIxoevzKlBY22rkk^U+$bs{LK{y? zF)WobrZ7J2hIH{3Dwd?P2~hDehCmnxxS{C=q19Ut@s^Atsk0g9??< z(}<5z72`r&000LajV_?iZ}F4*MK_ccFphH%laU4#Z$xY+RjA7+A>NS1|K$wDjs=O} z(adtnA-(IzBG2k)&uaHqA`<#N&c6eVH7q(2?b8aAId@8<;=1_Cdfll_6{;kRYXo2% zsi&hw>S?C@{LK&JM4;GA;XhQG4l9rR347vu zfT86qiHM1b$LlIWJTzVZDaEs)JlYT;L4g4PLLwp}e^6k5Gtt_$O%s^P8UnC@njcV7 z2C$L-OpM?|Jujm>{5sp$gIB*&32%13Qu0HDQ!VaOs7TKW-7mM3Fx*1BXuN*8+YL&R z$fp_8b@}qMmd;PFeJl7^F9R>1x+!a?#xHqLfdnHrd)8m;9J&BljT}&35t) zYrIhmEDM0fdkg&~M{|LwdqB<5%HsL@Re_kjBh^2{(Lg`ewiWj%=ut|*9jJFTcvU{% zoN?Mne)1O82Py657MmuUFnOewsp2u#$njMs%JFdRsEsj&gKOK2%*(uFE~ZDj4FYYI zxiG`p4PH;5vZ|i6ay+=~AvUSR?SWQJmIG2yE&z*>=Ro=ve==~GZyAi@+{RI&mi4t# zp{Jz7%0!h7ReO$v9ple9_&2X!#=h)$WFLFr69vwI{-<4|?&Ig!A`Z}!R8^O24?;hiz}y?A0it~PJDRvcV9TDD}SQ*sbQ zQNff~R++A0`Tl4C2utwtbM&g0&mTQI^{R7Xlhjqz6jha%XBL3Z&k*`WmDt7)WpN4B z2c$z$p}T(@&XGP>@2O7j@0k5E*L)43^BgzWG~JdC?%S6196s?`fDGf88ZH~jB4LLL z`hg~k$G>YR{|^YFIeWf)P6TkuxctwgH^6aLP9Qh=)sZ{4U>sa8ISX&lKkglSx< z7V%H_&+|SMC$jEw(?41~Zr@9j;j*7CRd}DLIFC@3$E2C?uKzA4?hn+k?ukT*6mfl9+^)9PeiAxz9=y_M=;Q;`7cK~Ma zt&FaYj!h!{=falCI8cBwas2^mm#Um~$8yyqc;SLoqZS{{tG1L(evt~d z5aN9)=2`MtYyv&hQ$Fd4l8nA5i>tm!V}jo+&^ACG2%r!=M*52cZ2RjjvYK35UPIm5A>43$kFEFEO7GODZ{3e5oUfkEBu4Re zs?-r&en1j{k#^@G`CAe~0RZ@?a6rEdS8AwK zs;5l)jbzEWnr3KiY;MNyYlht7xU)Nj>)4yOGcx-_aGrZ%MAN)1)7L&6+b|5YJNLc9 zIo@@BDFEK1>th5x=sOtTYT1Vj$Svrn3_IP{QP+l#10FR)XuN99LAgN4zR}oHH|mxh zT{wy)?b#w0{2yX5`=k3*0)FRH>-U{TU-*y{v{3ui@YX+g?rF>_)VdwrNW4p`QLX8m$+y-k{h^iN`5Ax?F7R$FVbkp^=^||Mo=kh zg1xS{`{5WAdI1B4q->Uw2yxx9^u6Fl>q!FJsB|TLhc5*`!{qgJeXFSbb!y{HPmmE4 z223?@b6U-A8ELQLzhv?XfJ<@WXk=pv0Y%){Fn${w8|r>4NJ=y--Rn}`jd2aCcvyzQ zy_~{*$3D}XNW!EA2m_Zt9KU7WMhrZ25i-WX*(rj)Pbm+y$vVtOf%QT*DnDLk#QhrU zzx-TvN$Q1~YXsn0>V1qnuU;Gg4lsbabtb?nFd@$AK;3Hr-(whFYJe}=v0wlyFeEM~ zBKbm_)*RK~gAu{RgC_g>@k-{}_3)<`Is&>M7@~v$#MDkZtGSl)T9qr4bxZOR&I`Hm z=*rZ}Z{rp}+J#+ttTWgjPf1q=UibLRz5qeOb+M2#*a9+H+CLa?&QU^}ExuEGJ+Kvk zmewC~yY2b-RlNdGgn+fdX!nNx&n|+eASaP;cc0o{qhH=H_b10>IT-w{k0Rfx518MW zKCpaM9+5seFPzRFpD!7=DEsk_Z=9yMo+e%kHxlm>_Y#j1UlMnrw~)7#r-~n))dhB1 zz|YN(w3{E^nQS<~!2My?l1ur3lU|KCGRGF)Eawe9E+CS*BmgQMkI}sbLM#rY}NPn2bA7-2jThkkkOqQ|m zvh+UH(9=pJ;{Qmb(YD&3J8&N|EyfZV^PNTwMJ^Oe*(ZCvO>kJ`iK1&8w4%9cn^n37 zf8q$UUd0lN&!T%SgaTTe+ynGe`iRHnx$MnbE=T}nxDfQp7o38v@SRQ&OlZ_xzcHaH zr6r=>2_>@=veppBmvec@f(*YV{2c1T7M;A@EySe@B;+9<$v9}@RH(3sD zXGIl@e*sM9P~5sVhtYSJ$X3|f*1EuFoh zKu*P`t4w!SLM}I!vRM`SXj_p(B0w-)&zR$gu!0th zTqEiBJc|)&G0v0GXq{EFc&1()#`tf8VDBR)ex1Ttzz8`Tuaya1H&Swxrjk8OnFmi0 zCa77=n=;!gah|F^S)87W5+x_w<9Rk*s~IUh28X8Kjfq(vasild^F5)q)9>H*PeINh90Bd6c%~q6_4L5<-V9}tQ8^CvIJ%|!Eoa$Bi78P~C&Mg^ zCwT~A_QB%7s*uZA__&qzp;gp^1s=#v5*AT_H@y?68onmaPP;*ZeGm$4o1q$D{^F?sKrcGPW9- zmz!C*j$WKs4WjG1D8@0RbRj62^f8sb_alx*GE=#D|15RYt&Aym!rW z<0pf(mKAc%cQBoD9FzxW=A#HT|RS4@(3EIl!g%-Zb_S_Yk|MwHx z6Z-SL5!j@iX}#oK&(~Vq4t)Tb?F*sUd~cm$YVd6W)OOQYvH^eg<_r4 zqxyY$5wXMy8s!apq86$Wd3Iu_G~4A>Iwmuv7*s3-f+|C`Oog?}SRv!8qFO?+6})(0 zS~W%*|GXSdGqrqX}f@gl#DejiJ;7#k)1rZ zkr9$$DjbiOk&|a;L)kRa(WZ}+nn+6bNFVYCncxZ+p$U8AiI)Tg$APapd}L%rvd~s+ z;p$|S*sc~GrDCbpfv+;dXjw-4ki*#Cbst2wO$%e|jGOYCCSjCTFeh6=6(Hz8wa(5j zXeR`^z$6$<9DcC~i@5EsWxu{&S~IRE1;zbQb5kxlf?7*?lI?u2CbwIEuFEo7zUSk~ zkLc!hPU(cKgRikMBRe%J@{?|=EU~YK8b+yG)4LdKmMD_MtK4zD*3ly46jYi_-}Xl_ z%Y8IogVAydw|>T zRqX5D6ef)RMzW?g#m;NJ?ud}5u8Y;C{S@VGG=)-iQO~*vK`FF zJ06A$VibP{wLU4Lt!5Cn%?nVsySiDKr$P=4)VkEwh+HkMCN$-&i42B6zFKZt`r?^< zx0Q9RBF(~QuT&*)%S6anq}|t_PbS5wf+we1hIG4^#;#K~UtHLMhO3w<@DAwy9=`0+ zDPF#M*?Qcddk(HoMSWpfVq3H8B9~$IH71%8#;c$IBBQ7+@p%)<3|7SkaZFOXZXABM zo&jO)@q=*>B6)^{x#n*+aWxYVYO<~nnnN(+Dp`5(<%Lkq@R9wI^vX9JQXHXFfAD-l zwx(6~u!rBDpA1jpv?EAw zjD0xa2e(eT^~((2$b1p0b;0rl*7brA7TqA8C)Q*o9bU;%0a8SoYO;5Wsz6dI3-(-j zuKkm&XHg0@pBWly?c{aGW1NBjvW2B&1cU{GA_27g1_Xi5y_e$TH93y-;&Md;LFocw z_HIfvyM5V&29WvXD=eh7uD1k@yA57{sp z1AhMd6x5L=p&-_e17rTzxpKTQ^N(V|+pW?=iV^i-8`+Mto0OrxAkxA{37@?|7PIVU z{}Z$rB0jF^A&n|Vzstm+0<^GcNy*yVVxk{KDPgb>{6|RV`P7TMVZ z>a^_2rCG7OmO-S?yhqYnT{qx_-)w$HV7}Q!qA{eK=5p|a&Ie~l*;B&0U~S({

2q zW_QJC<}%d9Uo(;ho^i&U@LtfS9uZEP1=thq|Dj@Zk=9)T;%fH+ESMslOKgDu>=q}c zG+K-iD{e-C`lQ@b9dzVNCGHkqwT3L%bsrKE>%pb;%tpiwZ*!MW9O#g#ilI~2>U}IY zunJ_QOhvn?K1|?Ef+Ps@4qo?iyY9*&BZ&+o;{oxl&Oml;FA~Bwa&|(o+gyRph~(m} zWQVR<)50|5NW)(5(L7-vtyKmkiDr_av!-v50fvz8u6@NUGEsyFN5uA>jA}M6!!N{$ zG)FxvB zBl>KZ%ctt4DK216MLxZ$Z9vSoBvT+yhY9D6*8@&6yYuT`m2CM6ZvervOyQ8lzaD}u z$4Afg$YVm+bQCptlsi7ZgP8MR3HZje`wf%C_n_ZDYO( zs8@TCI!5YS6U-pFOZZqrCYrN-aUrJjL@mhWag5g^)VEQ3$xjqiz(0Os&iqbnlujqjdQM z8xkwB=4hHF-TzfgJj~O{@`RIFEhF~RfCLqnokhAAhuX$dajk~-cl*G9l- zeKOk;q5DDiM%UY|qzyBraS&ELQ#R1rM5wh%sMOM}5vtddUGp&8r%|ZrNjrIK$VQ5v zw3#-{dfoPgi6*~%{M+a2v>74rPD@yZ>(aD@Db%<)3DIB%%7m;#qXAu)CR+5i`2@q&JeOxj8WU<&S=MmVz zMI`V;@Axr4uHxatbo>nX;y*OX z3q0`O`fdlMnZaY=f}&>Skj27K8@&<)QL<5$<5L+FVRX*>c(MtVA%Y)zMiDNO<<43% zLMMu=XhZhEf>0dXZORu~;WsRwwLP5)8oQ|l>Gwv0I%~!J9nE`Cn!l`sG5pk@H)odB zYqIDNbrczWy2EHlQWV}==~<0kS@i=fLTCcd_#D=~A6B*mRgZz38H|`Iq;GDF?xgLI zsiDY1^~4sl{AtZRAP^@wO;*hQdt_xuvt4U&G98qPzqz_zuhW3gD!Mk^!piv@e<1b_ z%hib}iwKSJlo{wnW0rgBHK?irG!oVYzmSr+??buEiiYu!7Lp=`Y9q>Hb35X&oopxh;9bn9kCknBs|=ZEYlv`SYm zrZv{u_zMEE#o2;6w=`*LWY8i^TurV2RK@7B&0wsIf*KAuJGm#AonFB z@)ZqT8H(Oe3ppu3eNtlfcetpnRUH*oXKYCf<+iMBP_-U)sPYn!+25zB@%Gl7&7Mh6 zA!?MB1j|lI)bIw0GP2diSY@{%OB;duDHZM=C&|{Z3+b_6`+7ELMu^+q`jr8K!{J@; z%lF4?_s)M6M%`t)A9!~~Q>MAPE1$mu=l)hpret`bz#j*Vwcg2LbK_B*BL-2PoC@?o z4`;J$h`hG(r8$%GTmFFv^$`teICOx2?`07evRyhH7=0UmKL8DUyd8jTj(bYt80R?s)C3a&*bJ} ziZ>m5?QUcm)9!wG!PR-bk)7S>eEa|lvbzFeo+Djw?#vzhsm7(QUU5M4lQmozz)KV% zxfM4VG67w$v06c7B1uy#q}S=xLuF8rvtIwifvq1nJ<0NrUna#L=XgMIKqj@@95;ZF z`1ndPH5-c5=BE{bq9EiBI71LkWYdca*hfMIAuqSBVi%K*?!g(s?Ml?qy^BvKjfxeW zpNlw6iZnC+-KCF{S5P>iExErCK>5DCVsoMIrf|K@<*TU8)76xv9jXm$rrx=6v1CsK zeApx&I+5xqLV4ha)2@uqkE+Y%-aPA;!r%7lN@bg~C~ub4;WhnxrNGBHB<5{ap!_Sh zrkUU4(dq%}6YRABTjt5DIjOby@UK27vf( zhXYqfu=yIp1Gj|q`?PN+#W)rv5Nk~1p1X9>2HHzKS?Ob69s|L^oHk@3FEt@UM_n93;PSfUdX#_sJ zYH;LvhKZ|Q5OxgC55|kNhiu&hGPO z%A`oC;@9(TA;$!fuaq#A6sU4Fgt|Wa1aSj`h*;uIdvWDFwak`RXv10FyO>*HA0HgH zBjiITQ^>N~bmv)B03Q)|9zNqWI^YU?M8{dHvrHRXUZf=+{4jY8y_9L8< z)9Tg8&B1`0>{Uk+(v3q5X#ZjJ?oj=zFoj7o0IJq;hu|IEK&-b_8n8pIYedt}uh`6nlDt%p8rsxN{kSlHNN z6#4X?U2*1kv{Hrk0BCm4*3g7&+Iz>(8=4kWw3qzlTx>i`g0cbSG#y(!U{<(4(p?1* z^L^J+5f*ZJGOM%*DZS@lpvW>qs2FiDu!g}F%qnoDfl6_z+^zW0XQx#^fkh%PaaoJu z?5u^F85z&Zh^41w3;I+TorRG12>lmFtdEE4x93nAFOA^1)O=@A}g)7g#?~n zJy{WXVYUNg1UJV^LwxUwE3D-5$rV%BP_{yy7jgjbgKN>^48rxz)`~rd=+*%YsGvut zNrLdxa2f$Ly^=dP_z)`bNf;UqfA3}Yes0d#IdIS}LAnC8{j;d0Z9W5J1rx$R!B(>z zw18G*bAA!xVs^$nW59KYTPG$=!ep$|-J=p|btLmkmO~v1<}t?TOro{fqD!JQr~iNq z*`@SXlglUp5`m42K>Qi`-8SPC0+tSeQ1j! zxrb6XiLs8v5W5zjqt-&RS+sWq;Dcy$HSYHubSr;)r`}(=C5wp8k#N=ri%16jR{j;F zpd?~)QiL2FtpULJ?ⅈ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

>b3f&h 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

CVpkoq1)ur2&B9 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 literal 0 HcmV?d00001 diff --git a/website/src/fonts/Switzer-Regular.woff2 b/website/src/fonts/Switzer-Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..df335d6cf7bf1d8fc0d7fd3e16f162e47d2870fc GIT binary patch literal 16728 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 b*6JBc+;1fr3!VF_IK=?*qv)87=o.md` (e.g. /appduct/start/quick-start.md), +// so agents can read the source without scraping HTML. The body is the authored MDX: import +// lines stay in, and component tags such as appear as written. +import type { APIRoute, GetStaticPaths } from 'astro'; +import { getCollection, type CollectionEntry } from 'astro:content'; + +export const getStaticPaths = (async () => { + const entries = await getCollection('docs', ({ id }) => id !== 'index' && id !== '404'); + return entries.map((entry) => ({ params: { slug: entry.id }, props: { entry } })); +}) satisfies GetStaticPaths; + +export const GET: APIRoute<{ entry: CollectionEntry<'docs'> }> = ({ props }) => { + const { title, description } = props.entry.data; + const header = [`# ${title}`, description ? `> ${description}` : ''].filter(Boolean).join('\n\n'); + const body = (props.entry.body ?? '').trim(); + return new Response(`${header}\n\n${body}\n`, { + headers: { 'Content-Type': 'text/markdown; charset=utf-8' }, + }); +}; diff --git a/website/src/pages/index.astro b/website/src/pages/index.astro new file mode 100644 index 00000000..d1aa2fce --- /dev/null +++ b/website/src/pages/index.astro @@ -0,0 +1,542 @@ +--- +// The landing page. Rendered through StarlightPage so the header, search, theme toggle and +// footer stay identical to the docs; the hero comes from the Hero override, the rest is here. +import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro'; +import { Code } from '@astrojs/starlight/components'; + +const base = import.meta.env.BASE_URL.replace(/\/$/, ''); +const docs = (slug: string) => `${base}/${slug}/`; +const repo = 'https://github.com/callstackincubator/appduct'; + +const toolCode = `import { useAppductTool } from "@appduct/react-native"; +import { z } from "zod"; + +useAppductTool({ + name: "seed_cart", + description: "Fill the cart with test items.", + inputSchema: z.object({ items: z.number() }), + handler: async ({ items }) => ({ added: items }), +});`; + +const invokeCode = `appduct invoke seed_cart --input '{"items":3}'`; + +const testCode = `import { connect } from "appduct/client"; + +const app = await connect(); +await app.call("seed_cart", { items: 3 });`; + +const mcpCode = `{ + "mcpServers": { + "appduct": { "command": "appduct", "args": ["mcp"] } + } +}`; + +const why = [ + { + title: 'Tests stop tapping through setup.', + body: 'Call login(userId) or seedCart(items) directly and jump to the part you are actually testing. Faster runs, less flakiness.', + }, + { + title: 'Agents can drive your app.', + body: 'One line of MCP config and the agent can find and call your app’s functions. Flip a flag, open a screen, check some state.', + }, + { + title: 'No hidden debug UI.', + body: 'No secret gestures, no admin panel behind a long-press. Only the functions you registered are reachable.', + }, + { + title: 'A dev loop that holds.', + body: 'Reloads, backgrounding, flaky Wi-Fi — the session survives and picks back up. One service, every device you plug in.', + }, +]; + +const platforms = [ + { + name: 'React Native', + pkg: '@appduct/react-native', + body: 'iOS 15.1+ and Android on the New Architecture. Expo dev builds or bare apps.', + href: docs('start/react-native'), + }, + { + name: 'iOS', + pkg: 'AppductCore', + body: 'Swift, iOS 15.1+. Swift Package Manager or CocoaPods. Nothing from React Native.', + href: docs('start/ios'), + }, + { + name: 'Android', + pkg: 'com.callstack.appduct:core', + body: 'Kotlin, Android 7.0 (API 24)+. Maven Central, with a no-op artifact for release.', + href: docs('start/android'), + }, +]; +--- + +reach into your running app.', + tagline: + 'Appduct lets a terminal, a test runner, or an AI agent call functions inside your app while it’s running. You pick what’s callable. Nothing else is reachable.', + actions: [ + { text: 'Quick start', link: docs('start/quick-start'), variant: 'primary', icon: 'right-arrow' }, + { text: 'GitHub', link: repo, variant: 'secondary', icon: 'external' }, + ], + }, + }} + hasSidebar={false} +> +

+

+ npm install -g appduct +

+ + +
+

Why you’d want this

+

+ Skip the setup. Test the part that matters. +

+
+ { + why.map(({ title, body }) => ( +
+

{title}

+

{body}

+
+ )) + } +
+
+ + +
+

What it looks like

+

+ Register a function. Call it from anywhere. +

+
+
+

01 In your app

+ +

+ Registers once per mount. The handler always sees the latest state it closes over. Native apps + register the same way from Swift or Kotlin. +

+
+
+

02 From your terminal

+ +

03 Or from a test

+ +

+ The CLI reads your deep-link scheme from app.json, Info.plist, or{' '} + build.gradle. There is nothing to configure. +

+
+
+
+ + +
+

Build variants

+

Nothing ships in your release build.

+
+

Debug builds only, by default.

+

Release builds compile it out, not just switch it off.

+

Opt in per build for TestFlight or internal tracks.

+
+ Build variants +
+ + +
+

Use it with an agent

+

+ One line of config. Your app becomes a toolset. +

+
+
+ +
+
+
+ MCP + Claude Code, Cursor, or any MCP client. The agent lists your app’s tools, reads their schemas, and calls them. +
+
+ CLI + skill + For agents that work in a shell: npx skills add callstackincubator/appduct --skill appduct +
+
+ Trust + Encrypted connection. The app checks who is on the other end. Security model → +
+ Agents guide +
+
+
+ + +
+

Runs where your app runs

+

+ React Native. Or no React Native at all. +

+
+ { + platforms.map(({ name, pkg, body, href }) => ( + +

{name}

+ {pkg} +

{body}

+ + Set up + +
+ )) + } +
+
+ + +
+

+ Register one tool. See where it goes. +

+ +
+
+ + + diff --git a/website/src/styles/docs.css b/website/src/styles/docs.css new file mode 100644 index 00000000..9f6ef483 --- /dev/null +++ b/website/src/styles/docs.css @@ -0,0 +1,311 @@ +/* Docs-page styling on top of theme.css: typography, sidebar, and Starlight's built-in components. */ + +/* ---------- Page title and headings ---------- */ +h1#_top { + font-family: var(--cs-font-display); + font-weight: 400; + font-size: clamp(2.5rem, 1.6rem + 3vw, 3.75rem); + line-height: 1.02; + letter-spacing: -0.05em; + color: var(--sl-color-white); + margin-top: 1.5rem; +} + +.sl-markdown-content :is(h1, h2, h3, h4, h5, h6):not(:where(.not-content *)) { + font-weight: 400; + color: var(--sl-color-white); +} +.sl-markdown-content h2:not(:where(.not-content *)) { + letter-spacing: -0.04em; + line-height: 1.1; +} +/* Hairline over each section, drawn on the anchor wrapper (the h2 itself is inline). */ +.sl-markdown-content .sl-heading-wrapper.level-h2 { + margin-top: 2.5em; + padding-top: 1.75rem; + border-top: 1px solid var(--cs-line); +} +.sl-markdown-content h3:not(:where(.not-content *)) { + letter-spacing: -0.03em; + line-height: 1.15; +} +.sl-markdown-content h4:not(:where(.not-content *)) { + letter-spacing: -0.02em; +} +.sl-markdown-content :is(h5, h6):not(:where(.not-content *)) { + font-family: var(--cs-font-mono); + font-size: 0.8125rem; + letter-spacing: 0.055em; + text-transform: uppercase; + color: var(--cs-muted); +} + +.sl-markdown-content :is(strong, b):not(:where(.not-content *)) { + font-weight: 500; + color: var(--sl-color-white); +} + +/* The page description, when Starlight renders a lede. */ +.sl-markdown-content > p:first-child:not(:where(.not-content *)) { + color: var(--sl-color-gray-2); +} + +/* Links: accent, hairline underline. */ +.sl-markdown-content a:not(:where(.not-content *)) { + color: var(--sl-color-text-accent); + text-decoration-thickness: 1px; + text-underline-offset: 0.2em; + text-decoration-color: color-mix(in srgb, currentColor 45%, transparent); +} +.sl-markdown-content a:not(:where(.not-content *)):hover { + text-decoration-color: currentColor; +} + +/* Inline code: mono on a faint wash with a hairline. */ +.sl-markdown-content :not(pre) > code:not(:where(.not-content *)) { + font-size: 0.875em; + padding: 0.1em 0.35em; + border: 1px solid var(--cs-line-soft); + background: var(--sl-color-bg-inline-code); + color: var(--sl-color-gray-1); +} + +/* Tables: hairline rows, mono uppercase header. */ +.sl-markdown-content table:not(:where(.not-content *)) { + border-collapse: collapse; +} +.sl-markdown-content :is(th, td):not(:where(.not-content *)) { + border: 0; + border-bottom: 1px solid var(--cs-line); + padding: 0.625rem 1rem 0.625rem 0; + background: transparent; +} +.sl-markdown-content th:not(:where(.not-content *)) { + font-family: var(--cs-font-mono); + font-size: 0.75rem; + font-weight: 400; + letter-spacing: 0.055em; + text-transform: uppercase; + color: var(--cs-muted); +} +.sl-markdown-content tr:nth-child(2n):not(:where(.not-content *)) { + background: transparent; +} + +.sl-markdown-content hr:not(:where(.not-content *)) { + border-top-color: var(--cs-line); +} + +/* Code blocks: the purple left rule from the deck's CodeBlock. */ +.expressive-code .frame pre { + border-inline-start: 3px solid var(--cs-purple) !important; +} +.expressive-code .frame .header { + gap: 0; +} +.expressive-code .frame.has-title .title, +.expressive-code .frame.is-terminal .title { + font-family: var(--cs-font-mono); + font-size: 0.75rem; + letter-spacing: 0.04em; +} + +/* ---------- Sidebar ---------- */ +.sidebar-content { + padding-top: 1.5rem; +} +.sidebar-content .top-level > li + li { + margin-top: 1.25rem; +} +.sidebar-content summary .group-label .large { + font-family: var(--cs-font-mono); + font-size: 0.75rem; + font-weight: 400; + letter-spacing: 0.055em; + text-transform: uppercase; + color: var(--cs-muted); +} +.sidebar-content ul ul li { + border-inline-start-color: var(--cs-line); +} +.sidebar-content a { + color: var(--sl-color-gray-2); + font-size: 0.9375rem; +} +.sidebar-content a:hover { + color: var(--sl-color-white); +} +.sidebar-content a[aria-current='page'], +.sidebar-content a[aria-current='page']:hover, +.sidebar-content a[aria-current='page']:focus { + font-weight: 400; + color: var(--sl-color-white); + background: var(--cs-wash); + box-shadow: inset 2px 0 0 var(--cs-purple); +} +.sidebar-content ul ul li:has(> a[aria-current='page']) { + border-inline-start-color: var(--cs-purple); +} + +/* ---------- Right-hand table of contents ---------- */ +starlight-toc h2, +mobile-starlight-toc .toggle { + font-family: var(--cs-font-mono); + font-size: 0.75rem !important; + font-weight: 400 !important; + letter-spacing: 0.055em; + text-transform: uppercase; + color: var(--cs-muted) !important; +} +starlight-toc a[aria-current='true'], +mobile-starlight-toc a[aria-current='true'] { + color: var(--sl-color-text-accent) !important; +} + +/* ---------- Asides ---------- */ +.starlight-aside { + border: 1px solid var(--cs-line); + border-inline-start: 3px solid var(--sl-color-asides-border, var(--cs-purple)); + background: var(--cs-wash); +} +.starlight-aside--note { + --sl-color-asides-border: var(--cs-purple); + --sl-color-asides-text-accent: var(--cs-accent); +} +.starlight-aside--tip { + --sl-color-asides-border: var(--sl-color-gray-3); + --sl-color-asides-text-accent: var(--sl-color-white); +} +.starlight-aside__title { + font-family: var(--cs-font-mono); + font-size: 0.75rem; + font-weight: 400; + letter-spacing: 0.055em; + text-transform: uppercase; +} + +/* ---------- Cards, link cards, link buttons, badges ---------- */ +.card { + border: 1px solid var(--cs-line) !important; + background: transparent !important; +} +.card .title { + font-weight: 400; + letter-spacing: -0.02em; +} +.card .icon { + border: 0 !important; + background: transparent !important; + color: var(--cs-accent) !important; +} + +.sl-link-card { + border: 1px solid var(--cs-line) !important; + background: transparent !important; + box-shadow: none !important; + transition: border-color 0.15s ease; +} +.sl-link-card:hover { + border-color: var(--cs-purple) !important; + background: var(--cs-wash) !important; +} +.sl-link-card .title { + font-weight: 400 !important; + letter-spacing: -0.02em; + color: var(--sl-color-white) !important; +} +.sl-link-card .icon { + color: var(--cs-accent) !important; +} + +.sl-link-button { + font-family: var(--cs-font-mono); + font-size: 0.8125rem !important; + letter-spacing: 0.055em; + text-transform: uppercase; +} +.sl-link-button.primary { + background: var(--cs-purple) !important; + border-color: var(--cs-purple) !important; + color: #ffffff !important; +} + +.sl-badge { + font-family: var(--cs-font-mono); + letter-spacing: 0.04em; + text-transform: uppercase; +} + +/* ---------- Tabs ---------- */ +starlight-tabs [role='tablist'] { + border-bottom: 1px solid var(--cs-line) !important; +} +starlight-tabs .tab { + --sl-tab-color-border: transparent !important; +} +starlight-tabs .tab:has([aria-selected='true']), +starlight-tabs [role='tab'][aria-selected='true'] { + --sl-tab-color-border: var(--cs-purple) !important; +} +starlight-tabs [role='tab'] { + font-family: var(--cs-font-mono); + font-size: 0.8125rem; + letter-spacing: 0.04em; + text-transform: uppercase; + color: var(--cs-muted) !important; +} +starlight-tabs [role='tab'][aria-selected='true'] { + color: var(--sl-color-white) !important; + font-weight: 400 !important; +} + +/* ---------- Steps ---------- */ +.sl-steps { + --bullet-size: 1.75rem; +} +.sl-steps > li::before { + font-family: var(--cs-font-mono); + font-weight: 400 !important; + background: transparent !important; + border: 1px solid var(--cs-purple); + color: var(--sl-color-white) !important; +} +.sl-steps > li::after { + background: var(--cs-line) !important; +} + +/* ---------- File tree ---------- */ +starlight-file-tree { + border: 1px solid var(--cs-line); + background: var(--cs-wash) !important; +} + +/* ---------- Footer: edit link, pagination ---------- */ +.meta { + font-family: var(--cs-font-mono); + font-size: 0.75rem !important; + letter-spacing: 0.04em; + text-transform: uppercase; +} +.pagination-links a { + border: 1px solid var(--cs-line) !important; + box-shadow: none !important; + transition: border-color 0.15s ease; +} +.pagination-links a:hover { + border-color: var(--cs-purple) !important; +} +.pagination-links a > span { + font-family: var(--cs-font-mono); + font-size: 0.75rem; + letter-spacing: 0.055em; + text-transform: uppercase; + color: var(--cs-muted); +} +.pagination-links .link-title { + font-family: var(--cs-font-display); + font-size: 1.375rem; + letter-spacing: -0.03em; + text-transform: none; + color: var(--sl-color-white); +} diff --git a/website/src/styles/theme.css b/website/src/styles/theme.css new file mode 100644 index 00000000..afa57497 --- /dev/null +++ b/website/src/styles/theme.css @@ -0,0 +1,239 @@ +/* + * Callstack theme for Starlight: black, white and one electric purple; light, tightly tracked + * grotesk headlines; uppercase mono metadata; square corners; 1px hairlines; no shadows. + * + * This file is unlayered, so it wins over Starlight's layered defaults. That also means every + * token overridden for dark mode (:root) must be overridden again for light mode, or the dark + * value would leak into light mode. + */ + +:root { + --cs-font-display: 'Switzer', Arial, sans-serif; + --cs-font-mono: 'Geist Mono', ui-monospace, monospace; + --cs-purple: #8232ff; + --cs-purple-muted: #e0ceff; + + --sl-font: var(--cs-font-display); + --sl-font-mono: var(--cs-font-mono); + --sl-line-height-headings: 1.1; + + --sl-shadow-sm: none; + --sl-shadow-md: none; + --sl-shadow-lg: none; +} + +/* ---------- Dark (default) ---------- */ +:root { + --cs-bg: #000000; + --cs-fg: #ffffff; + --cs-accent: #b789ff; + --cs-muted: #bcbac2; + --cs-line: #ffffff29; + --cs-line-soft: #ffffff17; + --cs-wash: #ffffff0a; + --cs-code-bg: #131116; + --cs-code-fg: #efedf5; + --cs-code-border: #ffffff26; + + --sl-color-white: #ffffff; + --sl-color-gray-1: #efedf5; + --sl-color-gray-2: #d6d4dc; + --sl-color-gray-3: #9d9aa5; + --sl-color-gray-4: #6b6873; + --sl-color-gray-5: #2c2a31; + --sl-color-gray-6: #121115; + --sl-color-gray-7: #0a090c; + --sl-color-black: #000000; + + --sl-color-accent-low: #25124a; + --sl-color-accent: #8232ff; + --sl-color-accent-high: #b789ff; + --sl-color-purple-low: #25124a; + --sl-color-purple: #8232ff; + --sl-color-purple-high: #d7bfff; + + --sl-color-text: #d6d4dc; + --sl-color-text-accent: #b789ff; + --sl-color-text-invert: #ffffff; + --sl-color-bg: #000000; + --sl-color-bg-nav: #000000; + --sl-color-bg-sidebar: #000000; + --sl-color-bg-inline-code: #17151b; + --sl-color-bg-accent: #8232ff; + --sl-color-hairline-light: #ffffff29; + --sl-color-hairline: #ffffff1f; + --sl-color-hairline-shade: #ffffff1f; + --sl-color-backdrop-overlay: #000000b3; +} + +/* ---------- Light ---------- */ +:root[data-theme='light'] { + --cs-bg: #ffffff; + --cs-fg: #000000; + --cs-accent: #8232ff; + --cs-muted: #646369; + --cs-line: #00000024; + --cs-line-soft: #00000014; + --cs-wash: #00000004; + --cs-code-bg: #f7f5fb; + --cs-code-fg: #29232f; + --cs-code-border: #ded7e8; + + --sl-color-white: #000000; + --sl-color-gray-1: #111014; + --sl-color-gray-2: #2b2a2f; + --sl-color-gray-3: #646369; + --sl-color-gray-4: #8e8c94; + --sl-color-gray-5: #d9d7de; + --sl-color-gray-6: #f1eff5; + --sl-color-gray-7: #f9f8fd; + --sl-color-black: #ffffff; + + --sl-color-accent-low: #ece2ff; + --sl-color-accent: #8232ff; + --sl-color-accent-high: #5b16d0; + --sl-color-purple-low: #ece2ff; + --sl-color-purple: #8232ff; + --sl-color-purple-high: #5b16d0; + + --sl-color-text: #2b2a2f; + --sl-color-text-accent: #8232ff; + --sl-color-text-invert: #ffffff; + --sl-color-bg: #ffffff; + --sl-color-bg-nav: #ffffff; + --sl-color-bg-sidebar: #ffffff; + --sl-color-bg-inline-code: #f3f0f8; + --sl-color-bg-accent: #8232ff; + --sl-color-hairline-light: #00000024; + --sl-color-hairline: #0000001a; + --sl-color-hairline-shade: #0000001a; + --sl-color-backdrop-overlay: #ffffffb3; +} + +/* ---------- Global ---------- */ + +/* Square corners everywhere — Starlight has no radius token, so this is the one blunt rule. */ +*, +*::before, +*::after { + border-radius: 0 !important; +} + +html { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body { + background-color: var(--cs-bg); +} + +::selection { + background: var(--cs-purple); + color: #ffffff; +} + +:focus-visible { + outline: 2px solid var(--cs-accent); + outline-offset: 2px; +} + +/* Header chrome: black bar, hairline under it, mono links on the right. */ +.header { + gap: 1.5rem; +} +.social-icons { + gap: 1.75rem !important; +} +.social-icons::after { + border-inline-end-color: var(--cs-line) !important; + height: 1rem !important; +} + +/* Theme select and search: mono, hairline, square. */ +starlight-theme-select label { + --sl-select-width: 7em !important; +} +starlight-theme-select select, +starlight-lang-select select { + font-family: var(--cs-font-mono); + font-size: 0.75rem; + letter-spacing: 0.04em; + text-transform: uppercase; +} + +site-search button[data-open-modal] { + border: 1px solid var(--cs-line) !important; + background: transparent !important; + font-family: var(--cs-font-mono); + font-size: 0.75rem; + letter-spacing: 0.04em; + text-transform: uppercase; + color: var(--cs-muted) !important; +} +site-search button[data-open-modal]:hover { + border-color: var(--cs-accent) !important; + color: var(--sl-color-white) !important; +} +site-search button[data-open-modal] kbd { + background: transparent !important; + border: 1px solid var(--cs-line); + font-family: var(--cs-font-mono); +} +site-search dialog { + border: 1px solid var(--cs-line) !important; + background: var(--cs-bg) !important; +} + +/* Buttons shared by the landing hero and CTAs. */ +.cs-button { + display: inline-flex; + align-items: center; + gap: 0.625rem; + padding: 0.875rem 1.375rem; + border: 1px solid var(--cs-line); + font-family: var(--cs-font-mono); + font-size: 0.8125rem; + letter-spacing: 0.055em; + text-transform: uppercase; + text-decoration: none; + color: var(--sl-color-white); + background: transparent; + transition: + background-color 0.15s ease, + border-color 0.15s ease, + color 0.15s ease; +} +.cs-button:hover { + border-color: var(--sl-color-white); +} +.cs-button--primary { + background: var(--cs-purple); + border-color: var(--cs-purple); + color: #ffffff; +} +.cs-button--primary:hover { + background: #6d1ff0; + border-color: #6d1ff0; + color: #ffffff; +} + +.cs-eyebrow { + margin: 0; + font-family: var(--cs-font-mono); + font-size: 0.8125rem; + line-height: 1.4; + letter-spacing: 0.055em; + text-transform: uppercase; + color: var(--cs-muted); +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + transition: none !important; + animation: none !important; + scroll-behavior: auto !important; + } +} diff --git a/website/tsconfig.json b/website/tsconfig.json new file mode 100644 index 00000000..8bf91d3b --- /dev/null +++ b/website/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "astro/tsconfigs/strict", + "include": [".astro/types.d.ts", "**/*"], + "exclude": ["dist"] +} From 45caa24db2d699fc32b938404b6721bce581a9ce Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Mon, 21 Sep 2026 16:07:31 +0200 Subject: [PATCH 2/5] docs(website): give installation its own sidebar section and add next steps --- website/README.md | 2 +- website/astro.config.mjs | 10 ++++++++-- website/llms-page-index.mjs | 1 + website/src/content/docs/guides/build-variants.mdx | 4 ++-- website/src/content/docs/guides/writing-tools.mdx | 2 +- .../src/content/docs/{start => install}/android.mdx | 13 ++++++++++--- website/src/content/docs/{start => install}/ios.mdx | 13 ++++++++++--- .../docs/{start => install}/react-native.mdx | 11 ++++++++++- .../src/content/docs/reference/react-native-api.md | 2 +- website/src/content/docs/start/introduction.mdx | 9 ++++++++- website/src/content/docs/start/playground.mdx | 2 +- website/src/content/docs/start/quick-start.mdx | 6 ++++-- website/src/pages/index.astro | 6 +++--- 13 files changed, 60 insertions(+), 21 deletions(-) rename website/src/content/docs/{start => install}/android.mdx (92%) rename website/src/content/docs/{start => install}/ios.mdx (92%) rename website/src/content/docs/{start => install}/react-native.mdx (93%) diff --git a/website/README.md b/website/README.md index cbe5e33f..5dd43b33 100644 --- a/website/README.md +++ b/website/README.md @@ -20,7 +20,7 @@ The build fails on a broken internal link between docs pages (checked by `starli | Path | What it is | | --- | --- | -| `src/content/docs/` | Docs pages, one `.md`/`.mdx` file per page. The folder decides the sidebar group (`start`, `guides`, `reference`); `sidebar.order` in the frontmatter decides the position. Link between pages with site URLs such as `/appduct/start/quick-start/`. | +| `src/content/docs/` | Docs pages, one `.md`/`.mdx` file per page. The folder decides the sidebar group (`start`, `install`, `guides`, `reference`); `sidebar.order` in the frontmatter decides the position. Link between pages with site URLs such as `/appduct/start/quick-start/`. | | `src/pages/index.astro` | The landing page. | | `src/pages/[...slug].md.ts` | Serves every docs page as raw Markdown at `.md`. | | `src/components/` | Starlight component overrides: header title and links, hero, footer, default dark theme. | diff --git a/website/astro.config.mjs b/website/astro.config.mjs index f7ab5f86..540201c3 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -57,6 +57,7 @@ export default defineConfig({ }, sidebar: [ { label: 'Start here', items: [{ autogenerate: { directory: 'start' } }] }, + { label: 'Installation', items: [{ autogenerate: { directory: 'install' } }] }, { label: 'Guides', items: [{ autogenerate: { directory: 'guides' } }] }, { label: 'Reference', items: [{ autogenerate: { directory: 'reference' } }] }, ], @@ -79,14 +80,19 @@ export default defineConfig({ '', llmsPageIndex({ site, base }), ].join('\n'), - promote: ['start/introduction', 'start/quick-start', 'start/**'], + promote: ['start/introduction', 'start/quick-start', 'start/**', 'install/**'], demote: ['reference/protocol', 'reference/architecture'], customSets: [ { label: 'Getting started', - description: 'installing Appduct and setting it up for React Native, iOS, or Android', + description: 'what Appduct is and the fastest way to try it', paths: ['start/**'], }, + { + label: 'Installation', + description: 'setting up Appduct for React Native, iOS, or Android', + paths: ['install/**'], + }, { label: 'Reference', description: 'CLI and React Native API reference, architecture, and wire protocol', diff --git a/website/llms-page-index.mjs b/website/llms-page-index.mjs index bbb7e181..61257c74 100644 --- a/website/llms-page-index.mjs +++ b/website/llms-page-index.mjs @@ -11,6 +11,7 @@ const docsDir = fileURLToPath(new URL('./src/content/docs/', import.meta.url)); /** Sidebar groups in display order: directory → label. */ const groups = [ ['start', 'Start here'], + ['install', 'Installation'], ['guides', 'Guides'], ['reference', 'Reference'], ]; diff --git a/website/src/content/docs/guides/build-variants.mdx b/website/src/content/docs/guides/build-variants.mdx index db61e338..fdd0c51e 100644 --- a/website/src/content/docs/guides/build-variants.mdx +++ b/website/src/content/docs/guides/build-variants.mdx @@ -119,9 +119,9 @@ To make sure a project never includes Appduct on a platform, regardless of envir Apps using Appduct without React Native get the same debug-only default through their dependency setup: -- **iOS with Swift Package Manager:** Debug builds get the real library; Release builds get a version that does nothing. Enable the `AlwaysEnabled` package trait to include it in Release. See [iOS setup](/appduct/start/ios/#ship-appduct-in-a-release-build). +- **iOS with Swift Package Manager:** Debug builds get the real library; Release builds get a version that does nothing. Enable the `AlwaysEnabled` package trait to include it in Release. See [iOS setup](/appduct/install/ios/#ship-appduct-in-a-release-build). - **iOS with CocoaPods:** `pod 'AppductCore', :configurations => ['Debug']`. Remove the restriction to include it everywhere. -- **Android:** `debugImplementation` of `core`, `releaseImplementation` of `core-noop`. Depend on `core` for a variant to include it. See [Android setup](/appduct/start/android/#ship-appduct-in-a-release-build). +- **Android:** `debugImplementation` of `core`, `releaseImplementation` of `core-noop`. Depend on `core` for a variant to include it. See [Android setup](/appduct/install/android/#ship-appduct-in-a-release-build). `APPDUCT_ENABLED` doesn't apply to these apps. diff --git a/website/src/content/docs/guides/writing-tools.mdx b/website/src/content/docs/guides/writing-tools.mdx index d2324d3e..289a0c83 100644 --- a/website/src/content/docs/guides/writing-tools.mdx +++ b/website/src/content/docs/guides/writing-tools.mdx @@ -5,7 +5,7 @@ sidebar: order: 3 --- -A tool is a named function your app registers, with a description and a schema for its arguments. The CLI, agents, and tests can call only the tools you register. This page covers React Native; the same ideas apply to [iOS](/appduct/start/ios/#register-tools-in-swift) and [Android](/appduct/start/android/#register-tools-in-kotlin), where schemas are plain JSON Schema. +A tool is a named function your app registers, with a description and a schema for its arguments. The CLI, agents, and tests can call only the tools you register. This page covers React Native; the same ideas apply to [iOS](/appduct/install/ios/#register-tools-in-swift) and [Android](/appduct/install/android/#register-tools-in-kotlin), where schemas are plain JSON Schema. ## Register a tool diff --git a/website/src/content/docs/start/android.mdx b/website/src/content/docs/install/android.mdx similarity index 92% rename from website/src/content/docs/start/android.mdx rename to website/src/content/docs/install/android.mdx index c54afb75..a3615470 100644 --- a/website/src/content/docs/start/android.mdx +++ b/website/src/content/docs/install/android.mdx @@ -2,12 +2,13 @@ title: Android setup description: Add Appduct to a Kotlin or Java Android app without React Native, register tools, and connect it to the CLI. sidebar: - order: 5 + label: Android + order: 3 --- import { Steps } from '@astrojs/starlight/components'; -This page adds Appduct to a plain Android app, with no React Native. You register tools in Kotlin, and the CLI or an agent calls them the same way as in a React Native app. Building with React Native instead? See [React Native setup](/appduct/start/react-native/). +This page adds Appduct to a plain Android app, with no React Native. You register tools in Kotlin, and the CLI or an agent calls them the same way as in a React Native app. Building with React Native instead? See [React Native setup](/appduct/install/react-native/). **Requirements** @@ -191,4 +192,10 @@ appduct doctor app/build/outputs/apk/debug/app-debug.apk --assert-present **A handler crashes when it touches the UI.** Handlers run off the main thread. Use `withContext(Dispatchers.Main)`. -For a complete example app, see the [native Android playground](/appduct/start/playground/#native-android-playground). +## Next steps + +- [Write more useful tools](/appduct/guides/writing-tools/): schemas, timeouts, and groups. Tool registration lives in Kotlin, on this page. +- [Connect an agent](/appduct/guides/agents/) such as Claude Code or Cursor over MCP. +- [Drive the app from a CLI or an E2E test](/appduct/guides/cli/). +- [Keep Appduct out of your release builds](/appduct/guides/build-variants/#verify-the-built-app), and verify it with `appduct doctor`. +- Try the [native Android playground](/appduct/start/playground/#native-android-playground) for a working example app. diff --git a/website/src/content/docs/start/ios.mdx b/website/src/content/docs/install/ios.mdx similarity index 92% rename from website/src/content/docs/start/ios.mdx rename to website/src/content/docs/install/ios.mdx index f538923a..59eab1af 100644 --- a/website/src/content/docs/start/ios.mdx +++ b/website/src/content/docs/install/ios.mdx @@ -2,12 +2,13 @@ title: iOS setup description: Add Appduct to a SwiftUI or UIKit app without React Native, register tools in Swift, and connect it to the CLI. sidebar: - order: 4 + label: iOS + order: 2 --- import { Steps, Tabs, TabItem } from '@astrojs/starlight/components'; -This page adds Appduct to a plain iOS app, with no React Native or Expo. You register tools in Swift, and the CLI or an agent calls them the same way as in a React Native app. Building with React Native instead? See [React Native setup](/appduct/start/react-native/). +This page adds Appduct to a plain iOS app, with no React Native or Expo. You register tools in Swift, and the CLI or an agent calls them the same way as in a React Native app. Building with React Native instead? See [React Native setup](/appduct/install/react-native/). **Requirements** @@ -235,4 +236,10 @@ appduct doctor build/Shop.app --assert-present # a build that should **The app crashes or misbehaves when a tool updates the UI.** The handler touched UI off the main actor. Use `await MainActor.run`. -For a complete example app, see the [native iOS playground](/appduct/start/playground/#native-ios-playground). +## Next steps + +- [Write more useful tools](/appduct/guides/writing-tools/): schemas, timeouts, and groups. Tool registration lives in Swift, on this page. +- [Connect an agent](/appduct/guides/agents/) such as Claude Code or Cursor over MCP. +- [Drive the app from a CLI or an E2E test](/appduct/guides/cli/). +- [Keep Appduct out of your Release builds](/appduct/guides/build-variants/#verify-the-built-app), and verify it with `appduct doctor`. +- Try the [native iOS playground](/appduct/start/playground/#native-ios-playground) for a working example app. diff --git a/website/src/content/docs/start/react-native.mdx b/website/src/content/docs/install/react-native.mdx similarity index 93% rename from website/src/content/docs/start/react-native.mdx rename to website/src/content/docs/install/react-native.mdx index e4a549a3..a43c1be8 100644 --- a/website/src/content/docs/start/react-native.mdx +++ b/website/src/content/docs/install/react-native.mdx @@ -2,7 +2,8 @@ title: React Native setup description: Add Appduct to an Expo or bare React Native app, register tools, and connect it to the CLI. sidebar: - order: 3 + label: React Native + order: 1 --- import { Steps, Tabs, TabItem } from '@astrojs/starlight/components'; @@ -178,3 +179,11 @@ If your app handles incoming links itself (custom routing, an in-app QR scanner) **`registerTool` throws in development.** The schema can't describe itself to agents (for example, Zod 3 or plain Valibot on its own), or the tool name or group is malformed. The error says what to fix. See [Writing tools](/appduct/guides/writing-tools/). **`connect()` rejects with `appduct_disabled`.** The build has no Appduct native code: it's a release build, Expo Go, or Appduct was excluded. See [Build variants](/appduct/guides/build-variants/). + +## Next steps + +- [Write more useful tools](/appduct/guides/writing-tools/): schemas, timeouts, and groups. +- [Connect an agent](/appduct/guides/agents/) such as Claude Code or Cursor over MCP. +- [Drive the app from a CLI or an E2E test](/appduct/guides/cli/). +- [Keep Appduct out of your release builds](/appduct/guides/build-variants/#verify-the-built-app), and verify it with `appduct doctor`. +- Try the [Expo playground](/appduct/start/playground/#expo-playground) for a working example app. diff --git a/website/src/content/docs/reference/react-native-api.md b/website/src/content/docs/reference/react-native-api.md index 82e3747c..2e24fd3b 100644 --- a/website/src/content/docs/reference/react-native-api.md +++ b/website/src/content/docs/reference/react-native-api.md @@ -5,7 +5,7 @@ sidebar: order: 2 --- -Reference for `@appduct/react-native`. For setup, see [React Native setup](/appduct/start/react-native/); for how to design tools, see [Write tools](/appduct/guides/writing-tools/). +Reference for `@appduct/react-native`. For setup, see [React Native setup](/appduct/install/react-native/); for how to design tools, see [Write tools](/appduct/guides/writing-tools/). ## Entry points diff --git a/website/src/content/docs/start/introduction.mdx b/website/src/content/docs/start/introduction.mdx index c5bb7496..d268b411 100644 --- a/website/src/content/docs/start/introduction.mdx +++ b/website/src/content/docs/start/introduction.mdx @@ -49,6 +49,13 @@ For more detail, see [How it works](/appduct/reference/architecture/). - + +### Choose your platform + + + + + + diff --git a/website/src/content/docs/start/playground.mdx b/website/src/content/docs/start/playground.mdx index 4095c94f..a89a2de3 100644 --- a/website/src/content/docs/start/playground.mdx +++ b/website/src/content/docs/start/playground.mdx @@ -2,7 +2,7 @@ title: Try the playground description: Run one of Appduct's example apps — Expo, SwiftUI, or Jetpack Compose — and drive it from the CLI. sidebar: - order: 6 + order: 3 --- import { Steps } from '@astrojs/starlight/components'; diff --git a/website/src/content/docs/start/quick-start.mdx b/website/src/content/docs/start/quick-start.mdx index b5cf7890..4317c7e8 100644 --- a/website/src/content/docs/start/quick-start.mdx +++ b/website/src/content/docs/start/quick-start.mdx @@ -5,11 +5,13 @@ sidebar: order: 2 --- -import { Steps, Tabs, TabItem } from '@astrojs/starlight/components'; +import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; By the end of this page you'll have called a function inside your running app from your terminal, and handed the same function to an AI agent. -This page uses an Expo app. For bare React Native, plain iOS, or plain Android, see [React Native setup](/appduct/start/react-native/), [iOS setup](/appduct/start/ios/), or [Android setup](/appduct/start/android/). + **Before you start, you need:** diff --git a/website/src/pages/index.astro b/website/src/pages/index.astro index d1aa2fce..fc764fc7 100644 --- a/website/src/pages/index.astro +++ b/website/src/pages/index.astro @@ -55,19 +55,19 @@ const platforms = [ name: 'React Native', pkg: '@appduct/react-native', body: 'iOS 15.1+ and Android on the New Architecture. Expo dev builds or bare apps.', - href: docs('start/react-native'), + href: docs('install/react-native'), }, { name: 'iOS', pkg: 'AppductCore', body: 'Swift, iOS 15.1+. Swift Package Manager or CocoaPods. Nothing from React Native.', - href: docs('start/ios'), + href: docs('install/ios'), }, { name: 'Android', pkg: 'com.callstack.appduct:core', body: 'Kotlin, Android 7.0 (API 24)+. Maven Central, with a no-op artifact for release.', - href: docs('start/android'), + href: docs('install/android'), }, ]; --- From 0c6981431e7834a591c9ee2c21aad4a9d02fc708 Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Mon, 21 Sep 2026 16:17:02 +0200 Subject: [PATCH 3/5] docs(website): match scheme discovery details from #78 --- website/src/content/docs/guides/cli.mdx | 2 +- website/src/content/docs/install/react-native.mdx | 4 ++-- website/src/content/docs/reference/cli.md | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/website/src/content/docs/guides/cli.mdx b/website/src/content/docs/guides/cli.mdx index 9d2499bd..5baf50aa 100644 --- a/website/src/content/docs/guides/cli.mdx +++ b/website/src/content/docs/guides/cli.mdx @@ -220,7 +220,7 @@ It reads `.app`, `.ipa`, `.apk`, and `.aab` files. With `--assert-absent` or `-- 4. `scheme` in `~/.appduct/config.json`. 5. Your project files, in the current directory: `app.json` (`expo.scheme`), then Android (`appductScheme` in `app/build.gradle(.kts)`, or `AndroidManifest.xml`), then iOS (`CFBundleURLSchemes` in an `Info.plist`, or XcodeGen's `project.yml`). -If none has a scheme, the error lists every place it looked. If your Android and iOS projects declare different schemes, it stops and names both rather than picking one. Appduct never runs `app.config.js` or a Gradle build to find the scheme; for dynamic config, use `appduct init --scheme`. +If none has a scheme, the error lists every place it looked. If two project files declare different schemes, it stops and names both rather than picking one. From a React Native root, only `app.json` and the iOS files are read: the Android files are expected at `app/` in the current directory, not under `android/`. Appduct never runs `app.config.js` or a Gradle build to find the scheme; for dynamic config, use `appduct init --scheme`. ## Keep the background service healthy diff --git a/website/src/content/docs/install/react-native.mdx b/website/src/content/docs/install/react-native.mdx index a43c1be8..1c21fedf 100644 --- a/website/src/content/docs/install/react-native.mdx +++ b/website/src/content/docs/install/react-native.mdx @@ -66,7 +66,7 @@ You don't need keys, certificates, or a config plugin for a first run, in any bu - **iOS:** add the scheme under `CFBundleURLTypes` in `Info.plist` (Xcode: target → Info → URL Types). - **Android:** add an intent filter with `android.intent.action.VIEW` and `` to your main activity in `AndroidManifest.xml`. - The CLI finds the scheme in these files automatically when you run it from the project root. + Use the same scheme on both platforms. Run from the project root, the CLI reads it from the iOS `Info.plist`; it doesn't look inside `android/`. If the app has no iOS project, record the scheme with `appduct init --scheme myapp` in step 5. @@ -174,7 +174,7 @@ If your app handles incoming links itself (custom routing, an in-app QR scanner) **Android shows an "Open with" chooser, or nothing happens.** More than one installed app declares your scheme. Pass `--app-id` with your package name, or record it with `appduct init --android-app-id`. -**`appduct link` reports conflicting schemes.** Your `ios/` and `android/` projects declare different schemes. Pass `--scheme`, or record one with `appduct init --scheme`. +**Links open on iOS but not on Android (bare React Native).** From the project root, the CLI takes the scheme from the iOS `Info.plist`, so an Android app that declares a different scheme never receives the link. Use the same scheme on both platforms, or pass `--scheme`. **`registerTool` throws in development.** The schema can't describe itself to agents (for example, Zod 3 or plain Valibot on its own), or the tool name or group is malformed. The error says what to fix. See [Writing tools](/appduct/guides/writing-tools/). diff --git a/website/src/content/docs/reference/cli.md b/website/src/content/docs/reference/cli.md index 0d35680d..38551743 100644 --- a/website/src/content/docs/reference/cli.md +++ b/website/src/content/docs/reference/cli.md @@ -20,7 +20,7 @@ Sets up the current app directory: writes `.appduct/config.json` (mode `0600`) a | `--scheme ` | Scheme to record. Without it, `init` looks in `app.json` and your native project files, never in `APPDUCT_SCHEME` or a parent directory. | | `--ios-app-id ` | iOS bundle id, recorded as `appId.ios`. Needed for `--open ios-device`. | | `--android-app-id ` | Android package name, recorded as `appId.android`. Needed for `--open android`. | -| `--force` | Replace a value that's already recorded. On its own, re-reads the scheme from `app.json`. Merges into the existing file rather than overwriting it. | +| `--force` | Replace a value that's already recorded. On its own, re-reads the scheme from your project files. Merges into the existing file rather than overwriting it. | A plain re-run keeps the recorded scheme and adds a note if your project files now declare a different one. @@ -189,7 +189,9 @@ With `--json`, the error's `type` field names the exact error. See [Error types] 2. Android: the `appductScheme` manifest placeholder in `app/build.gradle.kts` or `app/build.gradle`, then the first `` in an intent filter with `android.intent.action.VIEW` in `app/src/main/AndroidManifest.xml`. 3. iOS: the first `CFBundleURLSchemes` entry in any `Info.plist` up to two levels down (skipping `Pods`, `build`, `node_modules`, `DerivedData`), then XcodeGen's `project.yml`. -If nothing is found, the error lists every location. If the Android and iOS projects disagree, the command fails and names both. Dynamic config (`app.config.js`, Gradle scripts) is never run. +All of these paths are relative to the current directory. From a React Native root, the Android files sit under `android/`, so only `app.json` and the iOS files are read there. + +If nothing is found, the error lists every location. If two of these files declare different schemes, the command fails and names both. Dynamic config (`app.config.js`, Gradle scripts) is never run. ## Config files From 3672287cb91488ca3e205e8a031a90365f48c266 Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Mon, 21 Sep 2026 16:17:57 +0200 Subject: [PATCH 4/5] docs(website): tighten scheme discovery wording --- website/src/content/docs/guides/cli.mdx | 2 +- website/src/content/docs/install/react-native.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/src/content/docs/guides/cli.mdx b/website/src/content/docs/guides/cli.mdx index 5baf50aa..5242fc66 100644 --- a/website/src/content/docs/guides/cli.mdx +++ b/website/src/content/docs/guides/cli.mdx @@ -220,7 +220,7 @@ It reads `.app`, `.ipa`, `.apk`, and `.aab` files. With `--assert-absent` or `-- 4. `scheme` in `~/.appduct/config.json`. 5. Your project files, in the current directory: `app.json` (`expo.scheme`), then Android (`appductScheme` in `app/build.gradle(.kts)`, or `AndroidManifest.xml`), then iOS (`CFBundleURLSchemes` in an `Info.plist`, or XcodeGen's `project.yml`). -If none has a scheme, the error lists every place it looked. If two project files declare different schemes, it stops and names both rather than picking one. From a React Native root, only `app.json` and the iOS files are read: the Android files are expected at `app/` in the current directory, not under `android/`. Appduct never runs `app.config.js` or a Gradle build to find the scheme; for dynamic config, use `appduct init --scheme`. +If none has a scheme, the error lists every place it looked. If two project files declare different schemes, it stops and names both rather than picking one. From a React Native root, it reads only `app.json` and the iOS files, because it looks for Android's files in `app/` of the current directory, not in `android/`. Appduct never runs `app.config.js` or a Gradle build to find the scheme; for dynamic config, use `appduct init --scheme`. ## Keep the background service healthy diff --git a/website/src/content/docs/install/react-native.mdx b/website/src/content/docs/install/react-native.mdx index 1c21fedf..225f4a88 100644 --- a/website/src/content/docs/install/react-native.mdx +++ b/website/src/content/docs/install/react-native.mdx @@ -66,7 +66,7 @@ You don't need keys, certificates, or a config plugin for a first run, in any bu - **iOS:** add the scheme under `CFBundleURLTypes` in `Info.plist` (Xcode: target → Info → URL Types). - **Android:** add an intent filter with `android.intent.action.VIEW` and `` to your main activity in `AndroidManifest.xml`. - Use the same scheme on both platforms. Run from the project root, the CLI reads it from the iOS `Info.plist`; it doesn't look inside `android/`. If the app has no iOS project, record the scheme with `appduct init --scheme myapp` in step 5. + Use the same scheme on both platforms. When you run the CLI from the project root, it reads the scheme from the iOS `Info.plist` and doesn't look inside `android/`. If the app has no iOS project, record the scheme with `appduct init --scheme myapp` in step 5. From 4ccbaf2ce5b10cc645457c022e39b3e743dacba3 Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Mon, 21 Sep 2026 16:21:26 +0200 Subject: [PATCH 5/5] fix(website): single frame on the search shortcut, one active line in the sidebar --- website/src/styles/docs.css | 1 - website/src/styles/theme.css | 10 +++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/website/src/styles/docs.css b/website/src/styles/docs.css index 9f6ef483..40441425 100644 --- a/website/src/styles/docs.css +++ b/website/src/styles/docs.css @@ -141,7 +141,6 @@ h1#_top { font-weight: 400; color: var(--sl-color-white); background: var(--cs-wash); - box-shadow: inset 2px 0 0 var(--cs-purple); } .sidebar-content ul ul li:has(> a[aria-current='page']) { border-inline-start-color: var(--cs-purple); diff --git a/website/src/styles/theme.css b/website/src/styles/theme.css index afa57497..1cd1505a 100644 --- a/website/src/styles/theme.css +++ b/website/src/styles/theme.css @@ -175,11 +175,19 @@ site-search button[data-open-modal]:hover { border-color: var(--cs-accent) !important; color: var(--sl-color-white) !important; } -site-search button[data-open-modal] kbd { +/* The shortcut is a wrapping one per key: frame the wrapper only, so the keys + don't draw overlapping boxes inside it. */ +site-search button[data-open-modal] > kbd { background: transparent !important; border: 1px solid var(--cs-line); font-family: var(--cs-font-mono); } +site-search button[data-open-modal] > kbd kbd { + background: transparent !important; + border: 0 !important; + padding: 0 0.1em; + font-family: inherit; +} site-search dialog { border: 1px solid var(--cs-line) !important; background: var(--cs-bg) !important;