From c09da15bd02d4edca9294566d544e9ca2e9b4f46 Mon Sep 17 00:00:00 2001 From: Oier Bravo Urtasun Date: Sun, 24 May 2026 04:03:42 +0200 Subject: [PATCH] initial commit --- .env.example | 4 + .gitignore | 18 + CLAUDE.md | 280 +++ docker-compose.yml | 106 + extras/README.md | 13 + extras/modrinth-mods.txt | 24 + landing/astro.config.mjs | 13 + landing/package.json | 18 + landing/pnpm-lock.yaml | 4023 +++++++++++++++++++++++++++++++++ landing/public/.gitkeep | 0 landing/public/logo.png | Bin 0 -> 14656 bytes landing/src/data/site.ts | 31 + landing/src/pages/index.astro | 194 ++ landing/tsconfig.json | 5 + plan/00-overview.md | 122 + plan/01-dnsmasq.md | 57 + plan/02-caddy.md | 69 + plan/03-drasl.md | 52 + plan/04-packwiz.md | 48 + plan/05-minecraft.md | 52 + plan/06-launcher.md | 100 + plan/07-mc-backup.md | 30 + plan/08-tooling.md | 77 + plan/09-landing.md | 53 + plan/10-assets-mirror.md | 114 + plan/11-full-airgap-mirror.md | 132 ++ plan/12-build-order.md | 59 + tooling/build-stack.sh | 107 + 28 files changed, 5801 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 CLAUDE.md create mode 100644 docker-compose.yml create mode 100644 extras/README.md create mode 100644 extras/modrinth-mods.txt create mode 100644 landing/astro.config.mjs create mode 100644 landing/package.json create mode 100644 landing/pnpm-lock.yaml create mode 100644 landing/public/.gitkeep create mode 100644 landing/public/logo.png create mode 100644 landing/src/data/site.ts create mode 100644 landing/src/pages/index.astro create mode 100644 landing/tsconfig.json create mode 100644 plan/00-overview.md create mode 100644 plan/01-dnsmasq.md create mode 100644 plan/02-caddy.md create mode 100644 plan/03-drasl.md create mode 100644 plan/04-packwiz.md create mode 100644 plan/05-minecraft.md create mode 100644 plan/06-launcher.md create mode 100644 plan/07-mc-backup.md create mode 100644 plan/08-tooling.md create mode 100644 plan/09-landing.md create mode 100644 plan/10-assets-mirror.md create mode 100644 plan/11-full-airgap-mirror.md create mode 100644 plan/12-build-order.md create mode 100755 tooling/build-stack.sh diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..d4d0871 --- /dev/null +++ b/.env.example @@ -0,0 +1,4 @@ +# Copy to .env and fill in real values +RCON_PASSWORD=change-me-to-something-random +# Only needed if using CurseForge-exclusive mods: +# CF_API_KEY=your-curseforge-api-key diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7bbe8d1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +.env +backups/ +drasl/config/keycloak-client-secret +extras/authlib-injector.jar + +# rendered configs (from tooling/render-config.sh) +drasl/config/config.toml +dnsmasq/dnsmasq.conf + +# vendored / mirrored binaries +mirror/ +pack/mods-files/ + +# landing page: generated build output + deps +www/ +landing/node_modules/ +landing/.astro/ +landing/dist/ diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..f7cf079 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,280 @@ +# Minecraft LAN Party Server — Project Context + +> Self-hosted modded Minecraft server for a LAN party (~8 players), with +> persistent auth/skin infrastructure designed to outlive the LAN weekend +> and integrate with the existing homelab. + +## Goals & Constraints + +- **Players**: 4–10 friends, LAN-based +- **Modpack vibe**: Kitchen-sink (tech + magic + exploration + QoL) +- **Pack approach**: Manually curated (~50–100 mods), NOT a forked existing pack +- **Minecraft version**: 1.21.1 +- **Mod loader**: NeoForge (NOT classic Forge — see Decisions below) +- **Network**: LAN party context, but stack is persistent (lives past the weekend) +- **Auth**: Self-hosted Yggdrasil-compatible (Drasl) + Keycloak OIDC +- **Skins**: Handled by Drasl +- **Persistence horizon**: Long-term homelab service, not disposable + +## Existing Homelab Context (relevant to this project) + +- **Keycloak 26.0.7** running in Docker Compose (PostgreSQL 17, production mode, + bind-mounted secrets, xforwarded proxy headers). This is the IdP for everything. +- **NetBird** as the proxy/networking layer for remote access (NOT used for the + LAN party itself — see Decisions). +- **AdGuard Home** as recursive DNS resolver — used here for `*.home.local` LAN records. +- **Multi-VPS topology**: this Minecraft project likely runs on a local box or + beefier homelab node, not a VPS (RAM/CPU requirements). +- Operator timezone: Europe/Madrid. + +## Key Decisions (with reasoning) + +### NeoForge over classic Forge +Despite the user originally saying "Forge", the 1.21.x kitchen-sink ecosystem +(ATM10, Leaking Kitchen Sink, etc.) is overwhelmingly NeoForge in 2025/2026. +The original Forge team essentially migrated to NeoForge. `itzg/minecraft-server` +supports both via `TYPE=NEOFORGE`. Going with NeoForge 1.21.1. + +### Drasl over Ely.by or vanilla offline mode +- **Ely.by**: not self-hosted, Russian-hosted, no control over identity layer. +- **Vanilla offline + no auth server**: works for one weekend but skins break, + no persistent identity, doesn't match homelab philosophy. +- **Drasl**: self-hosted Go service, Yggdrasil-compatible, drop-in Mojang + replacement, supports skins + capes, **has first-class OIDC support with + PKCE** (perfect for Keycloak), actively maintained (current version 3.4.2+). + GPLv3 licensed. + +### LAN (not NetBird) for the party itself +NetBird is the homelab's remote access layer, but adding a mesh VPN on top +of a LAN party introduces complexity for guests with no upside. Drasl and +Minecraft live on the LAN; clients reach them via `drasl.home.local` resolved +through AdGuard. + +### Manual curation (user choice — flagged as expensive) +User insisted on manual curation despite my pushback that forking ATM10 or +Leaking Kitchen Sink would save weeks of crash-log triage. **Note for future +sessions**: if curation gets painful, the fork-and-trim option is still on +the table — Leaking Kitchen Sink is the closest match to the requested vibe. + +### itzg/minecraft-server as base image +The de facto standard. Handles NeoForge installation automatically via +`TYPE=NEOFORGE` + `VERSION` + `NEOFORGE_VERSION`. Supports Modrinth and +CurseForge mod auto-download via `MODRINTH_PROJECTS` and `CURSEFORGE_FILES`. + +## Architecture + +``` +LAN segment + │ + ├── AdGuard Home → resolves drasl.home.local, keycloak.home.local + │ to the Docker host's LAN IP + │ + ├── Keycloak (existing, separate compose) + │ realm: homelab + │ client: drasl (confidential, PKCE S256) + │ + └── Minecraft host (this project's compose) + │ + ├── drasl :25585 (Yggdrasil API + web UI) + │ └── OIDC → Keycloak + │ + ├── minecraft :25565 (server) + │ :24454/udp (Simple Voice Chat, optional) + │ └── -javaagent:authlib-injector.jar=http://drasl.home.local:25585/authlib-injector + │ └── ONLINE_MODE=false (required for authlib-injector) + │ + └── mc-backup (itzg/mc-backup, 6h interval) + └── RCON → minecraft + +Clients (LAN party guests): + Prism Launcher → authlib-injector account pointing at Drasl + → joins minecraft:25565 +``` + +## Auth Flow (end-to-end) + +1. Guest opens `http://drasl.home.local:25585` in browser. +2. Clicks "Register with Keycloak" → redirected to Keycloak login. +3. Logs in with homelab Keycloak credentials. +4. Returned to Drasl, picks a player name, uploads a skin. +5. Drasl shows them a "Minecraft Token" on their profile page. +6. In Prism Launcher: Settings → Accounts → Add authlib-injector account + with URL `http://drasl.home.local:25585/authlib-injector` and the + Minecraft Token as password. +7. Joins Minecraft server. Server validates session against Drasl (via + authlib-injector JVM agent), Drasl confirms, player enters with their skin. + +## Critical Gotchas + +### Minecraft 1.21+ secure profile incompatibility +- Server: must set `enforce-secure-profile=false` (compose: `ENFORCE_SECURE_PROFILE=FALSE`) +- Drasl: must set `SignPublicKeys = false` +- These are linked. The Drasl docs explicitly warn: *"Mixed authentication does + not work with `SignPublicKeys = true` on Minecraft 1.21+."* + +### authlib-injector JVM agent +- Syntax: `-javaagent:/path/to/authlib-injector.jar=` +- The URL after `=` is the **API root**, which for Drasl is + `/authlib-injector`. +- **Must match between server and client.** If server uses + `http://drasl.home.local:25585/authlib-injector` and client uses anything + else (e.g. an IP), session validation fails silently with "Invalid session". +- Download from: https://github.com/yushijinhun/authlib-injector/releases +- Mount into the itzg container at `/extras/authlib-injector.jar`. + +### Keycloak reachability on LAN day +If Keycloak is only reachable via NetBird or only from the public internet, +**Drasl OIDC registration breaks on LAN-only day**. Options: +1. Expose Keycloak on the LAN (simplest) +2. Pre-register all guests before the party +3. Temporarily disable OIDC and allow password registration during the LAN + (`AllowPasswordLogin = true`, comment out the OIDC block) + +### HTTP vs HTTPS for OIDC +Modern browsers warn on plain HTTP for OIDC flows but they work. For a +production-grade setup, front Drasl with Caddy or Traefik using a local CA +cert (smallstep/step-ca pairs well with the existing homelab). For LAN-only +HTTP is fine. + +### NeoForge version pinning +Mods are picky about exact NeoForge minor versions. The compose currently +pins `NEOFORGE_VERSION: "21.1.209"` as a placeholder. **Verify against +https://projects.neoforged.net/neoforged/neoforge before deploying.** Don't +use `"latest"` for a stable server. + +### Drasl username vs player name +- **Drasl username** = OIDC user's email (used for web UI login) +- **Player name** = `preferred_username` from OIDC, or user-chosen if + `AllowChoosingPlayerName = true` +- Keycloak users must have email set. Verify the realm's email-as-username + setting and the `preferred_username` mapper are configured. + +### Mod source preference +Prefer **Modrinth over CurseForge** for itzg auto-download. CurseForge +requires an API key (`CF_API_KEY`) and has been historically flakier with +the itzg image. Use CF only for mods that are exclusive to it. + +## Compose Stack + +The working compose file is at `./docker-compose.yml`. Key environment vars +documented inline. Adjacent files: + +``` +. +├── docker-compose.yml +├── .env # RCON_PASSWORD, CF_API_KEY (if needed) +├── drasl/ +│ └── config/ +│ ├── config.toml # see ./drasl-config.toml example +│ └── keycloak-client-secret # single line, no trailing newline +├── extras/ +│ ├── authlib-injector.jar # downloaded from yushijinhun's releases +│ ├── modrinth-mods.txt # one mod slug per line +│ └── cf-mods.txt # only if using CurseForge mods +├── backups/ # mc-backup writes here +└── CLAUDE.md # this file +``` + +### Memory sizing +With ~50–100 mods and 8 concurrent players on 1.21.1: +- `INIT_MEMORY: 4G`, `MAX_MEMORY: 10G` is a safe starting point +- Use `USE_AIKAR_FLAGS: TRUE` for the well-known GC tuning +- Monitor with `mc-monitor` (itzg makes one) if you want metrics + +### Backups +`itzg/mc-backup` runs alongside, talks to the server via RCON, takes +snapshots every 6h, prunes after 14 days. Backups are world-only (no mod +jars), which is correct — mods are reproducible from the mod list files. + +## Keycloak Client Configuration + +In the `homelab` realm (or whatever the realm is called): + +1. **Clients → Create client** + - Client type: `OpenID Connect` + - Client ID: `drasl` + - Name: `Drasl Minecraft Auth` + +2. **Capability config** + - Client authentication: **ON** (confidential client) + - Authentication flow: **Standard flow** only + - Disable: Direct access grants, Implicit, Service accounts + +3. **Login settings** + - Root URL: `http://drasl.home.local:25585` + - Valid redirect URIs: `http://drasl.home.local:25585/web/oidc-callback/Keycloak` + (the `Keycloak` at the end MUST match the `Name = "Keycloak"` in Drasl's + `[[RegistrationOIDC]]` block — case sensitive) + - Web origins: `http://drasl.home.local:25585` + +4. **Credentials tab** → copy Client Secret to + `./drasl/config/keycloak-client-secret` (no trailing newline). + +5. **Advanced tab** → PKCE Code Challenge Method: `S256` + +## Client Distribution (LAN guests) + +### Recommended launcher +**Prism Launcher** — open source, cross-platform (Win/Mac/Linux), first-class +authlib-injector support, can import/export instance ZIPs. + +### Per-guest one-time setup +1. Install Prism Launcher. +2. Add authlib-injector account: + - URL: `http://drasl.home.local:25585/authlib-injector` + - Username/password: their Drasl credentials (or Minecraft Token if + registered via Keycloak OIDC) +3. Import the modpack instance ZIP. + +### What to ship guests +- A Prism instance ZIP (right-click instance → Export Instance) +- A one-page README with the auth URL and import steps +- Optionally `authlib-injector.jar` for guests who refuse Prism + +## Open / Pending Work + +These were on the roadmap when we ended the brainstorm: + +- [ ] **Mod shortlist for the kitchen-sink pack.** Categories to fill: + - Performance (Embeddium/Sodium-equivalent for NeoForge, FerriteCore, ModernFix) + - Tech/automation (Mekanism, Create, Immersive Engineering, AE2) + - Magic (Ars Nouveau, Botania, Iron's Spells 'n Spellbooks) + - Storage (Sophisticated Storage/Backpacks, Functional Storage) + - Exploration (YUNG's structures, Repurposed Structures, biome packs) + - QoL (JEI, Jade, JEI Resources, Inventory Profiles Next, AppleSkin) + - World gen (Tectonic, Terralith — check NeoForge 1.21.1 compat) + - Compat glue (Polymorph for recipe conflicts) + - Map (XaeroMinimap + Xaero World Map) + - Voice (Simple Voice Chat — port 24454/udp already in compose) +- [ ] **Decide on dimension/server-side performance mods** (C2ME, Lithium-equivalent) +- [ ] **Reverse proxy + local TLS** for Drasl (Caddy + step-ca recommended, + given the existing homelab) +- [ ] **DNS record** in AdGuard for `drasl.home.local` → Docker host LAN IP +- [ ] **Keycloak client** creation per the section above +- [ ] **Verify NeoForge version** against current stable before first deploy +- [ ] **Bootstrap admin in Drasl**: leave `AllowPasswordLogin = true` initially, + create the admin account, then optionally disable password login to force OIDC + +## Reference URLs + +- Drasl repo: https://github.com/unmojang/drasl +- Drasl configuration docs: https://github.com/unmojang/drasl/blob/master/doc/configuration.md +- Drasl recipes (example configs): https://github.com/unmojang/drasl/blob/master/doc/recipes.md +- authlib-injector: https://github.com/yushijinhun/authlib-injector +- itzg/minecraft-server: https://github.com/itzg/docker-minecraft-server +- itzg NeoForge docs: https://github.com/itzg/docker-minecraft-server/blob/master/docs/types-and-platforms/server-types/forge.md +- itzg/mc-backup: https://github.com/itzg/docker-mc-backup +- NeoForge versions: https://projects.neoforged.net/neoforged/neoforge +- Prism Launcher: https://prismlauncher.org/ +- Reference modpacks for inspiration (NOT forking): + - ATM10 (Modrinth/CurseForge — ~500 mods, NeoForge 1.21.1) + - Leaking Kitchen Sink (CurseForge — trimmed ~150 mods, NeoForge 1.21.1) + +## Communication Preferences (carry-over from past sessions) + +- Concise and direct +- Diagnose and resolve without demanding detailed reproduction steps +- Prefer iterative single-change updates over large rewrites +- Cautious scripts that halt on ambiguity rather than proceeding silently +- Avoid over-engineered responses when a simple answer suffices +- Spanish or English fine; user is comfortable in both diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..342db74 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,106 @@ +# ────────────────────────────────────────────────────────────────── +# Minecraft 1.21.1 NeoForge + Drasl auth (with Keycloak OIDC) +# ────────────────────────────────────────────────────────────────── +# Assumes: +# - Keycloak is already running and reachable at https://keycloak.home.local +# - AdGuard Home resolves drasl.home.local -> this host's LAN IP +# - This host's LAN IP is on the same segment as the LAN party +# ────────────────────────────────────────────────────────────────── + +services: + drasl: + image: unmojang/drasl:latest + container_name: drasl + restart: unless-stopped + ports: + - "25585:25585" # Drasl web UI + Yggdrasil API + volumes: + - ./drasl/config:/etc/drasl:ro + - drasl_state:/var/lib/drasl + networks: + - mcnet + # No env vars needed — all config is in ./drasl/config/config.toml + + minecraft: + image: itzg/minecraft-server:java21 + container_name: minecraft + restart: unless-stopped + stdin_open: true + tty: true + ports: + - "25565:25565" + - "24454:24454/udp" # Simple Voice Chat, if used + environment: + EULA: "TRUE" + TYPE: "NEOFORGE" + VERSION: "1.21.1" + NEOFORGE_VERSION: "21.1.209" # pin a known-good build; update deliberately + + # ── Memory / performance ──────────────────────────────────── + INIT_MEMORY: "4G" + MAX_MEMORY: "10G" # 8 players + 100 mods comfortably + USE_AIKAR_FLAGS: "TRUE" + JVM_XX_OPTS: "-XX:+UseG1GC" + + # ── Auth: offline mode + authlib-injector pointing at Drasl ─ + ONLINE_MODE: "FALSE" + # mount authlib-injector.jar at /extras/authlib-injector.jar + JVM_OPTS: "-javaagent:/extras/authlib-injector.jar=http://drasl.home.local:25585/authlib-injector" + + # ── Server config ─────────────────────────────────────────── + DIFFICULTY: "normal" + MODE: "survival" + MOTD: "LAN party — kitchen sink" + MAX_PLAYERS: "10" + VIEW_DISTANCE: "10" + SIMULATION_DISTANCE: "8" + ENFORCE_SECURE_PROFILE: "FALSE" # required for authlib-injector on 1.21+ + ALLOW_FLIGHT: "TRUE" # many tech mods need this + + # ── Mod sources (Modrinth recommended over CF) ────────────── + MODRINTH_PROJECTS: "@/extras/modrinth-mods.txt" + MODRINTH_DOWNLOAD_DEPENDENCIES: "required" + # Optional, only if you need CF-exclusive mods: + # CF_API_KEY: ${CF_API_KEY} + # CURSEFORGE_FILES: "@/extras/cf-mods.txt" + + # ── RCON for remote admin ─────────────────────────────────── + ENABLE_RCON: "TRUE" + RCON_PASSWORD: ${RCON_PASSWORD} + RCON_PORT: 25575 + + TZ: "Europe/Madrid" + volumes: + - mc_data:/data + - ./extras:/extras:ro # authlib-injector.jar + mod lists live here + depends_on: + - drasl + networks: + - mcnet + + # Optional: backups + mc-backup: + image: itzg/mc-backup + container_name: mc-backup + restart: unless-stopped + environment: + BACKUP_INTERVAL: "6h" + RCON_HOST: "minecraft" + RCON_PASSWORD: ${RCON_PASSWORD} + PRUNE_BACKUPS_DAYS: "14" + TZ: "Europe/Madrid" + volumes: + - mc_data:/data:ro + - ./backups:/backups + depends_on: + - minecraft + networks: + - mcnet + +volumes: + drasl_state: + mc_data: + +networks: + mcnet: + driver: bridge diff --git a/extras/README.md b/extras/README.md new file mode 100644 index 0000000..7d1e009 --- /dev/null +++ b/extras/README.md @@ -0,0 +1,13 @@ +# /extras + +Mounted read-only into the Minecraft container at `/extras`. + +## Required files + +- `authlib-injector.jar` — download latest from + https://github.com/yushijinhun/authlib-injector/releases +- `modrinth-mods.txt` — one Modrinth project slug per line + +## Optional + +- `cf-mods.txt` — CurseForge mod file IDs, only if `CF_API_KEY` is set diff --git a/extras/modrinth-mods.txt b/extras/modrinth-mods.txt new file mode 100644 index 0000000..5b236d9 --- /dev/null +++ b/extras/modrinth-mods.txt @@ -0,0 +1,24 @@ +# One Modrinth project slug per line. Empty lines and # comments ignored. +# Pin versions with :version-id for stability. +# This is a placeholder — fill in during mod curation. + +# === Performance === +# embeddium +# ferritecore +# modernfix + +# === QoL === +# jei +# jade + +# === Tech === +# mekanism +# create + +# === Magic === +# ars-nouveau + +# === Map / Voice === +# xaeros-minimap +# xaeros-world-map +# simple-voice-chat diff --git a/landing/astro.config.mjs b/landing/astro.config.mjs new file mode 100644 index 0000000..dc3fab8 --- /dev/null +++ b/landing/astro.config.mjs @@ -0,0 +1,13 @@ +import { defineConfig } from "astro/config"; + +// Build writes straight into ../www, which Caddy serves at the apex domain. +// BASE_DOMAIN is baked at build time (default ulicraft.local). +export default defineConfig({ + outDir: "../www", + // Wipe ../www on each build so stale assets don't linger. + build: { assets: "_assets" }, + vite: { + // Surface BASE_DOMAIN to the build without the PUBLIC_ prefix dance; + // index.astro reads it from process.env directly in frontmatter. + }, +}); diff --git a/landing/package.json b/landing/package.json new file mode 100644 index 0000000..ad4c7f0 --- /dev/null +++ b/landing/package.json @@ -0,0 +1,18 @@ +{ + "name": "ulicraft-landing", + "version": "0.1.0", + "private": true, + "type": "module", + "packageManager": "pnpm@9.15.0", + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview", + "check": "astro check" + }, + "devDependencies": { + "@astrojs/check": "^0.9.4", + "astro": "^5.2.5", + "typescript": "^5.7.3" + } +} diff --git a/landing/pnpm-lock.yaml b/landing/pnpm-lock.yaml new file mode 100644 index 0000000..0f3201c --- /dev/null +++ b/landing/pnpm-lock.yaml @@ -0,0 +1,4023 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@astrojs/check': + specifier: ^0.9.4 + version: 0.9.9(prettier@3.8.3)(typescript@5.9.3) + astro: + specifier: ^5.2.5 + version: 5.18.1(rollup@4.60.4)(typescript@5.9.3)(yaml@2.9.0) + typescript: + specifier: ^5.7.3 + version: 5.9.3 + +packages: + + '@astrojs/check@0.9.9': + resolution: {integrity: sha512-A5UW8uIuErLWEoRQvzgXpO1gTjUFtK8r7nU2Z7GewAMxUb7bPvpk11qaKKgxqXlHJWlAvaaxy+Xg28A6bmQ1Tg==} + hasBin: true + peerDependencies: + typescript: ^5.0.0 || ^6.0.0 + + '@astrojs/compiler@2.13.1': + resolution: {integrity: sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==} + + '@astrojs/internal-helpers@0.7.6': + resolution: {integrity: sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q==} + + '@astrojs/language-server@2.16.9': + resolution: {integrity: sha512-L9kddTg+ZSO3X0Pwfx0ZPO+Z+eSSq0/39jXRyIkHzcBICzusdn2T464R4P6K0WcDZ6pMkLlFpuGS73u1pOnMSw==} + hasBin: true + peerDependencies: + prettier: ^3.0.0 + prettier-plugin-astro: '>=0.11.0' + peerDependenciesMeta: + prettier: + optional: true + prettier-plugin-astro: + optional: true + + '@astrojs/markdown-remark@6.3.11': + resolution: {integrity: sha512-hcaxX/5aC6lQgHeGh1i+aauvSwIT6cfyFjKWvExYSxUhZZBBdvCliOtu06gbQyhbe0pGJNoNmqNlQZ5zYUuIyQ==} + + '@astrojs/prism@3.3.0': + resolution: {integrity: sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} + + '@astrojs/telemetry@3.3.0': + resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} + + '@astrojs/yaml2ts@0.2.4': + resolution: {integrity: sha512-8oddpOae35pJsXPQXhTkM0ypfKPskVsh2bCxRtbf7e+/Epw2nReakFYpLKjZMEr75CsoF203PMnCocpfz0s69A==} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.3': + resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@capsizecss/unpack@4.0.0': + resolution: {integrity: sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==} + engines: {node: '>=18'} + + '@emmetio/abbreviation@2.3.3': + resolution: {integrity: sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==} + + '@emmetio/css-abbreviation@2.1.8': + resolution: {integrity: sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==} + + '@emmetio/css-parser@0.4.1': + resolution: {integrity: sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ==} + + '@emmetio/html-matcher@1.3.0': + resolution: {integrity: sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==} + + '@emmetio/scanner@1.0.4': + resolution: {integrity: sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==} + + '@emmetio/stream-reader-utils@0.1.0': + resolution: {integrity: sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==} + + '@emmetio/stream-reader@2.2.0': + resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@oslojs/encoding@1.1.0': + resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.60.4': + resolution: {integrity: sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.60.4': + resolution: {integrity: sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.60.4': + resolution: {integrity: sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.60.4': + resolution: {integrity: sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.60.4': + resolution: {integrity: sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.60.4': + resolution: {integrity: sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.60.4': + resolution: {integrity: sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.60.4': + resolution: {integrity: sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.60.4': + resolution: {integrity: sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.60.4': + resolution: {integrity: sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.60.4': + resolution: {integrity: sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.60.4': + resolution: {integrity: sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.60.4': + resolution: {integrity: sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.60.4': + resolution: {integrity: sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.60.4': + resolution: {integrity: sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.60.4': + resolution: {integrity: sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.60.4': + resolution: {integrity: sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.60.4': + resolution: {integrity: sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.60.4': + resolution: {integrity: sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.60.4': + resolution: {integrity: sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.60.4': + resolution: {integrity: sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.60.4': + resolution: {integrity: sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.60.4': + resolution: {integrity: sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.60.4': + resolution: {integrity: sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.60.4': + resolution: {integrity: sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==} + cpu: [x64] + os: [win32] + + '@shikijs/core@3.23.0': + resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==} + + '@shikijs/engine-javascript@3.23.0': + resolution: {integrity: sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==} + + '@shikijs/engine-oniguruma@3.23.0': + resolution: {integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==} + + '@shikijs/langs@3.23.0': + resolution: {integrity: sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==} + + '@shikijs/themes@3.23.0': + resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==} + + '@shikijs/types@3.23.0': + resolution: {integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/nlcst@2.0.3': + resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@ungap/structured-clone@1.3.1': + resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} + + '@volar/kit@2.4.28': + resolution: {integrity: sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg==} + peerDependencies: + typescript: '*' + + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + + '@volar/language-server@2.4.28': + resolution: {integrity: sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw==} + + '@volar/language-service@2.4.28': + resolution: {integrity: sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw==} + + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} + + '@volar/typescript@2.4.28': + resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + + '@vscode/emmet-helper@2.11.0': + resolution: {integrity: sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw==} + + '@vscode/l10n@0.0.18': + resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==} + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-iterate@2.0.1: + resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} + + astro@5.18.1: + resolution: {integrity: sha512-m4VWilWZ+Xt6NPoYzC4CgGZim/zQUO7WFL0RHCH0AiEavF1153iC3+me2atDvXpf/yX4PyGUeD8wZLq1cirT3g==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} + hasBin: true + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + base-64@1.0.0: + resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + boxen@8.0.1: + resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==} + engines: {node: '>=18'} + + camelcase@8.0.0: + resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} + engines: {node: '>=16'} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} + + cli-boxes@3.0.0: + resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} + engines: {node: '>=10'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + + common-ancestor-path@1.0.1: + resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} + + cookie-es@1.2.3: + resolution: {integrity: sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==} + + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + + css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + deterministic-object-hash@2.0.2: + resolution: {integrity: sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==} + engines: {node: '>=18'} + + devalue@5.8.1: + resolution: {integrity: sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dset@3.1.4: + resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} + engines: {node: '>=4'} + + emmet@2.4.11: + resolution: {integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==} + + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-uri@3.1.2: + resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + flattie@1.1.1: + resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} + engines: {node: '>=8'} + + fontace@0.4.1: + resolution: {integrity: sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==} + + fontkitten@1.0.3: + resolution: {integrity: sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==} + engines: {node: '>=20'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} + engines: {node: '>=18'} + + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + + h3@1.15.11: + resolution: {integrity: sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==} + + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-raw@9.1.0: + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-parse5@8.0.1: + resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} + + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + + html-escaper@3.0.3: + resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + + import-meta-resolve@4.2.0: + resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} + + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + jsonc-parser@2.3.1: + resolution: {integrity: sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==} + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + lru-cache@11.5.0: + resolution: {integrity: sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==} + engines: {node: 20 || >=22} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + magicast@0.5.3: + resolution: {integrity: sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==} + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + mdast-util-definitions@6.0.0: + resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + neotraverse@0.6.18: + resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==} + engines: {node: '>= 10'} + + nlcst-to-string@4.0.0: + resolution: {integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==} + + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + + node-mock-http@1.0.4: + resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + + oniguruma-parser@0.12.2: + resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==} + + oniguruma-to-es@4.3.6: + resolution: {integrity: sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==} + + p-limit@6.2.0: + resolution: {integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==} + engines: {node: '>=18'} + + p-queue@8.1.1: + resolution: {integrity: sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==} + engines: {node: '>=18'} + + p-timeout@6.1.4: + resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==} + engines: {node: '>=14.16'} + + package-manager-detector@1.6.0: + resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + + parse-latin@7.0.0: + resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + piccolore@0.1.3: + resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} + engines: {node: '>=14'} + hasBin: true + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} + + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + + rehype-parse@9.0.1: + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} + + rehype-raw@7.0.0: + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + + rehype-stringify@10.0.1: + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} + + rehype@13.0.2: + resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-smartypants@3.0.2: + resolution: {integrity: sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==} + engines: {node: '>=16.0.0'} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + request-light@0.5.8: + resolution: {integrity: sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==} + + request-light@0.7.0: + resolution: {integrity: sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + retext-latin@4.0.0: + resolution: {integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==} + + retext-smartypants@6.2.0: + resolution: {integrity: sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==} + + retext-stringify@4.0.0: + resolution: {integrity: sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==} + + retext@9.0.0: + resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==} + + rollup@4.60.4: + resolution: {integrity: sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + sax@1.6.0: + resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} + engines: {node: '>=11.0.0'} + + semver@7.8.1: + resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shiki@3.23.0: + resolution: {integrity: sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + smol-toml@1.6.1: + resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==} + engines: {node: '>= 18'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + svgo@4.0.1: + resolution: {integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==} + engines: {node: '>=16'} + hasBin: true + + tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + + tinyexec@1.2.2: + resolution: {integrity: sha512-M/Q0B2cp4K7kynaT/vnED1j8TlLY+Pp7C6Wl2bl/7u/F0mUVwdyOpwomQb8JpYLitHUssAJRmLZdMCGsrx7i+g==} + engines: {node: '>=18'} + + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + tsconfck@3.1.6: + resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + typesafe-path@0.2.2: + resolution: {integrity: sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==} + + typescript-auto-import-cache@0.3.6: + resolution: {integrity: sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + ultrahtml@1.6.0: + resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==} + + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unifont@0.7.4: + resolution: {integrity: sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==} + + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-modify-children@4.0.0: + resolution: {integrity: sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-remove-position@5.0.0: + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-children@3.0.0: + resolution: {integrity: sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + unstorage@1.17.5: + resolution: {integrity: sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6 || ^7 || ^8 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1 || ^2 || ^3 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite@6.4.2: + resolution: {integrity: sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + 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 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitefu@1.1.3: + resolution: {integrity: sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + vite: + optional: true + + volar-service-css@0.0.70: + resolution: {integrity: sha512-K1qyOvBpE3rzdAv3e4/6Rv5yizrYPy5R/ne3IWCAzLBuMO4qBMV3kSqWzj6KUVe6S0AnN6wxF7cRkiaKfYMYJw==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-emmet@0.0.70: + resolution: {integrity: sha512-xi5bC4m/VyE3zy/n2CXspKeDZs3qA41tHLTw275/7dNWM/RqE2z3BnDICQybHIVp/6G1iOQj5c1qXMgQC08TNg==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-html@0.0.70: + resolution: {integrity: sha512-eR6vCgMdmYAo4n+gcT7DSyBQbwB8S3HZZvSagTf0sxNaD4WppMCFfpqWnkrlGStPKMZvMiejRRVmqsX9dYcTvQ==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-prettier@0.0.70: + resolution: {integrity: sha512-Z6BCFSpGVCd8BPAsZ785Kce1BGlWd5ODqmqZGVuB14MJvrR4+CYz6cDy4F+igmE1gMifqfvMhdgT8Aud4M5ngg==} + peerDependencies: + '@volar/language-service': ~2.4.0 + prettier: ^2.2 || ^3.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + prettier: + optional: true + + volar-service-typescript-twoslash-queries@0.0.70: + resolution: {integrity: sha512-IdD13Z9N2Bu8EM6CM0fDV1E69olEYGHDU25X51YXmq8Y0CmJ2LNj6gOiBJgpS5JGUqFzECVhMNBW7R0sPdRTMQ==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-typescript@0.0.70: + resolution: {integrity: sha512-l46Bx4cokkUedTd74ojO5H/zqHZJ8SUuyZ0IB8JN4jfRqUM3bQFBHoOwlZCyZmOeO0A3RQNkMnFclxO4c++gsg==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-yaml@0.0.70: + resolution: {integrity: sha512-0c8bXDBeoATF9F6iPIlOuYTuZAC4c+yi0siQo920u7eiBJk8oQmUmg9cDUbR4+Gl++bvGP4plj3fErbJuPqdcQ==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + vscode-css-languageservice@6.3.10: + resolution: {integrity: sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA==} + + vscode-html-languageservice@5.6.2: + resolution: {integrity: sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg==} + + vscode-json-languageservice@4.1.8: + resolution: {integrity: sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==} + engines: {npm: '>=7.0.0'} + + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-nls@5.2.0: + resolution: {integrity: sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==} + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + + which-pm-runs@1.1.0: + resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==} + engines: {node: '>=4'} + + widest-line@5.0.0: + resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} + engines: {node: '>=18'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + + xxhash-wasm@1.1.0: + resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yaml-language-server@1.20.0: + resolution: {integrity: sha512-qhjK/bzSRZ6HtTvgeFvjNPJGWdZ0+x5NREV/9XZWFjIGezew2b4r5JPy66IfOhd5OA7KeFwk1JfmEbnTvev0cA==} + hasBin: true + + yaml@2.7.1: + resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==} + engines: {node: '>= 14'} + hasBin: true + + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + + yocto-spinner@0.2.3: + resolution: {integrity: sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==} + engines: {node: '>=18.19'} + + yoctocolors@2.1.2: + resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} + engines: {node: '>=18'} + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod-to-ts@1.2.0: + resolution: {integrity: sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==} + peerDependencies: + typescript: ^4.9.4 || ^5.0.2 + zod: ^3 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@astrojs/check@0.9.9(prettier@3.8.3)(typescript@5.9.3)': + dependencies: + '@astrojs/language-server': 2.16.9(prettier@3.8.3)(typescript@5.9.3) + chokidar: 4.0.3 + kleur: 4.1.5 + typescript: 5.9.3 + yargs: 17.7.2 + transitivePeerDependencies: + - prettier + - prettier-plugin-astro + + '@astrojs/compiler@2.13.1': {} + + '@astrojs/internal-helpers@0.7.6': {} + + '@astrojs/language-server@2.16.9(prettier@3.8.3)(typescript@5.9.3)': + dependencies: + '@astrojs/compiler': 2.13.1 + '@astrojs/yaml2ts': 0.2.4 + '@jridgewell/sourcemap-codec': 1.5.5 + '@volar/kit': 2.4.28(typescript@5.9.3) + '@volar/language-core': 2.4.28 + '@volar/language-server': 2.4.28 + '@volar/language-service': 2.4.28 + muggle-string: 0.4.1 + tinyglobby: 0.2.16 + volar-service-css: 0.0.70(@volar/language-service@2.4.28) + volar-service-emmet: 0.0.70(@volar/language-service@2.4.28) + volar-service-html: 0.0.70(@volar/language-service@2.4.28) + volar-service-prettier: 0.0.70(@volar/language-service@2.4.28)(prettier@3.8.3) + volar-service-typescript: 0.0.70(@volar/language-service@2.4.28) + volar-service-typescript-twoslash-queries: 0.0.70(@volar/language-service@2.4.28) + volar-service-yaml: 0.0.70(@volar/language-service@2.4.28) + vscode-html-languageservice: 5.6.2 + vscode-uri: 3.1.0 + optionalDependencies: + prettier: 3.8.3 + transitivePeerDependencies: + - typescript + + '@astrojs/markdown-remark@6.3.11': + dependencies: + '@astrojs/internal-helpers': 0.7.6 + '@astrojs/prism': 3.3.0 + github-slugger: 2.0.0 + hast-util-from-html: 2.0.3 + hast-util-to-text: 4.0.2 + import-meta-resolve: 4.2.0 + js-yaml: 4.1.1 + mdast-util-definitions: 6.0.0 + rehype-raw: 7.0.0 + rehype-stringify: 10.0.1 + remark-gfm: 4.0.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + remark-smartypants: 3.0.2 + shiki: 3.23.0 + smol-toml: 1.6.1 + unified: 11.0.5 + unist-util-remove-position: 5.0.0 + unist-util-visit: 5.1.0 + unist-util-visit-parents: 6.0.2 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@astrojs/prism@3.3.0': + dependencies: + prismjs: 1.30.0 + + '@astrojs/telemetry@3.3.0': + dependencies: + ci-info: 4.4.0 + debug: 4.4.3 + dlv: 1.1.3 + dset: 3.1.4 + is-docker: 3.0.0 + is-wsl: 3.1.1 + which-pm-runs: 1.1.0 + transitivePeerDependencies: + - supports-color + + '@astrojs/yaml2ts@0.2.4': + dependencies: + yaml: 2.9.0 + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/parser@7.29.3': + dependencies: + '@babel/types': 7.29.0 + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@capsizecss/unpack@4.0.0': + dependencies: + fontkitten: 1.0.3 + + '@emmetio/abbreviation@2.3.3': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/css-abbreviation@2.1.8': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/css-parser@0.4.1': + dependencies: + '@emmetio/stream-reader': 2.2.0 + '@emmetio/stream-reader-utils': 0.1.0 + + '@emmetio/html-matcher@1.3.0': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/scanner@1.0.4': {} + + '@emmetio/stream-reader-utils@0.1.0': {} + + '@emmetio/stream-reader@2.2.0': {} + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + + '@img/colour@1.1.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.10.0 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@oslojs/encoding@1.1.0': {} + + '@rollup/pluginutils@5.3.0(rollup@4.60.4)': + dependencies: + '@types/estree': 1.0.9 + estree-walker: 2.0.2 + picomatch: 4.0.4 + optionalDependencies: + rollup: 4.60.4 + + '@rollup/rollup-android-arm-eabi@4.60.4': + optional: true + + '@rollup/rollup-android-arm64@4.60.4': + optional: true + + '@rollup/rollup-darwin-arm64@4.60.4': + optional: true + + '@rollup/rollup-darwin-x64@4.60.4': + optional: true + + '@rollup/rollup-freebsd-arm64@4.60.4': + optional: true + + '@rollup/rollup-freebsd-x64@4.60.4': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.60.4': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.60.4': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-x64-musl@4.60.4': + optional: true + + '@rollup/rollup-openbsd-x64@4.60.4': + optional: true + + '@rollup/rollup-openharmony-arm64@4.60.4': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.60.4': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.60.4': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.60.4': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.60.4': + optional: true + + '@shikijs/core@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.6 + + '@shikijs/engine-oniguruma@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + + '@shikijs/themes@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + + '@shikijs/types@3.23.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree@1.0.8': {} + + '@types/estree@1.0.9': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + + '@types/nlcst@2.0.3': + dependencies: + '@types/unist': 3.0.3 + + '@types/unist@3.0.3': {} + + '@ungap/structured-clone@1.3.1': {} + + '@volar/kit@2.4.28(typescript@5.9.3)': + dependencies: + '@volar/language-service': 2.4.28 + '@volar/typescript': 2.4.28 + typesafe-path: 0.2.2 + typescript: 5.9.3 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + '@volar/language-core@2.4.28': + dependencies: + '@volar/source-map': 2.4.28 + + '@volar/language-server@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + '@volar/language-service': 2.4.28 + '@volar/typescript': 2.4.28 + path-browserify: 1.0.1 + request-light: 0.7.0 + vscode-languageserver: 9.0.1 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + '@volar/language-service@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + '@volar/source-map@2.4.28': {} + + '@volar/typescript@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + + '@vscode/emmet-helper@2.11.0': + dependencies: + emmet: 2.4.11 + jsonc-parser: 2.3.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + + '@vscode/l10n@0.0.18': {} + + acorn@8.16.0: {} + + ajv-draft-04@1.0.0(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.2 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-align@3.0.1: + dependencies: + string-width: 4.2.3 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + array-iterate@2.0.1: {} + + astro@5.18.1(rollup@4.60.4)(typescript@5.9.3)(yaml@2.9.0): + dependencies: + '@astrojs/compiler': 2.13.1 + '@astrojs/internal-helpers': 0.7.6 + '@astrojs/markdown-remark': 6.3.11 + '@astrojs/telemetry': 3.3.0 + '@capsizecss/unpack': 4.0.0 + '@oslojs/encoding': 1.1.0 + '@rollup/pluginutils': 5.3.0(rollup@4.60.4) + acorn: 8.16.0 + aria-query: 5.3.2 + axobject-query: 4.1.0 + boxen: 8.0.1 + ci-info: 4.4.0 + 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.8.1 + diff: 8.0.4 + dlv: 1.1.3 + dset: 3.1.4 + es-module-lexer: 1.7.0 + esbuild: 0.27.7 + estree-walker: 3.0.3 + flattie: 1.1.1 + fontace: 0.4.1 + 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.3 + 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.4 + prompts: 2.4.2 + rehype: 13.0.2 + semver: 7.8.1 + shiki: 3.23.0 + smol-toml: 1.6.1 + svgo: 4.0.1 + tinyexec: 1.2.2 + tinyglobby: 0.2.16 + tsconfck: 3.1.6(typescript@5.9.3) + ultrahtml: 1.6.0 + unifont: 0.7.4 + unist-util-visit: 5.1.0 + unstorage: 1.17.5 + vfile: 6.0.3 + vite: 6.4.2(yaml@2.9.0) + vitefu: 1.1.3(vite@6.4.2(yaml@2.9.0)) + 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.2(zod@3.25.76) + zod-to-ts: 1.2.0(typescript@5.9.3)(zod@3.25.76) + optionalDependencies: + sharp: 0.34.5 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@types/node' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - idb-keyval + - ioredis + - jiti + - less + - lightningcss + - rollup + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - uploadthing + - yaml + + axobject-query@4.1.0: {} + + bail@2.0.2: {} + + base-64@1.0.0: {} + + boolbase@1.0.0: {} + + boxen@8.0.1: + dependencies: + ansi-align: 3.0.1 + camelcase: 8.0.0 + chalk: 5.6.2 + cli-boxes: 3.0.0 + string-width: 7.2.0 + type-fest: 4.41.0 + widest-line: 5.0.0 + wrap-ansi: 9.0.2 + + camelcase@8.0.0: {} + + ccount@2.0.1: {} + + chalk@5.6.2: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 + + ci-info@4.4.0: {} + + cli-boxes@3.0.0: {} + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + comma-separated-tokens@2.0.3: {} + + commander@11.1.0: {} + + common-ancestor-path@1.0.1: {} + + cookie-es@1.2.3: {} + + cookie@1.1.1: {} + + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + + css-what@6.2.2: {} + + cssesc@3.0.0: {} + + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + + defu@6.1.7: {} + + dequal@2.0.3: {} + + destr@2.0.5: {} + + detect-libc@2.1.2: + optional: true + + deterministic-object-hash@2.0.2: + dependencies: + base-64: 1.0.0 + + devalue@5.8.1: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + diff@8.0.4: {} + + dlv@1.1.3: {} + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dset@3.1.4: {} + + emmet@2.4.11: + dependencies: + '@emmetio/abbreviation': 2.3.3 + '@emmetio/css-abbreviation': 2.1.8 + + emoji-regex@10.6.0: {} + + emoji-regex@8.0.0: {} + + entities@4.5.0: {} + + entities@6.0.1: {} + + es-module-lexer@1.7.0: {} + + 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 + + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + + escalade@3.2.0: {} + + escape-string-regexp@5.0.0: {} + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + eventemitter3@5.0.4: {} + + extend@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-uri@3.1.2: {} + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + flattie@1.1.1: {} + + fontace@0.4.1: + dependencies: + fontkitten: 1.0.3 + + fontkitten@1.0.3: + dependencies: + tiny-inflate: 1.0.3 + + fsevents@2.3.3: + optional: true + + get-caller-file@2.0.5: {} + + get-east-asian-width@1.6.0: {} + + github-slugger@2.0.0: {} + + h3@1.15.11: + dependencies: + cookie-es: 1.2.3 + crossws: 0.3.5 + defu: 6.1.7 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.4 + radix3: 1.1.2 + ufo: 1.6.4 + uncrypto: 0.1.3 + + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-raw@9.1.0: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + '@ungap/structured-clone': 1.3.1 + hast-util-from-parse5: 8.0.3 + hast-util-to-parse5: 8.0.1 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-parse5@8.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + + html-escaper@3.0.3: {} + + html-void-elements@3.0.0: {} + + http-cache-semantics@4.2.0: {} + + import-meta-resolve@4.2.0: {} + + iron-webcrypto@1.2.1: {} + + is-docker@3.0.0: {} + + is-fullwidth-code-point@3.0.0: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + + is-plain-obj@4.1.0: {} + + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + json-schema-traverse@1.0.0: {} + + jsonc-parser@2.3.1: {} + + jsonc-parser@3.3.1: {} + + kleur@3.0.3: {} + + kleur@4.1.5: {} + + longest-streak@3.1.0: {} + + lru-cache@11.5.0: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magicast@0.5.3: + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + source-map-js: 1.2.1 + + markdown-table@3.0.4: {} + + mdast-util-definitions@6.0.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.3: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.1 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + mdn-data@2.0.28: {} + + mdn-data@2.27.1: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + mrmime@2.0.1: {} + + ms@2.1.3: {} + + muggle-string@0.4.1: {} + + nanoid@3.3.12: {} + + neotraverse@0.6.18: {} + + nlcst-to-string@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + + node-fetch-native@1.6.7: {} + + node-mock-http@1.0.4: {} + + normalize-path@3.0.0: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + ofetch@1.5.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.4 + + ohash@2.0.11: {} + + oniguruma-parser@0.12.2: {} + + oniguruma-to-es@4.3.6: + dependencies: + oniguruma-parser: 0.12.2 + regex: 6.1.0 + regex-recursion: 6.0.2 + + p-limit@6.2.0: + dependencies: + yocto-queue: 1.2.2 + + p-queue@8.1.1: + dependencies: + eventemitter3: 5.0.4 + p-timeout: 6.1.4 + + p-timeout@6.1.4: {} + + package-manager-detector@1.6.0: {} + + parse-latin@7.0.0: + dependencies: + '@types/nlcst': 2.0.3 + '@types/unist': 3.0.3 + nlcst-to-string: 4.0.0 + unist-util-modify-children: 4.0.0 + unist-util-visit-children: 3.0.0 + vfile: 6.0.3 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + path-browserify@1.0.1: {} + + piccolore@0.1.3: {} + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.4: {} + + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prettier@3.8.3: {} + + prismjs@1.30.0: {} + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + property-information@7.1.0: {} + + radix3@1.1.2: {} + + readdirp@4.1.2: {} + + readdirp@5.0.0: {} + + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + + rehype-parse@9.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-html: 2.0.3 + unified: 11.0.5 + + rehype-raw@7.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-raw: 9.1.0 + vfile: 6.0.3 + + rehype-stringify@10.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + unified: 11.0.5 + + rehype@13.0.2: + dependencies: + '@types/hast': 3.0.4 + rehype-parse: 9.0.1 + rehype-stringify: 10.0.1 + unified: 11.0.5 + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-smartypants@3.0.2: + dependencies: + retext: 9.0.0 + retext-smartypants: 6.2.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + request-light@0.5.8: {} + + request-light@0.7.0: {} + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + retext-latin@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + parse-latin: 7.0.0 + unified: 11.0.5 + + retext-smartypants@6.2.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unist-util-visit: 5.1.0 + + retext-stringify@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unified: 11.0.5 + + retext@9.0.0: + dependencies: + '@types/nlcst': 2.0.3 + retext-latin: 4.0.0 + retext-stringify: 4.0.0 + unified: 11.0.5 + + rollup@4.60.4: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.60.4 + '@rollup/rollup-android-arm64': 4.60.4 + '@rollup/rollup-darwin-arm64': 4.60.4 + '@rollup/rollup-darwin-x64': 4.60.4 + '@rollup/rollup-freebsd-arm64': 4.60.4 + '@rollup/rollup-freebsd-x64': 4.60.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.4 + '@rollup/rollup-linux-arm-musleabihf': 4.60.4 + '@rollup/rollup-linux-arm64-gnu': 4.60.4 + '@rollup/rollup-linux-arm64-musl': 4.60.4 + '@rollup/rollup-linux-loong64-gnu': 4.60.4 + '@rollup/rollup-linux-loong64-musl': 4.60.4 + '@rollup/rollup-linux-ppc64-gnu': 4.60.4 + '@rollup/rollup-linux-ppc64-musl': 4.60.4 + '@rollup/rollup-linux-riscv64-gnu': 4.60.4 + '@rollup/rollup-linux-riscv64-musl': 4.60.4 + '@rollup/rollup-linux-s390x-gnu': 4.60.4 + '@rollup/rollup-linux-x64-gnu': 4.60.4 + '@rollup/rollup-linux-x64-musl': 4.60.4 + '@rollup/rollup-openbsd-x64': 4.60.4 + '@rollup/rollup-openharmony-arm64': 4.60.4 + '@rollup/rollup-win32-arm64-msvc': 4.60.4 + '@rollup/rollup-win32-ia32-msvc': 4.60.4 + '@rollup/rollup-win32-x64-gnu': 4.60.4 + '@rollup/rollup-win32-x64-msvc': 4.60.4 + fsevents: 2.3.3 + + sax@1.6.0: {} + + semver@7.8.1: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.1 + 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 + optional: true + + shiki@3.23.0: + dependencies: + '@shikijs/core': 3.23.0 + '@shikijs/engine-javascript': 3.23.0 + '@shikijs/engine-oniguruma': 3.23.0 + '@shikijs/langs': 3.23.0 + '@shikijs/themes': 3.23.0 + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + sisteransi@1.0.5: {} + + smol-toml@1.6.1: {} + + source-map-js@1.2.1: {} + + space-separated-tokens@2.0.2: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.6.0 + strip-ansi: 7.2.0 + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + + svgo@4.0.1: + dependencies: + commander: 11.1.0 + css-select: 5.2.2 + css-tree: 3.2.1 + css-what: 6.2.2 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.6.0 + + tiny-inflate@1.0.3: {} + + tinyexec@1.2.2: {} + + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + trim-lines@3.0.1: {} + + trough@2.2.0: {} + + tsconfck@3.1.6(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + + tslib@2.8.1: + optional: true + + type-fest@4.41.0: {} + + typesafe-path@0.2.2: {} + + typescript-auto-import-cache@0.3.6: + dependencies: + semver: 7.8.1 + + typescript@5.9.3: {} + + ufo@1.6.4: {} + + ultrahtml@1.6.0: {} + + uncrypto@0.1.3: {} + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unifont@0.7.4: + dependencies: + css-tree: 3.2.1 + ofetch: 1.5.1 + ohash: 2.0.11 + + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-modify-children@4.0.0: + dependencies: + '@types/unist': 3.0.3 + array-iterate: 2.0.1 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-remove-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-children@3.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unstorage@1.17.5: + dependencies: + anymatch: 3.1.3 + chokidar: 5.0.0 + destr: 2.0.5 + h3: 1.15.11 + lru-cache: 11.5.0 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.4 + + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite@6.4.2(yaml@2.9.0): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + postcss: 8.5.15 + rollup: 4.60.4 + tinyglobby: 0.2.16 + optionalDependencies: + fsevents: 2.3.3 + yaml: 2.9.0 + + vitefu@1.1.3(vite@6.4.2(yaml@2.9.0)): + optionalDependencies: + vite: 6.4.2(yaml@2.9.0) + + volar-service-css@0.0.70(@volar/language-service@2.4.28): + dependencies: + vscode-css-languageservice: 6.3.10 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-emmet@0.0.70(@volar/language-service@2.4.28): + dependencies: + '@emmetio/css-parser': 0.4.1 + '@emmetio/html-matcher': 1.3.0 + '@vscode/emmet-helper': 2.11.0 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-html@0.0.70(@volar/language-service@2.4.28): + dependencies: + vscode-html-languageservice: 5.6.2 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-prettier@0.0.70(@volar/language-service@2.4.28)(prettier@3.8.3): + dependencies: + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + prettier: 3.8.3 + + volar-service-typescript-twoslash-queries@0.0.70(@volar/language-service@2.4.28): + dependencies: + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-typescript@0.0.70(@volar/language-service@2.4.28): + dependencies: + path-browserify: 1.0.1 + semver: 7.8.1 + typescript-auto-import-cache: 0.3.6 + vscode-languageserver-textdocument: 1.0.12 + vscode-nls: 5.2.0 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-yaml@0.0.70(@volar/language-service@2.4.28): + dependencies: + vscode-uri: 3.1.0 + yaml-language-server: 1.20.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + vscode-css-languageservice@6.3.10: + dependencies: + '@vscode/l10n': 0.0.18 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + + vscode-html-languageservice@5.6.2: + dependencies: + '@vscode/l10n': 0.0.18 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + + vscode-json-languageservice@4.1.8: + dependencies: + jsonc-parser: 3.3.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-nls: 5.2.0 + vscode-uri: 3.1.0 + + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-nls@5.2.0: {} + + vscode-uri@3.1.0: {} + + web-namespaces@2.0.1: {} + + which-pm-runs@1.1.0: {} + + widest-line@5.0.0: + dependencies: + string-width: 7.2.0 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.2.0 + + xxhash-wasm@1.1.0: {} + + y18n@5.0.8: {} + + yaml-language-server@1.20.0: + dependencies: + '@vscode/l10n': 0.0.18 + ajv: 8.20.0 + ajv-draft-04: 1.0.0(ajv@8.20.0) + prettier: 3.8.3 + request-light: 0.5.8 + vscode-json-languageservice: 4.1.8 + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + yaml: 2.7.1 + + yaml@2.7.1: {} + + yaml@2.9.0: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yocto-queue@1.2.2: {} + + yocto-spinner@0.2.3: + dependencies: + yoctocolors: 2.1.2 + + yoctocolors@2.1.2: {} + + zod-to-json-schema@3.25.2(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod-to-ts@1.2.0(typescript@5.9.3)(zod@3.25.76): + dependencies: + typescript: 5.9.3 + zod: 3.25.76 + + zod@3.25.76: {} + + zwitch@2.0.4: {} diff --git a/landing/public/.gitkeep b/landing/public/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/landing/public/logo.png b/landing/public/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..86dbead3551a9fc26a6b3447cb89f05e7f0207d2 GIT binary patch literal 14656 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 + + + + + {site.name} — join the server + + + + +
+
+ +

{site.name}

+

{site.tagline}

+

+ Server + {site.serverAddress} + +

+
+ +
    +
  1. +

    1 Download the launcher

    +

    Grab {launcher.name} for your system.

    +
    + {launcher.downloads.map((d) => ( + + {d.os} + {d.hint} + + ))} +
    +
  2. + +
  3. +

    2 Add your account

    +

    In the launcher, add an authlib-injector account using this URL:

    +

    + {site.authlibUrl} + +

    +

    + Need credentials? Register at {site.authUrl}, then log in + with that username and password. +

    +
  4. + +
  5. +

    3 Import the modpack

    +

    Add a new instance from this packwiz URL:

    +

    + {site.packwizUrl} + +

    +
  6. + +
  7. +

    4 Connect

    +

    Launch the instance, add a server, and join:

    +

    + {site.serverAddress} + +

    +
  8. +
+ +
+

{site.name} · {site.baseDomain}

+
+
+ + + + + + diff --git a/landing/tsconfig.json b/landing/tsconfig.json new file mode 100644 index 0000000..376b772 --- /dev/null +++ b/landing/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "astro/tsconfigs/strict", + "include": [".astro/types.d.ts", "**/*"], + "exclude": ["dist", "../www"] +} diff --git a/plan/00-overview.md b/plan/00-overview.md new file mode 100644 index 0000000..de3d165 --- /dev/null +++ b/plan/00-overview.md @@ -0,0 +1,122 @@ +# Ulicraft Server — Plan Overview + +Self-hosted modded Minecraft LAN-party stack, designed to run **fully offline** +(air-gapped) during the party while remaining a persistent homelab service. + +## Single source of configuration + +Everything is driven by two env vars in `.env`: + +``` +BASE_DOMAIN=ulicraft.local # all services are subdomains of this +HOST_LAN_IP=192.168.x.x # the Docker host's LAN IP (dnsmasq target) +``` + +> `.local` collides with mDNS/Bonjour (RFC 6762). macOS + Linux Avahi may resolve +> `*.local` via multicast and bypass dnsmasq. Accepted risk for now; alternatives +> if it bites: `.lan`, `home.arpa`. Flagged, user chose `.local`. + +## Subdomain / ingress map + +``` +ulicraft.local → caddy → landing page (launcher downloads + guide) +auth.ulicraft.local → caddy → drasl:25585 (auth web UI + Yggdrasil API) +packwiz.ulicraft.local → caddy → /srv/pack (pack metadata + mod-jar mirror) +assets.ulicraft.local → caddy → /srv/assets (MC asset-object mirror; HTTPS forced — see 10) +mc.ulicraft.local:25565 → minecraft (NOT http; raw MC protocol) +``` + +Caddy is the only HTTP ingress (plain `:80` for now, TLS/step-ca later). +drasl's host port is removed — internal only, reached through Caddy. + +### Internal resolution trick + +Containers use the Docker resolver, NOT dnsmasq. Caddy gets network aliases so +the stack resolves its own subdomains internally: + +```yaml +caddy: + networks: + mcnet: + aliases: [ "auth.${BASE_DOMAIN}", "packwiz.${BASE_DOMAIN}" ] +``` + +Result: `http://auth.ulicraft.local/authlib-injector` and +`http://packwiz.ulicraft.local/pack.toml` resolve identically inside and outside +the stack. dnsmasq exists **only for guest laptops**. + +## Online vs offline split + +``` +PRE-PARTY (internet, run once): + 1. curate packwiz pack → see 04-packwiz.md + 2. mirror mod jars + rewrite URLs → tooling/mirror-mods.sh (08-tooling.md) + 3. pre-bake server volume → TYPE=NEOFORGE install (05-minecraft.md) + 4. download launcher releases → tooling/fetch-launcher.sh (06-launcher.md) + 5. capture+mirror client air-gap → tooling/mirror-airgap.sh (11-full-airgap-mirror.md) + 6. build landing page → cd landing && pnpm run build → www/ (09-landing.md) + 7. render configs from templates → tooling/render-config.sh (08-tooling.md) + +PARTY (air-gapped): + dnsmasq : *.ulicraft.local → HOST_LAN_IP + caddy : local CDN + landing page + drasl : password login (NO Keycloak/OIDC for now) + minecraft: TYPE=CUSTOM, no Mojang re-resolution + guests : install Fjord launcher, import pack, add authlib account → auth subdomain +``` + +## Why each hard call was made + +- **No OIDC/Keycloak (for now)** — drasl password login. Keycloak left out of this + stack's scope. Re-add later if desired. +- **itzg can't air-gap-boot in NEOFORGE mode** (re-resolves Mojang metadata every + start, issue #2340). Pre-bake then switch to `TYPE=CUSTOM`. +- **packwiz only serves metadata** — `.pw.toml` points at Modrinth CDN. Offline + needs jars mirrored onto Caddy + URL rewrite. +- **Fjord launcher** has authlib-injector built in → no manual JVM agent on clients. + +## Target folder layout + +``` +. +├── docker-compose.yml +├── .env / .env.example # BASE_DOMAIN, HOST_LAN_IP, RCON_PASSWORD +├── caddy/Caddyfile # {$BASE_DOMAIN} vhosts + landing page +├── dnsmasq/dnsmasq.conf.tmpl # wildcard template +├── drasl/config/ +│ ├── config.toml.tmpl # envsubst source +│ └── config.toml # generated (gitignored) +├── pack/ # packwiz source of truth +├── mirror/ # vendored mod jars + launcher releases (gitignored) +├── runtime/ # authlib-injector.jar (legacy; may be unused w/ Fjord) +├── tooling/ +│ ├── render-config.sh # envsubst templates → real configs, halt if unset +│ ├── mirror-mods.sh # vendor mod jars + rewrite .pw.toml URLs +│ ├── mirror-assets.sh # mirror MC asset objects for offline clients (10) +│ └── fetch-launcher.sh # download all Fjord release assets +├── landing/ # Astro+TS landing source (build → www/) +│ ├── astro.config.mjs # outDir ../www +│ ├── public/logo.png # stone 3D logo +│ └── src/{data/site.ts,pages/index.astro} +├── www/ # caddy landing page — GENERATED by landing build (gitignored) +├── backups/ +└── plan/ # these files +``` + +## Service plan files + +- `01-dnsmasq.md` — LAN wildcard DNS +- `02-caddy.md` — ingress + local CDN + landing page +- `03-drasl.md` — auth (password login) +- `04-packwiz.md` — modpack source + mod mirror +- `05-minecraft.md` — itzg NeoForge server + offline launch +- `06-launcher.md` — Fjord launcher fetch + distribution +- `07-mc-backup.md` — world backups +- `08-tooling.md` — render/mirror/fetch scripts +- `09-landing.md` — Astro+TS guest onboarding page → www/ +- `10-assets-mirror.md` — lighter alternative: objects-only Fjord Assets Server override +- `11-full-airgap-mirror.md` — CHOSEN: DNS+TLS transparent mirror for full client air-gap + +## Boot/dependency order + +`dnsmasq` → `caddy` (aliases) → `drasl` → `minecraft` (depends on drasl + packwiz served by caddy) → `mc-backup`. diff --git a/plan/01-dnsmasq.md b/plan/01-dnsmasq.md new file mode 100644 index 0000000..377d44b --- /dev/null +++ b/plan/01-dnsmasq.md @@ -0,0 +1,57 @@ +# dnsmasq — LAN wildcard DNS + +## Summary + +Provides name resolution for guest laptops so `*.ulicraft.local` resolves to the +Docker host. Replaces the homelab's AdGuard (dropped for the LAN party). Image: +`jpillora/dnsmasq` (dnsmasq wrapped in webproc, optional web UI on :8080). + +Config is a **file**, not env-driven — `/etc/dnsmasq.conf`, standard dnsmasq +format. Rendered from a template by `tooling/render-config.sh`. + +Only guest laptops point their DNS here. Stack-internal resolution is handled by +Docker network aliases on Caddy (see `02-caddy.md`), so dnsmasq is not on the +critical path for the server's own services. + +## Config template + +`dnsmasq/dnsmasq.conf.tmpl`: +``` +# wildcard: every *.ulicraft.local → host LAN IP +address=/${BASE_DOMAIN}/${HOST_LAN_IP} +# upstream optional; party is offline so may be omitted +no-resolv +``` + +### Air-gap spoof records (see 11) + +For full client air-gap, this file also spoofs the real upstream hosts → our +Caddy mirror (`piston-meta`/`piston-data`/`libraries.minecraft.net`/ +`maven.neoforged.net`/`resources.download.minecraft.net`/`meta.prismlauncher.org`). +Full list + rationale in `11-full-airgap-mirror.md`. Keep in sync with the +capture step. Auth hosts (session/textures/api.mojang) are NOT spoofed — drasl +handles those via authlib-injector. + +## Gotcha — port 53 conflict + +Linux Docker hosts usually run `systemd-resolved` bound to `:53`. Publishing +`53:53` will fail with `address already in use`. Resolve by one of: +- Bind dnsmasq only to the LAN IP: publish `${HOST_LAN_IP}:53:53/udp` (+tcp) +- Or disable resolved's stub listener (`DNSStubListener=no`) and restart resolved + +## Gotcha — `.local` / mDNS + +See overview. Avahi may shortcut `*.local` to multicast before hitting dnsmasq. +Test on a macOS client early; if broken, switch `BASE_DOMAIN` to `.lan`. + +## Tasks + +- [ ] Add `dnsmasq` service to `docker-compose.yml` (`jpillora/dnsmasq`) +- [ ] Create `dnsmasq/dnsmasq.conf.tmpl` with wildcard `address=` line +- [ ] Wire `render-config.sh` to emit `dnsmasq/dnsmasq.conf` (gitignored) +- [ ] Decide port-53 strategy (bind to `HOST_LAN_IP` vs disable resolved stub) +- [ ] Publish `53/udp` + `53/tcp`; mount rendered conf read-only +- [ ] Optionally expose webproc UI (8080) behind Caddy as `dns.ulicraft.local` +- [ ] Document guest DNS setting (set DNS server = `HOST_LAN_IP`) +- [ ] Verify `*.local` resolves on Windows + macOS + Linux guests (mDNS check) +- [ ] Add air-gap spoof `address=` records (see 11) once capture confirms the host list diff --git a/plan/02-caddy.md b/plan/02-caddy.md new file mode 100644 index 0000000..1078795 --- /dev/null +++ b/plan/02-caddy.md @@ -0,0 +1,69 @@ +# Caddy — ingress, local CDN, landing page + +## Summary + +Single HTTP ingress for the stack. Three roles: +1. **Reverse proxy** — `auth.ulicraft.local` → drasl. +2. **Local CDN / static** — `packwiz.ulicraft.local` serves pack metadata AND the + mirrored mod jars (offline installs). +3. **Landing page** — apex `ulicraft.local` serves launcher downloads + guest guide. + +Plain `:80` for now (LAN). TLS via step-ca deferred. Image: `caddy:alpine`. +Caddy natively reads `{$BASE_DOMAIN}` env placeholders — no template render needed. + +## Network aliases (internal resolution) + +```yaml +caddy: + networks: + mcnet: + aliases: + - "auth.${BASE_DOMAIN}" + - "packwiz.${BASE_DOMAIN}" +``` +Lets `minecraft` reach `http://auth.ulicraft.local/authlib-injector` and +`http://packwiz.ulicraft.local/pack.toml` without dnsmasq. + +## Caddyfile sketch + +``` +{ + auto_https off +} + +http://{$BASE_DOMAIN} { + root * /srv/www + file_server +} + +http://auth.{$BASE_DOMAIN} { + reverse_proxy drasl:25585 +} + +http://packwiz.{$BASE_DOMAIN} { + root * /srv/pack + file_server browse +} +``` + +Mounts: `./www:/srv/www:ro`, `./pack:/srv/pack:ro`, `./mirror/launcher:/srv/www/launcher:ro`. + +## Notes / risks + +- drasl behind a proxy: docs don't detail `X-Forwarded-*` trust. On plain HTTP LAN + with matching `BaseURL` it should be fine; revisit when TLS is added. +- `file_server browse` gives a directory listing — handy for debugging the pack. +- Mod-jar mirror lives under `/srv/pack/mods/` so packwiz URLs and jars share host. + +## Tasks + +- [ ] Add `caddy` service to `docker-compose.yml`, ports `80:80` (+`443` later) +- [ ] Pass `BASE_DOMAIN` into caddy env +- [ ] Create `caddy/Caddyfile` with apex + auth + packwiz vhosts +- [ ] Add network aliases for `auth.` and `packwiz.` subdomains +- [ ] Mount `./www`, `./pack`, `./mirror/launcher` +- [ ] Confirm reverse_proxy to drasl works (auth web UI loads, Yggdrasil API responds) +- [ ] Verify internal alias resolution from `minecraft` container (curl pack.toml) +- [ ] Air-gap mirror: add per-host `tls internal` vhosts + aliases + mounts (see 11) +- [ ] Export Caddy root CA for guest trust (LAN-party TLS = `tls internal`; step-ca deferred) +- [ ] Defer (reminder): graduate `tls internal` → step-ca for persistent homelab diff --git a/plan/03-drasl.md b/plan/03-drasl.md new file mode 100644 index 0000000..8bf1257 --- /dev/null +++ b/plan/03-drasl.md @@ -0,0 +1,52 @@ +# Drasl — self-hosted auth (Yggdrasil + skins) + +## Summary + +Self-hosted, Yggdrasil-compatible auth + skin server. Drop-in Mojang replacement +via authlib-injector. Image: `unmojang/drasl:latest`. Reached only through Caddy +at `auth.ulicraft.local`; no host port. + +**OIDC/Keycloak is OUT for now** — drasl runs in **password-login** mode +(`AllowPasswordLogin = true`). Admin + guests register with a username/password on +the drasl web UI. Re-introducing Keycloak OIDC later is a future task. + +Config is **TOML only** (no env var support). So `config.toml` is rendered from +`config.toml.tmpl` by `tooling/render-config.sh` to inject `BASE_DOMAIN`. + +## config.toml.tmpl (key fields) + +```toml +BaseURL = "http://auth.${BASE_DOMAIN}" +Domain = "auth.${BASE_DOMAIN}" +ListenAddress = "0.0.0.0:25585" # internal; Caddy proxies +DefaultAdminUsernames = ["admin"] + +AllowPasswordLogin = true + +[ApplicationOwner] +# ... + +# OIDC block intentionally omitted for now (no Keycloak). +# [[RegistrationOIDC]] ← future +``` + +## Critical gotchas (carry-over) + +- **1.21+ secure profile**: drasl `SignPublicKeys = false` MUST pair with server + `ENFORCE_SECURE_PROFILE=FALSE`. Linked — both or neither. +- **authlib endpoint** = `BaseURL` + `/authlib-injector` → + `http://auth.ulicraft.local/authlib-injector`. Must match on server and client. + Network alias makes this identical inside/outside the stack. +- **`Domain` affects skins** — if wrong, authlib clients may not see skins. + +## Tasks + +- [ ] Create `drasl/config/config.toml.tmpl` (password-login, no OIDC block) +- [ ] Set `BaseURL`/`Domain` to `auth.${BASE_DOMAIN}`, `ListenAddress 0.0.0.0:25585` +- [ ] Set `SignPublicKeys = false` +- [ ] Wire `render-config.sh` → `drasl/config/config.toml` (gitignored) +- [ ] Remove drasl host port from compose (internal only) +- [ ] Update compose: drasl on `mcnet`, no `25585:25585` publish +- [ ] Bootstrap admin account on first run; create guest accounts +- [ ] Verify authlib endpoint responds through Caddy +- [ ] Future: re-add `[[RegistrationOIDC]]` Keycloak block + secret file diff --git a/plan/04-packwiz.md b/plan/04-packwiz.md new file mode 100644 index 0000000..1dca7b8 --- /dev/null +++ b/plan/04-packwiz.md @@ -0,0 +1,48 @@ +# packwiz — modpack source of truth + offline mod mirror + +## Summary + +`packwiz` (installed at `~/go/bin/packwiz`) authors the modpack. The `./pack` +directory is the **single source of truth** for mods, consumed by both: +- the **server** (itzg `PACKWIZ_URL`), and +- **clients** (Fjord launcher imports the pack / packwiz-installer). + +Caddy serves `./pack` at `packwiz.ulicraft.local`. packwiz only emits **metadata** +(`pack.toml`, `index.toml`, `mods/*.pw.toml`); the `.pw.toml` files reference +Modrinth/CF **CDN URLs**, so true offline requires mirroring jars locally. + +## Behaviors confirmed + +- **Prune**: packwiz-installer tracks a manifest and **removes** client mods no + longer in the index on re-run. (Server side via itzg likewise re-syncs.) +- **Download source**: jars come from CDN URLs in `.pw.toml`, NOT the pack host — + unless URLs are rewritten to the local mirror. +- **itzg side filtering**: itzg downloads **server-side mods only**. Client-only + mods MUST be tagged `side = "client"` (not `both`) or the server may pull and + crash on them. + +## Offline mod mirror (the key work) + +`tooling/mirror-mods.sh` (see `08-tooling.md`): +1. Parse each `mods/*.pw.toml`, download the jar into `./mirror/mods/`. +2. Copy jars into `./pack/mods-files/` (served at `packwiz.ulicraft.local/...`). +3. Rewrite each `[download] url` to point at `http://packwiz.ulicraft.local/...`. +4. `packwiz refresh` to recompute hashes/index. + +Result: server + clients install mods entirely from the LAN. No CDN at party time. + +## NeoForge pinning + +`pack.toml` pins MC `1.21.1` + NeoForge `21.1.x`. Verify exact NeoForge build +against projects.neoforged.net before locking. + +## Tasks + +- [ ] `packwiz init` → `./pack` (MC 1.21.1, modloader neoforge, pinned version) +- [ ] Curate mod shortlist (perf/tech/magic/storage/QoL/worldgen/map/voice) +- [ ] Tag client-only mods `side = "client"` +- [ ] `packwiz refresh`; verify `index.toml` committed (clients fetch it) +- [ ] Write `tooling/mirror-mods.sh` (vendor jars + rewrite URLs + refresh) +- [ ] Point server `PACKWIZ_URL=http://packwiz.ulicraft.local/pack.toml` +- [ ] `.gitignore` the vendored `./mirror/` jars; keep `./pack/*.toml` tracked +- [ ] Test offline install end-to-end (cut internet, install on a fresh client) diff --git a/plan/05-minecraft.md b/plan/05-minecraft.md new file mode 100644 index 0000000..05eb824 --- /dev/null +++ b/plan/05-minecraft.md @@ -0,0 +1,52 @@ +# Minecraft server — itzg NeoForge + offline launch + +## Summary + +`itzg/minecraft-server:java21`, NeoForge 1.21.1, offline-mode + authlib-injector +pointing at drasl. Mods via `PACKWIZ_URL`. The challenge: **itzg re-resolves Mojang +version metadata on every boot** (issue #2340), so it cannot air-gap-boot in +`TYPE=NEOFORGE` mode. Solved with a pre-bake + custom-launch switch. + +## Offline strategy (two phases) + +**Phase 1 — pre-bake (online, once):** +``` +TYPE=NEOFORGE, VERSION=1.21.1, NEOFORGE_VERSION=21.1.x +PACKWIZ_URL=http://packwiz.ulicraft.local/pack.toml +``` +Boot once with internet → installs MC + NeoForge + libraries + server mods into +the `mc_data` volume, generates NeoForge's launch args/`run.sh`. + +**Phase 2 — offline launch (party):** +Switch to `TYPE=CUSTOM` + `CUSTOM_SERVER=` pointing at the +already-installed NeoForge launcher in `/data`. A **container path (not URL)** +means no download, no Mojang resolution → boots air-gapped, survives restarts. + +> OPEN: NeoForge 1.21.1 launches via `@libraries/.../unix_args.txt` / `run.sh`, +> not a single fat jar. Exact `CUSTOM_SERVER` target + any `EXTRA_ARGS` must be +> verified against a real pre-baked volume. Tracked as a task. + +## Auth / config (carry-over) + +``` +ONLINE_MODE=FALSE +ENFORCE_SECURE_PROFILE=FALSE # pairs with drasl SignPublicKeys=false +JVM_OPTS=-javaagent:/extras/authlib-injector.jar=http://auth.${BASE_DOMAIN}/authlib-injector +``` +authlib URL uses the `auth` subdomain; resolves internally via Caddi alias. +(Server still needs the agent even though Fjord clients have it built in.) + +Memory: `INIT_MEMORY 4G`, `MAX_MEMORY 10G`, `USE_AIKAR_FLAGS TRUE`. +RCON enabled for mc-backup. + +## Tasks + +- [ ] Compose: switch authlib URL to `http://auth.${BASE_DOMAIN}/authlib-injector` +- [ ] Compose: replace `MODRINTH_PROJECTS` with `PACKWIZ_URL` (packwiz subdomain) +- [ ] Mount renamed `./runtime` (was `./extras`) for authlib-injector.jar +- [ ] `depends_on`: drasl + caddy (pack served before server installs) +- [ ] Pre-bake the volume online; snapshot it +- [ ] Identify exact NeoForge launch target for `TYPE=CUSTOM` / `CUSTOM_SERVER` +- [ ] Add a documented "offline mode" compose override (`docker-compose.offline.yml`?) +- [ ] Verify air-gapped boot: cut internet, restart container, server comes up +- [ ] Confirm `ENFORCE_SECURE_PROFILE=FALSE` ↔ drasl `SignPublicKeys=false` diff --git a/plan/06-launcher.md b/plan/06-launcher.md new file mode 100644 index 0000000..2fec025 --- /dev/null +++ b/plan/06-launcher.md @@ -0,0 +1,100 @@ +# Launcher — FjordLauncherUnlocked distribution + +## Summary + +Guests use **FjordLauncherUnlocked** (`hero-persson/FjordLauncherUnlocked`) — a +Prism/PolyMC fork with **authlib-injector support built in**. So guests add their +drasl account directly in the launcher (no manual JVM `-javaagent`), import the +modpack, and play. + +We host the launcher installers for **all platforms** on the landing page +(`ulicraft.local`), served by Caddy from `./mirror/launcher/`. A script downloads +the latest release assets ahead of time so the party is fully offline. + +## Release assets (latest = 11.0.2.0) + +Every platform variant is published as a GitHub release asset: +- **Windows**: MSVC + MinGW, each as `.zip`, `Portable .zip`, `Setup .exe`; x64 + arm64 +- **macOS**: `.dmg`, `.zip` +- **Linux**: `.AppImage` (x86_64, aarch64) + `.zsync`, portable `.tar.gz` (Qt6) + +The fetch script grabs **all** assets via the GitHub API (loops +`browser_download_url`). The landing page highlights the common three: Windows +Setup `.exe`, macOS `.dmg`, Linux `.AppImage`. + +## tooling/fetch-launcher.sh + +```bash +#!/usr/bin/env bash +# Download all FjordLauncherUnlocked release assets for offline hosting. +# Halts on any error or ambiguity (no silent partial downloads). +set -euo pipefail + +REPO="hero-persson/FjordLauncherUnlocked" +DEST_ROOT="$(dirname "$0")/../mirror/launcher" +API="https://api.github.com/repos/${REPO}/releases/latest" + +command -v curl >/dev/null || { echo "curl required"; exit 1; } +command -v jq >/dev/null || { echo "jq required"; exit 1; } + +meta="$(curl -fsSL "$API")" +tag="$(jq -r '.tag_name' <<<"$meta")" +[ -n "$tag" ] && [ "$tag" != "null" ] || { echo "no tag_name resolved"; exit 1; } + +dest="${DEST_ROOT}/${tag}" +mkdir -p "$dest" +echo "Fetching FjordLauncher ${tag} → ${dest}" + +mapfile -t urls < <(jq -r '.assets[].browser_download_url' <<<"$meta") +[ "${#urls[@]}" -gt 0 ] || { echo "no assets found"; exit 1; } + +for url in "${urls[@]}"; do + fname="$(basename "$url")" + echo " ↓ ${fname}" + curl -fSL --retry 3 -o "${dest}/${fname}" "$url" +done + +# stable symlink for the landing page to reference +ln -sfn "$tag" "${DEST_ROOT}/latest" +echo "Done. ${#urls[@]} assets in ${dest}" +``` + +Caddy mount: `./mirror/launcher:/srv/www/launcher:ro`. + +### Stable symlinks (so landing links survive version bumps) + +The landing page (`09-landing.md`) links to **fixed** filenames, not versioned +ones. After downloading, `fetch-launcher.sh` must create these symlinks under +`mirror/launcher/latest/` pointing at the real assets: + +- `fjord-windows-setup.exe` → Windows Setup `.exe` (x64) +- `fjord-macos.dmg` → macOS `.dmg` +- `fjord-linux-x86_64.AppImage` → Linux x86_64 `.AppImage` + +Selecting the right asset from the release list needs filename matching (the +upstream names carry MSVC/MinGW/arch/version). Match cautiously; halt if a +category resolves to 0 or >1 candidate rather than guessing. **Names must stay in +sync with `landing/src/data/site.ts`.** + +## Per-guest flow + +1. Open `http://ulicraft.local`, download launcher for their OS, install. +2. Add account: authlib-injector type, URL + `http://auth.ulicraft.local/authlib-injector`, drasl username/password. +3. (Offline) Settings → APIs → **Assets Server** = + `https://assets.ulicraft.local/` so the heavy asset download comes from the LAN + mirror (see 10-assets-mirror.md). Requires trusting the local CA. +4. Import the modpack (packwiz URL `http://packwiz.ulicraft.local/pack.toml`, + or a shared instance zip). +5. Connect to `mc.ulicraft.local:25565`. + +## Tasks + +- [ ] Create `tooling/fetch-launcher.sh` (above); `chmod +x` +- [ ] Extend script: create stable symlinks (win/mac/linux) in `mirror/launcher/latest/` +- [ ] Run it pre-party while online; verify all assets land in `./mirror/launcher//` +- [ ] `.gitignore` `./mirror/` (done) +- [ ] Landing page DONE — `landing/` Astro project, builds to `www/` (see 09-landing.md) +- [ ] Confirm Fjord authlib-injector account flow against drasl +- [ ] Decide whether to ship a pre-built instance zip vs packwiz URL import +- [ ] Pin a launcher version (don't silently follow `latest` on party day) diff --git a/plan/07-mc-backup.md b/plan/07-mc-backup.md new file mode 100644 index 0000000..d521cf7 --- /dev/null +++ b/plan/07-mc-backup.md @@ -0,0 +1,30 @@ +# mc-backup — world backups + +## Summary + +`itzg/mc-backup` alongside the server, talking via RCON. Snapshots the world every +6h, prunes after 14 days. World-only (no mod jars — mods are reproducible from the +packwiz pack). Unchanged from the original design; lowest-priority service. + +## Config (carry-over) + +```yaml +mc-backup: + image: itzg/mc-backup + environment: + BACKUP_INTERVAL: "6h" + RCON_HOST: "minecraft" + RCON_PASSWORD: ${RCON_PASSWORD} + PRUNE_BACKUPS_DAYS: "14" + TZ: "Europe/Madrid" + volumes: + - mc_data:/data:ro + - ./backups:/backups +``` + +## Tasks + +- [ ] Keep `mc-backup` service on `mcnet`, `depends_on: minecraft` +- [ ] Confirm RCON enabled on server (`ENABLE_RCON`, `RCON_PASSWORD`) +- [ ] Verify `./backups/` is gitignored (already is) +- [ ] Optional: shorter interval / manual `rcon save-all` before risky changes diff --git a/plan/08-tooling.md b/plan/08-tooling.md new file mode 100644 index 0000000..86e8cd4 --- /dev/null +++ b/plan/08-tooling.md @@ -0,0 +1,77 @@ +# Tooling — config rendering, mod mirror, launcher fetch + +## Summary + +Three scripts in `./tooling/` turn the two env vars + templates into a working, +offline-capable stack. All are **cautious**: they halt on unset vars or missing +inputs rather than emit half-broken output. + +## render-config.sh + +Renders every `*.tmpl` into its real config by substituting `BASE_DOMAIN` / +`HOST_LAN_IP`. Caddy is excluded (it reads `{$BASE_DOMAIN}` natively). + +Targets: +- `drasl/config/config.toml.tmpl` → `drasl/config/config.toml` +- `dnsmasq/dnsmasq.conf.tmpl` → `dnsmasq/dnsmasq.conf` + +```bash +#!/usr/bin/env bash +set -euo pipefail +[ -f .env ] && set -a && . ./.env && set +a +: "${BASE_DOMAIN:?BASE_DOMAIN unset}" +: "${HOST_LAN_IP:?HOST_LAN_IP unset}" + +render() { # $1=tmpl $2=out + [ -f "$1" ] || { echo "missing template: $1"; exit 1; } + envsubst '${BASE_DOMAIN} ${HOST_LAN_IP}' < "$1" > "$2" + echo "rendered $2" +} + +render drasl/config/config.toml.tmpl drasl/config/config.toml +render dnsmasq/dnsmasq.conf.tmpl dnsmasq/dnsmasq.conf +``` + +> Note: `envsubst` with an explicit var list avoids clobbering `$`-syntax that +> belongs to the target file (e.g. dnsmasq/caddy literals). + +## mirror-mods.sh + +Vendors mod jars for offline install and rewrites packwiz URLs to the LAN host. +See `04-packwiz.md`. Outline: +1. For each `pack/mods/*.pw.toml`, read `[download] url` + `filename`. +2. Download jar → `pack/mods-files/` (served by Caddy under packwiz subdomain). +3. Rewrite `url` to `http://packwiz.${BASE_DOMAIN}/mods-files/`. +4. `packwiz refresh` to recompute hashes + `index.toml`. +Must halt if a download fails or a hash mismatches. + +## mirror-assets.sh + +Mirrors Minecraft asset objects for offline clients (the ~400 MB+ chunk) and lays +them out for Caddy + the Fjord "Assets Server" override. Full design in +`10-assets-mirror.md`. Verifies SHA1, idempotent, halts on mismatch. + +## fetch-launcher.sh + +Downloads all FjordLauncherUnlocked release assets → `mirror/launcher//`. +Full script in `06-launcher.md`. + +## Generated / gitignored + +``` +drasl/config/config.toml # rendered +dnsmasq/dnsmasq.conf # rendered +pack/mods-files/ # vendored jars +mirror/ # launcher assets + mod mirror +.env # secrets + host-specific +``` + +## Tasks + +- [ ] Write `tooling/render-config.sh` (above), `chmod +x` +- [ ] Write `tooling/mirror-mods.sh` (toml parse + download + rewrite + refresh) +- [ ] Write `tooling/mirror-assets.sh` (see 10) +- [ ] Write `tooling/fetch-launcher.sh` (see 06) +- [ ] Add `gettext` (envsubst) + `jq` to host prereqs doc +- [ ] Update `.gitignore` for rendered configs + `mirror/` + `pack/mods-files/` +- [ ] `build-stack.sh` orchestrator (preflight + `--prep` online + `--up` offline) — DONE, sequences the sub-scripts; see plan/12 diff --git a/plan/09-landing.md b/plan/09-landing.md new file mode 100644 index 0000000..d8924f4 --- /dev/null +++ b/plan/09-landing.md @@ -0,0 +1,53 @@ +# Landing page — guest onboarding site + +## Summary + +Apex `ulicraft.local` serves a clean static page guiding guests through joining: +download launcher → add account → import modpack → connect. Built with **Astro + +TypeScript** in its own `./landing/` project; `npm run build` emits straight into +`./www/`, which Caddy already serves at the apex domain. No runtime JS framework — +output is plain HTML/CSS plus one tiny copy-to-clipboard script. + +## Stack & wiring + +- `landing/` — Astro project (own `package.json`, `tsconfig`). +- `astro.config.mjs` → `outDir: "../www"`. Build overwrites `www/`; `www/` is + gitignored (generated artifact). +- `BASE_DOMAIN` env read at build time in `src/data/site.ts` + (`process.env.BASE_DOMAIN ?? "ulicraft.local"`). Bake before deploy: + `BASE_DOMAIN=ulicraft.local pnpm run build`. +- Logo: drop PNG at `landing/public/logo.png` → copied to `www/logo.png`, + referenced as `/logo.png` (favicon + hero). `image-rendering: pixelated` keeps + the stone 3D logo crisp. + +## Content (src/data/site.ts is the single source) + +- Hero: logo, name, server address `mc.${BASE_DOMAIN}:25565` (copy button). +- Step 1: launcher downloads — 3 OS buttons → `/launcher/latest/`. +- Step 2: add authlib-injector account, URL `http://auth.${BASE_DOMAIN}/authlib-injector`, + register link to `http://auth.${BASE_DOMAIN}`. +- Step 3: import packwiz `http://packwiz.${BASE_DOMAIN}/pack.toml`. +- Step 4: connect to server address. + +## Launcher download links (Option A — stable symlinks) + +Page links to fixed names so they survive launcher version bumps: +- `fjord-windows-setup.exe` +- `fjord-macos.dmg` +- `fjord-linux-x86_64.AppImage` + +`tooling/fetch-launcher.sh` must create these as symlinks under +`mirror/launcher/latest/` pointing at the real versioned assets. **Keep the names +in sync** between `site.ts` and the script. Caddy mount +`./mirror/launcher:/srv/www/launcher:ro` makes them resolve at `/launcher/latest/…`. + +## Tasks + +- [ ] User: place logo at `landing/public/logo.png` +- [ ] `cd landing && pnpm install` +- [ ] `BASE_DOMAIN=ulicraft.local pnpm run build` → verify `www/index.html` + `www/logo.png` +- [ ] Extend `fetch-launcher.sh`: after download, symlink stable names → versioned files + (resolve which asset = win setup / mac dmg / linux AppImage) +- [ ] Confirm Caddy serves apex from `./www` and `/launcher/latest/*` from mirror +- [ ] Optional: pin launcher tag instead of `latest` for party day +- [ ] Optional: add a "what's in the pack" section once mod list firms up diff --git a/plan/10-assets-mirror.md b/plan/10-assets-mirror.md new file mode 100644 index 0000000..f8a807f --- /dev/null +++ b/plan/10-assets-mirror.md @@ -0,0 +1,114 @@ +# Assets mirror — offline Minecraft asset objects for clients + +## Summary + +Guest launchers (FjordLauncherUnlocked, a Prism soft-fork) download ~400–600 MB of +**asset objects** (textures, sounds, lang) from `resources.download.minecraft.net` +on first instance launch. For an air-gapped party that's the single biggest +client-side download. Fjord/Prism expose an **"Assets Server"** override, so we +mirror the objects onto our host and point guests at it. + +`tooling/mirror-assets.sh` downloads + verifies every asset object for the pinned +Minecraft version and lays them out so Caddy can serve them in the exact path +shape the launcher expects. + +## Fjord/Prism override fields (confirmed) + +Settings → APIs → **Services** tab: + +| Field | Setting key | Default | What it overrides | +|---|---|---|---| +| **Assets Server** | `ResourceURL` | `https://resources.download.minecraft.net/` | asset **objects only** | +| **Metadata Server** | (meta URL) | `https://meta.prismlauncher.org/v1/` | Prism-format version meta | + +- Added in Prism 10.0.0 (PR #3875); inherited by Fjord. +- **There is NO libraries-URL field.** Library + client.jar URLs live inside the + version/meta JSON; only a meta mirror (or DNS spoof) can redirect them. + +### ⚠️ HTTPS is forced + +PR #3875 validates the Assets Server URL as **HTTPS and auto-rewrites `http://` +→ `https://`**. So the assets mirror **must be served over TLS** — plain `:80` +Caddy will not work for this endpoint. This pulls local TLS forward for one +subdomain ahead of the rest of the stack. + +Options to satisfy it: +1. Caddy TLS on `assets.${BASE_DOMAIN}` with a cert from a local CA + (step-ca); guests import the CA root once. Cleanest, matches homelab. +2. Caddy `internal` CA / self-signed — guests must trust it (more friction, per + machine). +3. Sidestep entirely with **pre-seed** (below) and skip the Assets Server override. + +## What this mirror does and does NOT cover + +| Client download | Host | Covered here? | +|---|---|---| +| asset objects (bulk) | resources.download.minecraft.net | ✅ this mirror + Assets Server field | +| asset index json | meta/piston | ⚠️ fetched here for completeness; launcher still pulls it from meta unless meta is also mirrored | +| libraries | libraries.minecraft.net | ❌ no override field | +| client.jar | piston-data.mojang.com | ❌ | +| version/meta json | meta.prismlauncher.org | ❌ (separate Metadata Server field) | + +**Full client air-gap therefore needs more than this.** For the uncovered, small +(~150 MB) remainder, the pragmatic fallback is **pre-seed**: each guest launches +the instance once while online (on arrival, before air-gapping); Prism caches +libraries/jar/meta locally. The assets mirror still saves the heavy 400 MB+ per +guest. A full meta+libraries mirror (mcm-style / PrismLauncher-meta gen) is the +heavyweight alternative, deferred. + +## tooling/mirror-assets.sh — design + +Input: `MC_VERSION` (default `1.21.1`, or read from the pre-baked server's +`version.json`). Cautious: verifies SHA1 on every file, halts on mismatch, +idempotent (skips already-valid files). + +``` +1. GET https://piston-meta.mojang.com/mc/game/version_manifest_v2.json + → find entry for $MC_VERSION → version-json URL +2. GET version-json → read .assetIndex { id, url, sha1 } +3. GET asset index → mirror/assets/indexes/.json (verify sha1) +4. For each object in index .objects{}: + hash=; rel="${hash:0:2}/${hash}" + dest="mirror/assets/objects/${rel}" + [ -f "$dest" ] && sha1 ok → skip + else GET https://resources.download.minecraft.net/${rel} → $dest ; verify sha1 +5. Report counts; non-zero exit on any failure. +``` + +Layout served by Caddy: +``` +mirror/assets/ +├── indexes/.json # e.g. 17.json / 1.21.json (for pre-seed/meta use) +└── objects/<2hex>/ # launcher requests /<2hex>/ +``` + +### Caddy wiring + +Serve the **objects** dir at the web root of an HTTPS vhost so the launcher's +`/<2hex>/` resolves directly: + +``` +https://assets.{$BASE_DOMAIN} { + tls # or `tls internal` + root * /srv/assets/objects + file_server +} +``` +Mount `./mirror/assets/objects:/srv/assets/objects:ro`. Add network alias +`assets.${BASE_DOMAIN}` to Caddy (same trick as auth/packwiz). +Fjord "Assets Server" = `https://assets.${BASE_DOMAIN}/`. + +## Tasks + +- [ ] Write `tooling/mirror-assets.sh` (above); `chmod +x`; deps `curl` + `jq` + `sha1sum` +- [ ] Decide MC_VERSION source: hardcode `1.21.1` vs read pre-baked `version.json` +- [ ] Run pre-party while online; verify `mirror/assets/objects/` populated + sha1 clean +- [ ] Stand up TLS for `assets.${BASE_DOMAIN}` (step-ca or `tls internal`) — REQUIRED (HTTPS forced) +- [ ] Add `assets.` Caddy vhost + network alias + mount +- [ ] Document guest step: Settings → APIs → Assets Server = `https://assets.${BASE_DOMAIN}/` +- [ ] Document guest CA-trust step (import local CA root) if not using a publicly-trusted cert +- [ ] Confirm in Fjord's actual UI that the field exists + HTTPS-forcing behavior matches Prism +- [ ] Fallback path: pre-seed instructions (launch once online) for libraries/jar/meta +- [ ] Defer decision: full meta+libraries mirror (mcm / PrismLauncher-meta) vs pre-seed +- [ ] `.gitignore` already covers `mirror/` +``` diff --git a/plan/11-full-airgap-mirror.md b/plan/11-full-airgap-mirror.md new file mode 100644 index 0000000..24a9f28 --- /dev/null +++ b/plan/11-full-airgap-mirror.md @@ -0,0 +1,132 @@ +# Full client air-gap — DNS + TLS transparent mirror + +## Summary + +Goal: a guest laptop with **zero internet** can install + launch the modded +instance entirely from the LAN. The chosen architecture is a **transparent +mirror**: dnsmasq points the real upstream hostnames at our host, Caddy serves +byte-exact copies of the files at the same paths, and `tls internal` mints certs +those hostnames validate against (guests trust the Caddy root CA once). + +The launcher is **unmodified** — it requests the real Mojang/Prism/NeoForge URLs; +DNS just resolves them to us. This is cleaner than rewriting Prism-format +metadata, and it makes the `10-assets-mirror.md` "Assets Server" field +**redundant** (the launcher hits the real resources host, which now resolves to +the LAN). `10` is kept as the lighter objects-only alternative. + +## Decision record + +- **TLS for LAN party = Caddy `tls internal`** (not step-ca). Zero extra infra; + Caddy is the local CA. step-ca stays a future-homelab reminder (see `02-caddy` + open item). Guests import the Caddy root CA once. +- **Full air-gap chosen** over pre-seed. + +## Hosts to mirror (NeoForge 1.21.1 instance) + +| Host | Serves | Notes | +|---|---|---| +| `meta.prismlauncher.org` | Prism-format component meta (MC, LWJGL, NeoForge) | path `/v1/...` | +| `piston-meta.mojang.com` | version manifest + version json | | +| `piston-data.mojang.com` | client.jar, asset index, some objects | | +| `libraries.minecraft.net` | vanilla MC libraries (maven layout) | | +| `maven.neoforged.net` | NeoForge libraries | more mavens may appear → capture catches them | +| `resources.download.minecraft.net` | asset objects (~400 MB+) | the bulk | + +**Not mirrored — auth runtime** (`session.minecraft.net`, `textures.minecraft.net`, +`api.mojang.com`, `sessionserver.mojang.com`): these are redirected to **drasl** +by the authlib-injector account already; leave them to drasl. + +## How it works + +``` +guest laptop (LAN DNS = our dnsmasq, trusts Caddy root CA) + │ resolves meta.prismlauncher.org, libraries.minecraft.net, … → HOST_LAN_IP + ▼ +dnsmasq ── spoof A-records ──► Caddy (tls internal, cert per host) + └─ static file_server, byte-exact path mirror +``` + +### dnsmasq (extends 01) + +Add explicit spoof records alongside the `*.${BASE_DOMAIN}` wildcard: + +``` +address=/meta.prismlauncher.org/${HOST_LAN_IP} +address=/piston-meta.mojang.com/${HOST_LAN_IP} +address=/piston-data.mojang.com/${HOST_LAN_IP} +address=/libraries.minecraft.net/${HOST_LAN_IP} +address=/maven.neoforged.net/${HOST_LAN_IP} +address=/resources.download.minecraft.net/${HOST_LAN_IP} +``` +> Only effective while the guest uses our dnsmasq as resolver. Fully reversible — +> off-LAN the real hosts resolve normally. Keep this list in sync with whatever +> the capture step (below) actually observed. + +### Caddy (extends 02) + +One vhost per spoofed host, each rooted at its mirror tree, all `tls internal`: + +``` +piston-data.mojang.com, libraries.minecraft.net, resources.download.minecraft.net, +meta.prismlauncher.org, piston-meta.mojang.com, maven.neoforged.net { + tls internal + root * /srv/mirror/{host} + file_server +} +``` +(Practically: a small snippet per host, or Caddy on-demand TLS + a path-routed +`map`. Keep explicit per-host for clarity.) Add each as a **network alias** on +Caddy too, so the `minecraft`/tooling containers resolve them internally. + +Mount `./mirror/upstream/:/srv/mirror/:ro`. + +## Capture (the actual work) — `tooling/mirror-airgap.sh` + +Byte-exact mirroring needs the exact URL set. Capture it once, online: + +1. **Record**: launch the instance once with the launcher pointed at a logging + forward-proxy (mitmproxy `--mode reverse`/transparent, or even Caddy as a + logging reverse proxy). Collect every requested absolute URL. +2. **Fetch**: for each URL, download to `mirror/upstream//`, + preserving path exactly. Verify SHA1 where the source json provides it + (libraries, assets). Halt on mismatch. +3. **Assets shortcut**: the objects (resources.download…) can be filled directly + from the asset index (same logic as `10-assets-mirror.md`) without proxy + capture — reuse that loop into `mirror/upstream/resources.download.minecraft.net/<2hex>/`. +4. **Verify offline**: re-run a launch on a second machine with internet cut and + DNS set to our dnsmasq + CA trusted. Fix any 404 → missing URL → add to fetch. + +> Cautious by design: the proxy-capture enumerates whatever hosts/paths are *truly* +> hit (incl. unforeseen maven mirrors), so the mirror is complete rather than +> guessed. Re-capture if MC/NeoForge versions change. + +## Guest one-time setup (offline) + +1. Set laptop DNS → our dnsmasq (LAN IP). (Often via DHCP/router, or manual.) +2. Import the **Caddy root CA** into the OS/browser trust store. +3. Install Fjord, add authlib-injector account (`auth.${BASE_DOMAIN}`), import pack, + launch. All downloads resolve to the LAN mirror. + +No launcher API-field overrides needed in this architecture. + +## Open / reminders + +- [ ] **Reminder (kept):** graduate `tls internal` → step-ca for the persistent + homelab; revisit cert distribution then. +- [ ] Confirm exact `meta.prismlauncher.org` path layout Fjord requests (fork may + pin a different meta host/version). +- [ ] Verify Caddy `tls internal` certs validate in Fjord's Qt network stack with + the root CA imported (no extra pinning). +- [ ] mitmproxy vs Caddy-log for the capture step — pick one. +- [ ] CA-trust UX per OS (Windows/macOS/Linux) — document for guests. + +## Tasks + +- [ ] Write `tooling/mirror-airgap.sh` (capture + fetch + sha1 verify + offline re-test) +- [ ] Add spoof `address=` lines to `dnsmasq/dnsmasq.conf.tmpl` (01) +- [ ] Add per-host `tls internal` vhosts + network aliases + mounts to Caddy (02) +- [ ] Export Caddy root CA; build a guest CA-import mini-guide (link from landing page) +- [ ] Run capture online for MC 1.21.1 + NeoForge 21.1.x; populate `mirror/upstream/` +- [ ] Offline acceptance test on a clean machine (internet cut, LAN DNS, CA trusted) +- [ ] `.gitignore` already covers `mirror/` +``` diff --git a/plan/12-build-order.md b/plan/12-build-order.md new file mode 100644 index 0000000..e05f54c --- /dev/null +++ b/plan/12-build-order.md @@ -0,0 +1,59 @@ +# Build order — one commit per task + +Dependency-ordered. Each numbered item = one git commit. `main` currently has +**zero commits**; item 0 is the baseline. Operational steps (pre-bake, capture, +acceptance test) need internet/hardware and are NOT commits — marked `[ops]`. + +> Commit message convention: Conventional Commits, scope = service. Footer: +> `Co-Authored-By: Claude Opus 4.7 (1M context) `. + +## Phase 0 — baseline +0. `chore: baseline scaffolding` — existing untracked tree (CLAUDE.md, plan/, + current docker-compose.yml, extras/, .gitignore, .env.example). + +## Phase 1 — config foundation +1. `feat(env): add BASE_DOMAIN + HOST_LAN_IP to .env.example` +2. `feat(tooling): add render-config.sh (envsubst, halt on unset var)` + +## Phase 2 — DNS + ingress (no app yet, but the backbone) +3. `feat(dnsmasq): add dnsmasq.conf.tmpl (wildcard *.BASE_DOMAIN)` +4. `feat(caddy): add Caddyfile (apex + auth + packwiz vhosts)` +5. `feat(compose): add dnsmasq + caddy services + network aliases` + +## Phase 3 — auth +6. `feat(drasl): add config.toml.tmpl (password login, SignPublicKeys=false)` +7. `refactor(compose): drasl internal-only behind caddy; authlib URL → auth.` + +## Phase 4 — modpack +8. `feat(pack): packwiz init + initial mod curation` +9. `feat(tooling): add mirror-mods.sh (vendor jars + rewrite .pw.toml URLs)` +10. `refactor(compose): minecraft via PACKWIZ_URL; extras→runtime` + +## Phase 5 — landing +11. `feat(landing): Astro+TS onboarding site → www/` (files already drafted) +12. `chore(landing): wire logo + .gitignore for www/ + build output` + +## Phase 6 — launcher distribution +13. `feat(tooling): add fetch-launcher.sh (all platforms + stable symlinks)` + +## Phase 7 — full client air-gap (chosen path, plan/11) +14. `feat(tooling): add mirror-airgap.sh (capture + fetch + sha1 verify)` +15. `feat(dnsmasq): add air-gap spoof records for upstream hosts` +16. `feat(caddy): add tls internal vhosts for upstream mirror hosts` + +## Phase 8 — backups + orchestration +17. `feat(compose): add mc-backup service (RCON, 6h)` +18. `feat(tooling): add build-stack.sh orchestrator` + +## Phase 9 — operational (no commits) +- [ops] Run `build-stack.sh --prep` online: render configs, build landing, + mirror mods, mirror air-gap, fetch launcher, **pre-bake** server volume. +- [ops] Offline acceptance test: clean machine, internet cut, LAN DNS = dnsmasq, + Caddy CA trusted → install Fjord, import pack, join. +- [ops] If green: tag `v1-lan-ready`. + +## Notes +- Items 3–5 can be smoke-tested (`docker compose up dnsmasq caddy`) before later + phases exist — Caddy serves a 404/landing, dnsmasq resolves. +- Items 14–16 depend on a working online launch to capture the URL set first. +- Each commit should leave the tree in a non-broken state (compose still parses). diff --git a/tooling/build-stack.sh b/tooling/build-stack.sh new file mode 100755 index 0000000..5cf3dff --- /dev/null +++ b/tooling/build-stack.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +# build-stack.sh — orchestrate the Ulicraft stack: offline prep then bring-up. +# +# Phases: +# preflight always — verify .env + required tools +# --prep ONLINE — render configs, build landing, mirror mods + air-gap, +# fetch launcher, pre-bake the server volume +# --up OFFLINE — docker compose up -d the full stack +# (no flag) preflight + print what each phase would do, then exit +# +# Cautious by design: halts on the first missing var, missing tool, or failed +# step. Each sub-script is itself responsible for its own integrity checks. +set -euo pipefail + +cd "$(dirname "$0")/.." # repo root +COMPOSE=(docker compose) + +# ---- helpers --------------------------------------------------------------- +log() { printf '\n\033[1;32m==>\033[0m %s\n' "$*"; } +warn() { printf '\033[1;33m!!\033[0m %s\n' "$*" >&2; } +die() { printf '\033[1;31mxx\033[0m %s\n' "$*" >&2; exit 1; } + +need_tool() { command -v "$1" >/dev/null 2>&1 || die "missing required tool: $1"; } +have_script() { [ -x "tooling/$1" ] || die "missing/not-executable: tooling/$1"; } + +# ---- preflight ------------------------------------------------------------- +preflight() { + log "preflight" + [ -f .env ] || die ".env not found (copy .env.example and fill it)" + # shellcheck disable=SC1091 + set -a; . ./.env; set +a + : "${BASE_DOMAIN:?BASE_DOMAIN unset in .env}" + : "${HOST_LAN_IP:?HOST_LAN_IP unset in .env}" + : "${RCON_PASSWORD:?RCON_PASSWORD unset in .env}" + + need_tool docker + ${COMPOSE[@]} version >/dev/null 2>&1 || die "docker compose plugin not available" + need_tool envsubst + need_tool jq + need_tool curl + need_tool sha1sum + command -v pnpm >/dev/null 2>&1 || warn "pnpm not found — landing build will be skipped if absent" + + echo " BASE_DOMAIN=${BASE_DOMAIN} HOST_LAN_IP=${HOST_LAN_IP}" + echo " preflight ok" +} + +# ---- online prep ----------------------------------------------------------- +prep() { + log "PHASE prep (requires internet)" + + log "render configs" + have_script render-config.sh + tooling/render-config.sh + + log "build landing page → www/" + if command -v pnpm >/dev/null 2>&1; then + ( cd landing && pnpm install --frozen-lockfile && BASE_DOMAIN="${BASE_DOMAIN}" pnpm run build ) + else + warn "pnpm absent — skipping landing build" + fi + + log "mirror mod jars (offline pack)" + have_script mirror-mods.sh + tooling/mirror-mods.sh + + log "mirror full air-gap upstream (meta/libraries/assets/client.jar)" + have_script mirror-airgap.sh + tooling/mirror-airgap.sh + + log "fetch launcher releases" + have_script fetch-launcher.sh + tooling/fetch-launcher.sh + + log "pre-bake server volume (TYPE=NEOFORGE install, one-shot, online)" + # Bring minecraft up once so itzg installs NeoForge + mods into the volume, + # then stop it. The party then runs offline against the baked volume. + "${COMPOSE[@]}" up -d minecraft + warn "watch logs until 'Done' then re-run with --up; or automate a readiness probe" +} + +# ---- offline bring-up ------------------------------------------------------ +up() { + log "PHASE up (offline-capable bring-up)" + have_script render-config.sh + tooling/render-config.sh # cheap; ensures configs match current .env + "${COMPOSE[@]}" up -d + log "stack up. apex: http://${BASE_DOMAIN} auth: http://auth.${BASE_DOMAIN}" +} + +# ---- dispatch -------------------------------------------------------------- +preflight +case "${1:-}" in + --prep) prep ;; + --up) up ;; + "") cat <