diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c675193..f2539bd 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -41,19 +41,19 @@ jobs: uses: actions/configure-pages@v5 # Must run before the typecheck. src/generated/packages.json is gitignored because it is - # rebuilt from npm every time, so in a fresh clone it does not exist yet and - # packages.service.ts cannot resolve its import. Locally this passes only because a build - # has already happened. - - name: Fetch the catalogue from npm - run: bun run packages + # rebuilt from npm every time, so in a fresh clone it does not exist and packages.service.ts + # cannot resolve its import. Locally this passes only because a build already ran. + # + # This also refreshes the committed changelog page, which is what lets the nightly cron pick + # up a release published since the last commit. + - name: Generate the catalogue and changelogs from npm + run: bun run generate - # astro check needs @astrojs/check, which is a devDependency for exactly this reason. - # Without it the command tries to install interactively and hangs the job. - name: Typecheck - run: bun run typecheck + run: bun run check-types - # Runs scripts/fetch-packages.mjs first, so the catalogue, versions, download counts and - # changelogs are read from npm on every deploy. No credentials: every source is public. + # `generate` runs again here as part of the build script. It is cheap and keeps a local + # `bun run build` self-contained. No credentials: every source is public. - name: Build run: bun run build @@ -61,7 +61,7 @@ jobs: if: github.event_name != 'pull_request' uses: actions/upload-pages-artifact@v3 with: - path: dist + path: out deploy: name: Deploy diff --git a/.gitignore b/.gitignore index 9a2c70a..c7f49a9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,10 @@ dist *.tsbuildinfo # Regenerated from npm on every build — never hand-edited, so never committed. src/generated/packages.json + +# Next and fumadocs build output +.next/ +out/ +.source +next-env.d.ts +.migration-keep diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 0000000..e3ee0cb --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,15 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": ["typescript", "react", "import", "nextjs", "unicorn"], + "env": { "builtin": true, "es2022": true }, + "settings": { "react": { "version": "19.2" } }, + "rules": { + "eqeqeq": ["warn", "smart"], + "no-debugger": "warn", + "no-var": "warn", + "prefer-const": "warn", + "import/no-duplicates": "error", + "typescript/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }] + }, + "ignorePatterns": [".next", ".source", "out", "next-env.d.ts", "node_modules"] +} diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..69f6c8d --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "printWidth": 100, + "tabWidth": 2, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/README.md b/README.md index ee70492..aca4277 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # Axonpack -**The open source tools and libraries for React and React Native.** +**Axonpack ends the guesswork when things break.** -Small, focused, dependency-light packages. Drop one in and carry on. There is no framework here -to adopt. +Answers you and your agent can both read. Every request, error, log and stored value, captured on +the device and copied out as structured JSON. Live at [axonpack.github.io](https://axonpack.github.io). Docs at [axonpack.github.io/docs](https://axonpack.github.io/docs). diff --git a/astro.config.mjs b/astro.config.mjs deleted file mode 100644 index 93dd321..0000000 --- a/astro.config.mjs +++ /dev/null @@ -1,16 +0,0 @@ -import react from "@astrojs/react"; -import sitemap from "@astrojs/sitemap"; -import tailwindcss from "@tailwindcss/vite"; -import { defineConfig } from "astro/config"; - -export default defineConfig({ - // Static by default — Astro prerenders to a plain directory of HTML. GitHub Pages cannot run a - // server, so there is deliberately no adapter and no SSR here. - output: "static", - // axonpack.github.io is the organisation root site, so the app owns "/" and needs no base. The - // docs repo is a project site and does need one. `site` is what lets sitemap emit absolute URLs. - site: "https://axonpack.github.io", - trailingSlash: "always", - integrations: [react(), sitemap()], - vite: { plugins: [tailwindcss()] }, -}); diff --git a/bun.lock b/bun.lock index ff1145f..2ac85fb 100644 --- a/bun.lock +++ b/bun.lock @@ -5,286 +5,281 @@ "": { "name": "axonpack-landing", "dependencies": { - "@astrojs/react": "^4.2.0", - "@astrojs/sitemap": "^3.2.1", - "astro": "^5.2.0", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "lucide-react": "^0.460.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "tailwind-merge": "^2.5.5", + "@radix-ui/react-navigation-menu": "^1.2.22", + "fumadocs-core": "16.15.4", + "fumadocs-mdx": "15.4.0", + "fumadocs-ui": "npm:@fumadocs/base-ui@16.15.4", + "lucide-react": "^1.34.0", + "next": "16.3.3", + "react": "^19.2.8", + "react-dom": "^19.2.8", }, "devDependencies": { - "@astrojs/check": "^0.9.4", - "@tailwindcss/vite": "^4.0.0", - "@types/react": "^19.0.0", - "@types/react-dom": "^19.0.0", - "tailwindcss": "^4.0.0", - "typescript": "^5.7.0", + "@tailwindcss/postcss": "^4.3.3", + "@types/mdx": "^2.0.14", + "@types/node": "^26.3.0", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.5", + "oxlint": "^1.77.0", + "postcss": "^8.5.26", + "serve": "^14.2.6", + "tailwindcss": "^4.3.3", + "typescript": "^6.0.3", }, }, }, "packages": { - "@astrojs/check": ["@astrojs/check@0.9.10", "", { "dependencies": { "@astrojs/language-server": "^2.16.7", "chokidar": "^4.0.3", "kleur": "^4.1.5", "yargs": "^18.0.0" }, "peerDependencies": { "typescript": "^5.0.0 || ^6.0.0" }, "bin": { "astro-check": "./bin/astro-check.js" } }, "sha512-zgx/UQMozdjOa3bOxjgeCFdtpE3c9rRX6xHwa+2QXvy8z8Akifu2AtubHyv/zzC2znO8dl8fFWL4K+Ba9kS8HQ=="], + "@alloc/quick-lru": ["@alloc/quick-lru@5.3.0", "", {}, "sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA=="], - "@astrojs/compiler": ["@astrojs/compiler@2.13.1", "", {}, "sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg=="], + "@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="], - "@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.7.6", "", {}, "sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q=="], + "@base-ui/react": ["@base-ui/react@1.8.0", "", { "dependencies": { "@babel/runtime": "^7.29.7", "@base-ui/utils": "0.4.0", "@floating-ui/react-dom": "^2.1.9", "@floating-ui/utils": "^0.2.12", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@date-fns/tz": "^1.2.0", "@types/react": "^17 || ^18 || ^19", "date-fns": "^4.0.0", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@date-fns/tz", "@types/react", "date-fns"] }, "sha512-P0/1sxo6SBVZOklKMIedvTWqw2s2IQzi9x5bIVsXu980cuSOD4NeuRSs+/L7LZQfDkZP/uRZyGPyfFl/B1oH+Q=="], - "@astrojs/language-server": ["@astrojs/language-server@2.16.16", "", { "dependencies": { "@astrojs/compiler": "^2.13.1", "@astrojs/yaml2ts": "^0.2.4", "@jridgewell/sourcemap-codec": "^1.5.5", "@volar/kit": "~2.4.28", "@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.16", "volar-service-css": "0.0.71", "volar-service-emmet": "0.0.71", "volar-service-html": "0.0.71", "volar-service-prettier": "0.0.71", "volar-service-typescript": "0.0.71", "volar-service-typescript-twoslash-queries": "0.0.71", "volar-service-yaml": "0.0.71", "vscode-html-languageservice": "^5.6.2", "vscode-uri": "^3.1.0" }, "peerDependencies": { "prettier": "^3.0.0", "prettier-plugin-astro": ">=0.11.0" }, "optionalPeers": ["prettier", "prettier-plugin-astro"], "bin": { "astro-ls": "./bin/nodeServer.js" } }, "sha512-KuS17AOOqH/M5mHXPmKvtp8L+NNteARC7Xjf395+9R9dtJOBndqdStwU4V+OKzYZpgZ+hliV13knzx/oMtFl7Q=="], + "@base-ui/utils": ["@base-ui/utils@0.4.0", "", { "dependencies": { "@babel/runtime": "^7.29.7", "@floating-ui/utils": "^0.2.12", "reselect": "^5.2.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-bO9fz25kKtPf+aZVyfQrC0PDmJdmVni31W2hCS5/Owb+inwdIL3XU26pCPRPlt4LSxZrBgLwubXQXQlKaFEZzw=="], - "@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.11", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.6", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "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.2", "shiki": "^3.21.0", "smol-toml": "^1.6.0", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, "sha512-hcaxX/5aC6lQgHeGh1i+aauvSwIT6cfyFjKWvExYSxUhZZBBdvCliOtu06gbQyhbe0pGJNoNmqNlQZ5zYUuIyQ=="], + "@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="], - "@astrojs/prism": ["@astrojs/prism@3.3.0", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ=="], - "@astrojs/react": ["@astrojs/react@4.4.2", "", { "dependencies": { "@vitejs/plugin-react": "^4.7.0", "ultrahtml": "^1.6.0", "vite": "^6.4.1" }, "peerDependencies": { "@types/react": "^17.0.50 || ^18.0.21 || ^19.0.0", "@types/react-dom": "^17.0.17 || ^18.0.6 || ^19.0.0", "react": "^17.0.2 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0" } }, "sha512-1tl95bpGfuaDMDn8O3x/5Dxii1HPvzjvpL2YTuqOOrQehs60I2DKiDgh1jrKc7G8lv+LQT5H15V6QONQ+9waeQ=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.28.2", "", { "os": "android", "cpu": "arm" }, "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg=="], - "@astrojs/sitemap": ["@astrojs/sitemap@3.7.4", "", { "dependencies": { "sitemap": "^9.0.0", "zod": "^4.3.6" } }, "sha512-LbKNC24bdUWcQf/pThB6qLlSqHojxGjZDURIzFocY8rlWnAn2t74nnhnK6S5x0NHriHoAduLEpVjRykmeGiVvA=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A=="], - "@astrojs/telemetry": ["@astrojs/telemetry@3.3.0", "", { "dependencies": { "ci-info": "^4.2.0", "debug": "^4.4.0", "dlv": "^1.1.3", "dset": "^3.1.4", "is-docker": "^3.0.0", "is-wsl": "^3.1.0", "which-pm-runs": "^1.1.0" } }, "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.28.2", "", { "os": "android", "cpu": "x64" }, "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q=="], - "@astrojs/yaml2ts": ["@astrojs/yaml2ts@0.2.4", "", { "dependencies": { "yaml": "^2.8.3" } }, "sha512-8oddpOae35pJsXPQXhTkM0ypfKPskVsh2bCxRtbf7e+/Epw2nReakFYpLKjZMEr75CsoF203PMnCocpfz0s69A=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw=="], - "@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw=="], - "@babel/compat-data": ["@babel/compat-data@7.29.7", "", {}, "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw=="], - "@babel/core": ["@babel/core@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-compilation-targets": "^7.29.7", "@babel/helper-module-transforms": "^7.29.7", "@babel/helpers": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/template": "^7.29.7", "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg=="], - "@babel/generator": ["@babel/generator@7.29.8", "", { "dependencies": { "@babel/parser": "^7.29.8", "@babel/types": "^7.29.8", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.2", "", { "os": "linux", "cpu": "arm" }, "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w=="], - "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.29.7", "", { "dependencies": { "@babel/compat-data": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug=="], - "@babel/helper-globals": ["@babel/helper-globals@7.29.7", "", {}, "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ=="], - "@babel/helper-module-imports": ["@babel/helper-module-imports@7.29.7", "", { "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ=="], - "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.29.7", "", { "dependencies": { "@babel/helper-module-imports": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA=="], - "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.29.7", "", {}, "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ=="], - "@babel/helper-string-parser": ["@babel/helper-string-parser@7.29.7", "", {}, "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA=="], - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg=="], - "@babel/helper-validator-option": ["@babel/helper-validator-option@7.29.7", "", {}, "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.2", "", { "os": "linux", "cpu": "x64" }, "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ=="], - "@babel/helpers": ["@babel/helpers@7.29.7", "", { "dependencies": { "@babel/template": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw=="], - "@babel/parser": ["@babel/parser@7.29.8", "", { "dependencies": { "@babel/types": "^7.29.8" }, "bin": "./bin/babel-parser.js" }, "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.2", "", { "os": "none", "cpu": "x64" }, "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw=="], - "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ=="], - "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw=="], - "@babel/template": ["@babel/template@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q=="], - "@babel/traverse": ["@babel/traverse@7.29.8", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.8", "@babel/helper-globals": "^7.29.7", "@babel/parser": "^7.29.8", "@babel/template": "^7.29.7", "@babel/types": "^7.29.8", "debug": "^4.3.1" } }, "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g=="], - "@babel/types": ["@babel/types@7.29.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg=="], + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ=="], - "@capsizecss/unpack": ["@capsizecss/unpack@4.0.1", "", { "dependencies": { "fontkitten": "^1.0.3" } }, "sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ=="], + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA=="], - "@emmetio/abbreviation": ["@emmetio/abbreviation@2.3.3", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA=="], + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g=="], - "@emmetio/css-abbreviation": ["@emmetio/css-abbreviation@2.1.8", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw=="], + "@floating-ui/core": ["@floating-ui/core@1.8.0", "", { "dependencies": { "@floating-ui/utils": "^0.2.12" } }, "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ=="], - "@emmetio/css-parser": ["@emmetio/css-parser@0.4.1", "", { "dependencies": { "@emmetio/stream-reader": "^2.2.0", "@emmetio/stream-reader-utils": "^0.1.0" } }, "sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ=="], + "@floating-ui/dom": ["@floating-ui/dom@1.8.0", "", { "dependencies": { "@floating-ui/core": "^1.8.0", "@floating-ui/utils": "^0.2.12" } }, "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg=="], - "@emmetio/html-matcher": ["@emmetio/html-matcher@1.3.0", "", { "dependencies": { "@emmetio/scanner": "^1.0.0" } }, "sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ=="], + "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.9", "", { "dependencies": { "@floating-ui/dom": "^1.8.0" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg=="], - "@emmetio/scanner": ["@emmetio/scanner@1.0.4", "", {}, "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA=="], + "@floating-ui/utils": ["@floating-ui/utils@0.2.12", "", {}, "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww=="], - "@emmetio/stream-reader": ["@emmetio/stream-reader@2.2.0", "", {}, "sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw=="], + "@fuma-translate/react": ["@fuma-translate/react@1.0.2", "", { "peerDependencies": { "@types/react": "*", "react": "^19.2.0", "react-dom": "^19.2.0" }, "optionalPeers": ["@types/react"] }, "sha512-uOiOtBx3nRXR8Nu1GzBf1tApgF1FErDBTHxRIAQeyQdyOoZbrNRN6H4kDCWObY4qyGeGbHydG0DHzgeUgFDMIw=="], - "@emmetio/stream-reader-utils": ["@emmetio/stream-reader-utils@0.1.0", "", {}, "sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A=="], + "@fumadocs/tailwind": ["@fumadocs/tailwind@0.1.1", "", { "peerDependencies": { "tailwindcss": "^4.0.0" }, "optionalPeers": ["tailwindcss"] }, "sha512-BnPe52UxSaG8yKlHMKBxXw8h6GpK5qO55ci6+Qd5JnquTvIw6SpfbC1P+qAi82PuPWv1KZAWY8bxRk4+x9ctXw=="], - "@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="], + "@fumari/image-size": ["@fumari/image-size@0.1.0", "", {}, "sha512-x2o9u6P8uKUK15B8XgEoRhR3PgLoLSbQKK6FUCd14JzumEw+e8FXZPelij/dZ4VQVMp4r61VD3DcvSo3aEhLAA=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], + "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], - "@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="], + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.3.3" }, "os": "darwin", "cpu": "arm64" }, "sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA=="], - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.7", "", { "os": "android", "cpu": "arm64" }, "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ=="], + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.3.3" }, "os": "darwin", "cpu": "x64" }, "sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw=="], - "@esbuild/android-x64": ["@esbuild/android-x64@0.27.7", "", { "os": "android", "cpu": "x64" }, "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg=="], + "@img/sharp-freebsd-wasm32": ["@img/sharp-freebsd-wasm32@0.35.4", "", { "dependencies": { "@img/sharp-wasm32": "0.35.4" }, "os": "freebsd" }, "sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA=="], - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw=="], + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg=="], - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ=="], + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw=="], - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.7", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w=="], + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.3.3", "", { "os": "linux", "cpu": "arm" }, "sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA=="], - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ=="], + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A=="], - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.7", "", { "os": "linux", "cpu": "arm" }, "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA=="], + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.3.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w=="], - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A=="], + "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.3.3", "", { "os": "linux", "cpu": "none" }, "sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ=="], - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.7", "", { "os": "linux", "cpu": "ia32" }, "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg=="], + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.3.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q=="], - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q=="], + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA=="], - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw=="], + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw=="], - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.7", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ=="], + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw=="], - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ=="], + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.3.3" }, "os": "linux", "cpu": "arm" }, "sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A=="], - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.7", "", { "os": "linux", "cpu": "s390x" }, "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw=="], + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.3.3" }, "os": "linux", "cpu": "arm64" }, "sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ=="], - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.7", "", { "os": "linux", "cpu": "x64" }, "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA=="], + "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.3.3" }, "os": "linux", "cpu": "ppc64" }, "sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ=="], - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w=="], + "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.3.3" }, "os": "linux", "cpu": "none" }, "sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA=="], - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.7", "", { "os": "none", "cpu": "x64" }, "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw=="], + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.3.3" }, "os": "linux", "cpu": "s390x" }, "sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ=="], - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.7", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A=="], + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.3.3" }, "os": "linux", "cpu": "x64" }, "sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA=="], - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.7", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg=="], + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.3.3" }, "os": "linux", "cpu": "arm64" }, "sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA=="], - "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw=="], + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.3.3" }, "os": "linux", "cpu": "x64" }, "sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg=="], - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.7", "", { "os": "sunos", "cpu": "x64" }, "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA=="], + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.35.4", "", { "dependencies": { "@emnapi/runtime": "^1.11.3" } }, "sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA=="], - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA=="], + "@img/sharp-webcontainers-wasm32": ["@img/sharp-webcontainers-wasm32@0.35.4", "", { "dependencies": { "@img/sharp-wasm32": "0.35.4" }, "cpu": "none" }, "sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA=="], - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.7", "", { "os": "win32", "cpu": "ia32" }, "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw=="], + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.35.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw=="], - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="], + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.35.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw=="], - "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.35.4", "", { "os": "win32", "cpu": "x64" }, "sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg=="], - "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], - "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="], + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], - "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="], + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], - "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="], + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.6.0", "", {}, "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw=="], - "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="], + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="], + "@mdx-js/mdx": ["@mdx-js/mdx@3.1.1", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", "acorn": "^8.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", "recma-build-jsx": "^1.0.0", "recma-jsx": "^1.0.0", "recma-stringify": "^1.0.0", "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "source-map": "^0.7.0", "unified": "^11.0.0", "unist-util-position-from-estree": "^2.0.0", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ=="], - "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="], + "@next/env": ["@next/env@16.3.3", "", {}, "sha512-U2eYQRwXj+dsqxV79zFqExDdatnNY/ZWc2nsJU1p/OgT7fd3dXwlF6OjYaFQCfMoeTA19PWq+wVmYgimVA+V+g=="], - "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="], + "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-8Hiv32QJPwdV6KYJ8meR9SBA061tQqnIKTJDocvOXlEQqib0xMFpzArosuffFUUc0sslbh7QQ8a3Yey1QV8EIw=="], - "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="], + "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-A1lgKgwVchRYmSe467zdwhxT9040dd8lH+o65sL5Jet8fjB4kegw/rDyPIpYVRb6jAqwXFOJpjIXJLxQKLiE3A=="], - "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="], + "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-bf0FIssMFueU2dm7vQEWWxk0c8UjKTdW0yzuh0sQsD8pf1+KCLDdaqhYZNMYGmXwEOiHAUzgBKudovIlcvvBjg=="], - "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="], + "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-W7viwCk9JY/cAkdz/A273rd5bb3RgT/IHwR7Upv90tunjBWNtAAhGhoecHh+teRNRSinuAFmE+l7fwZ4YKkrXg=="], - "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="], + "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-0W46zw1N3ODpI6n0GeivHvvob1pooozgZVqy65k0mh4/7vr+FbY9+WpHzNVXjHipJf/A3FDheBG19H1s5A25rA=="], - "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="], + "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-H4mBso8ZTMBPtdT0PN0pBx2ayTvQuTuvS6qT13d77yVFJXAPCxkyIhLTmdMaGTJs0krQYI/qpzdHijCeihXhbg=="], - "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="], + "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.3.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-cTMUJpcEGmeywofCUfhR+rSsoE33+rVPnPEYNTNdLNlsOeEg/vktOsKUSTb28vUGqD2jkm4Zaskcwn7OCI6FQg=="], - "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="], + "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.3.3", "", { "os": "win32", "cpu": "x64" }, "sha512-2VR4cTBzHXaBjnGsuH6GyJjENzQOmHeAh11uY1iUhjm3j5dEUrVJuUj+VL78jaGi/Dik8xS76zEj18BsFhlVZQ=="], - "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="], + "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.82.0", "", { "os": "android", "cpu": "arm" }, "sha512-a3LB+C5Dsj5b/qtmG/mv5WrzuiXEpg1KF5nXWcEvaoN5TYAqkIvxPOwTPp3Jy/FoGpRo8zsTFhMElMXfeoOEzA=="], - "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="], + "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.82.0", "", { "os": "android", "cpu": "arm64" }, "sha512-OBlhRgNqFblGpGenno/aqOfJLOkQ2B8Ig3iDAalfn0H8hJGZKXPeexCRTDm6uwv6YUjSA9Xnwt1y/Bgj5ZH8uw=="], - "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="], + "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.82.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-dsopxqtY5ZdyT9uLHyGt1SyiLop6hi7hWI3PKpePodkRQOkLaCm+OE4fR9CAz9qdfjiFO8531tX/QDyP/psjFg=="], - "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="], + "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.82.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-94Lu0SgTClKColU66g1VDuigV3HkcbkJBnTtZjGYfE8UPugaWDgKrm2icjC6HJVUYler2OXaHP/X0TBy8+CowQ=="], - "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="], + "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.82.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-hne/V06ewhh1i0w8+l7GDNROAGCGPmyFuOwiP7YTRu0JycyStJ4785dmF8xU5p0uUwt2emvIF9vc7Xjis+cJ0g=="], - "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="], + "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.82.0", "", { "os": "linux", "cpu": "arm" }, "sha512-aWY2xtbZf1LneW9Qsv/n2Sp8gOu74JrlQzEtj4coHX2SHFrCfhmAumaU+sI/A5nr+yoTRTSmI/pL2s6ADlNSkw=="], - "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="], + "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.82.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Fe+TtXCXMh/5f7kWlZ2VAwsMumZWtraFlKVk1NJlL52/beGwfDE7ov+/8gVirHzWokzGu7X65hSPq0ucPDskWQ=="], - "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="], + "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.82.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-6azCZ6OJudlvipNttXCCQcyeFfcJ/NvUZdSN1z8elo73kCHtyQC7WTiUcSjWYvJ1jaq9KDUyMAoAS/vNzhBomA=="], - "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], + "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.82.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-PLEaSD8IAIIlwW4dwOd9YaxuxeOpwiXL4J24rcnE4iNtyM5j9Q9/3+gti08oXpx0u2ygNjRDx9xjWWpQonuJEw=="], - "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.82.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-D94em/BwknNTn4vqxjHh5wb2oL566eFhArabqKIr0cNZMHOJuiraFp1A8tXpH05bbE5tqwEfLXTI0MWEGtn3Dw=="], - "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.82.0", "", { "os": "linux", "cpu": "none" }, "sha512-MOprxBaoYU2D4VgxXCl3ghydThWtx7Um1lL51kGYNeQ5Al7WzsH7/tqGdNtbLrIWnjq3bsm13+nz/gRIxjrOXw=="], - "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.82.0", "", { "os": "linux", "cpu": "none" }, "sha512-5h55QsfJ/luDXZzC20k6SNOY1Az+dCP9WvntKtcUWh2JhckAdwApY2ZusaBTwLENnReXU+A2fJtSrYvZJNKNPg=="], - "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.6.0", "", {}, "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw=="], + "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.82.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-IE8NJNLlHr0CaXyGJPGVn0eTkUyoj1I2UfA8x7I4PSOYKsQ/6btVC7Pywrj5onk0cMH25r6Z38SoN3AvE5Zuog=="], - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - - "@napi-rs/lzma-linux-x64-gnu": ["@napi-rs/lzma-linux-x64-gnu@1.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ=="], - - "@oslojs/encoding": ["@oslojs/encoding@1.1.0", "", {}, "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ=="], + "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.82.0", "", { "os": "linux", "cpu": "x64" }, "sha512-XUUUxaBo9XKl+J1B9EmP1cTGQPddzeURvoGkfwh/94PGnbW+hBprDljneoI2M1jzC1bzrIV3ihc7iM9UXl8+tg=="], - "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="], + "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.82.0", "", { "os": "linux", "cpu": "x64" }, "sha512-SWLSFulX9TDuH6yvbPYp4+VNn6jkkIvvI+KiujDM5rWBRHEfkesCC/pCneIIUr6ovkxZ5fRtpi2v5Cz5FrMJZg=="], - "@rollup/pluginutils": ["@rollup/pluginutils@5.4.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg=="], + "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.82.0", "", { "os": "none", "cpu": "arm64" }, "sha512-BQy35f6ZUdNr9a6c7B7orxQTcLjByGT2z3WAgmRovpRwmPYAaJ+NTplmMzhdjdJ4qSchfMNZy/Ukg+qRg6zseQ=="], - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.63.1", "", { "os": "android", "cpu": "arm" }, "sha512-UZ8sUxPTiHWYX9QNdJedb1kDZSpS1t/VPWBWGSgqHNi9w3Cu6IXvu2mzbhiTiPvtrqgTQJ+zqiAq2iPIPilpaQ=="], + "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.82.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-V4QhSTg5gctZue8RJjsGi7NpQPThr/p1/HfmiMC5kfe1KFEup9SQRVub4A6kijQjdHfxj7bLL1KO3QO7/5bwMQ=="], - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.63.1", "", { "os": "android", "cpu": "arm64" }, "sha512-cQ4nFQABN5cDvDpbvJ7bMStCpnaVxynZrRMfUJYgxcIk9Sh54FIO1vtfkg0B69REjER77ioZ/ov+eAApx/KmLQ=="], + "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.82.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-TUSCLaKB2yktpFAJ/r3HAUYsaV/3DT7JS4iNKyoh3a9YNwD0UG7Ezh4D8m23654vQcU6P/RQrCAjRPKe4peP/A=="], - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.63.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-FQNqd1lRy/0QhDk3xeRIkSBiCpXCiDnZO3YLVdcDKN1UBiKToNftCzcXYNLshmPDUMlu2TdeS8tGcsU6f3YF1Q=="], + "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.82.0", "", { "os": "win32", "cpu": "x64" }, "sha512-VTVoRIWJTb+wvUX8EYoPArfFH02whuR10goFXE/LHRRX33ajRrFgqbcONXZMiF4C5rnattfkm87HqYn8jb8hmQ=="], - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.63.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-pvD16V939D3CloK0+qikpGaxiPrDUXTe7Y5cWOMkMSy7m1cawa8EGy/kXYi/G/cKAC4HDAbSnzCIk1WmsoOKXg=="], + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.7", "", {}, "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q=="], - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.63.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-pcFGeL2345VwdTnJhA6zLbew+YgWB0qBG2+dMtXjCicf6+rm6kO6cOoh5VnTe0ZMrMRgRyuHmCJxZWrIdzYuOw=="], + "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.15", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-slot": "1.3.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9W+B9NPF0NaaPh/1NJd3+KqsnlLqU9H7T2rvww+fp+T/evVXdNAyYcnfRQZFOjkR1ajQp3yORlqnI8soawLvNA=="], - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.63.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-mRJlqSRulVzcKq/LKA6ICSIc3K/l4fzlVn/gePn2nXIHy8seRi5z/eeRE0d/XMBxcMldiXtQTSpRj0tkkC3g8Q=="], + "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.5", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA=="], - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.63.1", "", { "os": "linux", "cpu": "arm" }, "sha512-YDUNvVM85TI3g/1OpnqKP1h4NeW/j64DfWMf+G3M809xNk1bJSnpFp4sh83NpmVE5DXnkh8ULor4LTVZKoYLHw=="], + "@radix-ui/react-context": ["@radix-ui/react-context@1.2.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA=="], - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.63.1", "", { "os": "linux", "cpu": "arm" }, "sha512-7Mcn71p9ZuQFAj+h+dhQXy/yeLePRS2yKRnmW1DijA9thKO5qap0GNOIQK4yQ6iP3SU0Mrb/yWo8h8vgRba8lw=="], + "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-5pzg4FGQNpExhnhT2zlrP1wZFaYCd1K0nYWoFAdcYoYK868IEigqMX3B3f8yIoRlAhAeDWciLI6ZdCKHF9P4Vg=="], - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.63.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-4YiLQTX6U4CSl0L9cluep9A9W6UmTfqBDc2/CH6wlu54pl4E7Jn3cOD8oxzvBDEGk/JMKgJ47C8g+radF7mwvg=="], + "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.19", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-effect-event": "0.0.5" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w=="], - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.63.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-2ra8F7w8OquwZN9z2/fKFnli69wa8PLwaVzRMIPGb13ByMJwC28Fbp8YcVGoUhlYMTt7j5j9bNgpysrN2UM+vw=="], + "@radix-ui/react-id": ["@radix-ui/react-id@1.1.4", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA=="], - "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.63.1", "", { "os": "linux", "cpu": "none" }, "sha512-Sy20ncyhjmBP0Ml+UvQbimjlk6VFgjW5uNP+qqwHB00mTE8Bl2C1TuHTlRwK2YoXeZbee5lP2XevBWVkAQAtSQ=="], + "@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.22", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-use-previous": "1.1.4", "@radix-ui/react-visually-hidden": "1.2.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ou7iLEJ+yrhQndkkA4U21XIdS/CS45F4iXIkTZcb6/Ne9EMsOuDudVmCwmDnfFZZ+y1FZqXRNSIgBy+YMvZVZg=="], - "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.63.1", "", { "os": "linux", "cpu": "none" }, "sha512-noITLp8oNjYliPnGWmLyelIHwULGqbHloQHGw1rtxbWhTuWooRpnZarZQJ1y9EUC4szuCusCc+HEpUtxpIwYvA=="], + "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.10", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw=="], - "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.63.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-hlxxXd+F1mWiAcaFR7Sv9ZQT6m6UfI8+Vy/kFJzztq2pDMU/0wZ9sish0iszNZvsQDo8Gc0i5yuFEOz5dDf6fA=="], + "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.10", "", { "dependencies": { "@radix-ui/react-slot": "1.3.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg=="], - "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.63.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-EF7OpqQTQ/BvGqLzUi4rEHuagCV9MugAUXSHemwPW5vxZ75RR+jxO/2j95Ph2dalMpFHSVECjRoioHZgA9zOYA=="], + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.5" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q=="], - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.63.1", "", { "os": "linux", "cpu": "none" }, "sha512-wQO3JesW9PRkwlabQ27y7sPfVOOTLRG73I4F2UYHG5PXun3J9U3y+b7ezVKSYbsvSKGQ1k1cq8Qlun4C9kLt3w=="], + "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ=="], - "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.63.1", "", { "os": "linux", "cpu": "none" }, "sha512-ouAGwhO6wHRXdnOVCOsB0tRFkA7nhNB2Nwax6oECXN0YiN8EYUTBAOudADOB1PI+yDL61TeNx/u7MVCzksNbkQ=="], + "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-use-effect-event": "0.0.5", "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ=="], - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.63.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-q2R38Sn+1J8RxhfJ+T54wSWmyKXWec+9jgDfqO2AtArEqHO5R2aeayp5H5OYLr5UYDVGsVaZPEFUooMhYCdz5A=="], + "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.5", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg=="], - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.63.1", "", { "os": "linux", "cpu": "x64" }, "sha512-gfI5T24WLLuFfSKw7Go/zDXjAAV0fny0swTaDv+WjK7vqcw4cRhFfdsyKL1n+ukI+ooBxn3bVQnyrn06WpI50w=="], + "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw=="], - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.63.1", "", { "os": "linux", "cpu": "x64" }, "sha512-4h6XqthmB4Hspji84wvgk+ElodTsGj+dbZqHJHHtKxj4mYq0ANSEEPX9ys3moJueqsRjwpaJYH7874Itwnj2ow=="], + "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-XoSLhbRbqxFtgJoi2fNHA3C6pDlY34x508vUpUGoFZfvePfHXHbE1lC4FYFMnJWgiCRroSTw6fOsXQoVS9RwZg=="], - "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.63.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-dlfCOa87o1VAYegLQ9EKilx2JCeRofiyPGhTCmqnuXZ6bMPiycO1rq1+sKoulAp7pGLIsTIw+1x5R+zgh5LhhA=="], + "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.11", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-NFS86RYYZb4/exihaESBGOpMJFz8MGLAfu3mOBSGByVnVPC9JPASfYubxd/8KbkQK0sYAv8lVQDEQukDX/qXvQ=="], - "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.63.1", "", { "os": "none", "cpu": "arm64" }, "sha512-cjkLbOlfcm3QGhMM1J5zaZjsw1GggbN6rw9UTSSRrPrR1KkcXnN7Uq9rPw34xImQ9VOY9GN+6u2Zj80B9ptkcw=="], + "@shikijs/core": ["@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" } }, "sha512-QCR4q2ZO/ILJEuwiBMel4wdcTDb1JGwfjKTxPDF6x8ixOaluPrVqIn06C99AcRPhmYlBR56d/Fb+GN58GzExpg=="], - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.63.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-Li1KdUnWGE4N3e1F/B4RTB1ms+nG4WBgjByO46pkeBVX/2UBsY53xf5vK9WygVmnH3RwncIST7lkSdLSY6P9lg=="], + "@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.4.3", "", { "dependencies": { "@shikijs/types": "4.4.3", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.6" } }, "sha512-FbOjFJp9VLdo1Wevs10BBtVxiTWwNLqZh5Gkhjgda/ioL15YOgeSl9n+6XMa3qRlPQzfhFNe641SrynFHYG0nQ=="], - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.63.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-t4ZYOSoLTgwhuFMrmTMLx/+i1DQVK7HYqMc6kY46EApwi8X0nIVphzdNoThU3xt6n+N5urG1/gxBdCaKDLavfg=="], + "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.4.3", "", { "dependencies": { "@shikijs/types": "4.4.3", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-EcOQkxdxGQrc1Row/cC2c96/v1dbZqGnEVu1qTuT/MJmp6+cXCvQussowVmCv5Tqr3KuY3c7IbM6HTW3LJ1k9w=="], - "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.63.1", "", { "os": "win32", "cpu": "x64" }, "sha512-RgroPfMmKlD1RzSDxvwgcPiy2HNQKoYV7OmwIXDsk73uKW5t6B/V8KIy27SMv/FNXFo/oSBtWc9J0X7t91ezZg=="], + "@shikijs/langs": ["@shikijs/langs@4.4.3", "", { "dependencies": { "@shikijs/types": "4.4.3" } }, "sha512-ePic0yfAJGOF83D5wBHK/00EjK65oahBYxFk5epgq33WRv7X9UuxLEV8PtR0szC0z8dl7INIpIodB99JRFlR+A=="], - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.63.1", "", { "os": "win32", "cpu": "x64" }, "sha512-at8QVep6S3h5Y6gSbdGU06bRY5WJkf6WUduM9YtvYMbYhB1MOFfUgc6kehitQXzOtMSaT70q7f9ydPhpqu821w=="], + "@shikijs/primitive": ["@shikijs/primitive@4.4.3", "", { "dependencies": { "@shikijs/types": "4.4.3", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.5" } }, "sha512-m0wBeLDQDeIxRdUmrCPdQqfuUamDwRL5isCfYbguKD6NiaKpVbsv+3J81DyIKgNW5h4WAIIr8T4EkgQrBBxvaQ=="], - "@shikijs/core": ["@shikijs/core@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA=="], + "@shikijs/themes": ["@shikijs/themes@4.4.3", "", { "dependencies": { "@shikijs/types": "4.4.3" } }, "sha512-w8UHjeUnIR965KMWJHUPXOc2mNJUnK3vpVLYLvw5IYU2mnTTJ89E24OrJDBNiJDQ0qzb0tc4l7mrIXx5cFeIyw=="], - "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA=="], + "@shikijs/types": ["@shikijs/types@4.4.3", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.5" } }, "sha512-UEJxmRR++MAGR6hugn0vgVS2W/6lWAts84FFSrnlH9sP0LNol7E5+NQ792pH8liWUhyMyjhTgSUH3k7iD7tc5g=="], - "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g=="], - - "@shikijs/langs": ["@shikijs/langs@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg=="], - - "@shikijs/themes": ["@shikijs/themes@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA=="], + "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], - "@shikijs/types": ["@shikijs/types@3.23.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ=="], + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], - "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], + "@swc/helpers": ["@swc/helpers@0.5.23", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw=="], "@tailwindcss/node": ["@tailwindcss/node@4.3.3", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.24.1", "jiti": "^2.7.0", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.3" } }, "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg=="], @@ -314,105 +309,99 @@ "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.3.3", "", { "os": "win32", "cpu": "x64" }, "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw=="], - "@tailwindcss/vite": ["@tailwindcss/vite@4.3.3", "", { "dependencies": { "@tailwindcss/node": "4.3.3", "@tailwindcss/oxide": "4.3.3", "tailwindcss": "4.3.3" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw=="], - - "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], - - "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], - - "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], - - "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], + "@tailwindcss/postcss": ["@tailwindcss/postcss@4.3.3", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.3.3", "@tailwindcss/oxide": "4.3.3", "postcss": "^8.5.16", "tailwindcss": "4.3.3" } }, "sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg=="], "@types/debug": ["@types/debug@4.1.13", "", { "dependencies": { "@types/ms": "*" } }, "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw=="], "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], + "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], + "@types/hast": ["@types/hast@3.0.5", "", { "dependencies": { "@types/unist": "*" } }, "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g=="], "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], - "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], + "@types/mdx": ["@types/mdx@2.0.14", "", {}, "sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg=="], - "@types/nlcst": ["@types/nlcst@2.0.3", "", { "dependencies": { "@types/unist": "*" } }, "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA=="], + "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], - "@types/node": ["@types/node@22.20.2", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-xlvWf4Vs9n1PEVYwP1n4vvG07M6y8WgvJ2t0vbrWTmijsIHp1cS+uJ2kMIRdY3nHZK0nCYKrPeD171+SzF4/zw=="], + "@types/node": ["@types/node@26.5.1", "", { "dependencies": { "undici-types": "~8.9.0" } }, "sha512-CzNm2FezW4VR/LjG6yUdiEgLE/rAQ9Slj5gCu/C2VrdcW7I0ahNZ8DRbHT7zOZ6r3ONgd/bsQIeSaoDGrd1C6g=="], "@types/react": ["@types/react@19.3.0", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg=="], "@types/react-dom": ["@types/react-dom@19.3.0", "", { "peerDependencies": { "@types/react": "^19.3.0" } }, "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q=="], - "@types/sax": ["@types/sax@1.2.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A=="], - "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], "@ungap/structured-clone": ["@ungap/structured-clone@1.4.0", "", {}, "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ=="], - "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], + "@yuku-analyzer/binding-android-arm64": ["@yuku-analyzer/binding-android-arm64@0.9.5", "", { "os": "android", "cpu": "arm64" }, "sha512-Rvr0/EkPfPgc0C1wx8dz4bv6o4I4yeYI06tcHUL0f4ZdwSyIreABoLHNW51Ap0VNA7aDRVQ4izRNQh/LuykofA=="], - "@volar/kit": ["@volar/kit@2.4.28", "", { "dependencies": { "@volar/language-service": "2.4.28", "@volar/typescript": "2.4.28", "typesafe-path": "^0.2.2", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "typescript": "*" } }, "sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg=="], + "@yuku-analyzer/binding-darwin-arm64": ["@yuku-analyzer/binding-darwin-arm64@0.9.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-sh9DaXzkVmedM9aWvjCAAluRtvz/trk5VSosF7dPhqDf3IhrJW2DOh9iuA+YQzWSktP/ILsKfKili2UZ/ZjRzw=="], - "@volar/language-core": ["@volar/language-core@2.4.28", "", { "dependencies": { "@volar/source-map": "2.4.28" } }, "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ=="], + "@yuku-analyzer/binding-darwin-x64": ["@yuku-analyzer/binding-darwin-x64@0.9.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-qPKyWlGK92vjwwFdAKwGkfqF3rye4UR8X2WPvzhOSt/plATd2pPJFyMBhF1aclRMBNbk20YnctWYRYLS8FBgAg=="], - "@volar/language-server": ["@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.17.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" } }, "sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw=="], + "@yuku-analyzer/binding-freebsd-x64": ["@yuku-analyzer/binding-freebsd-x64@0.9.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-LeSbxDQ7k0WFyddM3BiFW3i55eSkWwi4hgG8PmqNBGL9dZ4sysYOwcy3We8vyxc/fyhuhc0CYxa6p6v14+UBow=="], - "@volar/language-service": ["@volar/language-service@2.4.28", "", { "dependencies": { "@volar/language-core": "2.4.28", "vscode-languageserver-protocol": "^3.17.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" } }, "sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw=="], + "@yuku-analyzer/binding-linux-arm-gnu": ["@yuku-analyzer/binding-linux-arm-gnu@0.9.5", "", { "os": "linux", "cpu": "arm" }, "sha512-GVtm5UmUhKMnicVz/Q4QgRr7OFyvxDrr7j9u0Mrgnisj/GmABhcFhzqVwW+rbS+EFnUHY7yIamwY2Fc3CoCTCw=="], - "@volar/source-map": ["@volar/source-map@2.4.28", "", {}, "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ=="], + "@yuku-analyzer/binding-linux-arm-musl": ["@yuku-analyzer/binding-linux-arm-musl@0.9.5", "", { "os": "linux", "cpu": "arm" }, "sha512-c/9lCWXRwp0eaAvbTZslrplIjaLhiFCdc5bF/hCV13HrYYyICSwEcCgx3/OEEpwfHpdQsqejhsntUKc/0Ylbfg=="], - "@volar/typescript": ["@volar/typescript@2.4.28", "", { "dependencies": { "@volar/language-core": "2.4.28", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw=="], + "@yuku-analyzer/binding-linux-arm64-gnu": ["@yuku-analyzer/binding-linux-arm64-gnu@0.9.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-BwZYDPfnuP9gh8KphdjClzN3XRV0smbc2nNGkxvSOEYB/uRW0e+S2Jh82QKMSCK5TptQfovmFWe55Z5lToLAfA=="], - "@vscode/emmet-helper": ["@vscode/emmet-helper@2.11.0", "", { "dependencies": { "emmet": "^2.4.3", "jsonc-parser": "^2.3.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.15.1", "vscode-uri": "^3.0.8" } }, "sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw=="], + "@yuku-analyzer/binding-linux-arm64-musl": ["@yuku-analyzer/binding-linux-arm64-musl@0.9.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-xglOsssSkPQGwendJdWud5maVWoM6h5SwlouStfg0eUACjxV8uLvnub2NT+euQJQMVzH3aRc5RuPPqzvMFeDTA=="], - "@vscode/l10n": ["@vscode/l10n@0.0.18", "", {}, "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ=="], + "@yuku-analyzer/binding-linux-x64-gnu": ["@yuku-analyzer/binding-linux-x64-gnu@0.9.5", "", { "os": "linux", "cpu": "x64" }, "sha512-X7J/LWSnNsyx1E4hv6CFofXQft4GMePfc4pDn00B4lG6BO3HNR/zGlYZ5ayQsxhRNLxtAlvSFSaguaSuyz6p6g=="], - "acorn": ["acorn@8.18.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ=="], + "@yuku-analyzer/binding-linux-x64-musl": ["@yuku-analyzer/binding-linux-x64-musl@0.9.5", "", { "os": "linux", "cpu": "x64" }, "sha512-gmi9vazzSs4PLpHjgkFLPGCDMzG7ths3mcip0qZEHhLwLJthH5PTA+LYKi+7FRKHNQT4A50RTVox5CjdUC+prw=="], - "ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], + "@yuku-analyzer/binding-win32-arm64": ["@yuku-analyzer/binding-win32-arm64@0.9.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-0iKC5sGOCrFqumzSHLv2qCQa0OTytK605dSJrdHah5CoLT13oStEfk3jwNltYB77J3BiSagg896d5YmTY8HQPA=="], - "ajv-draft-04": ["ajv-draft-04@1.0.0", "", { "peerDependencies": { "ajv": "^8.5.0" }, "optionalPeers": ["ajv"] }, "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw=="], + "@yuku-analyzer/binding-win32-x64": ["@yuku-analyzer/binding-win32-x64@0.9.5", "", { "os": "win32", "cpu": "x64" }, "sha512-dSb5o6D9JugPmKRsjVLDLpgHRdSd1oCvNhY6AP6+OCzMwn0kbiNxhf2DwXYtt4xIBjliYQnw+ZsvIy1d0lHtSg=="], - "ajv-i18n": ["ajv-i18n@4.2.0", "", { "peerDependencies": { "ajv": "^8.0.0-beta.0" } }, "sha512-v/ei2UkCEeuKNXh8RToiFsUclmU+G57LO1Oo22OagNMENIw+Yb8eMwvHu7Vn9fmkjJyv6XclhJ8TbuigSglPkg=="], + "@yuku-toolchain/types": ["@yuku-toolchain/types@0.9.5", "", {}, "sha512-KiuLNNgX9uNealaWAR+G3/cMXnRk9x4TY2EkYe/KIag+UPdwiA0RRf1hr1WAxzTP8KGzCTkqUdLPvqh32sEO3w=="], - "ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="], + "@zeit/schemas": ["@zeit/schemas@2.36.0", "", {}, "sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg=="], - "ansi-regex": ["ansi-regex@6.3.0", "", {}, "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ=="], + "acorn": ["acorn@8.18.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ=="], - "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], - "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + "ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="], - "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], + "ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="], - "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + "ansi-regex": ["ansi-regex@6.3.0", "", {}, "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ=="], - "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], + "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], - "array-iterate": ["array-iterate@2.0.1", "", {}, "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg=="], + "arch": ["arch@2.2.0", "", {}, "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ=="], - "astro": ["astro@5.18.2", "", { "dependencies": { "@astrojs/compiler": "^2.13.0", "@astrojs/internal-helpers": "0.7.6", "@astrojs/markdown-remark": "6.3.11", "@astrojs/telemetry": "3.3.0", "@capsizecss/unpack": "^4.0.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.3.0", "acorn": "^8.15.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.3.1", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^1.1.1", "cssesc": "^3.0.0", "debug": "^4.4.3", "deterministic-object-hash": "^2.0.2", "devalue": "^5.6.2", "diff": "^8.0.3", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.7.0", "esbuild": "^0.27.3", "estree-walker": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.4.0", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "magic-string": "^0.30.21", "magicast": "^0.5.1", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.1", "package-manager-detector": "^1.6.0", "piccolore": "^0.1.3", "picomatch": "^4.0.3", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.3", "shiki": "^3.21.0", "smol-toml": "^1.6.0", "svgo": "^4.0.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", "unifont": "~0.7.3", "unist-util-visit": "^5.0.0", "unstorage": "^1.17.4", "vfile": "^6.0.3", "vite": "^6.4.1", "vitefu": "^1.1.1", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.3", "zod": "^3.25.76", "zod-to-json-schema": "^3.25.1", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.34.0" }, "bin": { "astro": "astro.js" } }, "sha512-TnFwLnAXty5MXKPDGuKXqK4AMBXG+FH6RUdK7Oyc3gyfNoFIthT+4eRbzOK43bdRlLaZuxgciDSjgtggZ3OtGQ=="], + "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], - "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], + "astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="], "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], - "base-64": ["base-64@1.0.0", "", {}, "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="], + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "baseline-browser-mapping": ["baseline-browser-mapping@2.11.21", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ=="], - "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + "boxen": ["boxen@7.0.0", "", { "dependencies": { "ansi-align": "^3.0.1", "camelcase": "^7.0.0", "chalk": "^5.0.1", "cli-boxes": "^3.0.0", "string-width": "^5.1.2", "type-fest": "^2.13.0", "widest-line": "^4.0.1", "wrap-ansi": "^8.0.1" } }, "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg=="], - "boxen": ["boxen@8.0.1", "", { "dependencies": { "ansi-align": "^3.0.1", "camelcase": "^8.0.0", "chalk": "^5.3.0", "cli-boxes": "^3.0.0", "string-width": "^7.2.0", "type-fest": "^4.21.0", "widest-line": "^5.0.0", "wrap-ansi": "^9.0.0" } }, "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw=="], + "brace-expansion": ["brace-expansion@1.1.18", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw=="], - "browserslist": ["browserslist@4.28.9", "", { "dependencies": { "baseline-browser-mapping": "^2.11.20", "caniuse-lite": "^1.0.30001810", "electron-to-chromium": "^1.5.420", "node-releases": "^2.0.54", "update-browserslist-db": "^1.3.2" }, "bin": { "browserslist": "cli.js" } }, "sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg=="], + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], - "camelcase": ["camelcase@8.0.0", "", {}, "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA=="], + "camelcase": ["camelcase@7.0.1", "", {}, "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw=="], "caniuse-lite": ["caniuse-lite@1.0.30001810", "", {}, "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg=="], "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], - "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + "chalk": ["chalk@5.0.1", "", {}, "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w=="], + + "chalk-template": ["chalk-template@0.4.0", "", { "dependencies": { "chalk": "^4.1.2" } }, "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg=="], "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], @@ -420,97 +409,91 @@ "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], - "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + "character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="], - "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], + "chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], "cli-boxes": ["cli-boxes@3.0.0", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="], - "cliui": ["cliui@9.0.1", "", { "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w=="], + "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], - "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + "clipboardy": ["clipboardy@3.0.0", "", { "dependencies": { "arch": "^2.2.0", "execa": "^5.1.1", "is-wsl": "^2.2.0" } }, "sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg=="], - "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], - "commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], + "cnfast": ["cnfast@0.1.0", "", { "bin": { "cnfast": "bin/cli.js" } }, "sha512-rH0jBKeLkVrK7NsZ5Ba2l7WdMBmm1k0FMpABeXUU1PgTUxbz3261gEuCSsrYuXo4BwAe3yCcIbQ93YyS52lOGQ=="], - "common-ancestor-path": ["common-ancestor-path@1.0.1", "", {}, "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="], + "collapse-white-space": ["collapse-white-space@2.1.0", "", {}, "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw=="], - "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - "cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - "cookie-es": ["cookie-es@1.2.3", "", {}, "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw=="], + "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], - "crossws": ["crossws@0.3.5", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA=="], + "compressible": ["compressible@2.0.18", "", { "dependencies": { "mime-db": ">= 1.43.0 < 2" } }, "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg=="], - "css-select": ["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" } }, "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw=="], + "compression": ["compression@1.8.1", "", { "dependencies": { "bytes": "3.1.2", "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", "on-headers": "~1.1.0", "safe-buffer": "5.2.1", "vary": "~1.1.2" } }, "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w=="], - "css-tree": ["css-tree@3.2.1", "", { "dependencies": { "mdn-data": "2.27.1", "source-map-js": "^1.2.1" } }, "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA=="], + "compute-scroll-into-view": ["compute-scroll-into-view@3.1.1", "", {}, "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw=="], - "css-what": ["css-what@7.0.0", "", {}, "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ=="], + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], - "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], + "content-disposition": ["content-disposition@0.5.2", "", {}, "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA=="], - "csso": ["csso@5.0.5", "", { "dependencies": { "css-tree": "~2.2.0" } }, "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ=="], + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], - "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="], - "defu": ["defu@6.1.7", "", {}, "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="], + "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], - "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="], - "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], - "deterministic-object-hash": ["deterministic-object-hash@2.0.2", "", { "dependencies": { "base-64": "^1.0.0" } }, "sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ=="], - - "devalue": ["devalue@5.9.2", "", {}, "sha512-po4PAY5c53tw5XMocSnf8A/5OHhbbUftpr93aEN6BBoAdntUmK7vu7wOATqvt7cXO7m1Cl4gMVn6p7n6n4mj0w=="], + "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], - "diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], - - "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="], + "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], - "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], - "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + "enhanced-resolve": ["enhanced-resolve@5.24.5", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A=="], - "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], - "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + "esast-util-from-estree": ["esast-util-from-estree@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", "estree-util-visit": "^2.0.0", "unist-util-position-from-estree": "^2.0.0" } }, "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ=="], - "dset": ["dset@3.1.4", "", {}, "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA=="], + "esast-util-from-js": ["esast-util-from-js@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "acorn": "^8.0.0", "esast-util-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw=="], - "electron-to-chromium": ["electron-to-chromium@1.5.426", "", {}, "sha512-2Gcq6inCQs/AqfHP3f5ftCzk+pqeW2VlA1LgmPqEj2hfBO8HiZRspNYkD4HzFBe4u6lGqca4BspFr6Ix4Q400g=="], + "esbuild": ["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" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="], - "emmet": ["emmet@2.4.11", "", { "dependencies": { "@emmetio/abbreviation": "^2.3.3", "@emmetio/css-abbreviation": "^2.1.8" } }, "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ=="], + "escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], - "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + "estree-util-attach-comments": ["estree-util-attach-comments@3.0.0", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw=="], - "enhanced-resolve": ["enhanced-resolve@5.24.5", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A=="], + "estree-util-build-jsx": ["estree-util-build-jsx@3.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-walker": "^3.0.0" } }, "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ=="], - "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + "estree-util-is-identifier-name": ["estree-util-is-identifier-name@3.0.0", "", {}, "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg=="], - "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], + "estree-util-scope": ["estree-util-scope@1.0.1", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0" } }, "sha512-B0np3dcdxqILX5e9nEi5/Fr4K7gL4oYFVPV1zRa2e9wRCbQoZZNWOZFYyoInvXUPJXBXjss+QXlWLJChDEHDkA=="], - "esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], + "estree-util-to-js": ["estree-util-to-js@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "astring": "^1.8.0", "source-map": "^0.7.0" } }, "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg=="], - "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "estree-util-value-to-estree": ["estree-util-value-to-estree@3.5.0", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-aMV56R27Gv3QmfmF1MY12GWkGzzeAezAX+UplqHVASfjc9wNzI/X6hC0S9oxq61WT4aQesLGslWP9tKk6ghRZQ=="], - "escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + "estree-util-visit": ["estree-util-visit@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/unist": "^3.0.0" } }, "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww=="], "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], - "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], + "execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], @@ -520,81 +503,75 @@ "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], - "flattie": ["flattie@1.1.1", "", {}, "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ=="], + "framer-motion": ["framer-motion@13.2.0", "", { "dependencies": { "motion-dom": "^13.2.0", "motion-utils": "^13.0.0", "tslib": "^2.4.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-9E33ebgMaO33w1nN/jEdW8z3/GO483fMi4rqbMG9rt83XgW9QLKRe4NcmJ8s+fQ3O34++UHrIQwlIWGIWTITjA=="], - "fontace": ["fontace@0.4.1", "", { "dependencies": { "fontkitten": "^1.0.2" } }, "sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw=="], + "fumadocs-core": ["fumadocs-core@16.15.4", "", { "dependencies": { "@fumari/image-size": "^0.1.0", "estree-util-value-to-estree": "^3.5.0", "github-slugger": "^2.0.0", "hast-util-to-estree": "^3.1.3", "hast-util-to-jsx-runtime": "^2.3.6", "mdast-util-mdx": "^3.0.0", "mdast-util-to-markdown": "^2.1.2", "npm-to-yarn": "3.2.0", "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-rehype": "^11.1.2", "scroll-into-view-if-needed": "^3.1.0", "shiki": "^4.4.3", "tinyglobby": "^0.2.17", "unified": "^11.0.5", "unist-util-visit": "^5.1.0", "vfile": "^6.0.3", "yaml": "^2.9.0", "zbsearch": "^4.0.0" }, "peerDependencies": { "@mdx-js/mdx": "*", "@mixedbread/sdk": "0.x.x", "@orama/core": "1.x.x", "@oramacloud/client": "2.x.x", "@tanstack/react-router": "1.x.x", "@types/estree-jsx": "*", "@types/hast": "*", "@types/mdast": "*", "@types/react": "*", "algoliasearch": "5.x.x", "flexsearch": "*", "lucide-react": "*", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "react-router": "7.x.x || 8.x.x", "waku": "*", "zod": "4.x.x" }, "optionalPeers": ["@mdx-js/mdx", "@mixedbread/sdk", "@orama/core", "@oramacloud/client", "@tanstack/react-router", "@types/estree-jsx", "@types/hast", "@types/mdast", "@types/react", "algoliasearch", "flexsearch", "lucide-react", "next", "react", "react-dom", "react-router", "waku", "zod"] }, "sha512-kdOuM0tvHkLWajnDu73BmtryPuUq4xsu610ssl1YMAm9fYF7BRmvYxx2apHbyf2Lt+7w8OEiWDTmB8Ja3zqp4Q=="], - "fontkitten": ["fontkitten@1.0.3", "", { "dependencies": { "tiny-inflate": "^1.0.3" } }, "sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw=="], + "fumadocs-mdx": ["fumadocs-mdx@15.4.0", "", { "dependencies": { "@mdx-js/mdx": "^3.1.1", "@standard-schema/spec": "^1.1.0", "chokidar": "^5.0.0", "esbuild": "^0.28.2", "estree-util-value-to-estree": "^3.5.0", "github-slugger": "^2.0.0", "magic-string": "^1.2.2", "mdast-util-mdx": "^3.0.0", "picocolors": "^1.1.1", "picomatch": "^4.0.7", "tinyexec": "^1.3.0", "tinyglobby": "^0.2.17", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.1.0", "vfile": "^6.0.3", "yaml": "^2.9.0", "yuku-analyzer": "^0.9.1", "zod": "^4.4.3" }, "peerDependencies": { "@fumadocs/satteri": "0.x.x", "@types/mdast": "*", "@types/mdx": "*", "@types/react": "*", "fumadocs-core": "^16.15.3", "mdast-util-directive": "*", "next": "^15.3.0 || ^16.0.0", "react": "^19.2.0", "rolldown": "*", "satteri": "^0.10.5", "vite": "7.x.x || 8.x.x" }, "optionalPeers": ["@fumadocs/satteri", "@types/mdast", "@types/mdx", "@types/react", "mdast-util-directive", "next", "react", "rolldown", "satteri", "vite"], "bin": { "fumadocs-mdx": "./bin.js" } }, "sha512-bJCQfsckKUQ4x2pyz8OdASEAARVMB49kOej7njaJ3t+tYsP1HnwkmqiO8e/jdQHcv6JH3XkXWidTho3ZC/WBcA=="], - "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + "fumadocs-ui": ["@fumadocs/base-ui@16.15.4", "", { "dependencies": { "@base-ui/react": "^1.7.0", "@fuma-translate/react": "^1.0.2", "@fumadocs/tailwind": "0.1.1", "class-variance-authority": "^0.7.1", "cnfast": "^0.1.0", "lucide-react": "^1.34.0", "motion": "^13.1.1", "next-themes": "^0.4.6", "react-remove-scroll": "^2.7.2", "rehype-raw": "^7.0.0", "scroll-into-view-if-needed": "^3.1.0", "shiki": "^4.4.3", "unist-util-visit": "^5.1.0" }, "peerDependencies": { "@types/mdx": "*", "@types/react": "*", "fumadocs-core": "16.15.4", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "takumi-js": "*" }, "optionalPeers": ["@types/mdx", "@types/react", "next", "takumi-js"] }, "sha512-BcoUPoSbfX/uaUl2NgPn0IKOjqJCkwsWPP6z5uRlKSEdh4zbImwXf3k6+qJ3ULlVaFEY8hqfR2wn+Ya5vPKKEQ=="], - "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], - "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], - - "get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="], + "get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "h3": ["h3@1.15.11", "", { "dependencies": { "cookie-es": "^1.2.3", "crossws": "^0.3.5", "defu": "^6.1.6", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.4", "radix3": "^1.1.2", "ufo": "^1.6.3", "uncrypto": "^0.1.3" } }, "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg=="], - - "hast-util-from-html": ["hast-util-from-html@2.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "devlop": "^1.1.0", "hast-util-from-parse5": "^8.0.0", "parse5": "^7.0.0", "vfile": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw=="], + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], "hast-util-from-parse5": ["hast-util-from-parse5@8.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "hastscript": "^9.0.0", "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" } }, "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg=="], - "hast-util-is-element": ["hast-util-is-element@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g=="], - "hast-util-parse-selector": ["hast-util-parse-selector@4.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A=="], "hast-util-raw": ["hast-util-raw@9.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "@ungap/structured-clone": "^1.0.0", "hast-util-from-parse5": "^8.0.0", "hast-util-to-parse5": "^8.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "parse5": "^7.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0", "web-namespaces": "^2.0.0", "zwitch": "^2.0.0" } }, "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw=="], + "hast-util-to-estree": ["hast-util-to-estree@3.1.3", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.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.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w=="], + "hast-util-to-html": ["hast-util-to-html@9.0.5", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "stringify-entities": "^4.0.0", "zwitch": "^2.0.4" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="], - "hast-util-to-parse5": ["hast-util-to-parse5@8.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "web-namespaces": "^2.0.0", "zwitch": "^2.0.0" } }, "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA=="], + "hast-util-to-jsx-runtime": ["hast-util-to-jsx-runtime@2.3.6", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "hast-util-whitespace": "^3.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "vfile-message": "^4.0.0" } }, "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg=="], - "hast-util-to-text": ["hast-util-to-text@4.0.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "hast-util-is-element": "^3.0.0", "unist-util-find-after": "^5.0.0" } }, "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A=="], + "hast-util-to-parse5": ["hast-util-to-parse5@8.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "web-namespaces": "^2.0.0", "zwitch": "^2.0.0" } }, "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA=="], "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="], "hastscript": ["hastscript@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" } }, "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w=="], - "html-escaper": ["html-escaper@3.0.3", "", {}, "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ=="], - "html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="], - "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="], + "human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], - "import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="], + "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], - "iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="], + "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], - "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], + "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="], - "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + "is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="], - "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], + "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], - "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], + "is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], - "is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="], + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], - "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], + "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="], - "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], - "js-yaml": ["js-yaml@4.3.2", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA=="], + "is-port-reachable": ["is-port-reachable@4.0.0", "", {}, "sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig=="], - "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], - "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + "is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], - "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - "jsonc-parser": ["jsonc-parser@2.3.1", "", {}, "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg=="], + "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], - "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], @@ -622,18 +599,14 @@ "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], - "lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], - - "lucide-react": ["lucide-react@0.460.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" } }, "sha512-BVtq/DykVeIvRTJvRAgCsOwaGL8Un3Bxh8MbDxMhEWlZay3T4IpEKDEpwt5KZ0KJMHzgm6jrltxlT5eXOWXDHg=="], + "lucide-react": ["lucide-react@1.44.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-2egNApH4hX4j/qdCgRublh88+9u3mEhz9iSlW5ckm4kaQEqZbXbMr0l5u5JZLy8nmWRx2dbHGQkEDYz6C9aCgw=="], - "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + "magic-string": ["magic-string@1.3.1", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.6.0" } }, "sha512-rm91zr2Ou+XueDTohjQQjdQEcYM6zVi8KVUCG8Ec3vHwUEKrhSdCNyfuIywkA6hcCAteIn0ZOtAHA6eGpiX+Pg=="], - "magicast": ["magicast@0.5.4", "", { "dependencies": { "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7", "source-map-js": "^1.2.1" } }, "sha512-llBEhWm1SacoRwgHUoQJYtwp4PBLF4faQi5TCpIGyGs9n4y5+juI0tDgyKIfpqxckRHaHzouUEph3THklWh03w=="], + "markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="], "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], - "mdast-util-definitions": ["mdast-util-definitions@6.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ=="], - "mdast-util-find-and-replace": ["mdast-util-find-and-replace@3.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "escape-string-regexp": "^5.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg=="], "mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.3", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q=="], @@ -650,6 +623,14 @@ "mdast-util-gfm-task-list-item": ["mdast-util-gfm-task-list-item@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ=="], + "mdast-util-mdx": ["mdast-util-mdx@3.0.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w=="], + + "mdast-util-mdx-expression": ["mdast-util-mdx-expression@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ=="], + + "mdast-util-mdx-jsx": ["mdast-util-mdx-jsx@3.2.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" } }, "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q=="], + + "mdast-util-mdxjs-esm": ["mdast-util-mdxjs-esm@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg=="], + "mdast-util-phrasing": ["mdast-util-phrasing@4.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" } }, "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w=="], "mdast-util-to-hast": ["mdast-util-to-hast@13.2.1", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA=="], @@ -658,7 +639,7 @@ "mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="], - "mdn-data": ["mdn-data@2.27.1", "", {}, "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ=="], + "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], "micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="], @@ -678,10 +659,22 @@ "micromark-extension-gfm-task-list-item": ["micromark-extension-gfm-task-list-item@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw=="], + "micromark-extension-mdx-expression": ["micromark-extension-mdx-expression@3.0.1", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q=="], + + "micromark-extension-mdx-jsx": ["micromark-extension-mdx-jsx@3.0.2", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ=="], + + "micromark-extension-mdx-md": ["micromark-extension-mdx-md@2.0.0", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ=="], + + "micromark-extension-mdxjs": ["micromark-extension-mdxjs@3.0.0", "", { "dependencies": { "acorn": "^8.0.0", "acorn-jsx": "^5.0.0", "micromark-extension-mdx-expression": "^3.0.0", "micromark-extension-mdx-jsx": "^3.0.0", "micromark-extension-mdx-md": "^2.0.0", "micromark-extension-mdxjs-esm": "^3.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ=="], + + "micromark-extension-mdxjs-esm": ["micromark-extension-mdxjs-esm@3.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-position-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A=="], + "micromark-factory-destination": ["micromark-factory-destination@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA=="], "micromark-factory-label": ["micromark-factory-label@2.0.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg=="], + "micromark-factory-mdx-expression": ["micromark-factory-mdx-expression@2.0.3", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-position-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ=="], + "micromark-factory-space": ["micromark-factory-space@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg=="], "micromark-factory-title": ["micromark-factory-title@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw=="], @@ -702,6 +695,8 @@ "micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="], + "micromark-util-events-to-acorn": ["micromark-util-events-to-acorn@2.0.3", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "estree-util-visit": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg=="], + "micromark-util-html-tag-name": ["micromark-util-html-tag-name@2.0.1", "", {}, "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA=="], "micromark-util-normalize-identifier": ["micromark-util-normalize-identifier@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q=="], @@ -716,51 +711,55 @@ "micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="], - "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "mime-types": ["mime-types@2.1.18", "", { "dependencies": { "mime-db": "~1.33.0" } }, "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ=="], - "muggle-string": ["muggle-string@0.4.1", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="], + "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], - "nanoid": ["nanoid@3.3.18", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w=="], + "minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], - "neotraverse": ["neotraverse@0.6.18", "", {}, "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="], + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], - "nlcst-to-string": ["nlcst-to-string@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0" } }, "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA=="], + "motion": ["motion@13.2.0", "", { "dependencies": { "framer-motion": "^13.2.0", "tslib": "^2.4.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-4Hrb5vD6HhjFstLUiCmWvtpsw+WTpP4R+QXfSDYZBz7+uxE/LrRg3aV0ReJxHrTRffHhbIE6svEqnotngXvesQ=="], - "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], + "motion-dom": ["motion-dom@13.2.0", "", { "dependencies": { "motion-utils": "^13.0.0" } }, "sha512-N6gdSoWRDk0Rh/fVtlqUtLs+fEN3ELFZI3cn3IQE9Mnf3E+Mh8wjO6MstzCOPFh4Yf0L1as5m2eUyYWj8ylVSQ=="], - "node-mock-http": ["node-mock-http@1.0.5", "", {}, "sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw=="], + "motion-utils": ["motion-utils@13.0.0", "", {}, "sha512-7DnN7TmbLcYXcG4RVadXIihWlyuM9afoUww8Y5Agg431kGKiuL2/OMyP4mJ5wLz+pvN3t5ySClLOaVXJ+wekRQ=="], - "node-releases": ["node-releases@2.0.55", "", {}, "sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ=="], + "ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + "nanoid": ["nanoid@3.3.18", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w=="], - "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + "negotiator": ["negotiator@0.6.4", "", {}, "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w=="], - "ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="], + "next": ["next@16.3.3", "", { "dependencies": { "@next/env": "16.3.3", "@swc/helpers": "0.5.23", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.5.23", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.3.3", "@next/swc-darwin-x64": "16.3.3", "@next/swc-linux-arm64-gnu": "16.3.3", "@next/swc-linux-arm64-musl": "16.3.3", "@next/swc-linux-x64-gnu": "16.3.3", "@next/swc-linux-x64-musl": "16.3.3", "@next/swc-win32-arm64-msvc": "16.3.3", "@next/swc-win32-x64-msvc": "16.3.3", "sharp": "^0.35.3" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-tuRTx1nQ/yVw83cwJBo9F+njGUgMn3UHQycreWHB8XsStvvAh1AthbI8/4IpKnFaF58F+iSiHejYOlMQ/eq83g=="], - "ohash": ["ohash@2.0.12", "", {}, "sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw=="], + "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], - "oniguruma-parser": ["oniguruma-parser@0.12.2", "", {}, "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw=="], + "npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="], - "oniguruma-to-es": ["oniguruma-to-es@4.3.6", "", { "dependencies": { "oniguruma-parser": "^0.12.2", "regex": "^6.1.0", "regex-recursion": "^6.0.2" } }, "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA=="], + "npm-to-yarn": ["npm-to-yarn@3.2.0", "", {}, "sha512-K1HmQeZT2HrjpsR6KgqbN2FAXL2NrJJmNUSD9ck7HGTVu1JKXox8n9SB+tjbU8m8JGLF4OscrroPepew/L7/Xw=="], + + "on-headers": ["on-headers@1.1.0", "", {}, "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A=="], - "p-limit": ["p-limit@6.2.0", "", { "dependencies": { "yocto-queue": "^1.1.1" } }, "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA=="], + "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], - "p-queue": ["p-queue@8.1.1", "", { "dependencies": { "eventemitter3": "^5.0.1", "p-timeout": "^6.1.2" } }, "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ=="], + "oniguruma-parser": ["oniguruma-parser@0.12.2", "", {}, "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw=="], - "p-timeout": ["p-timeout@6.1.4", "", {}, "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg=="], + "oniguruma-to-es": ["oniguruma-to-es@4.3.6", "", { "dependencies": { "oniguruma-parser": "^0.12.2", "regex": "^6.1.0", "regex-recursion": "^6.0.2" } }, "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA=="], - "package-manager-detector": ["package-manager-detector@1.8.0", "", {}, "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A=="], + "oxlint": ["oxlint@1.82.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.82.0", "@oxlint/binding-android-arm64": "1.82.0", "@oxlint/binding-darwin-arm64": "1.82.0", "@oxlint/binding-darwin-x64": "1.82.0", "@oxlint/binding-freebsd-x64": "1.82.0", "@oxlint/binding-linux-arm-gnueabihf": "1.82.0", "@oxlint/binding-linux-arm-musleabihf": "1.82.0", "@oxlint/binding-linux-arm64-gnu": "1.82.0", "@oxlint/binding-linux-arm64-musl": "1.82.0", "@oxlint/binding-linux-ppc64-gnu": "1.82.0", "@oxlint/binding-linux-riscv64-gnu": "1.82.0", "@oxlint/binding-linux-riscv64-musl": "1.82.0", "@oxlint/binding-linux-s390x-gnu": "1.82.0", "@oxlint/binding-linux-x64-gnu": "1.82.0", "@oxlint/binding-linux-x64-musl": "1.82.0", "@oxlint/binding-openharmony-arm64": "1.82.0", "@oxlint/binding-win32-arm64-msvc": "1.82.0", "@oxlint/binding-win32-ia32-msvc": "1.82.0", "@oxlint/binding-win32-x64-msvc": "1.82.0" }, "peerDependencies": { "oxlint-tsgolint": ">=7.0.2001", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-+iFM1BGw1ntYJt3QngbJmjbrGxPaKMUADOXOijpWGnYcBPq8YZnQftSS1C+pVcDYy9YxqDVJKQqQkTazTQMboQ=="], - "parse-latin": ["parse-latin@7.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "@types/unist": "^3.0.0", "nlcst-to-string": "^4.0.0", "unist-util-modify-children": "^4.0.0", "unist-util-visit-children": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ=="], + "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], - "path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="], + "path-is-inside": ["path-is-inside@1.0.2", "", {}, "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], - "piccolore": ["piccolore@0.1.3", "", {}, "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw=="], + "path-to-regexp": ["path-to-regexp@3.3.0", "", {}, "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw=="], "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], @@ -768,23 +767,31 @@ "postcss": ["postcss@8.5.28", "", { "dependencies": { "nanoid": "^3.3.18", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A=="], - "prettier": ["prettier@3.9.6", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g=="], - - "prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="], - - "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="], - "property-information": ["property-information@7.2.0", "", {}, "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg=="], - "radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="], + "range-parser": ["range-parser@1.2.0", "", {}, "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A=="], + + "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], "react": ["react@19.3.0", "", {}, "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog=="], "react-dom": ["react-dom@19.3.0", "", { "dependencies": { "scheduler": "^0.28.0" }, "peerDependencies": { "react": "^19.3.0" } }, "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q=="], - "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="], + "react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], + + "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], + + "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], - "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + "readdirp": ["readdirp@5.1.1", "", {}, "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA=="], + + "recma-build-jsx": ["recma-build-jsx@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-build-jsx": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew=="], + + "recma-jsx": ["recma-jsx@1.0.1", "", { "dependencies": { "acorn-jsx": "^5.0.0", "estree-util-to-js": "^2.0.0", "recma-parse": "^1.0.0", "recma-stringify": "^1.0.0", "unified": "^11.0.0" }, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w=="], + + "recma-parse": ["recma-parse@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "esast-util-from-js": "^2.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ=="], + + "recma-stringify": ["recma-stringify@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-to-js": "^2.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g=="], "regex": ["regex@6.1.0", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="], @@ -792,74 +799,80 @@ "regex-utilities": ["regex-utilities@2.3.0", "", {}, "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="], - "rehype": ["rehype@13.0.2", "", { "dependencies": { "@types/hast": "^3.0.0", "rehype-parse": "^9.0.0", "rehype-stringify": "^10.0.0", "unified": "^11.0.0" } }, "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A=="], + "registry-auth-token": ["registry-auth-token@3.3.2", "", { "dependencies": { "rc": "^1.1.6", "safe-buffer": "^5.0.1" } }, "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ=="], - "rehype-parse": ["rehype-parse@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-from-html": "^2.0.0", "unified": "^11.0.0" } }, "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag=="], + "registry-url": ["registry-url@3.1.0", "", { "dependencies": { "rc": "^1.0.1" } }, "sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA=="], "rehype-raw": ["rehype-raw@7.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-raw": "^9.0.0", "vfile": "^6.0.0" } }, "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww=="], - "rehype-stringify": ["rehype-stringify@10.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-to-html": "^9.0.0", "unified": "^11.0.0" } }, "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA=="], + "rehype-recma": ["rehype-recma@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "hast-util-to-estree": "^3.0.0" } }, "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw=="], + + "remark": ["remark@15.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A=="], "remark-gfm": ["remark-gfm@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", "micromark-extension-gfm": "^3.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg=="], + "remark-mdx": ["remark-mdx@3.1.1", "", { "dependencies": { "mdast-util-mdx": "^3.0.0", "micromark-extension-mdxjs": "^3.0.0" } }, "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg=="], + "remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "micromark-util-types": "^2.0.0", "unified": "^11.0.0" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="], "remark-rehype": ["remark-rehype@11.1.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "mdast-util-to-hast": "^13.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw=="], - "remark-smartypants": ["remark-smartypants@3.0.3", "", { "dependencies": { "retext": "^9.0.0", "retext-smartypants": "^6.0.0", "unified": "^11.0.4", "unist-util-visit": "^5.0.0" } }, "sha512-gCaK+ndZ0hYezlqFegHFCVh2CQemsi0Npdh1qVM9bxlUFknjkbP6VmojWhddOCrbK0PbbacmYLWfTULRiT1eWA=="], - "remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="], - "request-light": ["request-light@0.7.0", "", {}, "sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q=="], - "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], - "retext": ["retext@9.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "retext-latin": "^4.0.0", "retext-stringify": "^4.0.0", "unified": "^11.0.0" } }, "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA=="], + "reselect": ["reselect@5.3.0", "", {}, "sha512-XGoLeRAVzUTcJ1qkxPQhDJyIZ5d6zzZD9nT7AEZOaaU9UbWclhycElmhO+VD5bFeLuzhPBaOV2oXC8uG35ZSpg=="], - "retext-latin": ["retext-latin@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "parse-latin": "^7.0.0", "unified": "^11.0.0" } }, "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA=="], + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], - "retext-smartypants": ["retext-smartypants@6.2.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ=="], + "scheduler": ["scheduler@0.28.0", "", {}, "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw=="], - "retext-stringify": ["retext-stringify@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", "unified": "^11.0.0" } }, "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA=="], + "scroll-into-view-if-needed": ["scroll-into-view-if-needed@3.1.0", "", { "dependencies": { "compute-scroll-into-view": "^3.0.2" } }, "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ=="], - "rollup": ["rollup@4.63.1", "", { "dependencies": { "@types/estree": "1.0.9" }, "optionalDependencies": { "@napi-rs/lzma-linux-x64-gnu": "1.5.1", "@rollup/rollup-android-arm-eabi": "4.63.1", "@rollup/rollup-android-arm64": "4.63.1", "@rollup/rollup-darwin-arm64": "4.63.1", "@rollup/rollup-darwin-x64": "4.63.1", "@rollup/rollup-freebsd-arm64": "4.63.1", "@rollup/rollup-freebsd-x64": "4.63.1", "@rollup/rollup-linux-arm-gnueabihf": "4.63.1", "@rollup/rollup-linux-arm-musleabihf": "4.63.1", "@rollup/rollup-linux-arm64-gnu": "4.63.1", "@rollup/rollup-linux-arm64-musl": "4.63.1", "@rollup/rollup-linux-loong64-gnu": "4.63.1", "@rollup/rollup-linux-loong64-musl": "4.63.1", "@rollup/rollup-linux-ppc64-gnu": "4.63.1", "@rollup/rollup-linux-ppc64-musl": "4.63.1", "@rollup/rollup-linux-riscv64-gnu": "4.63.1", "@rollup/rollup-linux-riscv64-musl": "4.63.1", "@rollup/rollup-linux-s390x-gnu": "4.63.1", "@rollup/rollup-linux-x64-gnu": "4.63.1", "@rollup/rollup-linux-x64-musl": "4.63.1", "@rollup/rollup-openbsd-x64": "4.63.1", "@rollup/rollup-openharmony-arm64": "4.63.1", "@rollup/rollup-win32-arm64-msvc": "4.63.1", "@rollup/rollup-win32-ia32-msvc": "4.63.1", "@rollup/rollup-win32-x64-gnu": "4.63.1", "@rollup/rollup-win32-x64-msvc": "4.63.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-3Df9jsstwhccuEfmAMi9l8XUh/GOkVObmFTU7CCVBysEbcOZLl84jCtaAZMcPiMz2EGKsATzQcU+Xr3n/wU6cg=="], + "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - "sax": ["sax@1.6.1", "", {}, "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q=="], + "serve": ["serve@14.2.6", "", { "dependencies": { "@zeit/schemas": "2.36.0", "ajv": "8.18.0", "arg": "5.0.2", "boxen": "7.0.0", "chalk": "5.0.1", "chalk-template": "0.4.0", "clipboardy": "3.0.0", "compression": "1.8.1", "is-port-reachable": "4.0.0", "serve-handler": "6.1.7", "update-check": "1.5.4" }, "bin": { "serve": "build/main.js" } }, "sha512-QEjUSA+sD4Rotm1znR8s50YqA3kYpRGPmtd5GlFxbaL9n/FdUNbqMhxClqdditSk0LlZyA/dhud6XNRTOC9x2Q=="], - "scheduler": ["scheduler@0.28.0", "", {}, "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw=="], + "serve-handler": ["serve-handler@6.1.7", "", { "dependencies": { "bytes": "3.0.0", "content-disposition": "0.5.2", "mime-types": "2.1.18", "minimatch": "3.1.5", "path-is-inside": "1.0.2", "path-to-regexp": "3.3.0", "range-parser": "1.2.0" } }, "sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg=="], - "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + "sharp": ["sharp@0.35.4", "", { "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" }, "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA=="], - "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], - "shiki": ["shiki@3.23.0", "", { "dependencies": { "@shikijs/core": "3.23.0", "@shikijs/engine-javascript": "3.23.0", "@shikijs/engine-oniguruma": "3.23.0", "@shikijs/langs": "3.23.0", "@shikijs/themes": "3.23.0", "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA=="], + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], - "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], + "shiki": ["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" } }, "sha512-Mb/GvXPHBAXdgGIcnfU5L3ldpn1XcxrGkPHwqgRx17/I2XRfqlFKk2vGkHWINn1kdXvzJZeuO3is6I9KLPFm0g=="], - "sitemap": ["sitemap@9.0.1", "", { "dependencies": { "@types/node": "^24.9.2", "@types/sax": "^1.2.1", "arg": "^5.0.0", "sax": "^1.4.1" }, "bin": { "sitemap": "dist/esm/cli.js" } }, "sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ=="], + "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], - "smol-toml": ["smol-toml@1.8.0", "", {}, "sha512-kCZr2V3ch9i00x8zXRhjUNVcjG9ijES5dDudkXvUVCT5QlJNQWElSJdZqyPemffHoLNUYwOcou0Fy+ojN0uHSQ=="], + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], - "string-width": ["string-width@8.2.2", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg=="], + "string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], "strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], - "svgo": ["svgo@4.1.0", "", { "dependencies": { "commander": "^11.1.0", "css-select": "^6.0.0", "css-tree": "^3.0.1", "css-what": "^7.0.0", "csso": "^5.0.5", "picocolors": "^1.1.1", "sax": "1.6.1" }, "bin": { "svgo": "bin/svgo.js" } }, "sha512-bkxnTg1kSU0guhIBmibA6UUhrQmPVA1XsQLN+ylCd+UWzbnLkySOcXpyk1mrl05f+pcaCx2eHb+sp6BgMZWX+Q=="], + "strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="], + + "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], - "tailwind-merge": ["tailwind-merge@2.6.1", "", {}, "sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ=="], + "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="], + + "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], + + "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "@babel/core": "*", "babel-plugin-macros": "*", "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" }, "optionalPeers": ["@babel/core", "babel-plugin-macros"] }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "tailwindcss": ["tailwindcss@4.3.3", "", {}, "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ=="], "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], - "tiny-inflate": ["tiny-inflate@1.0.3", "", {}, "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="], - "tinyexec": ["tinyexec@1.3.1", "", {}, "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA=="], "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], @@ -868,141 +881,67 @@ "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], - "tsconfck": ["tsconfck@3.1.6", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"], "bin": { "tsconfck": "bin/tsconfck.js" } }, "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w=="], - "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], - - "typesafe-path": ["typesafe-path@0.2.2", "", {}, "sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA=="], + "type-fest": ["type-fest@2.19.0", "", {}, "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="], - "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], - "typescript-auto-import-cache": ["typescript-auto-import-cache@0.3.6", "", { "dependencies": { "semver": "^7.3.8" } }, "sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ=="], - - "ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="], - - "ultrahtml": ["ultrahtml@1.7.0", "", {}, "sha512-2xRd0VHoAQE4M+vF/DvFFB7pUV0ZxTW1TLi7lHQWnF/Sb5TPeEUV/l+hxcNnGO00ZXGnR0voCMmYRKQf+rvJ2g=="], - - "uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="], - - "undici": ["undici@8.10.2", "", {}, "sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ=="], - - "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + "undici-types": ["undici-types@8.9.0", "", {}, "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg=="], "unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="], - "unifont": ["unifont@0.7.5", "", { "dependencies": { "css-tree": "^3.1.0", "ohash": "^2.0.11", "undici": "^8.0.0" } }, "sha512-ULe/Cs+ZIsq+dcFofNkhqielCrUJnb5mr+Yc4EBM2VlL+6OZR6+cjtI2mT1bJvRBrVncqHAbLURxmPLcCXzWMg=="], - - "unist-util-find-after": ["unist-util-find-after@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ=="], - "unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="], - "unist-util-modify-children": ["unist-util-modify-children@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "array-iterate": "^2.0.0" } }, "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw=="], - "unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="], + "unist-util-position-from-estree": ["unist-util-position-from-estree@2.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ=="], + "unist-util-remove-position": ["unist-util-remove-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q=="], "unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="], "unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="], - "unist-util-visit-children": ["unist-util-visit-children@3.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA=="], - "unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="], - "unstorage": ["unstorage@1.17.5", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^5.0.0", "destr": "^2.0.5", "h3": "^1.15.10", "lru-cache": "^11.2.7", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.3" }, "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" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg=="], - - "update-browserslist-db": ["update-browserslist-db@1.3.2", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw=="], - - "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], - - "vfile-location": ["vfile-location@5.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="], - - "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], - - "vite": ["vite@6.4.3", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A=="], - - "vitefu": ["vitefu@1.1.3", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["vite"] }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="], - - "volar-service-css": ["volar-service-css@0.0.71", "", { "dependencies": { "vscode-css-languageservice": "^6.3.0", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-wRRFt9BpjMKCazcgOh67MSjUjiWUCAh99DyYSDIOTuxaRjEtDC7PpB0k1Y1wbJIW/pVtMUSVbpPo3UGSm0Byxw=="], - - "volar-service-emmet": ["volar-service-emmet@0.0.71", "", { "dependencies": { "@emmetio/css-parser": "^0.4.1", "@emmetio/html-matcher": "^1.3.0", "@vscode/emmet-helper": "^2.9.3", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-zqjzt6bN95e3CUstBm0PBFAJnrfz0ZAARka87fart46/gNCLLuP3Vujy8V/J8HEziTFLnfkgIASLFYPUhonJcA=="], - - "volar-service-html": ["volar-service-html@0.0.71", "", { "dependencies": { "vscode-html-languageservice": "^5.3.0", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-e8tHPhgQ7ooLfudAEIku+kgd9pWkq3SSz8RbnQDI1+Eb8wbenkLGHqoirLqz5ORLV6wIMr2Iv08RWBG5eOcgpw=="], - - "volar-service-prettier": ["volar-service-prettier@0.0.71", "", { "dependencies": { "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0", "prettier": "^2.2 || ^3.0" }, "optionalPeers": ["@volar/language-service", "prettier"] }, "sha512-Rz7JVH3qD108UCdmIEiZvOBNljMt2nLFdbN8AXcDfn7xD9F5I2aCIsDVqBbXw21PsnxG0b7MfwtNF+zPS/NKUg=="], - - "volar-service-typescript": ["volar-service-typescript@0.0.71", "", { "dependencies": { "path-browserify": "^1.0.1", "semver": "^7.6.2", "typescript-auto-import-cache": "^0.3.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-nls": "^5.2.0", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-yTtM/BVT6hoyEYnDtaCyAtNhdNeS/mhTTABlBOdw3NNiRBUin3IznFJpgfjer4c6RYopiPjjQjc9VFhxVl1mLw=="], - - "volar-service-typescript-twoslash-queries": ["volar-service-typescript-twoslash-queries@0.0.71", "", { "dependencies": { "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-9K2k72s4n7rV9s4bX0MyjbX9iBribvKZbBJKuEmTCZfeWJXs6Yh7bGpY4eoc7UufAjvpheBqwyZCOIPBvxCv0A=="], + "update-check": ["update-check@1.5.4", "", { "dependencies": { "registry-auth-token": "3.3.2", "registry-url": "3.1.0" } }, "sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ=="], - "volar-service-yaml": ["volar-service-yaml@0.0.71", "", { "dependencies": { "vscode-uri": "^3.0.8", "yaml-language-server": "~1.23.0" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-qYGWGuVpUTnZGu5P/CR4KLK4aIR8RrcVnmfZ2eRcj9q/I8VZCoC5yy9FtEvfNvnDp4MU17yhdJcvpQPIqhJS2Q=="], + "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], - "vscode-css-languageservice": ["vscode-css-languageservice@6.3.10", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "3.17.5", "vscode-uri": "^3.1.0" } }, "sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA=="], + "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], - "vscode-html-languageservice": ["vscode-html-languageservice@5.6.2", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5", "vscode-uri": "^3.1.0" } }, "sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg=="], + "use-sync-external-store": ["use-sync-external-store@1.7.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A=="], - "vscode-json-languageservice": ["vscode-json-languageservice@4.1.8", "", { "dependencies": { "jsonc-parser": "^3.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.16.0", "vscode-nls": "^5.0.0", "vscode-uri": "^3.0.2" } }, "sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg=="], + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], - "vscode-jsonrpc": ["vscode-jsonrpc@9.0.2", "", {}, "sha512-SbQSV9yRemARxeXw6LU5sS6Zq0e9/DgCCX5yelH263ZQWukbTk8EF8fjTrr1dziasf4GwlJbvTwFnTrnQFWZXQ=="], - - "vscode-languageserver": ["vscode-languageserver@9.0.1", "", { "dependencies": { "vscode-languageserver-protocol": "3.17.5" }, "bin": { "installServerIntoExtension": "bin/installServerIntoExtension" } }, "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g=="], - - "vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.18.3", "", { "dependencies": { "vscode-jsonrpc": "9.0.2", "vscode-languageserver-types": "3.18.3" } }, "sha512-DF49+WeV5py4zO5hhobp60jjsDSK0lAqA0OuKBLBvp423HPWQcCbhZz3JgyfIewsEz2f8U+X75xNIFHdiXZm2w=="], - - "vscode-languageserver-textdocument": ["vscode-languageserver-textdocument@1.0.14", "", {}, "sha512-EQyqJMi552E4ZTf46izQ4Fj6XquqxCySR3J5ZSD1SisMf6RfpeOWHxGBE8Gr6V0/3GHIGdAzDn8F8+1nTGCnoQ=="], - - "vscode-languageserver-types": ["vscode-languageserver-types@3.18.3", "", {}, "sha512-XIlzJ7Qp/jzSI1ds7/FwPAWrPeTZA7pAtlW4hdJ1J6xXWJL6dR9QYnDhJOdLzdKhUQ5Mm6mvUMw+3DcOQQasPw=="], + "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], - "vscode-nls": ["vscode-nls@5.2.0", "", {}, "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng=="], + "vfile-location": ["vfile-location@5.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="], - "vscode-uri": ["vscode-uri@3.2.0", "", {}, "sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg=="], + "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], - "which-pm-runs": ["which-pm-runs@1.1.0", "", {}, "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA=="], - - "widest-line": ["widest-line@5.0.0", "", { "dependencies": { "string-width": "^7.0.0" } }, "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA=="], - - "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], - - "xxhash-wasm": ["xxhash-wasm@1.1.0", "", {}, "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA=="], - - "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], - - "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - "yaml": ["yaml@2.8.3", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="], + "widest-line": ["widest-line@4.0.1", "", { "dependencies": { "string-width": "^5.0.1" } }, "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig=="], - "yaml-language-server": ["yaml-language-server@1.23.0", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "ajv-i18n": "^4.2.0", "prettier": "^3.8.1", "request-light": "^0.5.7", "vscode-json-languageservice": "4.1.8", "vscode-languageserver": "^9.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.16.0", "vscode-uri": "^3.0.2", "yaml": "2.8.3" }, "bin": { "yaml-language-server": "bin/yaml-language-server" } }, "sha512-3qVyCOexLCWw06PQa5kRPwvMWMZ/eZeCRWUvgD6a0OkqL/4iCnxy2WumbWifa937Uo5xhyWJ0uxlU39ljhNh7A=="], + "wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - "yargs": ["yargs@18.1.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^8.2.1", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg=="], + "yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], - "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + "yuku-analyzer": ["yuku-analyzer@0.9.5", "", { "dependencies": { "@yuku-toolchain/types": "^0.9.5", "yuku-ast": "^0.9.5" }, "optionalDependencies": { "@yuku-analyzer/binding-android-arm64": "0.9.5", "@yuku-analyzer/binding-darwin-arm64": "0.9.5", "@yuku-analyzer/binding-darwin-x64": "0.9.5", "@yuku-analyzer/binding-freebsd-x64": "0.9.5", "@yuku-analyzer/binding-linux-arm-gnu": "0.9.5", "@yuku-analyzer/binding-linux-arm-musl": "0.9.5", "@yuku-analyzer/binding-linux-arm64-gnu": "0.9.5", "@yuku-analyzer/binding-linux-arm64-musl": "0.9.5", "@yuku-analyzer/binding-linux-x64-gnu": "0.9.5", "@yuku-analyzer/binding-linux-x64-musl": "0.9.5", "@yuku-analyzer/binding-win32-arm64": "0.9.5", "@yuku-analyzer/binding-win32-x64": "0.9.5" } }, "sha512-wUPmylpfXlJAIOQ6F73kPbWii7LEeyPWx++NWlJ+6NihQbO/D1YeQQjMY4Lwqg2o1RKDCHQqBfgc4ZLs0eYs5A=="], - "yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="], + "yuku-ast": ["yuku-ast@0.9.5", "", { "dependencies": { "@yuku-toolchain/types": "^0.9.5" } }, "sha512-Q8qW8WwQnN5Cm0ZZivdRIfv0sRLTjUq0YumXJkw8CYN1aCdICH9rk4C47/4n6kA5EqDtlj+F608twoTSV2MwdQ=="], - "yocto-spinner": ["yocto-spinner@0.2.3", "", { "dependencies": { "yoctocolors": "^2.1.1" } }, "sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ=="], - - "yoctocolors": ["yoctocolors@2.2.0", "", {}, "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg=="], + "zbsearch": ["zbsearch@4.0.0", "", {}, "sha512-gm4zfO31n2ZdruTTRQoWVWO4Q2+zrDt2GlrvIc+5JulRQNAm4IanCxER82vQ7Ug96FYkGqWUJBXFe1kGAcDWaQ=="], "zod": ["zod@4.6.1", "", {}, "sha512-341aRWQsve0rvronKNTqZpjmzdbUDlFuzHaI/XLg/Ej82qffDJRRfBTCuv7+9q/rMjB6LSLyEBnW4InJeMtt/Q=="], - "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], - - "zod-to-ts": ["zod-to-ts@1.2.0", "", { "peerDependencies": { "typescript": "^4.9.4 || ^5.0.2", "zod": "^3" } }, "sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA=="], - "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], - "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], - - "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + "@tailwindcss/node/magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.3", "tslib": "^2.4.0" }, "bundled": true }, "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg=="], @@ -1016,117 +955,29 @@ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "@types/sax/@types/node": ["@types/node@24.13.4", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-YJ7EqCstVTzIr0fMr7qul/977en+pQHrfmuKIo6Zr9i75Be21dr3MovcfvGtyvi2HAUrRerWps5sMO9I7WaxDw=="], - - "@vscode/emmet-helper/vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="], - "ansi-align/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], - - "astro/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "boxen/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], - - "cliui/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], - - "csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="], - - "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + "boxen/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], - "prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], + "chalk-template/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - "sitemap/@types/node": ["@types/node@24.13.4", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-YJ7EqCstVTzIr0fMr7qul/977en+pQHrfmuKIo6Zr9i75Be21dr3MovcfvGtyvi2HAUrRerWps5sMO9I7WaxDw=="], + "micromark/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - "unstorage/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], + "mime-types/mime-db": ["mime-db@1.33.0", "", {}, "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="], - "vite/esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], + "next/postcss": ["postcss@8.5.23", "", { "dependencies": { "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg=="], - "vscode-css-languageservice/vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="], + "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], - "vscode-json-languageservice/jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="], - - "vscode-languageserver/vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.17.5", "", { "dependencies": { "vscode-jsonrpc": "8.2.0", "vscode-languageserver-types": "3.17.5" } }, "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg=="], - - "widest-line/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], - - "wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], - - "yaml-language-server/request-light": ["request-light@0.5.8", "", {}, "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg=="], - - "yaml-language-server/vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="], - - "yargs/yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="], - - "zod-to-ts/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@types/sax/@types/node/undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], + "serve-handler/bytes": ["bytes@3.0.0", "", {}, "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw=="], "ansi-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="], - - "sitemap/@types/node/undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], - - "unstorage/chokidar/readdirp": ["readdirp@5.1.1", "", {}, "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA=="], - - "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], - - "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], - - "vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], - - "vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], - - "vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], - - "vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], - - "vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], - - "vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], - - "vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], - - "vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], - - "vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], - - "vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], - - "vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], - - "vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], - - "vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], - - "vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], - - "vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], - - "vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], - - "vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], - - "vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], - - "vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], - - "vite/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], - - "vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], - - "vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], - - "vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], - - "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], - - "vscode-languageserver/vscode-languageserver-protocol/vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="], + "chalk-template/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - "vscode-languageserver/vscode-languageserver-protocol/vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="], + "micromark/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], } diff --git a/components.json b/components.json deleted file mode 100644 index aa201e8..0000000 --- a/components.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "new-york", - "rsc": false, - "tsx": true, - "tailwind": { "config": "", "css": "src/styles/global.css", "baseColor": "slate", "cssVariables": true }, - "iconLibrary": "lucide", - "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" - } -} diff --git a/content/docs/expo-devtools/changelog.mdx b/content/docs/expo-devtools/changelog.mdx new file mode 100644 index 0000000..ebc1ee6 --- /dev/null +++ b/content/docs/expo-devtools/changelog.mdx @@ -0,0 +1,272 @@ +--- +title: Changelog +description: Every published release of @axonpack/expo-devtools, newest first. +--- + +{/* Generated by scripts/sync-changelog.mjs from the package's CHANGELOG.md — do not edit by hand. */} + +Every published release, newest first. The current version is **2.5.4**. + +## 2.5.4 + + + +- **Badges, cards and progress tracks sit above the panel** rather than looking punched into it, on Dracula, Monokai and One Dark +- **A theme whose header is a different shade from its panel keeps readable tabs** — the labels take their colour from the header now, worked out from it when your theme doesn't say +- **A custom theme can set `surface`** for anything raised inside a tab, and `toolbarText` / `toolbarTextActive` for the header's own labels + +## 2.5.3 + + + +- **The status bar follows the theme you picked** — light icons on a dark theme, dark ones on a light theme, and your app's own back when the panel closes +- **The strip above the toolbar is gone** — the header now paints the area behind the status bar, in every theme +- **A custom theme can declare its own `statusBarStyle`**, or leave it out and have it read off the theme's colours +- **``** leaves the status bar alone, for an app that manages it itself +- **Tapping a WebSocket row opens it** — the panel used to close itself as it appeared + +## 2.5.2 + + + +- **Your own crash reporter sees JavaScript errors again** — Sentry, Crashlytics or anything else installed alongside now receives every error this catches, fatal ones included +- **A fatal error ends the app**, as it did before these tools were added, and is reported at the next launch +- **React Native's red box is back for fatal errors** in development +- **Unhandled rejections show in the red box too**, rather than only in the Console tab + +## 2.5.1 + + + +- **`defaultTheme` only accepts a theme you have** — a built-in palette or one of your own from `themes`; anything else is a type error before the app runs +- **Every option explains itself in your editor** — hover any field of `createDevtoolsClient` for what it does and what it defaults to +- **The same for what the tools hand back** — crash records, request and console entries, storage adapters and performance samples all document their fields +- **Custom theme colours are named on hover**, so you can see what each one paints before you override it + +## 2.5.0 + + + +- **`expo-clipboard` is now a peer dependency**, so it resolves to the version your own Expo SDK ships. As a direct dependency it was pinned to `~57.0.1`, which tied this package to SDK 57 — that was the only thing that did +- **Install it alongside the others**: `npx expo install @axonpack/expo-devtools react-native-safe-area-context react-native-webview expo-clipboard` +- **The package now ships its `CHANGELOG.md`**, so you can read what changed without leaving `node_modules` + +## 2.4.1 + + + +- **Add a key** to a store from the Storage tab — you pick the name, the type and the value, and a key that already exists is refused +- **Import a snapshot** back into a store: paste the file and see what it would add, overwrite, skip or leave alone before anything is written +- **Exported snapshots carry a version**, so the tab knows whether it can read one back +- **Blacklist keys per store** with a pattern or a function — a match is never listed, never read and never written +- **Declare which types a store accepts**, so the Add-key sheet only offers what that store can keep +- **A store's fixed key list can now be a function**, re-read on every refresh + +## 2.4.0 + + + +- New **Crashes** tab: every crash the app has hit, with the unread count on the tab itself +- **Crash report sheet** opens the moment a crash is caught, with the message, stack, component stack, breadcrumbs, device details and the raw record +- **Stack frames name your files** — in development the stack is symbolicated against the dev server, so a frame reads `CrashDemo.tsx:79:25` instead of `index.bundle:104857:23`, with the failing source line and a caret under the exact column — for a render error, both the throwing line and the element that rendered it — and library frames folded behind **See N more frames** +- **Copy and share** any report as Markdown or JSON, straight to the share sheet +- **Crashes that end the app** are saved to the device and reported the next time it opens +- **Catches four kinds of crash**: fatal and non-fatal JavaScript errors, unhandled promise rejections, React render errors, and uncaught native exceptions on iOS and Android +- **Unhandled promise rejections are now caught in release builds**, which React Native only reports during development +- New **`DevtoolsErrorBoundary`** shows a Try again screen where a render error used to leave a blank one, and records which component threw +- **Keep crash reporting on in production** with `crash.enableWhileDevtoolsDisabled` — it works whether or not you start the devtools, and the panel, the console prompt and request logging all stay off +- **Only crashes that actually close the app are reported when the devtools are not started** — JavaScript errors the app recovered from stay a development concern +- **Turn off React Native's red box** with `crash.disableDefaultLogBox`, so a JavaScript error is reported in one place +- **The floating devtools button now hides itself** unless the tools were started, so leaving it mounted in a release build shows nothing +- **A plain crash notice outside development** — what broke, when, and a Share report button — rather than the developer sheet with its tabs and stack traces +- **Tap an error in the Console tab** to read its full crash report without leaving the tab +- **Breadcrumbs** replay the console and network activity leading up to a crash +- **`redact`** rewrites or drops a report before it is stored, saved or handed to `onCrash` +- **`setCrashContext`** attaches your own details — user, screen, feature flags — to every report +- New **Debug** tab for the tools that break the app on purpose — blocking a thread, and crashing one +- **The Limiter has moved** off the Performance tab into Debug; every other Performance section reports something that happened, while this one causes it + +## 2.3.0 + + + +- New **Storage** tab: every key in every store you register, with its value, type and byte size, plus the store's total size and largest key +- Register the stores you already use — `asyncStorageAdapter`, `mmkvAdapter`, `secureStoreAdapter`, or `defineStorageAdapter` for anything else — through `createDevtoolsClient({ storage: { adapters } })`. This package still depends on no storage library +- Search keys, values or both, with match case / whole word / regex, filter by value type, sort by key, size or type, and group by the `auth:token` / `cache/user/1` prefixes your keys already use +- Inspect a value in the same expandable JSON tree the Network and Console tabs use, or read the raw characters exactly as stored +- Edit one value or delete one key, with a confirmation on delete. A value is written back through the type it was read as, so a number stays a number. There is no store-wide clear anywhere in the tab +- Honest about what a store can't do: SecureStore's keys can't be listed so you name them, reads stop at `storage.maxKeys` (1,000) and say how many they skipped, and binary values are shown but not editable +- Export the filtered keys of a store as JSON through the share sheet + +## 2.2.0 + + + +- Search the Payload, Preview and Response tabs of a request, with every match highlighted in place — in the JSON tree, in syntax-coloured code, and in the raw body +- Searching a JSON tree opens the branches holding a match and collapses the rest, so a hit is never buried in a closed node +- Match case, whole word and regex switches on every search box, in the Network filter, the Console filter and the request detail panel +- Highlighted matches in the request list and in console output +- Filter requests by status — 2xx / 3xx / 4xx / 5xx / Failed / Pending, offering only the ones actually captured +- Invert now flips the whole Network filter rather than only the search text, and a new Clear resets every filter at once +- New `matchHighlight` palette token, set on all seven built-in themes, for the search highlight background +- Fixed the Preview tab rendering unsyntax-highlighted bodies in near-black, unreadable on every dark theme + +## 2.1.1 + + + +- ## 📝 Documentation + +- The README now gathers Network, Console and Performance under one Features section. +- Every Performance section has its own screenshot. +- The theme picker and a request's payload view are now pictured. +- The reference page now warns that starting the tools and mounting the panel are separate guards, and a release build needs both. + +## 2.1.0 + + + +- ## ✨ Features + +- The Performance tab is now split into sections you pick from the toolbar — Statistics, User timing, Interactions, Long tasks and Limiter — instead of everything sharing one long screen. +- Only the section you are looking at is drawn, so the tab is lighter on older phones and the graphs no longer redraw while you read a list. +- The Limiter, for freezing the app on purpose, is now one of those sections rather than a panel that opened over everything else. +- Every list tells you when recording is off, and offers to start it, instead of looking empty. +- Long tasks now lists the freezes worth acting on: anything over 150 milliseconds, rather than 50. You can still ask for the shorter ones. + + ## 📝 Documentation +- A new reference page explains every tab, section, button and field in the panel, alongside the full list of settings. +- Setting the tools up in an app that uses Expo Router is now written up, with where to start them and where to put the button. +- Three settings were documented under the wrong name or the wrong default. The page now matches what the code actually does. + +## 2.0.0 + + + +### Major changes + +- ## ✨ Features + +- **Performance** — a new tab showing what your app is doing to the device, with no desktop profiler and no cable. +- Watch the JavaScript memory climb while you use the app, on a live graph. +- See the frame rate, so you can tell a slow screen from a slow network. +- See how long your app took to start, broken into its stages. +- **Long tasks** — a list of every moment the app froze for long enough to notice, with when it happened and for how long. +- **Interactions** — taps that took too long to respond, with the time your own code was responsible for shown separately. +- The panel header now shows your app's own name and icon instead of the devtools' own, so it looks like part of your app. +- Any tab can start switched off, for when you only want one of them recording. + + ## 🐛 Bug Fixes +- Requests no longer raise an error and go missing from the log when the response comes back as a file, an image, or anything else that isn't plain text. In some apps this affected every request the app made. + + ## ⚠️ Breaking Changes +- The list of in-app browser views to capture is now given at the top level, as `webviewSources`, instead of inside `network`. It covers both the network and console tabs, so it no longer belongs to either one. Move it up a level: + + ```ts + // before + createDevtoolsClient({ network: { webviewSources: ['my-webview'] } }); + + // after + createDevtoolsClient({ webviewSources: ['my-webview'] }); + ``` + + Left inside `network` it is silently ignored, and nothing from that browser view is captured. + +- The `enabled` option is gone. Guard the `.init()` call instead — until it runs, nothing is recorded: + + ```ts + if (__DEV__) devtools.init(); + ``` + +### Minor changes + +- ## ✨ Features + +- The devtools panel now opens on whichever tab you had open last, instead of going back to Network every time. + +### Patch changes + +- ## 🐛 Bug Fixes + +- Requests no longer raise an error and go missing from the network log when their response comes back as a file, an image, or anything else that isn't plain text. In some apps this affected every request the app made. +- Those responses now show a short summary with their type and size, instead of appearing empty. +- A page open in an in-app browser is no longer disturbed when it loads that kind of response. + +## 1.1.1 + + + +- ## 📝 Documentation +- The package page now shows what the tools actually look like, with screenshots of the request list, the console, and the expression prompt. +- Rewritten as a walkthrough of what you can do — find one request among hundreds, try a slow connection, resend a request with different details, read your logs and run an expression — rather than a list of settings. + +## 1.1.0 + + + +### Minor changes + +- ## ✨ Features + +- **Console** — a new tab in the devtools panel showing everything your app logs, without a desktop debugger attached. +- Warnings and errors are coloured and counted, so problems stand out while you scroll. +- Objects and arrays can be opened up and explored, instead of appearing as `[object Object]`. +- Errors show their full stack when you tap them. +- The same message logged over and over collapses into one line with a count, so a chatty screen doesn't bury everything else. +- **Run an expression** — type JavaScript at the prompt and see the result straight away, with name suggestions as you type. +- Tap a command you ran earlier to load it back into the prompt and send it again. +- Anything logged inside an in-app browser page is captured too, labelled so you can tell it apart from your app's own output. +- Filter by level or by where a message came from, or search the text of every message. +- The list follows new output as it arrives, and holds still when you scroll back to read something, with a button to jump to the newest again. +- Copy any line with one tap. +- Nothing is captured until you turn devtools on, the same as the network inspector, and the expression prompt stays out of production builds unless you ask for it. + +### Patch changes + +- ## ✨ Features + +- **Network throttling** — try your app on a slow connection without leaving your desk. Pick Slow 3G, Fast 3G, Fast 4G or Offline, or set your own speed and delay. +- Throttling applies to your app's own requests and to requests made inside an in-app browser view. +- **User agent** — pretend to be an iPhone, an Android phone, a desktop browser or Googlebot, or type your own. +- Both settings take effect straight away, with no need to restart the app. +- Every captured request now shows the connection settings it actually ran under, so requests recorded before and after a change stay easy to tell apart. +- The sandbox has its own connection settings section, so you can slow a request down while trying it out. +- The devtools panel and its pop-up sheets now carry the axonpack logo. + + ## 🐛 Bug Fixes +- Requests an in-app browser page makes while it is still loading are now captured. Previously they were missed entirely. +- Requests still in flight now stand out as an amber "PENDING" instead of blending into the rest of the row. +- Request rows show a proper icon for each kind of response, instead of the words "HTTP", "CSS" and "JS". +- JSON responses now have their own orange marker. + + ## ⚠️ Breaking Changes +- If you capture requests from an in-app browser view, rename `getWebViewInjectedScript` to `getWebViewInjectedJavaScriptBeforeContentLoaded` and pass it to the `injectedJavaScriptBeforeContentLoaded` prop instead of `injectedJavaScript`. The new prop runs earlier, which is what lets requests made during page load be captured. + +## 1.0.1 + + + +- ## 🐛 Bug Fixes +- Fixed links on the npm package page that pointed to the project's old GitHub location. + +## 1.0.0 + + + +- ## ✨ Features + + First release of `@axonpack/expo-devtools` — an on-device network inspector for React Native and Expo apps. + +- A draggable button opens a full network inspector right inside your app, no desktop tool needed. +- Nothing is captured until you turn it on, so it's safe to leave in a production build. +- Requests made with `fetch`, `XMLHttpRequest`, and popular HTTP client libraries (like axios) are captured automatically. +- Requests made inside an in-app browser view can be captured too, once you opt a screen into it. +- Search and filter requests by method, type, or source, and reverse the sort order. +- A tap-to-filter activity graph shows your request traffic over time, with time labels. +- Tap any request to see its headers, a pretty-printed preview, the raw response, and timing details. +- Image, HTML, and SVG responses show up as an actual preview, not just raw text. +- Failed requests (4xx/5xx) are clearly marked in red so they stand out from successful ones. +- Copy any header value, the full request URL, or a ready-to-paste cURL command with one tap. +- A built-in sandbox lets you edit and resend any captured request — method, URL, headers, query params, or body — and see the response live. +- Export your current, filtered request log to share it with someone else. +- Request and response bodies are always shown in full, never cut off. diff --git a/content/docs/expo-devtools/compatibility.mdx b/content/docs/expo-devtools/compatibility.mdx new file mode 100644 index 0000000..05ca2ad --- /dev/null +++ b/content/docs/expo-devtools/compatibility.mdx @@ -0,0 +1,72 @@ +--- +title: Compatibility +description: The versions this is built against, what it requires you to have installed, and which platforms it runs on. +--- + +## Versions + + + +| `@axonpack/expo-devtools` | Expo SDK | React Native | React | +| ------------------------- | -------- | ------------ | ----- | +| 2.5.x | 57 | 0.86 | 19.2 | + +That row is what the package is **built and tested against** — the versions in its own dev +dependencies and in the example app that exercises every tab. + + + Every Expo package this needs is a peer dependency, so each resolves to the version your own SDK + ships. The row above is what the package is built and tested against, not a range it refuses to run + outside. + + +## What you have to install + +| Package | Why | +| -------------------------------- | ------------------------------------------------------------ | +| `react-native-safe-area-context` | The overlay and panel lay themselves out inside the safe area | +| `react-native-webview` | HTML and image response previews in the Network tab | +| `expo-clipboard` | Every Copy button, in every tab | + +Both are peer dependencies, so they come from your app rather than from this package: + +```sh +npx expo install @axonpack/expo-devtools react-native-safe-area-context react-native-webview expo-clipboard +``` + +Every peer range is `*`. That is deliberate: the point of a peer is that your SDK decides the +version, and a narrower range here would fight it. It does mean npm will not warn you when you are +outside what has been tested, so treat the table above, not the peer range, as the answer. + +`expo-clipboard` is a peer rather than a dependency for that reason — as a dependency it would have +to name a version, and any version it named would tie the package to one SDK line. React Native does +still ship a built-in `Clipboard`, but it is deprecated, slated for removal, and warns through +`console.warn`, which this package patches — so its own deprecation notice would appear in its own +Console tab. + +## Platforms + +| Platform | State | +| ----------- | ------------------------------------------------------------------------- | +| **iOS** | Full support, native module included | +| **Android** | Full support, native module included | + +The native module is written once per platform and is loaded **optionally**, so the panel itself is +plain JavaScript and never depends on it existing. That is what makes Expo Go work — see +[What needs a development build](/docs/expo-devtools/reference/development-build) for the handful of +readings that go quiet there. + +## Storage libraries + +The Storage tab reads whatever you register, so its compatibility is really the adapters'. Versions +the example app is built against: + +| Library | Versions handled | +| --------------------------------------------- | --------------------------------------------------------------------- | +| `@react-native-async-storage/async-storage` | v1, v2 and v3 — `getMany` and `multiGet` are both accepted | +| `react-native-mmkv` | v3 and v4 — `delete` and `remove` are both accepted | +| `expo-secure-store` | SDK 57 | +| anything else | via `defineStorageAdapter`, which duck-types nothing | + +MMKV and SecureStore carry native code of their own, so a store that needs a development build to +exist also needs one to be inspectable. An adapter over an in-memory `Map` works in Expo Go. diff --git a/content/docs/expo-devtools/console.mdx b/content/docs/expo-devtools/console.mdx new file mode 100644 index 0000000..b3c2eb8 --- /dev/null +++ b/content/docs/expo-devtools/console.mdx @@ -0,0 +1,74 @@ +--- +title: Console +description: Everything your app logs, on the device, plus a prompt that runs JavaScript and answers. +--- + +The Console tab mirrors everything your app logs, on the device. Warnings sit on a yellow row and +errors on a red one, and the toolbar keeps a running count of each — so you can see at a glance +whether anything went wrong while you were not looking. + +![Console tab listing captured logs](/expo-devtools/screenshots/console-log.png) + +- Each thing you logged gets its own line, so a message and the object next to it do not run together. + Objects and arrays start collapsed. Tap to open them up, level by level. +- Errors show their message on the row and the **full stack** when you tap it. +- The same message logged over and over becomes **one row with a count**, so a chatty screen does not + bury everything else. +- Filter by level (each chip carries a live count) or by source, or search the text of every message — + with match case, whole word and regex, and every match highlighted where it sits. +- The newest output stays in view automatically, and stops following if you scroll back to read + something, with a button to jump back to the newest. +- Copy any line with one tap. + +![Level filter chips showing live counts](/expo-devtools/screenshots/console-filters.png) + +## Running an expression + +![An expanded error stack and name suggestions at the prompt](/expo-devtools/screenshots/console-autocomplete.png) + +The `>` prompt at the bottom runs JavaScript on the device and shows you what came back. Your typed +command appears with a `›`, the answer with a `‹`, and objects come back as the same explorable tree. +Something that returns a promise shows as pending and fills in when it settles, so +`fetch(...).then((r) => r.json())` works as you would expect. + +- Names are **suggested as you type**, including the members of whatever object you are inside. +- **Tap any command you ran earlier** to load it straight back into the prompt. +- Two built-in helpers reach your app's own code in a development build: `$modules('auth')` lists the + files that are loaded, and `$m('src/stores/auth')` hands you one of them. + +![The prompt answering an expression](/expo-devtools/screenshots/console-repl.png) + +### Reaching your own objects + +Your app's files are bundled as private closures, so nothing can reach an imported name on its own the +way a browser console reaches a page's variables. Anything you want to poke at by name, hand over in +`context`: + +```ts +createDevtoolsClient({ + console: { context: { store, queryClient } }, +}); +``` + +It is also the only thing that works in a release build, where the module list the two helpers above +read is not available. + + + `console.repl` defaults to `true`, and it is not gated on `__DEV__`. Once `init()` has run, the + prompt is there — including in a release build, where it will run whatever is typed into it. Guard + your `init()` call (see [Leaving it in production](/docs/expo-devtools/production)), or turn the prompt off + explicitly with `console: { repl: false }`. + + +## Limits + +- The list holds the **500** most recent rows. +- Only `console.log`, `.info`, `.warn`, `.error` and `.debug` are mirrored. +- The prompt cannot reach bundled module names on its own. `console.context` is the supported route. + +## Next step + + + + + diff --git a/content/docs/expo-devtools/crash-reporting.mdx b/content/docs/expo-devtools/crash-reporting.mdx new file mode 100644 index 0000000..1613563 --- /dev/null +++ b/content/docs/expo-devtools/crash-reporting.mdx @@ -0,0 +1,132 @@ +--- +title: Crash reporting +description: JS errors, unhandled rejections, render errors and native exceptions, turned into a report you can read on the device. +--- + +The Crashes tab turns the errors that end a session, or nearly do, into a report you can read on the +device. It is also the one subsystem here meant to survive into a release build. + +A report carries the message, the stack, the component stack where there is one, breadcrumbs, device +details and the raw JSON. You can copy it as Markdown or JSON, or share the whole thing. Past reports +stay in a history with an unread count on the tab. + +## The four tiers + +Which tier caught a crash decides how much it can say. + +| Tier | Where it comes from | +| ------------------------------- | --------------------------------------------------------------------------------------------------------------- | +| **JS errors** | The global `ErrorUtils` handler, *wrapped* rather than replaced, so LogBox and React Native's own reporting live | +| **Unhandled promise rejections** | The Hermes rejection tracker. React Native registers its own only in development | +| **React render errors** | The exported ``. The only tier that produces a component stack | +| **Uncaught native exceptions** | The platform's uncaught-exception handler on each side, chained to whatever was installed before it | + +## Reporting from a release build + +Crash capture has the only gate that is not `init()`. Setting one flag installs the handlers when the +client is **constructed**, so an app can keep its usual development-only `init()` call and still report +crashes from release: + +```ts title="devtools.ts" +export const devtools = createDevtoolsClient({ + crash: { enableWhileDevtoolsDisabled: true }, +}); +``` + +On its own that captures **native exceptions only** — the crashes that end the app — and reports them +in the compact sheet. A later `init()` upgrades it: the JS tiers install too and the full sheet takes +over. It brings nothing else with it either way: no panel, no REPL, no console capture, no request +bodies. + +The JS tiers are held back before `init()` on purpose. They report errors the app survived, which is a +developer's concern, and the sheet there is in front of somebody using the app. A fatal JS error still +arrives, because React Native turns it into a native exception on its way to killing the process. + + + `popupDetail` defaults to `'auto'`, which picks between two sheets. With the devtools enabled you get + the full developer sheet: tabs, a stack tree, raw JSON and this package's branding. With them + disabled you get a compact notice: what broke, when, and Share / Copy / Dismiss. Set it explicitly + for an internal build that ships the crash sheet but not the panel and still wants the stack on + screen. + + +If you ship crash reporting without the panel, mount the sheet yourself: + +```tsx +import { CrashReportOverlay } from '@axonpack/expo-devtools'; +``` + +`` already mounts one, and mounting both is harmless: whichever mounted first owns +the sheet and the other draws nothing. + +## Catching render errors + +`` is the only tier that produces a component stack, and it turns a white +screen into a Try again button — which is why it is worth mounting even in a release build: + +```tsx +import { DevtoolsErrorBoundary } from '@axonpack/expo-devtools'; + + } + onError={(error, info) => report(error, info)} +> + +; +``` + +`fallback` replaces the built-in screen and `reset` remounts the subtree that threw. A boundary around +a subtree is the stronger tool wherever it fits, because unmounting that subtree actually discards the +broken state rather than stepping over it. + +## Attaching your own details + +```ts +devtools.setCrashContext({ userId, screen, flags }); +``` + +Everything you pass is attached to every record from that point on. + +To rewrite or drop a record before it is stored, handed to `onCrash` or written to disk, use `redact`: + +```ts +createDevtoolsClient({ + crash: { + redact: (record) => (record.message.includes('token') ? null : record), + onCrash: (record) => myBackend.send(record), + }, +}); +``` + +## Decisions worth knowing + +- **A fatal JS error does not end the app, and there is no switch for that.** React Native decides this + by build: in development it hands the error to the red box and tells the native side nothing; in a + release build it reports it, which is what ends the process. The same error, the same fatality — only + the branch differs. Capturing it closes that gap. Turning the `jsErrors` tier off hands the decision + back to React Native. +- **What survives is the process, not necessarily the state.** The JavaScript thread was interrupted + part-way through, possibly mid-render, so component state, the native view tree and your own state + may afterwards disagree. This is why the report is put on screen rather than filed quietly. +- **A crash that killed the app is reported at the next launch.** A dying process is written from + native, on the dying thread, into the app's own sandbox, and drained at the next launch — which is + also the proof the process died. Non-fatal records are not persisted: the app survived them, so + re-reporting one next launch would be a bug. `persistNonFatal` turns that on if you want it. +- **Stacks are symbolicated by asking Metro**, the way LogBox does, and only when the trace itself came + from an http origin. A release build asks nobody. +- **Breadcrumbs carry request URLs and whatever the app logged**, which is a different privacy + proposition from a stack trace. They default to on; `crash: { breadcrumbs: false }` turns them off. + +## Limits + +- **No backend.** Nothing is sent anywhere. `onCrash` is the hook if you want to send reports + yourself — queueing and retry are yours to write. +- **No grouping.** Duplicate crashes are one row each. +- **The current route is not captured automatically.** Pass it through `setCrashContext`. + +## Next step + + + + + diff --git a/content/docs/expo-devtools/debug.mdx b/content/docs/expo-devtools/debug.mdx new file mode 100644 index 0000000..cd255f2 --- /dev/null +++ b/content/docs/expo-devtools/debug.mdx @@ -0,0 +1,42 @@ +--- +title: Debug +description: Tools that break the app on purpose, so the numbers on the other tabs can be trusted. +--- + +The Debug tab breaks the app on purpose, so the numbers on the other tabs can be trusted. It blocks or +crashes a thread on demand, which is the only way to see what a real freeze does to the readings. + +![Debug tab with thread and duration options](/expo-devtools/screenshots/perf-limiter.png) + +## Blocking a thread + +Pick a thread, pick a duration (100 ms to 3 s, or type your own), and block it: + +- **JavaScript** — shows up as a long task and drops the FPS reading. Works everywhere. +- **Main (UI)** — freezes what you see and touch while the JS numbers stay perfectly healthy. That gap + is the blind spot the frame-rate card warns about, and this is how you see it for yourself. Needs a + development build. + +## Crashing a thread + +There is also a **Crash** button for either thread, which takes two taps: the first arms it, the second +does it. + +The two are not the same event, and the difference is worth seeing once. A JS throw is caught and +reported before you let go of the button, while a main-thread crash ends the process and is read back +off disk at the next launch. Either way the report is waiting on the Crashes tab. + + + They call straight into the native module, so they work whenever the panel is on screen, whether or + not `.init()` ran. Guarding the `` mount is what keeps them out of a release — + see [Leaving it in production](/docs/expo-devtools/production). + + +There is no record button and nothing to clear, so the tab carries no toolbar. + +## Next step + + + + + diff --git a/content/docs/expo-devtools/example-app.mdx b/content/docs/expo-devtools/example-app.mdx new file mode 100644 index 0000000..06bd020 --- /dev/null +++ b/content/docs/expo-devtools/example-app.mdx @@ -0,0 +1,43 @@ +--- +title: Example app +description: A runnable Expo app for trying all of this against real traffic. +--- + +`example/` in the repository is a runnable Expo app for trying all of this against real traffic. It has +one screen per tab, each a wall of buttons. + +```sh +git clone https://github.com/axonpack/axonpack.git +cd axonpack +bun install +cd packages/@axonpack/expo-devtools/example +bun run start # Expo Go / dev client +bun run ios # or: bun run android (full native build) +``` + +## What each screen does + +- **Requests** fires GET, POST and DELETE, downloads an image and uploads one, across `fetch`, + `XMLHttpRequest` and axios, so you can watch all three interception paths land in the same list. Its + WebView sub-tab loads a real external site, whose own requests arrive tagged with their source. +- **Console** covers every kind of output worth testing, in three groups. Levels; argument shapes — + mixed arguments, nested objects, arrays of objects, class instances, `Map` and `Set`, exotic + primitives, empty values; and edge cases — circular references, a throwing getter, an unhandled + rejection, a message repeated five times, a very long message, and a 600-entry flood. +- **Performance** blocks the JS thread for 60 ms, 150 ms, 400 ms or three bursts in a row, runs a + deliberately slow tap handler, records `mark` and `measure` pairs with and without `detail`, and + allocates memory you can retain or release to make the heap chart move. +- **Storage** seeds AsyncStorage, MMKV, SecureStore and an in-memory `Map` with a spread of value + shapes, and can write past the 1,000-key read cap. + +## A worked configuration + +`example/devtools.ts` doubles as a worked configuration: a dark default theme, a custom `midnight` one, +two declared `webviewSources`, a `console.context` you can reach from the prompt, and all four storage +adapters registered against real AsyncStorage, MMKV, SecureStore and an in-memory `Map`. + + + AsyncStorage and SecureStore ship inside Expo Go, so `bun run start` exercises them as-is. MMKV does + not, and `createMMKV()` throws when its native module is missing — the example catches that and + registers the other three stores instead of crashing. `bun run ios` gets you all four. + diff --git a/content/docs/expo-devtools/in-app-browsers.mdx b/content/docs/expo-devtools/in-app-browsers.mdx new file mode 100644 index 0000000..dd8f79a --- /dev/null +++ b/content/docs/expo-devtools/in-app-browsers.mdx @@ -0,0 +1,59 @@ +--- +title: In-app browsers +description: Two props on the WebView, one declared name, and the page's requests and logs join your app's. +--- + +A `` runs its own separate JavaScript, in a separate engine, invisible to everything that +patches `fetch` and `console` in your app. So it needs two props wired up: + +```tsx +import { WebView } from 'react-native-webview'; +import { devtools } from './devtools'; + + devtools.handleWebViewMessage(event)} +/>; +``` + +Declare the name up front, so a typo cannot silently swallow everything: + +```ts title="devtools.ts" +export const devtools = createDevtoolsClient({ + webviewSources: ['my-webview'], +}); +``` + +That covers both the page's **requests and its console output**. Rows show up tagged +`WebView::[my-webview]` in either tab, and the Source chips can filter them apart from your app's own. + +`webviewSources` uses a TypeScript `const` type parameter, so the literal names flow into the helpers' +parameter types: passing an undeclared name is a compile error, and at runtime a message from an +undeclared source is dropped. + + + The latter runs after the page's own scripts have already fired, so their requests escape. + + +## Optional: reaching the page with throttling + +Three more props, only needed if you want the connection settings to apply to the page too: + +| Prop | Value | What it buys | +| ------------------------------ | ------------------------------------ | --------------------------------------------------------- | +| `ref` | `devtools.getWebViewRef('my-webview')` | A speed change reaches an already-open page | +| `userAgent` | `devtools.getWebViewUserAgent()` | The browser override applies for real | +| `onShouldStartLoadWithRequest` | `devtools.shouldAllowWebViewRequest` | Navigation is blocked while Offline is on | + +A page can never be *fully* throttled: images, stylesheets and scripts the browser loads by itself +still go out at full speed. + +## Next step + + + + + diff --git a/content/docs/expo-devtools/index.mdx b/content/docs/expo-devtools/index.mdx new file mode 100644 index 0000000..5bac75a --- /dev/null +++ b/content/docs/expo-devtools/index.mdx @@ -0,0 +1,75 @@ +--- +title: Overview +description: Browser-style devtools that live inside your React Native or Expo app. +icon: House +--- + +Tap a floating button and get six tabs on the device itself. No desktop debugger, no cable, and +nothing captured until you switch it on. + +```sh +npx expo install @axonpack/expo-devtools react-native-safe-area-context react-native-webview expo-clipboard +``` + + + +| Tab | What it gives you | +| --------------------------------------------- | ----------------------------------------------------------------------------------------- | +| **[Network](/docs/expo-devtools/network)** | Every request, searchable, resendable, with connection throttling | +| **[Console](/docs/expo-devtools/console)** | Every log, plus a `>` prompt that answers | +| **[Performance](/docs/expo-devtools/performance)** | Frame rate, memory, startup, and the moments the app froze | +| **[Storage](/docs/expo-devtools/storage)** | Every key you have saved — search it, edit it, import and export it | +| **[Crashes](/docs/expo-devtools/crash-reporting)** | JS errors, unhandled rejections, render errors and native exceptions, as readable reports | +| **[Debug](/docs/expo-devtools/debug)** | Tools that block or crash a thread on purpose | + +Two more guides cover things that are not tabs: [themes](/docs/expo-devtools/themes), and +[capturing inside an in-app browser](/docs/expo-devtools/in-app-browsers). + +![Network tab listing captured requests](/expo-devtools/screenshots/network-log.png) + +## What makes it different + +- **One native module, on purpose.** It does the two things JavaScript cannot: block the main thread, + and report the real process start time. Everything else is JS, so the package works in Expo Go with + only a handful of readings dark. +- **It depends on no storage library.** The Storage tab reads the stores _you_ register, which is why + adding this package cannot drag AsyncStorage or MMKV into your app. +- **`init()` is the only gate.** Ship the code freely: until you call it, nothing is patched, + observed or recorded, and the overlay draws nothing. +- **It states its limits.** Every guide here ends with what the tab cannot measure and why, rather + than showing a number it had to invent. + +## Where to go next + + + + + + + + + diff --git a/content/docs/expo-devtools/installation.mdx b/content/docs/expo-devtools/installation.mdx new file mode 100644 index 0000000..6a9b2d6 --- /dev/null +++ b/content/docs/expo-devtools/installation.mdx @@ -0,0 +1,43 @@ +--- +title: Installation +description: Install @axonpack/expo-devtools and its two peer dependencies. +--- + +```sh +npx expo install @axonpack/expo-devtools react-native-safe-area-context react-native-webview expo-clipboard +``` + +`react-native-safe-area-context`, `react-native-webview` and `expo-clipboard` are peer dependencies — +your app supplies them, so each resolves to the version your Expo SDK ships rather than one this +package pins. + +There is nothing else to install: no config plugin, no `app.json` changes, and no native code to +write. + +## Expo Go or a development build + +Both work. The package ships exactly one native module, loaded optionally, so an app running in Expo +Go still gets the whole panel — a handful of readings simply go quiet: + +- Main-thread frame rate +- App memory and device memory +- Disk space (Android only in any case) +- The measured startup breakdown +- The Debug tab's main-thread controls +- Native crash capture + +Everything else, including all of Network and Console, behaves identically. A development build made +with `expo run:ios`, `expo run:android` or EAS lights the rest up. The full list is in +[What needs a development build](/docs/expo-devtools/reference/development-build). + + + A control that needs the native module says so where it sits. Nothing in the panel crashes without + it. + + +## Next step + + + + + diff --git a/content/docs/expo-devtools/meta.json b/content/docs/expo-devtools/meta.json new file mode 100644 index 0000000..09da974 --- /dev/null +++ b/content/docs/expo-devtools/meta.json @@ -0,0 +1,30 @@ +{ + "title": "Expo Devtools", + "description": "On-device network, console, performance, storage and crash devtools", + "root": true, + "icon": "Bug", + "pages": [ + "---Get started---", + "index", + "installation", + "compatibility", + "quick-start", + "---Guides---", + "network", + "console", + "performance", + "storage", + "crash-reporting", + "debug", + "themes", + "in-app-browsers", + "---Shipping---", + "production", + "example-app", + "---Reference---", + "reference", + "---Releases---", + "changelog" + ], + "defaultOpen": true +} diff --git a/content/docs/expo-devtools/network.mdx b/content/docs/expo-devtools/network.mdx new file mode 100644 index 0000000..b9644b5 --- /dev/null +++ b/content/docs/expo-devtools/network.mdx @@ -0,0 +1,117 @@ +--- +title: Network +description: Every request the app makes, searchable, replayable and throttled, in-app browser traffic included. +--- + +The Network tab records every request your app makes and shows each one as a row. + +A row carries the method, the status, how long it took and when it started. Underneath sit the short +name and the full URL, plus badges for the kind of response, where the request came from and how big +it was. A request still in flight shows an amber **PENDING**, so you can tell "waiting" from +"finished". + +Three capture paths feed one list — `fetch`, `XMLHttpRequest` (which is what catches axios and most +HTTP client libraries), and any `` you wired up. Nothing needs configuring: the tab records +from launch. + +![Network tab listing captured requests](/expo-devtools/screenshots/network-log.png) + +## Finding one request among hundreds + +![Filter panel with type, method and source chips](/expo-devtools/screenshots/network-filters.png) + +Search the text, then narrow with the chips: type (Fetch/XHR, JS, Img, Media, Other), status (2xx, +4xx, Failed, Pending), method, or source. The status, method and source chips are built from what you +have actually captured, so they only ever offer real options, and method and source take **more than +one at a time** — two clients side by side, or GET and POST together. + +Status also takes an expression when a band is not the question: `>= 400`, `200-299`, or one exact +code. Search matches light up in the list, and the box carries the three switches you expect from an +editor: **match case**, **whole word** and **regex**. **Invert** flips the whole filter — every chip, +not just the text — and **Clear** resets all of it in one press. + +Under **More filters**: a size and a duration range (`20kb`, `1.5s` — the units you would say out +loud), show only what is still in flight, show only what one of your override rules answered, and the +toggles that hide data URLs or failed requests. + +## Testing a bad connection + +![Throttling and user agent options](/expo-devtools/screenshots/network-conditions.png) + +Pick Slow 3G, Fast 3G, Fast 4G, Offline, or set your own speed and delay. It applies immediately, to +your app's own requests and to in-app browser pages. You can also pretend to be an iPhone, an Android +phone, a desktop browser, or Googlebot. + +Every captured request remembers the settings it ran under, so requests from before and after a change +stay easy to tell apart. The exact profiles are in the +[Network tab reference](/docs/expo-devtools/reference/network-tab#settings-panel). + +## Reading the room + +![Traffic graph with requests grouped by source](/expo-devtools/screenshots/network-overview.png) + +Turn on the traffic graph to see request volume over time, and tap a section to zoom the list to that +moment. Turn on grouping to bundle rows by where they came from, with a count per group. Or switch to +compact rows to fit more on screen. + +**Sort by** time, size, duration or status — the arrow in the toolbar flips the direction and says +what pressing it would give you, so "which one is slow" is one tap rather than a read through two +hundred rows. + +## Tapping a request + +![Headers tab with a copy button on every value](/expo-devtools/screenshots/request-headers.png) + +A panel slides up with everything captured, across a few tabs: + +- **Headers** — what was sent and what came back, each value with its own copy button, plus the + connection settings this request ran under. +- **Payload** — what you sent, as an explorable tree rather than a wall of text. +- **Preview** — the response pretty-printed and colour-coded; images and HTML render as a real + preview. +- **Response** — the raw body, in full, never cut off. +- **Timing** — when it started and how long it took. It also tells you plainly that a DNS/TCP/TLS + breakdown is not available on-device, rather than showing numbers it cannot measure. + +![Request payload as an explorable JSON tree](/expo-devtools/screenshots/request-payload.png) + +Payload, Preview and Response share a search box that stays put while the body scrolls, with the same +match case / whole word / regex switches, and every hit highlighted where it sits — in the JSON tree, +in the syntax-coloured code, and in the raw body alike. + +The **⋮** menu copies the URL, or the whole request as a ready-to-paste **cURL** command or `fetch` +snippet. + +## Editing and resending a request + +![Sandbox with editable URL, method, auth and query parameters](/expo-devtools/screenshots/sandbox.png) + +**Try in sandbox** opens the request as something you can edit: change the method, the URL, the query +parameters, headers, cookies, auth, or the body, then Send and watch the real response come back. +Handy for "does this break if the token is missing?" without touching your code. + +Sandbox requests go out through the same patched `fetch`, so they appear in the log like any other +request. + +## Taking it with you + +**Export** opens the OS share sheet with the currently-filtered list as JSON, named +`network-log-.json`. Mail it to yourself, drop it in Slack, paste it into a bug report. It +uses React Native's own `Share` and nothing else, so there is no filesystem involved and no extra +dependency. + +## Limits + +- The list holds the **200** most recent requests; older ones fall off the end. Request and response + bodies are kept in full, never truncated. +- There is no DNS/TCP/TLS/TTFB breakdown. Those phases happen in the native networking stack, where + JavaScript cannot see them. +- A wired-up page can never be *fully* throttled: images, stylesheets and scripts the browser loads by + itself still go out at full speed. + +## Next step + + + + + diff --git a/content/docs/expo-devtools/performance.mdx b/content/docs/expo-devtools/performance.mdx new file mode 100644 index 0000000..b49eea4 --- /dev/null +++ b/content/docs/expo-devtools/performance.mdx @@ -0,0 +1,112 @@ +--- +title: Performance +description: Frame rate, memory, startup and the moments the app froze — measured on the device. +--- + +The Performance tab measures frame rate, memory and startup on the device itself — no desktop profiler, +no cable. The toolbar carries the record and clear buttons, then a chip per section. Only the section +you are looking at is mounted, so the charts are not re-rendering behind a list you are reading. + +![Performance tab showing frame rate and memory charts](/expo-devtools/screenshots/perf-statistics.png) + + + Unlike the other two recording tabs, this one starts paused, because measuring is not free. While it + is paused nothing is measured at all: the instrumentation detaches rather than running and + discarding, so leaving it off costs nothing. Pressing record attaches everything fresh and picks up + whatever the platform still has buffered. + + +## Statistics + +- **Frame rate** — the JS thread from a frame-delta loop, and the main thread from a native + display-link counter, on one chart. The gap between them is the reading that matters: a healthy JS + line above a collapsed main-thread line is an app that feels frozen while every JS metric says it is + fine. The main-thread figure needs a development build. +- **JS heap** — how much the JavaScript engine has allocated, with a sparkline of the last two minutes, + so you can watch it climb while you use the app. +- **App memory** — the whole process footprint, which is what the OS holds against you and what a user + means by "memory". Routinely several times the JS heap, so the two are stacked as separate plots + rather than letting one stand in for the other. Needs a development build. +- **Device memory** — how much RAM the phone has, and how much this app may still allocate, as a meter + directly under the app's own footprint. On Android the available side is system-wide free memory; on + iOS it is what the process can still claim before being killed. Needs a development build. +- **Storage** — total, used and free space on the data partition. Android only, for the App Store + reason below. Needs a development build. +- **Startup** — process start to first render, split into native startup, bundle eval, app setup and + first render. Measured by this package's own native module, so it works even where the platform's own + markers are all null. Phase boundaries are this package's load points, not platform milestones, so + they shift a little with import order. If the platform *does* report its markers, they are shown + underneath as a second set. + +## User timing + +![User timing entries with durations](/expo-devtools/screenshots/perf-user-timing.png) + +Timings you name yourself, following the [W3C User Timing](https://www.w3.org/TR/user-timing/) +signatures. This is the one metric here that can point at a specific piece of code, so it is the answer +to a long task you cannot explain: + +```ts +devtools.mark('checkout'); +await buildCart(); +devtools.measure('checkout'); +``` + +`measure(name, startOrOptions?, endMark?)` takes a start mark name, or an options object with `start`, +`end`, `duration` and `detail`, the same shapes the spec defines. Calls are also forwarded to the real +`performance.mark` and `performance.measure`, so the entries exist on the platform timeline too. +Nothing is *observed* from that timeline, which is why React's own internal measures never appear here. + +## Interactions + +![Slow interactions with handler time and total](/expo-devtools/screenshots/perf-interactions.png) + +Anything that took longer than 100 ms from the event to the next paint. Each row also shows how long +your handler itself held the JS thread: a small handler under a large total means the interaction was +stuck behind something else rather than being slow itself. + +Durations come rounded to the nearest 8 ms, and nothing under 16 ms is ever reported. + +## Long tasks + +![Long tasks list, newest first](/expo-devtools/screenshots/perf-long-tasks.png) + +Anything that blocked the JS thread past the threshold (150 ms by default), newest first. A "long task" +is one stretch of JavaScript that ran without yielding, so nothing else on that thread could happen +meanwhile: no touches, no timers, no animation driven from JS. + +At 60 fps a frame is 16.7 ms, so 150 ms is about nine frames lost; past roughly 200 ms it reads as a +freeze. Drop `performance.longTaskThresholdMs` to 50 if you want to see the smaller ones too. + +## What it deliberately does not show + +This tab is honest about the difference between what it can actually measure and what you probably want +to know. + +- **Storage is Android-only.** Nothing here asks for a permission on either platform, and nothing makes + your App Store submission harder, which is why iOS storage is missing. `StatFs` on Android needs no + permission and no manifest entry, but iOS's `systemFreeSize` is one of Apple's required-reason APIs: + no prompt, but it obliges a privacy-manifest declaration at submission, and a library reading it + risks pushing that onto every app that embeds it. +- **No "% of heap limit" gauge.** Hermes does not report a heap-size limit, so the denominator would + have to be invented. +- **No heap snapshots or flame charts.** Those come from the CDP `HeapProfiler` and `Profiler` domains + over the inspector socket, driven from outside the app, and a multi-megabyte snapshot is not + something you would browse on a phone anyway. +- **Long tasks name no culprit.** React Native's `PerformanceLongTaskTiming` returns a permanently empty + `attribution` array — the web API's mechanism for reporting which code was responsible — so a row can + tell you a task blocked the thread for 180 ms, but never that it was your list render. Use it to find + *when* to look, then correlate against what the app was doing. +- **Some metrics depend on the platform.** Long tasks and the platform's own startup markers only appear + if the native side implements them, which varies by platform and React Native version. When they are + missing the tab says so rather than showing zeros. +- **Some entries never reach the list.** The platform keeps its own buffer and discards entries once it + overflows, telling us only how many went missing. When that happens the list says so rather than + presenting what survived as the whole picture. + +## Next step + + + + + diff --git a/content/docs/expo-devtools/production.mdx b/content/docs/expo-devtools/production.mdx new file mode 100644 index 0000000..156a2bc --- /dev/null +++ b/content/docs/expo-devtools/production.mdx @@ -0,0 +1,44 @@ +--- +title: Leaving it in production +description: Shipping the code is safe. Two switches decide whether anything runs. +--- + +Shipping the code is safe. Until `.init()` runs, nothing is patched and nothing is recorded, so the +cost of leaving the package in a production bundle is the bundle size and nothing else. + +There are two switches, and they do different jobs: + +- **Capture** — `if (DEVTOOLS_ENABLED) devtools.init();` patches `fetch`, `XMLHttpRequest` and + `console`. Skip it and nothing is ever recorded. +- **Access** — `{DEVTOOLS_ENABLED && }` draws the floating button. Skip it and there + is no way into the panel. + +`DEVTOOLS_ENABLED` is whatever condition you want, evaluated at runtime. +`process.env.EXPO_PUBLIC_APP_ENV !== 'prod'` from the [Quick start](/docs/expo-devtools/quick-start) and +`__DEV__` are the two usual choices; anything else works too, including a value you fetch for a +specific user. + + + It hides itself until `init()` has brought the panel up, so skipping the `init()` call alone is + enough. Guarding both is still worth doing — it keeps the component out of the render tree entirely. + + +That also settles the [Debug tab](/docs/expo-devtools/debug), whose buttons call straight into the native +module and are **not** restricted to development builds. They live behind the panel, and the panel is +unreachable without `init()`. + +## The two things that do run in production + +- **Crash reporting**, if you asked for it. `crash: { enableWhileDevtoolsDisabled: true }` installs the + handlers when the client is constructed rather than at `init()`. It is the one subsystem meant to + survive into a release build — see [Crash reporting](/docs/expo-devtools/crash-reporting). +- **The `>` prompt**, if you called `init()`. `console.repl` defaults to `true` and is not gated on + `__DEV__`, so a build that calls `init()` gets a prompt that runs whatever is typed into it. Set + `console: { repl: false }` for any build where that is not what you want. + +## Next step + + + + + diff --git a/content/docs/expo-devtools/quick-start.mdx b/content/docs/expo-devtools/quick-start.mdx new file mode 100644 index 0000000..c69b3e6 --- /dev/null +++ b/content/docs/expo-devtools/quick-start.mdx @@ -0,0 +1,168 @@ +--- +title: Quick start +description: Create the client, call init() once at startup, and mount the overlay once at the root. +--- + +Two things have to happen: `init()` runs **once at startup**, and `` is mounted +**once at the root**. Nothing else. + +## 1. Create the client + +One shared instance the rest of your app imports, plus one flag deciding whether it runs at all: + +```ts title="devtools.ts" +import { createDevtoolsClient } from '@axonpack/expo-devtools'; + +export const DEVTOOLS_ENABLED = process.env.EXPO_PUBLIC_APP_ENV !== 'prod'; + +export const devtools = createDevtoolsClient(); +``` + +Set `EXPO_PUBLIC_APP_ENV=prod` for your production builds (in `eas.json`, or a `.env` file) and leave +it unset everywhere else. Use `__DEV__` instead if a dev/release split is all you need. + +## 2. Wire it up + +Use whichever of these matches your app. You only need one. + + + + + +The root layout is the place. `devtools.init()` goes at **module scope**, outside the component, so +the `fetch` and `console` patches are installed before the first screen renders. + +```tsx title="app/_layout.tsx" +import { Stack } from 'expo-router'; +import { DevtoolsOverlay } from '@axonpack/expo-devtools'; +import { devtools, DEVTOOLS_ENABLED } from '../devtools'; + +if (DEVTOOLS_ENABLED) devtools.init(); + +export default function RootLayout() { + return ( + <> + + {DEVTOOLS_ENABLED && } + + ); +} +``` + + + + + +`init()` goes in the entry file, before the app is registered. The overlay goes in your root +component. + +```ts title="index.ts" +import { registerRootComponent } from 'expo'; +import App from './App'; +import { devtools, DEVTOOLS_ENABLED } from './devtools'; + +if (DEVTOOLS_ENABLED) devtools.init(); +registerRootComponent(App); +``` + +```tsx title="App.tsx" +import { DevtoolsOverlay } from '@axonpack/expo-devtools'; +import { DEVTOOLS_ENABLED } from './devtools'; + +export default function App() { + return ( + <> + + {DEVTOOLS_ENABLED && } + + ); +} +``` + + + + + +That is it. Drag the button anywhere on screen, tap it to open the panel, and the Network and Console +tabs are already recording. The Storage tab is empty until you tell it which stores you use — see +[Storage](/docs/expo-devtools/storage). The panel reopens on whichever tab you last had open, for as long as +the app is running. + +## Things that trip people up + +- **Mount the overlay exactly once.** The root is the place, because one mount there covers every + route: the panel opens as a modal on top of whichever screen is showing, so nested Tabs and Drawer + layouts are already covered and must not mount their own. A second mount gives you a second button. +- **`init()` runs exactly once too**, at module scope rather than in a `useEffect`. Anything that + fires before an effect would run — requests during module evaluation, logs at import time — is + missed otherwise. +- **Performance starts paused.** Measuring is not free, so press its record button when you want it. + The other two recording tabs record from launch. +- **Expo Go works.** See [Installation](/docs/expo-devtools/installation) for the handful of readings that go + quiet there. +- **In-app browser pages need two extra props** on the `` itself. See + [In-app browsers](/docs/expo-devtools/in-app-browsers). +- **`init()` is the guard.** `` draws nothing until `init()` has brought the panel + up, so an unguarded mount in a release build is harmless rather than a button over empty lists. + Crash reports still surface, because that is the one subsystem meant to run in production. + +## Optional: starting before Expo Router + +Skip this unless you need it. Step 2 is enough for normal use. + +The root layout runs after Expo Router's own entry file, so requests and logs from that window are +missed, and the startup breakdown's *App setup* phase starts later than the app really did. You can +move `init()` ahead of Expo Router by owning the entry file yourself. + +Point `main` at your own file: + +```json title="package.json" +{ "main": "index.js" } +``` + +Then have that file call `init()` before handing control to Expo Router. The import order is the whole +point, so keep `init()` in a separate module rather than calling it inline: an `import` is hoisted +above statements in the same file, which would put `expo-router/entry` first anyway. + +```js title="index.js" +import './devtools-init'; // a module whose only job is `devtools.init()` +import 'expo-router/entry'; +``` + +Now remove the `devtools.init()` line from `app/_layout.tsx`, keeping `` there. The +overlay still belongs in the root layout; only the `init()` call moves. + +## The launcher button + +Nothing has to be configured: `` on its own gives you the bug glyph on a blue +circle. Everything about its appearance is a prop, since that is where you mount it. + +| Prop | Default | What it does | +| --------------- | ----------- | --------------------------------------------------------------------------------- | +| `iconComponent` | none | Renders in place of the built-in glyph. Given the resolved `size`; colour is yours | +| `size` | `44` | Diameter of the button, in dp | +| `color` | accent blue | Button fill | +| `iconColor` | white | The built-in glyph only; an `iconComponent` colours itself | + +```tsx + } + size={56} + color="#111827" +/> +``` + +A `size` under 44 still gets a 44dp touch area through `hitSlop`, so a small button stays as easy to +hit as it looks, and however big you make it, the drag stays inside the screen. + + + `color` and the default glyph have to work together: a pale button needs `iconColor` set, or the + white glyph vanishes into it. + + +## Next step + + + + + diff --git a/content/docs/expo-devtools/reference/client.mdx b/content/docs/expo-devtools/reference/client.mdx new file mode 100644 index 0000000..4de0e46 --- /dev/null +++ b/content/docs/expo-devtools/reference/client.mdx @@ -0,0 +1,135 @@ +--- +title: createDevtoolsClient +description: Every configuration option, and every method on the client it returns. +--- + +```ts +import { createDevtoolsClient } from '@axonpack/expo-devtools'; + +export const devtools = createDevtoolsClient(config?); +``` + +Call it once, at module scope, and export the instance. Everything else hangs off it. Every option is +optional, and the defaults are what most apps want. + +## Top level + +| Option | Type | Default | What it does | +| ---------------- | ----------------------------- | ----------- | ----------------------------------------------------------------------------------- | +| `defaultTheme` | `ThemeId` | `'light'` | Which theme the panel opens with: a built-in or one of yours. | +| `themes` | `Record` | `undefined` | Your own themes: a `base` to inherit and the tokens to override. | +| `webviewSources` | `readonly string[]` | `undefined` | Names of ``s allowed to report in, for both the Network and Console tabs. | + +`webviewSources` uses a `const` type parameter, so the literal names flow into the WebView helpers' +parameter types: passing an undeclared name is a compile error, and at runtime a message from an +undeclared source is dropped. + +## Network + +The switches name the **kind of traffic**, not the mechanism that carried it. A request is a request +whether it went out through `fetch`, through `XMLHttpRequest`, from a JSI client or from inside a page. + +| Option | Type | Default | What it does | +| --------------------------- | --------- | ------- | --------------------------------------------------------------------------------- | +| `network.http` | `boolean` | `true` | Capture plain requests, by whatever transport they left on. Off also means no phase timing. | +| `network.websocket` | `boolean` | `true` | Capture WebSocket connections and their messages, the app's own and a page's. | +| `network.sse` | `boolean` | `true` | Capture server-sent event streams and their events, whichever client opened them. | +| `network.disabledByDefault` | `boolean` | `false` | Open the Network tab paused. | + +With `sse` off, the app's own stream is still recognised as one — its endless body has to be, or it +would be read as a response — so the row remains and only the events are dropped. A page's stream has no +request underneath it that anything here can see, so that one disappears entirely. + +## Console + +| Option | Type | Default | What it does | +| --------------------------- | ------------------------- | ----------- | --------------------------------------------------------------------------- | +| `console.capture` | `boolean` | `true` | Mirror `console.*` into the Console tab, including from declared WebViews. | +| `console.repl` | `boolean` | `true` | Show the `>` prompt. | +| `console.context` | `Record` | `undefined` | Extra names an expression can use, for example `{ store, queryClient }`. | +| `console.disabledByDefault` | `boolean` | `false` | Open the Console tab paused. The prompt still works. | + + + It defaults to `true` in every build. Once `init()` has run the prompt is there, including in a + release build, where it runs whatever is typed into it. Guard your `init()` call, or set + `console: { repl: false }`. + + +## Performance + +| Option | Type | Default | What it does | +| ------------------------------------ | --------- | ------- | --------------------------------------------------------------------------------- | +| `performance.sampleIntervalMs` | `number` | `1000` | How often memory is sampled. Each read crosses into the engine, so keep it coarse. | +| `performance.longTaskThresholdMs` | `number` | `150` | Only keep tasks that blocked the JS thread at least this long. | +| `performance.interactionThresholdMs` | `number` | `100` | Only keep interactions at least this long, event to next paint. | +| `performance.historySize` | `number` | `120` | How many memory samples, long tasks, user timings and interactions are kept. | +| `performance.disabledByDefault` | `boolean` | `true` | Open the Performance tab paused. **Defaults to on**, since measuring costs something. | + +## Storage + +| Option | Type | Default | What it does | +| -------------------- | ---------------------------- | ----------- | ----------------------------------------------------------------------- | +| `storage.adapters` | `StorageAdapterDefinition[]` | `undefined` | The stores the Storage tab can see. Nothing is discovered automatically. | +| `storage.maxKeys` | `number` | `1000` | Keys read per store before the tab stops and says how many it skipped. | +| `storage.readOnly` | `boolean` | `false` | Blanket read-only default; an individual adapter can still set its own. | + +See [Storage adapters](/docs/expo-devtools/reference/storage-adapters) for how to build one. + +## Crash + +Crash capture is the only part of this package that can run without `init()`. + +| Option | Type | Default | What it does | +| ----------------------------------- | ------------------------------------------ | -------- | -------------------------------------------------------------------------------------------------- | +| `crash.enabled` | `boolean` | `true` | Capture at all. | +| `crash.enableWhileDevtoolsDisabled` | `boolean` | `false` | Install the handlers when the client is **constructed**, so crashes are reported without `init()`. | +| `crash.handlers.jsErrors` | `boolean` | `true` | The `ErrorUtils` global handler — fatal and non-fatal JS errors. | +| `crash.handlers.unhandledRejections` | `boolean` | `true` | Unhandled promise rejections, via the Hermes rejection tracker. | +| `crash.handlers.nativeExceptions` | `boolean` | `true` | Uncaught Java/Kotlin and Objective-C exceptions, via the native module. | +| `crash.popupDetail` | `'auto' \| 'full' \| 'compact'` | `'auto'` | Which sheet a crash opens. `'auto'` is the full sheet when the devtools are enabled, compact when not. | +| `crash.disableDefaultLogBox` | `boolean` | `false` | Uninstall React Native's LogBox, so a JS error is reported here and nowhere else. | +| `crash.breadcrumbs` | `boolean` | `true` | Attach the recent console and network entries to each record. | +| `crash.maxBreadcrumbs` | `number` | — | How many breadcrumbs are attached. | +| `crash.maxRecords` | `number` | `25` | Reports kept in memory. | +| `crash.persistNonFatal` | `boolean` | `false` | Also write non-fatal records to disk. | +| `crash.redact` | `(record: CrashRecord) => CrashRecord \| null` | `undefined` | Runs before the record reaches the store, the disk or `onCrash`. Return `null` to drop it. | +| `crash.onCrash` | `(record: CrashRecord) => void` | `undefined` | Your own handler, after `redact`. | + +Before `init()`, an app relying on `enableWhileDevtoolsDisabled` alone installs `nativeExceptions` only, +whatever the other two say: the JS tiers report errors the app survived, which is a developer's concern, +and the sheet there is in front of a user. A fatal JS error still arrives, because React Native turns it +into a native exception on the way to killing the process. + +`disableDefaultLogBox` uninstalls LogBox rather than muting it, which takes the **yellow warning toasts +with it** — LogBox is one component and the two cannot be separated. Warnings are still captured by the +Console tab. It only does anything in development; LogBox is already an empty stub in a release build. + +## Client methods + +| Member | What it does | +| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `init()` | Installs everything: the fetch/XHR patches, the console patch, the REPL context, the performance collectors, your storage adapters, and your themes. Until this runs, nothing is captured and no store is read. Call once, as early as possible. | +| `mark(name, options?)` | Records a user-timing mark. `options`: `{ detail?, startTime? }`. | +| `measure(name, startOrOptions?, endMark?)` | Records a measure. Second argument is a start-mark name or `{ start?, end?, duration?, detail? }`. Passing `start`, `end` **and** `duration` together throws, since they can disagree. | +| `clearMarks(name?)` | Drops recorded marks, all of them or one name. | +| `clearMeasures(name?)` | Drops recorded measures, all of them or one name. | +| `setCrashContext(context)` | Extra keys attached to every crash record from here on — user id, route, feature flags. | +| `getWebViewInjectedJavaScriptBeforeContentLoaded(source)` | The script to hand a ``'s `injectedJavaScriptBeforeContentLoaded`. Covers both requests and console output. | +| `handleWebViewMessage(event)` | Feed a ``'s `onMessage` events here. Returns `true` when it consumed one. | +| `getWebViewRef(source)` | A ref to attach to the ``, so a throttle change reaches an already-open page. | +| `getWebViewUserAgent()` | The current user-agent override, for the `userAgent` prop. | +| `shouldAllowWebViewRequest` | For `onShouldStartLoadWithRequest`. Blocks navigation while Offline is on. | +| `networkLogStore`, `networkConditionsStore`, `consoleLogStore`, `storageStore`, `crashStore` | The underlying stores, if you want to read or drive them yourself. | + +## User timing + +```ts +devtools.mark('checkout'); +await buildCart(); +devtools.measure('checkout'); // measures from the mark of the same name +``` + +`measure` follows the [W3C User Timing](https://www.w3.org/TR/user-timing/) signatures, and calls are +forwarded to the real `performance.mark` and `performance.measure` too, so the entries exist on the +platform timeline as well. Nothing is *observed* from that timeline, which is why React's own internal +measures never appear in the list. diff --git a/content/docs/expo-devtools/reference/console-tab.mdx b/content/docs/expo-devtools/reference/console-tab.mdx new file mode 100644 index 0000000..edb798f --- /dev/null +++ b/content/docs/expo-devtools/reference/console-tab.mdx @@ -0,0 +1,61 @@ +--- +title: Console tab +description: Toolbar, filters, row anatomy, and the > prompt. +--- + +Mirrors `console.log`, `.info`, `.warn`, `.error` and `.debug`, plus output from wired-up WebView pages. +Holds the **500** most recent rows. + +## Toolbar + +| Control | What it does | +| ----------------- | -------------------------------------------------------------------------------- | +| Record / Clear | As on [the panel](/docs/expo-devtools/reference/panel#toolbar-row). The `>` prompt still answers while capture is paused. | +| Filter (⌕ list) | Opens the filters panel. | +| Warn/error counts | On the right: a live count of captured warnings and errors, each in its colour. | + +## Filters panel + +| Field | What it does | +| ---------------- | -------------------------------------------------------------------------------------------------- | +| Search box | Matches the rendered text of a message. | +| **Level** chips | `All (n)`, `Logs (n)`, `Info (n)`, `Warnings (n)`, `Errors (n)`, `Debug (n)`. Counts are live. | +| **Source** chips | One per source, shown only when more than one source has logged — that is, once a WebView reports in. | + +## A console row + +| Element | Meaning | +| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Level icon | Info, warning, error and debug get a glyph and colour; warnings and errors tint the whole row. | +| Arguments | One cell per logged argument, so a message and its object stay apart. Objects and arrays render as a collapsed JSON tree; tap to expand level by level. | +| Error | The message on the row; tap to expand the full stack. | +| Source | `WebView::[name]` for browser-view output; absent for your app's own. | +| ×n | Repeat count. Consecutive identical messages from the same source collapse into one row. | +| Time | Wall-clock time of the most recent occurrence. | +| Copy | Copies the row's text. | + +The list follows the newest output and stops following the moment you scroll back, with a ⌄ button to +jump to the newest again. + +A row for an uncaught error links to its own crash report: tapping the message opens the report over +the Console tab, while the disclosure arrow still expands the inline stack. + +## The `>` prompt + +Present when the REPL is enabled through `console.repl`, which +[defaults to `true` in every build](/docs/expo-devtools/reference/client#console). + +- Type an expression and submit: your input appears as an `input` row (`›`), the result as a `result` + row (`‹`). Objects come back as the same explorable tree. +- A returned promise shows as pending and fills in when it settles. +- **Suggestions** appear as chips above the prompt as you type, including members of whatever object + you are inside. Tap one to complete. +- **Tap any earlier input row** to load that command back into the prompt. +- `$modules('auth')` lists loaded Metro modules matching a string; `$m('src/stores/auth')` returns one. + Both read Metro's module registry, which only a development bundle has, so in a release build they + return nothing. +- Anything passed in `console.context` is in scope by name. + +Your app's own imports are **not** reachable by name: a bundled module is a private closure, so there is +nothing for an expression to resolve. `context` is how you hand over the objects you want to poke at, +and it is the only route that works in a release build. diff --git a/content/docs/expo-devtools/reference/debug-tab.mdx b/content/docs/expo-devtools/reference/debug-tab.mdx new file mode 100644 index 0000000..3c8cd99 --- /dev/null +++ b/content/docs/expo-devtools/reference/debug-tab.mdx @@ -0,0 +1,33 @@ +--- +title: Debug tab +description: Blocking and crashing a thread on purpose. +--- + +Tools that break the app on purpose, so the numbers on the other tabs can be trusted. No toolbar: there +is no stream to record and nothing to clear. + +## Block and crash a thread + +Every Performance section reports something that happened; these go out and cause it, which is why +they sit here rather than there. + +| Field | Options | +| ------ | ---------------------------------------------------------------------------------- | +| Thread | **JavaScript** (works everywhere) or **Main (UI)** (needs a dev build). | +| For | `100ms`, `250ms`, `500ms`, `1s`, `3s`, or a custom value in ms. | +| Block | Blocks the chosen thread for that long. | +| Crash | Crashes the chosen thread. Takes two taps: the first arms it, the second does it. | + +Blocking the JS thread shows up as a long task and drops the JS frame rate. Blocking the main thread +freezes the screen while every JS number stays healthy. That gap is the blind spot the frame-rate card +warns about, and this is how you see it for yourself. + + + The crash paths do not go through any store, so `.init()` is not what keeps them out of a release: + they work as soon as the panel is on screen. What gates them is whether you rendered + `` at all. + + +Both crash paths are captured by the Crashes tab when crash reporting is on. A JS crash is reported +before you let go of the button; a main-thread crash ends the process and is read back off disk at the +next launch. diff --git a/content/docs/expo-devtools/reference/development-build.mdx b/content/docs/expo-devtools/reference/development-build.mdx new file mode 100644 index 0000000..db8781d --- /dev/null +++ b/content/docs/expo-devtools/reference/development-build.mdx @@ -0,0 +1,28 @@ +--- +title: What needs a development build +description: Feature by feature, what Expo Go shows instead. +--- + +Everything not listed here works in Expo Go. The native module is loaded optionally, so a missing module +dims a control instead of breaking the panel. + +| Feature | Without a dev build | +| --------------------------- | ------------------------------------------------------------ | +| Main-thread frame rate | Reads `dev build`; the JS line still plots. | +| App memory · Device memory | Card says `Needs a dev build`. | +| Storage card (disk space) | Card says `Needs a dev build`; Android only regardless. | +| Startup, measured block | Falls back to the platform block, which may be all dashes. | +| Debug tab, Main (UI) thread | Block and crash buttons disabled with a note. | +| Native crash capture | Uncaught native exceptions are not reported. | + +## Platform-dependent regardless of build type + +Long tasks and interactions only appear if the native side implements those entry types, which varies by +platform and React Native version. When they are missing the list says so rather than showing zeros. + +## The Storage tab is a special case + +It needs nothing from this package's native module — but the stores you register bring their own +requirements. MMKV and SecureStore carry native code of their own, so a store that needs a dev build to +exist at all also needs one to be inspectable. A store built on `defineStorageAdapter` alone (an +in-memory `Map`, say) works in Expo Go. diff --git a/content/docs/expo-devtools/reference/index.mdx b/content/docs/expo-devtools/reference/index.mdx new file mode 100644 index 0000000..d535774 --- /dev/null +++ b/content/docs/expo-devtools/reference/index.mdx @@ -0,0 +1,38 @@ +--- +title: Overview +description: Every control, section and field in the panel, and the whole public API. +icon: House +--- + +The [Guides](/docs/expo-devtools) are the tour. This is the map. + +Throughout: **dev build** means the feature reads this package's native module, so it is dark in Expo +Go and lights up in a build made with `expo run:ios`, `expo run:android` or EAS. Nothing in the panel +crashes without it: the control says what it needs instead. + +## The panel + + + + + + + + + + +## API + + + + + + + + + +## Platform + + + + diff --git a/content/docs/expo-devtools/reference/meta.json b/content/docs/expo-devtools/reference/meta.json new file mode 100644 index 0000000..ec6f64e --- /dev/null +++ b/content/docs/expo-devtools/reference/meta.json @@ -0,0 +1,24 @@ +{ + "title": "Reference", + "description": "Every control, section and field in the panel, and the whole public API", + "icon": "SquareTerminal", + "defaultOpen": false, + "pages": [ + "index", + "---The panel---", + "panel", + "network-tab", + "console-tab", + "performance-tab", + "storage-tab", + "debug-tab", + "---API---", + "client", + "storage-adapters", + "overlay", + "themes", + "types", + "---Platform---", + "development-build" + ] +} diff --git a/content/docs/expo-devtools/reference/network-tab.mdx b/content/docs/expo-devtools/reference/network-tab.mdx new file mode 100644 index 0000000..12886ea --- /dev/null +++ b/content/docs/expo-devtools/reference/network-tab.mdx @@ -0,0 +1,142 @@ +--- +title: Network tab +description: Toolbar, filters, settings, throttle profiles, the request row, the detail sheet and the sandbox. +--- + +Three capture paths feed one list: `fetch`, `XMLHttpRequest` (which is what catches axios and most HTTP +client libraries), and any `` you wired up. The list holds the **200** most recent requests; +older ones fall off the end. Request and response bodies are kept in full, never truncated. + +## Toolbar + +| Control | What it does | +| ----------------- | ---------------------------------------------------------------------------------------------------------------------- | +| Record / Clear | As on [the panel](/docs/expo-devtools/reference/panel#toolbar-row). | +| Sort (↑ / ↓) | Flips the direction of whatever **Sort by** is set to. Its label says what pressing it would give you. | +| Filter (⌕ list) | Opens the filters panel below. | +| Preserve log (🔖) | On by default. Keeps captured rows when a wired-up WebView page navigates; off means the log clears with the page. | +| Export (⤓) | Opens the OS share sheet with the **currently filtered** list as JSON, named `network-log-.json`. | +| Settings (⚙) | Opens the settings panel below. | + +## Filters panel + +| Field | What it does | +| ---------------------------- | ---------------------------------------------------------------------------------------------------------------- | +| Search box | Matches method, URL, status code and source, not header or body text. Clear it with the ✕ inside the box. | +| **Invert** chip | Shows everything that does *not* match the search text. | +| **Type** chips | `All`, `Fetch/XHR`, `JS`, `Img`, `Media`, `Other`, classified from the response MIME type. | +| **Status** chips | `All` plus one per band captured (`2xx`, `4xx`, `Failed`, `Pending`). Each one writes the field below. | +| Status expression | `404`, `4xx`, `>= 400`, `200-299`, `failed`, `pending`. Unreadable text turns the field red and filters nothing. | +| **Method** chips | One per method actually captured (`GET`, `POST`, …), and more than one can be on at once. `All` clears them. | +| **Source** chips | One per source seen — your app, or `WebView::[name]` per declared browser view — and again multi-select. | +| More filters ▸ | Reveals the rest, below. | +| Size: at least / at most | Bytes, or with a unit: `500`, `20kb`, `1.5mb`. | +| Duration: at least / at most | Milliseconds, or with a unit: `250`, `800ms`, `1.5s`, `2min`. | +| Only requests in flight | Keeps just the ones that have not finished. | +| Only overridden or blocked | Keeps just the ones a rule of yours answered. | +| Hide data URLs | Drops requests whose URL starts with `data:`. | +| Hide failed requests | Drops requests that errored (network failures, not 4xx/5xx responses). | + +Every filter combines with the search. **Invert** negates all of them together except the two `Hide` +switches, which stay absolute — inverting those would bring back the exact noise they suppress. A filter +an entry has no figure for excludes it: a socket has no size or status code, and a request in flight has +no duration yet. + +## Settings panel + +| Setting | Default | What it does | +| --------------------- | -------------- | ----------------------------------------------------------------------------------------------------------- | +| Large request rows | On | Off gives compact rows: no short name, no badges, URL as the primary line. | +| **Sort by** | Time | `Time`, `Size`, `Duration`, `Status`, plus the direction the toolbar's arrow also flips. | +| Group by fetch client | Off | Groups rows under a header per source, with a count per group. | +| Show overview | Off | Shows the traffic graph above the list. | +| Stack header values | On below 768dp | In the detail sheet, puts each header's value under its name instead of beside it. | +| **Throttling** | No throttling | `No throttling`, `Slow 3G`, `Fast 3G`, `Fast 4G`, `Offline`, `Custom`. | +| **User agent** | Default | `Default`, `iPhone Safari`, `Android Chrome`, `Chrome (macOS)`, `Chrome (Windows)`, `Googlebot`, `Custom`. | + +### Throttle profiles + +Applied to your app's own requests and to wired-up WebView pages. + +| Preset | Download | Latency | +| ------- | ------------------------ | ------------------------------------------ | +| Slow 3G | 400 kbps | 2000 ms | +| Fast 3G | 1638 kbps | 563 ms | +| Fast 4G | 9000 kbps | 85 ms | +| Offline | none | requests fail immediately | +| Custom | your **Download (kbps)** | your **Latency (ms)** (defaults 750 / 500) | + +Picking **Custom** under User agent reveals a free-text field for the whole UA string. Every captured +request records the conditions it ran under, so the detail sheet can show them later. + +## Overview strip + +Shown when **Show overview** is on, and only once at least one request is captured. + +- 36 buckets spanning the oldest to the newest captured request; bar height is request count. +- A bucket containing a failed request is drawn in the error colour. +- Tap a bucket to narrow the list to that slice of time; tap it again to clear. +- The row underneath shows the first timestamp, the selected span, and the last timestamp. + +## A request row + +| Element | Meaning | +| --------------- | --------------------------------------------------------------------------------------------- | +| Method | Colour-coded per verb. | +| Status | The HTTP code, or the error text, or an amber **PENDING** while still in flight. | +| Duration · time | Total ms and the wall-clock start. A dash until it finishes. | +| Type icon | Per response kind; JSON gets its own glyph. | +| Name | Last path segment plus the query string (large rows only). | +| URL | Full URL, one line on large rows, two on compact. | +| Badges | Resource type · source (only when it came from a WebView) · response size (large rows only). | +| ⋮ | The copy menu, also on long-press anywhere in the row. | + +The copy menu: **Copy URL**, **Copy as cURL**, **Copy as fetch**, **Copy as fetch (Node.js)**, plus +**Copy request payload** and **Copy response** when those exist. + +## Detail sheet + +Tapping a row opens a sheet with up to five tabs. It always opens on **Headers**. + +### Headers + +| Section | Fields | +| ------------------ | -------------------------------------------------------------------------------------------------------------- | +| General | Request URL, Request Method, Status Code, Source (only for WebView traffic). | +| Network Conditions | Throttling, User Agent, and Agent String when an override was active. Amber when throttled, red when offline. | +| Request Headers | Every header sent, with a per-value copy button. Count in the section header. | +| Response Headers | Every header received, same treatment. | + +### The other four + +- **Payload** — the request body as an explorable JSON tree. The tab is hidden entirely when the + request had no body. +- **Preview** — the response rendered: pretty-printed and syntax-coloured JSON, a real image for image + responses, HTML as HTML. Falls back to `No preview available`. +- **Response** — the raw response body, in full, with a copy button. +- **Timing** — Started At and Duration (`(pending)` while in flight), plus a note that a + DNS/TCP/TLS/TTFB breakdown is not observable from JS, since those phases happen in the native + networking stack. + +The sheet's ⋮ menu adds **Try in sandbox** above the same copy items as the row menu. + +## Sandbox + +Opens the request as something editable, seeded from what was captured: URL, method, query parameters, +headers, cookies, auth and body all split into their own fields. + +| Area | What is in it | +| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| URL bar | The base URL, without the query string. | +| Method chips | `GET`, `POST`, `PUT`, `PATCH`, `DELETE`. | +| Send | Fires the request and switches to the Response tab. | +| **Request** tab | Authentication · Query Parameters · Headers · Cookies · Body. | +| **Response** tab | Status code and text, colour-coded, with the round trip in ms; Response Headers (with count); Response Body. A failed request shows `Request failed` and the error instead. | + +Authentication offers `none`, `bearer` (a **Token** field) and `apikey` (a header-name field, for +example `x-api-key`, and a **Value** field). Query parameters, headers and cookies are key/value tables +that grow a blank row as you fill the last one. Cookies are recombined into one `Cookie` header on +send. + +Sandbox requests go out through the same patched `fetch`, so they appear in the log like any other +request. diff --git a/content/docs/expo-devtools/reference/overlay.mdx b/content/docs/expo-devtools/reference/overlay.mdx new file mode 100644 index 0000000..acd0ba0 --- /dev/null +++ b/content/docs/expo-devtools/reference/overlay.mdx @@ -0,0 +1,29 @@ +--- +title: DevtoolsOverlay +description: The launcher button's props, and what mounting it means. +--- + +```tsx +import { DevtoolsOverlay } from '@axonpack/expo-devtools'; +``` + +| Prop | Type | Default | What it does | +| --------------- | --------------------------------- | ----------- | ------------------------------------------------------------------- | +| `iconComponent` | `ComponentType<{ size: number }>` | none | Renders in place of the built-in glyph. Given the resolved `size`. | +| `size` | `number` | `44` | Diameter of the button, in dp. | +| `color` | `string` | accent blue | Button fill. | +| `iconColor` | `string` | `'#ffffff'` | The built-in glyph only; an `iconComponent` colours itself. | + +The button is draggable, stays inside the screen, and keeps a 44dp touch area through `hitSlop` even at +a smaller `size`. Mounting it is also what marks *first render* for the startup breakdown. + +The overlay renders whether or not `.init()` has run: it takes no `enabled` prop and reads no store to +decide. Guard the mount itself when you do not want the panel reachable, as in the +[Quick start](/docs/expo-devtools/quick-start). + +## Related components + +| Component | What it is for | +| -------------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| `` | The crash sheet on its own, for a build that ships crash reporting but not the panel. `` mounts one itself; mounting both is harmless. | +| `` | Catches render errors — the only tier that produces a component stack. Props: `children`, `fallback(error, reset)`, `onError(error, info)`. | diff --git a/content/docs/expo-devtools/reference/panel.mdx b/content/docs/expo-devtools/reference/panel.mdx new file mode 100644 index 0000000..f9d9801 --- /dev/null +++ b/content/docs/expo-devtools/reference/panel.mdx @@ -0,0 +1,60 @@ +--- +title: The panel +description: The header row, the toolbar row, and the two gates that are easily confused. +--- + +`` renders a draggable floating button. Tapping it opens a full-screen modal; the +button itself never appears inside the modal. + +## Header row + +| Item | What it does | +| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Tab bar | **Network**, **Console**, **Performance**, **Storage**, **Crashes**, **Debug**. Scrolls horizontally on a narrow screen. | +| Error badge | A red count on the Console tab when it is not the active tab, showing captured `console.error`s. The Crashes tab carries the same badge for unread reports. | +| Palette (🎨) | Opens the theme list; the active one is ticked. Applies immediately. | +| Close (✕) | Dismisses the panel. Recording carries on while it is closed. | + +The tab you last had open is remembered for the life of the app process, so reopening the panel returns +you to it. Only the active tab is mounted, so switching tabs and back resets that tab's filters, its +open detail sheet and its scroll position. Captured data is untouched: it lives in the stores, not the +views. + +## Toolbar row + +On the three tabs that record — Network, Console, Performance — it opens with the same two controls: + +| Control | What it does | +| ---------- | ------------------------------------------------------------------------------------ | +| Record (⏺) | Pauses and resumes **capture** for that tab. Red when recording, hollow when paused. | +| Clear (⊘) | Throws away everything that tab has collected. Not undoable. | + +Not every tab has one: + +- **Storage** has no record button, on purpose: it reads on demand rather than recording, so there is + no stream to pause, and a clear button there would mean wiping your storage rather than dropping a + log. It opens with Refresh instead. +- **Crashes** has a clear button but no record button — a crash is not a stream you can afford to have + switched off. +- **Debug** has no toolbar at all: nothing there records or collects. + +## The two gates + +Pausing and `.init()` are different switches, and the difference matters when you ship. + +| Gate | Set by | What it does | +| ---------- | ----------------------------- | ---------------------------------------------------------------------------------------- | +| `.init()` | Your call, once at startup | Until it runs, nothing is patched, observed or recorded anywhere. There is no UI for it. | +| Record | The record button in a toolbar | Pauses a tab that `.init()` already turned on. | + +`disabledByDefault` in the config sets the **record** gate, not the `.init()` one, so a tab that starts +paused can always be started from its own toolbar. + +`.init()` controls both **capture** and **access**: the overlay subscribes to whether `.init()` +finished and draws nothing until it has, so an unguarded mount in a release build shows no button +rather than a panel over empty lists. There is no config flag that says "off" — not calling `.init()` +is what says it. + +The one thing the overlay keeps rendering is the crash report sheet, which is +[meant to work in production](/docs/expo-devtools/crash-reporting). Guarding the mount as well is still worth +doing; it just is not what keeps the panel out. diff --git a/content/docs/expo-devtools/reference/performance-tab.mdx b/content/docs/expo-devtools/reference/performance-tab.mdx new file mode 100644 index 0000000..1a02e77 --- /dev/null +++ b/content/docs/expo-devtools/reference/performance-tab.mdx @@ -0,0 +1,120 @@ +--- +title: Performance tab +description: Statistics cards, user timing, interactions and long tasks. +--- + +The toolbar carries the record button, the clear button, then the section chips: + +``` +[⏺] [⊘] │ (Statistics) (User timing) (Interactions) (Long tasks) +``` + +Only the chosen section is mounted, which is deliberate: the charts stop re-rendering while you read a +list, and a burst of long tasks does not re-render a chart. The three list chips carry a live count +when they have entries. + +This tab **starts paused** (`performance.disabledByDefault` defaults to `true`) because measuring costs +something. While paused the collectors are detached rather than left running and filtered, so a paused +tab costs nothing at all; pressing record attaches them fresh and re-reads whatever the platform still +has buffered. Every empty list shows the same **Not recording** panel with a *Start recording* button. + +`performance.historySize` (default 120) caps the memory samples, long tasks, user timing entries and +interactions kept. + +## Statistics + +Four cards plus the startup breakdown. + +### Frames per second + +| Field | Meaning | +| ----------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| JS thread | Current frames per second from a `requestAnimationFrame` delta loop, sampled every 500 ms. | +| Main thread | Current frames per second from a native display-link counter. Reads `dev build` without the native module. | +| Chart | Both threads on one plot, one colour per thread, 60 buckets of 5 s, covering the **last 5 min**. Each bucket keeps its worst reading. | +| Axis | Scaled to the confirmed peak (min 60) plus headroom, so a 120 Hz device is not clipped. | + +The gap between the two lines is the reading that matters: a healthy JS line above a collapsed main line +is an app that feels frozen while every JS metric says it is fine. + +### Interactions card + +The slowest event-to-next-paint seen, with the average and the count as the hint. Before anything is +captured it reads `Slowest event to next paint`. + +### Memory + +| Field | Meaning | +| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| JS Heap plot | `performance.memory` used heap, captioned `of allocated`. Reads `This JS engine doesn't report it` on JSC/V8. | +| App memory plot | Whole-process footprint, what the OS holds against you. Needs a dev build. | +| Device memory meter | Used against total RAM, captioned with what is still available to this app. On Android that is system-wide free memory; on iOS it is what the process can still claim. Needs a dev build. | + +Both plots are sampled on `performance.sampleIntervalMs` (default 1 s) and span `historySize` samples, +two minutes at the defaults. Each carries its own peak marker. + +### Storage + +Disk space, not the [Storage tab](/docs/expo-devtools/reference/storage-tab)'s contents — a Used meter against the +data partition's total, captioned with the free space. Android only, and needs a dev build; the card +says which of the two is missing. + +iOS is absent on purpose: `systemFreeSize` is one of Apple's required-reason APIs, and a library reading +it would push a privacy-manifest declaration onto every app that embeds it. + +### Startup + +Process start to first render, read once at launch. Up to two blocks: + +| Block | Rows | +| ------------------------ | ----------------------------------------------------------------- | +| Measured by this package | Total · Native startup · Bundle eval · App setup · To first render | +| Reported by the platform | Total · Native init · Runtime setup · Bundle eval | + +The measured block comes from the native module's real process start time, so it works where the +platform's own markers are all null. Its phase boundaries are this package's own load points, so they +shift a little with your import order; the earlier you call `.init()`, the truer *App setup* is. The +platform block is `performance.rnStartupTiming`, and a dash means the platform never reported that +marker. The whole section is hidden when neither is available. + +## User timing + +Marks and measures you record yourself, newest first. + +| Column | Meaning | +| -------- | -------------------------------------------------------------- | +| Name | The name you passed. | +| Kind | An icon, not a word: a pin for a mark, a ruler for a measure. | +| Detail | Your `detail`, stringified, when you passed one. | +| Time | Wall-clock time it was recorded. | +| Duration | The measured span; a mark shows `—`. | + +This is the only list here that can point at a specific piece of your code, which makes it the answer to +a long task you cannot explain. See [`mark` and `measure`](/docs/expo-devtools/reference/client#user-timing). + +## Interactions + +Anything slower than `performance.interactionThresholdMs` (default 100 ms) from event to next paint. + +| Column | Meaning | +| ----------- | -------------------------------------------------- | +| Name | The event type. | +| handler Xms | How long your handler itself held the JS thread. | +| Duration | Event to next paint, colour-coded by severity. | + +A small handler under a large total means the interaction was stuck behind something else rather than +being slow itself. The platform rounds durations to 8 ms and never reports anything under 16 ms. + +## Long tasks + +Stretches of JavaScript that ran without yielding for longer than +`performance.longTaskThresholdMs` (default **150 ms**), newest first: name, wall-clock time, and +duration colour-coded by severity. At 60 fps a frame is 16.7 ms, so 150 ms is about nine frames lost; +past roughly 200 ms it reads as a freeze. + +A long task tells you *when* to look, never at what: React Native's `PerformanceLongTaskTiming` returns +a permanently empty `attribution` array. Correlate against what the app was doing, or wrap the suspect +in `mark` and `measure`. + +Both this list and Interactions show a note when the platform's own buffer overflowed and discarded +entries before the panel could read them. diff --git a/content/docs/expo-devtools/reference/storage-adapters.mdx b/content/docs/expo-devtools/reference/storage-adapters.mdx new file mode 100644 index 0000000..044c49d --- /dev/null +++ b/content/docs/expo-devtools/reference/storage-adapters.mdx @@ -0,0 +1,89 @@ +--- +title: Storage adapters +description: The four factories that tell the Storage tab which stores exist, and what they may do to them. +--- + +Four factories, all built on the last one. Each returns a `StorageAdapterDefinition` for +`storage.adapters`; ids are assigned from the names at `init()`, suffixed on collision. + +```ts +import AsyncStorage from '@react-native-async-storage/async-storage'; +import * as SecureStore from 'expo-secure-store'; +import { createMMKV } from 'react-native-mmkv'; + +const mmkv = createMMKV(); + +createDevtoolsClient({ + storage: { + adapters: [ + asyncStorageAdapter({ driver: AsyncStorage }), + mmkvAdapter({ driver: mmkv }), + secureStoreAdapter({ driver: SecureStore, keys: ['session', 'pin'] }), + defineStorageAdapter({ + name: 'In-memory', + kind: 'sync', + getAllKeys: () => [...map.keys()], + getItem: (key) => map.get(key) ?? null, + setItem: (key, text) => { + map.set(key, text); + }, + removeItem: (key) => { + map.delete(key); + }, + }), + ], + }, +}); +``` + +| Factory | For | +| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| `asyncStorageAdapter({ driver })` | `@react-native-async-storage/async-storage` and anything copying its API. Uses `getMany` (v3) or `multiGet` (v1/v2) for batch reads when present. | +| `mmkvAdapter({ driver })` | `react-native-mmkv`, both majors — v4's `remove` and v3's `delete` are both accepted. | +| `secureStoreAdapter({ driver, keys })` | `expo-secure-store`. Takes `keys` because the keychain cannot be listed, and an optional `options` passed through to every call. | +| `defineStorageAdapter({ ... })` | Anything else. Duck-types nothing; takes exactly what you hand it. | + +## Shared fields + +All four accept these: + +| Field | Type | What it does | +| ---------------- | ------------------------------------------ | ------------------------------------------------------------------------------------- | +| `name` | `string` | Shown in the store dropdown. Defaulted from the library. | +| `readOnly` | `boolean` | Makes this store read-only regardless of what else you passed. | +| `supportedTypes` | `StorageValueType[]` | What the store can actually hold. Defaults to all four. | +| `blacklist` | `RegExp \| ((key: string) => boolean)` | A key it matches is never listed, never read and never written. | +| `kind` | `'sync' \| 'async'` | The badge the tab shows. Never a branch — every read is awaited either way. | + +## `defineStorageAdapter` + +Needs either `getAllKeys` or a fixed `keys` list — passing `keys` is what turns enumeration off, and it +may be a function, resolved on every read, for an app that keeps its own list of what it stored. Then +any of `getItem` (required), `getMany`, `setItem` and `removeItem`. + +**Whether the tab can edit or delete is derived from which of those you provided**, so a store you +registered read-only in effect is read-only in the UI without a flag. Sync functions are fine +everywhere: they are awaited, not branched on. + +`getItem` may return a bare `string | null`, or a `{ text, valueType }` when the type matters — that +second form is how `mmkvAdapter` keeps a stored `1` from rendering as `"1"`, and what an edit is written +back through. + +## `blacklist` + +A `RegExp` or a `(key: string) => boolean`. A key it matches is never listed, never read, and never +written — the filtering happens in the adapter, before the read, not in the view, so the value never +reaches memory at all. A `/g` regex is safe: `lastIndex` is reset before every test. + +The summary says a blacklist is set, but never how many keys it matched. That is a count this tab +deliberately never learns. + +## `supportedTypes` + +The list of types the store can really hold; it defaults to all four. `asyncStorageAdapter` and +`secureStoreAdapter` declare `['string']` for you, since both hand back a string whatever went in; MMKV +takes all four. + +The Add-key sheet offers only these types, so a write the store would have flattened is never offered in +the first place. Binary is never offered for either creating or editing — there is no text form of the +bytes to round-trip. diff --git a/content/docs/expo-devtools/reference/storage-tab.mdx b/content/docs/expo-devtools/reference/storage-tab.mdx new file mode 100644 index 0000000..e14fd47 --- /dev/null +++ b/content/docs/expo-devtools/reference/storage-tab.mdx @@ -0,0 +1,124 @@ +--- +title: Storage tab +description: Toolbar, import, store summary, filters, the key row and the detail sheet. +--- + +Every key in every store you registered, with its value, type and byte size. + +``` +[AsyncStorage 12 ▾] │ [⟳] [+] [Filter] │ [⤓] [⤒] +AsyncStorage · Async · read at 14:22:07 +[12 keys] [4.1 KB] [cache/feed · 1.2 KB] +``` + +Unlike the other three recording tabs, this one **finds nothing by itself**. A key-value store is a +separate install with its own native code, and this package depends on none of them, so the stores +arrive through `storage.adapters` in the client config. With none registered the tab explains that and +shows the snippet to copy, rather than an empty list that would read as "you have no data". + +## Toolbar + +| Control | What it does | +| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Store dropdown (▾) | Which store the tab is showing, with its key count. Appears once a second store is registered; the menu ticks the active one and carries every store's count. | +| Refresh (⟳) | Re-reads the selected store. This is where the record button is in every other tab. | +| Add key (+) | Opens a sheet to write a key the store does not hold yet: a name, a type the store accepts, and a value. Shown only for a store the tab can write to. | +| Filter | Opens the filter panel, at the top of the scrolling content. Pressing it also scrolls you back up to it. | +| Export (⤓) | The currently-filtered entries as JSON through the OS share sheet, under a `schemaVersion`. | +| Import (⤒) | Paste a snapshot back in. Shows what it would do before writing anything. Shown only for a store the tab can write to. | + +Adding a key is a distinct operation from editing one, not an alias: the type is chosen rather than +inherited from a value that is already there, and a key the store already holds is refused rather than +quietly overwritten. The check asks the store, not the list on screen — a store the tab cannot enumerate +holds keys the list never had. + +There is **no record button** — storage is a pull, not a stream, so there is no stream to pause. And no +clear button: that icon means "clear the log" in the other three tabs, and it must never come to mean +"wipe your storage". The tab reads on open and on Refresh; nothing polls. + +## Import + +There is no filesystem module in this package and no dev server to upload to, so a snapshot comes back +the way it left: as text. The sheet takes a paste, or reads the clipboard for you. +Before anything is written it reports what the file would do: how many keys are new, how many would be +overwritten, how many already hold exactly that value, and how many are skipped. Each skip gives its +reason — hidden by the blacklist, a type this store does not hold, or no value to write. A file exported from a different store +is not refused, but it is called out. + +Only then does the Write button do anything. Keys are written one at a time so a failure names the key +that caused it, and the store is re-read afterwards rather than patched key by key — an import is the +one write here big enough for the difference to matter, and a store is free to normalise every value it +was handed. + +A file from a schema version this build does not read is refused outright, with the version it found. + +## Store summary + +The toolbar is the only pinned row. The summary and the filter panel are the list's header, so they +scroll away with the rows — an open filter panel would otherwise leave a phone with almost no list. + +The summary names the store, whether it is `Async` or `Sync`, when it was last read, its key count, +total bytes and largest key — plus whatever needs saying honestly: + +- `SecureStore can't list its own keys — showing the 2 you declared.` +- `Read 1,000 of 4,312 keys — the rest are past the cap.` +- `Read-only — values here cannot be edited or deleted.` + +## Filters panel + +| Section | What it holds | +| ------------ | ---------------------------------------------------------------------------------------------------------------------------- | +| Header | `n of m`, **Invert**, **Clear** — as in the Network tab. | +| Search | The shared search box, with match-case / whole-word / regex modes. | +| Search in | **Keys + values**, **Keys**, **Values**. A key and its value are different haystacks. | +| Type | Object · Array · String · Number · Boolean · Binary · Empty · Missing, with counts. Only types actually present get a chip. | +| Sort by | **Key**, **Size**, **Type**, plus an ascending/descending chip. Sorted by key within a type. | +| More filters | **Group by namespace**, **Hide empty values**, **JSON values only**. | + +**Group by namespace** recovers the prefix conventions no store knows about — `auth:token`, +`cache/user/1`, `settings.theme`, `user_name` — splitting on the first of `:` `/` `.` `_` and grouping +under it. A key with no prefix lands under `Ungrouped`. + +## A key row + +The type glyph, the key, its size, and the value collapsed to one line. Matches from the search are +highlighted in both the key and the value. + +**Empty** and **Missing** are separate types on purpose: an empty string is a value a store can hold, +and conflating the two hides a real one. A key that failed to read shows the reason in red instead of a +value — SecureStore throws per key on a value it cannot decrypt, and losing the whole store to that +would be the wrong trade. Long-press for the copy menu. + +## Detail sheet + +Tap a row for **Value**, **Raw**, **Edit** and **Info**, with a kebab menu of Copy key / Copy value / +Copy as JSON / Copy value (formatted), and **Delete key** when the store can delete. + +| Tab | What it shows | +| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Value | The same inspectable, syntax-highlighted JSON tree as the Network tab's Preview when the text parses as an object or array; monospace text when it does not. | +| Raw | The characters exactly as stored — no parsing, no pretty-printing — with the character and byte counts. | +| Edit | The value in an editable box, with Revert and Save. | +| Info | Key, store, how it is shown, how it is stored, size, read time, whether it can be edited or deleted. | + +Value and Raw carry their own search box for looking inside one large value, the same one the Network +tab's detail sheet uses. + +**Editing.** Save writes through the type the value was read as, so a number edited in a text box is +still a number to the store; a non-numeric edit of a numeric key is refused rather than silently +stringified. The key is then read back rather than assumed, because a store is free to normalise what it +was handed. Broken JSON in a value that was stored as JSON is a **warning, not a block** — a store can +legitimately hold text that was never JSON. Edit says why it is unavailable when it is: the store is +read-only, or was registered without a way to write, or the value is binary. + +**Deleting** asks for confirmation first, and acts on exactly one key. There is no store-wide clear +anywhere in the tab, and no way to add a key that is not already there. + +## What this tab does not do + +- **No mutation history.** Nothing patches the store instance you hand over, so the tab shows state, not + the writes that produced it. +- **No SQLite.** A table needs schema, queries and paging, not a key list — and squeezing `expo-sqlite` + into a key-value adapter would serve neither. +- **Binary values are shown, never edited.** There is no text form of the bytes to round-trip, so only + their length is reported. diff --git a/content/docs/expo-devtools/reference/themes.mdx b/content/docs/expo-devtools/reference/themes.mdx new file mode 100644 index 0000000..3a31abd --- /dev/null +++ b/content/docs/expo-devtools/reference/themes.mdx @@ -0,0 +1,37 @@ +--- +title: Themes +description: The built-in theme ids, and all 22 palette tokens. +--- + +A theme patches a base rather than redefining everything: + +```ts +createDevtoolsClient({ + defaultTheme: 'midnight', + themes: { + midnight: { base: 'dark', colors: { accent: '#a78bfa' } }, + }, +}); +``` + +Built-in ids: `light`, `dark`, `dracula`, `nord`, `monokai`, `one-dark`, `solarized-light`. Reuse one as +your own name and you replace it. A `defaultTheme` naming something unregistered is ignored rather than +leaving the panel unstyled. + +The choice lives in memory for the session. Persisting it would mean taking a storage dependency for a +colour scheme. + +## The 22 tokens of `Palette` + +| Group | Tokens | +| -------- | --------------------------------------------------------------------------------------------- | +| Surfaces | `background`, `toolbarBackground`, `toolbarOverlay`, `sectionTint`, `border` | +| Text | `textPrimary`, `textSecondary` | +| Status | `accent`, `pending`, `success`, `error`, `warning`, `errorSurface`, `warningSurface` | +| Search | `matchHighlight` | +| Syntax | `keyAccent`, `jsonKey`, `jsonString`, `jsonNumber`, `codeKeyword`, `codeComment`, `codeTag` | + + + It is the background painted behind text matching the current search. Every built-in palette sets it + to a translucent colour so syntax highlighting still reads through it. + diff --git a/content/docs/expo-devtools/reference/types.mdx b/content/docs/expo-devtools/reference/types.mdx new file mode 100644 index 0000000..a507991 --- /dev/null +++ b/content/docs/expo-devtools/reference/types.mdx @@ -0,0 +1,46 @@ +--- +title: Exported types +description: Everything the package root exports as a type. +--- + +```ts +import type { DevtoolsClientConfig, Palette } from '@axonpack/expo-devtools'; +``` + +## Configuration + +`DevtoolsClientConfig`, `DevtoolsNetworkConfig`, `DevtoolsConsoleConfig`, `DevtoolsPerformanceConfig`, +`DevtoolsStorageConfig`, `DevtoolsCrashConfig`, `DevtoolsOverlayProps`, `DevtoolsErrorBoundaryProps`. + +## Theming + +`BuiltInThemeId`, `ThemeId`, `ThemeConfig`, `Palette`. + +## Network + +`NetworkLogEntry`, `NetworkLogStatus`, `ResolvedNetworkConditions`, `ThrottlePresetId`, +`ThrottleProfile`, `UserAgentPresetId`. + +## Console + +`ConsoleLogEntry`, `ConsoleLogLevel`. + +## Performance + +`LongTaskEntry`, `MemorySample`, `StartupTiming`, `UserTimingEntry`, `MarkOptions`, `MeasureOptions`. + +## Storage + +`StorageAdapter`, `StorageAdapterConfig`, `StorageAdapterDefinition`, `StorageAdapterKind`, +`StorageKeyBlacklist`, `StorageAdapterState`, `StorageEntry`, `StorageReadResult`, `StorageValueType`, +`StoredValueKind`, `AsyncStorageLikeDriver`, `MmkvLikeDriver`, `SecureStoreLikeDriver`. + +## Crash + +`CrashRecord`, `CrashKind`, `CrashBreadcrumb`, `CrashBreadcrumbCategory`, `CrashDeviceInfo`, +`CrashNativeDetail`, `CrashPopupDetail`. + +## Values, not types + +Alongside the factories and components, the package root also exports `formatCrashReport` and +`formatCrashJson` for turning a `CrashRecord` into Markdown or JSON yourself. diff --git a/content/docs/expo-devtools/storage.mdx b/content/docs/expo-devtools/storage.mdx new file mode 100644 index 0000000..ddf202b --- /dev/null +++ b/content/docs/expo-devtools/storage.mdx @@ -0,0 +1,116 @@ +--- +title: Storage +description: Every key you have saved — but only for the stores you hand over, because this package depends on none of them. +--- + +The Storage tab lists every key you have saved, on the device, so you never have to write +`console.log(await AsyncStorage.getAllKeys())` again. + + + A key-value store is a separate install with its own native code, and this package deliberately + depends on none of them. Register the stores you already use and the tab reads them; register + nothing and it explains that instead of showing an empty list. + + +## Registering your stores + +Hand over the stores you already use, once, where you create the client: + +```ts title="devtools.ts" +import AsyncStorage from '@react-native-async-storage/async-storage'; +import * as SecureStore from 'expo-secure-store'; +import { createMMKV } from 'react-native-mmkv'; +import { + createDevtoolsClient, + asyncStorageAdapter, + mmkvAdapter, + secureStoreAdapter, + defineStorageAdapter, +} from '@axonpack/expo-devtools'; + +const mmkv = createMMKV(); + +export const devtools = createDevtoolsClient({ + storage: { + adapters: [ + asyncStorageAdapter({ driver: AsyncStorage }), + mmkvAdapter({ driver: mmkv }), + // SecureStore can't list its own keys, so you name the ones worth watching. + // A function works too, if your app keeps its own list — it's read on every refresh. + secureStoreAdapter({ driver: SecureStore, keys: ['session'] }), + // Anything else — your own cache, a wrapper, an in-memory store. + defineStorageAdapter({ + name: 'My cache', + kind: 'sync', + blacklist: /^secret\./, // keys you'd rather the panel never see + getAllKeys: () => cache.keys(), + getItem: (key) => cache.get(key) ?? null, + setItem: (key, text) => cache.set(key, text), + removeItem: (key) => cache.remove(key), + }), + ], + }, +}); +``` + +The full shape of each factory is in [Storage adapters](/docs/expo-devtools/reference/storage-adapters). + +## What the tab gives you + +The toolbar gets a dropdown to switch between your stores, and each key a row with its type, size and +value. + +- **Search** keys, values or both, with match case / whole word / regex, and matches highlighted in + place. +- **Filter** by value type — Object, Array, String, Number, Boolean, Binary, Empty, Missing — with + counts, or narrow to JSON only and hide empty values. +- **Sort** by key, size or type, ascending or descending, and **group by namespace**: the `auth:token`, + `cache/user/1`, `settings.theme` prefixes your keys already use, which no store knows about. +- **Tap a key** for its value in the same expandable JSON tree the Network tab uses, the raw characters + exactly as stored, an editor, and an Info tab. Copy the key, the value, or the pair as JSON. +- **Edit** a value and **delete** a key, one at a time, with a confirmation on delete. +- **Add** a key the store does not have yet: you pick the name, the type and the value. A key that is + already there is refused rather than quietly overwritten. +- **Export** the filtered keys of a store as JSON through the share sheet. The file carries a version, + so it can be read back later. +- **Import** one of those files: paste it in and you are told how many keys are new, how many would be + overwritten, how many already hold that value and how many are skipped — before anything is written. + +## What a store is allowed to do + +Whether a store can be edited or deleted from is derived from what you handed over: register it without +a `setItem` and the editor says so. Add and Import only appear for a store that can be written to. +`storage: { readOnly: true }`, or `readOnly` on one adapter, makes that explicit. + +Two more options on an adapter are worth knowing: + +- **`blacklist`** — a `RegExp` or a function. A key it matches is never listed, never read and never + written, so its value never reaches the panel at all. The tab says a blacklist is set, but not how + many keys it hid. +- **`supportedTypes`** — what the store can really hold. AsyncStorage and SecureStore hand back a string + whatever went in, so they declare `['string']` for you; MMKV takes all four. The Add-key sheet offers + only these, so you cannot write something the store would flatten. + +## Why there is no record button + +Storage is a pull, not a stream, so there is no stream to pause — the toolbar carries Refresh where the +other tabs carry a record button. There is no clear button either: that icon means "clear the log" in +three tabs, and it must never come to mean "wipe your storage". + +Nothing patches the store instance you hand over, so there is no mutation history and your app's +behaviour is unchanged. The tab only calls what it was handed. + +## Limits + +- **1,000 keys per store** by default, then it stops and reports how many it skipped. Raise it with + `storage.maxKeys`. +- **No SQLite.** A table needs schema, queries and paging, not a key list. +- **Binary values are shown, never edited.** There is no text form of the bytes to round-trip, so only + their length is reported. + +## Next step + + + + + diff --git a/content/docs/expo-devtools/themes.mdx b/content/docs/expo-devtools/themes.mdx new file mode 100644 index 0000000..7c23656 --- /dev/null +++ b/content/docs/expo-devtools/themes.mdx @@ -0,0 +1,58 @@ +--- +title: Themes +description: Seven built-in palettes, and your own as a patch over any of them. +--- + +The panel ships seven themes and takes your own. The palette button in the header — one row holding +the tabs, that button, then close — lists them all and switches the panel immediately. + +![Theme picker listing the built-in themes and a custom one](/expo-devtools/screenshots/theme-picker.png) + +## The seven built-ins + +| Id | Where it comes from | +| ----------------- | ---------------------------------------------------- | +| `light` | Chrome DevTools' light Network tab, the default | +| `dark` | Chrome DevTools' own dark theme | +| `dracula` | [Dracula](https://draculatheme.com) | +| `nord` | [Nord](https://www.nordtheme.com) | +| `monokai` | Monokai, as in TextMate and Sublime | +| `one-dark` | One Dark, from Atom | +| `solarized-light` | Solarized Light, the second of the two light options | + +Each is the project's published colours mapped onto this panel's tokens, not an approximation. + +## Your own + +Pick which one the panel opens with, and add your own: + +```ts +export const devtools = createDevtoolsClient({ + defaultTheme: 'midnight', + themes: { + midnight: { base: 'dark', colors: { accent: '#a78bfa' } }, + }, +}); +``` + +A theme names a `base` to inherit from (any of the seven) and overrides only the tokens it cares about, +so a one-colour change is a one-line entry rather than a copy of all of them that rots whenever a token +is added. + +- Reuse a built-in's id as your own name and you replace it. +- A `defaultTheme` naming something that was never registered is ignored, rather than leaving the panel + unstyled. + +The full token list is the `Palette` type, exported from the package root and documented in +[Themes reference](/docs/expo-devtools/reference/themes). + + + The choice lives in memory for the session, like the tab you last had open. Persisting it would mean + taking a storage dependency for a devtools colour scheme. + + +## Next step + + + + diff --git a/content/docs/index.mdx b/content/docs/index.mdx new file mode 100644 index 0000000..9c6bd91 --- /dev/null +++ b/content/docs/index.mdx @@ -0,0 +1,53 @@ +--- +title: Introduction +description: What Axonpack is, how these docs are organised, and where to start. +icon: House +--- + +Axonpack is a set of free, open-source foundation libraries for React Native and Expo apps. Each one +is small, focused and dependency-light — something you drop into an app you already have, rather than +a framework you adopt. + +Every package is published independently, versioned independently, and documented independently. +There is no `axonpack` meta-package to install, and installing one never brings in another. + +Everything is MIT licensed and developed in the open at +[github.com/axonpack/axonpack](https://github.com/axonpack/axonpack). + +## The packages + + + + + These docs cover what is published, and nothing else — a page describing something you cannot + install would only make you guess which half of this site is real. + + +## How these docs are organised + +**One folder per package.** The sidebar lists them below this page — picking one puts you in that +package's documentation and nothing else. A package's guides, its reference and its screenshots all +live under its own name, so nothing here is shared between two libraries by accident. + +Inside a package, the shape is always the same: + +| Section | What is in it | +| --------------- | ------------------------------------------------------------------------------- | +| **Get started** | Install it and wire it up. Read in order the first time. | +| **Guides** | One page per thing it does, written as prose with the limits stated. | +| **Reference** | Exhaustive: every control, field, option and exported type. Read by lookup. | + +## Start here + + + + + diff --git a/content/docs/meta.json b/content/docs/meta.json new file mode 100644 index 0000000..b945ea1 --- /dev/null +++ b/content/docs/meta.json @@ -0,0 +1,8 @@ +{ + "pages": [ + "index", + "---Packages---", + "expo-devtools", + "react-pretty-print" + ] +} diff --git a/content/docs/react-pretty-print/changelog.mdx b/content/docs/react-pretty-print/changelog.mdx new file mode 100644 index 0000000..153f237 --- /dev/null +++ b/content/docs/react-pretty-print/changelog.mdx @@ -0,0 +1,21 @@ +--- +title: Changelog +description: Every published release of @axonpack/react-pretty-print, newest first. +--- + +{/* Generated by scripts/sync-changelog.mjs from the package's CHANGELOG.md — do not edit by hand. */} + +Every published release, newest first. The current version is **0.1.0**. + +## 0.1.0 + + + +- **JSON and XML viewers** — expand and collapse any value or document, with a preview on every closed node +- **Syntax highlighting for 38 languages** — JavaScript and TypeScript through YAML, SQL, diffs and logs +- **One implementation for React and React Native** — pass in your own container, text and pressable components; a web set ships with the package +- **Search across all three views** — matching runs are painted, and only the branches holding a match open +- **Match case, whole word and regular expression** search modes +- **Node actions** — expand or collapse a subtree, or copy any value as formatted JSON +- **130 palettes**, or write your own from a flat set of colour roles +- **Minified source is re-indented** before it is shown, and that can be turned off diff --git a/content/docs/react-pretty-print/code-highlight.mdx b/content/docs/react-pretty-print/code-highlight.mdx new file mode 100644 index 0000000..d870f0e --- /dev/null +++ b/content/docs/react-pretty-print/code-highlight.mdx @@ -0,0 +1,65 @@ +--- +title: CodeHighlight +description: Highlighted source, one node per token, in 38 languages. +icon: Code +--- + +```tsx + +``` + +## Props + +| Prop | Type | Default | What it does | +| -------------------- | ------------------ | ------------------------ | ------------------------------------------------ | +| `primitives` | `Primitives` | required | See [Primitives](/docs/react-pretty-print/primitives) | +| `code` | `string` | required | The source | +| `language` | `Language` | required | One of the 38 below | +| `theme` | `PrettyPrintTheme` | `DARK_THEME` | See [Themes](/docs/react-pretty-print/themes) | +| `format` | `boolean` | `true` | Re-indent minified source first | +| `maxHighlightLength` | `number` | `50_000` | Above this, render unstyled rather than block | +| `matcher` | `Matcher` | none | See [Search](/docs/react-pretty-print/search) | + +Use `detectLanguage()` when you have a content type rather than a known language. + +## format + +It is a re-indenter, not a pretty-printer. It breaks lines on braces, brackets and statement +terminators and spaces separators, but it will not insert a space after a keyword or invent a +terminator the source left out. Turn it off for source you formatted yourself. + +## maxHighlightLength + +Above the cap the source renders as one unstyled block. Nothing is truncated, only the highlighting +is skipped. Pass `Infinity` to remove it: + +```tsx + +``` + +Tokenizing walks the string once per rule per position, so cost grows with length times the size of +the language's rule table. A megabyte of minified source is enough to block the thread. That is the +trade you are making when you raise it. + +## Languages + +38 of them, exported as `SUPPORTED_LANGUAGES`. + +| Group | Languages | `format` re-indents | +| ------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------- | +| Braces, `//`, `/* */` | `javascript` `typescript` `tsx` `java` `kotlin` `swift` `go` `rust` `c` `cpp` `csharp` `php` `dart` `scala` `protobuf` | yes | +| `#` comments | `python` `ruby` `bash` `dockerfile` `makefile` `graphql` | `graphql` only | +| Key and value | `json` `json5` `yaml` `toml` `ini` `properties` | `json` and `json5` | +| Angle brackets | `html` `xml` `svg` `markdown` | no | +| Stylesheets | `css` `scss` `less` | yes | +| Line-oriented | `sql` `diff` `log` | `sql` only | +| Unstyled | `plain` | no | + +Indentation-sensitive and line-oriented formats are left out of `format` on purpose. `python` and +`yaml` carry meaning in the whitespace they already have, markup and markdown have their own shape, +and a diff or a log is already one record per line. + +## Won't do + +- **Mount a scroller.** A long line needs one, and only you know whether the block is already inside + a `ScrollView` or a container with `overflow-x`. diff --git a/content/docs/react-pretty-print/context-menu.mdx b/content/docs/react-pretty-print/context-menu.mdx new file mode 100644 index 0000000..01785a5 --- /dev/null +++ b/content/docs/react-pretty-print/context-menu.mdx @@ -0,0 +1,43 @@ +--- +title: The context menu +description: The package decides which actions apply. You render the popover. +icon: MousePointerClick +--- + +The package computes which actions apply to a node and what each one does to the expansion state. +You render the menu itself. + +It cannot ship one. A floating menu has to escape its scroll container, which needs a `Modal` on +React Native and a portal or `position: fixed` on the DOM. React Native has no portal and the DOM has +no modal, so there is no shared subset to write against. + +```tsx +const [menu, setMenu] = useState<{ items: MenuItem[]; x: number; y: number } | null>(null); + + { + const { pageX, pageY } = (event as GestureResponderEvent).nativeEvent; + setMenu({ items, x: pageX, y: pageY }); + }} +/>; +``` + +`MenuItem` is `{ label: string; onSelect: () => void }`. Render the labels and call `onSelect` on +press. + +## Which items appear + +| Item | When | +| --------------------------------------------- | -------------------------------------------- | +| Copy value, Copy object | `onCopy` is set | +| Expand, Collapse | The node is a container with children | +| Expand recursively, Collapse recursively | The node is a container with children | + +`onRequestMenu` is what enables the gesture, which is long-press on React Native and right-click on +the web. Without it, no menu is requested. + +`event` is `unknown` because the package never reads it. Cast it at this one call site: +`nativeEvent.pageX` on React Native, `clientX` on a DOM mouse event. diff --git a/content/docs/react-pretty-print/index.mdx b/content/docs/react-pretty-print/index.mdx new file mode 100644 index 0000000..8a63591 --- /dev/null +++ b/content/docs/react-pretty-print/index.mdx @@ -0,0 +1,38 @@ +--- +title: Overview +description: Collapsible JSON and XML trees and a syntax highlighter, for React and React Native from one implementation. +icon: House +--- + +You pass in the container, text and pressable components. The package owns everything else: +expansion state, array chunking, collapsed-node previews, an XML parser, a 38-language tokenizer and +130 palettes. + +```sh +npm install @axonpack/react-pretty-print +``` + + + +| Renderer | What it gives you | +| ------------------------------------------------------------ | ------------------------------------------------------------- | +| **[JsonTree](/docs/react-pretty-print/json-tree)** | A value as a tree, with a preview on every closed node | +| **[XmlTree](/docs/react-pretty-print/xml-tree)** | A document as a tree, parsed in JS so it works off the DOM | +| **[CodeHighlight](/docs/react-pretty-print/code-highlight)** | Highlighted source, one node per token, in 38 languages | + +## What makes it different + +- **No dependencies, and no platform imports.** Nothing in it imports `react-native` or touches the + DOM. A web project installs nothing but React and aliases no bundler path, and a React Native + project hands over its own components with no adapter to write. +- **You supply the primitives.** That single decision is what lets one implementation serve both + platforms. See [Primitives](/docs/react-pretty-print/primitives). +- **No native module.** There is no `pod install` and no prebuild, so it runs in Expo Go. +- **The palettes are a separate entry point.** 130 of them is about 52KB, and a project that only + wants a renderer should not pull them in to discover it did not need them. + +## Where to go next + +[Installation](/docs/react-pretty-print/installation) covers the peer dependency and both platforms. +[Primitives](/docs/react-pretty-print/primitives) is the contract every renderer is built on, and is +worth reading before the renderers themselves. diff --git a/content/docs/react-pretty-print/installation.mdx b/content/docs/react-pretty-print/installation.mdx new file mode 100644 index 0000000..20e86cb --- /dev/null +++ b/content/docs/react-pretty-print/installation.mdx @@ -0,0 +1,53 @@ +--- +title: Installation +description: One install, no native module, and the components you already have. +icon: Download +--- + +```sh +npm install @axonpack/react-pretty-print +``` + +React 18 or newer is the only peer dependency. There is no native module, so there is no +`pod install` and no prebuild, and it runs in Expo Go. + +## On the web + +`domPrimitives` ships with the package, so there is nothing to write. + +```tsx +import { CodeHighlight, JsonTree, XmlTree, domPrimitives } from '@axonpack/react-pretty-print'; +import { LIGHT_THEME } from '@axonpack/react-pretty-print/themes'; + +const Example = () => ( + <> + + + + +); +``` + +## On React Native + +React Native's own components satisfy the contract as they are. + +```tsx +import { Pressable, Text, View } from 'react-native'; +import { JsonTree } from '@axonpack/react-pretty-print'; + +const Example = () => ; +``` + + + Every shipped palette asks for `monospace`, which is an Android family name. iOS finds no font by + it and falls back to the proportional system font without warning. See + [Themes](/docs/react-pretty-print/themes) for the one-line override. + + +## Entry points + +| Import | Holds | +| ----------------------------------------- | ---------------------------------------------------------- | +| `@axonpack/react-pretty-print` | The three renderers, `domPrimitives`, and every utility | +| `@axonpack/react-pretty-print/themes` | The 130 palettes and the `PrettyPrintTheme` type | diff --git a/content/docs/react-pretty-print/json-tree.mdx b/content/docs/react-pretty-print/json-tree.mdx new file mode 100644 index 0000000..27178e8 --- /dev/null +++ b/content/docs/react-pretty-print/json-tree.mdx @@ -0,0 +1,36 @@ +--- +title: JsonTree +description: A value as a tree that expands and collapses, with a preview on every closed node. +icon: Braces +--- + +```tsx + +``` + +## Props + +| Prop | Type | Default | What it does | +| ----------------- | ---------------------------------------- | ------------- | --------------------------------------------------------------------- | +| `primitives` | `Primitives` | required | See [Primitives](/docs/react-pretty-print/primitives) | +| `value` | `JsonValue` | required | The value itself, already parsed | +| `rootLabel` | `string` | none | A label for the root row. Without it the root is its own preview | +| `theme` | `PrettyPrintTheme` | `DARK_THEME` | See [Themes](/docs/react-pretty-print/themes) | +| `defaultExpanded` | `boolean` | `true` | Whether the root starts open | +| `onCopy` | `(text: string) => void` | none | Enables the copy actions | +| `onRequestMenu` | `(items: MenuItem[], event: unknown)` | none | Enables the long-press and right-click menu | +| `matcher` | `Matcher` | none | See [Search](/docs/react-pretty-print/search) | + +`value` takes a parsed value, not text. Parse a response body before handing it over. + +## Things worth knowing + +- **Only the root starts open.** Its children always start closed, whatever `defaultExpanded` says. + A hundred-entry payload opened all the way is a wall, not a tree. +- **`onCopy` is what offers the copy actions.** The clipboard is platform-specific, so the package + takes a function rather than reaching for one. Without it those actions are not offered at all. + Pass `Clipboard.setStringAsync` or `navigator.clipboard.writeText`. +- **A `matcher` drives expansion as well as painting.** Branches holding a match open, and everything + else collapses. +- **Long arrays are bucketed** in groups of `ARRAY_CHUNK_SIZE`, which is 10. +- **`{}` and `[]` get no toggle**, because `hasChildren` is false for them. diff --git a/content/docs/react-pretty-print/meta.json b/content/docs/react-pretty-print/meta.json new file mode 100644 index 0000000..91e71f3 --- /dev/null +++ b/content/docs/react-pretty-print/meta.json @@ -0,0 +1,25 @@ +{ + "title": "React Pretty Print", + "description": "Collapsible JSON and XML trees, plus a syntax highlighter", + "root": true, + "icon": "Braces", + "pages": [ + "---Get started---", + "index", + "installation", + "primitives", + "---Renderers---", + "json-tree", + "xml-tree", + "code-highlight", + "---Guides---", + "search", + "themes", + "context-menu", + "---Reference---", + "reference", + "---Releases---", + "changelog" + ], + "defaultOpen": true +} diff --git a/content/docs/react-pretty-print/primitives.mdx b/content/docs/react-pretty-print/primitives.mdx new file mode 100644 index 0000000..cb0e2ef --- /dev/null +++ b/content/docs/react-pretty-print/primitives.mdx @@ -0,0 +1,42 @@ +--- +title: Primitives +description: The contract that lets one implementation render on both platforms. +icon: Blocks +--- + +Every renderer takes its components from you. That is the whole reason there is no separate web +build and no React Native build. + +```ts +type Primitives = { + View: ComponentType<{ style?; children? }>; + Text: ComponentType<{ style?; children?; selectable? }>; + Pressable: ComponentType<{ style?; children?; onPress?; onLongPress? }>; +}; +``` + +| Platform | What to pass | +| ------------ | ------------------------------------------------------------------------- | +| React Native | `{ View, Text, Pressable }` from `react-native`, with no wrapper | +| The DOM | `domPrimitives`, exported from this package | + +Anything that accepts a style object and renders children will do, so a custom set is a few lines. + +## Why the types are loose + +`selectable` is there for React Native, where text is unselectable by default and a code block you +cannot copy from is useless. `domPrimitives` drops it rather than forwarding an unknown attribute to +a ``. + +The style types are deliberately wide. React Native's `StyleProp` and React's +`CSSProperties` are not assignable to each other in either direction, so a single concrete type +would reject one platform outright. + +The long-press event is `unknown` and passed through untouched for the same reason. Anything +narrower fails contravariance, which would force every React Native consumer to write a wrapper. +Cast it at your own call site, as [the context menu](/docs/react-pretty-print/context-menu) shows. + +## Won't do + +- **Ship a default for React Native.** That would mean importing `react-native`, which is the one + thing this design rules out. The DOM set can ship because it needs no import at all. diff --git a/content/docs/react-pretty-print/reference.mdx b/content/docs/react-pretty-print/reference.mdx new file mode 100644 index 0000000..842d379 --- /dev/null +++ b/content/docs/react-pretty-print/reference.mdx @@ -0,0 +1,47 @@ +--- +title: Reference +description: Every export, so a caller that wants its own rendering can skip the components. +icon: BookOpen +--- + +Everything the renderers use is exported. A caller that wants to render the parsed output itself can +take it and leave the components alone. + +## Utilities + +| Export | Signature | Notes | +| ------------------------ | -------------------------------------------------------------- | -------------------------------------------------------------- | +| `detectLanguage` | `(mimeType: string \| undefined, body: string) => Language` | Reads the content type, then sniffs the body | +| `tokenize` | `(code: string, language: Language) => Token[]` | Concatenating `text` returns the input unchanged | +| `formatCode` | `(code: string, language: Language) => string` | Returns the input for a language it does not format | +| `parseXml` | `(source: string) => { root } \| { error }` | Never throws | +| `isExpandable` | `(value: JsonValue) => boolean` | True for any object or array | +| `hasChildren` | `(value: JsonValue) => boolean` | False for empty ones, which is why they get no toggle | +| `isPlainObject` | `(value: JsonValue) => boolean` | `null` is not one | +| `buildPreview` | `(value) => string` | The summary a closed node shows | +| `chunkArrayRange` | `(length: number) => [number, number][]` | The bucket boundaries for a long array | +| `collectExpandablePaths` | `(path: string, value: JsonValue) => string[]` | Every path under a node, for expanding a subtree | +| `formatCopyValue` | `(value: JsonValue) => string` | `JSON.stringify` at two spaces | +| `buildMatcher` | `(query: SearchQuery) => Matcher` | See [Search](/docs/react-pretty-print/search) | +| `findMatches` | ranges over a string | With `clipMatches`, `splitByMatches` and `testMatch` | + +## Constants + +| Export | Value | Meaning | +| ----------------------- | -------- | -------------------------------------------------------------- | +| `SUPPORTED_LANGUAGES` | 38 | Sorted | +| `MAX_HIGHLIGHT_LENGTH` | `50_000` | Above this, `CodeHighlight` renders unhighlighted | +| `MAX_SEARCHABLE_LENGTH` | a cap | The point past which a string is not searched | +| `ARRAY_CHUNK_SIZE` | `10` | Arrays longer than this are bucketed | +| `DEFAULT_SEARCH_MODES` | object | `matchCase`, `wholeWord` and `regex`, all off | + +## Types + +From the root: `JsonValue`, `Language`, `Token`, `TokenType`, `MenuItem`, `Matcher`, `MatchRange`, +`SearchModes`, `SearchQuery`, `TextSegment`, `Primitives`, `JsonTreeProps`, `XmlTreeProps`, +`CodeHighlightProps`, `XmlNode`, `XmlElement`, `XmlText`, `XmlCData`, `XmlParseResult`. + +From `/themes`: `PrettyPrintTheme`. + +`TokenType` is one of `keyword`, `string`, `comment`, `number`, `function`, `tag`, `attr-name`, +`attr-value`, `property`, `selector`, `punctuation`, `plain`. diff --git a/content/docs/react-pretty-print/search.mdx b/content/docs/react-pretty-print/search.mdx new file mode 100644 index 0000000..5b78ae6 --- /dev/null +++ b/content/docs/react-pretty-print/search.mdx @@ -0,0 +1,38 @@ +--- +title: Search +description: One matcher, shared by all three renderers, as plain data rather than a callback. +icon: Search +--- + +```ts +type Matcher = { pattern: RegExp | null; invalid: boolean }; +``` + +That shape is the whole contract. If your app already compiles a matcher for its own filtering, pass +it straight in: TypeScript matches structurally, so there is nothing to import and nothing to +convert. + +```tsx +import { buildMatcher, DEFAULT_SEARCH_MODES } from '@axonpack/react-pretty-print'; + +const matcher = buildMatcher({ text: query, ...DEFAULT_SEARCH_MODES, matchCase: false }); + +; +``` + +`SearchModes` are `matchCase`, `wholeWord` and `regex`. + +## Two behaviours worth knowing + +- **An uncompilable pattern is no search, not no results.** A half-typed regular expression gives + `{ pattern: null, invalid: true }`, and the tree keeps its normal expansion rather than collapsing + to nothing. Read `invalid` if you want to mark the input. +- **A closed node still previews its contents.** The walk looks at the leaves underneath it, so a + branch with a match opens and a branch without one stays closed and shows its preview as usual. + +The band is the `matchHighlight` token, translucent so matched text keeps its syntax colour. In +`CodeHighlight` a match that spans a token boundary is still painted: matching runs once over the +whole string and the ranges are clipped per token. + +`findMatches`, `clipMatches`, `splitByMatches` and `testMatch` are exported for building your own +row filters against the same matcher. diff --git a/content/docs/react-pretty-print/themes.mdx b/content/docs/react-pretty-print/themes.mdx new file mode 100644 index 0000000..55f41bb --- /dev/null +++ b/content/docs/react-pretty-print/themes.mdx @@ -0,0 +1,68 @@ +--- +title: Themes +description: 130 palettes, each a flat set of colour roles rather than a stylesheet. +icon: Palette +--- + +```ts +import { AZURE_DARK_VIVID_THEME, DARK_THEME } from '@axonpack/react-pretty-print/themes'; +import type { PrettyPrintTheme } from '@axonpack/react-pretty-print/themes'; +``` + +A palette is never a stylesheet, so nothing has to be translated between platforms. They are a +separate entry point on purpose: 130 palettes is about 52KB, and a project that only wants a +renderer should not pull them into its module graph to find out it did not need them. + +## Tokens + +| Token | Paints | +| ------------------------- | --------------------------------------------------------------------------- | +| `background` | The surface the palette was designed against. No renderer draws it | +| `text` | Unclassified code text | +| `key` | JSON keys, XML element names | +| `string` | Quoted strings, XML attribute values | +| `number`, `boolean` | Literals. They share a colour in every shipped palette | +| `null` | An absent value | +| `punctuation` | Braces, separators, collapsed-node previews | +| `toggle` | The expand arrow | +| `keyword` | Language keywords | +| `comment` | Comments | +| `accent` | Function names, CSS properties, attribute names | +| `tag` | Markup tags, CSS selectors | +| `fontFamily`, `fontSize` | Type. Monospace at 12 in every shipped palette | + +`background` is stated so you know what the palette was built against, but you own your container, +so nothing draws it for you. Painting `2` and `true` differently is noise, which is why numbers and +booleans share a colour. + +## The set + +`DARK_THEME` and `LIGHT_THEME` are the neutral pair the renderers default to, and the only two with +no hue cast. The other 128 are named `___THEME`: 16 hues, `dark` or `light`, +and four characters, `muted`, `vivid`, `soft` and `crisp`. + +Every palette clears a WCAG contrast ratio against its own background: 4.5:1 for body text, 7:1 on +`crisp`, and never below 3:1 for any token. Writing your own is a plain object. + +## The monospace font on React Native + + + Every shipped palette says `fontFamily: 'monospace'`. That is right on the web and on Android and + wrong on iOS, which finds no font by that name and falls back to the proportional system font + with no warning. It stays invisible until something has to line up. + + +Nothing in the package can call `Platform.select`, because importing a platform is the one thing +this design rules out. Override the token instead: + +```tsx +import { Platform } from 'react-native'; +import { DARK_THEME } from '@axonpack/react-pretty-print/themes'; + +const MONOSPACE = Platform.select({ ios: 'Menlo', default: 'monospace' }); +const theme = { ...DARK_THEME, fontFamily: MONOSPACE }; +``` + +It has to be a single family name, not a CSS stack. React Native looks the string up verbatim, so +`"Menlo, monospace"` matches nothing on either platform. `Menlo` ships with every iOS, and nothing +on the DOM needs this. diff --git a/content/docs/react-pretty-print/xml-tree.mdx b/content/docs/react-pretty-print/xml-tree.mdx new file mode 100644 index 0000000..dedb0aa --- /dev/null +++ b/content/docs/react-pretty-print/xml-tree.mdx @@ -0,0 +1,32 @@ +--- +title: XmlTree +description: A document as a tree, parsed in JavaScript so it works with no DOM. +icon: FileCode +--- + +```tsx + +``` + +## Props + +| Prop | Type | Default | What it does | +| ------------ | ------------------ | ------------ | --------------------------------------------- | +| `primitives` | `Primitives` | required | See [Primitives](/docs/react-pretty-print/primitives) | +| `source` | `string` | required | The raw XML | +| `theme` | `PrettyPrintTheme` | `DARK_THEME` | See [Themes](/docs/react-pretty-print/themes) | +| `matcher` | `Matcher` | none | See [Search](/docs/react-pretty-print/search) | + +Elements expand and collapse. Text and character data are leaves. + +## Things worth knowing + +- **It parses in JavaScript**, because React Native has no `DOMParser`. +- **It never throws.** A document that will not parse renders a one-line reason instead, so keep the + raw text around to show beside it. `parseXml` returns either a root or an error for the same + reason. +- **A match on an element's own name or attributes does not open it.** That says nothing about + whether its contents are worth unfolding, so it is painted where it sits. An element opens only + for a match inside it. + +Searching covers element names, attribute names, attribute values, text and character data. diff --git a/next.config.mjs b/next.config.mjs new file mode 100644 index 0000000..e617e02 --- /dev/null +++ b/next.config.mjs @@ -0,0 +1,30 @@ +import { createMDX } from 'fumadocs-mdx/next'; + +const withMDX = createMDX(); + +// This directory is the whole project, and it is mounted into the axonpack monorepo as a submodule +// at `docs/`. Pinning Turbopack's root here stops it inferring one from a lockfile further up +// when it is checked out inside that monorepo. +const projectRoot = import.meta.dirname; + +// No basePath. This repo is named axonpack.github.io, so Pages serves it as the organisation root +// site and the app owns "/" directly. The docs live under a real /docs route segment instead of +// borrowing one from the prefix. +/** @type {import('next').NextConfig} */ +const config = { + output: 'export', + // Pages resolves `/foo/` to `/foo/index.html`. Without this, export writes `foo.html`, which works + // on Pages but breaks any host that doesn't guess the extension. + trailingSlash: true, + // There is no server to optimise images on. + images: { unoptimized: true }, + reactStrictMode: true, + turbopack: { root: projectRoot }, + outputFileTracingRoot: projectRoot, + // Next 16 serves /_next/* only to allowed hosts, so opening the dev server on the LAN IP to + // check the mobile layout 403s every chunk: the page renders but nothing hydrates. A bare '*' + // is rejected as a host pattern, so this names the subnet and survives DHCP moving the last octet. + allowedDevOrigins: ['*.*.*.*'], +}; + +export default withMDX(config); diff --git a/package.json b/package.json index 710d745..5302e51 100644 --- a/package.json +++ b/package.json @@ -1,31 +1,39 @@ { - "name": "axonpack-landing", - "private": true, - "type": "module", + "name": "@axonpack/docs", + "version": "0.0.0", + "private": false, + "description": "Documentation site for the @axonpack/* libraries", + "license": "MIT", "scripts": { - "packages": "node scripts/fetch-packages.mjs", - "dev": "node scripts/fetch-packages.mjs && astro dev", - "build": "node scripts/fetch-packages.mjs && astro build", - "preview": "astro preview", - "typecheck": "astro check" + "dev": "next dev", + "generate": "node scripts/fetch-packages.mjs && node scripts/sync-changelog.mjs", + "build": "bun run generate && next build", + "start": "serve out", + "lint": "oxlint src", + "format": "oxlint src --fix", + "check-types": "next typegen && tsc --noEmit", + "sync:changelog": "node scripts/sync-changelog.mjs" }, "dependencies": { - "@astrojs/react": "^4.2.0", - "@astrojs/sitemap": "^3.2.1", - "astro": "^5.2.0", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "lucide-react": "^0.460.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "tailwind-merge": "^2.5.5" + "@radix-ui/react-navigation-menu": "^1.2.22", + "fumadocs-core": "16.15.4", + "fumadocs-mdx": "15.4.0", + "fumadocs-ui": "npm:@fumadocs/base-ui@16.15.4", + "lucide-react": "^1.34.0", + "next": "16.3.3", + "react": "^19.2.8", + "react-dom": "^19.2.8" }, "devDependencies": { - "@astrojs/check": "^0.9.4", - "@tailwindcss/vite": "^4.0.0", - "@types/react": "^19.0.0", - "@types/react-dom": "^19.0.0", - "tailwindcss": "^4.0.0", - "typescript": "^5.7.0" + "@tailwindcss/postcss": "^4.3.3", + "@types/mdx": "^2.0.14", + "@types/node": "^26.3.0", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.5", + "oxlint": "^1.77.0", + "postcss": "^8.5.26", + "serve": "^14.2.6", + "tailwindcss": "^4.3.3", + "typescript": "^6.0.3" } } diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 0000000..297374d --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; + +export default config; diff --git a/src/content/blog/.gitkeep b/public/.nojekyll similarity index 100% rename from src/content/blog/.gitkeep rename to public/.nojekyll diff --git a/public/expo-devtools/screenshots/console-autocomplete.png b/public/expo-devtools/screenshots/console-autocomplete.png new file mode 100644 index 0000000..605a5cb Binary files /dev/null and b/public/expo-devtools/screenshots/console-autocomplete.png differ diff --git a/public/expo-devtools/screenshots/console-filters.png b/public/expo-devtools/screenshots/console-filters.png new file mode 100644 index 0000000..bd50c34 Binary files /dev/null and b/public/expo-devtools/screenshots/console-filters.png differ diff --git a/public/expo-devtools/screenshots/console-log.png b/public/expo-devtools/screenshots/console-log.png new file mode 100644 index 0000000..76a831f Binary files /dev/null and b/public/expo-devtools/screenshots/console-log.png differ diff --git a/public/expo-devtools/screenshots/console-repl.png b/public/expo-devtools/screenshots/console-repl.png new file mode 100644 index 0000000..5a5842b Binary files /dev/null and b/public/expo-devtools/screenshots/console-repl.png differ diff --git a/public/expo-devtools/screenshots/network-conditions.png b/public/expo-devtools/screenshots/network-conditions.png new file mode 100644 index 0000000..31f86d3 Binary files /dev/null and b/public/expo-devtools/screenshots/network-conditions.png differ diff --git a/public/expo-devtools/screenshots/network-filters.png b/public/expo-devtools/screenshots/network-filters.png new file mode 100644 index 0000000..771a8c6 Binary files /dev/null and b/public/expo-devtools/screenshots/network-filters.png differ diff --git a/public/expo-devtools/screenshots/network-log.png b/public/expo-devtools/screenshots/network-log.png new file mode 100644 index 0000000..acfdc50 Binary files /dev/null and b/public/expo-devtools/screenshots/network-log.png differ diff --git a/public/expo-devtools/screenshots/network-overview.png b/public/expo-devtools/screenshots/network-overview.png new file mode 100644 index 0000000..c190ecb Binary files /dev/null and b/public/expo-devtools/screenshots/network-overview.png differ diff --git a/public/expo-devtools/screenshots/perf-interactions.png b/public/expo-devtools/screenshots/perf-interactions.png new file mode 100644 index 0000000..af944a0 Binary files /dev/null and b/public/expo-devtools/screenshots/perf-interactions.png differ diff --git a/public/expo-devtools/screenshots/perf-limiter.png b/public/expo-devtools/screenshots/perf-limiter.png new file mode 100644 index 0000000..d9aa388 Binary files /dev/null and b/public/expo-devtools/screenshots/perf-limiter.png differ diff --git a/public/expo-devtools/screenshots/perf-long-tasks.png b/public/expo-devtools/screenshots/perf-long-tasks.png new file mode 100644 index 0000000..e8f2348 Binary files /dev/null and b/public/expo-devtools/screenshots/perf-long-tasks.png differ diff --git a/public/expo-devtools/screenshots/perf-statistics.png b/public/expo-devtools/screenshots/perf-statistics.png new file mode 100644 index 0000000..9961425 Binary files /dev/null and b/public/expo-devtools/screenshots/perf-statistics.png differ diff --git a/public/expo-devtools/screenshots/perf-user-timing.png b/public/expo-devtools/screenshots/perf-user-timing.png new file mode 100644 index 0000000..598a84d Binary files /dev/null and b/public/expo-devtools/screenshots/perf-user-timing.png differ diff --git a/public/expo-devtools/screenshots/request-headers.png b/public/expo-devtools/screenshots/request-headers.png new file mode 100644 index 0000000..31f31a0 Binary files /dev/null and b/public/expo-devtools/screenshots/request-headers.png differ diff --git a/public/expo-devtools/screenshots/request-payload.png b/public/expo-devtools/screenshots/request-payload.png new file mode 100644 index 0000000..a90c5be Binary files /dev/null and b/public/expo-devtools/screenshots/request-payload.png differ diff --git a/public/expo-devtools/screenshots/sandbox.png b/public/expo-devtools/screenshots/sandbox.png new file mode 100644 index 0000000..b2c0b73 Binary files /dev/null and b/public/expo-devtools/screenshots/sandbox.png differ diff --git a/public/expo-devtools/screenshots/theme-picker.png b/public/expo-devtools/screenshots/theme-picker.png new file mode 100644 index 0000000..cafb35c Binary files /dev/null and b/public/expo-devtools/screenshots/theme-picker.png differ diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000..19ea1ad Binary files /dev/null and b/public/logo.png differ diff --git a/scripts/fetch-packages.mjs b/scripts/fetch-packages.mjs index 69e1517..c1763d1 100644 --- a/scripts/fetch-packages.mjs +++ b/scripts/fetch-packages.mjs @@ -13,7 +13,7 @@ // // No dependencies. Node 20+ has fetch. -import { mkdir, writeFile } from "node:fs/promises"; +import { access, mkdir, writeFile } from "node:fs/promises"; const SCOPE = "@axonpack/"; @@ -92,28 +92,92 @@ if (names.size === 0) { throw new Error("no @axonpack packages found, refusing to build an empty catalogue"); } +const exists = async (relative) => { + try { + await access(new URL(relative, import.meta.url)); + return true; + } catch { + return false; + } +}; + +const DAY = 86_400_000; +/** + * 500, not 549. npm serves at most ~18 months of history and says nothing when it truncates: ask it + * for everything since 2022 and it answers for the last year and a half with a `start` you have to + * read to notice. 500 leaves room rather than sitting on the edge of a limit nobody documents. + */ +const CHUNK_DAYS = 500; +const iso = (date) => date.toISOString().slice(0, 10); +const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + +/** + * Every download since the package was published. + * + * The silent truncation above is the whole reason this is a loop. Measured against + * `@tanstack/react-query`, one request for all of time answers 2.00bn and the chunked walk answers + * 2.33bn, so the naive version drops 330m downloads and looks perfectly plausible doing it. + * + * The range endpoint rather than the point one: it returns a day at a time, so the total is a sum of + * values that can be inspected instead of a single number to take on trust. Requests go one at a + * time with a pause between, because this runs once per package on every build and npm's API is + * free. + * + * Credit: https://tanstack.com/blog/npm-stats-the-right-way + */ +async function countDownloads(name, publishedAt) { + const stamps = Object.entries(publishedAt) + .filter(([key]) => key !== "modified") + .map(([, value]) => new Date(value).getTime()) + .filter((time) => Number.isFinite(time)); + if (stamps.length === 0) return null; + + let from = new Date(Math.min(...stamps)); + const today = new Date(); + let total = 0; + let answered = false; + + while (from <= today) { + const to = new Date(Math.min(from.getTime() + CHUNK_DAYS * DAY, today.getTime())); + const url = `https://api.npmjs.org/downloads/range/${iso(from)}:${iso(to)}/${encode(name)}`; + + for (let attempt = 0; attempt < 3; attempt++) { + try { + const window = await json(url); + total += (window.downloads ?? []).reduce((sum, day) => sum + day.downloads, 0); + answered = true; + break; + } catch { + // A window before npm began counting is a legitimate miss, not a failure, so the last + // attempt gives up quietly. Anything earlier waits and tries again, since a rate limit and + // an empty range look identical from here. + if (attempt < 2) await sleep(500 * (attempt + 1)); + } + } + + from = new Date(to.getTime() + DAY); + if (from <= today) await sleep(200); + } + + return answered ? total : null; +} + const packages = []; for (const name of [...names].sort()) { const manifest = await json(`https://registry.npmjs.org/${encode(name)}/latest`); const slug = name.slice(SCOPE.length); - let weeklyDownloads = null; - try { - weeklyDownloads = ( - await json(`https://api.npmjs.org/downloads/point/last-week/${encode(name)}`) - ).downloads; - } catch { - // Downloads are decoration; a brand-new package has no data point yet. - } - // The registry's full document is the only place per-version publish times live; the changelog - // has notes but no dates, so the two are joined here. + // has notes but no dates, so the two are joined here. It also gives the first publish, which is + // where the download count has to start from. let publishedAt = {}; try { publishedAt = (await json(`https://registry.npmjs.org/${encode(name)}`)).time ?? {}; } catch { // Dates are decoration; releases still render without them. } + + const totalDownloads = await countDownloads(name, publishedAt); const releases = await fetchReleases(name, manifest.version, publishedAt); packages.push({ @@ -125,11 +189,16 @@ for (const name of [...names].sort()) { description: manifest.description ?? "", keywords: manifest.keywords ?? [], license: manifest.license ?? null, - weeklyDownloads, + totalDownloads, // Flat, derived from the package name. This is the same shape /docs/expo-devtools/ already uses, so a // new package needs no routing entry anywhere. docsHref: `/docs/${slug}/`, npmHref: `https://www.npmjs.com/package/${name}`, + // Publishing to npm puts a package in this catalogue, but writing its docs is a separate job. + // Until those pages exist every /docs// link 404s, so anything that links there has to + // check first rather than assume the two happen together. + hasDocs: await exists(`../content/docs/${slug}`), + hasChangelog: await exists(`../content/docs/${slug}/changelog.mdx`), }); console.log(` ${name} -> v${manifest.version} /docs/${slug}/ ${releases.length} releases`); } diff --git a/scripts/sync-changelog.mjs b/scripts/sync-changelog.mjs new file mode 100644 index 0000000..310f9a8 --- /dev/null +++ b/scripts/sync-changelog.mjs @@ -0,0 +1,195 @@ +/** + * Rebuilds each package's `content/docs//changelog.mdx` from its own CHANGELOG.md. + * + * The changelogs are written by Changesets in the monorepo, and this site is a different repository — + * so the pages here are generated and committed rather than fetched at build time. A build that has + * to reach GitHub to render a page fails whenever GitHub does, and a release only happens a few + * times a month, which is exactly the cadence a manual `bun run sync:changelog` suits. + * + * Release dates come from the npm registry: Changesets does not record them, and the git tags that + * would carry them are not reliably pushed. + * + * Usage: bun run sync:changelog + */ +import { readFile, writeFile } from 'node:fs/promises'; + +/** + * Every package with a changelog page. A package earns an entry here on the day it goes to npm, the + * same rule the rest of the site follows. The slug is the docs folder, which is the npm name without + * the scope, exactly as `packages.service` derives it. + */ +const PACKAGES = [ + { name: '@axonpack/expo-devtools', slug: 'expo-devtools' }, + { name: '@axonpack/react-pretty-print', slug: 'react-pretty-print' }, +]; + +const OUT_DATA = new URL('../src/lib/releases.generated.ts', import.meta.url); + +const get = async (url, as = 'text') => { + const res = await fetch(url); + if (!res.ok) throw new Error(`${res.status} ${res.statusText} — ${url}`); + return as === 'json' ? res.json() : res.text(); +}; + +/** + * This repository is mounted as a submodule at `docs/` inside the monorepo, so when you are working + * there the package's changelog is on disk one level up. Read that first: it means a version bumped + * locally shows on the site immediately, without waiting for the change to reach `main`. + */ +async function readChangelog(name) { + try { + const local = await readFile( + new URL(`../../packages/${name}/CHANGELOG.md`, import.meta.url), + 'utf8', + ); + console.log(`${name}: ../packages (local checkout)`); + return local; + } catch { + console.log(`${name}: raw.githubusercontent.com (main)`); + return get(`https://raw.githubusercontent.com/axonpack/axonpack/main/packages/${name}/CHANGELOG.md`); + } +} + +/** + * Only the release dates and the current version come from npm. Losing them costs a date on each + * heading, which is not worth failing a local run over — offline, the page still regenerates. + */ +async function readRegistry(name) { + try { + return await get(`https://registry.npmjs.org/${name}`, 'json'); + } catch (error) { + console.warn(`${name}: npm registry unavailable (${error.message}) — dates omitted`); + return null; + } +} + +/** + * Changesets emits `- : ` with any further bullets indented under it, and plain + * `- ` when the changeset carried no sha. A changeset whose body is itself a list comes out + * of the second shape as `- - `, which renders as an empty bullet wrapping the real one. + */ +const stripCommitPrefix = (line) => + line.replace(/^- [0-9a-f]{7,40}: (?:- )?/, '- ').replace(/^- - /, '- '); +const dedent = (line) => (line.startsWith(' - ') ? line.slice(2) : line); + +function parse(markdown) { + const releases = []; + let current = null; + for (const raw of markdown.split('\n')) { + const version = raw.match(/^## (\d+\.\d+\.\d+.*)$/); + if (version) { + current = { version: version[1].trim(), sections: [] }; + releases.push(current); + continue; + } + if (!current) continue; // the file's own H1 + const section = raw.match(/^### (Major|Minor|Patch) Changes$/); + if (section) { + current.sections.push({ bump: section[1], lines: [] }); + continue; + } + const open = current.sections.at(-1); + if (open) open.lines.push(dedent(stripCommitPrefix(raw))); + } + return releases; +} + +async function sync({ name, slug }) { + const [markdown, registry] = await Promise.all([readChangelog(name), readRegistry(name)]); + + // `null` means we could not reach npm, which is not the same as a version being absent from it — + // saying "not yet published" because the network was down would put a false claim on the page. + const known = registry !== null; + const dates = registry?.time ?? {}; + const fmtDate = (v) => + dates[v] + ? new Date(dates[v]).toLocaleDateString('en-GB', { + day: 'numeric', + month: 'long', + year: 'numeric', + }) + : null; + + const releases = parse(markdown); + + const body = releases + .map((r) => { + const date = fmtDate(r.version); + const bumps = r.sections.map((s) => s.bump.toLowerCase()); + // A version can be in CHANGELOG.md before it reaches npm: `changeset version` writes the + // entry, `changeset publish` does the publishing. Until then there is no date and no page to + // link to, so say that rather than linking somewhere that 404s. + const published = Boolean(dates[r.version]); + // A release can carry more than one kind of change. The badge shows the largest, which is the + // one that decides the version bump, so it cannot disagree with the number in the heading. + const rank = { major: 3, minor: 2, patch: 1 }; + const bump = bumps.sort((a, b) => rank[b] - rank[a])[0] ?? null; + // Three states, not two. `pending` is only truthful when npm answered and did not list the + // version; when npm was unreachable we know nothing, so neither attribute is written. + const attrs = [ + published ? `date="${date}"` : known ? 'pending' : '', + bump ? `bump="${bump}"` : '', + published ? `npm="https://www.npmjs.com/package/${name}/v/${r.version}"` : '', + ] + .filter(Boolean) + .join(' '); + + // The bump is already on the meta line; repeating it as a heading only adds noise when a + // release has one kind of change, which nearly all of them do. + const showHeadings = r.sections.length > 1; + const sections = r.sections + .map((s) => { + const text = s.lines.join('\n').trim(); + return showHeadings ? `### ${s.bump} changes\n\n${text}` : text; + }) + .join('\n\n'); + + return `## ${r.version}\n\n\n\n${sections}`; + }) + .join('\n\n'); + + const latest = registry?.['dist-tags']?.latest; + const page = `--- +title: Changelog +description: Every published release of ${name}, newest first. +--- + +{/* Generated by scripts/sync-changelog.mjs from the package's CHANGELOG.md — do not edit by hand. */} + +Every published release, newest first.${latest ? ` The current version is **${latest}**.` : ''} + +${body} +`; + + await writeFile(new URL(`../content/docs/${slug}/changelog.mdx`, import.meta.url), page); + console.log( + ` wrote ${releases.length} releases to content/docs/${slug}/changelog.mdx` + + (latest ? ` (latest ${latest})` : ''), + ); + + return { slug, latest, date: latest ? fmtDate(latest) : null }; +} + +const results = await Promise.all(PACKAGES.map(sync)); + +// The pages that advertise a current version read it from here, so a badge cannot drift from the +// changelog it links to — both come out of the same sync. A package npm could not answer for is left +// out rather than written with a hole in it, and the file is only rewritten if at least one answered: +// without that, a run made offline would wipe every version the site knows. +const found = results.filter((r) => r.latest); +if (found.length === 0) { + console.warn('no versions from npm — leaving releases.generated.ts untouched'); +} else { + if (found.length < results.length) { + const missing = results.filter((r) => !r.latest).map((r) => r.slug); + console.warn(`no version from npm for ${missing.join(', ')} — omitted from releases.generated.ts`); + } + await writeFile( + OUT_DATA, + `// Generated by scripts/sync-changelog.mjs — do not edit by hand. +export const releases: Record = { +${found.map((r) => ` '${r.slug}': { version: '${r.latest}', date: '${r.date}' },`).join('\n')} +}; +`, + ); +} diff --git a/serve.sh b/serve.sh deleted file mode 100755 index 77678c1..0000000 --- a/serve.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env sh -# Local preview. The page loads content.json as a JSON module, so it needs a real origin with -# correct MIME types — opening index.html over file:// will not work. -# Usage: ./serve.sh [port] -set -e -PORT="${1:-4000}" -cd "$(dirname "$0")" -echo "http://localhost:$PORT" -exec python3 -m http.server "$PORT" --bind 127.0.0.1 diff --git a/src/app/api/search.json/route.ts b/src/app/api/search.json/route.ts new file mode 100644 index 0000000..a59519b --- /dev/null +++ b/src/app/api/search.json/route.ts @@ -0,0 +1,33 @@ +import { source } from '@/lib/source'; +import { createFromSource } from 'fumadocs-core/search/server'; +import { packages } from '@/lib/services/packages.service'; + +const packageSlugs = new Set(packages.map((pkg) => pkg.slug)); + +export const revalidate = false; + +// `staticGET`, not `GET`: a static export has no server to run a search endpoint, so the whole index +// is written out at build time and queried in the browser. See `src/components/search.tsx`. +// +// The route is `search.json` rather than `search` so the export lands on disk with an extension. +// GitHub Pages types and compresses a file by its extension: extensionless, this ~1.2 MB index is +// served as application/octet-stream and uncompressed; as .json it is served gzipped, near 240 KB. +export const { staticGET: GET } = createFromSource(source, { + // https://docs.orama.com/docs/orama-js/supported-languages + language: 'english', + // The default builder, plus a tag. One index still covers every package — the tag is what lets a + // reader inside one package stop seeing the others, which is the part that gets worse with each + // library added, not the file size. + async buildIndex(page) { + return { + id: page.url, + title: page.data.title, + description: page.data.description, + url: page.url, + structuredData: await page.data.structuredData, + // The first slug segment names the package, when the page belongs to one. The introduction + // sits at the site root and belongs to none, so it stays untagged. + tag: packageSlugs.has(page.slugs[0]) ? page.slugs[0] : undefined, + }; + }, +}); diff --git a/src/app/blog/layout.tsx b/src/app/blog/layout.tsx new file mode 100644 index 0000000..a1e139a --- /dev/null +++ b/src/app/blog/layout.tsx @@ -0,0 +1,12 @@ +import { HomeLayout } from 'fumadocs-ui/layouts/home'; +import { baseOptions } from '@/lib/layout.shared'; + +// The blog pages were bare mains with no header at all. They take fumadocs' own navbar, built from +// the same `baseOptions` every layout gets, so the links match without sharing the landing header. +export default function Layout({ children }: LayoutProps<'/blog'>) { + return ( + + {children} + + ); +} diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx new file mode 100644 index 0000000..88c8ce1 --- /dev/null +++ b/src/app/blog/page.tsx @@ -0,0 +1,38 @@ +import type { Metadata } from 'next'; +import Link from 'next/link'; +import { ArrowRight } from 'lucide-react'; +import { getReleases } from '@/lib/services/blog-entries.service'; +import { documented } from '@/lib/services/packages.service'; + +export const metadata: Metadata = { + title: 'Blog', + description: 'Writing about the Axonpack libraries. Release notes live in the changelog.', +}; + +export default function BlogPage() { + const count = getReleases().length; + // Release notes live in each library's docs now, so the button goes to the only one that ships. + // With more than one there is no single page to send people to, so it falls back to the index. + const href = documented.length === 1 ? `${documented[0].docsHref}changelog/` : '/docs/'; + return ( +
+

Blog

+

+ Writing about the libraries and how they are built. +

+
+

+ Nothing written yet. There is a changelog though, and it is not short. +

+ + Read the changelog + {count} + + +
+
+ ); +} diff --git a/src/app/docs/[[...slug]]/page.tsx b/src/app/docs/[[...slug]]/page.tsx new file mode 100644 index 0000000..4470e24 --- /dev/null +++ b/src/app/docs/[[...slug]]/page.tsx @@ -0,0 +1,71 @@ +import { getPageImageUrl, getPageMarkdownUrl, source } from '@/lib/source'; +import { + DocsBody, + DocsDescription, + DocsPage, + DocsTitle, + MarkdownCopyButton, + ViewOptionsPopover, +} from 'fumadocs-ui/layouts/docs/page'; +import { notFound } from 'next/navigation'; +import { getMDXComponents } from '@/components/mdx'; +import type { Metadata } from 'next'; +import { createRelativeLink } from 'fumadocs-ui/mdx'; +import { findNeighbour } from 'fumadocs-core/page-tree'; +import { pageSourceUrl } from '@/lib/shared'; + +export default async function Page(props: PageProps<'/docs/[[...slug]]'>) { + const params = await props.params; + const page = source.getPage(params.slug); + if (!page) notFound(); + + const MDX = page.data.body; + const markdownUrl = getPageMarkdownUrl(page).url; + // The footer renders whatever it is handed; it does not work its own neighbours out of the tree. + const neighbours = findNeighbour(source.getPageTree(), page.url); + + return ( + + {page.data.title} + {page.data.description} +
+ + +
+ + + +
+ ); +} + +export async function generateStaticParams() { + return source.generateParams(); +} + +export async function generateMetadata(props: PageProps<'/docs/[[...slug]]'>): Promise { + const params = await props.params; + const page = source.getPage(params.slug); + if (!page) notFound(); + + return { + title: page.data.title, + description: page.data.description, + openGraph: { + images: getPageImageUrl(page).url, + }, + }; +} diff --git a/src/app/docs/layout.tsx b/src/app/docs/layout.tsx new file mode 100644 index 0000000..276378b --- /dev/null +++ b/src/app/docs/layout.tsx @@ -0,0 +1,12 @@ +import { source } from '@/lib/source'; +import { DocsLayout } from 'fumadocs-ui/layouts/docs'; +import { baseOptions } from '@/lib/layout.shared'; + +/** Fumadocs' own docs chrome. `SiteNav` is the landing page's header and stays on the landing page. */ +export default function Layout({ children }: LayoutProps<'/'>) { + return ( + + {children} + + ); +} diff --git a/src/app/global.css b/src/app/global.css new file mode 100644 index 0000000..4881e7e --- /dev/null +++ b/src/app/global.css @@ -0,0 +1,55 @@ +@import 'tailwindcss'; +@import 'fumadocs-ui/css/neutral.css'; +@import 'fumadocs-ui/css/preset.css'; + +/* The neutral preset ships a greyscale primary, so every `text-fd-primary` on the site rendered as + plain foreground and nothing carried the brand. #0c63e9 is the blue in the logo itself. Dark mode + takes a lighter step of the same hue, because the logo blue does not clear the contrast floor on + a near-black ground. */ +:root { + --color-fd-primary: #0c63e9; + --color-fd-primary-foreground: #ffffff; +} + +.dark { + --color-fd-primary: #5b9dff; + --color-fd-primary-foreground: hsl(214 46% 7%); +} + +html { + scrollbar-gutter: stable; +} + +html > body[data-scroll-locked] { + margin-right: 0px !important; + --removed-body-scroll-bar-size: 0px !important; +} + +/* The hero's entrance. Runs on load with no observer and no library, which is the whole reason it + is here rather than in JS. Anyone who has asked the OS for less motion gets none. */ +@keyframes rise { + from { + opacity: 0; + transform: translateY(12px); + } +} + +@media (prefers-reduced-motion: no-preference) { + .rise { + animation: rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) both; + } +} + +/* Sections arrive as they are scrolled to, driven by the scroll position itself rather than by an + observer, so there is no JS and nothing to run on a page nobody scrolls. Browsers without + scroll-driven animations skip the whole block and show the section outright, which is the correct + fallback rather than a degraded one. */ +@supports (animation-timeline: view()) { + @media (prefers-reduced-motion: no-preference) { + .reveal { + animation: rise linear both; + animation-timeline: view(); + animation-range: entry 5% cover 26%; + } + } +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx new file mode 100644 index 0000000..0344bca --- /dev/null +++ b/src/app/layout.tsx @@ -0,0 +1,31 @@ +import { Provider } from '@/components/provider'; +import { SiteFooter } from '@/components/site-footer'; +import './global.css'; +import type { Metadata } from 'next'; +import { Inter } from 'next/font/google'; +import { appLongName, appName, appTagline } from '@/lib/shared'; + +const inter = Inter({ subsets: ['latin'] }); + +export const metadata: Metadata = { + // Set NEXT_PUBLIC_SITE_URL once the site has a domain; without it Next resolves OG image URLs + // against localhost and warns on every build. + metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL ?? 'http://localhost:3000'), + // Long name when the site names itself, short as a suffix on a page that already has a title. + title: { default: appLongName, template: `%s — ${appName}` }, + description: appTagline, + icons: { icon: '/logo.png' }, +}; + +export default function Layout({ children }: LayoutProps<'/'>) { + return ( + + + + {children} + + + + + ); +} diff --git a/src/app/llms-full.txt/route.ts b/src/app/llms-full.txt/route.ts new file mode 100644 index 0000000..d494d2c --- /dev/null +++ b/src/app/llms-full.txt/route.ts @@ -0,0 +1,10 @@ +import { getLLMText, source } from '@/lib/source'; + +export const revalidate = false; + +export async function GET() { + const scan = source.getPages().map(getLLMText); + const scanned = await Promise.all(scan); + + return new Response(scanned.join('\n\n')); +} diff --git a/src/app/llms.mdx/docs/[[...slug]]/route.ts b/src/app/llms.mdx/docs/[[...slug]]/route.ts new file mode 100644 index 0000000..1618aa4 --- /dev/null +++ b/src/app/llms.mdx/docs/[[...slug]]/route.ts @@ -0,0 +1,22 @@ +import { getLLMText, getPageMarkdownUrl, source } from '@/lib/source'; +import { notFound } from 'next/navigation'; + +export const revalidate = false; + +export async function GET(_req: Request, { params }: RouteContext<'/llms.mdx/docs/[[...slug]]'>) { + const { slug } = await params; + const page = source.getPage(slug?.slice(0, -1)); + if (!page) notFound(); + + return new Response(await getLLMText(page), { + headers: { + 'Content-Type': 'text/markdown', + }, + }); +} + +export function generateStaticParams() { + return source.getPages().map((page) => ({ + slug: getPageMarkdownUrl(page).segments, + })); +} diff --git a/src/app/llms.txt/route.ts b/src/app/llms.txt/route.ts new file mode 100644 index 0000000..fc80cb6 --- /dev/null +++ b/src/app/llms.txt/route.ts @@ -0,0 +1,8 @@ +import { source } from '@/lib/source'; +import { llms } from 'fumadocs-core/source'; + +export const revalidate = false; + +export function GET() { + return new Response(llms(source).index()); +} diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx new file mode 100644 index 0000000..a98b7dd --- /dev/null +++ b/src/app/not-found.tsx @@ -0,0 +1,51 @@ +import Link from 'next/link'; +import type { Metadata } from 'next'; +import { appName, gitConfig } from '@/lib/shared'; + +// A static export serves this as 404.html, which is what GitHub Pages hands back for any unknown +// path. It is the only page a mistyped or stale URL ever reaches, anywhere on the site, so it +// points at the site as a whole rather than assuming the reader was looking for the docs. +export const metadata: Metadata = { + title: 'Page not found', + robots: { index: false, follow: true }, +}; + +const destinations = [ + { href: '/', label: 'Home', hint: `What ${appName} is` }, + { href: '/docs/', label: 'Docs', hint: 'Guides and reference for every library' }, + { href: '/docs/expo-devtools/changelog/', label: 'Changelog', hint: 'Every release, newest first' }, + { + href: `https://github.com/${gitConfig.user}/${gitConfig.repo}`, + label: 'GitHub', + hint: 'Source, issues and releases', + external: true, + }, +]; + +export default function NotFound() { + return ( +
+
+

404

+

This page does not exist

+

+ It may have moved, or the link that sent you here may be out of date. +

+
+
    + {destinations.map((item) => ( +
  • + + {item.label} + {item.hint} + +
  • + ))} +
+
+ ); +} diff --git a/src/app/og/docs/[...slug]/route.tsx b/src/app/og/docs/[...slug]/route.tsx new file mode 100644 index 0000000..d84cb30 --- /dev/null +++ b/src/app/og/docs/[...slug]/route.tsx @@ -0,0 +1,28 @@ +import { getPageImageUrl, source } from '@/lib/source'; +import { notFound } from 'next/navigation'; +import { ImageResponse } from 'next/og'; +import { generate as DefaultImage } from 'fumadocs-ui/og'; +import { appLongName } from '@/lib/shared'; + +export const revalidate = false; + +export async function GET(_req: Request, { params }: RouteContext<'/og/docs/[...slug]'>) { + const { slug } = await params; + const page = source.getPage(slug.slice(0, -1)); + if (!page) notFound(); + + return new ImageResponse( + , + { + width: 1200, + height: 630, + }, + ); +} + +export function generateStaticParams() { + return source.getPages().map((page) => ({ + lang: page.locale, + slug: getPageImageUrl(page).segments, + })); +} diff --git a/src/app/page.tsx b/src/app/page.tsx new file mode 100644 index 0000000..be84aa3 --- /dev/null +++ b/src/app/page.tsx @@ -0,0 +1,27 @@ +import type { Metadata } from 'next'; +import { HomeLayout } from 'fumadocs-ui/layouts/home'; +import { baseOptions } from '@/lib/layout.shared'; +import { SiteNav } from '@/components/site-nav'; +import { Hero } from '@/components/hero'; +import { LibraryGrid } from '@/components/library-grid'; +import { Principles } from '@/components/principles'; +import { content } from '@/lib/services/content.service'; + +export const metadata: Metadata = { + // The headline names the project itself now, so prefixing it with the long name said it twice. + title: { absolute: `${content.hero.title} ${content.hero.titleAccent}` }, + description: content.hero.lead, +}; + +/** Composes only. Each section is its own component, per the monorepo's CONVENTIONS.md. */ +export default function HomePage() { + return ( + +
+ + + +
+
+ ); +} diff --git a/src/components/copy-button.tsx b/src/components/copy-button.tsx new file mode 100644 index 0000000..e69dc6b --- /dev/null +++ b/src/components/copy-button.tsx @@ -0,0 +1,32 @@ +'use client'; + +import { useState } from 'react'; +import { Check, Copy, Terminal } from 'lucide-react'; + +/** The only interactive part of the hero, so the only thing that needs to be a client component. */ +export function InstallChip({ command }: { command: string }) { + const [copied, setCopied] = useState(false); + + return ( +
+ + {command} + +
+ ); +} diff --git a/src/components/devtools-panel.module.css b/src/components/devtools-panel.module.css new file mode 100644 index 0000000..c7bc891 --- /dev/null +++ b/src/components/devtools-panel.module.css @@ -0,0 +1,79 @@ +/* The panel's own motion, kept beside it rather than in the page's stylesheet, so rewriting the + hero cannot take the carousel with it. */ + +/* Six panes over 24s, dwelling on each then sliding to the next. The track carries a seventh pane + that repeats the first, so the wrap at 100% lands on an identical frame instead of snapping back. + Change the pane count and every stop below has to be recut. */ +@keyframes carousel { + 0%, + 13% { + transform: translateX(0); + } + 16.67%, + 29.67% { + transform: translateX(-100%); + } + 33.33%, + 46.33% { + transform: translateX(-200%); + } + 50%, + 63% { + transform: translateX(-300%); + } + 66.67%, + 79.67% { + transform: translateX(-400%); + } + 83.33%, + 96.33% { + transform: translateX(-500%); + } + 100% { + transform: translateX(-600%); + } +} + +/* Same clock as the track, one delay per tab. */ +@keyframes tabOn { + 0%, + 13% { + opacity: 1; + } + 16.67%, + 97% { + opacity: 0.35; + } + 100% { + opacity: 1; + } +} + +/* The one request still in flight, so the panel reads as live rather than as a picture of a list. */ +@keyframes flow { + from { + transform: translateX(-110%); + } + to { + transform: translateX(320%); + } +} + +/* Without motion the track never moves, so only the first tab may read as the active one. */ +.tab:not(:first-child) { + opacity: 0.35; +} + +@media (prefers-reduced-motion: no-preference) { + .track { + animation: carousel 24s cubic-bezier(0.65, 0, 0.35, 1) infinite; + } + + .tab { + animation: tabOn 24s steps(1, end) infinite; + } + + .flow { + animation: flow 1.6s ease-in-out infinite; + } +} diff --git a/src/components/devtools-panel.tsx b/src/components/devtools-panel.tsx new file mode 100644 index 0000000..833abf1 --- /dev/null +++ b/src/components/devtools-panel.tsx @@ -0,0 +1,261 @@ +import { Bug, Database, Gauge, Radio, Terminal, TriangleAlert } from 'lucide-react'; +import styles from './devtools-panel.module.css'; + +type Tone = 'ok' | 'warn' | 'bad' | 'muted'; +type Row = { lead: string; text: string; trail?: string; tone?: Tone }; +type Pane = { + tab: string; + icon: typeof Radio; + filters: string[]; + rows: Row[]; + views: string[]; + detail: { key: string; value: string; tone?: Tone }[]; +}; + +const TONES: Record = { + ok: 'text-emerald-500', + warn: 'text-amber-500', + bad: 'text-rose-500', + muted: 'text-fd-muted-foreground', +}; + +// Every tab the package ships. Five rows and four detail lines each, so the panes are the same +// height and the window never resizes mid-slide. The carousel keyframes are cut for six of these. +const panes: Pane[] = [ + { + tab: 'Network', + icon: Radio, + filters: ['All', 'Fetch', 'XHR', 'WS', 'SSE'], + rows: [ + { lead: 'GET', text: '/v1/session', trail: '200', tone: 'ok' }, + { lead: 'POST', text: '/v1/orders', trail: '201', tone: 'ok' }, + { lead: 'GET', text: '/v1/products?page=2', trail: '200', tone: 'ok' }, + { lead: 'GET', text: '/v1/me', trail: '401', tone: 'bad' }, + { lead: 'WS', text: '/live', trail: 'open', tone: 'ok' }, + ], + views: ['Headers', 'Response', 'Timing', 'Initiator'], + detail: [ + { key: 'status', value: '401 Unauthorized', tone: 'bad' }, + { key: 'body', value: '{ "error": "token_expired" }' }, + { key: 'waiting', value: '61 ms · downloading 27 ms' }, + { key: 'initiator', value: 'api-client.ts:88' }, + ], + }, + { + tab: 'Console', + icon: Terminal, + filters: ['All', 'Log', 'Warn', 'Error', 'REPL'], + rows: [ + { lead: 'log', text: 'session restored' }, + { lead: 'log', text: 'cart hydrated, 3 items' }, + { lead: 'warn', text: 'slow render, 142 ms', tone: 'warn' }, + { lead: 'error', text: 'TypeError: cart is undefined', tone: 'bad' }, + { lead: '>', text: 'store.getState().user' }, + ], + views: ['Message', 'Arguments', 'Source'], + detail: [ + { key: 'level', value: 'error', tone: 'bad' }, + { key: 'origin', value: 'CartScreen.tsx:42' }, + { key: 'argument', value: '{ userId: 8812, retry: false }' }, + { key: 'repeated', value: '3 times' }, + ], + }, + { + tab: 'Crash', + icon: TriangleAlert, + filters: ['All', 'Fatal', 'Rejection', 'Render', 'Native'], + rows: [ + { lead: 'fatal', text: "cannot read 'id' of null", tone: 'bad' }, + { lead: 'render', text: 'CartScreen boundary caught', tone: 'bad' }, + { lead: 'reject', text: 'refresh failed, 401', tone: 'warn' }, + { lead: 'native', text: 'NSInvalidArgumentException', tone: 'bad' }, + { lead: 'note', text: 'reported at next launch' }, + ], + views: ['Stack', 'Component stack', 'Breadcrumbs', 'Device'], + detail: [ + { key: 'message', value: "cannot read 'id' of null", tone: 'bad' }, + { key: 'stack', value: 'at CartScreen (CartScreen.tsx:42:11)' }, + { key: 'component', value: 'CartScreen › CartList › Row' }, + { key: 'device', value: 'iPhone 15 · iOS 18.2 · build 412' }, + ], + }, + { + tab: 'Storage', + icon: Database, + filters: ['All', 'Async', 'MMKV', 'Secure', 'Custom'], + rows: [ + { lead: 'async', text: 'auth.token', trail: 'string' }, + { lead: 'async', text: 'onboarding.seen', trail: 'boolean' }, + { lead: 'mmkv', text: 'cart.items', trail: 'json' }, + { lead: 'secure', text: 'refresh.key', trail: 'string' }, + { lead: 'custom', text: 'feature.flags', trail: 'json' }, + ], + views: ['Value', 'Type', 'Edit'], + detail: [ + { key: 'key', value: 'auth.token' }, + { key: 'store', value: 'AsyncStorage · async' }, + { key: 'type', value: 'string · 184 bytes' }, + { key: 'value', value: '"eyJhbGciOiJIUzI1NiIsInR5cCI6…"' }, + ], + }, + { + tab: 'Perf', + icon: Gauge, + filters: ['All', 'Frames', 'Memory', 'Long tasks', 'Startup'], + rows: [ + { lead: 'fps', text: 'JS thread', trail: '58', tone: 'ok' }, + { lead: 'fps', text: 'lowest this minute', trail: '31', tone: 'warn' }, + { lead: 'heap', text: 'Hermes allocated', trail: '42 MB' }, + { lead: 'task', text: 'long task, main bundle', trail: '180 ms', tone: 'warn' }, + { lead: 'task', text: 'long task, image decode', trail: '96 ms', tone: 'warn' }, + ], + views: ['Startup', 'Frames', 'Memory'], + detail: [ + { key: 'bundle', value: '412 ms' }, + { key: 'first render', value: '780 ms' }, + { key: 'runtime init', value: '96 ms' }, + { key: 'note', value: 'JS heap, not app memory' }, + ], + }, + { + tab: 'Debug', + icon: Bug, + filters: ['All', 'JS thread', 'Main thread'], + rows: [ + { lead: 'block', text: 'JS thread, 3 s' }, + { lead: 'block', text: 'main thread, 3 s' }, + { lead: 'crash', text: 'JS thread', tone: 'bad' }, + { lead: 'crash', text: 'main thread', tone: 'bad' }, + { lead: 'note', text: 'needs a development build' }, + ], + views: ['Effect', 'Why'], + detail: [ + { key: 'armed', value: 'tap again to crash', tone: 'bad' }, + { key: 'js block', value: 'shows as a long task, drops JS fps' }, + { key: 'main block', value: 'freezes the screen, JS stays fine' }, + { key: 'crash', value: 'read back off disk at next launch' }, + ], + }, +]; + +/** + * A drawing of the panel rather than a screenshot, so it themes with the page, weighs nothing and + * can walk its own tabs. The track repeats the first pane at the end: the loop's wrap then lands on + * an identical frame instead of snapping backwards through five panes. + * + * It owns its motion and knows nothing about where it is mounted, so it outlives the hero. + */ +export function DevtoolsPanel() { + return ( +
+
+ + + + + + Axonpack devtools + + + recording on device + +
+ +
+
+ {panes.map((pane, i) => ( + + + + {pane.tab} + + ))} +
+ +
+
+ {[...panes, panes[0]].map((pane, i) => ( +
+
+
+ {pane.filters.map((filter, f) => ( + + {filter} + + ))} +
+
    + {pane.rows.map((row) => ( +
  • + {row.lead} + {row.text} + {row.trail && ( + + {row.trail} + + )} +
  • + ))} +
  • + GET + /v1/feed + + + +
  • +
+
+ +
+
+ {pane.views.map((view, v) => ( + + {view} + + ))} +
+
+ {pane.detail.map((line) => ( +
+
{line.key}
+
{line.value}
+
+ ))} +
+
+
+ ))} +
+
+
+
+ ); +} diff --git a/src/components/hero.component.astro b/src/components/hero.component.astro deleted file mode 100644 index 1a7e227..0000000 --- a/src/components/hero.component.astro +++ /dev/null @@ -1,67 +0,0 @@ ---- -import Icon from "@/components/ui/icon.ui.astro"; -import InstallChip from "@/components/install-chip.component.astro"; -import { content } from "@/lib/services/content.service"; -import { packages } from "@/lib/services/packages.service"; - -const compact = (n: number) => (n >= 1000 ? `${(n / 1000).toFixed(1).replace(/\.0$/, "")}K` : `${n}`); -const weekly = packages.reduce((sum, p) => sum + (p.weeklyDownloads ?? 0), 0); -const releaseCount = packages.reduce((sum, p) => sum + p.releases.length, 0); - -// Derived from npm, so the strip can never contradict the catalogue below it. The old hand-written -// "1 package published" went stale the moment a second package shipped. -const stats = [ - { value: `${packages.length}`, label: packages.length === 1 ? "package published" : "packages published" }, - { value: compact(weekly), label: "downloads a week" }, - { value: `${releaseCount}`, label: releaseCount === 1 ? "release shipped" : "releases shipped" }, - { value: "MIT", label: "licensed, no tiers" }, -]; ---- - -
-
-

- - {content.hero.eyebrow} -

-

- {content.hero.title}{" "} - - {content.hero.titleAccent} - -

-

{content.hero.lead}

- - - - - -
    - { - stats.map((stat, i) => ( -
  • 0 && "sm:border-l", i % 2 === 1 && "border-l", i >= 2 && "border-t sm:border-t-0"]}> - {stat.value} - {stat.label} -
  • - )) - } -
-
-
diff --git a/src/components/hero.tsx b/src/components/hero.tsx new file mode 100644 index 0000000..4b3ec3f --- /dev/null +++ b/src/components/hero.tsx @@ -0,0 +1,63 @@ +import Link from 'next/link'; +import { ArrowRight, ArrowUpRight } from 'lucide-react'; +import { InstallChip } from '@/components/copy-button'; +import { DevtoolsPanel } from '@/components/devtools-panel'; +import { content } from '@/lib/services/content.service'; + +// The accent half of the headline is the tail, so the words carry on counting rather than restarting. +const words = [ + ...content.hero.title.split(' ').map((word) => ({ word, accent: false })), + ...content.hero.titleAccent.split(' ').map((word) => ({ word, accent: true })), +]; + +/** Type, two actions and the product. No scenery: the page's own background is the background. */ +export function Hero() { + return ( +
+
+

+ {words.map(({ word, accent }, i) => ( + + {word} + + ))} +

+ +

+ {content.hero.lead} +

+ +
+ + Read the docs + + + + {content.hero.actions[1].label} + + +
+ +
+ +
+
+ +
+ +
+
+ ); +} diff --git a/src/components/icon.tsx b/src/components/icon.tsx new file mode 100644 index 0000000..2ef7a8b --- /dev/null +++ b/src/components/icon.tsx @@ -0,0 +1,18 @@ +import { ICON_PATHS } from '@/lib/constants/icon-paths.const'; + +/** Inline SVG from the shared path data, so no icon font or runtime library is involved. */ +export function Icon({ name, className = 'size-5' }: { name: string; className?: string }) { + return ( + + ); +} diff --git a/src/components/install-chip.component.astro b/src/components/install-chip.component.astro deleted file mode 100644 index 107b541..0000000 --- a/src/components/install-chip.component.astro +++ /dev/null @@ -1,42 +0,0 @@ ---- -import Icon from "@/components/ui/icon.ui.astro"; - -interface Props { - command: string; -} -const { command } = Astro.props; ---- - -
- - {command} - -
- - diff --git a/src/components/latest-release.tsx b/src/components/latest-release.tsx new file mode 100644 index 0000000..c4dcca0 --- /dev/null +++ b/src/components/latest-release.tsx @@ -0,0 +1,25 @@ +import Link from 'next/link'; +import { releases } from '@/lib/releases.generated'; + +/** + * The version and the link to what changed, on a package's overview page. Both come from + * `releases.generated.ts`, which the changelog sync writes — so the version advertised here can + * never drift from the changelog it points at. + */ +export function LatestRelease({ slug }: { slug: string }) { + const release = releases[slug]; + if (!release) return null; + + return ( + + + v{release.version} + + Released {release.date} + What changed → + + ); +} diff --git a/src/components/library-grid.component.astro b/src/components/library-grid.component.astro deleted file mode 100644 index 099ef31..0000000 --- a/src/components/library-grid.component.astro +++ /dev/null @@ -1,62 +0,0 @@ ---- -import Icon from "@/components/ui/icon.ui.astro"; -import { packages } from "@/lib/services/packages.service"; - -import { LIBRARY_ACCENTS } from "@/lib/constants/library-accents.const"; ---- - -
-
-
-

- Libraries -

-

- Every package is released and documented on its own, and this list comes straight from - npm. If it is here, it is installable today. -

-
- - -
-
diff --git a/src/components/library-grid.tsx b/src/components/library-grid.tsx new file mode 100644 index 0000000..00e9e5f --- /dev/null +++ b/src/components/library-grid.tsx @@ -0,0 +1,44 @@ +import { Card, Cards } from 'fumadocs-ui/components/card'; +import { Download } from 'lucide-react'; +import { packages } from '@/lib/services/packages.service'; + +/** + * Fumadocs' own Card and Cards, the same pair `PackageCards` uses inside MDX, so a library looks + * the same on the landing page as it does in the docs. The version and download line is the only + * thing added on top, since those come from npm and the docs list has no notion of them. + */ +export function LibraryGrid() { + return ( +
+
+
+

+ Libraries +

+

+ Every library is released and documented on its own, and this list comes straight from + npm. If it is here, it is installable today. +

+
+ + {packages.map((pkg) => ( + +
+ + v{pkg.version} + + {pkg.totalDownloads !== null && ( + + + {pkg.totalDownloads.toLocaleString()} downloads + + )} + {pkg.license && {pkg.license}} +
+
+ ))} +
+
+
+ ); +} diff --git a/src/components/logo.tsx b/src/components/logo.tsx new file mode 100644 index 0000000..15573c8 --- /dev/null +++ b/src/components/logo.tsx @@ -0,0 +1,23 @@ +import Image from 'next/image'; +import logo from '../../public/logo.png'; +import logoDark from '../../public/assets/logo-dark.png'; + +/** + * The mark swaps with the theme instead of sitting on a tile. One of its two strokes is black, so + * the transparent light version loses half the letter on a dark background. Both images render and + * CSS picks one, so it is already correct on the first paint rather than after hydration. + */ +export function Logo({ size = 30 }: { size?: number }) { + return ( + <> + + + + ); +} diff --git a/src/components/mdx.tsx b/src/components/mdx.tsx new file mode 100644 index 0000000..c76d3fd --- /dev/null +++ b/src/components/mdx.tsx @@ -0,0 +1,32 @@ +import defaultMdxComponents from 'fumadocs-ui/mdx'; +import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; +import { Step, Steps } from 'fumadocs-ui/components/steps'; +import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; +import type { MDXComponents } from 'mdx/types'; +import { PackageCards } from './package-cards'; +import { LatestRelease } from './latest-release'; +import { ReleaseMeta } from './release-meta'; + +// Anything an .mdx page uses without importing it has to be listed here — fumadocs' own defaults +// cover Card/Cards/Callout and the code block, and no more. +export function getMDXComponents(components?: MDXComponents) { + return { + ...defaultMdxComponents, + Tabs, + Tab, + Steps, + Step, + Accordions, + Accordion, + PackageCards, + LatestRelease, + ReleaseMeta, + ...components, + } satisfies MDXComponents; +} + +export const useMDXComponents = getMDXComponents; + +declare global { + type MDXProvidedComponents = ReturnType; +} diff --git a/src/components/package-cards.tsx b/src/components/package-cards.tsx new file mode 100644 index 0000000..f4603eb --- /dev/null +++ b/src/components/package-cards.tsx @@ -0,0 +1,17 @@ +import { Card, Cards } from 'fumadocs-ui/components/card'; +import { documented } from '@/lib/services/packages.service'; + +/** + * Rendered from the generated catalogue rather than a hand-written list, so publishing a library + * puts it on every page that lists them with nothing to remember. `documented` rather than every + * package: one on npm without pages yet would be a card linking at a 404. + */ +export function PackageCards() { + return ( + + {documented.map((pkg) => ( + + ))} + + ); +} diff --git a/src/components/principles.component.astro b/src/components/principles.component.astro deleted file mode 100644 index 8f72b83..0000000 --- a/src/components/principles.component.astro +++ /dev/null @@ -1,26 +0,0 @@ ---- -import Icon from "@/components/ui/icon.ui.astro"; -import { content } from "@/lib/services/content.service"; ---- - -
-
-
-

- {content.principles.title} -

-

{content.principles.body}

-
-
- { - content.principles.items.map((item) => ( -
- -

{item.title}

-

{item.body}

-
- )) - } -
-
-
diff --git a/src/components/principles.tsx b/src/components/principles.tsx new file mode 100644 index 0000000..6d11a7c --- /dev/null +++ b/src/components/principles.tsx @@ -0,0 +1,28 @@ +import { Icon } from '@/components/icon'; +import { content } from '@/lib/services/content.service'; + +export function Principles() { + return ( +
+
+
+

+ {content.principles.title} +

+

{content.principles.body}

+
+
+ {content.principles.items.map((item) => ( +
+ +

+ {item.title} +

+

{item.body}

+
+ ))} +
+
+
+ ); +} diff --git a/src/components/provider.tsx b/src/components/provider.tsx new file mode 100644 index 0000000..54d40fc --- /dev/null +++ b/src/components/provider.tsx @@ -0,0 +1,8 @@ +'use client'; +import { RootProvider } from 'fumadocs-ui/provider/next'; +import type { ReactNode } from 'react'; +import SearchDialog from './search'; + +export function Provider({ children }: { children: ReactNode }) { + return {children}; +} diff --git a/src/components/release-meta.tsx b/src/components/release-meta.tsx new file mode 100644 index 0000000..7a86e6e --- /dev/null +++ b/src/components/release-meta.tsx @@ -0,0 +1,46 @@ +import { BUMP_STYLES } from '@/lib/constants/bump-styles.const'; + +/** + * The badge row under a version heading on a generated changelog page. + * + * The `## ` heading above it stays plain markdown on purpose: fumadocs builds the table of + * contents and the anchor from real headings, and a component heading would drop out of both. + * + * Written by scripts/sync-changelog.mjs, not by hand. + */ +export function ReleaseMeta({ + date, + bump, + npm, + pending, +}: { + date?: string; + bump?: string; + npm?: string; + /** npm answered and had no such version. Absent when npm could not be reached at all. */ + pending?: boolean; +}) { + return ( +
+ {bump && ( + + {bump} + + )} + {date && {date}} + {!date && pending && Not yet published} + {npm && ( + + on npm → + + )} +
+ ); +} diff --git a/src/components/search.tsx b/src/components/search.tsx new file mode 100644 index 0000000..b31c2d1 --- /dev/null +++ b/src/components/search.tsx @@ -0,0 +1,88 @@ +'use client'; +import { + SearchDialog, + SearchDialogClose, + SearchDialogContent, + SearchDialogFooter, + SearchDialogHeader, + SearchDialogIcon, + SearchDialogInput, + SearchDialogList, + SearchDialogOverlay, + TagsList, + TagsListItem, + type SharedProps, +} from 'fumadocs-ui/components/dialog/search'; +import { useDocsSearch } from 'fumadocs-core/search/client'; +import { staticClient } from 'fumadocs-core/search/client/orama-static'; +import { usePathname } from 'next/navigation'; +import { useMemo, useState } from 'react'; +import { packages } from '@/lib/services/packages.service'; + +// `staticClient` only applies its own base path to the *default* endpoint; an explicit `from` is used +// verbatim. So this one has to carry the prefix itself. +const searchIndexUrl = '/api/search.json'; + +/** + * Search is filtered by the folder a page sits in, which is the same string as the package's slug. + * The introduction sits above them all and belongs to no package, so it carries no tag and shows up + * only in an unfiltered search. + */ +const searchTags = packages.map((pkg) => ({ value: pkg.slug, label: pkg.title })); +const tagValues = new Set(searchTags.map((tag) => tag.value)); + +/** + * `/docs/expo-devtools/network` -> `expo-devtools`. The docs sit under their own segment now, so + * the slug is the second one, not the first. Reading the first returned "docs" and matched no tag. + */ +function packageFromPathname(pathname: string): string | undefined { + const [, first, second] = pathname.split('/'); + const slug = first === 'docs' ? second : first; + if (!slug) return undefined; + return tagValues.has(slug) ? slug : undefined; +} + +export default function StaticSearchDialog(props: SharedProps) { + const pathname = usePathname(); + const currentPackage = packageFromPathname(pathname); + + // Opening search inside a package searches that package. Clearing the tag searches everything, + // which is the right default only when you are not already reading one. + // + // Adjusted during render rather than in an effect: an effect would render once with the previous + // package's tag, then again with this one, and the first of those two renders would run a query. + const [tag, setTag] = useState(currentPackage); + const [tagFor, setTagFor] = useState(currentPackage); + if (tagFor !== currentPackage) { + setTagFor(currentPackage); + setTag(currentPackage); + } + + // `useDocsSearch` keys its effect on `client.deps`, which is a fresh array on every + // `staticClient()` call — an unmemoized client re-runs the query on every render. + const client = useMemo(() => staticClient({ from: searchIndexUrl, tag }), [tag]); + const { search, setSearch, query } = useDocsSearch({ client }); + + return ( + + + + + + + + + + + + {searchTags.map((item) => ( + + {item.label} + + ))} + + + + + ); +} diff --git a/src/components/site-footer.component.astro b/src/components/site-footer.component.astro deleted file mode 100644 index f82bc45..0000000 --- a/src/components/site-footer.component.astro +++ /dev/null @@ -1,59 +0,0 @@ ---- -import { content } from "@/lib/services/content.service"; -import { packages } from "@/lib/services/packages.service"; - -const isExternal = (href: string) => /^https?:/.test(href); ---- - -
-
-
-
-
- - - - - {content.brand.name} -
-

{content.footer.blurb}

-
- - {/* Generated from npm, so a new package appears here the same build it appears everywhere else. */} -
-

Libraries

- { - packages.map((pkg) => ( - - {pkg.slug} - - )) - } -
- - { - content.footer.columns.map((column) => ( -
-

- {column.title} -

- {column.links.map((link) => ( - - {link.label} - - ))} -
- )) - } -
-
{content.footer.legal}
-
-
diff --git a/src/components/site-footer.tsx b/src/components/site-footer.tsx new file mode 100644 index 0000000..1d9d33a --- /dev/null +++ b/src/components/site-footer.tsx @@ -0,0 +1,57 @@ +import Link from 'next/link'; +import { Logo } from './logo'; +import { content } from '@/lib/services/content.service'; +import { packages } from '@/lib/services/packages.service'; +import { appName } from '@/lib/shared'; + +const isExternal = (href: string) => /^https?:/.test(href); +const COL = 'mb-3 text-xs font-semibold tracking-wider text-fd-muted-foreground uppercase'; +const LINK = 'block py-1 text-sm text-fd-muted-foreground transition-colors hover:text-fd-primary'; + +/** Ported from the Astro site. No interactivity, so it stays a server component. */ +export function SiteFooter() { + return ( +
+
+
+
+
+ + {appName} +
+

{content.footer.blurb}

+
+ + {/* From npm, so a new library appears here the same build it appears everywhere else. */} +
+

Libraries

+ {packages.map((pkg) => ( + + {pkg.title} + + ))} +
+ + {content.footer.columns.map((column) => ( +
+

{column.title}

+ {column.links.map((link) => ( + + {link.label} + + ))} +
+ ))} +
+
+ {content.footer.legal} +
+
+
+ ); +} diff --git a/src/components/site-header.component.astro b/src/components/site-header.component.astro deleted file mode 100644 index d1ed056..0000000 --- a/src/components/site-header.component.astro +++ /dev/null @@ -1,255 +0,0 @@ ---- -import Icon from "@/components/ui/icon.ui.astro"; -import ThemeToggle from "@/components/theme-toggle.component.astro"; -import { content, navLink } from "@/lib/services/content.service"; -import { packages } from "@/lib/services/packages.service"; -import { getPosts, getReleases } from "@/lib/services/blog-entries.service"; -import { formatDate } from "@/lib/utils/format-date.util"; - -const docs = navLink("Docs"); -// The panel reads the same services the two pages do, so it cannot disagree with them about -// what the newest release is or whether any posts exist. -const posts = (await getPosts()).slice(0, 4); -const releases = getReleases(); -const latestReleases = releases.slice(0, 4); -const community = navLink("Community"); - -const linkClass = - "flex items-center gap-1.5 rounded-lg px-3 py-2 text-sm text-muted-foreground hover:bg-secondary hover:text-foreground max-lg:justify-between max-lg:text-base"; -const panelClass = - "absolute left-1/2 top-[calc(100%+10px)] flex -translate-x-1/2 gap-7 rounded-lg border bg-popover p-4 shadow-2xl before:absolute before:inset-x-0 before:-top-2.5 before:h-2.5 max-lg:static max-lg:translate-x-0 max-lg:flex-col max-lg:gap-3 max-lg:border-0 max-lg:p-0 max-lg:pl-2 max-lg:shadow-none"; ---- - - - - diff --git a/src/components/site-nav.tsx b/src/components/site-nav.tsx new file mode 100644 index 0000000..4fe6fce --- /dev/null +++ b/src/components/site-nav.tsx @@ -0,0 +1,245 @@ +'use client'; + +import { useState } from 'react'; +import Link from 'next/link'; +import * as NavigationMenu from '@radix-ui/react-navigation-menu'; +import { ChevronDown, Menu, X } from 'lucide-react'; +import { FullSearchTrigger } from 'fumadocs-ui/layouts/shared/slots/search-trigger'; +import { ThemeSwitch } from 'fumadocs-ui/layouts/shared/slots/theme-switch'; +import { Logo } from './logo'; +import { Icon } from '@/components/icon'; +import { appName, gitConfig } from '@/lib/shared'; +import { documented, packages } from '@/lib/services/packages.service'; +import { getReleases } from '@/lib/services/blog-entries.service'; +import { navLink } from '@/lib/services/content.service'; + +/** + * Radix's NavigationMenu, because it opens on pointer enter with a configurable delay and handles + * keyboard, focus and dismissal itself. Fumadocs' own navbar menus are click-to-open: their only + * hover handler is on the mobile collapsible trigger, so `links: type: 'menu'` could never do this. + * + * Search and the theme switch are still fumadocs', so they stay consistent with the docs pages and + * keep talking to the same providers. + * + * Rendered through fumadocs' `slots.header`, which supplies header props and nothing else, so the + * menu data is read here rather than passed in: a closure made in a server component cannot cross + * the client boundary. + */ + +const TRIGGER = + 'group flex items-center gap-1.5 rounded-lg px-3 py-2 text-sm text-fd-muted-foreground transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground data-[state=open]:bg-fd-accent data-[state=open]:text-fd-accent-foreground'; +const PANEL = + 'absolute left-0 top-[calc(100%+8px)] flex gap-6 rounded-lg border bg-fd-popover p-4 shadow-2xl'; +const HEADING = 'mb-1 ml-2 text-[0.6875rem] font-semibold tracking-wider text-fd-muted-foreground uppercase'; +const ENTRY = 'block rounded-lg p-2 transition-colors hover:bg-fd-accent'; + +type Entry = { label: string; href: string; note?: string; badge?: string; external?: boolean }; +type Column = { title: string; entries: Entry[]; footer?: { label: string; href: string } }; + +export function SiteNav(props: React.ComponentProps<'header'>) { + const [drawer, setDrawer] = useState(false); + const releases = getReleases(); + const community = navLink('Community'); + + const menus: { id: string; label: string; columns: Column[] }[] = [ + { + id: 'libraries', + label: 'Libraries', + columns: [ + { + title: 'Published', + entries: packages.map((pkg) => ({ + label: pkg.title, + href: pkg.docsHref, + note: pkg.description, + badge: `v${pkg.version}`, + })), + }, + ], + }, + { + id: 'blog', + label: 'Blog', + columns: [ + { + title: 'Writing', + entries: [], + footer: { label: 'Blog', href: '/blog/' }, + }, + { + title: 'Changelog', + // One entry per library, pointing at the changelog in its own docs. That page is + // newest-first, so the latest release is already at the top and the link needs no anchor + // to chase — which also means nothing here has to mirror fumadocs' heading-slug rule. + // Only documented packages: npm can list one whose pages do not exist yet. + entries: documented.map((pkg) => ({ + label: pkg.title, + href: `${pkg.docsHref}changelog/`, + badge: `v${pkg.version}`, + note: `${releases.filter((r) => r.library === pkg.slug).length} releases`, + })), + }, + ], + }, + ...(community?.menu + ? [ + { + id: 'community', + label: 'Community', + columns: community.menu.map((group) => ({ + title: group.title, + entries: group.items.map((item) => ({ + label: item.label, + href: item.href, + external: /^https?:/.test(item.href), + })), + })), + }, + ] + : []), + ]; + + const entryLink = (entry: Entry) => ( + + + + {entry.label} + {entry.badge && ( + + {entry.badge} + + )} + + {entry.note && ( + {entry.note} + )} + + + ); + + return ( + // The grid-area matters only on docs pages: DocsLayout lays its children out in a named grid + // ("sidebar sidebar header toc toc"), and a header that claims no area gets auto-placed. That + // dropped it into the first column, 229px wide of a 390px phone, with its own controls + // overflowing. Naming the area is what fumadocs' own header does. Spanning every column + // instead is wrong: the sidebar occupies columns 1 and 2 on every row, so the two overlap. +
+
+ + + {appName} + + + + + + + + Docs + + + + + {menus.map((menu) => ( + + + {menu.label} + + + + {menu.columns.map((column) => ( +
+

{column.title}

+ {column.entries.length === 0 && ( +

Nothing published yet.

+ )} + {column.entries.map(entryLink)} + {column.footer && ( + + + {column.footer.label} + + + )} +
+ ))} +
+
+ ))} +
+
+ +
+ {/* Below lg both of these live in the drawer instead: at phone width the header has no + room for them beside the logo, and a search box worth typing into needs real width. */} + + + + + + +
+
+ + {/* Mobile: one flat list. Nested hover menus are meaningless on a touch screen. */} + {drawer && ( +
+
+ {/* The shortcut hint is dead weight on a device with no ⌘, so the box takes that width. */} + + +
+ + Docs + + {menus.map((menu) => ( +
+

{menu.label}

+ {menu.columns.map((column) => ( +
+ {/* The desktop panel puts columns side by side under their own titles. Flattened + into one list those titles are what stops "expo-devtools" under Blog reading + as a post rather than that library's changelog. */} + {menu.columns.length > 1 && column.entries.length > 0 && ( +

{column.title}

+ )} + {column.entries.map((entry) => ( + + {entry.label} + + ))} + {column.footer && ( + + {column.footer.label} + + )} +
+ ))} +
+ ))} +
+ )} +
+ ); +} diff --git a/src/components/theme-toggle.component.astro b/src/components/theme-toggle.component.astro deleted file mode 100644 index 55e44f7..0000000 --- a/src/components/theme-toggle.component.astro +++ /dev/null @@ -1,51 +0,0 @@ ---- -import Icon from "@/components/ui/icon.ui.astro"; ---- - - - - diff --git a/src/components/ui/icon.ui.astro b/src/components/ui/icon.ui.astro deleted file mode 100644 index 11d63c9..0000000 --- a/src/components/ui/icon.ui.astro +++ /dev/null @@ -1,22 +0,0 @@ ---- -import { ICON_PATHS } from "@/lib/constants/icon-paths.const"; - -interface Props { - name: string; - class?: string; -} -const { name, class: className = "size-5" } = Astro.props; -const path = ICON_PATHS[name] ?? ICON_PATHS.box; ---- - - diff --git a/src/content.config.ts b/src/content.config.ts deleted file mode 100644 index c74ecbd..0000000 --- a/src/content.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { glob } from "astro/loaders"; -import { defineCollection, z } from "astro:content"; - -// Hand-written posts. Release notes are not here. They come from each library's CHANGELOG.md at -// build time, so nobody has to copy a changeset into a blog post by hand. -const blog = defineCollection({ - loader: glob({ pattern: "**/*.md", base: "./src/content/blog" }), - schema: z.object({ - title: z.string(), - description: z.string(), - date: z.coerce.date(), - author: z.string().default("Axonpack"), - draft: z.boolean().default(false), - }), -}); - -export const collections = { blog }; diff --git a/src/content.json b/src/content.json index 7bde128..25f1c8e 100644 --- a/src/content.json +++ b/src/content.json @@ -63,10 +63,9 @@ } }, "hero": { - "eyebrow": "MIT licensed · React and React Native", - "title": "The open source tools and libraries for", - "titleAccent": "React and React Native", - "lead": "Small, focused, dependency-light packages. Drop one in and carry on. There is no framework here to adopt.", + "title": "Axonpack ends the guesswork", + "titleAccent": "when things break.", + "lead": "Answers you and your agent can both read. Every request, error, log and stored value, captured on the device and copied out as structured JSON.", "actions": [ { "label": "Read the docs", diff --git a/src/layouts/base.layout.astro b/src/layouts/base.layout.astro deleted file mode 100644 index 2687778..0000000 --- a/src/layouts/base.layout.astro +++ /dev/null @@ -1,65 +0,0 @@ ---- -import "@/styles/global.css"; -import { packages } from "@/lib/services/packages.service"; - -interface Props { - title: string; - description: string; -} -const { title, description } = Astro.props; -const canonical = new URL(Astro.url.pathname, Astro.site).href; -const ogImage = new URL("/assets/logo.png", Astro.site).href; - -// Structured data for a library catalogue. Generated from the same npm-derived list the page -// renders, so it can never describe a package the page does not show. -const jsonLd = { - "@context": "https://schema.org", - "@type": "ItemList", - name: "Axonpack open-source libraries", - itemListElement: packages.map((pkg, index) => ({ - "@type": "ListItem", - position: index + 1, - item: { - "@type": "SoftwareSourceCode", - name: pkg.name, - description: pkg.description, - softwareVersion: pkg.version, - license: pkg.license ?? undefined, - codeRepository: "https://github.com/axonpack/axonpack", - programmingLanguage: "TypeScript", - url: new URL(pkg.docsHref, Astro.site).href, - }, - })), -}; ---- - - - - - - - {title} - - - - - - - - - - - - -