diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..6240da8b --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,21 @@ +# build output +dist/ +# generated types +.astro/ + +# dependencies +node_modules/ + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store diff --git a/docs/.vscode/extensions.json b/docs/.vscode/extensions.json new file mode 100644 index 00000000..22a15055 --- /dev/null +++ b/docs/.vscode/extensions.json @@ -0,0 +1,4 @@ +{ + "recommendations": ["astro-build.astro-vscode"], + "unwantedRecommendations": [] +} diff --git a/docs/.vscode/launch.json b/docs/.vscode/launch.json new file mode 100644 index 00000000..d6422097 --- /dev/null +++ b/docs/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "command": "./node_modules/.bin/astro dev", + "name": "Development server", + "request": "launch", + "type": "node-terminal" + } + ] +} diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..1b7f5c3d --- /dev/null +++ b/docs/README.md @@ -0,0 +1,49 @@ +# Starlight Starter Kit: Basics + +[![Built with Starlight](https://astro.badg.es/v2/built-with-starlight/tiny.svg)](https://starlight.astro.build) + +``` +npm create astro@latest -- --template starlight +``` + +> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun! + +## 🚀 Project Structure + +Inside of your Astro + Starlight project, you'll see the following folders and files: + +``` +. +├── public/ +├── src/ +│ ├── assets/ +│ ├── content/ +│ │ └── docs/ +│ └── content.config.ts +├── astro.config.mjs +├── package.json +└── tsconfig.json +``` + +Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its file name. + +Images can be added to `src/assets/` and embedded in Markdown with a relative link. + +Static assets, like favicons, can be placed in the `public/` directory. + +## 🧞 Commands + +All commands are run from the root of the project, from a terminal: + +| Command | Action | +| :------------------------ | :----------------------------------------------- | +| `npm install` | Installs dependencies | +| `npm run dev` | Starts local dev server at `localhost:4321` | +| `npm run build` | Build your production site to `./dist/` | +| `npm run preview` | Preview your build locally, before deploying | +| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` | +| `npm run astro -- --help` | Get help using the Astro CLI | + +## 👀 Want to learn more? + +Check out [Starlight’s docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat). diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs new file mode 100644 index 00000000..db6e856b --- /dev/null +++ b/docs/astro.config.mjs @@ -0,0 +1,93 @@ +// @ts-check +import { defineConfig } from 'astro/config'; +import starlight from '@astrojs/starlight'; + +// https://astro.build/config +export default defineConfig({ + integrations: [ + starlight({ + title: 'Flutter Server Box', + description: 'A comprehensive cross-platform server management application built with Flutter', + logo: { + src: './src/assets/logo.svg', + }, + social: [ + { icon: 'github', label: 'GitHub', href: 'https://github.com/lollipopkit/flutter_server_box' }, + ], + sidebar: [ + { + label: 'Getting Started', + items: [ + { label: 'Introduction', slug: 'introduction' }, + { label: 'Installation', slug: 'installation' }, + { label: 'Quick Start', slug: 'quick-start' }, + ], + }, + { + label: 'Features', + items: [ + { label: 'Server Monitoring', slug: 'features/monitoring' }, + { label: 'Docker Management', slug: 'features/docker' }, + { label: 'Process & Services', slug: 'features/process' }, + { label: 'Command Snippets', slug: 'features/snippets' }, + { label: 'Network Tools', slug: 'features/network' }, + { label: 'PVE (Proxmox)', slug: 'features/pve' }, + ], + }, + { + label: 'Configuration', + items: [ + { label: 'Server Setup', slug: 'configuration/server' }, + { label: 'Terminal & SSH', slug: 'configuration/terminal' }, + { label: 'SFTP File Browser', slug: 'configuration/sftp' }, + { label: 'Jump Server', slug: 'configuration/jump-server' }, + { label: 'Backup & Restore', slug: 'configuration/backup' }, + { label: 'Appearance', slug: 'configuration/appearance' }, + { label: 'Localizations', slug: 'configuration/localizations' }, + ], + }, + { + label: 'Platform Features', + items: [ + { label: 'Mobile', slug: 'platforms/mobile' }, + { label: 'Desktop', slug: 'platforms/desktop' }, + { label: 'watchOS', slug: 'platforms/watchos' }, + ], + }, + { + label: 'Advanced', + items: [ + { label: 'Bulk Import Servers', slug: 'advanced/bulk-import' }, + { label: 'Widget Setup', slug: 'advanced/widgets' }, + { label: 'Custom Commands', slug: 'advanced/custom-commands' }, + { label: 'Custom Logo', slug: 'advanced/custom-logo' }, + { label: 'JSON Settings', slug: 'advanced/json-settings' }, + { label: 'Common Issues', slug: 'advanced/troubleshooting' }, + ], + }, + { + label: 'How It Works', + items: [ + { label: 'Architecture', slug: 'principles/architecture' }, + { label: 'SSH Connection', slug: 'principles/ssh' }, + { label: 'Terminal', slug: 'principles/terminal' }, + { label: 'SFTP', slug: 'principles/sftp' }, + { label: 'State Management', slug: 'principles/state' }, + ], + }, + { + label: 'Development', + items: [ + { label: 'Project Structure', slug: 'development/structure' }, + { label: 'Architecture', slug: 'development/architecture' }, + { label: 'State Management', slug: 'development/state' }, + { label: 'Code Generation', slug: 'development/codegen' }, + { label: 'Building', slug: 'development/building' }, + { label: 'Testing', slug: 'development/testing' }, + ], + }, + ], + customCss: ['./src/styles/custom.css'], + }), + ], +}); diff --git a/docs/bun.lock b/docs/bun.lock new file mode 100644 index 00000000..bb826e27 --- /dev/null +++ b/docs/bun.lock @@ -0,0 +1,900 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "docs", + "dependencies": { + "@astrojs/starlight": "^0.37.4", + "astro": "^5.6.1", + "sharp": "^0.34.2", + }, + }, + }, + "packages": { + "@astrojs/compiler": ["@astrojs/compiler@2.13.0", "", {}, "sha512-mqVORhUJViA28fwHYaWmsXSzLO9osbdZ5ImUfxBarqsYdMlPbqAqGJCxsNzvppp1BEzc1mJNjOVvQqeDN8Vspw=="], + + "@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.7.5", "", {}, "sha512-vreGnYSSKhAjFJCWAwe/CNhONvoc5lokxtRoZims+0wa3KbHBdPHSSthJsKxPd8d/aic6lWKpRTYGY/hsgK6EA=="], + + "@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.10", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.5", "@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.19.0", "smol-toml": "^1.5.2", "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-kk4HeYR6AcnzC4QV8iSlOfh+N8TZ3MEStxPyenyCtemqn8IpEATBFMTJcfrNW32dgpt6MY3oCkMM/Tv3/I4G3A=="], + + "@astrojs/mdx": ["@astrojs/mdx@4.3.13", "", { "dependencies": { "@astrojs/markdown-remark": "6.3.10", "@mdx-js/mdx": "^3.1.1", "acorn": "^8.15.0", "es-module-lexer": "^1.7.0", "estree-util-visit": "^2.0.0", "hast-util-to-html": "^9.0.5", "piccolore": "^0.1.3", "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.1", "remark-smartypants": "^3.0.2", "source-map": "^0.7.6", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-IHDHVKz0JfKBy3//52JSiyWv089b7GVSChIXLrlUOoTLWowG3wr2/8hkaEgEyd/vysvNQvGk+QhysXpJW5ve6Q=="], + + "@astrojs/prism": ["@astrojs/prism@3.3.0", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="], + + "@astrojs/sitemap": ["@astrojs/sitemap@3.7.0", "", { "dependencies": { "sitemap": "^8.0.2", "stream-replace-string": "^2.0.0", "zod": "^3.25.76" } }, "sha512-+qxjUrz6Jcgh+D5VE1gKUJTA3pSthuPHe6Ao5JCxok794Lewx8hBFaWHtOnN0ntb2lfOf7gvOi9TefUswQ/ZVA=="], + + "@astrojs/starlight": ["@astrojs/starlight@0.37.4", "", { "dependencies": { "@astrojs/markdown-remark": "^6.3.1", "@astrojs/mdx": "^4.2.3", "@astrojs/sitemap": "^3.3.0", "@pagefind/default-ui": "^1.3.0", "@types/hast": "^3.0.4", "@types/js-yaml": "^4.0.9", "@types/mdast": "^4.0.4", "astro-expressive-code": "^0.41.1", "bcp-47": "^2.1.0", "hast-util-from-html": "^2.0.1", "hast-util-select": "^6.0.2", "hast-util-to-string": "^3.0.0", "hastscript": "^9.0.0", "i18next": "^23.11.5", "js-yaml": "^4.1.0", "klona": "^2.0.6", "magic-string": "^0.30.17", "mdast-util-directive": "^3.0.0", "mdast-util-to-markdown": "^2.1.0", "mdast-util-to-string": "^4.0.0", "pagefind": "^1.3.0", "rehype": "^13.0.1", "rehype-format": "^5.0.0", "remark-directive": "^3.0.0", "ultrahtml": "^1.6.0", "unified": "^11.0.5", "unist-util-visit": "^5.0.0", "vfile": "^6.0.2" }, "peerDependencies": { "astro": "^5.5.0" } }, "sha512-ygPGDgRd9nCcNgaYMNN7UeAMAkDOR1ibv3ps3xEz+cuvKG3CRLd19UwdB+Gyz1tbkyfjPWPkFKNhLwNybro8Tw=="], + + "@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=="], + + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], + + "@babel/parser": ["@babel/parser@7.28.6", "", { "dependencies": { "@babel/types": "^7.28.6" }, "bin": "./bin/babel-parser.js" }, "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ=="], + + "@babel/runtime": ["@babel/runtime@7.28.6", "", {}, "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA=="], + + "@babel/types": ["@babel/types@7.28.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg=="], + + "@capsizecss/unpack": ["@capsizecss/unpack@4.0.0", "", { "dependencies": { "fontkitten": "^1.0.0" } }, "sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA=="], + + "@ctrl/tinycolor": ["@ctrl/tinycolor@4.2.0", "", {}, "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], + + "@expressive-code/core": ["@expressive-code/core@0.41.6", "", { "dependencies": { "@ctrl/tinycolor": "^4.0.4", "hast-util-select": "^6.0.2", "hast-util-to-html": "^9.0.1", "hast-util-to-text": "^4.0.1", "hastscript": "^9.0.0", "postcss": "^8.4.38", "postcss-nested": "^6.0.1", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1" } }, "sha512-FvJQP+hG0jWi/FLBSmvHInDqWR7jNANp9PUDjdMqSshHb0y7sxx3vHuoOr6SgXjWw+MGLqorZyPQ0aAlHEok6g=="], + + "@expressive-code/plugin-frames": ["@expressive-code/plugin-frames@0.41.6", "", { "dependencies": { "@expressive-code/core": "^0.41.6" } }, "sha512-d+hkSYXIQot6fmYnOmWAM+7TNWRv/dhfjMsNq+mIZz8Tb4mPHOcgcfZeEM5dV9TDL0ioQNvtcqQNuzA1sRPjxg=="], + + "@expressive-code/plugin-shiki": ["@expressive-code/plugin-shiki@0.41.6", "", { "dependencies": { "@expressive-code/core": "^0.41.6", "shiki": "^3.2.2" } }, "sha512-Y6zmKBmsIUtWTzdefqlzm/h9Zz0Rc4gNdt2GTIH7fhHH2I9+lDYCa27BDwuBhjqcos6uK81Aca9dLUC4wzN+ng=="], + + "@expressive-code/plugin-text-markers": ["@expressive-code/plugin-text-markers@0.41.6", "", { "dependencies": { "@expressive-code/core": "^0.41.6" } }, "sha512-PBFa1wGyYzRExMDzBmAWC6/kdfG1oLn4pLpBeTfIRrALPjcGA/59HP3e7q9J0Smk4pC7U+lWkA2LHR8FYV8U7Q=="], + + "@img/colour": ["@img/colour@1.0.0", "", {}, "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw=="], + + "@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=="], + + "@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=="], + + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="], + + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="], + + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="], + + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="], + + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="], + + "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="], + + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="], + + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="], + + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="], + + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@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=="], + + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="], + + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="], + + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@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=="], + + "@oslojs/encoding": ["@oslojs/encoding@1.1.0", "", {}, "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ=="], + + "@pagefind/darwin-arm64": ["@pagefind/darwin-arm64@1.4.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-2vMqkbv3lbx1Awea90gTaBsvpzgRs7MuSgKDxW0m9oV1GPZCZbZBJg/qL83GIUEN2BFlY46dtUZi54pwH+/pTQ=="], + + "@pagefind/darwin-x64": ["@pagefind/darwin-x64@1.4.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-e7JPIS6L9/cJfow+/IAqknsGqEPjJnVXGjpGm25bnq+NPdoD3c/7fAwr1OXkG4Ocjx6ZGSCijXEV4ryMcH2E3A=="], + + "@pagefind/default-ui": ["@pagefind/default-ui@1.4.0", "", {}, "sha512-wie82VWn3cnGEdIjh4YwNESyS1G6vRHwL6cNjy9CFgNnWW/PGRjsLq300xjVH5sfPFK3iK36UxvIBymtQIEiSQ=="], + + "@pagefind/freebsd-x64": ["@pagefind/freebsd-x64@1.4.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-WcJVypXSZ+9HpiqZjFXMUobfFfZZ6NzIYtkhQ9eOhZrQpeY5uQFqNWLCk7w9RkMUwBv1HAMDW3YJQl/8OqsV0Q=="], + + "@pagefind/linux-arm64": ["@pagefind/linux-arm64@1.4.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-PIt8dkqt4W06KGmQjONw7EZbhDF+uXI7i0XtRLN1vjCUxM9vGPdtJc2mUyVPevjomrGz5M86M8bqTr6cgDp1Uw=="], + + "@pagefind/linux-x64": ["@pagefind/linux-x64@1.4.0", "", { "os": "linux", "cpu": "x64" }, "sha512-z4oddcWwQ0UHrTHR8psLnVlz6USGJ/eOlDPTDYZ4cI8TK8PgwRUPQZp9D2iJPNIPcS6Qx/E4TebjuGJOyK8Mmg=="], + + "@pagefind/windows-x64": ["@pagefind/windows-x64@1.4.0", "", { "os": "win32", "cpu": "x64" }, "sha512-NkT+YAdgS2FPCn8mIA9bQhiBs+xmniMGq1LFPDhcFn0+2yIUEiIG06t7bsZlhdjknEQRTSdT7YitP6fC5qwP0g=="], + + "@rollup/pluginutils": ["@rollup/pluginutils@5.3.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-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.0", "", { "os": "android", "cpu": "arm" }, "sha512-tPgXB6cDTndIe1ah7u6amCI1T0SsnlOuKgg10Xh3uizJk4e5M1JGaUMk7J4ciuAUcFpbOiNhm2XIjP9ON0dUqA=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.57.0", "", { "os": "android", "cpu": "arm64" }, "sha512-sa4LyseLLXr1onr97StkU1Nb7fWcg6niokTwEVNOO7awaKaoRObQ54+V/hrF/BP1noMEaaAW6Fg2d/CfLiq3Mg=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.57.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/NNIj9A7yLjKdmkx5dC2XQ9DmjIECpGpwHoGmA5E1AhU0fuICSqSWScPhN1yLCkEdkCwJIDu2xIeLPs60MNIVg=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.57.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-xoh8abqgPrPYPr7pTYipqnUi1V3em56JzE/HgDgitTqZBZ3yKCWI+7KUkceM6tNweyUKYru1UMi7FC060RyKwA=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.57.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-PCkMh7fNahWSbA0OTUQ2OpYHpjZZr0hPr8lId8twD7a7SeWrvT3xJVyza+dQwXSSq4yEQTMoXgNOfMCsn8584g=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.57.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1j3stGx+qbhXql4OCDZhnK7b01s6rBKNybfsX+TNrEe9JNq4DLi1yGiR1xW+nL+FNVvI4D02PUnl6gJ/2y6WJA=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.57.0", "", { "os": "linux", "cpu": "arm" }, "sha512-eyrr5W08Ms9uM0mLcKfM/Uzx7hjhz2bcjv8P2uynfj0yU8GGPdz8iYrBPhiLOZqahoAMB8ZiolRZPbbU2MAi6Q=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.57.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Xds90ITXJCNyX9pDhqf85MKWUI4lqjiPAipJ8OLp8xqI2Ehk+TCVhF9rvOoN8xTbcafow3QOThkNnrM33uCFQA=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.57.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Xws2KA4CLvZmXjy46SQaXSejuKPhwVdaNinldoYfqruZBaJHqVo6hnRa8SDo9z7PBW5x84SH64+izmldCgbezw=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.57.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-hrKXKbX5FdaRJj7lTMusmvKbhMJSGWJ+w++4KmjiDhpTgNlhYobMvKfDoIWecy4O60K6yA4SnztGuNTQF+Lplw=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.57.0", "", { "os": "linux", "cpu": "none" }, "sha512-6A+nccfSDGKsPm00d3xKcrsBcbqzCTAukjwWK6rbuAnB2bHaL3r9720HBVZ/no7+FhZLz/U3GwwZZEh6tOSI8Q=="], + + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.57.0", "", { "os": "linux", "cpu": "none" }, "sha512-4P1VyYUe6XAJtQH1Hh99THxr0GKMMwIXsRNOceLrJnaHTDgk1FTcTimDgneRJPvB3LqDQxUmroBclQ1S0cIJwQ=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.57.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-8Vv6pLuIZCMcgXre6c3nOPhE0gjz1+nZP6T+hwWjr7sVH8k0jRkH+XnfjjOTglyMBdSKBPPz54/y1gToSKwrSQ=="], + + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.57.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-r1te1M0Sm2TBVD/RxBPC6RZVwNqUTwJTA7w+C/IW5v9Ssu6xmxWEi+iJQlpBhtUiT1raJ5b48pI8tBvEjEFnFA=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.57.0", "", { "os": "linux", "cpu": "none" }, "sha512-say0uMU/RaPm3CDQLxUUTF2oNWL8ysvHkAjcCzV2znxBr23kFfaxocS9qJm+NdkRhF8wtdEEAJuYcLPhSPbjuQ=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.57.0", "", { "os": "linux", "cpu": "none" }, "sha512-/MU7/HizQGsnBREtRpcSbSV1zfkoxSTR7wLsRmBPQ8FwUj5sykrP1MyJTvsxP5KBq9SyE6kH8UQQQwa0ASeoQQ=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.57.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-Q9eh+gUGILIHEaJf66aF6a414jQbDnn29zeu0eX3dHMuysnhTvsUvZTCAyZ6tJhUjnvzBKE4FtuaYxutxRZpOg=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.57.0", "", { "os": "linux", "cpu": "x64" }, "sha512-OR5p5yG5OKSxHReWmwvM0P+VTPMwoBS45PXTMYaskKQqybkS3Kmugq1W+YbNWArF8/s7jQScgzXUhArzEQ7x0A=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.57.0", "", { "os": "linux", "cpu": "x64" }, "sha512-XeatKzo4lHDsVEbm1XDHZlhYZZSQYym6dg2X/Ko0kSFgio+KXLsxwJQprnR48GvdIKDOpqWqssC3iBCjoMcMpw=="], + + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.57.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-Lu71y78F5qOfYmubYLHPcJm74GZLU6UJ4THkf/a1K7Tz2ycwC2VUbsqbJAXaR6Bx70SRdlVrt2+n5l7F0agTUw=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.57.0", "", { "os": "none", "cpu": "arm64" }, "sha512-v5xwKDWcu7qhAEcsUubiav7r+48Uk/ENWdr82MBZZRIm7zThSxCIVDfb3ZeRRq9yqk+oIzMdDo6fCcA5DHfMyA=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.57.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-XnaaaSMGSI6Wk8F4KK3QP7GfuuhjGchElsVerCplUuxRIzdvZ7hRBpLR0omCmw+kI2RFJB80nenhOoGXlJ5TfQ=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.57.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-3K1lP+3BXY4t4VihLw5MEg6IZD3ojSYzqzBG571W3kNQe4G4CcFpSUQVgurYgib5d+YaCjeFow8QivWp8vuSvA=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.57.0", "", { "os": "win32", "cpu": "x64" }, "sha512-MDk610P/vJGc5L5ImE4k5s+GZT3en0KoK1MKPXCRgzmksAMk79j4h3k1IerxTNqwDLxsGxStEZVBqG0gIqZqoA=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.57.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Zv7v6q6aV+VslnpwzqKAmrk5JdVkLUzok2208ZXGipjb+msxBr/fJPZyeEXiFgH7k62Ak0SLIfxQRZQvTuf7rQ=="], + + "@shikijs/core": ["@shikijs/core@3.21.0", "", { "dependencies": { "@shikijs/types": "3.21.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-AXSQu/2n1UIQekY8euBJlvFYZIw0PHY63jUzGbrOma4wPxzznJXTXkri+QcHeBNaFxiiOljKxxJkVSoB3PjbyA=="], + + "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.21.0", "", { "dependencies": { "@shikijs/types": "3.21.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-ATwv86xlbmfD9n9gKRiwuPpWgPENAWCLwYCGz9ugTJlsO2kOzhOkvoyV/UD+tJ0uT7YRyD530x6ugNSffmvIiQ=="], + + "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.21.0", "", { "dependencies": { "@shikijs/types": "3.21.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-OYknTCct6qiwpQDqDdf3iedRdzj6hFlOPv5hMvI+hkWfCKs5mlJ4TXziBG9nyabLwGulrUjHiCq3xCspSzErYQ=="], + + "@shikijs/langs": ["@shikijs/langs@3.21.0", "", { "dependencies": { "@shikijs/types": "3.21.0" } }, "sha512-g6mn5m+Y6GBJ4wxmBYqalK9Sp0CFkUqfNzUy2pJglUginz6ZpWbaWjDB4fbQ/8SHzFjYbtU6Ddlp1pc+PPNDVA=="], + + "@shikijs/themes": ["@shikijs/themes@3.21.0", "", { "dependencies": { "@shikijs/types": "3.21.0" } }, "sha512-BAE4cr9EDiZyYzwIHEk7JTBJ9CzlPuM4PchfcA5ao1dWXb25nv6hYsoDiBq2aZK9E3dlt3WB78uI96UESD+8Mw=="], + + "@shikijs/types": ["@shikijs/types@3.21.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-zGrWOxZ0/+0ovPY7PvBU2gIS9tmhSUUt30jAcNV0Bq0gb2S98gwfjIs1vxlmH5zM7/4YxLamT6ChlqqAJmPPjA=="], + + "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], + + "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], + + "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], + + "@types/js-yaml": ["@types/js-yaml@4.0.9", "", {}, "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg=="], + + "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], + + "@types/mdx": ["@types/mdx@2.0.13", "", {}, "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw=="], + + "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], + + "@types/nlcst": ["@types/nlcst@2.0.3", "", { "dependencies": { "@types/unist": "*" } }, "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA=="], + + "@types/node": ["@types/node@17.0.45", "", {}, "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw=="], + + "@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.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], + + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + + "ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="], + + "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + + "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], + + "array-iterate": ["array-iterate@2.0.1", "", {}, "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg=="], + + "astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="], + + "astro": ["astro@5.16.16", "", { "dependencies": { "@astrojs/compiler": "^2.13.0", "@astrojs/internal-helpers": "0.7.5", "@astrojs/markdown-remark": "6.3.10", "@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.25.0", "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-MFlFvQ84ixaHyqB3uGwMhNHdBLZ3vHawyq3PqzQS2TNWiNfQrxp5ag6S3lX+Cvnh0MUcXX+UnJBPMBHjP1/1ZQ=="], + + "astro-expressive-code": ["astro-expressive-code@0.41.6", "", { "dependencies": { "rehype-expressive-code": "^0.41.6" }, "peerDependencies": { "astro": "^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta" } }, "sha512-l47tb1uhmVIebHUkw+HEPtU/av0G4O8Q34g2cbkPvC7/e9ZhANcjUUciKt9Hp6gSVDdIuXBBLwJQn2LkeGMOAw=="], + + "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], + + "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], + + "base-64": ["base-64@1.0.0", "", {}, "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="], + + "bcp-47": ["bcp-47@2.1.0", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w=="], + + "bcp-47-match": ["bcp-47-match@2.0.3", "", {}, "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ=="], + + "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + + "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=="], + + "camelcase": ["camelcase@8.0.0", "", {}, "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA=="], + + "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], + + "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + + "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], + + "character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="], + + "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], + + "character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="], + + "chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], + + "ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="], + + "cli-boxes": ["cli-boxes@3.0.0", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="], + + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + + "collapse-white-space": ["collapse-white-space@2.1.0", "", {}, "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw=="], + + "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], + + "commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], + + "common-ancestor-path": ["common-ancestor-path@1.0.1", "", {}, "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="], + + "cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], + + "cookie-es": ["cookie-es@1.2.2", "", {}, "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg=="], + + "crossws": ["crossws@0.3.5", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA=="], + + "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + + "css-selector-parser": ["css-selector-parser@3.3.0", "", {}, "sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g=="], + + "css-tree": ["css-tree@3.1.0", "", { "dependencies": { "mdn-data": "2.12.2", "source-map-js": "^1.0.1" } }, "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w=="], + + "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + + "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], + + "csso": ["csso@5.0.5", "", { "dependencies": { "css-tree": "~2.2.0" } }, "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "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.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], + + "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.6.2", "", {}, "sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg=="], + + "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], + + "diff": ["diff@8.0.3", "", {}, "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ=="], + + "direction": ["direction@2.0.1", "", { "bin": { "direction": "cli.js" } }, "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA=="], + + "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="], + + "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=="], + + "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + + "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=="], + + "dset": ["dset@3.1.4", "", {}, "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA=="], + + "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + + "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + + "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], + + "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=="], + + "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=="], + + "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=="], + + "escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + + "estree-util-attach-comments": ["estree-util-attach-comments@3.0.0", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw=="], + + "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=="], + + "estree-util-is-identifier-name": ["estree-util-is-identifier-name@3.0.0", "", {}, "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg=="], + + "estree-util-scope": ["estree-util-scope@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0" } }, "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ=="], + + "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=="], + + "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=="], + + "expressive-code": ["expressive-code@0.41.6", "", { "dependencies": { "@expressive-code/core": "^0.41.6", "@expressive-code/plugin-frames": "^0.41.6", "@expressive-code/plugin-shiki": "^0.41.6", "@expressive-code/plugin-text-markers": "^0.41.6" } }, "sha512-W/5+IQbrpCIM5KGLjO35wlp1NCwDOOVQb+PAvzEoGkW1xjGM807ZGfBKptNWH6UECvt6qgmLyWolCMYKh7eQmA=="], + + "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], + + "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=="], + + "fontace": ["fontace@0.4.0", "", { "dependencies": { "fontkitten": "^1.0.0" } }, "sha512-moThBCItUe2bjZip5PF/iZClpKHGLwMvR79Kp8XpGRBrvoRSnySN4VcILdv3/MJzbhvUA5WeiUXF5o538m5fvg=="], + + "fontkitten": ["fontkitten@1.0.2", "", { "dependencies": { "tiny-inflate": "^1.0.3" } }, "sha512-piJxbLnkD9Xcyi7dWJRnqszEURixe7CrF/efBfbffe2DPyabmuIuqraruY8cXTs19QoM8VJzx47BDRVNXETM7Q=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="], + + "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], + + "h3": ["h3@1.15.5", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "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-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg=="], + + "hast-util-embedded": ["hast-util-embedded@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-is-element": "^3.0.0" } }, "sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA=="], + + "hast-util-format": ["hast-util-format@1.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-embedded": "^3.0.0", "hast-util-minify-whitespace": "^1.0.0", "hast-util-phrasing": "^3.0.0", "hast-util-whitespace": "^3.0.0", "html-whitespace-sensitive-tag-names": "^3.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA=="], + + "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=="], + + "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-has-property": ["hast-util-has-property@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA=="], + + "hast-util-is-body-ok-link": ["hast-util-is-body-ok-link@3.0.1", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ=="], + + "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-minify-whitespace": ["hast-util-minify-whitespace@1.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-embedded": "^3.0.0", "hast-util-is-element": "^3.0.0", "hast-util-whitespace": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw=="], + + "hast-util-parse-selector": ["hast-util-parse-selector@4.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A=="], + + "hast-util-phrasing": ["hast-util-phrasing@3.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-embedded": "^3.0.0", "hast-util-has-property": "^3.0.0", "hast-util-is-body-ok-link": "^3.0.0", "hast-util-is-element": "^3.0.0" } }, "sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ=="], + + "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-select": ["hast-util-select@6.0.4", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "bcp-47-match": "^2.0.0", "comma-separated-tokens": "^2.0.0", "css-selector-parser": "^3.0.0", "devlop": "^1.0.0", "direction": "^2.0.0", "hast-util-has-property": "^3.0.0", "hast-util-to-string": "^3.0.0", "hast-util-whitespace": "^3.0.0", "nth-check": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw=="], + + "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-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-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-string": ["hast-util-to-string@3.0.1", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A=="], + + "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-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=="], + + "html-whitespace-sensitive-tag-names": ["html-whitespace-sensitive-tag-names@3.0.1", "", {}, "sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA=="], + + "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="], + + "i18next": ["i18next@23.16.8", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg=="], + + "import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="], + + "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], + + "iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="], + + "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="], + + "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-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], + + "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="], + + "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-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], + + "is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="], + + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + + "kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], + + "klona": ["klona@2.0.6", "", {}, "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA=="], + + "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], + + "lru-cache": ["lru-cache@11.2.5", "", {}, "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "magicast": ["magicast@0.5.1", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "source-map-js": "^1.2.1" } }, "sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw=="], + + "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-directive": ["mdast-util-directive@3.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "devlop": "^1.0.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-visit-parents": "^6.0.0" } }, "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q=="], + + "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.2", "", { "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-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA=="], + + "mdast-util-gfm": ["mdast-util-gfm@3.1.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-gfm-autolink-literal": "^2.0.0", "mdast-util-gfm-footnote": "^2.0.0", "mdast-util-gfm-strikethrough": "^2.0.0", "mdast-util-gfm-table": "^2.0.0", "mdast-util-gfm-task-list-item": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ=="], + + "mdast-util-gfm-autolink-literal": ["mdast-util-gfm-autolink-literal@2.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "ccount": "^2.0.0", "devlop": "^1.0.0", "mdast-util-find-and-replace": "^3.0.0", "micromark-util-character": "^2.0.0" } }, "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ=="], + + "mdast-util-gfm-footnote": ["mdast-util-gfm-footnote@2.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0" } }, "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ=="], + + "mdast-util-gfm-strikethrough": ["mdast-util-gfm-strikethrough@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg=="], + + "mdast-util-gfm-table": ["mdast-util-gfm-table@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "markdown-table": "^3.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg=="], + + "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=="], + + "mdast-util-to-markdown": ["mdast-util-to-markdown@2.1.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "longest-streak": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "mdast-util-to-string": "^4.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA=="], + + "mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="], + + "mdn-data": ["mdn-data@2.12.2", "", {}, "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA=="], + + "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=="], + + "micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="], + + "micromark-extension-directive": ["micromark-extension-directive@3.0.2", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "parse-entities": "^4.0.0" } }, "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA=="], + + "micromark-extension-gfm": ["micromark-extension-gfm@3.0.0", "", { "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", "micromark-extension-gfm-footnote": "^2.0.0", "micromark-extension-gfm-strikethrough": "^2.0.0", "micromark-extension-gfm-table": "^2.0.0", "micromark-extension-gfm-tagfilter": "^2.0.0", "micromark-extension-gfm-task-list-item": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w=="], + + "micromark-extension-gfm-autolink-literal": ["micromark-extension-gfm-autolink-literal@2.1.0", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw=="], + + "micromark-extension-gfm-footnote": ["micromark-extension-gfm-footnote@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw=="], + + "micromark-extension-gfm-strikethrough": ["micromark-extension-gfm-strikethrough@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw=="], + + "micromark-extension-gfm-table": ["micromark-extension-gfm-table@2.1.1", "", { "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-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg=="], + + "micromark-extension-gfm-tagfilter": ["micromark-extension-gfm-tagfilter@2.0.0", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg=="], + + "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=="], + + "micromark-factory-whitespace": ["micromark-factory-whitespace@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-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ=="], + + "micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="], + + "micromark-util-chunked": ["micromark-util-chunked@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA=="], + + "micromark-util-classify-character": ["micromark-util-classify-character@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q=="], + + "micromark-util-combine-extensions": ["micromark-util-combine-extensions@2.0.1", "", { "dependencies": { "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg=="], + + "micromark-util-decode-numeric-character-reference": ["micromark-util-decode-numeric-character-reference@2.0.2", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw=="], + + "micromark-util-decode-string": ["micromark-util-decode-string@2.0.1", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ=="], + + "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=="], + + "micromark-util-resolve-all": ["micromark-util-resolve-all@2.0.1", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg=="], + + "micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ=="], + + "micromark-util-subtokenize": ["micromark-util-subtokenize@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA=="], + + "micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="], + + "micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="], + + "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "neotraverse": ["neotraverse@0.6.18", "", {}, "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="], + + "nlcst-to-string": ["nlcst-to-string@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0" } }, "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA=="], + + "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], + + "node-mock-http": ["node-mock-http@1.0.4", "", {}, "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + + "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + + "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=="], + + "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], + + "oniguruma-parser": ["oniguruma-parser@0.12.1", "", {}, "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w=="], + + "oniguruma-to-es": ["oniguruma-to-es@4.3.4", "", { "dependencies": { "oniguruma-parser": "^0.12.1", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA=="], + + "p-limit": ["p-limit@6.2.0", "", { "dependencies": { "yocto-queue": "^1.1.1" } }, "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA=="], + + "p-queue": ["p-queue@8.1.1", "", { "dependencies": { "eventemitter3": "^5.0.1", "p-timeout": "^6.1.2" } }, "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ=="], + + "p-timeout": ["p-timeout@6.1.4", "", {}, "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg=="], + + "package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="], + + "pagefind": ["pagefind@1.4.0", "", { "optionalDependencies": { "@pagefind/darwin-arm64": "1.4.0", "@pagefind/darwin-x64": "1.4.0", "@pagefind/freebsd-x64": "1.4.0", "@pagefind/linux-arm64": "1.4.0", "@pagefind/linux-x64": "1.4.0", "@pagefind/windows-x64": "1.4.0" }, "bin": { "pagefind": "lib/runner/bin.cjs" } }, "sha512-z2kY1mQlL4J8q5EIsQkLzQjilovKzfNVhX8De6oyE6uHpfFtyBaqUpcl/XzJC/4fjD8vBDyh1zolimIcVrCn9g=="], + + "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=="], + + "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=="], + + "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], + + "piccolore": ["piccolore@0.1.3", "", {}, "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + + "postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="], + + "postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], + + "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.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], + + "radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="], + + "readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], + + "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=="], + + "regex-recursion": ["regex-recursion@6.0.2", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg=="], + + "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=="], + + "rehype-expressive-code": ["rehype-expressive-code@0.41.6", "", { "dependencies": { "expressive-code": "^0.41.6" } }, "sha512-aBMX8kxPtjmDSFUdZlAWJkMvsQ4ZMASfee90JWIAV8tweltXLzkWC3q++43ToTelI8ac5iC0B3/S/Cl4Ql1y2g=="], + + "rehype-format": ["rehype-format@5.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-format": "^1.0.0" } }, "sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ=="], + + "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=="], + + "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-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=="], + + "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=="], + + "remark-directive": ["remark-directive@3.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-directive": "^3.0.0", "micromark-extension-directive": "^3.0.0", "unified": "^11.0.0" } }, "sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A=="], + + "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.2", "", { "dependencies": { "retext": "^9.0.0", "retext-smartypants": "^6.0.0", "unified": "^11.0.4", "unist-util-visit": "^5.0.0" } }, "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA=="], + + "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=="], + + "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=="], + + "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=="], + + "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=="], + + "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=="], + + "rollup": ["rollup@4.57.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.0", "@rollup/rollup-android-arm64": "4.57.0", "@rollup/rollup-darwin-arm64": "4.57.0", "@rollup/rollup-darwin-x64": "4.57.0", "@rollup/rollup-freebsd-arm64": "4.57.0", "@rollup/rollup-freebsd-x64": "4.57.0", "@rollup/rollup-linux-arm-gnueabihf": "4.57.0", "@rollup/rollup-linux-arm-musleabihf": "4.57.0", "@rollup/rollup-linux-arm64-gnu": "4.57.0", "@rollup/rollup-linux-arm64-musl": "4.57.0", "@rollup/rollup-linux-loong64-gnu": "4.57.0", "@rollup/rollup-linux-loong64-musl": "4.57.0", "@rollup/rollup-linux-ppc64-gnu": "4.57.0", "@rollup/rollup-linux-ppc64-musl": "4.57.0", "@rollup/rollup-linux-riscv64-gnu": "4.57.0", "@rollup/rollup-linux-riscv64-musl": "4.57.0", "@rollup/rollup-linux-s390x-gnu": "4.57.0", "@rollup/rollup-linux-x64-gnu": "4.57.0", "@rollup/rollup-linux-x64-musl": "4.57.0", "@rollup/rollup-openbsd-x64": "4.57.0", "@rollup/rollup-openharmony-arm64": "4.57.0", "@rollup/rollup-win32-arm64-msvc": "4.57.0", "@rollup/rollup-win32-ia32-msvc": "4.57.0", "@rollup/rollup-win32-x64-gnu": "4.57.0", "@rollup/rollup-win32-x64-msvc": "4.57.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-e5lPJi/aui4TO1LpAXIRLySmwXSE8k3b9zoGfd42p67wzxog4WHjiZF3M2uheQih4DGyc25QEV4yRBbpueNiUA=="], + + "sax": ["sax@1.4.4", "", {}, "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw=="], + + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "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=="], + + "shiki": ["shiki@3.21.0", "", { "dependencies": { "@shikijs/core": "3.21.0", "@shikijs/engine-javascript": "3.21.0", "@shikijs/engine-oniguruma": "3.21.0", "@shikijs/langs": "3.21.0", "@shikijs/themes": "3.21.0", "@shikijs/types": "3.21.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-N65B/3bqL/TI2crrXr+4UivctrAGEjmsib5rPMMPpFp1xAx/w03v8WZ9RDDFYteXoEgY7qZ4HGgl5KBIu1153w=="], + + "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], + + "sitemap": ["sitemap@8.0.2", "", { "dependencies": { "@types/node": "^17.0.5", "@types/sax": "^1.2.1", "arg": "^5.0.0", "sax": "^1.4.1" }, "bin": { "sitemap": "dist/cli.js" } }, "sha512-LwktpJcyZDoa0IL6KT++lQ53pbSrx2c9ge41/SeLTyqy2XUNA6uR4+P9u5IVo5lPeL2arAcOKn1aZAxoYbCKlQ=="], + + "smol-toml": ["smol-toml@1.6.0", "", {}, "sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw=="], + + "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=="], + + "stream-replace-string": ["stream-replace-string@2.0.0", "", {}, "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w=="], + + "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=="], + + "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.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "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=="], + + "svgo": ["svgo@4.0.0", "", { "dependencies": { "commander": "^11.1.0", "css-select": "^5.1.0", "css-tree": "^3.0.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.1.1", "sax": "^1.4.1" }, "bin": "./bin/svgo.js" }, "sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw=="], + + "tiny-inflate": ["tiny-inflate@1.0.3", "", {}, "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="], + + "tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], + + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + + "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], + + "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=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], + + "ultrahtml": ["ultrahtml@1.6.0", "", {}, "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw=="], + + "uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="], + + "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.3", "", { "dependencies": { "css-tree": "^3.1.0", "ofetch": "^1.5.1", "ohash": "^2.0.11" } }, "sha512-b0GtQzKCyuSHGsfj5vyN8st7muZ6VCI4XD4vFlr7Uy1rlWVYxC3npnfk8MyreHxJYrz1ooLDqDzFe9XqQTlAhA=="], + + "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.4", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^5.0.0", "destr": "^2.0.5", "h3": "^1.15.5", "lru-cache": "^11.2.0", "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-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "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.1", "", { "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-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="], + + "vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="], + + "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=="], + + "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + + "yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="], + + "yocto-spinner": ["yocto-spinner@0.2.3", "", { "dependencies": { "yoctocolors": "^2.1.1" } }, "sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ=="], + + "yoctocolors": ["yoctocolors@2.1.2", "", {}, "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug=="], + + "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="], + + "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=="], + + "@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + + "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.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "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=="], + + "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + + "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=="], + + "ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + } +} diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 00000000..07df67b0 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,17 @@ +{ + "name": "docs", + "type": "module", + "version": "0.0.1", + "scripts": { + "dev": "astro dev", + "start": "astro dev", + "build": "astro build", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "@astrojs/starlight": "^0.37.4", + "astro": "^5.6.1", + "sharp": "^0.34.2" + } +} \ No newline at end of file diff --git a/docs/public/favicon.svg b/docs/public/favicon.svg new file mode 100644 index 00000000..cba5ac14 --- /dev/null +++ b/docs/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/src/assets/houston.webp b/docs/src/assets/houston.webp new file mode 100644 index 00000000..930c1649 Binary files /dev/null and b/docs/src/assets/houston.webp differ diff --git a/docs/src/assets/logo.svg b/docs/src/assets/logo.svg new file mode 100644 index 00000000..7a4c7c73 --- /dev/null +++ b/docs/src/assets/logo.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + > + + + + + + + + + + + + + + + diff --git a/docs/src/content.config.ts b/docs/src/content.config.ts new file mode 100644 index 00000000..d9ee8c9d --- /dev/null +++ b/docs/src/content.config.ts @@ -0,0 +1,7 @@ +import { defineCollection } from 'astro:content'; +import { docsLoader } from '@astrojs/starlight/loaders'; +import { docsSchema } from '@astrojs/starlight/schema'; + +export const collections = { + docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }), +}; diff --git a/docs/src/content/docs/advanced/bulk-import.md b/docs/src/content/docs/advanced/bulk-import.md new file mode 100644 index 00000000..8ba04647 --- /dev/null +++ b/docs/src/content/docs/advanced/bulk-import.md @@ -0,0 +1,83 @@ +--- +title: Bulk Import Servers +description: Import multiple servers from JSON file +--- + +Import multiple server configurations at once using a JSON file. + +## JSON Format + +:::danger[Security Warning] +**Never store plaintext passwords in files!** This JSON example shows a password field for demonstration only, but you should: + +- **Prefer SSH keys** (`keyId`) instead of `pwd` - they're more secure +- **Use secret managers** or environment variables if you must use passwords +- **Delete the file immediately** after import - don't leave credentials lying around +- **Add to .gitignore** - never commit credential files to version control +::: + +```json +[ + { + "name": "My Server", + "ip": "example.com", + "port": 22, + "user": "root", + "pwd": "password", + "keyId": "", + "tags": ["production"], + "autoConnect": false + } +] +``` + +## Fields + +| Field | Required | Description | +|-------|----------|-------------| +| `name` | Yes | Display name | +| `ip` | Yes | Domain or IP address | +| `port` | Yes | SSH port (usually 22) | +| `user` | Yes | SSH username | +| `pwd` | No | Password (avoid - use SSH keys instead) | +| `keyId` | No | SSH key name (from Private Keys - recommended) | +| `tags` | No | Organization tags | +| `autoConnect` | No | Auto-connect on startup | + +## Import Steps + +1. Create JSON file with server configurations +2. Settings → Backup → Bulk Import Servers +3. Select your JSON file +4. Confirm import + +## Example + +```json +[ + { + "name": "Production", + "ip": "prod.example.com", + "port": 22, + "user": "admin", + "keyId": "my-key", + "tags": ["production", "web"] + }, + { + "name": "Development", + "ip": "dev.example.com", + "port": 2222, + "user": "dev", + "keyId": "dev-key", + "tags": ["development"] + } +] +``` + +## Tips + +- **Use SSH keys** instead of passwords when possible +- **Test connection** after import +- **Organize with tags** for easier management +- **Delete JSON file** after import +- **Never commit** JSON files with credentials to version control diff --git a/docs/src/content/docs/advanced/custom-commands.md b/docs/src/content/docs/advanced/custom-commands.md new file mode 100644 index 00000000..b80aa657 --- /dev/null +++ b/docs/src/content/docs/advanced/custom-commands.md @@ -0,0 +1,72 @@ +--- +title: Custom Commands +description: Display custom command output on server page +--- + +Add custom shell commands to show their output on the server detail page. + +## Setup + +1. Server settings → Custom Commands +2. Enter commands in JSON format + +## Basic Format + +```json +{ + "Display Name": "shell command" +} +``` + +**Example:** +```json +{ + "Memory": "free -h", + "Disk": "df -h", + "Uptime": "uptime" +} +``` + +## Viewing Results + +After setup, custom commands appear on server detail page and refresh automatically. + +## Special Command Names + +### server_card_top_right + +Display on home page server card (top-right corner): + +```json +{ + "server_card_top_right": "your-command-here" +} +``` + +## Tips + +**Use absolute paths:** +```json +{"My Script": "/usr/local/bin/my-script.sh"} +``` + +**Pipe commands:** +```json +{"Top Process": "ps aux | sort -rk 3 | head -5"} +``` + +**Format output:** +```json +{"CPU Load": "uptime | awk -F'load average:' '{print $2}'"} +``` + +**Keep commands fast:** Under 5 seconds for best experience + +**Limit output:** +```json +{"Logs": "tail -20 /var/log/syslog"} +``` + +## Security + +Commands run with SSH user permissions. Avoid commands that modify system state. diff --git a/docs/src/content/docs/advanced/custom-logo.md b/docs/src/content/docs/advanced/custom-logo.md new file mode 100644 index 00000000..b8d7ae47 --- /dev/null +++ b/docs/src/content/docs/advanced/custom-logo.md @@ -0,0 +1,54 @@ +--- +title: Custom Server Logo +description: Use custom images for server cards +--- + +Display custom logos on server cards using image URLs. + +## Setup + +1. Server settings → Custom Logo +2. Enter image URL + +## URL Placeholders + +### {DIST} - Linux Distribution + +Auto-replaced with detected distribution: + +``` +https://example.com/{DIST}.png +``` + +Becomes: `debian.png`, `ubuntu.png`, `arch.png`, etc. + +### {BRIGHT} - Theme + +Auto-replaced with current theme: + +``` +https://example.com/{BRIGHT}.png +``` + +Becomes: `light.png` or `dark.png` + +### Combine Both + +``` +https://example.com/{DIST}-{BRIGHT}.png +``` + +Becomes: `debian-light.png`, `ubuntu-dark.png`, etc. + +## Tips + +- Use PNG or SVG formats +- Recommended size: 64x64 to 128x128 pixels +- Use HTTPS URLs +- Keep file sizes small + +## Supported Distributions + +debian, ubuntu, centos, fedora, opensuse, kali, alpine, arch, rocky, deepin, armbian, wrt + +Full list: [`dist.dart`](https://github.com/lollipopkit/flutter_server_box/blob/main/lib/data/model/server/dist.dart) diff --git a/docs/src/content/docs/advanced/json-settings.md b/docs/src/content/docs/advanced/json-settings.md new file mode 100644 index 00000000..18fb531e --- /dev/null +++ b/docs/src/content/docs/advanced/json-settings.md @@ -0,0 +1,75 @@ +--- +title: Hidden Settings (JSON) +description: Access advanced settings via JSON editor +--- + +Some settings are hidden from the UI but accessible via JSON editor. + +## Access + +Long-press **Settings** in drawer to open JSON editor. + +## Common Hidden Settings + +### serverTabUseOldUI + +Use old server tab UI. + +```json +{"serverTabUseOldUI": true} +``` + +**Type:** boolean | **Default:** false + +### timeout + +Connection timeout in seconds. + +```json +{"timeout": 10} +``` + +**Type:** integer | **Default:** 5 | **Range:** 1-60 + +### recordHistory + +Save history (SFTP paths, etc.). + +```json +{"recordHistory": true} +``` + +**Type:** boolean | **Default:** true + +### textFactor + +Text scaling factor. + +```json +{"textFactor": 1.2} +``` + +**Type:** double | **Default:** 1.0 | **Range:** 0.8-1.5 + +## Finding More Settings + +All settings defined in [`setting.dart`](https://github.com/lollipopkit/flutter_server_box/blob/main/lib/data/store/setting.dart). + +Look for: +```dart +late final settingName = StoreProperty(box, 'settingKey', defaultValue); +``` + +## ⚠️ Important + +**Before editing:** +- **Create backup** - Wrong settings can cause app to not open +- **Edit carefully** - JSON must be valid +- **Change one at a time** - Test each setting + +## Recovery + +If app won't open after editing: +1. Clear app data (last resort) +2. Reinstall app +3. Restore from backup diff --git a/docs/src/content/docs/advanced/troubleshooting.md b/docs/src/content/docs/advanced/troubleshooting.md new file mode 100644 index 00000000..0ea24c8e --- /dev/null +++ b/docs/src/content/docs/advanced/troubleshooting.md @@ -0,0 +1,118 @@ +--- +title: Common Issues +description: Solutions to common problems +--- + +## Connection Issues + +### SSH Won't Connect + +**Symptoms:** Timeout, connection refused, auth failed + +**Solutions:** + +1. **Verify server type:** Only Unix-like systems supported (Linux, macOS, Android/Termux) +2. **Test manually:** `ssh user@server -p port` +3. **Check firewall:** Port 22 must be open +4. **Verify credentials:** Username and password/key correct + +### Frequent Disconnections + +**Symptoms:** Terminal disconnects after inactivity + +**Solutions:** + +1. **Server keep-alive:** + ```bash + # /etc/ssh/sshd_config + ClientAliveInterval 60 + ClientAliveCountMax 3 + ``` + +2. **Disable battery optimization:** + - MIUI: Battery → "No limits" + - Android: Settings → Apps → Disable optimization + - iOS: Enable background refresh + +## Input Issues + +### Can't Type Certain Characters + +**Solution:** Settings → Keyboard Type → Switch to `visiblePassword` + +Note: CJK input may not work after this change. + +## App Issues + +### App Crashes on Startup + +**Symptoms:** App won't open, black screen + +**Causes:** Corrupted settings, especially from JSON editor + +**Solutions:** + +1. **Clear app data:** + - Android: Settings → Apps → ServerBox → Clear Data + - iOS: Delete and reinstall + +2. **Restore backup:** Import backup created before changing settings + +### Backup/Restore Issues + +**Backup not working:** +- Check storage space +- Verify app has storage permissions +- Try different location + +**Restore fails:** +- Verify backup file integrity +- Check app version compatibility + +## Widget Issues + +### Widget Not Updating + +**iOS:** +- Wait up to 30 minutes for automatic refresh +- Remove and re-add widget +- Check URL ends with `/status` + +**Android:** +- Tap widget to force refresh +- Verify widget ID matches configuration in app settings + +**watchOS:** +- Restart watch app +- Wait a few minutes after config change +- Verify URL format + +### Widget Shows Error + +- Verify ServerBox Monitor is running on server +- Test URL in browser +- Check authentication credentials + +## Performance Issues + +### App is Slow + +**Solutions:** +- Reduce refresh rate in settings +- Check network speed +- Disable unused servers + +### High Battery Usage + +**Solutions:** +- Increase refresh intervals +- Disable background refresh +- Close unused SSH sessions + +## Getting Help + +If issues persist: + +1. **Search GitHub Issues:** https://github.com/lollipopkit/flutter_server_box/issues +2. **Create New Issue:** Include app version, platform, and steps to reproduce +3. **Check Wiki:** This documentation and GitHub Wiki diff --git a/docs/src/content/docs/advanced/widgets.md b/docs/src/content/docs/advanced/widgets.md new file mode 100644 index 00000000..33713e39 --- /dev/null +++ b/docs/src/content/docs/advanced/widgets.md @@ -0,0 +1,91 @@ +--- +title: Home Screen Widgets +description: Add server status widgets to your home screen +--- + +Requires [ServerBox Monitor](https://github.com/lollipopkit/server_box_monitor) installed on your servers. + +## Prerequisites + +Install ServerBox Monitor on your server first. See [ServerBox Monitor Wiki](https://github.com/lollipopkit/server_box_monitor/wiki/Home) for setup instructions. + +After installation, your server should have: +- HTTP/HTTPS endpoint +- `/status` API endpoint +- Optional authentication + +## URL Format + +``` +https://your-server.com/status +``` + +Must end with `/status`. + +## iOS Widget + +### Setup + +1. Long press home screen → Tap **+** +2. Search "ServerBox" +3. Choose widget size +4. Long press widget → **Edit Widget** +5. Enter URL ending with `/status` + +### Notes + +- Must use HTTPS (except local IPs) +- Max refresh rate: 30 minutes (iOS limit) +- Add multiple widgets for multiple servers + +## Android Widget + +### Setup + +1. Long press home screen → **Widgets** +2. Find "ServerBox" → Add to home screen +3. Note the widget ID number displayed +4. Open ServerBox app → Settings +5. Tap **Config home widget link** +6. Add entry: `Widget ID` = `Status URL` + +Example: +- Key: `17` +- Value: `https://my-server.com/status` + +7. Tap widget on home screen to refresh + +## watchOS Widget + +### Setup + +1. Open iPhone app → Settings +2. **iOS Settings** → **Watch app** +3. Tap **Add URL** +4. Enter URL ending with `/status` +5. Wait for watch app to sync + +### Notes + +- Try restarting watch app if not updating +- Verify phone and watch are connected + + +## Troubleshooting + +### Widget Not Updating + +**iOS:** Wait up to 30 minutes, then remove and re-add +**Android:** Tap widget to force refresh, verify ID in settings +**watchOS:** Restart watch app, wait a few minutes + +### Widget Shows Error + +- Verify ServerBox Monitor is running +- Test URL in browser +- Check URL ends with `/status` + +## Security + +- **Always use HTTPS** when possible +- **Local IPs only** on trusted networks diff --git a/docs/src/content/docs/configuration/appearance.md b/docs/src/content/docs/configuration/appearance.md new file mode 100644 index 00000000..847e5748 --- /dev/null +++ b/docs/src/content/docs/configuration/appearance.md @@ -0,0 +1,124 @@ +--- +title: Appearance +description: Customize the look and feel +--- + +Flutter Server Box offers extensive appearance customization. + +## Themes + +### Light Theme + +Clean, bright interface for daytime use. + +### Dark Theme + +Easy on the eyes for low-light environments. + +### AMOLED Dark + +Pure black background for OLED screens, saves battery. + +### System Theme + +Automatically switches between light and dark based on system settings. + +Set in: **Settings > Appearance > Theme** + +## Terminal Appearance + +### Customization Options + +- **Font Size**: Adjust text size in terminal +- **Font Family**: Choose from available fonts +- **Text Color**: Customize text color +- **Background Color**: Set terminal background +- **Background Opacity**: Adjust transparency +- **Blur Effect**: Enable background blur + +### Terminal Themes + +Create terminal color themes: + +1. Go to Settings > Terminal > Themes +2. Create new theme or edit existing +3. Customize colors: + - Text color + - Background color + - Cursor color + - Selection color + +## Server Cards + +### Card Style + +- **Compact**: Minimal information per card +- **Detailed**: Extended information per card +- **Custom**: Choose which metrics to show + +### Card Order + +1. Go to Settings > Server Card Order +2. Drag cards to reorder +3. Changes apply immediately + +### Card Metrics + +Enable/disable metrics: +- CPU +- Memory +- Disk +- Network +- GPU +- Temperature + +## Charts and Graphs + +### Chart Style + +- **Line**: Continuous line chart +- **Area**: Filled area chart +- **Bar**: Bar chart visualization + +### Chart Colors + +Customize chart colors in: +**Settings > Charts > Colors** + +### Refresh Rate + +Adjust how often charts update: +**Settings > Charts > Refresh Rate** + +- **Power Saving**: 5 seconds +- **Normal**: 2 seconds +- **High Performance**: 1 second + +## Layout + +### Navigation Style + +- **Bottom Navigation**: Mobile-style bottom tabs +- **Side Navigation**: Desktop-style sidebar +- **Tabs**: Classic tab interface + +### View Mode + +- **List**: Vertical list view +- **Grid**: Grid layout for servers +- **Cards**: Card-based layout + +## Icons and Symbols + +Choose icon style: +- **Filled**: Solid icons +- **Outlined**: Line icons +- **Rounded**: Soft, rounded icons + +## Animations + +Control animation speed: +- **Off**: No animations +- **Reduced**: Minimal animations +- **Normal**: Standard animations +- **Enhanced**: Extra animations diff --git a/docs/src/content/docs/configuration/backup.md b/docs/src/content/docs/configuration/backup.md new file mode 100644 index 00000000..825a9d15 --- /dev/null +++ b/docs/src/content/docs/configuration/backup.md @@ -0,0 +1,80 @@ +--- +title: Backup & Restore +description: Backup and restore your app data +--- + +Protect your server configurations and settings with built-in backup functionality. + +## What Gets Backed Up + +- **Server Configurations**: All saved servers +- **SSH Keys**: Imported private keys (encrypted) +- **Snippets**: Saved command snippets +- **Settings**: App preferences + +**Not included:** Passwords (for security) + +## Creating Backups + +### Manual Backup + +1. Settings → Backup +2. Tap **Create Backup** +3. Choose location +4. Backup saved with timestamp + +### Auto Backup + +Settings → Backup → Auto Backup: +- Daily / Weekly / Monthly / Off + +### Cloud Sync + +- **iOS/macOS**: iCloud automatic backup +- **Android**: Google Drive integration + +## Restoring + +### From Local Backup + +1. Settings → Backup → Restore Backup +2. Select backup file +3. Authenticate (biometric/password) +4. Confirm restore + +### From Cloud + +1. Sign in to same cloud account +2. Settings → Backup → Restore from Cloud +3. Select backup from list +4. Authenticate and confirm + +## Important Notes + +### Passwords Not Backed Up + +After restore, you'll need to re-enter passwords for each server. + +**Tip:** Use SSH keys instead - they ARE backed up. + +### Cross-Platform + +Backups work across all platforms (iOS ↔ Android ↔ Desktop). + +## Best Practices + +1. **Enable auto backup** for peace of mind +2. **Test restore** periodically to verify backups work +3. **Backup before** updating app or switching devices +4. **Use SSH keys** to avoid re-entering passwords + +## Troubleshooting + +**Restore failed:** +- Check backup file integrity +- Ensure sufficient storage +- Verify app version compatibility + +**Missing data after restore:** +- Passwords are not backed up (re-enter them) +- Check selective restore settings diff --git a/docs/src/content/docs/configuration/jump-server.md b/docs/src/content/docs/configuration/jump-server.md new file mode 100644 index 00000000..655f0a75 --- /dev/null +++ b/docs/src/content/docs/configuration/jump-server.md @@ -0,0 +1,88 @@ +--- +title: Jump Server +description: Route connections through intermediate servers +--- + +Connect to servers behind firewalls or in private networks by routing through an intermediate jump server. + +## What is Jump Server? + +A jump server acts as a gateway to access other servers that: +- Are behind firewalls +- Don't have direct SSH access +- Are in private networks +- Require multi-hop connections + +## Setup + +### Step 1: Configure Jump Server + +Add the jump server as a normal server first: +1. Add server with SSH credentials +2. Test connection to ensure it works +3. This server will be your jump host + +### Step 2: Configure Target Servers + +For each server you want to access via jump: +1. Add target server (credentials for target, not jump) +2. Server settings → Jump Server +3. Select your jump server from list +4. Save + +### Step 3: Connect + +Connect to target server normally. The app automatically: +1. Connects to jump server +2. Tunnels through to target server +3. Maintains connection + +## Use Cases + +### Private Network Access + +``` +Your Device → Jump Server (public IP) → Private Server (10.0.0.x) +``` + +### Behind Firewall + +``` +Your Device → Bastion Host → Internal Server +``` + +### Multi-Hop + +You can chain multiple jump servers for complex networks. + +## Requirements + +- Jump server must be accessible from your device +- Jump server must be able to reach target servers +- SSH keys recommended for jump server (faster authentication) + +## Tips + +- **Use SSH keys** on jump server for faster connections +- **Test direct access** to jump server first +- **Check firewall rules** on both ends +- **Monitor connection** - issues could be on jump or target + +## Troubleshooting + +### Connection Times Out + +- Verify jump server is accessible +- Check jump server can reach target +- Test manually: `ssh -J jump@jump-server user@target-server` + +### Authentication Fails + +- Verify credentials for target server (not jump) +- Check SSH keys if using key authentication + +### Slow Connection + +- Normal for jump connections (extra hop) +- Consider using SSH keys for faster auth +- Check network latency to jump server diff --git a/docs/src/content/docs/configuration/localizations.md b/docs/src/content/docs/configuration/localizations.md new file mode 100644 index 00000000..80d6f8bb --- /dev/null +++ b/docs/src/content/docs/configuration/localizations.md @@ -0,0 +1,93 @@ +--- +title: Localizations +description: Language and region settings +--- + +Flutter Server Box supports 12+ languages with full localization. + +## Supported Languages + +| Language | Status | +|----------|--------| +| English (en) | ✅ Native | +| 简体中文 (zh) | ✅ Native | +| 繁體中文 (zh-Hant) | ✅ Native | +| Deutsch (de) | ✅ Native | +| Français (fr) | ✅ Native | +| Español (es) | ✅ Native | +| Português (pt) | ✅ Native | +| Русский (ru) | ✅ Native | +| Türkçe (tr) | ✅ Native | +| Українська (uk) | ✅ Native | +| Bahasa Indonesia (id) | ✅ Native | +| Nederlands (nl) | ✅ Native | +| 日本語 (ja) | ✅ AI-translated | + +## Changing Language + +1. Go to **Settings > Language** +2. Select preferred language +3. App restarts to apply changes + +## Number Formatting + +Numbers are formatted according to locale: + +- **Thousands separator**: Comma vs period +- **Decimal separator**: Period vs comma +- **Date format**: Locale-specific + +## Time Format + +Choose between: + +- **24-hour**: 13:00, 14:30 +- **12-hour**: 1:00 PM, 2:30 PM + +Set in: **Settings > Time Format** + +## Contributing Translations + +We welcome community translations! + +### Translation Files + +Located in `lib/l10n/`: + +- `app_en.arb` - English (reference) +- `app_zh.arb` - Simplified Chinese +- etc. + +### How to Contribute + +1. Fork the repository +2. Copy `app_en.arb` to `app_YOUR_LOCALE.arb` +3. Translate values (keep keys the same) +4. Test your translations +5. Submit pull request + +### Translation Guidelines + +- Keep technical terms consistent +- Use formal address for professional tone +- Maintain placeholder format: `{variable}` +- Test UI with translated strings + +## Adding New Language + +1. Create new ARB file: `app_xx.arb` +2. Copy all keys from `app_en.arb` +3. Translate all values +4. Add to `l10n.yaml` configuration +5. Run `flutter gen-l10n` +6. Test with new locale + +## RTL Languages + +Right-to-left languages (Arabic, Hebrew) are partially supported. Full RTL layout support is planned for future releases. + +## Quality Notes + +- Some languages are AI-translated and may contain errors +- Native speaker reviews are appreciated +- Report translation issues via GitHub diff --git a/docs/src/content/docs/configuration/server.md b/docs/src/content/docs/configuration/server.md new file mode 100644 index 00000000..c3755295 --- /dev/null +++ b/docs/src/content/docs/configuration/server.md @@ -0,0 +1,90 @@ +--- +title: Server Setup +description: Configure and manage server connections +--- + +## Adding a Server + +1. Tap the **+** button on the main screen +2. Fill in connection details: + - **Name**: Friendly name for identification + - **Host**: IP address or domain name + - **Port**: SSH port (default: 22) + - **Username**: SSH login user + - **Authentication**: Password or SSH key + +3. Configure optional settings: + - **Initial Directory**: Starting directory for terminal/SFTP + - **Environment**: Custom environment variables + - **Keep-alive Interval**: Connection keep-alive setting + +4. Tap **Save** + +## Connection Types + +### Password Authentication + +Simple username/password authentication: + +- Enter password in the password field +- Password is stored securely (encrypted) +- Requires re-entry on app restart (unless saved) + +### SSH Key Authentication + +More secure, passwordless authentication: + +1. Generate or import SSH key +2. Add key to server's `~/.ssh/authorized_keys` +3. Select key in app when adding server + +See [SSH Keys](/configuration/ssh-keys/) for detailed setup. + +## Server Groups + +Organize servers into groups for easier management: + +1. Go to Settings > Server Groups +2. Create a new group +3. Assign servers to groups +4. Groups appear as sections in main view + +## Server Cards + +Customize what information appears on server cards: + +1. Go to Settings > Server Card Settings +2. Enable/disable metrics: + - CPU + - Memory + - Disk + - Network +3. Reorder cards by dragging + +## Connection Profiles + +Save connection profiles for different use cases: + +- **Default Profile**: Standard settings +- **Low Bandwidth**: Reduced refresh rate +- **High Performance**: Maximum refresh rate + +## Troubleshooting + +### Connection Refused + +- Check server is running +- Verify SSH port +- Check firewall rules + +### Authentication Failed + +- Verify username/password +- Check SSH key permissions +- Ensure SSH service is running + +### Timeout + +- Check network connectivity +- Increase timeout in settings +- Try different network diff --git a/docs/src/content/docs/configuration/sftp.md b/docs/src/content/docs/configuration/sftp.md new file mode 100644 index 00000000..5ef7a848 --- /dev/null +++ b/docs/src/content/docs/configuration/sftp.md @@ -0,0 +1,118 @@ +--- +title: SFTP File Browser +description: File transfer and management via SFTP +--- + +Browse, edit, and transfer files on your servers with a built-in SFTP client. + +## Basic Usage + +### Opening SFTP + +1. Connect to server +2. Tap **Files** button on server page +3. Or from terminal: Tap **SFTP** button + +### Navigation + +- **Tap folder**: Enter directory +- **Tap file**: View/Edit/Download options +- **Back button**: Previous directory +- **Home button**: User's home directory +- **Goto button**: Jump to path with autocomplete + +## File Operations + +### Common Actions + +| Action | How | +|--------|-----| +| **Download** | Long-press file → Download | +| **Upload** | Folder icon → Select file | +| **Rename** | Long-press → Rename | +| **Delete** | Long-press → Delete | +| **Copy/Move** | Long-press → Select → Choose destination | +| **Permissions** | Tap file info → Edit permissions | + +### Permission Editor + +Unix permissions editor: + +- **3x3 Grid**: User/Group/Other × Read/Write/Execute +- **Numeric**: Direct input (755, 644, etc.) +- **Symbolic**: rwxr-xr-x format + +### Edit Files + +1. Tap file → Edit +2. Edit in built-in editor +3. Save → Upload back to server + +**Size limit:** Files up to 1 MB. For larger files, use the terminal with vim/nano instead. + +**Editor settings:** Settings → SFTP Editor +- Preferred editor (vim, nano, etc.) +- Close after save +- Soft wrap +- Syntax highlighting + +## Display Settings + +### Sort Order + +Settings → Sort By: +- Name (alphabetical) +- Size (largest first) +- Time (newest first) + +### Folders First + +Show directories before files: +Settings → Folders First + +### Hidden Files + +Show dotfiles (`.git`, `.bashrc`, etc.): +Settings → Show Hidden Files + +## Archive Support + +Extract common archive formats directly on your server. + +| Format | Variants | Command Required | +|--------|----------|------------------| +| .tar.gz | .tgz, .tar.Z | tar | +| .tar.bz2 | .tbz2, .tar.bz2 | tar | +| .tar.xz | .txz | tar | +| .zip | .zipx | unzip | +| .7z | - | 7z | +| .rar | - | unrar | + +**Note:** The corresponding command (`tar`, `unzip`, `7z`, `unrar`) must be installed on your server. These tools handle many sub-formats not listed above. + +## Quick Access + +### From Terminal + +Tap **SFTP** button to open current terminal directory in file browser. + +### Remember Last Path + +Automatically return to last visited directory: +Settings → SFTP Open Last Path + +## Troubleshooting + +### Permission Denied + +- Check user has read access to directory +- Verify directory permissions: `ls -la` +- Ensure SFTP is enabled in sshd_config + +### Slow Listing + +Large directories (1000+ items) use pagination for performance. + +### Can't Edit File + +File larger than 1 MB? Use terminal with vim/nano instead. diff --git a/docs/src/content/docs/configuration/terminal.md b/docs/src/content/docs/configuration/terminal.md new file mode 100644 index 00000000..d784f3a1 --- /dev/null +++ b/docs/src/content/docs/configuration/terminal.md @@ -0,0 +1,127 @@ +--- +title: Terminal & SSH +description: SSH terminal setup and configuration +--- + +Complete SSH terminal access with full keyboard support and customizable interface. + +## Basic Setup + +### First Connection + +1. Add server with SSH credentials +2. Tap server card to connect +3. Accept host key fingerprint (first time only) +4. Terminal opens automatically + +### Virtual Keyboard (Mobile) + +Customizable virtual keyboard for terminal access: + +| Button | Function | +|--------|----------| +| **Ctrl, Alt, Shift** | Modifier keys (tap before other key) | +| **Esc, Tab** | Special characters | +| **Arrows** | Navigation | +| **F1-F12** | Function keys | +| **SFTP** | Open current directory in file browser | +| **Clipboard** | Copy selection / Paste clipboard | +| **Snippets** | Quick command execution | + +**Customize keyboard:** Settings → SSH Virtual Keys +- Enable/disable keys +- Reorder layout +- Add/remove buttons + +## Terminal Settings + +### Appearance + +**Font Size:** Settings → Terminal Font Size +- Affects all new sessions +- Typical range: 8-24 pixels + +**Colors:** Settings → Terminal Color +- Text color +- Background color & opacity +- Blur effect (iOS/macOS) +- Cursor color + +### Keyboard Type + +If you can't input certain characters: + +1. Settings → Keyboard Type +2. Switch to `visiblePassword` +3. Note: CJK input may not work after this change + +## Connection Management + +### Multi-Tab + +- **Desktop**: Ctrl+T (new), Ctrl+W (close) +- **Mobile**: Tap + button +- Sessions persist between app launches + +### Auto-Connect + +Set server to auto-connect on app open: +1. Server settings → Auto-Connect +2. Enable toggle + +### Jump Server + +Route through intermediate server: + +1. Add and configure jump server first +2. Target server settings → Select jump server +3. Connection routes through jump server automatically + +## SSH Keys (Recommended) + +More secure than passwords: + +1. Generate key: Settings → Private Keys → Add +2. Upload public key to server: `ssh-copy-id -i pubkey user@server` +3. Server settings → Use key instead of password + +## Common Issues + +### Can't Connect + +**Timeout/Refused:** +- Verify server is Unix-like (Linux, macOS, Android/Termux) +- Check firewall allows SSH port (default 22) +- Test manually: `ssh user@server -p port` + +**Auth Failed:** +- Verify username and password +- Check SSH key is uploaded correctly +- Ensure account is not locked + +### Terminal Disconnects + +**Frequent disconnections:** + +1. Check server keep-alive settings: + ```bash + # /etc/ssh/sshd_config + ClientAliveInterval 60 + ClientAliveCountMax 3 + ``` + +2. Disable battery optimization: + - **MIUI**: Battery → "No limits" + - **Android**: Settings → Apps → Disable optimization + - **iOS**: Enable background refresh + +### Can't Input Characters + +Change keyboard type to `visiblePassword` in settings. + +## Tips + +- **Test connection** first with regular SSH client +- **Use SSH keys** instead of passwords for security +- **Save snippets** for frequently used commands +- **Pinch to zoom** for temporary font size change (mobile) diff --git a/docs/src/content/docs/development/architecture.md b/docs/src/content/docs/development/architecture.md new file mode 100644 index 00000000..475395a7 --- /dev/null +++ b/docs/src/content/docs/development/architecture.md @@ -0,0 +1,86 @@ +--- +title: Architecture +description: Architecture patterns and design decisions +--- + +Flutter Server Box follows clean architecture principles with clear separation between data, domain, and presentation layers. + +## Layered Architecture + +``` +┌─────────────────────────────────────┐ +│ Presentation Layer │ +│ (lib/view/page/) │ +│ - Pages, Widgets, Controllers │ +└─────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────┐ +│ Business Logic Layer │ +│ (lib/data/provider/) │ +│ - Riverpod Providers │ +│ - State Management │ +└─────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────┐ +│ Data Layer │ +│ (lib/data/model/, store/) │ +│ - Models, Storage, Services │ +└─────────────────────────────────────┘ +``` + +## Key Patterns + +### State Management: Riverpod + +- **Code Generation**: Uses `riverpod_generator` for type-safe providers +- **State Notifiers**: For mutable state with business logic +- **Async Notifiers**: For loading and error states +- **Stream Providers**: For real-time data + +### Immutable Models: Freezed + +- All data models use Freezed for immutability +- Union types for state representation +- Built-in JSON serialization +- CopyWith extensions for updates + +### Local Storage: Hive + +- **hive_ce**: Community edition of Hive +- No manual `@HiveField` or `@HiveType` needed +- Type adapters auto-generated +- Persistent key-value storage + +## Dependency Injection + +Services and stores are injected via: + +1. **Providers**: Expose dependencies to UI +2. **GetIt**: Service location (where applicable) +3. **Constructor Injection**: Explicit dependencies + +## Data Flow + +``` +User Action → Widget → Provider → Service/Store → Model Update → UI Rebuild +``` + +1. User interacts with widget +2. Widget calls provider method +3. Provider updates state via service/store +3. State change triggers UI rebuild +4. New state reflected in widget + +## Custom Dependencies + +The project uses several custom forks to extend functionality: + +- **dartssh2**: Enhanced SSH features +- **xterm**: Terminal emulator with mobile support +- **fl_lib**: Shared UI components and utilities + +## Threading + +- **Isolates**: Heavy computation off main thread +- **computer package**: Multi-threading utilities +- **Async/Await**: Non-blocking I/O operations diff --git a/docs/src/content/docs/development/building.md b/docs/src/content/docs/development/building.md new file mode 100644 index 00000000..cf989c38 --- /dev/null +++ b/docs/src/content/docs/development/building.md @@ -0,0 +1,116 @@ +--- +title: Building +description: Build instructions for different platforms +--- + +Flutter Server Box uses a custom build system (`fl_build`) for cross-platform builds. + +## Prerequisites + +- Flutter SDK (stable channel) +- Platform-specific tools (Xcode for iOS, Android Studio for Android) +- Rust toolchain (for some native dependencies) + +## Development Build + +```bash +# Run in development mode +flutter run + +# Run on specific device +flutter run -d +``` + +## Production Build + +The project uses `fl_build` for building: + +```bash +# Build for specific platform +dart run fl_build -p + +# Available platforms: +# - ios +# - android +# - macos +# - linux +# - windows +``` + +## Platform-Specific Builds + +### iOS + +```bash +dart run fl_build -p ios +``` + +Requires: +- macOS with Xcode +- CocoaPods +- Apple Developer account for signing + +### Android + +```bash +dart run fl_build -p android +``` + +Requires: +- Android SDK +- Java Development Kit +- Keystore for signing + +### macOS + +```bash +dart run fl_build -p macos +``` + +### Linux + +```bash +dart run fl_build -p linux +``` + +### Windows + +```bash +dart run fl_build -p windows +``` + +Requires Windows with Visual Studio. + +## Pre/Post Build + +The `make.dart` script handles: + +- Metadata generation +- Version string updates +- Platform-specific configurations + +## Troubleshooting + +### Clean Build + +```bash +flutter clean +dart run build_runner build --delete-conflicting-outputs +flutter pub get +``` + +### Version Mismatch + +Ensure all dependencies are compatible: +```bash +flutter pub upgrade +``` + +## Release Checklist + +1. Update version in `pubspec.yaml` +2. Run code generation +3. Run tests +4. Build for all target platforms +5. Test on physical devices +6. Create GitHub release diff --git a/docs/src/content/docs/development/codegen.md b/docs/src/content/docs/development/codegen.md new file mode 100644 index 00000000..67bce6eb --- /dev/null +++ b/docs/src/content/docs/development/codegen.md @@ -0,0 +1,98 @@ +--- +title: Code Generation +description: Using build_runner for code generation +--- + +Flutter Server Box heavily uses code generation for models, state management, and serialization. + +## When to Run Code Generation + +Run after modifying: + +- Models with `@freezed` annotation +- Classes with `@JsonSerializable` +- Hive models +- Providers with `@riverpod` +- Localizations (ARB files) + +## Running Code Generation + +```bash +# Generate all code +dart run build_runner build --delete-conflicting-outputs + +# Clean and regenerate +dart run build_runner build --delete-conflicting-outputs --clean +``` + +## Generated Files + +### Freezed (`*.freezed.dart`) + +Immutable data models with union types: + +```dart +@freezed +class ServerState with _$ServerState { + const factory ServerState.connected() = Connected; + const factory ServerState.disconnected() = Disconnected; + const factory ServerState.error(String message) = Error; +} +``` + +### JSON Serialization (`*.g.dart`) + +Generated from `json_serializable`: + +```dart +@JsonSerializable() +class Server { + final String id; + final String name; + final String host; + + Server({required this.id, required this.name, required this.host}); + + factory Server.fromJson(Map json) => + _$ServerFromJson(json); + Map toJson() => _$ServerToJson(this); +} +``` + +### Riverpod Providers (`*.g.dart`) + +Generated from `@riverpod` annotation: + +```dart +@riverpod +class MyNotifier extends _$MyNotifier { + @override + int build() => 0; +} +``` + +### Hive Adapters (`*.g.dart`) + +Auto-generated for Hive models (hive_ce): + +```dart +@HiveType(typeId: 0) +class ServerModel { + @HiveField(0) + final String id; +} +``` + +## Localization Generation + +```bash +flutter gen-l10n +``` + +Generates `lib/generated/l10n/` from `lib/l10n/*.arb` files. + +## Tips + +- Use `--delete-conflicting-outputs` to avoid conflicts +- Add generated files to `.gitignore` +- Never manually edit generated files diff --git a/docs/src/content/docs/development/state.md b/docs/src/content/docs/development/state.md new file mode 100644 index 00000000..8d85fbe9 --- /dev/null +++ b/docs/src/content/docs/development/state.md @@ -0,0 +1,115 @@ +--- +title: State Management +description: Riverpod-based state management patterns +--- + +Flutter Server Box uses Riverpod with code generation for state management. + +## Provider Types + +### StateProvider + +Simple state that can be read and written: + +```dart +@riverpod +class Settings extends _$Settings { + @override + SettingsModel build() { + return SettingsModel.defaults(); + } + + void update(SettingsModel newSettings) { + state = newSettings; + } +} +``` + +### AsyncNotifierProvider + +State that loads asynchronously with loading/error states: + +```dart +@riverpod +class ServerStatus extends _$ServerStatus { + @override + Future build(Server server) async { + return fetchStatus(server); + } + + Future refresh() async { + state = const AsyncValue.loading(); + state = await AsyncValue.guard(() => fetchStatus(server)); + } +} +``` + +### StreamProvider + +Real-time data from streams: + +```dart +@riverpod +Stream cpuUsage(CpuUsageRef ref, Server server) { + return cpuService.monitor(server); +} +``` + +## State Patterns + +### Loading States + +```dart +state.when( + data: (data) => DataWidget(data), + loading: () => LoadingWidget(), + error: (error, stack) => ErrorWidget(error), +) +``` + +### Family Providers + +Parameterized providers: + +```dart +@riverpod +List containers(ContainersRef ref, Server server) { + return containerService.list(server); +} +``` + +### Auto-Dispose + +Providers that dispose when no longer referenced: + +```dart +@Riverpod(keepAlive: false) +class TempState extends _$TempState { + // ... +} +``` + +## Best Practices + +1. **Use code generation**: Always use `@riverpod` annotation +2. **Co-locate providers**: Place near consuming widgets +3. **Avoid singletons**: Use providers instead +4. **Layer correctly**: Keep UI logic separate from business logic + +## Reading State in Widgets + +```dart +class ServerWidget extends ConsumerWidget { + @override + Widget build(BuildContext context, WidgetRef ref) { + final status = ref.watch(serverStatusProvider(server)); + return status.when(...); + } +} +``` + +## Modifying State + +```dart +ref.read(settingsProvider.notifier).update(newSettings); +``` diff --git a/docs/src/content/docs/development/structure.md b/docs/src/content/docs/development/structure.md new file mode 100644 index 00000000..ec31caa9 --- /dev/null +++ b/docs/src/content/docs/development/structure.md @@ -0,0 +1,96 @@ +--- +title: Project Structure +description: Understanding the Flutter Server Box codebase +--- + +The Flutter Server Box project follows a modular architecture with clear separation of concerns. + +## Directory Structure + +``` +lib/ +├── core/ # Core utilities and extensions +├── data/ # Data layer +│ ├── model/ # Data models by feature +│ ├── provider/ # Riverpod providers +│ └── store/ # Local storage (Hive) +├── view/ # UI layer +│ ├── page/ # Main pages +│ └── widget/ # Reusable widgets +├── generated/ # Generated localization +├── l10n/ # Localization ARB files +└── hive/ # Hive adapters +``` + +## Core Layer (`lib/core/`) + +Contains utilities, extensions, and routing configuration: + +- **Extensions**: Dart extensions for common types +- **Routes**: App routing configuration +- **Utils**: Shared utility functions + +## Data Layer (`lib/data/`) + +### Models (`lib/data/model/`) + +Organized by feature: + +- `server/` - Server connection and status models +- `container/` - Docker container models +- `ssh/` - SSH session models +- `sftp/` - SFTP file models +- `app/` - App-specific models + +### Providers (`lib/data/provider/`) + +Riverpod providers for dependency injection and state management: + +- Server providers +- UI state providers +- Service providers + +### Stores (`lib/data/store/`) + +Hive-based local storage: + +- Server storage +- Settings storage +- Cache storage + +## View Layer (`lib/view/`) + +### Pages (`lib/view/page/`) + +Main application screens: + +- `server/` - Server management pages +- `ssh/` - SSH terminal pages +- `container/` - Container pages +- `setting/` - Settings pages +- `storage/` - SFTP pages +- `snippet/` - Snippet pages + +### Widgets (`lib/view/widget/`) + +Reusable UI components: + +- Server cards +- Status charts +- Input components +- Dialogs + +## Generated Files + +- `lib/generated/l10n/` - Auto-generated localization +- `*.g.dart` - Generated code (json_serializable, freezed, hive, riverpod) +- `*.freezed.dart` - Freezed immutable classes + +## Packages Directory (`/packages/`) + +Contains custom forks of dependencies: + +- `dartssh2/` - SSH library +- `xterm/` - Terminal emulator +- `fl_lib/` - Shared utilities +- `fl_build/` - Build system diff --git a/docs/src/content/docs/development/testing.md b/docs/src/content/docs/development/testing.md new file mode 100644 index 00000000..d19b5345 --- /dev/null +++ b/docs/src/content/docs/development/testing.md @@ -0,0 +1,113 @@ +--- +title: Testing +description: Testing strategies and running tests +--- + +## Running Tests + +```bash +# Run all tests +flutter test + +# Run specific test file +flutter test test/battery_test.dart + +# Run with coverage +flutter test --coverage +``` + +## Test Structure + +Tests are located in the `test/` directory mirroring the lib structure: + +``` +test/ +├── data/ +│ ├── model/ +│ └── provider/ +├── view/ +│ └── widget/ +└── test_helpers.dart +``` + +## Unit Tests + +Test business logic and data models: + +```dart +test('should calculate CPU percentage', () { + final cpu = CpuModel(usage: 75.0); + expect(cpu.usagePercentage, '75%'); +}); +``` + +## Widget Tests + +Test UI components: + +```dart +testWidgets('ServerCard displays server name', (tester) async { + await tester.pumpWidget( + ProviderScope( + child: MaterialApp( + home: ServerCard(server: testServer), + ), + ), + ); + + expect(find.text('Test Server'), findsOneWidget); +}); +``` + +## Provider Tests + +Test Riverpod providers: + +```dart +test('serverStatusProvider returns status', () async { + final container = ProviderContainer(); + final status = await container.read(serverStatusProvider(testServer).future); + expect(status, isA()); +}); +``` + +## Mocking + +Use mocks for external dependencies: + +```dart +class MockSshService extends Mock implements SshService {} + +test('connects to server', () async { + final mockSsh = MockSshService(); + when(mockSsh.connect(any)).thenAnswer((_) async => true); + + // Test with mock +}); +``` + +## Integration Tests + +Test complete user flows (in `integration_test/`): + +```dart +testWidgets('add server flow', (tester) async { + await tester.pumpWidget(MyApp()); + + // Tap add button + await tester.tap(find.byIcon(Icons.add)); + await tester.pumpAndSettle(); + + // Fill form + await tester.enterText(find.byKey(Key('name')), 'Test Server'); + // ... +}); +``` + +## Best Practices + +1. **Arrange-Act-Assert**: Structure tests clearly +2. **Descriptive names**: Test names should describe behavior +3. **One assertion per test**: Keep tests focused +4. **Mock external deps**: Don't depend on real servers +5. **Test edge cases**: Empty lists, null values, etc. diff --git a/docs/src/content/docs/features/docker.md b/docs/src/content/docs/features/docker.md new file mode 100644 index 00000000..a94c6b3a --- /dev/null +++ b/docs/src/content/docs/features/docker.md @@ -0,0 +1,55 @@ +--- +title: Docker Management +description: Monitor and manage Docker containers +--- + +Flutter Server Box provides an intuitive interface for managing Docker containers on your servers. + +## Features + +### Container List + +- View all containers (running and stopped) +- Container ID and name display +- Image information +- Status indicators +- Creation time + +### Container Actions + +- **Start**: Launch stopped containers +- **Stop**: Gracefully stop running containers +- **Restart**: Restart containers +- **Remove**: Delete containers +- **View Logs**: Check container logs +- **Inspect**: View container details + +### Container Details + +- Environment variables +- Port mappings +- Volume mounts +- Network configuration +- Resource usage + +## Requirements + +- Docker must be installed on your server +- SSH user must have Docker permissions +- For non-root users, add to docker group: + ```bash + sudo usermod -aG docker your_username + ``` + +## Quick Actions + +- Single tap: View container details +- Long press: Quick action menu +- Swipe: Quick start/stop +- Bulk select: Multiple container operations + +## Tips + +- Use **auto-refresh** to monitor container status changes +- Filter by running/stopped containers +- Search containers by name or ID diff --git a/docs/src/content/docs/features/monitoring.md b/docs/src/content/docs/features/monitoring.md new file mode 100644 index 00000000..fc60df56 --- /dev/null +++ b/docs/src/content/docs/features/monitoring.md @@ -0,0 +1,73 @@ +--- +title: Server Monitoring +description: Real-time server status monitoring with beautiful charts +--- + +Flutter Server Box provides comprehensive real-time monitoring of your server's health and performance. + +## Status Cards + +The server detail page displays configurable status cards for different system metrics. You can enable/disable cards in settings. + +### CPU Monitoring + +- Real-time CPU usage percentage +- Per-core CPU usage breakdown +- Historical usage charts +- CPU frequency information + +### Memory Monitoring + +- **RAM Usage**: Used vs total memory with percentage +- **Swap Usage**: Swap memory utilization +- Memory pressure indicators +- Historical memory trends + +### Disk Monitoring + +- Mount point usage with percentage +- Total, used, and free space +- I/O statistics +- Multiple disk support + +### Network Monitoring + +- Real-time upload/download speeds +- Bandwidth usage charts +- Network interface statistics +- Total data transferred + +### Advanced Metrics + +- **GPU Status**: NVIDIA and AMD GPU monitoring +- **Temperature**: CPU, GPU, and system temperatures +- **Sensors**: Fan speeds, voltages, and other sensor data +- **S.M.A.R.T**: Disk health monitoring +- **Battery**: UPS or battery status (if available) + +## Customizing Display + +### Reordering Cards + +1. Go to Settings +2. Select Server Settings +3. Drag cards to reorder them on the server detail page + +### Enabling/Disabling Cards + +1. Open a server's detail page +2. Tap the edit/menu button +3. Toggle individual cards on or off + +## Auto-Refresh + +- Status cards automatically refresh +- Refresh interval is configurable in settings +- Manual refresh available with pull-to-refresh gesture + +## Charts and Visualizations + +- **Line Charts**: Historical data trends +- **Gauge Charts**: Current usage percentage +- **Color Coding**: Visual indicators for status levels +- **Zoom**: Pinch to zoom on charts for detailed views diff --git a/docs/src/content/docs/features/network.md b/docs/src/content/docs/features/network.md new file mode 100644 index 00000000..ee023f4e --- /dev/null +++ b/docs/src/content/docs/features/network.md @@ -0,0 +1,67 @@ +--- +title: Network Tools +description: Network testing and diagnostic tools +--- + +Flutter Server Box includes several network tools for testing and diagnostics. + +## iPerf + +Perform network speed tests between your device and server. + +### Features + +- **Upload/Download Speed**: Test bandwidth +- **Server Mode**: Use server as iPerf server +- **Client Mode**: Connect to iPerf servers +- **Custom Parameters**: Duration, parallel streams, etc. + +### Usage + +1. Open a server +2. Tap **iPerf** +3. Choose server or client mode +4. Configure parameters +5. Start test + +## Ping + +Test network connectivity and latency. + +### Features + +- **ICMP Ping**: Standard ping tool +- **Packet Count**: Specify number of packets +- **Packet Size**: Custom packet size +- **Interval**: Time between pings + +### Usage + +1. Open a server +2. Tap **Ping** +3. Enter target host +4. Configure parameters +5. Start pinging + +## Wake on LAN + +Wake up remote servers via magic packet. + +### Features + +- **MAC Address**: Target device MAC +- **Broadcast**: Send broadcast magic packet +- **Saved Profiles**: Store WoL configurations + +### Requirements + +- Target device must support Wake-on-LAN +- WoL must be enabled in BIOS/UEFI +- Device must be in sleep/soft-off state +- Device must be on the same network or reachable via broadcast + +## Tips + +- Use iPerf to diagnose network bottlenecks +- Ping multiple hosts to compare latency +- Save WoL profiles for frequently woken devices diff --git a/docs/src/content/docs/features/process.md b/docs/src/content/docs/features/process.md new file mode 100644 index 00000000..99334f59 --- /dev/null +++ b/docs/src/content/docs/features/process.md @@ -0,0 +1,56 @@ +--- +title: Process & Services +description: Monitor processes and manage systemd services +--- + +## Process Management + +View and manage running processes on your servers. + +### Process List + +- All running processes with details +- PID (Process ID) +- CPU and memory usage +- User ownership +- Process command + +### Process Actions + +- **Kill**: Terminate processes +- **Filter**: By name or user +- **Sort**: By CPU, memory, or PID +- **Search**: Find specific processes + +## Systemd Services + +Manage systemd services for service control. + +### Service List + +- All systemd services +- Active/inactive status +- Enabled/disabled state +- Service description + +### Service Actions + +- **Start**: Launch a stopped service +- **Stop**: Stop a running service +- **Restart**: Restart a service +- **Enable**: Enable auto-start on boot +- **Disable**: Disable auto-start +- **View Status**: Check service status and logs +- **Reload**: Reload service configuration + +## Requirements + +- SSH user must have appropriate permissions +- For service management: `sudo` access may be required +- Process viewing: Standard user permissions usually sufficient + +## Tips + +- Use process list to identify resource hogs +- Check service logs for troubleshooting +- Monitor critical services with auto-refresh diff --git a/docs/src/content/docs/features/pve.md b/docs/src/content/docs/features/pve.md new file mode 100644 index 00000000..f3672e71 --- /dev/null +++ b/docs/src/content/docs/features/pve.md @@ -0,0 +1,105 @@ +--- +title: Proxmox (PVE) +description: Proxmox Virtual Environment management +--- + +Flutter Server Box includes support for managing Proxmox VE virtualization platform. + +## Features + +### VM Management + +- **List VMs**: View all virtual machines +- **VM Status**: Check running/stopped states +- **VM Actions**: Start, stop, restart VMs +- **VM Details**: View configuration and resources + +### Container (LXC) Management + +- **List Containers**: View all LXC containers +- **Container Status**: Monitor container states +- **Container Actions**: Start, stop, restart containers +- **Console Access**: Terminal access to containers + +### Node Monitoring + +- **Resource Usage**: CPU, memory, disk, network +- **Node Status**: Check node health +- **Cluster View**: Multi-node cluster overview + +## Setup + +### Adding PVE Server + +1. Add server as normal SSH connection +2. Ensure user has PVE permissions +3. Access PVE features from server detail page + +### Permissions Required + +PVE user needs: + +- **VM.Audit**: View VM status +- **VM.PowerMgmt**: Start/stop VMs +- **VM.Console**: Console access + +Example permissions setup: + +```bash +pveum useradd myuser -password mypass +pveum aclmod /vms -user myuser@pve -role VMAdmin +``` + +## Usage + +### VM Management + +1. Open server with PVE +2. Tap **PVE** button +3. View VM list +4. Tap VM for details +5. Use action buttons for management + +### Container Management + +1. Open server with PVE +2. Tap **PVE** button +3. Switch to Containers tab +4. View and manage LXC containers + +### Monitoring + +- Real-time resource usage +- Historical data charts +- Multiple node support + +## Features by Status + +### Implemented + +- VM listing and status +- Container listing and status +- Basic VM operations (start/stop/restart) +- Resource monitoring + +### Planned + +- VM creation from templates +- Snapshot management +- Console access +- Storage management +- Network configuration + +## Requirements + +- **PVE Version**: 6.x or 7.x +- **Access**: SSH access to PVE host +- **Permissions**: Appropriate PVE user roles +- **Network**: Connectivity to PVE API (via SSH) + +## Tips + +- Use **dedicated PVE user** with limited permissions +- Monitor **resource usage** for optimal performance +- Check **VM status** before maintenance +- Use **snapshots** before major changes diff --git a/docs/src/content/docs/features/snippets.md b/docs/src/content/docs/features/snippets.md new file mode 100644 index 00000000..cd8e2635 --- /dev/null +++ b/docs/src/content/docs/features/snippets.md @@ -0,0 +1,60 @@ +--- +title: Snippets +description: Save and execute custom shell commands +--- + +Snippets allow you to save frequently used shell commands for quick execution. + +## Creating Snippets + +1. Go to the **Snippets** tab +2. Tap the **+** button +3. Fill in snippet details: + - **Name**: Friendly name for the snippet + - **Command**: The shell command to execute + - **Description**: Optional notes +4. Save the snippet + +## Using Snippets + +1. Open a server +2. Tap the **Snippet** button +3. Select a snippet to execute +4. View output in the terminal + +## Snippet Features + +- **Quick Execute**: One-tap command execution +- **Variables**: Use server-specific variables +- **Organization**: Group related snippets +- **Import/Export**: Share snippets between devices +- **Sync**: Optional cloud sync + +## Example Snippets + +### System Update +```bash +sudo apt update && sudo apt upgrade -y +``` + +### Disk Cleanup +```bash +sudo apt autoremove -y && sudo apt clean +``` + +### Docker Cleanup +```bash +docker system prune -a +``` + +### View System Logs +```bash +journalctl -n 50 -f +``` + +## Tips + +- Use **descriptive names** for easy identification +- Add **comments** for complex commands +- Test commands before saving as snippets +- Organize snippets by category or server type diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx new file mode 100644 index 00000000..c0b7cbd7 --- /dev/null +++ b/docs/src/content/docs/index.mdx @@ -0,0 +1,46 @@ +--- +title: Flutter Server Box +description: A comprehensive cross-platform server management application +hero: + tagline: Manage your Linux servers from anywhere + actions: + - text: Get Started + link: /introduction/ + icon: right-arrow + variant: primary + - text: View on GitHub + link: https://github.com/lollipopkit/flutter_server_box + icon: github + variant: minimal +--- + +import { Card, CardGrid } from '@astrojs/starlight/components'; + +## Features + + + + Monitor CPU, memory, disk, network, GPU, and temperature with beautiful real-time charts. + + + Full-featured SSH terminal with multi-tab support and virtual keyboard for mobile devices. + + + Manage files on your servers with the built-in SFTP client and local file browser. + + + Start, stop, and monitor Docker containers with an intuitive interface. + + + Available on iOS, Android, macOS, Linux, Windows, and watchOS. + + + Full localization support including English, Chinese, German, French, and more. + + + +## Quick Links + +- **Download**: Available on [App Store](https://apps.apple.com/app/flutter-server-box), [Google Play](https://play.google.com/store/apps/details), [GitHub](https://github.com/lollipopkit/flutter_server_box/releases), and [F-Droid](https://f-droid.org/) +- **Documentation**: Explore the guides to get started with Flutter Server Box +- **Support**: Join our community on GitHub for discussions and issues diff --git a/docs/src/content/docs/installation.mdx b/docs/src/content/docs/installation.mdx new file mode 100644 index 00000000..5fa6944c --- /dev/null +++ b/docs/src/content/docs/installation.mdx @@ -0,0 +1,52 @@ +--- +title: Installation +description: Download and install Flutter Server Box on your device +--- + +Flutter Server Box is available on multiple platforms. Choose your preferred method of installation. + +## Mobile Apps + +### iOS + +Download from the **[App Store](https://apps.apple.com/app/flutter-server-box)**. + +### Android + +Choose your preferred source: + +- **[Google Play](https://play.google.com/store/apps/details)** - Recommended for most users +- **[F-Droid](https://f-droid.org/)** - For users who prefer FOSS-only sources +- **[GitHub Releases](https://github.com/lollipopkit/flutter_server_box/releases)** - For the latest version directly from the source + +## Desktop Apps + +### macOS + +Download from **[GitHub Releases](https://github.com/lollipopkit/flutter_server_box/releases)**. + +Features: +- Native menu bar integration +- Support for both Intel and Apple Silicon + +### Linux + +Download from **[GitHub Releases](https://github.com/lollipopkit/flutter_server_box/releases)**. + +Available as AppImage, deb, or tar.gz packages. + +### Windows + +Download from **[GitHub Releases](https://github.com/lollipopkit/flutter_server_box/releases)**. + +## watchOS + +Available on the **[App Store](https://apps.apple.com/app/flutter-server-box)** as part of the iOS app. + +## Building from Source + +To build Flutter Server Box from source, see the [Building](/development/building) section in the Development documentation. + +## Version Information + +Check the [GitHub Releases](https://github.com/lollipopkit/flutter_server_box/releases) page for the latest version and changelog. diff --git a/docs/src/content/docs/introduction.mdx b/docs/src/content/docs/introduction.mdx new file mode 100644 index 00000000..44325620 --- /dev/null +++ b/docs/src/content/docs/introduction.mdx @@ -0,0 +1,33 @@ +--- +title: Introduction +description: Learn what Flutter Server Box is and what it can do +--- + +Flutter Server Box is a comprehensive cross-platform server management application built with Flutter. It allows you to monitor, manage, and control your Linux, Unix, and Windows servers from anywhere. + +## What is Flutter Server Box? + +Flutter Server Box provides a unified interface for server administration tasks through SSH connections. Whether you're a system administrator, developer, or hobbyist running home servers, this app puts powerful server management tools in your pocket. + +## Key Capabilities + +- **Real-time Monitoring**: Track CPU, memory, disk usage, network speed, GPU status, and system temperatures +- **SSH Terminal**: Full terminal access with multi-tab support and customizable appearance +- **SFTP Client**: Browse and manage files on your servers +- **Docker Management**: Control containers with ease +- **Process Management**: View and manage system processes +- **Systemd Services**: Start, stop, and monitor systemd services +- **Network Tools**: iPerf testing, ping, and Wake-on-LAN +- **Snippets**: Save and execute custom shell commands + +## Supported Platforms + +Flutter Server Box is truly cross-platform: + +- **Mobile**: iOS and Android +- **Desktop**: macOS, Linux, and Windows +- **Wearable**: watchOS (Apple Watch) + +## License + +This project is licensed under AGPL v3. Source code is available on [GitHub](https://github.com/lollipopkit/flutter_server_box). diff --git a/docs/src/content/docs/platforms/desktop.md b/docs/src/content/docs/platforms/desktop.md new file mode 100644 index 00000000..baa418d0 --- /dev/null +++ b/docs/src/content/docs/platforms/desktop.md @@ -0,0 +1,80 @@ +--- +title: Desktop Features +description: macOS, Linux, and Windows specific features +--- + +Flutter Server Box on desktop platforms provides additional productivity features. + +## macOS + +### Menu Bar Integration + +- Quick server status in menu bar +- One-click server access +- Compact mode for minimal distraction +- Native macOS menu bar styling + +### Window State Persistence + +- Remembers window position and size +- Restore previous session on launch +- Multiple monitor support + +### Native Features + +- **Title Bar**: Custom or system title bar option +- **Full Screen Mode**: Dedicated server monitoring +- **Keyboard Shortcuts**: macOS-native shortcuts +- **Touch Bar** (supported devices): Quick actions + +## Linux + +### Native Integration + +- System tray support +- Desktop notification integration +- File picker integration + +### Window Management + +- X11 and Wayland support +- Tiling window manager friendly +- Custom window decorations option + +## Windows + +### Features + +- System tray integration +- Jump List quick actions +- Native window controls +- Auto-start on boot option + +## Cross-Platform Desktop Features + +### Keyboard Shortcuts + +- **Cmd/Ctrl + N**: New server +- **Cmd/Ctrl + W**: Close tab +- **Cmd/Ctrl + T**: New terminal tab +- **Cmd/Ctrl + ,**: Settings + +### Themes + +- Light theme +- Dark theme +- AMOLED theme (pure black) +- System theme (follows OS) + +### Multiple Windows + +- Open multiple servers in separate windows +- Drag tabs to new window +- Compare server stats side-by-side + +### Advantages Over Mobile + +- Larger screen for monitoring +- Full keyboard for terminal +- Faster file operations +- Better multitasking diff --git a/docs/src/content/docs/platforms/mobile.md b/docs/src/content/docs/platforms/mobile.md new file mode 100644 index 00000000..8e5a8547 --- /dev/null +++ b/docs/src/content/docs/platforms/mobile.md @@ -0,0 +1,77 @@ +--- +title: Mobile Features +description: iOS and Android specific features +--- + +Flutter Server Box provides several mobile-specific features for iOS and Android devices. + +## Biometric Authentication + +Secure your servers with biometric authentication: + +- **iOS**: Face ID or Touch ID +- **Android**: Fingerprint authentication + +Enable in Settings > Security > Biometric Authentication + +## Home Screen Widgets + +Add server status widgets to your home screen for quick monitoring. + +### iOS + +- Long press on home screen +- Tap **+** to add widget +- Search for "Flutter Server Box" +- Choose widget size: + - Small: Single server status + - Medium: Multiple servers + - Large: Detailed info + +### Android + +- Long press on home screen +- Tap **Widgets** +- Find "Flutter Server Box" +- Select widget type + +## Background Running + +### Android + +Keep connections alive in the background: + +- Enable in Settings > Advanced > Background Running +- Requires battery optimization exclusion +- Persistent notifications for active connections + +### iOS + +Background limitations apply: + +- Connections may pause in background +- Quick reconnect on return to app +- Background refresh support + +## Push Notifications + +Receive notifications for: + +- Server offline alerts +- High resource usage warnings +- Task completion alerts + +Configure in Settings > Notifications + +## Mobile UI Features + +- **Pull to Refresh**: Update server status +- **Swipe Actions**: Quick server operations +- **Landscape Mode**: Better terminal experience +- **Virtual Keyboard**: Terminal shortcuts + +## File Integration + +- **Files App (iOS)**: Direct SFTP access from Files +- **Storage Access Framework (Android)**: Share files with other apps +- **Document Picker**: Easy file selection diff --git a/docs/src/content/docs/platforms/watchos.md b/docs/src/content/docs/platforms/watchos.md new file mode 100644 index 00000000..4513912e --- /dev/null +++ b/docs/src/content/docs/platforms/watchos.md @@ -0,0 +1,55 @@ +--- +title: watchOS App +description: Apple Watch companion app +--- + +Flutter Server Box includes a companion app for Apple Watch, providing quick server monitoring on your wrist. + +## Features + +### Server Status at a Glance + +- View server online/offline status +- Quick CPU and memory stats +- One-tap server connectivity check + +### Complications + +Add server information to your watch face: + +- **Modular**: Server status icon +- **Infograph**: Small complication +- **Extra Large**: Large complication + +### Quick Actions + +- Ping servers +- Wake on LAN +- Quick terminal command + +## Requirements + +- Apple Watch Series 3 or later +- watchOS 8.0 or later +- Paired iPhone with Flutter Server Box installed +- iPhone and Watch on same Wi-Fi + +## Setup + +1. Install Flutter Server Box on iPhone +2. Open the Watch app on iPhone +3. Find Flutter Server Box under "Available Apps" +4. Toggle "Show App on Apple Watch" + +## Limitations + +- No full terminal access +- Reduced SFTP functionality +- Dependent on iPhone connection +- Simplified server management + +## Tips + +- Use complications for persistent status +- Quick actions for emergency checks +- Sync servers from iPhone app diff --git a/docs/src/content/docs/principles/architecture.md b/docs/src/content/docs/principles/architecture.md new file mode 100644 index 00000000..181398b8 --- /dev/null +++ b/docs/src/content/docs/principles/architecture.md @@ -0,0 +1,214 @@ +--- +title: Architecture Overview +description: High-level application architecture +--- + +Flutter Server Box follows a layered architecture with clear separation of concerns. + +## Architecture Layers + +``` +┌─────────────────────────────────────────────────┐ +│ Presentation Layer (UI) │ +│ lib/view/page/, lib/view/widget/ │ +│ - Pages, Widgets, Controllers │ +└─────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────┐ +│ Business Logic Layer │ +│ lib/data/provider/ │ +│ - Riverpod Providers, State Notifiers │ +└─────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────┐ +│ Data Access Layer │ +│ lib/data/store/, lib/data/model/ │ +│ - Hive Stores, Data Models │ +└─────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────┐ +│ External Integration Layer │ +│ - SSH (dartssh2), Terminal (xterm), SFTP │ +│ - Platform-specific code (iOS, Android, etc.) │ +└─────────────────────────────────────────────────┘ +``` + +## Application Foundation + +### Main Entry Point + +`lib/main.dart` initializes the app: + +```dart +void main() { + runApp( + ProviderScope( + child: MyApp(), + ), + ); +} +``` + +### Root Widget + +`MyApp` provides: +- **Theme Management**: Light/dark theme switching +- **Routing Configuration**: Navigation structure +- **Provider Scope**: Dependency injection root + +### Home Page + +`HomePage` serves as navigation hub: +- **Tabbed Interface**: Server, Snippet, Container, SSH +- **State Management**: Per-tab state +- **Navigation**: Feature access + +## Core Systems + +### State Management: Riverpod + +**Why Riverpod?** +- Compile-time safety +- Easy testing +- No Build context dependency +- Works across platforms + +**Provider Types Used:** +- `StateProvider`: Simple mutable state +- `AsyncNotifierProvider`: Loading/error/data states +- `StreamProvider`: Real-time data streams +- Future providers: One-time async operations + +### Data Persistence: Hive CE + +**Why Hive CE?** +- No native code dependencies +- Fast key-value storage +- Type-safe with code generation +- No manual field annotations needed + +**Stores:** +- `SettingStore`: App preferences +- `ServerStore`: Server configurations +- `SnippetStore`: Command snippets +- `KeyStore`: SSH keys + +### Immutable Models: Freezed + +**Benefits:** +- Compile-time immutability +- Union types for state +- Built-in JSON serialization +- CopyWith extensions + +## Cross-Platform Strategy + +### Plugin System + +Flutter plugins provide platform integration: + +| Platform | Integration Method | +|----------|-------------------| +| iOS | CocoaPods, Swift/Obj-C | +| Android | Gradle, Kotlin/Java | +| macOS | CocoaPods, Swift | +| Linux | CMake, C++ | +| Windows | CMake, C# | + +### Platform-Specific Features + +**iOS Only:** +- Home screen widgets +- Live Activities +- Apple Watch companion + +**Android Only:** +- Background service +- Push notifications +- File system access + +**Desktop Only:** +- Menu bar integration +- Multiple windows +- Custom title bar + +## Custom Dependencies + +### dartssh2 Fork + +Enhanced SSH client with: +- Better mobile support +- Enhanced error handling +- Performance optimizations + +### xterm.dart Fork + +Terminal emulator with: +- Mobile-optimized rendering +- Touch gesture support +- Virtual keyboard integration + +### fl_lib + +Shared utilities package with: +- Common widgets +- Extensions +- Helper functions + +## Build System + +### fl_build Package + +Custom build system for: +- Multi-platform builds +- Code signing +- Asset bundling +- Version management + +### Build Process + +``` +make.dart (version) → fl_build (build) → Platform output +``` + +1. **Pre-build**: Calculate version from Git +2. **Build**: Compile for target platform +3. **Post-build**: Package and sign + +## Data Flow Example + +### Server Status Update + +``` +1. Timer triggers → +2. Provider calls service → +3. Service executes SSH command → +4. Response parsed to model → +5. State updated → +6. UI rebuilds with new data +``` + +### User Action Flow + +``` +1. User taps button → +2. Widget calls provider method → +3. Provider updates state → +4. State change triggers rebuild → +5. New state reflected in UI +``` + +## Security Architecture + +### Data Protection + +- **Passwords**: Encrypted with flutter_secure_storage +- **SSH Keys**: Encrypted at rest +- **Host Fingerprints**: Stored securely +- **Session Data**: Not persisted + +### Connection Security + +- **Host Key Verification**: MITM detection +- **Encryption**: Standard SSH encryption +- **No Plain Text**: Sensitive data never stored plain diff --git a/docs/src/content/docs/principles/sftp.md b/docs/src/content/docs/principles/sftp.md new file mode 100644 index 00000000..5e0d82f8 --- /dev/null +++ b/docs/src/content/docs/principles/sftp.md @@ -0,0 +1,490 @@ +--- +title: SFTP System +description: How the SFTP file browser works +--- + +The SFTP system provides file management capabilities over SSH. + +## Architecture + +``` +┌─────────────────────────────────────────────┐ +│ SFTP UI Layer │ +│ - File browser (remote) │ +│ - File browser (local) │ +│ - Transfer queue │ +└─────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────┐ +│ SFTP State Management │ +│ - sftpProvider │ +│ - Path management │ +│ - Operation queue │ +└─────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────┐ +│ SFTP Protocol Layer │ +│ - SSH subsystem │ +│ - File operations │ +│ - Directory listing │ +└─────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────┐ +│ SSH Transport │ +│ - Secure channel │ +│ - Data streaming │ +└─────────────────────────────────────────────┘ +``` + +## Connection Establishment + +### SFTP Client Creation + +```dart +Future createSftpClient(Spi spi) async { + // 1. Get SSH client (reuse if available) + final sshClient = await genClient(spi); + + // 2. Open SFTP subsystem + final sftp = await sshClient.openSftp(); + + return sftp; +} +``` + +### Connection Reuse + +SFTP reuses existing SSH connections: + +```dart +class ServerProvider { + SSHClient? _sshClient; + SftpClient? _sftpClient; + + Future getSftpClient(String spiId) async { + _sftpClient ??= await _sshClient!.openSftp(); + return _sftpClient!; + } +} +``` + +## File System Operations + +### Directory Listing + +```dart +Future> listDirectory(String path) async { + final sftp = await getSftpClient(spiId); + + // List directory + final files = await sftp.listDir(path); + + // Sort based on settings + files.sort((a, b) { + switch (sortOption) { + case SortOption.name: + return a.name.toLowerCase().compareTo(b.name.toLowerCase()); + case SortOption.size: + return a.size.compareTo(b.size); + case SortOption.time: + return a.modified.compareTo(b.modified); + } + }); + + // Folders first if enabled + if (showFoldersFirst) { + final dirs = files.where((f) => f.isDirectory); + final regular = files.where((f) => !f.isDirectory); + return [...dirs, ...regular]; + } + + return files; +} +``` + +### File Metadata + +```dart +class SftpFile { + final String name; + final String path; + final int size; // Bytes + final int modified; // Unix timestamp + final String permissions; // e.g., "rwxr-xr-x" + final String owner; + final String group; + final bool isDirectory; + final bool isSymlink; + + String get sizeFormatted => formatBytes(size); + String get modifiedFormatted => formatDate(modified); +} +``` + +## File Operations + +### Upload + +```dart +Future uploadFile( + String localPath, + String remotePath, +) async { + final sftp = await getSftpClient(spiId); + + // Create request + final req = SftpReq( + spi: spi, + remotePath: remotePath, + localPath: localPath, + type: SftpReqType.upload, + ); + + // Add to queue + _transferQueue.add(req); + + // Execute transfer with progress + final file = File(localPath); + final size = await file.length(); + final stream = file.openRead(); + + await sftp.upload( + stream: stream, + toPath: remotePath, + onProgress: (transferred) { + _updateProgress(req, transferred, size); + }, + ); + + // Complete + _transferQueue.remove(req); +} +``` + +### Download + +```dart +Future downloadFile( + String remotePath, + String localPath, +) async { + final sftp = await getSftpClient(spiId); + + // Create local file + final file = File(localPath); + final sink = file.openWrite(); + + // Download with progress + final stat = await sftp.stat(remotePath); + + await sftp.download( + fromPath: remotePath, + toSink: sink, + onProgress: (transferred) { + _updateProgress( + SftpReq(...), + transferred, + stat.size, + ); + }, + ); + + await sink.close(); +} +``` + +### Permission Editing + +```dart +Future setPermissions( + String path, + String permissions, +) async { + final sftp = await getSftpClient(spiId); + + // Parse permissions (e.g., "rwxr-xr-x" or "755") + final mode = parsePermissions(permissions); + + // Set via SSH command (more reliable than SFTP) + final ssh = await getSshClient(spiId); + await ssh.exec('chmod $mode "$path"'); +} +``` + +## Path Management + +### Path Structure + +```dart +class PathWithPrefix { + final String prefix; // e.g., "/home/user" + final String path; // Relative or absolute + + String get fullPath { + if (path.startsWith('/')) { + return path; // Absolute path + } + return '$prefix/$path'; // Relative path + } + + PathWithPrefix cd(String subPath) { + return PathWithPrefix( + prefix: fullPath, + path: subPath, + ); + } +} +``` + +### Navigation History + +```dart +class PathHistory { + final List _history = []; + int _index = -1; + + void push(String path) { + // Remove forward history + _history.removeRange(_index + 1, _history.length); + _history.add(path); + _index = _history.length - 1; + } + + String? back() { + if (_index > 0) { + _index--; + return _history[_index]; + } + return null; + } + + String? forward() { + if (_index < _history.length - 1) { + _index++; + return _history[_index]; + } + return null; + } +} +``` + +## Transfer System + +### Transfer Request + +```dart +class SftpReq { + final Spi spi; + final String remotePath; + final String localPath; + final SftpReqType type; + final DateTime createdAt; + + int? totalBytes; + int? transferredBytes; + String? error; +} +``` + +### Progress Tracking + +```dart +class TransferProgress { + final SftpReq request; + final int total; + final int transferred; + final DateTime startTime; + + double get percentage => (transferred / total) * 100; + Duration get elapsed => DateTime.now().difference(startTime); + + String get speedFormatted { + final bytesPerSecond = transferred / elapsed.inSeconds; + return formatSpeed(bytesPerSecond); + } +} +``` + +### Queue Management + +```dart +class TransferQueue { + final List _queue = []; + final Map _progress = {}; + int _concurrent = 3; // Max concurrent transfers + + Future process() async { + final active = _progress.values.where((p) => p.isInProgress); + if (active.length >= _concurrent) return; + + final pending = _queue.where((r) => !_progress.containsKey(r.id)); + for (final req in pending.take(_concurrent - active.length)) { + _executeTransfer(req); + } + } + + Future _executeTransfer(SftpReq req) async { + try { + _progress[req.id] = TransferProgress.inProgress(req); + + if (req.type == SftpReqType.upload) { + await uploadFile(req.localPath, req.remotePath); + } else { + await downloadFile(req.remotePath, req.localPath); + } + + _progress[req.id] = TransferProgress.completed(req); + } catch (e) { + _progress[req.id] = TransferProgress.failed(req, e); + } + } +} +``` + +## Local Storage Pattern + +### Download Cache + +Downloaded files stored at: + +```dart +String getLocalDownloadPath(String spiId, String remotePath) { + final normalized = remotePath.replaceAll('/', '_'); + return 'Paths.file/$spiId/$normalized'; +} +``` + +Example: +- Remote: `/var/log/nginx/access.log` +- spiId: `server-123` +- Local: `Paths.file/server-123/_var_log_nginx_access.log` + +## File Editing + +### Edit Workflow + +```dart +Future editFile(String path) async { + final sftp = await getSftpClient(spiId); + + // 1. Check size + final stat = await sftp.stat(path); + if (stat.size > editorMaxSize) { + showWarning('File too large for built-in editor'); + return; + } + + // 2. Download to temp + final temp = await downloadToTemp(path); + + // 3. Open in editor + final content = await openEditor(temp.path); + + // 4. Upload back + await uploadFile(temp.path, path); + + // 5. Cleanup + await temp.delete(); +} +``` + +### External Editor Integration + +```dart +Future editInExternalEditor(String path) async { + final ssh = await getSshClient(spiId); + + // Open terminal with editor + final editor = getSetting('sftpEditor', 'vim'); + await ssh.exec('$editor "$path"'); + + // User edits in terminal + // After save, refresh SFTP view +} +``` + +## Error Handling + +### Permission Errors + +```dart +try { + await sftp.upload(...); +} on SftpPermissionException { + showError('Permission denied: ${stat.path}'); + showHint('Check file permissions and ownership'); +} +``` + +### Connection Errors + +```dart +try { + await sftp.listDir(path); +} on SftpConnectionException { + showError('Connection lost'); + await reconnect(); +} +``` + +### Space Errors + +```dart +try { + await sftp.upload(...); +} on SftpNoSpaceException { + showError('Disk full on remote server'); +} +``` + +## Performance Optimizations + +### Directory Caching + +```dart +class DirectoryCache { + final Map _cache = {}; + final Duration ttl = Duration(minutes: 5); + + Future> list(String path) async { + final cached = _cache[path]; + if (cached != null && !cached.isExpired) { + return cached.files; + } + + final files = await sftp.listDir(path); + _cache[path] = CachedDirectory(files); + return files; + } +} +``` + +### Lazy Loading + +For large directories (>1000 items): + +```dart +List loadPage(String path, int page, int pageSize) { + final all = cache[path] ?? []; + final start = page * pageSize; + final end = start + pageSize; + return all.sublist(start, end.clamp(0, all.length)); +} +``` + +### Pagination + +```dart +class PaginatedDirectory { + static const pageSize = 100; + + Future> getPage(int page) async { + final offset = page * pageSize; + return await sftp.listDir( + path, + offset: offset, + limit: pageSize, + ); + } +} +``` diff --git a/docs/src/content/docs/principles/ssh.md b/docs/src/content/docs/principles/ssh.md new file mode 100644 index 00000000..5b759422 --- /dev/null +++ b/docs/src/content/docs/principles/ssh.md @@ -0,0 +1,299 @@ +--- +title: SSH Connection +description: How SSH connections are established and managed +--- + +Understanding SSH connections in Flutter Server Box. + +## Connection Flow + +``` +User Input → Spi Config → genClient() → SSH Client → Session +``` + +### Step 1: Configuration + +The `Spi` (Server Parameter Info) model contains: + +```dart +class Spi { + String name; // Server name + String ip; // IP address + int port; // SSH port (default 22) + String user; // Username + String? pwd; // Password (encrypted) + String? keyId; // SSH key ID + String? jumpId; // Jump server ID + String? alterUrl; // Alternative URL +} +``` + +### Step 2: Client Generation + +`genClient(spi)` creates SSH client: + +```dart +Future genClient(Spi spi) async { + // 1. Establish socket + final socket = await connect(spi.ip, spi.port); + + // 2. Try alternative URL if failed + if (socket == null && spi.alterUrl != null) { + socket = await connect(spi.alterUrl, spi.port); + } + + // 3. Authenticate + final client = SSHClient( + socket: socket, + username: spi.user, + onPasswordRequest: () => spi.pwd, + onIdentityRequest: () => loadKey(spi.keyId), + ); + + // 4. Verify host key + await verifyHostKey(client, spi); + + return client; +} +``` + +### Step 3: Jump Server (if configured) + +For jump servers, recursive connection: + +```dart +if (spi.jumpId != null) { + final jumpClient = await genClient(getJumpSpi(spi.jumpId)); + final forwarded = await jumpClient.forwardLocal( + spi.ip, + spi.port, + ); + // Connect through forwarded socket +} +``` + +## Authentication Methods + +### Password Authentication + +```dart +onPasswordRequest: () => spi.pwd +``` + +- Password stored encrypted in Hive +- Decrypted on connection +- Sent to server for verification + +### Private Key Authentication + +```dart +onIdentityRequest: () async { + final key = await KeyStore.get(spi.keyId); + return decyptPem(key.pem, key.password); +} +``` + +**Key Loading Process:** +1. Retrieve encrypted key from `KeyStore` +2. Decrypt password (biometric/prompt) +3. Parse PEM format +4. Standardize line endings (LF) +5. Return for authentication + +### Keyboard-Interactive + +```dart +onUserInfoRequest: (instructions) async { + // Handle challenge-response + return responses; +} +``` + +Supports: +- Password authentication +- OTP tokens +- Two-factor authentication + +## Host Key Verification + +### Why Verify Host Keys? + +Prevents **Man-in-the-Middle (MITM)** attacks by ensuring you're connecting to the same server. + +### Storage Format + +``` +{spi.id}::{keyType} +``` + +Example: +``` +my-server::ssh-ed25519 +my-server::ecdsa-sha2-nistp256 +``` + +### Fingerprint Formats + +**MD5 Hex:** +``` +aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99 +``` + +**Base64:** +``` +SHA256:AbCdEf1234567890...= +``` + +### Verification Flow + +```dart +Future verifyHostKey(SSHClient client, Spi spi) async { + final key = await client.hostKey; + final fingerprint = md5Hex(key); // or base64 + + final stored = SettingStore.sshKnownHostsFingerprints + ['$keyId::$keyType']; + + if (stored == null) { + // New host - prompt user + final trust = await promptUser( + 'Unknown host', + 'Fingerprint: $fingerprint', + ); + if (trust) { + SettingStore.sshKnownHostsFingerprints + ['$keyId::$keyType'] = fingerprint; + } + } else if (stored != fingerprint) { + // Changed - warn user + await warnUser( + 'Host key changed!', + 'Possible MITM attack', + ); + } +} +``` + +## Session Management + +### Connection Pooling + +Active clients maintained in `ServerProvider`: + +```dart +class ServerProvider { + final Map _clients = {}; + + SSHClient getClient(String spiId) { + return _clients[spiId] ??= connect(spiId); + } +} +``` + +### Keep-Alive + +Maintain connection during inactivity: + +```dart +Timer.periodic( + Duration(seconds: 30), + (_) => client.sendKeepAlive(), +); +``` + +### Auto-Reconnect + +On connection loss: + +```dart +client.onError.listen((error) async { + await Future.delayed(Duration(seconds: 5)); + reconnect(); +}); +``` + +## Connection Lifecycle + +``` +┌─────────────┐ +│ Initial │ +└──────┬──────┘ + │ connect() + ↓ +┌─────────────┐ +│ Connecting │ ←──┐ +└──────┬──────┘ │ + │ success │ + ↓ │ fail (retry) +┌─────────────┐ │ +│ Connected │───┘ +└──────┬──────┘ + │ + ↓ +┌─────────────┐ +│ Active │ ──→ Send commands +└──────┬──────┘ + │ + ↓ (error/disconnect) +┌─────────────┐ +│ Disconnected│ +└─────────────┘ +``` + +## Error Handling + +### Connection Timeout + +```dart +try { + await client.connect().timeout( + Duration(seconds: 30), + ); +} on TimeoutException { + throw ConnectionException('Connection timeout'); +} +``` + +### Authentication Failure + +```dart +onAuthFail: (error) { + if (error.contains('password')) { + return 'Invalid password'; + } else if (error.contains('key')) { + return 'Invalid SSH key'; + } + return 'Authentication failed'; +} +``` + +### Host Key Mismatch + +```dart +onHostKeyMismatch: (stored, current) { + showSecurityWarning( + 'Host key has changed!', + 'Possible MITM attack', + ); +} +``` + +## Performance Considerations + +### Connection Reuse + +- Reuse clients across features +- Don't disconnect/reconnect unnecessarily +- Pool connections for concurrent operations + +### Optimal Settings + +- **Timeout**: 30 seconds (adjustable) +- **Keep-alive**: Every 30 seconds +- **Retry delay**: 5 seconds + +### Network Efficiency + +- Single connection for multiple operations +- Pipeline commands when possible +- Avoid opening multiple connections diff --git a/docs/src/content/docs/principles/state.md b/docs/src/content/docs/principles/state.md new file mode 100644 index 00000000..098a0e25 --- /dev/null +++ b/docs/src/content/docs/principles/state.md @@ -0,0 +1,405 @@ +--- +title: State Management +description: How state is managed with Riverpod +--- + +Understanding the state management architecture in Flutter Server Box. + +## Why Riverpod? + +**Key Benefits:** +- **Compile-time safety**: Catch errors at compile time +- **No BuildContext needed**: Access state anywhere +- **Easy testing**: Simple to test providers in isolation +- **Code generation**: Less boilerplate, type-safe + +## Provider Architecture + +``` +┌─────────────────────────────────────────────┐ +│ UI Layer (Widgets) │ +│ - ConsumerWidget / ConsumerStatefulWidget │ +│ - ref.watch() / ref.read() │ +└─────────────────────────────────────────────┘ + ↓ watches +┌─────────────────────────────────────────────┐ +│ Provider Layer │ +│ - @riverpod annotations │ +│ - Generated *.g.dart files │ +└─────────────────────────────────────────────┘ + ↓ uses +┌─────────────────────────────────────────────┐ +│ Service / Store Layer │ +│ - Business logic │ +│ - Data access │ +└─────────────────────────────────────────────┘ +``` + +## Provider Types Used + +### 1. StateProvider (Simple State) + +For simple, observable state: + +```dart +@riverpod +class ThemeNotifier extends _$ThemeNotifier { + @override + ThemeMode build() { + // Load from settings + return SettingStore.themeMode; + } + + void setTheme(ThemeMode mode) { + state = mode; + SettingStore.themeMode = mode; // Persist + } +} +``` + +**Usage:** +```dart +class MyWidget extends ConsumerWidget { + @override + Widget build(BuildContext context, WidgetRef ref) { + final theme = ref.watch(themeNotifierProvider); + return Text('Theme: $theme'); + } +} +``` + +### 2. AsyncNotifierProvider (Async State) + +For data that loads asynchronously: + +```dart +@riverpod +class ServerStatus extends _$ServerStatus { + @override + Future build(Server server) async { + // Initial load + return await fetchStatus(server); + } + + Future refresh() async { + state = const AsyncValue.loading(); + state = await AsyncValue.guard(() async { + return await fetchStatus(server); + }); + } +} +``` + +**Usage:** +```dart +final status = ref.watch(serverStatusProvider(server)); + +status.when( + data: (data) => StatusWidget(data), + loading: () => LoadingWidget(), + error: (error, stack) => ErrorWidget(error), +) +``` + +### 3. StreamProvider (Real-time Data) + +For continuous data streams: + +```dart +@riverpod +Stream cpuUsage(CpuUsageRef ref, Server server) { + final client = ref.watch(sshClientProvider(server)); + final stream = client.monitorCpu(); + + // Auto-dispose when not watched + ref.onDispose(() { + client.stopMonitoring(); + }); + + return stream; +} +``` + +**Usage:** +```dart +final cpu = ref.watch(cpuUsageProvider(server)); + +cpu.when( + data: (usage) => CpuChart(usage), + loading: () => CircularProgressIndicator(), + error: (error, stack) => ErrorWidget(error), +) +``` + +### 4. Family Providers (Parameterized) + +Providers that accept parameters: + +```dart +@riverpod +Future> containers(ContainersRef ref, Server server) async { + final client = await ref.watch(sshClientProvider(server).future); + return await client.listContainers(); +} +``` + +**Usage:** +```dart +final containers = ref.watch(containersProvider(server)); + +// Different servers = different cached states +final containers2 = ref.watch(containersProvider(server2)); +``` + +## State Update Patterns + +### Direct State Update + +```dart +ref.read(settingsProvider.notifier).updateTheme(darkMode); +``` + +### Computed State + +```dart +@riverpod +int totalServers(TotalServersRef ref) { + final servers = ref.watch(serversProvider); + return servers.length; +} +``` + +### Derived State + +```dart +@riverpod +List onlineServers(OnlineServersRef ref) { + final all = ref.watch(serversProvider); + return all.where((s) => s.isOnline).toList(); +} +``` + +## Server-Specific State + +### Per-Server Providers + +Each server has isolated state: + +```dart +@riverpod +class ServerProvider extends _$ServerProvider { + @override + ServerState build(Server server) { + return ServerState.disconnected(); + } + + Future connect() async { + state = ServerState.connecting(); + try { + final client = await genClient(server.spi); + state = ServerState.connected(client); + } catch (e) { + state = ServerState.error(e.toString()); + } + } +} +``` + +### Provider Keys + +```dart +// Unique provider per server +@riverpod +ServerStatus serverStatus(ServerStatusRef ref, Server server) { + // server.id used as key +} +``` + +## Reactive Patterns + +### Auto-Refresh + +```dart +@riverpod +class AutoRefreshServerStatus extends _$AutoRefreshServerStatus { + Timer? _timer; + + @override + Future build(Server server) async { + // Start timer + _timer = Timer.periodic(Duration(seconds: 5), (_) { + refresh(); + }); + + ref.onDispose(() { + _timer?.cancel(); + }); + + return await fetchStatus(server); + } + + Future refresh() async { + state = const AsyncValue.loading(); + state = await AsyncValue.guard(() => fetchStatus(server)); + } +} +``` + +### Multi-Provider Dependencies + +```dart +@riverpod +Future systemInfo(SystemInfoRef ref, Server server) async { + // Wait for SSH client first + final client = await ref.watch(sshClientProvider(server).future); + + // Then fetch system info + return await client.getSystemInfo(); +} +``` + +## State Persistence + +### Hive Integration + +```dart +@riverpod +class ServerStoreNotifier extends _$ServerStoreNotifier { + @override + List build() { + // Load from Hive + return Hive.box('servers').values.toList(); + } + + void addServer(Server server) { + state = [...state, server]; + // Persist to Hive + Hive.box('servers').put(server.id, server); + } + + void removeServer(String id) { + state = state.where((s) => s.id != id).toList(); + // Remove from Hive + Hive.box('servers').delete(id); + } +} +``` + +## Error Handling + +### Error States + +```dart +@riverpod +class ConnectionManager extends _$ConnectionManager { + @override + ConnectionState build() { + return ConnectionState.idle(); + } + + Future connect(Server server) async { + state = ConnectionState.connecting(); + try { + final client = await genClient(server.spi); + state = ConnectionState.connected(client); + } on SocketException catch (e) { + state = ConnectionState.error('Network error: $e'); + } on AuthenticationException catch (e) { + state = ConnectionState.error('Auth failed: $e'); + } catch (e) { + state = ConnectionState.error('Unknown error: $e'); + } + } +} +``` + +### Error Recovery + +```dart +@riverpod +class ResilientFetcher extends _$ResilientFetcher { + int _retryCount = 0; + + @override + Future build(Server server) async { + return await _fetchWithRetry(); + } + + Future _fetchWithRetry() async { + try { + return await fetchData(server); + } catch (e) { + if (_retryCount < 3) { + _retryCount++; + await Future.delayed(Duration(seconds: 2)); + return await _fetchWithRetry(); + } + rethrow; + } + } +} +``` + +## Performance Optimizations + +### Provider Keep-Alive + +```dart +@Riverpod(keepAlive: true) // Don't dispose when no listeners +class GlobalSettings extends _$GlobalSettings { + @override + Settings build() { + return Settings.defaults(); + } +} +``` + +### Selective Watching + +```dart +// Watch only specific part of state +final name = ref.watch(serverProvider.select((s) => s.name)); +``` + +### Provider Caching + +Family providers cache results per parameter: + +```dart +// Cached per server ID +final status1 = ref.watch(serverStatusProvider(server1)); +final status2 = ref.watch(serverStatusProvider(server2)); +// Different states, both cached +``` + +## Testing with Riverpod + +### Provider Container + +```dart +test('fetch server status', () async { + final container = ProviderContainer(); + addTearDown(container.dispose); + + // Override provider + container.overrideFactory( + sshClientProvider, + (ref, server) => MockSshClient(), + ); + + final status = await container.read( + serverStatusProvider(testServer).future, + ); + + expect(status, isA()); +}); +``` + +## Best Practices + +1. **Co-locate providers**: Place near consuming widgets +2. **Use code generation**: Always use `@riverpod` +3. **Keep providers focused**: Single responsibility +4. **Handle loading states**: Always handle AsyncValue states +5. **Dispose resources**: Use `ref.onDispose()` for cleanup +6. **Avoid deep provider trees**: Keep provider graph flat diff --git a/docs/src/content/docs/principles/terminal.md b/docs/src/content/docs/principles/terminal.md new file mode 100644 index 00000000..0bceeb48 --- /dev/null +++ b/docs/src/content/docs/principles/terminal.md @@ -0,0 +1,343 @@ +--- +title: Terminal Implementation +description: How the SSH terminal works internally +--- + +The SSH terminal is one of the most complex features, built on a custom xterm.dart fork. + +## Architecture Overview + +``` +┌─────────────────────────────────────────────┐ +│ Terminal UI Layer │ +│ - Tab management │ +│ - Virtual keyboard │ +│ - Text selection │ +└─────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────┐ +│ xterm.dart Emulator │ +│ - PTY (Pseudo Terminal) │ +│ - VT100/ANSI emulation │ +│ - Rendering engine │ +└─────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────┐ +│ SSH Client Layer │ +│ - SSH session │ +│ - Channel management │ +│ - Data streaming │ +└─────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────┐ +│ Remote Server │ +│ - Shell process │ +│ - Command execution │ +└─────────────────────────────────────────────┘ +``` + +## Terminal Session Lifecycle + +### 1. Session Creation + +```dart +Future createSession(Spi spi) async { + // 1. Get SSH client + final client = await genClient(spi); + + // 2. Create PTY + final pty = await client.openPty( + term: 'xterm-256color', + cols: 80, + rows: 24, + ); + + // 3. Initialize terminal emulator + final terminal = Terminal( + backend: PtyBackend(pty), + ); + + // 4. Setup resize handler + terminal.onResize.listen((size) { + pty.resize(size.cols, size.rows); + }); + + return TerminalSession( + terminal: terminal, + pty: pty, + client: client, + ); +} +``` + +### 2. Terminal Emulation + +The xterm.dart fork provides: + +**VT100/ANSI Emulation:** +- Cursor movement +- Colors (256-color support) +- Text attributes (bold, underline, etc.) +- Scrolling regions +- Alternate screen buffer + +**Rendering:** +- Line-based rendering +- Bidirectional text support +- Unicode/emoji support +- Optimized redraws + +### 3. Data Flow + +``` +User Input + ↓ +Virtual Keyboard / Physical Keyboard + ↓ +Terminal Emulator (key → escape sequence) + ↓ +SSH Channel (send) + ↓ +Remote PTY + ↓ +Remote Shell + ↓ +Command Output + ↓ +SSH Channel (receive) + ↓ +Terminal Emulator (parse ANSI codes) + ↓ +Render to Screen +``` + +## Multi-Tab System + +### Tab Management + +```dart +class TerminalTabs { + final Map _tabs = {}; + String? _activeTabId; + + void createTab(Server server) { + final id = _generateTabId(server); + _tabs[id] = TabData( + id: id, + name: _generateTabName(server), + session: createSession(server), + ); + _activeTabId = id; + } + + String _generateTabName(Server server) { + final count = _tabs.values + .where((t) => t.name.startsWith(server.name)) + .length; + return count == 0 ? server.name : '${server.name}($count)'; + } +} +``` + +### Session Persistence + +Tabs maintain state across navigation: + +- SSH connection kept alive +- Terminal state preserved +- Scroll buffer maintained +- Input history retained + +## Virtual Keyboard + +### Platform-Specific Implementation + +**iOS:** +- UIView-based custom keyboard +- Toggleable with keyboard button +- Auto-show/hide based on focus + +**Android:** +- Custom input method +- Integrated with system keyboard +- Quick action buttons + +### Keyboard Buttons + +| Button | Action | +|--------|--------| +| **Toggle** | Show/hide system keyboard | +| **Ctrl** | Send Ctrl modifier | +| **Alt** | Send Alt modifier | +| **SFTP** | Open current directory | +| **Clipboard** | Copy/Paste context-aware | +| **Snippets** | Execute snippet | + +### Key Encoding + +```dart +String encodeKey(Key key) { + switch (key) { + case Key.enter: + return '\r'; + case Key.tab: + return '\t'; + case Key.escape: + return '\x1b'; + case Key.ctrlC: + return '\x03'; + // ... more keys + } +} +``` + +## Text Selection + +### Selection Mode + +1. **Long press**: Enter selection mode +2. **Drag**: Extend selection +3. **Release**: Copy to clipboard + +### Selection Storage + +```dart +class TextSelection { + final BufferRange range; + final String text; + + void copyToClipboard() { + Clipboard.setData(ClipboardData(text: text)); + } +} +``` + +## Font and Dimensions + +### Size Calculation + +```dart +class TerminalDimensions { + static Size calculate(double fontSize, Size screenSize) { + final charWidth = fontSize * 0.6; // Monospace aspect ratio + final charHeight = fontSize * 1.2; + + final cols = (screenSize.width / charWidth).floor(); + final rows = (screenSize.height / charHeight).floor(); + + return Size(cols.toDouble(), rows.toDouble()); + } +} +``` + +### Pinch-to-Zoom + +```dart +GestureDetector( + onScaleStart: () => _baseFontSize = currentFontSize, + onScaleUpdate: (details) { + final newFontSize = _baseFontSize * details.scale; + resize(newFontSize); + }, +) +``` + +## Color Scheme + +### ANSI Color Mapping + +```dart +const colorMap = { + 0: Color(0x000000), // Black + 1: Color(0x800000), // Red + 2: Color(0x008000), // Green + 3: Color(0x808000), // Yellow + 4: Color(0x000080), // Blue + 5: Color(0x800080), // Magenta + 6: Color(0x008080), // Cyan + 7: Color(0xC0C0C0), // White + // ... 256-color palette +}; +``` + +### Theme Support + +- **Light**: Light background, dark text +- **Dark**: Dark background, light text +- **AMOLED**: Pure black background + +## Performance Optimizations + +### Rendering Optimizations + +- **Dirty rectangle**: Only redraw changed regions +- **Line caching**: Cache rendered lines +- **Lazy scrolling**: Virtual scrolling for long buffers + +### Data Optimizations + +- **Batch updates**: Coalesce multiple writes +- **Compression**: Compress scroll buffer +- **Debouncing**: Debounce rapid inputs + +## Clipboard Integration + +### Copy Selection + +```dart +void copySelection() { + final selected = terminal.getSelection(); + Clipboard.setData(ClipboardData(text: selected)); +} +``` + +### Paste Clipboard + +```dart +Future pasteClipboard() async { + final data = await Clipboard.getData('text/plain'); + if (data?.text != null) { + terminal.paste(data!.text!); + } +} +``` + +### Context-Aware Button + +- **Has selection**: Show "Copy" +- **Has clipboard**: Show "Paste" +- **Both**: Show primary action + +## Special Features + +### Snippet Execution + +```dart +void executeSnippet(Snippet snippet) { + final formatted = formatSnippet(snippet); + terminal.paste(formatted); + terminal.paste('\r'); // Execute +} +``` + +### SFTP Quick Access + +```dart +void openSftp() async { + final cwd = await terminal.getCurrentWorkingDirectory(); + Navigator.push( + context, + SftpPage(initialPath: cwd), + ); +} +``` + +### Keep-Alive + +```dart +Timer.periodic(Duration(seconds: 30), (_) { + if (terminal.isActive) { + terminal.send('\x00'); // NUL - no-op keep-alive + } +}); +``` diff --git a/docs/src/content/docs/quick-start.mdx b/docs/src/content/docs/quick-start.mdx new file mode 100644 index 00000000..948eca68 --- /dev/null +++ b/docs/src/content/docs/quick-start.mdx @@ -0,0 +1,51 @@ +--- +title: Quick Start +description: Get up and running with Flutter Server Box in minutes +--- + +Follow this quick start guide to connect to your first server and start monitoring. + +## Step 1: Add a Server + +1. Open Flutter Server Box +2. Tap the **+** button to add a new server +3. Fill in the server information: + - **Name**: A friendly name for your server + - **Host**: IP address or domain name + - **Port**: SSH port (default: 22) + - **User**: SSH username + - **Password or Key**: Authentication method + +4. Tap **Save** to add the server + +## Step 2: Connect and Monitor + +1. Tap on your server card to connect +2. The app will establish an SSH connection +3. You'll see real-time status for: + - CPU usage + - Memory (RAM) and Swap + - Disk usage + - Network speed + +## Step 3: Explore Features + +Once connected, you can: + +- **Open Terminal**: Tap the terminal button for full SSH access +- **Browse Files**: Use SFTP to manage files +- **Manage Containers**: View and control Docker containers +- **View Processes**: Check running processes +- **Run Snippets**: Execute saved commands + +## Tips + +- **Biometric Authentication**: Enable Face ID / Touch ID / Fingerprint for quick access (mobile) +- **Home Screen Widgets**: Add server status widgets to your home screen (iOS/Android) +- **Background Running**: Keep connections alive in the background (Android) + +## Next Steps + +- Explore the [Features](/features/) section for detailed guides +- Configure [SSH Keys](/configuration/ssh-keys/) for passwordless authentication +- Customize your experience in [Settings](/configuration/appearance/) diff --git a/docs/src/styles/custom.css b/docs/src/styles/custom.css new file mode 100644 index 00000000..ace1f804 --- /dev/null +++ b/docs/src/styles/custom.css @@ -0,0 +1,7 @@ +/* Flutter Server Box Custom Styles */ + +:root { + --sl-color-accent: #02569b; + --sl-color-accent-low: #02569b15; + --starlight-cards--border: var(--sl-color-accent-low); +} diff --git a/docs/tsconfig.json b/docs/tsconfig.json new file mode 100644 index 00000000..8bf91d3b --- /dev/null +++ b/docs/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "astro/tsconfigs/strict", + "include": [".astro/types.d.ts", "**/*"], + "exclude": ["dist"] +} diff --git a/lib/generated/l10n/l10n.dart b/lib/generated/l10n/l10n.dart index 9747bb72..50125318 100644 --- a/lib/generated/l10n/l10n.dart +++ b/lib/generated/l10n/l10n.dart @@ -404,7 +404,7 @@ abstract class AppLocalizations { /// No description provided for @compactDatabaseContent. /// /// In en, this message translates to: - /// **'Database size: {size}\n\nThis will reorganize the database to reduce file size. No data will be deleted.'** + /// **'Database size: {size}\n\nThis will rebuild the whole database to reduce file size.'** String compactDatabaseContent(Object size); /// No description provided for @confirm. diff --git a/lib/generated/l10n/l10n_en.dart b/lib/generated/l10n/l10n_en.dart index 40cf1a52..f80c7b61 100644 --- a/lib/generated/l10n/l10n_en.dart +++ b/lib/generated/l10n/l10n_en.dart @@ -166,7 +166,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String compactDatabaseContent(Object size) { - return 'Database size: $size\n\nThis will reorganize the database to reduce file size. No data will be deleted.'; + return 'Database size: $size\n\nThis will rebuild the whole database to reduce file size.'; } @override