This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

docs: rebuild with astro starlight

Signed-off-by: Anirudh Oppiliappan <anirudh@tangled.org>

author
Anirudh Oppiliappan
date (Jul 22, 2026, 2:05 PM +0300) commit 00960331 parent cc3b7534 change-id stwpzywy
+11757 -3386
+3
docs/.gitignore
··· 1 + node_modules/ 2 + dist/ 3 + .astro/
-2888
docs/DOCS.md
··· 1 - --- 2 - title: Tangled docs 3 - author: The Tangled Contributors 4 - date: 21 Sun, Dec 2025 5 - abstract: | 6 - Tangled is a decentralized code hosting and collaboration 7 - platform. Every component of Tangled is open-source and 8 - self-hostable. [tangled.org](https://tangled.org) also 9 - provides hosting and CI services that are free to use. 10 - 11 - There are several models for decentralized code 12 - collaboration platforms, ranging from ActivityPub’s 13 - (Forgejo) federated model, to Radicle’s entirely P2P model. 14 - Our approach attempts to be the best of both worlds by 15 - adopting the AT Protocol—a protocol for building decentralized 16 - social applications with a central identity 17 - 18 - Our approach to this is the idea of “knots”. Knots are 19 - lightweight, headless servers that enable users to host Git 20 - repositories with ease. Knots are designed for either single 21 - or multi-tenant use which is perfect for self-hosting on a 22 - Raspberry Pi at home, or larger “community” servers. By 23 - default, Tangled provides managed knots where you can host 24 - your repositories for free. 25 - 26 - The appview at tangled.org acts as a consolidated "view" 27 - into the whole network, allowing users to access, clone and 28 - contribute to repositories hosted across different knots 29 - seamlessly. 30 - --- 31 - 32 - # Quick start guide 33 - 34 - ## Login or sign up 35 - 36 - You can [login](https://tangled.org) by using your AT Protocol 37 - account. If you are unclear on what that means, simply head 38 - to the [signup](https://tangled.org/signup) page and create 39 - an account. By doing so, you will be choosing Tangled as 40 - your account provider (you will be granted a handle of the 41 - form `user.tngl.sh`). 42 - 43 - In the AT Protocol network, users are free to choose their account 44 - provider (known as a "Personal Data Service", or PDS), and 45 - login to applications that support AT accounts. 46 - 47 - You can think of it as "one account for all of the atmosphere"! 48 - 49 - If you already have an AT account (you may have one if you 50 - signed up to Bluesky, for example), you can login with the 51 - same handle on Tangled (so just use `user.bsky.social` on 52 - the login page). 53 - 54 - ## Add an SSH key 55 - 56 - Once you are logged in, you can start creating repositories 57 - and pushing code. Tangled supports pushing git repositories 58 - over SSH. 59 - 60 - First, you'll need to generate an SSH key if you don't 61 - already have one: 62 - 63 - ```bash 64 - ssh-keygen -t ed25519 -C "foo@bar.com" 65 - ``` 66 - 67 - When prompted, save the key to the default location 68 - (`~/.ssh/id_ed25519`) and optionally set a passphrase. 69 - 70 - Copy your public key to your clipboard: 71 - 72 - ```bash 73 - # on X11 74 - cat ~/.ssh/id_ed25519.pub | xclip -sel c 75 - 76 - # on wayland 77 - cat ~/.ssh/id_ed25519.pub | wl-copy 78 - 79 - # on macos 80 - cat ~/.ssh/id_ed25519.pub | pbcopy 81 - ``` 82 - 83 - Now, navigate to 'Settings' -> 'Keys' and hit 'Add Key', 84 - paste your public key, give it a descriptive name, and hit 85 - save. 86 - 87 - ## Create a repository 88 - 89 - Once your SSH key is added, create your first repository: 90 - 91 - 1. Hit the green `+` icon on the topbar, and select 92 - repository 93 - 2. Enter a repository name 94 - 3. Add a description 95 - 4. Choose a knotserver to host this repository on 96 - 5. Hit create 97 - 98 - Knots are self-hostable, lightweight Git servers that can 99 - host your repository. Unlike traditional code forges, your 100 - code can live on any server. Read the [Knots](TODO) section 101 - for more. 102 - 103 - ## Configure SSH 104 - 105 - To ensure Git uses the correct SSH key and connects smoothly 106 - to Tangled, add this configuration to your `~/.ssh/config` 107 - file: 108 - 109 - ``` 110 - Host tangled.org 111 - Hostname tangled.org 112 - User git 113 - IdentityFile ~/.ssh/id_ed25519 114 - AddressFamily inet 115 - ``` 116 - 117 - This tells SSH to use your specific key when connecting to 118 - Tangled and prevents authentication issues if you have 119 - multiple SSH keys. 120 - 121 - Note that this configuration only works for knotservers that 122 - are hosted by tangled.org. If you use a custom knot, refer 123 - to the [Knots](TODO) section. 124 - 125 - ## Push your first repository 126 - 127 - Initialize a new Git repository: 128 - 129 - ```bash 130 - mkdir my-project 131 - cd my-project 132 - 133 - git init 134 - echo "# My Project" > README.md 135 - ``` 136 - 137 - Add some content and push! 138 - 139 - ```bash 140 - git add README.md 141 - git commit -m "Initial commit" 142 - git remote add origin git@tangled.org:user.tngl.sh/my-project 143 - git push -u origin main 144 - ``` 145 - 146 - That's it! Your code is now hosted on Tangled. 147 - 148 - ## Migrating an existing repository 149 - 150 - Moving your repositories from GitHub, GitLab, Bitbucket, or 151 - any other Git forge to Tangled is straightforward. You'll 152 - simply change your repository's remote URL. At the moment, 153 - Tangled does not have any tooling to migrate data such as 154 - GitHub issues or pull requests. 155 - 156 - First, create a new repository on tangled.org as described 157 - in the [Quick Start Guide](#create-a-repository). 158 - 159 - Navigate to your existing local repository: 160 - 161 - ```bash 162 - cd /path/to/your/existing/repo 163 - ``` 164 - 165 - You can inspect your existing Git remote like so: 166 - 167 - ```bash 168 - git remote -v 169 - ``` 170 - 171 - You'll see something like: 172 - 173 - ```bash 174 - origin git@github.com:username/my-project.git (fetch) 175 - origin git@github.com:username/my-project.git (push) 176 - ``` 177 - 178 - Update the remote URL to point to tangled: 179 - 180 - ```bash 181 - git remote set-url origin git@tangled.org:user.tngl.sh/my-project 182 - ``` 183 - 184 - Verify the change: 185 - 186 - ```bash 187 - git remote -v 188 - ``` 189 - 190 - You should now see: 191 - 192 - ```bash 193 - origin git@tangled.org:user.tngl.sh/my-project (fetch) 194 - origin git@tangled.org:user.tngl.sh/my-project (push) 195 - ``` 196 - 197 - Push all your branches and tags to Tangled: 198 - 199 - ```bash 200 - git push -u origin --all 201 - git push -u origin --tags 202 - ``` 203 - 204 - Your repository is now migrated to Tangled! All commit 205 - history, branches, and tags have been preserved. 206 - 207 - ## Mirroring a repository to Tangled 208 - 209 - If you want to maintain your repository on multiple forges 210 - simultaneously, for example, keeping your primary repository 211 - on GitHub while mirroring to Tangled for backup or 212 - redundancy, you can do so by adding [multiple remotes](https://git-scm.com/docs/git-push#_remotes). 213 - 214 - You can configure your local repository to push to both 215 - Tangled and, say, GitHub. You may already have the following 216 - setup: 217 - 218 - ```bash 219 - $ git remote -v 220 - origin git@github.com:username/my-project.git (fetch) 221 - origin git@github.com:username/my-project.git (push) 222 - ``` 223 - 224 - Now add Tangled as an additional push URL to the same 225 - remote: 226 - 227 - ```bash 228 - git remote set-url --add --push origin git@tangled.org:user.tngl.sh/my-project 229 - ``` 230 - 231 - You also need to re-add the original URL as a push 232 - destination (Git will now use the original URL to fetch only): 233 - 234 - ```bash 235 - git remote set-url --add --push origin git@github.com:username/my-project.git 236 - ``` 237 - 238 - Verify your configuration: 239 - 240 - ```bash 241 - $ git remote -v 242 - origin git@github.com:username/my-project.git (fetch) 243 - origin git@tangled.org:user.tngl.sh/my-project (push) 244 - origin git@github.com:username/my-project.git (push) 245 - ``` 246 - 247 - Notice that there's one fetch URL (the primary remote) and 248 - two push URLs. Now, whenever you push, Git will 249 - automatically push to both remotes: 250 - 251 - ```bash 252 - git push origin main 253 - ``` 254 - 255 - This single command pushes your `main` branch to both GitHub 256 - and Tangled simultaneously. 257 - 258 - To push all branches and tags: 259 - 260 - ```bash 261 - git push origin --all 262 - git push origin --tags 263 - ``` 264 - 265 - If you prefer more control over which remote you push to, 266 - you can maintain separate remotes: 267 - 268 - ```bash 269 - git remote add github git@github.com:username/my-project.git 270 - git remote add tangled git@tangled.org:user.tngl.sh/my-project 271 - ``` 272 - 273 - Then push to each explicitly: 274 - 275 - ```bash 276 - git push github main 277 - git push tangled main 278 - ``` 279 - 280 - # Hosting websites on Tangled 281 - 282 - You can serve static websites directly from your git repositories on 283 - Tangled. If you've used GitHub Pages or Codeberg Pages, this should feel 284 - familiar. 285 - 286 - ## Overview 287 - 288 - Every user gets a sites domain. If you signed up through Tangled's own 289 - PDS (`tngl.sh`), your sites domain is automatically 290 - `<your-handle>.tngl.sh` no setup needed. Otherwise, you can claim a 291 - `<subdomain>.tngl.io` domain from your settings. 292 - 293 - You can serve multiple sites per domain: 294 - 295 - - One **index site** served at the root of your domain (e.g. 296 - `alice.tngl.sh`) 297 - - Any number of **sub-path sites** served under the repository name 298 - (e.g. `alice.tngl.sh/my-project`) 299 - 300 - ## Claiming a domain 301 - 302 - If you don't have a `tngl.sh` handle, you need to claim a domain before 303 - publishing sites: 304 - 305 - 1. Go to **Settings → Sites** 306 - 2. Enter a subdomain (e.g. `alice` to claim `alice.tngl.io`) 307 - 3. Click **claim** 308 - 309 - You can only hold one domain at a time. Releasing a domain puts it in a 310 - 30-day cooldown before anyone else can claim it. 311 - 312 - ## Configuring a site for a repository 313 - 314 - 1. Navigate to your repository 315 - 2. Go to **Settings → Sites** 316 - 3. Choose a **branch** to deploy from 317 - 4. Set the **deploy directory** — the path within the repository 318 - containing your `index.html`. Use `/` for the root, or a subdirectory 319 - like `/docs` or `/public` 320 - 5. Choose the **site type**: 321 - - **Index site** — served at the root of your domain (e.g. 322 - `alice.tngl.sh`) 323 - - **Sub-path site** — served under the repository name (e.g. 324 - `alice.tngl.sh/my-project`) 325 - 6. Click **save** 326 - 327 - The site will be deployed automatically. You can see the status of your 328 - previous deploys in the **Recent Deploys** section at the bottom of the 329 - page. 330 - 331 - Sites are redeployed automatically on every push to the configured 332 - branch. 333 - 334 - ## Custom domains 335 - 336 - Tangled currently doesn't support custom domains for sites. This will be 337 - added in a future update. 338 - 339 - ## Deploy directory 340 - 341 - The deploy directory is the path within your repository that Tangled 342 - serves as the site root. It must contain an `index.html`. 343 - 344 - | Deploy directory | Result | 345 - |---|---| 346 - | `/` | Serves the repository root | 347 - | `/docs` | Serves the `docs/` subdirectory | 348 - | `/public` | Serves the `public/` subdirectory | 349 - 350 - Directories are served with automatic `index.html` resolution -- a 351 - request to `/about` will serve `/about/index.html` if it exists. 352 - 353 - ## Site types 354 - 355 - | Type | URL | 356 - |---|---| 357 - | Index site | `alice.tngl.sh` | 358 - | Sub-path site | `alice.tngl.sh/my-project` | 359 - 360 - Only one repository can be the index site for a given domain at a time. 361 - If another repository already holds the index site, you will see a 362 - notice in the settings and only the sub-path option will be available. 363 - 364 - ## Deploy triggers 365 - 366 - A deployment is triggered automatically when: 367 - 368 - - You push to the configured branch 369 - - You change the site configuration (branch, deploy directory, or site 370 - type) 371 - 372 - ## Disabling a site 373 - 374 - To stop serving a site, go to **Settings → Sites** in your repository 375 - and click **Disable**. This removes the site configuration and stops 376 - serving the site. The deployed files are also deleted from storage. 377 - 378 - Releasing your domain from **Settings → Sites** at the account level 379 - will disable all sites associated with it and delete their files. 380 - 381 - 382 - # Knot self-hosting guide 383 - 384 - So you want to run your own knot server? Great! Here are a few prerequisites: 385 - 386 - 1. A server of some kind (a VPS, a Raspberry Pi, etc.). Preferably running a Linux distribution of some kind. 387 - 2. A (sub)domain name. People generally use `knot.example.com`. 388 - 3. A valid SSL certificate for your domain. 389 - 390 - ## NixOS 391 - 392 - Refer to the [knot 393 - module](https://tangled.org/tangled.org/core/blob/master/nix/modules/knot.nix) 394 - for a full list of options. Sample configurations: 395 - 396 - - [The test VM](https://tangled.org/tangled.org/core/blob/master/nix/vm.nix#L85) 397 - - [@pyrox.dev/nix](https://tangled.org/pyrox.dev/nix/blob/c2b644c214d278af12523618de952ee2eab1af3d/hosts/marvin/services/tangled.nix#L15-26) 398 - 399 - ## Docker 400 - 401 - Refer to 402 - [@tangled.org/knot-docker](https://tangled.org/@tangled.org/knot-docker). 403 - Note that this is community maintained. 404 - 405 - ## Manual setup 406 - 407 - First, clone this repository: 408 - 409 - ``` 410 - git clone https://tangled.org/@tangled.org/core 411 - ``` 412 - 413 - Then, build the `knot` CLI. This is the knot administration 414 - and operation tool. For the purpose of this guide, we're 415 - only concerned with these subcommands: 416 - 417 - - `knot server`: the main knot server process, typically 418 - run as a supervised service 419 - - `knot guard`: handles role-based access control for git 420 - over SSH (you'll never have to run this yourself) 421 - - `knot keys`: fetches SSH keys associated with your knot; 422 - we'll use this to generate the SSH 423 - `AuthorizedKeysCommand` 424 - 425 - ``` 426 - cd core 427 - export CGO_ENABLED=1 428 - go build -o knot ./cmd/knot 429 - ``` 430 - 431 - Next, move the `knot` binary to a location owned by `root` -- 432 - `/usr/local/bin/` is a good choice. Make sure the binary itself is also owned by `root`: 433 - 434 - ``` 435 - sudo mv knot /usr/local/bin/knot 436 - sudo chown root:root /usr/local/bin/knot 437 - ``` 438 - 439 - This is necessary because SSH `AuthorizedKeysCommand` requires [really 440 - specific permissions](https://stackoverflow.com/a/27638306). The 441 - `AuthorizedKeysCommand` specifies a command that is run by `sshd` to 442 - retrieve a user's public SSH keys dynamically for authentication. Let's 443 - set that up. 444 - 445 - ``` 446 - sudo tee /etc/ssh/sshd_config.d/authorized_keys_command.conf <<EOF 447 - Match User git 448 - AuthorizedKeysCommand /usr/local/bin/knot keys -o authorized-keys 449 - AuthorizedKeysCommandUser nobody 450 - EOF 451 - ``` 452 - 453 - Then, reload `sshd`: 454 - 455 - ``` 456 - sudo systemctl reload ssh 457 - ``` 458 - 459 - Next, create the `git` user. We'll use the `git` user's home directory 460 - to store repositories: 461 - 462 - ``` 463 - sudo adduser git 464 - ``` 465 - 466 - Create `/home/git/.knot.env` with the following, updating the values as 467 - necessary. The `KNOT_SERVER_OWNER` should be set to your 468 - DID, you can find your DID in the [Settings](https://tangled.sh/settings) page. 469 - 470 - ``` 471 - KNOT_REPO_SCAN_PATH=/home/git 472 - KNOT_SERVER_HOSTNAME=knot.example.com 473 - APPVIEW_ENDPOINT=https://tangled.org 474 - KNOT_SERVER_OWNER=did:plc:foobar 475 - KNOT_SERVER_INTERNAL_LISTEN_ADDR=127.0.0.1:5444 476 - KNOT_SERVER_LISTEN_ADDR=127.0.0.1:5555 477 - ``` 478 - 479 - If you run a Linux distribution that uses systemd, you can 480 - use the provided service file to run the server. Copy 481 - [`knotserver.service`](https://tangled.org/tangled.org/core/blob/master/systemd/knotserver.service) 482 - to `/etc/systemd/system/`. Then, run: 483 - 484 - ``` 485 - systemctl enable knotserver 486 - systemctl start knotserver 487 - ``` 488 - 489 - The last step is to configure a reverse proxy like Nginx or Caddy to front your 490 - knot. Here's an example configuration for Nginx: 491 - 492 - ``` 493 - server { 494 - listen 80; 495 - listen [::]:80; 496 - server_name knot.example.com; 497 - 498 - location / { 499 - proxy_pass http://localhost:5555; 500 - proxy_set_header Host $host; 501 - proxy_set_header X-Real-IP $remote_addr; 502 - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 503 - proxy_set_header X-Forwarded-Proto $scheme; 504 - } 505 - 506 - # wss endpoint for git events 507 - location /events { 508 - proxy_set_header X-Forwarded-For $remote_addr; 509 - proxy_set_header Host $http_host; 510 - proxy_set_header Upgrade websocket; 511 - proxy_set_header Connection Upgrade; 512 - proxy_pass http://localhost:5555; 513 - } 514 - # additional config for SSL/TLS go here. 515 - } 516 - 517 - ``` 518 - 519 - Remember to use Let's Encrypt or similar to procure a certificate for your 520 - knot domain. 521 - 522 - You should now have a running knot server! You can finalize 523 - your registration by hitting the `verify` button on the 524 - [/settings/knots](https://tangled.org/settings/knots) page. This simply creates 525 - a record on your PDS to announce the existence of the knot. 526 - 527 - ### Custom paths 528 - 529 - (This section applies to manual setup only. Docker users should edit the mounts 530 - in `docker-compose.yml` instead.) 531 - 532 - Right now, the database and repositories of your knot lives in `/home/git`. You 533 - can move these paths if you'd like to store them in another folder. Be careful 534 - when adjusting these paths: 535 - 536 - - Stop your knot when moving data (e.g. `systemctl stop knotserver`) to prevent 537 - any possible side effects. Remember to restart it once you're done. 538 - - Make backups before moving in case something goes wrong. 539 - - Make sure the `git` user can read and write from the new paths. 540 - 541 - #### Database 542 - 543 - As an example, let's say the current database is at `/home/git/knotserver.db`, 544 - and we want to move it to `/home/git/database/knotserver.db`. 545 - 546 - Copy the current database to the new location. Make sure to copy the `.db-shm` 547 - and `.db-wal` files if they exist. 548 - 549 - ``` 550 - mkdir /home/git/database 551 - cp /home/git/knotserver.db* /home/git/database 552 - ``` 553 - 554 - In the environment (e.g. `/home/git/.knot.env`), set `KNOT_SERVER_DB_PATH` to 555 - the new file path (_not_ the directory): 556 - 557 - ``` 558 - KNOT_SERVER_DB_PATH=/home/git/database/knotserver.db 559 - ``` 560 - 561 - #### Repositories 562 - 563 - As an example, let's say the repositories are currently in `/home/git`, and we 564 - want to move them into `/home/git/repositories`. 565 - 566 - Create the new folder, then move the existing repositories (if there are any): 567 - 568 - ``` 569 - mkdir /home/git/repositories 570 - # move all DIDs into the new folder; these will vary for you! 571 - mv /home/git/did:plc:wshs7t2adsemcrrd4snkeqli /home/git/repositories 572 - ``` 573 - 574 - In the environment (e.g. `/home/git/.knot.env`), update `KNOT_REPO_SCAN_PATH` 575 - to the new directory: 576 - 577 - ``` 578 - KNOT_REPO_SCAN_PATH=/home/git/repositories 579 - ``` 580 - 581 - Similarly, update your `sshd` `AuthorizedKeysCommand` to use the updated 582 - repository path: 583 - 584 - ``` 585 - sudo tee /etc/ssh/sshd_config.d/authorized_keys_command.conf <<EOF 586 - Match User git 587 - AuthorizedKeysCommand /usr/local/bin/knot keys -o authorized-keys -git-dir /home/git/repositories 588 - AuthorizedKeysCommandUser nobody 589 - EOF 590 - ``` 591 - 592 - Make sure to restart your SSH server! 593 - 594 - #### MOTD (message of the day) 595 - 596 - To configure the MOTD used ("Welcome to this knot!" by default), edit the 597 - `/home/git/motd` file: 598 - 599 - ``` 600 - printf "Hi from this knot!\n" > /home/git/motd 601 - ``` 602 - 603 - Note that you should add a newline at the end if setting a non-empty message 604 - since the knot won't do this for you. 605 - 606 - ## Secure Mode 607 - 608 - Secure Mode isolates each `git` subprocess to the repository it is 609 - operating on, using two mechanisms: 610 - 611 - - **Linux Landlock** restricts the filesystem paths the subprocess 612 - can access -- it can only read/write its own repository and the 613 - system directories it needs to run. 614 - - **UID isolation** runs each subprocess as a virtual UID assigned 615 - to the repository owner, so that repositories belonging to 616 - different owners are isolated from each other at the OS level 617 - even if Landlock were somehow bypassed. 618 - 619 - Secure Mode requires: 620 - 621 - - Linux kernel >= 5.19 (Landlock V2). This is the minimum needed 622 - for `git push` to work, because receive-pack's quarantine 623 - migration uses cross-directory rename which requires the 624 - Landlock `REFER` access right (added in V2). Kernels 5.13-5.18 625 - support Landlock V1 and clones will work, but pushes will fail 626 - with cross-device link errors. On kernels without any Landlock 627 - support (< 5.13), the sandbox call is a no-op: UID isolation 628 - still applies but no filesystem restriction is enforced. 629 - - `CAP_SETUID`, `CAP_SETGID`, and `CAP_CHOWN` available to the 630 - knot process. The NixOS module grants these automatically; for 631 - manual setups see the `setcap` step below. 632 - 633 - ### NixOS 634 - 635 - Add `server.secureMode = true;` to your knot module configuration: 636 - 637 - ```nix 638 - services.tangled.knot = { 639 - server.secureMode = true; 640 - # ... other options 641 - }; 642 - ``` 643 - 644 - The NixOS module handles everything else automatically: 645 - 646 - - Grants the required capabilities to the knot service via 647 - `AmbientCapabilities` in the systemd unit. 648 - - Installs a capability-bearing wrapper at 649 - `/run/wrappers/bin/knot` via `security.wrappers`, so that 650 - SSH-invoked git operations (pushes) also run under the correct 651 - UID without requiring the service to run as root. 652 - - Runs `knot migrate-isolation` at service start to chown 653 - existing repositories to their virtual UIDs. 654 - 655 - ### Manual setup 656 - 657 - **Step 1.** Grant the required capabilities to the knot binary. 658 - This allows the knot process to switch to virtual UIDs at runtime 659 - without running as root. You will need to repeat this step 660 - whenever the binary is updated. 661 - 662 - ``` 663 - sudo setcap cap_setuid,cap_setgid,cap_chown+eip /usr/local/bin/knot 664 - ``` 665 - 666 - **Step 2.** Run the migration tool to assign virtual UIDs to all 667 - existing repositories and set their filesystem permissions. This 668 - must be run as root: 669 - 670 - ``` 671 - sudo knot migrate-isolation \ 672 - --git-dir /home/git \ 673 - --db /home/git/knotserver.db \ 674 - --internal-api 127.0.0.1:5444 675 - ``` 676 - 677 - You can re-run this at any time with `--force` to reapply 678 - permissions (e.g. after a manual repair or after updating the 679 - binary). 680 - 681 - **Step 2a.** Ensure the home directory is traversable by 682 - non-group users. Git subprocesses run as virtual UIDs that are 683 - not in the git group, and they need to resolve 684 - `$HOME/.config/git/config` to load the global config: 685 - 686 - ``` 687 - sudo chmod o+x /home/git 688 - ``` 689 - 690 - This adds only the execute bit, not read -- the virtual UIDs can 691 - traverse to known paths but cannot list directory contents. 692 - 693 - **Step 3.** Enable Secure Mode in your environment file: 694 - 695 - ``` 696 - KNOT_SERVER_SECURE_MODE=true 697 - ``` 698 - 699 - Or pass it as a flag: 700 - 701 - ``` 702 - knot server --secure-mode 703 - ``` 704 - 705 - **Step 4.** Regenerate the `AuthorizedKeysCommand` with the 706 - `-secure-mode` flag. This causes `knot keys` to emit guard 707 - command lines that include `-secure-mode`, so SSH pushes also 708 - get UID isolation: 709 - 710 - ``` 711 - sudo tee /etc/ssh/sshd_config.d/authorized_keys_command.conf <<EOF 712 - Match User git 713 - AuthorizedKeysCommand /usr/local/bin/knot keys \ 714 - -o authorized-keys -secure-mode 715 - AuthorizedKeysCommandUser nobody 716 - EOF 717 - ``` 718 - 719 - Reload `sshd` after making this change. 720 - 721 - > **Note:** the server will refuse to start in Secure Mode if any 722 - > repositories have not yet been isolation-migrated. Re-run 723 - > `migrate-isolation` if you see this error. 724 - 725 - ## Troubleshooting 726 - 727 - If you run your own knot, you may run into some of these 728 - common issues. You can always join the 729 - [IRC](https://web.libera.chat/#tangled) or 730 - [Discord](https://chat.tangled.org/) if this section does 731 - not help. 732 - 733 - ### Unable to push 734 - 735 - If you are unable to push to your knot or repository: 736 - 737 - 1. First, ensure that you have added your SSH public key to 738 - your account 739 - 2. Check to see that your knot has synced the key by running 740 - `knot keys` 741 - 3. Check to see if git is supplying the correct private key 742 - when pushing: `GIT_SSH_COMMAND="ssh -v" git push ...` 743 - 4. Check to see if `sshd` on the knot is rejecting the push 744 - for some reason: `journalctl -xeu ssh` (or `sshd`, 745 - depending on your machine). These logs are unavailable if 746 - using docker. 747 - 5. Check to see if the knot itself is rejecting the push, 748 - depending on your setup, the logs might be in one of the 749 - following paths: 750 - - `/tmp/knotguard.log` 751 - - `/home/git/log` 752 - - `/home/git/guard.log` 753 - 754 - # Spindles 755 - 756 - ## Pipelines 757 - 758 - Spindle workflows allow you to write CI/CD pipelines in a 759 - simple format. They're located in the `.tangled/workflows` 760 - directory at the root of your repository, and are defined 761 - using YAML. 762 - 763 - A workflow has a set of common fields that apply no matter 764 - which engine you pick: 765 - 766 - - [Trigger](#trigger): A **required** field that defines 767 - when a workflow should be triggered. 768 - - [Engine](#engine): A **required** field that defines which 769 - engine a workflow should run on. 770 - - [Clone options](#clone-options): An **optional** field 771 - that defines how the repository should be cloned. 772 - - [Environment](#environment): An **optional** field that 773 - allows you to define environment variables. 774 - - [Steps](#steps): An **optional** field that allows you to 775 - define what steps should run in the workflow. 776 - 777 - On top of these, each engine has its own options for things 778 - like dependencies and images. See [Engines](#engines) for 779 - the per-engine fields. 780 - 781 - ### Trigger 782 - 783 - The first thing to add to a workflow is the trigger, which 784 - defines when a workflow runs. This is defined using a `when` 785 - field, which takes in a list of conditions. Each condition 786 - has the following fields: 787 - 788 - - `event`: This is a **required** field that defines when 789 - your workflow should run. It's a list that can take one or 790 - more of the following values: 791 - - `push`: The workflow should run every time a commit is 792 - pushed to the repository. 793 - - `pull_request`: The workflow should run every time a 794 - pull request is made or updated. 795 - - `manual`: The workflow can be triggered manually. 796 - - `branch`: Defines which branches the workflow should run 797 - for. If used with the `push` event, commits to the 798 - branch(es) listed here will trigger the workflow. If used 799 - with the `pull_request` event, updates to pull requests 800 - targeting the branch(es) listed here will trigger the 801 - workflow. This field has no effect with the `manual` 802 - event. Supports glob patterns using `*` and `**` (e.g., 803 - `main`, `develop`, `release-*`). Either `branch` or `tag` 804 - (or both) must be specified for `push` events. 805 - - `tag`: Defines which tags the workflow should run for. 806 - Only used with the `push` event - when tags matching the 807 - pattern(s) listed here are pushed, the workflow will 808 - trigger. This field has no effect with `pull_request` or 809 - `manual` events. Supports glob patterns using `*` and `**` 810 - (e.g., `v*`, `v1.*`, `release-**`). Either `branch` or 811 - `tag` (or both) must be specified for `push` events. 812 - 813 - For example, if you'd like to define a workflow that runs 814 - when commits are pushed to the `main` and `develop` 815 - branches, or when pull requests that target the `main` 816 - branch are updated, or manually, you can do so with: 817 - 818 - ```yaml 819 - when: 820 - - event: ["push", "manual"] 821 - branch: ["main", "develop"] 822 - - event: ["pull_request"] 823 - branch: ["main"] 824 - ``` 825 - 826 - You can also trigger workflows on tag pushes. For instance, 827 - to run a deployment workflow when tags matching `v*` are 828 - pushed: 829 - 830 - ```yaml 831 - when: 832 - - event: ["push"] 833 - tag: ["v*"] 834 - ``` 835 - 836 - You can even combine branch and tag patterns in a single 837 - constraint (the workflow triggers if either matches): 838 - 839 - ```yaml 840 - when: 841 - - event: ["push"] 842 - branch: ["main", "release-*"] 843 - tag: ["v*", "stable"] 844 - ``` 845 - 846 - To skip CI for a push, pass a Git push option: 847 - 848 - ```sh 849 - git push -o skip-ci 850 - ``` 851 - 852 - `ci-skip` is also accepted. 853 - 854 - ### Engine 855 - 856 - Next is the engine on which the workflow should run, defined 857 - using the **required** `engine` field. The currently 858 - supported engines are: 859 - 860 - - `nixery`: This uses an instance of 861 - [Nixery](https://nixery.dev) to run steps, which allows 862 - you to add [dependencies](#dependencies) from 863 - Nixpkgs (https://github.com/NixOS/nixpkgs). You can 864 - search for packages on https://search.nixos.org, and 865 - there's a pretty good chance the package(s) you're looking 866 - for will be there. 867 - See [Nixery engine](#nixery-engine). 868 - - `microvm`: Runs the whole workflow inside its own 869 - microVM. Has configuration features for NixOS images 870 - that will let you enable services, do Docker-in-VM, etc. 871 - See [microVM engine](#microvm-engine). 872 - 873 - Example: 874 - 875 - ```yaml 876 - engine: "nixery" 877 - ``` 878 - 879 - Each engine also adds its own workflow fields (dependencies, 880 - images, services, and so on). These are documented under 881 - [Engines](#engines). 882 - 883 - ### Clone options 884 - 885 - When a workflow starts, the first step is to clone the 886 - repository. You can customize this behavior using the 887 - **optional** `clone` field. It has the following fields: 888 - 889 - - `skip`: Setting this to `true` will skip cloning the 890 - repository. This can be useful if your workflow is doing 891 - something that doesn't require anything from the 892 - repository itself. This is `false` by default. 893 - - `depth`: This sets the number of commits, or the "clone 894 - depth", to fetch from the repository. For example, if you 895 - set this to 2, the last 2 commits will be fetched. By 896 - default, the depth is set to 1, meaning only the most 897 - recent commit will be fetched, which is the commit that 898 - triggered the workflow. 899 - - `submodules`: If you use Git submodules 900 - (https://git-scm.com/book/en/v2/Git-Tools-Submodules) 901 - in your repository, setting this field to `true` will 902 - recursively fetch all submodules. This is `false` by 903 - default. 904 - 905 - The default settings are: 906 - 907 - ```yaml 908 - clone: 909 - skip: false 910 - depth: 1 911 - submodules: false 912 - ``` 913 - 914 - ### Environment 915 - 916 - The `environment` field allows you define environment 917 - variables that will be available throughout the entire 918 - workflow. **Do not put secrets here, these environment 919 - variables are visible to anyone viewing the repository. You 920 - can add secrets for pipelines in your repository's 921 - settings.** 922 - 923 - Example: 924 - 925 - ```yaml 926 - environment: 927 - GOOS: "linux" 928 - GOARCH: "arm64" 929 - NODE_ENV: "production" 930 - MY_ENV_VAR: "MY_ENV_VALUE" 931 - ``` 932 - 933 - By default, the following environment variables are set: 934 - 935 - - `CI` - Always set to `true` to indicate a CI environment 936 - - `TANGLED_PIPELINE_ID` - The AT URI of the current pipeline 937 - - `TANGLED_PIPELINE_KIND` - One of `push`, `pull_request` or 938 - `manual` 939 - - `TANGLED_REPO_KNOT` - The repository's knot hostname 940 - - `TANGLED_REPO_DID` - The DID of the repository owner 941 - - `TANGLED_REPO_NAME` - The name of the repository 942 - - `TANGLED_REPO_DEFAULT_BRANCH` - The default branch of the 943 - repository 944 - - `TANGLED_REPO_URL` - The full URL to the repository 945 - 946 - These variables are only available when the pipeline is 947 - triggered by a push: 948 - 949 - - `TANGLED_REF` - The full git reference (e.g., 950 - `refs/heads/main` or `refs/tags/v1.0.0`) 951 - - `TANGLED_REF_NAME` - The short name of the reference 952 - (e.g., `main` or `v1.0.0`) 953 - - `TANGLED_REF_TYPE` - The type of reference, either 954 - `branch` or `tag` 955 - - `TANGLED_SHA` - The commit SHA that triggered the pipeline 956 - - `TANGLED_COMMIT_SHA` - Alias for `TANGLED_SHA` 957 - 958 - These variables are only available when the pipeline is 959 - triggered by a pull request: 960 - 961 - - `TANGLED_PR_SOURCE_BRANCH` - The source branch of the pull 962 - request 963 - - `TANGLED_PR_TARGET_BRANCH` - The target branch of the pull 964 - request 965 - - `TANGLED_PR_SOURCE_SHA` - The commit SHA of the source 966 - branch 967 - 968 - ### Steps 969 - 970 - The `steps` field allows you to define what steps should run 971 - in the workflow. It's a list of step objects, each with the 972 - following fields: 973 - 974 - - `name`: This field allows you to give your step a name. 975 - This name is visible in your workflow runs, and is used to 976 - describe what the step is doing. 977 - - `command`: This field allows you to define a command to 978 - run in that step. The step is run in a Bash shell, and the 979 - logs from the command will be visible in the pipelines 980 - page on the Tangled website. Any dependencies you added in 981 - your engine's section (see [Engines](#engines)) will be 982 - available to use here. 983 - - `environment`: Similar to the global 984 - [environment](#environment) config, this **optional** 985 - field is a key-value map that allows you to set 986 - environment variables for the step. **Do not put secrets 987 - here, these environment variables are visible to anyone 988 - viewing the repository. You can add secrets for pipelines 989 - in your repository's settings.** 990 - 991 - Example: 992 - 993 - ```yaml 994 - steps: 995 - - name: "Build backend" 996 - command: "go build" 997 - environment: 998 - GOOS: "darwin" 999 - GOARCH: "arm64" 1000 - - name: "Build frontend" 1001 - command: "npm run build" 1002 - environment: 1003 - NODE_ENV: "production" 1004 - ``` 1005 - 1006 - ## Engines 1007 - 1008 - The common fields above apply to every workflow. Each engine 1009 - then adds its own fields on top. Pick an engine with the 1010 - [`engine`](#engine) field and use the matching section below. 1011 - 1012 - ### Nixery engine 1013 - 1014 - #### Dependencies 1015 - 1016 - When you're running a workflow you'll usually need additional 1017 - dependencies. The `dependencies` field lets you define which 1018 - dependencies to get, and from where. It's a key-value map, 1019 - with the key being the registry to fetch dependencies from, 1020 - and the value being the list of dependencies to fetch. 1021 - 1022 - The registry URL syntax can be found [on the nix 1023 - manual](https://nix.dev/manual/nix/2.18/command-ref/new-cli/nix3-registry-add). 1024 - 1025 - Say you want to fetch Node.js and Go from `nixpkgs`, and a 1026 - package called `my_pkg` you've made from your own registry 1027 - at your repository at 1028 - `https://tangled.org/@example.com/my_pkg`. You can define 1029 - those dependencies like so: 1030 - 1031 - ```yaml 1032 - dependencies: 1033 - # nixpkgs 1034 - nixpkgs: 1035 - - nodejs 1036 - - go 1037 - # unstable 1038 - nixpkgs/nixpkgs-unstable: 1039 - - bun 1040 - # custom registry 1041 - git+https://tangled.org/@example.com/my_pkg: 1042 - - my_pkg 1043 - ``` 1044 - 1045 - Now these dependencies are available to use in your 1046 - workflow! 1047 - 1048 - #### Complete nixery workflow 1049 - 1050 - ```yaml 1051 - # .tangled/workflows/build.yml 1052 - 1053 - when: 1054 - - event: ["push", "manual"] 1055 - branch: ["main", "develop"] 1056 - - event: ["pull_request"] 1057 - branch: ["main"] 1058 - 1059 - engine: "nixery" 1060 - 1061 - # using the default values 1062 - clone: 1063 - skip: false 1064 - depth: 1 1065 - submodules: false 1066 - 1067 - dependencies: 1068 - # nixpkgs 1069 - nixpkgs: 1070 - - nodejs 1071 - - go 1072 - # custom registry 1073 - git+https://tangled.org/@example.com/my_pkg: 1074 - - my_pkg 1075 - 1076 - environment: 1077 - GOOS: "linux" 1078 - GOARCH: "arm64" 1079 - NODE_ENV: "production" 1080 - MY_ENV_VAR: "MY_ENV_VALUE" 1081 - 1082 - steps: 1083 - - name: "Build backend" 1084 - command: "go build" 1085 - environment: 1086 - GOOS: "darwin" 1087 - GOARCH: "arm64" 1088 - - name: "Build frontend" 1089 - command: "npm run build" 1090 - environment: 1091 - NODE_ENV: "production" 1092 - ``` 1093 - 1094 - If you want another example of a workflow, you can look at 1095 - the one [Tangled uses to build the 1096 - project](https://tangled.org/@tangled.org/core/blob/master/.tangled/workflows/build.yml). 1097 - 1098 - ### microVM engine 1099 - 1100 - #### Image 1101 - 1102 - A workflow picks the image to boot with the top-level `image` 1103 - field: 1104 - 1105 - ```yaml 1106 - engine: microvm 1107 - image: nixos 1108 - ``` 1109 - 1110 - There are two flavours of images: 1111 - 1112 - - **NixOS images** (e.g. `nixos`): the whole guest is built 1113 - with Nix, so you can configure it from the workflow file 1114 - itself. The `dependencies`, `services`, `virtualisation`, 1115 - `registry` and `caches` fields below are all understood 1116 - here, and the guest builds and activates that configuration 1117 - before any of your steps run. 1118 - - **Non-NixOS images** (e.g. `alpine`): there's no NixOS to 1119 - configure, so the workflow-level config fields above have 1120 - no effect. You still get a full machine to run steps in. 1121 - 1122 - The available image names depend on what the spindle operator 1123 - has installed. `nixos` and `alpine` are examples. If `image` 1124 - is omitted, the spindle's configured default image is used. 1125 - 1126 - #### Dependencies 1127 - 1128 - On the microVM engine, `dependencies` is a flat list of 1129 - packages that are made available to every step. This field 1130 - only applies to **NixOS images**; for other images you can 1131 - use the package manager included in a step. 1132 - 1133 - The guest builds a [`nix develop`](https://nix.dev/manual/nix/2.18/command-ref/new-cli/nix3-develop)-style 1134 - devshell from your dependencies and uses it for each step, 1135 - so you can, for example, add `pkg-config` and `openssl` and 1136 - have the `openssl-sys` crate while compiling a Rust project 1137 - just work. 1138 - 1139 - A bare name like `go` is looked up in nixpkgs. You can also 1140 - point at any flake with the `flakeref#attr` syntax, so 1141 - `github:nixos/nixpkgs#hello` pulls `hello` straight out of 1142 - that flake. 1143 - 1144 - ```yaml 1145 - dependencies: 1146 - - go 1147 - - github:nixos/nixpkgs#hello 1148 - ``` 1149 - 1150 - #### Registry 1151 - 1152 - The `registry` field remaps flake references, the same way 1153 - `nix registry` does. This lets you pin or alias the flakes 1154 - used by `dependencies`. 1155 - 1156 - For example, pin `nixpkgs` to `nixos-unstable` so that the 1157 - bare `go` above resolves from unstable, and alias your own 1158 - flake so you can use `myflake#tool` in `dependencies`: 1159 - 1160 - ```yaml 1161 - registry: 1162 - nixpkgs: github:nixos/nixpkgs/nixos-unstable 1163 - myflake: github:me/x 1164 - ``` 1165 - 1166 - #### Caches 1167 - 1168 - The `caches` field is a map of Nix binary cache URL to its 1169 - trusted public key. These are fed into the spindle's read 1170 - proxy, so the guest can substitute prebuilt paths from them 1171 - instead of building everything from scratch. 1172 - 1173 - ```yaml 1174 - caches: 1175 - https://nix-community.cachix.org: "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" 1176 - ``` 1177 - 1178 - #### Services and virtualisation 1179 - 1180 - The `services` and `virtualisation` fields are passed straight 1181 - through to NixOS. Anything you could write under 1182 - `services.*` or `virtualisation.*` in a NixOS configuration, 1183 - you can write here, and it's brought up before any of your 1184 - steps run. 1185 - 1186 - As a convenience, `true` works as shorthand for 1187 - `.enable = true` anywhere an `enable` option exists (e.g. 1188 - `virtualisation.docker: true`). 1189 - 1190 - ```yaml 1191 - services: 1192 - postgresql: 1193 - enable: true 1194 - ensureDatabases: ["spindle-workflow"] 1195 - ensureUsers: 1196 - - name: spindle-workflow 1197 - ensureDBOwnership: true 1198 - 1199 - virtualisation: 1200 - docker: true 1201 - ``` 1202 - 1203 - #### Recipes 1204 - 1205 - ##### Lint, test and build a Node project 1206 - 1207 - ```yaml 1208 - when: 1209 - - event: ["push", "pull_request"] 1210 - branch: ["main"] 1211 - 1212 - engine: microvm 1213 - image: nixos 1214 - 1215 - dependencies: 1216 - - pnpm 1217 - 1218 - steps: 1219 - - name: "Install dependencies" 1220 - command: pnpm install --frozen-lockfile 1221 - - name: "Lint and test" 1222 - command: | 1223 - pnpm run lint 1224 - pnpm test 1225 - - name: "Build" 1226 - command: pnpm run build 1227 - ``` 1228 - 1229 - ##### Check formatting 1230 - 1231 - ```yaml 1232 - when: 1233 - - event: ["push", "pull_request"] 1234 - branch: ["main"] 1235 - 1236 - engine: microvm 1237 - image: alpine # slimmer image for checking the formatting 1238 - 1239 - steps: 1240 - - name: "Install go" 1241 - command: apk add go 1242 - - name: "Check formatting" 1243 - command: test -z $(gofmt -l .) 1244 - ``` 1245 - 1246 - ##### Build a Rust project that links OpenSSL 1247 - 1248 - ```yaml 1249 - when: 1250 - - event: ["push", "pull_request"] 1251 - branch: ["main"] 1252 - 1253 - engine: microvm 1254 - image: nixos 1255 - 1256 - dependencies: 1257 - - gcc 1258 - - cargo 1259 - - rustc 1260 - - clippy 1261 - - rustfmt 1262 - - pkg-config # exports PKG_CONFIG_PATH for the libraries below 1263 - - openssl # the C library + headers openssl-sys links against 1264 - 1265 - steps: 1266 - - name: "Check formatting" 1267 - command: cargo fmt --check 1268 - - name: "Clippy" 1269 - command: cargo clippy --all-targets -- -D warnings 1270 - - name: "Test" 1271 - command: cargo test --all 1272 - - name: "Release build" 1273 - command: cargo build --release 1274 - ``` 1275 - 1276 - ##### Run migrations and integration tests against PostgreSQL 1277 - 1278 - ```yaml 1279 - when: 1280 - - event: ["push", "pull_request"] 1281 - branch: ["main"] 1282 - 1283 - engine: microvm 1284 - image: nixos 1285 - 1286 - environment: 1287 - DATABASE_URL: "postgresql:///spindle-workflow?host=/run/postgresql" 1288 - 1289 - dependencies: 1290 - - gcc 1291 - - cargo 1292 - - rustc 1293 - - pkg-config 1294 - - openssl 1295 - - sqlx-cli 1296 - 1297 - services: 1298 - postgresql: 1299 - enable: true 1300 - # has to be same name as the user for peer auth to work automatically 1301 - ensureDatabases: ["spindle-workflow"] 1302 - ensureUsers: 1303 - - name: spindle-workflow 1304 - ensureDBOwnership: true 1305 - 1306 - steps: 1307 - - name: "Run migrations" 1308 - command: sqlx migrate run 1309 - - name: "Integration tests" 1310 - command: cargo test --all 1311 - ``` 1312 - 1313 - ##### Build and push a Docker image on tag 1314 - 1315 - ```yaml 1316 - when: 1317 - - event: ["push"] 1318 - tag: ["v*"] 1319 - 1320 - engine: microvm 1321 - image: nixos 1322 - 1323 - virtualisation: 1324 - docker: true 1325 - 1326 - steps: 1327 - - name: "Build and push to ghcr.io" 1328 - command: | 1329 - set -euo pipefail 1330 - 1331 - echo "$REGISTRY_TOKEN" | docker login ghcr.io -u "$REGISTRY_USER" --password-stdin 1332 - image="ghcr.io/$REGISTRY_USER/myapp:$TANGLED_REF_NAME" 1333 - 1334 - docker build -t "$image" -t "ghcr.io/$REGISTRY_USER/myapp:latest" . 1335 - docker push "$image" 1336 - docker push "ghcr.io/$REGISTRY_USER/myapp:latest" 1337 - ``` 1338 - 1339 - ##### Deploy to Cloudflare Workers on tag 1340 - 1341 - ```yaml 1342 - # .tangled/workflows/deploy.yml 1343 - when: 1344 - - event: ["push"] 1345 - tag: ["v*"] 1346 - 1347 - engine: microvm 1348 - image: nixos 1349 - 1350 - dependencies: 1351 - - pnpm 1352 - 1353 - steps: 1354 - - name: "Install dependencies" 1355 - command: pnpm install --frozen-lockfile 1356 - - name: "Deploy worker" 1357 - # `wrangler` picks up `CLOUDFLARE_API_TOKEN` from the env. 1358 - # set it under **Settings → Secrets**. 1359 - command: pnpm exec wrangler deploy 1360 - ``` 1361 - 1362 - ##### Publish a release artifact 1363 - 1364 - ```yaml 1365 - when: 1366 - - event: ["push"] 1367 - tag: ["v*"] # trigger on versions 1368 - 1369 - engine: microvm 1370 - image: nixos 1371 - 1372 - dependencies: 1373 - - go 1374 - 1375 - steps: 1376 - - name: "Build release binary" 1377 - command: | 1378 - mkdir -p dist 1379 - CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o dist/myapp ./cmd/myapp 1380 - 1381 - - name: "Publish artifact record" 1382 - command: | 1383 - set -euo pipefail 1384 - # change this if you're not on `tngl.sh` 1385 - PDS="https://tngl.sh" 1386 - # also update this to your handle or did 1387 - ATP_IDENTIFIER="user.tngl.sh" 1388 - ARTIFACT_PATH="dist/myapp" 1389 - ARTIFACT_NAME="myapp" 1390 - 1391 - # set `ATP_APP_PASSWORD` under **Settings → Secrets** 1392 - session=$(curl -fsS -X POST "$PDS/xrpc/com.atproto.server.createSession" \ 1393 - -H "Content-Type: application/json" \ 1394 - -d "{\"identifier\":\"$ATP_IDENTIFIER\",\"password\":\"$ATP_APP_PASSWORD\"}") 1395 - jwt=$(echo "$session" | jq -r .accessJwt) 1396 - did=$(echo "$session" | jq -r .did) 1397 - 1398 - # upload the binary as a blob 1399 - blob=$(curl -fsS -X POST "$PDS/xrpc/com.atproto.repo.uploadBlob" \ 1400 - -H "Authorization: Bearer $jwt" \ 1401 - -H "Content-Type: application/octet-stream" \ 1402 - --data-binary @"$ARTIFACT_PATH") 1403 - 1404 - # note that this requires an annotated tag (`git tag -a v1.0.0 -m ...`) 1405 - tag_hash=$(git rev-parse "$TANGLED_REF_NAME^{tag}") 1406 - tag_bytes=$(printf '%s' "$tag_hash" | xxd -r -p | base64 | tr -d '=') 1407 - 1408 - # the sh.tangled.repo.artifact record for your artifact 1409 - record=$(jq -n \ 1410 - --arg did "$did" \ 1411 - --arg tag "$tag_bytes" \ 1412 - --arg name "$ARTIFACT_NAME" \ 1413 - --arg repo "$TANGLED_REPO_URL" \ 1414 - --arg created "$(date -Iseconds)" \ 1415 - --argjson blob "$(echo "$blob" | jq .blob)" '{ 1416 - repo: $did, 1417 - collection: "sh.tangled.repo.artifact", 1418 - validate: false, 1419 - record: { 1420 - "$type": "sh.tangled.repo.artifact", 1421 - tag: {"$bytes": $tag}, 1422 - name: $name, 1423 - repo: $repo, 1424 - artifact: $blob, 1425 - createdAt: $created 1426 - } 1427 - }') 1428 - 1429 - # create the record on the PDS 1430 - curl -fsS -X POST "$PDS/xrpc/com.atproto.repo.createRecord" \ 1431 - -H "Authorization: Bearer $jwt" \ 1432 - -H "Content-Type: application/json" \ 1433 - -d "$record" 1434 - ``` 1435 - 1436 - ## Self-hosting guide 1437 - 1438 - ### Prerequisites 1439 - 1440 - - Go 1441 - - For the **nixery** engine: Docker (or Podman with Docker 1442 - compatibility enabled). 1443 - - For the **microVM** engine: a Linux host with KVM, plus the 1444 - microVM host dependencies described in [Running microVM 1445 - workflows](#running-microvm-workflows). 1446 - 1447 - ### Configuration 1448 - 1449 - Spindle is configured using environment variables. The following environment variables are available: 1450 - 1451 - - `SPINDLE_SERVER_LISTEN_ADDR`: The address the server listens on (default: `"0.0.0.0:6555"`). 1452 - - `SPINDLE_SERVER_DB_PATH`: The path to the SQLite database file (default: `"spindle.db"`). 1453 - - `SPINDLE_SERVER_HOSTNAME`: The hostname of the server (required). 1454 - - `SPINDLE_SERVER_JETSTREAM_ENDPOINT`: The endpoint of the Jetstream server (default: `"wss://jetstream1.us-west.bsky.network/subscribe"`). 1455 - - `SPINDLE_SERVER_DEV`: A boolean indicating whether the server is running in development mode (default: `false`). 1456 - - `SPINDLE_SERVER_OWNER`: The DID of the owner (required). 1457 - - `SPINDLE_SERVER_LOG_DIR`: The directory to store workflow logs (default: `"/var/log/spindle"`). 1458 - - `SPINDLE_SERVER_DOCKER_SOCKET`: Path to Docker socket to expose to invoked Spindle containers (default: `""`). 1459 - - `SPINDLE_PIPELINES_NIXERY`: The Nixery URL (default: `"nixery.tangled.sh"`). 1460 - - `SPINDLE_PIPELINES_WORKFLOW_TIMEOUT`: The default workflow timeout (default: `"5m"`). 1461 - 1462 - For the microVM engine, the following are also available 1463 - (prefix `SPINDLE_MICROVM_PIPELINES_`): 1464 - 1465 - - `SPINDLE_MICROVM_PIPELINES_IMAGE_DIR`: Directory containing 1466 - microVM images (**required** to use the engine). See 1467 - [Running microVM workflows](#running-microvm-workflows). 1468 - - `SPINDLE_MICROVM_PIPELINES_DEFAULT_IMAGE`: Image used when a 1469 - workflow doesn't set `image` (default: `"nixos-x86_64"`). 1470 - - `SPINDLE_MICROVM_PIPELINES_OVERLAY_DIR`: Where per-workflow 1471 - temporary disks are created (default: the system temp dir). 1472 - - `SPINDLE_MICROVM_PIPELINES_ENABLE_KVM`: Use KVM hardware 1473 - acceleration (default: `true`). Without KVM, guests fall 1474 - back to slow software emulation. 1475 - - `SPINDLE_MICROVM_PIPELINES_WORKFLOW_TIMEOUT`: Default 1476 - workflow timeout (default: `"5m"`). 1477 - 1478 - Optional resource limits (a value of `0` disables that 1479 - limit). The limits cap usage across all running microVM 1480 - workflows: 1481 - 1482 - - `SPINDLE_MICROVM_PIPELINES_MAX_TOTAL_MEMORY_MIB` 1483 - - `SPINDLE_MICROVM_PIPELINES_MAX_TOTAL_VCPUS` 1484 - - `SPINDLE_MICROVM_PIPELINES_MAX_TOTAL_DISK_MIB` 1485 - 1486 - Optional cgroup enforcement: 1487 - 1488 - - `SPINDLE_MICROVM_PIPELINES_ENABLE_CGROUPS`: Place each 1489 - workflow's QEMU and slirp4netns in a per-workflow cgroup= 1490 - (default: `false`). 1491 - - `SPINDLE_MICROVM_PIPELINES_CGROUP_PARENT`: Parent cgroup; 1492 - `self` resolves the spindle service's own cgroup (default: 1493 - `"self"`). 1494 - - `SPINDLE_MICROVM_PIPELINES_CGROUP_PIDS_MAX`: Max processes 1495 - per workflow cgroup (default: `4096`). 1496 - - `SPINDLE_MICROVM_PIPELINES_CGROUP_SWAP_MAX_MIB`: Max swap 1497 - per workflow cgroup (default: `0`, no swap). 1498 - - `SPINDLE_MICROVM_PIPELINES_CGROUP_SUPERVISOR_MEMORY_MIN_MIB`: 1499 - Memory protected for spindle itself so it isn't OOM-killed 1500 - before the workflows (default: `512`). 1501 - 1502 - To push paths built inside microVMs back to a shared Nix 1503 - cache (and read from it), configure the cache (prefix 1504 - `SPINDLE_NIX_CACHE_`): 1505 - 1506 - - `SPINDLE_NIX_CACHE_READ_URLS`: Comma-separated binary cache 1507 - URLs the guest reads from. 1508 - - `SPINDLE_NIX_CACHE_TRUSTED_PUBLIC_KEYS`: Comma-separated 1509 - trusted public keys for those caches. 1510 - - `SPINDLE_NIX_CACHE_UPLOAD_URL`: Cache URL that paths built 1511 - in the guest are uploaded to. 1512 - 1513 - ### Running spindle 1514 - 1515 - 1. **Set the environment variables.** For example: 1516 - 1517 - ```shell 1518 - export SPINDLE_SERVER_HOSTNAME="your-hostname" 1519 - export SPINDLE_SERVER_OWNER="your-did" 1520 - ``` 1521 - 1522 - 2. **Build the Spindle binary.** 1523 - 1524 - ```shell 1525 - cd core 1526 - go mod download 1527 - go build -o cmd/spindle/spindle cmd/spindle/main.go 1528 - ``` 1529 - 1530 - 3. **Create the log directory.** 1531 - 1532 - ```shell 1533 - sudo mkdir -p /var/log/spindle 1534 - sudo chown $USER:$USER -R /var/log/spindle 1535 - ``` 1536 - 1537 - 4. **Run the Spindle binary.** 1538 - 1539 - ```shell 1540 - ./cmd/spindle/spindle 1541 - ``` 1542 - 1543 - Spindle will now start, connect to the Jetstream server, and begin processing pipelines. 1544 - 1545 - ### Running microVM workflows 1546 - 1547 - The microVM engine needs a few extra things on the host, and 1548 - it needs images to boot. 1549 - 1550 - #### Host dependencies 1551 - 1552 - microVM workflows depend on a handful of host tools and 1553 - devices. spindle checks for the ones an image needs right 1554 - before it launches, so a missing dependency surfaces as a 1555 - clear error. You'll need: 1556 - 1557 - - `qemu`: the runner. The QEMU binary for the image's arch 1558 - must be present (e.g. `qemu-system-x86_64`). 1559 - - `mkfs.ext4` (from `e2fsprogs`): to format the per-workflow 1560 - writable volumes. 1561 - - [`slirp4netns`](https://github.com/rootless-containers/slirp4netns#install), 1562 - `ip` (from `iproute2`), `mount` and `unshare` (from `util-linux`): 1563 - used to sandbox guest networking. 1564 - - `/dev/kvm`: for hardware acceleration (unless you disable 1565 - KVM with `SPINDLE_MICROVM_PIPELINES_ENABLE_KVM=false`). 1566 - - `/dev/vhost-vsock`: used by QEMU to enable guest-to-host vsock 1567 - communication. 1568 - - `/dev/vsock`: used by spindle on the host to listen on vsock ports 1569 - and accept guest agent connections. 1570 - - `/dev/net/tun`: required by `slirp4netns` to set up tap devices 1571 - for sandboxed guest networking. 1572 - 1573 - On NixOS, the [spindle 1574 - module](https://tangled.org/tangled.org/core/blob/master/nix/modules/spindle.nix) 1575 - puts `qemu`, `e2fsprogs`, `slirp4netns`, `iproute2` and 1576 - `util-linux` on the service's `PATH` for you. 1577 - 1578 - #### Container virtualization 1579 - 1580 - Running `spindle` inside a container (e.g., Docker, Podman, or LXD) requires passing host device nodes into the container and granting the runtime additional privileges. Because spindle uses nested namespaces (`unshare`) and helper tools (`slirp4netns`), the container configuration will require: 1581 - 1582 - - `/dev/vsock`, `/dev/vhost-vsock`, `/dev/kvm`, and `/dev/net/tun` mapped from the host. 1583 - - `NET_ADMIN` and `SYS_ADMIN` capabilities to manage network namespaces and mounts inside the container. 1584 - - Relaxed seccomp filters (e.g., `seccomp=unconfined`) and SELinux/AppArmor containment if they restrict namespace creation or device access. 1585 - 1586 - #### Building images 1587 - 1588 - Images are built with Nix. The flake exposes packages for the 1589 - two stock images (use the `-tarball` prefixed ones for a gzipped 1590 - tarball you can copy to another host): 1591 - 1592 - ```shell 1593 - # a NixOS image 1594 - nix build .#spindle-nixos-image 1595 - # an Alpine image 1596 - nix build .#spindle-alpine-image 1597 - ``` 1598 - 1599 - #### Installing images 1600 - 1601 - Spindle looks for images in 1602 - `SPINDLE_MICROVM_PIPELINES_IMAGE_DIR`. An image is resolved by 1603 - the name a workflow puts in its `image` field, matched 1604 - literally against what's on disk: 1605 - 1606 - 1. a directory `<name>/` containing a `spec.json` (next to the 1607 - kernel/initrd/store-disk), or 1608 - 2. a flat `<name>.json` self-contained spec. 1609 - 1610 - Resolution depends only on the name and what's on disk, never 1611 - on the host doing the resolving, so the same workflow resolves 1612 - to the same image on every spindle. If you keep multiple 1613 - arches side by side, you can name them `<name>-<arch>` (e.g. 1614 - `nixos-x86_64`, `alpine-aarch64`); the suffix is just part of 1615 - the name. To make a name like `nixos` work if you are hosting 1616 - multiple arches, you can use symlinks. 1617 - 1618 - On NixOS, you'll most likely want to use `systemd.tmpfiles.rules` 1619 - to set these up declaratively. 1620 - 1621 - ## Architecture 1622 - 1623 - Spindle is a small CI runner service. Here's a high-level overview of how it operates: 1624 - 1625 - - Listens for [`sh.tangled.spindle.member`](/lexicons/spindle/member.json) and 1626 - [`sh.tangled.repo`](/lexicons/repo.json) records on the Jetstream. 1627 - - When a new repo record comes through (typically when you add a spindle to a 1628 - repo from the settings), spindle then resolves the underlying knot and 1629 - subscribes to repo events (see: 1630 - [`sh.tangled.pipeline`](/lexicons/pipeline.json)). 1631 - - The spindle engine then handles execution of the pipeline, with results and 1632 - logs beamed on the spindle event stream over WebSocket 1633 - 1634 - ### The engines 1635 - 1636 - Spindle has two execution backends, picked per-workflow with 1637 - the [`engine`](#engine) field: 1638 - 1639 - - **nixery**: executes each step in a fresh Docker container 1640 - (Podman works too, if Docker compatibility is enabled so 1641 - that `/run/docker.sock` is created), with state persisted 1642 - across steps within the `/tangled/workspace` directory. The 1643 - base image for the container is constructed on the fly using 1644 - [Nixery](https://nixery.dev), which is/rhandy for caching 1645 - layers for frequently used packages. 1646 - - **microvm**: runs the whole workflow inside its own 1647 - microVM, supporting different images, with extra 1648 - configuration for NixOS images (e.g. services in workflow file) 1649 - See the [engine 1650 - README](https://tangled.org/tangled.org/core/blob/master/spindle/engines/microvm/README.md) 1651 - for the architecture in depth. 1652 - 1653 - The pipeline manifest is [specified here](https://docs.tangled.org/spindles.html#pipelines). 1654 - 1655 - ## Secrets with openbao 1656 - 1657 - This document covers setting up spindle to use OpenBao for secrets 1658 - management via OpenBao Proxy instead of the default SQLite backend. 1659 - 1660 - ### Overview 1661 - 1662 - Spindle now uses OpenBao Proxy for secrets management. The proxy handles 1663 - authentication automatically using AppRole credentials, while spindle 1664 - connects to the local proxy instead of directly to the OpenBao server. 1665 - 1666 - This approach provides better security, automatic token renewal, and 1667 - simplified application code. 1668 - 1669 - ### Installation 1670 - 1671 - Install OpenBao from Nixpkgs: 1672 - 1673 - ```bash 1674 - nix shell nixpkgs#openbao # for a local server 1675 - ``` 1676 - 1677 - ### Setup 1678 - 1679 - The setup process can is documented for both local development and production. 1680 - 1681 - #### Local development 1682 - 1683 - Start OpenBao in dev mode: 1684 - 1685 - ```bash 1686 - bao server -dev -dev-root-token-id="root" -dev-listen-address=127.0.0.1:8201 1687 - ``` 1688 - 1689 - This starts OpenBao on `http://localhost:8201` with a root token. 1690 - 1691 - Set up environment for bao CLI: 1692 - 1693 - ```bash 1694 - export BAO_ADDR=http://localhost:8200 1695 - export BAO_TOKEN=root 1696 - ``` 1697 - 1698 - #### Production 1699 - 1700 - You would typically use a systemd service with a 1701 - configuration file. Refer to 1702 - [@tangled.org/infra](https://tangled.org/@tangled.org/infra) 1703 - for how this can be achieved using Nix. 1704 - 1705 - Then, initialize the bao server: 1706 - 1707 - ```bash 1708 - bao operator init -key-shares=1 -key-threshold=1 1709 - ``` 1710 - 1711 - This will print out an unseal key and a root key. Save them 1712 - somewhere (like a password manager). Then unseal the vault 1713 - to begin setting it up: 1714 - 1715 - ```bash 1716 - bao operator unseal <unseal_key> 1717 - ``` 1718 - 1719 - All steps below remain the same across both dev and 1720 - production setups. 1721 - 1722 - #### Configure openbao server 1723 - 1724 - Create the spindle KV mount: 1725 - 1726 - ```bash 1727 - bao secrets enable -path=spindle -version=2 kv 1728 - ``` 1729 - 1730 - Set up AppRole authentication and policy: 1731 - 1732 - Create a policy file `spindle-policy.hcl`: 1733 - 1734 - ```hcl 1735 - # Full access to spindle KV v2 data 1736 - path "spindle/data/*" { 1737 - capabilities = ["create", "read", "update", "delete"] 1738 - } 1739 - 1740 - # Access to metadata for listing and management 1741 - path "spindle/metadata/*" { 1742 - capabilities = ["list", "read", "delete", "update"] 1743 - } 1744 - 1745 - # Allow listing at root level 1746 - path "spindle/" { 1747 - capabilities = ["list"] 1748 - } 1749 - 1750 - # Required for connection testing and health checks 1751 - path "auth/token/lookup-self" { 1752 - capabilities = ["read"] 1753 - } 1754 - ``` 1755 - 1756 - Apply the policy and create an AppRole: 1757 - 1758 - ```bash 1759 - bao policy write spindle-policy spindle-policy.hcl 1760 - bao auth enable approle 1761 - bao write auth/approle/role/spindle \ 1762 - token_policies="spindle-policy" \ 1763 - token_ttl=1h \ 1764 - token_max_ttl=4h \ 1765 - bind_secret_id=true \ 1766 - secret_id_ttl=0 \ 1767 - secret_id_num_uses=0 1768 - ``` 1769 - 1770 - Get the credentials: 1771 - 1772 - ```bash 1773 - # Get role ID (static) 1774 - ROLE_ID=$(bao read -field=role_id auth/approle/role/spindle/role-id) 1775 - 1776 - # Generate secret ID 1777 - SECRET_ID=$(bao write -f -field=secret_id auth/approle/role/spindle/secret-id) 1778 - 1779 - echo "Role ID: $ROLE_ID" 1780 - echo "Secret ID: $SECRET_ID" 1781 - ``` 1782 - 1783 - #### Create proxy configuration 1784 - 1785 - Create the credential files: 1786 - 1787 - ```bash 1788 - # Create directory for OpenBao files 1789 - mkdir -p /tmp/openbao 1790 - 1791 - # Save credentials 1792 - echo "$ROLE_ID" > /tmp/openbao/role-id 1793 - echo "$SECRET_ID" > /tmp/openbao/secret-id 1794 - chmod 600 /tmp/openbao/role-id /tmp/openbao/secret-id 1795 - ``` 1796 - 1797 - Create a proxy configuration file `/tmp/openbao/proxy.hcl`: 1798 - 1799 - ```hcl 1800 - # OpenBao server connection 1801 - vault { 1802 - address = "http://localhost:8200" 1803 - } 1804 - 1805 - # Auto-Auth using AppRole 1806 - auto_auth { 1807 - method "approle" { 1808 - mount_path = "auth/approle" 1809 - config = { 1810 - role_id_file_path = "/tmp/openbao/role-id" 1811 - secret_id_file_path = "/tmp/openbao/secret-id" 1812 - } 1813 - } 1814 - 1815 - # Optional: write token to file for debugging 1816 - sink "file" { 1817 - config = { 1818 - path = "/tmp/openbao/token" 1819 - mode = 0640 1820 - } 1821 - } 1822 - } 1823 - 1824 - # Proxy listener for spindle 1825 - listener "tcp" { 1826 - address = "127.0.0.1:8201" 1827 - tls_disable = true 1828 - } 1829 - 1830 - # Enable API proxy with auto-auth token 1831 - api_proxy { 1832 - use_auto_auth_token = true 1833 - } 1834 - 1835 - # Enable response caching 1836 - cache { 1837 - use_auto_auth_token = true 1838 - } 1839 - 1840 - # Logging 1841 - log_level = "info" 1842 - ``` 1843 - 1844 - #### Start the proxy 1845 - 1846 - Start OpenBao Proxy: 1847 - 1848 - ```bash 1849 - bao proxy -config=/tmp/openbao/proxy.hcl 1850 - ``` 1851 - 1852 - The proxy will authenticate with OpenBao and start listening on 1853 - `127.0.0.1:8201`. 1854 - 1855 - #### Configure spindle 1856 - 1857 - Set these environment variables for spindle: 1858 - 1859 - ```bash 1860 - export SPINDLE_SERVER_SECRETS_PROVIDER=openbao 1861 - export SPINDLE_SERVER_SECRETS_OPENBAO_PROXY_ADDR=http://127.0.0.1:8201 1862 - export SPINDLE_SERVER_SECRETS_OPENBAO_MOUNT=spindle 1863 - ``` 1864 - 1865 - On startup, spindle will now connect to the local proxy, 1866 - which handles all authentication automatically. 1867 - 1868 - ### Production setup for proxy 1869 - 1870 - For production, you'll want to run the proxy as a service: 1871 - 1872 - Place your production configuration in 1873 - `/etc/openbao/proxy.hcl` with proper TLS settings for the 1874 - vault connection. 1875 - 1876 - ### Verifying setup 1877 - 1878 - Test the proxy directly: 1879 - 1880 - ```bash 1881 - # Check proxy health 1882 - curl -H "X-Vault-Request: true" http://127.0.0.1:8201/v1/sys/health 1883 - 1884 - # Test token lookup through proxy 1885 - curl -H "X-Vault-Request: true" http://127.0.0.1:8201/v1/auth/token/lookup-self 1886 - ``` 1887 - 1888 - Test OpenBao operations through the server: 1889 - 1890 - ```bash 1891 - # List all secrets 1892 - bao kv list spindle/ 1893 - 1894 - # Add a test secret via the spindle API, then check it exists 1895 - bao kv list spindle/repos/ 1896 - 1897 - # Get a specific secret 1898 - bao kv get spindle/repos/your_repo_path/SECRET_NAME 1899 - ``` 1900 - 1901 - ### How it works 1902 - 1903 - - Spindle connects to OpenBao Proxy on localhost (typically 1904 - port 8200 or 8201) 1905 - - The proxy authenticates with OpenBao using AppRole 1906 - credentials 1907 - - All spindle requests go through the proxy, which injects 1908 - authentication tokens 1909 - - Secrets are stored at 1910 - `spindle/repos/{sanitized_repo_path}/{secret_key}` 1911 - - Repository paths like `did:plc:alice/myrepo` become 1912 - `did_plc_alice_myrepo` 1913 - - The proxy handles all token renewal automatically 1914 - - Spindle no longer manages tokens or authentication 1915 - directly 1916 - 1917 - ### Troubleshooting 1918 - 1919 - **Connection refused**: Check that the OpenBao Proxy is 1920 - running and listening on the configured address. 1921 - 1922 - **403 errors**: Verify the AppRole credentials are correct 1923 - and the policy has the necessary permissions. 1924 - 1925 - **404 route errors**: The spindle KV mount probably doesn't 1926 - exist—run the mount creation step again. 1927 - 1928 - **Proxy authentication failures**: Check the proxy logs and 1929 - verify the role-id and secret-id files are readable and 1930 - contain valid credentials. 1931 - 1932 - **Secret not found after writing**: This can indicate policy 1933 - permission issues. Verify the policy includes both 1934 - `spindle/data/*` and `spindle/metadata/*` paths with 1935 - appropriate capabilities. 1936 - 1937 - Check proxy logs: 1938 - 1939 - ```bash 1940 - # If running as systemd service 1941 - journalctl -u openbao-proxy -f 1942 - 1943 - # If running directly, check the console output 1944 - ``` 1945 - 1946 - Test AppRole authentication manually: 1947 - 1948 - ```bash 1949 - bao write auth/approle/login \ 1950 - role_id="$(cat /tmp/openbao/role-id)" \ 1951 - secret_id="$(cat /tmp/openbao/secret-id)" 1952 - ``` 1953 - 1954 - # Webhooks 1955 - 1956 - Webhooks allow you to receive HTTP POST notifications when events occur in your repositories. This enables you to integrate Tangled with external services, trigger CI/CD pipelines, send notifications, or automate workflows. 1957 - 1958 - ## Overview 1959 - 1960 - Webhooks send HTTP POST requests to URLs you configure whenever specific events happen. Currently, Tangled supports push, repository rename, and pull request events, with more event types coming soon. 1961 - 1962 - ## Configuring webhooks 1963 - 1964 - To set up a webhook for your repository: 1965 - 1966 - 1. Navigate to your repository 1967 - 2. Go to **Settings → Hooks** 1968 - 3. Click **new webhook** 1969 - 4. Configure your webhook: 1970 - - **Payload URL**: The endpoint that will receive the webhook POST requests 1971 - - **Secret**: An optional secret key for verifying webhook authenticity (leave blank to send unsigned webhooks) 1972 - - **Events**: Select which events trigger the webhook 1973 - - **Active**: Toggle whether the webhook is enabled 1974 - 1975 - ## Webhook payload 1976 - 1977 - ### Push 1978 - 1979 - When a push event occurs, Tangled sends a POST request with a JSON payload of the format: 1980 - 1981 - ```json 1982 - { 1983 - "after": "7b320e5cbee2734071e4310c1d9ae401d8f6cab5", 1984 - "before": "c04ddf64eddc90e4e2a9846ba3b43e67a0e2865e", 1985 - "pusher": { 1986 - "did": "did:plc:hwevmowznbiukdf6uk5dwrrq" 1987 - }, 1988 - "ref": "refs/heads/main", 1989 - "repository": { 1990 - "clone_url": "https://tangled.org/did:plc:hwevmowznbiukdf6uk5dwrrq/some-repo", 1991 - "created_at": "2025-09-15T08:57:23Z", 1992 - "description": "an example repository", 1993 - "fork": false, 1994 - "full_name": "did:plc:hwevmowznbiukdf6uk5dwrrq/some-repo", 1995 - "html_url": "https://tangled.org/did:plc:hwevmowznbiukdf6uk5dwrrq/some-repo", 1996 - "name": "some-repo", 1997 - "open_issues_count": 5, 1998 - "owner": { 1999 - "did": "did:plc:hwevmowznbiukdf6uk5dwrrq" 2000 - }, 2001 - "ssh_url": "ssh://git@tangled.org/did:plc:hwevmowznbiukdf6uk5dwrrq/some-repo", 2002 - "stars_count": 1, 2003 - "updated_at": "2025-09-15T08:57:23Z" 2004 - } 2005 - } 2006 - ``` 2007 - 2008 - ### Pull request 2009 - 2010 - Pull request events are sent as separate event types, so you can subscribe to 2011 - exactly the transitions you care about: 2012 - 2013 - - `pull_request:created` — a pull request was opened 2014 - - `pull_request:resubmitted` — a new round (revision) was pushed to a pull request 2015 - - `pull_request:merged` — a pull request was merged 2016 - - `pull_request:closed` — a pull request was closed 2017 - - `pull_request:reopened` — a closed pull request was reopened 2018 - 2019 - All pull request events share the same payload format: 2020 - 2021 - ```json 2022 - { 2023 - "action": "created", 2024 - "pull_request": { 2025 - "number": 4, 2026 - "title": "add dark mode", 2027 - "body": "implements dark mode as discussed in #2", 2028 - "state": "open", 2029 - "target_branch": "main", 2030 - "source": { 2031 - "branch": "dark-mode", 2032 - "sha": "7b320e5cbee2734071e4310c1d9ae401d8f6cab5" 2033 - }, 2034 - "round_number": 0, 2035 - "owner": { 2036 - "did": "did:plc:hwevmowznbiukdf6uk5dwrrq" 2037 - }, 2038 - "html_url": "https://tangled.org/did:plc:hwevmowznbiukdf6uk5dwrrq/some-repo/pulls/4", 2039 - "patch_url": "https://tangled.org/did:plc:hwevmowznbiukdf6uk5dwrrq/some-repo/pulls/4/round/0.patch", 2040 - "created_at": "2025-09-15T08:57:23Z" 2041 - }, 2042 - "repository": { ... }, 2043 - "sender": { 2044 - "did": "did:plc:hwevmowznbiukdf6uk5dwrrq" 2045 - } 2046 - } 2047 - ``` 2048 - 2049 - Notes: 2050 - 2051 - - `action` mirrors the event type suffix (`created`, `resubmitted`, `merged`, `closed`, `reopened`). 2052 - - `repository` has the same format as in the push payload. 2053 - - The patch itself is not embedded in the payload (patches can be large); fetch it from `patch_url` instead. `round_number` identifies the latest round, and `patch_url` always points at that round's patch. 2054 - - `source` is only present for branch-based and fork-based pull requests; it is omitted for patch-based pulls. For fork-based pulls, `source.repo` contains the DID of the source repository. 2055 - - `sender` is the user who performed the action. 2056 - 2057 - ## HTTP headers 2058 - 2059 - Each webhook request includes the following headers: 2060 - 2061 - - `Content-Type: application/json` 2062 - - `User-Agent: Tangled-Hook/<short-sha>` — User agent with short SHA of the commit (push events); `Tangled-Hook/pull_request` for pull request events 2063 - - `X-Tangled-Event: push` — The full event type (e.g. `push`, `pull_request:merged`) 2064 - - `X-Tangled-Hook-ID: <webhook-id>` — The webhook ID 2065 - - `X-Tangled-Delivery: <uuid>` — Unique delivery ID 2066 - - `X-Tangled-Signature-256: sha256=<hmac>` — HMAC-SHA256 signature (if secret configured) 2067 - 2068 - ## Verifying webhook signatures 2069 - 2070 - If you configured a secret, you should verify the webhook signature to ensure requests are authentic. For example, in Go: 2071 - 2072 - ```go 2073 - package main 2074 - 2075 - import ( 2076 - "crypto/hmac" 2077 - "crypto/sha256" 2078 - "encoding/hex" 2079 - "io" 2080 - "net/http" 2081 - "strings" 2082 - ) 2083 - 2084 - func verifySignature(payload []byte, signatureHeader, secret string) bool { 2085 - // Remove 'sha256=' prefix from signature header 2086 - signature := strings.TrimPrefix(signatureHeader, "sha256=") 2087 - 2088 - // Compute expected signature 2089 - mac := hmac.New(sha256.New, []byte(secret)) 2090 - mac.Write(payload) 2091 - expected := hex.EncodeToString(mac.Sum(nil)) 2092 - 2093 - // Use constant-time comparison to prevent timing attacks 2094 - return hmac.Equal([]byte(signature), []byte(expected)) 2095 - } 2096 - 2097 - func webhookHandler(w http.ResponseWriter, r *http.Request) { 2098 - // Read the request body 2099 - payload, err := io.ReadAll(r.Body) 2100 - if err != nil { 2101 - http.Error(w, "Bad request", http.StatusBadRequest) 2102 - return 2103 - } 2104 - 2105 - // Get signature from header 2106 - signatureHeader := r.Header.Get("X-Tangled-Signature-256") 2107 - 2108 - // Verify signature 2109 - if signatureHeader != "" && verifySignature(payload, signatureHeader, yourSecret) { 2110 - // Webhook is authentic, process it 2111 - processWebhook(payload) 2112 - w.WriteHeader(http.StatusOK) 2113 - } else { 2114 - http.Error(w, "Invalid signature", http.StatusUnauthorized) 2115 - } 2116 - } 2117 - ``` 2118 - 2119 - ## Delivery retries 2120 - 2121 - Webhooks are automatically retried on failure: 2122 - 2123 - - **3 total attempts** (1 initial + 2 retries) 2124 - - **Exponential backoff** starting at 1 second, max 10 seconds 2125 - - **Retried on**: 2126 - - Network errors 2127 - - HTTP 5xx server errors 2128 - - **Not retried on**: 2129 - - HTTP 4xx client errors (bad request, unauthorized, etc.) 2130 - 2131 - ### Timeouts 2132 - 2133 - Webhook requests timeout after 30 seconds. If your endpoint needs more time: 2134 - 2135 - 1. Respond with 200 OK immediately 2136 - 2. Process the webhook asynchronously in the background 2137 - 2138 - ## Example integrations 2139 - 2140 - ### Discord notifications 2141 - 2142 - ```javascript 2143 - app.post("/webhook", (req, res) => { 2144 - const payload = req.body; 2145 - 2146 - fetch("https://discord.com/api/webhooks/...", { 2147 - method: "POST", 2148 - headers: { "Content-Type": "application/json" }, 2149 - body: JSON.stringify({ 2150 - content: `New push to ${payload.repository.full_name}`, 2151 - embeds: [ 2152 - { 2153 - title: `${payload.pusher.did} pushed to ${payload.ref}`, 2154 - url: payload.repository.html_url, 2155 - color: 0x00ff00, 2156 - }, 2157 - ], 2158 - }), 2159 - }); 2160 - 2161 - res.status(200).send("OK"); 2162 - }); 2163 - ``` 2164 - 2165 - # Migrating knots and spindles 2166 - 2167 - Sometimes, non-backwards compatible changes are made to the 2168 - knot/spindle XRPC APIs. If you host a knot or a spindle, you 2169 - will need to follow this guide to upgrade. Typically, this 2170 - only requires you to deploy the newest version. 2171 - 2172 - This document is laid out in reverse-chronological order. 2173 - Newer migration guides are listed first, and older guides 2174 - are further down the page. 2175 - 2176 - ## Upgrading to v1.16.0-alpha 2177 - 2178 - Starting with v1.16.0-alpha, spindles own CI pipeline data 2179 - directly. The appview no longer stores pipeline runs or follows 2180 - spindle event streams for pipeline history. Instead, it asks the 2181 - configured spindle for pipeline lists, single pipeline details, 2182 - workflow logs, retries, and cancellations over XRPC. 2183 - 2184 - This means that existing pipeline logs / runs won't appear after 2185 - you upgrade. Existing pipeline history from the appview cannot be 2186 - automatically migrated. If you want to migrate your data, you can 2187 - reach out to us and we will send you an SQL file that'll add the data 2188 - into your spindle. 2189 - 2190 - - Upgrade to the latest tag (v1.16.0 or above) 2191 - - Head to the [spindle 2192 - dashboard](https://tangled.org/settings/spindles) and hit the 2193 - "retry" button to verify your spindle 2194 - 2195 - ## Upgrading to v1.15.0-alpha 2196 - 2197 - With v1.15.0-alpha, a knot itself owns its members and 2198 - per-repo collaborators directly. Previously this data was sourced from 2199 - PDS records (`sh.tangled.knot.member` and `sh.tangled.repo.collaborator`) 2200 - that the appview and the knot both read off the firehose. 2201 - The knot is now the source of truth and serves them over XRPC instead: 2202 - 2203 - - `sh.tangled.knot.addMember`, `sh.tangled.knot.removeMember`, `sh.tangled.knot.listMembers` 2204 - - `sh.tangled.repo.addCollaborator`, `sh.tangled.repo.removeCollaborator`, `sh.tangled.repo.listCollaborators` 2205 - 2206 - Until your knot is upgraded, the appview keeps reading its 2207 - members and collaborators from the old firehose-sourced records. 2208 - Upgrade to move your knot onto knot-owned access control. 2209 - 2210 - - Upgrade to the latest tag (v1.15.0 or above) 2211 - - Head to the [knot dashboard](https://tangled.org/settings/knots) and 2212 - hit the "retry" button to verify your knot 2213 - 2214 - ## Upgrading to v1.14.0-alpha 2215 - 2216 - Starting with v1.14.0-alpha, the fully knot uses the repoDID as its 2217 - canonical handle for repositories. This unlocks repository 2218 - renames from the appview UI and changes the wire format for 2219 - the following lexicons (`sh.tangled.repo.pull`, `sh.tangled.repo.collaborator`, 2220 - `sh.tangled.repo.issue`, `sh.tangled.git.refUpdate`). 2221 - 2222 - Knots that have not been upgraded may silently drop new push 2223 - events, pull requests, issues, and collaborator invites for 2224 - repositories they host until upgraded. So upgrade please!!! 2225 - 2226 - - Upgrade to the latest tag (v1.14.0 or above) 2227 - - Head to the [knot dashboard](https://tangled.org/settings/knots) and 2228 - hit the "retry" button to verify your knot 2229 - 2230 - ## Upgrading to v1.13.0-alpha 2231 - 2232 - Starting with v1.13.0-alpha, every repository on a knot is 2233 - assigned a DID. This makes repositories stable across 2234 - renames and transfers. 2235 - 2236 - When you upgrade your knot to this version, the server will 2237 - automatically mint DIDs for all existing repositories on 2238 - startup. This is a one-time process and you may see 2239 - additional log output during the first boot as DIDs are 2240 - assigned. 2241 - 2242 - - Upgrade to the latest tag (v1.13.0 or above) 2243 - - Head to the [knot dashboard](https://tangled.org/settings/knots) and 2244 - hit the "retry" button to verify your knot 2245 - 2246 - ## Upgrading from v1.8.x 2247 - 2248 - After v1.8.2, the HTTP API for knots and spindles has been 2249 - deprecated and replaced with XRPC. Repositories on outdated 2250 - knots will not be viewable from the appview. Upgrading is 2251 - straightforward however. 2252 - 2253 - For knots: 2254 - 2255 - - Upgrade to the latest tag (v1.9.0 or above) 2256 - - Head to the [knot dashboard](https://tangled.org/settings/knots) and 2257 - hit the "retry" button to verify your knot 2258 - 2259 - For spindles: 2260 - 2261 - - Upgrade to the latest tag (v1.9.0 or above) 2262 - - Head to the [spindle 2263 - dashboard](https://tangled.org/settings/spindles) and hit the 2264 - "retry" button to verify your spindle 2265 - 2266 - ## Upgrading from v1.7.x 2267 - 2268 - After v1.7.0, knot secrets have been deprecated. You no 2269 - longer need a secret from the appview to run a knot. All 2270 - authorized commands to knots are managed via [Inter-Service 2271 - Authentication](https://atproto.com/specs/xrpc#inter-service-authentication-jwt). 2272 - Knots will be read-only until upgraded. 2273 - 2274 - Upgrading is quite easy, in essence: 2275 - 2276 - - `KNOT_SERVER_SECRET` is no more, you can remove this 2277 - environment variable entirely 2278 - - `KNOT_SERVER_OWNER` is now required on boot, set this to 2279 - your DID. You can find your DID in the 2280 - [settings](https://tangled.org/settings) page. 2281 - - Restart your knot once you have replaced the environment 2282 - variable 2283 - - Head to the [knot dashboard](https://tangled.org/settings/knots) and 2284 - hit the "retry" button to verify your knot. This simply 2285 - writes a `sh.tangled.knot` record to your PDS. 2286 - 2287 - If you use the nix module, simply bump the flake to the 2288 - latest revision, and change your config block like so: 2289 - 2290 - ```diff 2291 - services.tangled.knot = { 2292 - enable = true; 2293 - server = { 2294 - - secretFile = /path/to/secret; 2295 - + owner = "did:plc:foo"; 2296 - }; 2297 - }; 2298 - ``` 2299 - 2300 - # Bobbin 2301 - 2302 - Bobbin is an API appview for Tangled records. It serves XRPC 2303 - endpoints for `sh.tangled.*`, with it you can get repos, 2304 - issues, pulls, comments, follows, stars, labels, pipelines, 2305 - and profiles. It is read-only, there is no auth, since that 2306 - should all be handled direct-to-PDS and knot respectively. 2307 - 2308 - **Bobbin has no permanent storage**. 2309 - 2310 - It is only a glorified edge index, in the graph theory 2311 - sense. Additionally it has a record cache, re-filled on 2312 - demand. All other data that Bobbin serves comes live from 2313 - PDSes & knots. 2314 - 2315 - ## What Bobbin needs 2316 - 2317 - The way that Bobbin is able to pull off being 2318 - so stateless is by moving state upstream. 2319 - Primarily it depends on an instance of 2320 - [Hydrant](https://tangled.org/did:plc:6v3ul2ptnqctyxwkz5ti4amn) 2321 - , which is the service that gives an event stream 2322 - for Bobbin to quickly backfill from on every restart. 2323 - Backfilling ought to take less than a couple of minutes 2324 - maximum. If the upstream instance of Hydrant fails 2325 - while Bobbin is live, its list/count endpoints stop 2326 - advancing and report a stale cursor. Single-lookups 2327 - will continue working, due to the second dependency: 2328 - [Slingshot](https://tangled.org/did:plc:c7mc2fn47ihdihul4vjwsuy3/tree/main/slingshot). 2329 - Slingshot fetches individual records & resolves identities. 2330 - If the upstream instance of Slingshot fails, single-lookups 2331 - will fail with a `502` error. There are some aggregation 2332 - endpoints that use Slingshot for hydrating, which will also 2333 - fail. 2334 - 2335 - A soft dependency that ought to exist for Bobbin to operate 2336 - correctly is simply the plethora of knots that are out 2337 - there, that Bobbin talks to directly for git data and, for 2338 - knots at v1.15+, members & collaborators. 2339 - 2340 - ## Building Bobbin 2341 - 2342 - Bobbin is under [Tangled's core monorepo, under bobbin/](https://tangled.org/did:plc:j5hmlfdrwkvtxm7cjmu7j2is/tree/master/bobbin). 2343 - Here's an easy local debug-build: 2344 - 2345 - ```sh 2346 - cargo build -p bobbin 2347 - ``` 2348 - 2349 - Bobbin loves being in a container. When using 2350 - `bobbin/containerfiles/bobbin.Containerfile`, it runs `cargo 2351 - build --release --bin bobbin --package bobbin` within a 2352 - little Debian runtime, exposing port 8090. 2353 - 2354 - ## Configuration 2355 - 2356 - The best way to configure Bobbin is via a toml config file. 2357 - There's an `example.toml` in [Bobbin's subdir](https://tangled.org/did:plc:j5hmlfdrwkvtxm7cjmu7j2is/blob/master/bobbin/example.toml). 2358 - Every value is overridable by a `BOBBIN_*` env var. 2359 - The load order is env, then `--config <path>`, then 2360 - `/etc/bobbin/config.toml`, then built-in defaults. 2361 - 2362 - Load and check a config without starting the server: 2363 - 2364 - ```sh 2365 - bobbin --config config.toml validate 2366 - ``` 2367 - 2368 - Minimal config is the two upstream URLs. The hydrant URL 2369 - takes `ws://` or `wss://`. An `http://` or `https://` 2370 - URL is rewritten to the matching websocket scheme at 2371 - connection-time. 2372 - 2373 - ```toml 2374 - [server] 2375 - binds = ["127.0.0.1:8090"] 2376 - 2377 - # Loopback-only & can leave empty to disable debug introspection. 2378 - debug_bind = "127.0.0.1:8091" 2379 - 2380 - [hydrant] 2381 - url = "https://hydrant.example.com" 2382 - 2383 - [slingshot] 2384 - url = "https://slingshot.example.com" 2385 - ``` 2386 - 2387 - > 🦪 Lewis 2388 - > 2389 - > At time of writing, we (Tangled) don't host public 2390 - > instances of Hydrant or Slingshot. You will have to 2391 - > find public instances or spin these up yourself! :P 2392 - 2393 - Take a gander in the project's example.toml for an 2394 - exhaustive list of things to configure. 2395 - 2396 - You will discover fun things such as a configurable adaptive 2397 - loop that watches the cgroup memory limit & throttles heavy 2398 - requests under pressure. It only works if it detects a 2399 - cgroup limit is present. The config for that is in the 2400 - `[backpressure]` block of the config template. 2401 - 2402 - ## Running Bobbin 2403 - 2404 - Start the server using a config toml: 2405 - 2406 - ```bash 2407 - bobbin --config config.toml 2408 - ``` 2409 - Bobbin wakes up in a cold sweat and immediately gets to 2410 - work: 2411 - 1. It binds its listeners, connects to the Hydrant stream 2412 - in the background. 2413 - 2. It serves requests from the first 2414 - moment it's alive, even before the Hydrant stream connects 2415 - or finishes catching up. Having a cold Hydrant itself 2416 - costs only latency and approximate counts. 2417 - 2418 - ## The API 2419 - 2420 - **Single lookups** take a record's AT-URI. 2421 - 2422 - - `getRepo` takes the repo URI: 2423 - 2424 - ```sh 2425 - curl "$BOBBIN/xrpc/sh.tangled.repo.getRepo?repo=at://did:plc:boltless/sh.tangled.repo/squid" 2426 - ``` 2427 - ```json 2428 - { 2429 - "uri": "at://did:plc:boltless/sh.tangled.repo/squid", 2430 - "cid": "bafyrei...", 2431 - "value": { "$type": "sh.tangled.repo", "knot": "knot1.tangled.sh", "description": "...", "createdAt": "..." } 2432 - } 2433 - ``` 2434 - 2435 - - `getProfile` takes the full profile record URI, so a bare 2436 - handle or DID will not resolve: 2437 - 2438 - ```sh 2439 - curl "$BOBBIN/xrpc/sh.tangled.actor.getProfile?actor=at://did:plc:boltless/sh.tangled.actor.profile/self" 2440 - ``` 2441 - 2442 - - If Slingshot cannot serve the record, the response is `502`: 2443 - 2444 - ```json 2445 - { "error": "UpstreamFailed", "message": "upstream unavailable: ..." } 2446 - ``` 2447 - 2448 - **Aggregation** endpoints come in `list*` and `count*` pairs, 2449 - each with a `*By` sibling, and require a `subject` query param. 2450 - 2451 - - `listRepos` and `countRepos` key on the owner DID: 2452 - 2453 - ```sh 2454 - curl "$BOBBIN/xrpc/sh.tangled.repo.countRepos?subject=did:plc:boltless" 2455 - ``` 2456 - ```json 2457 - { "count": 7, "distinctAuthors": 1 } 2458 - ``` 2459 - 2460 - ```sh 2461 - curl "$BOBBIN/xrpc/sh.tangled.repo.listRepos?subject=did:plc:boltless&limit=3" 2462 - ``` 2463 - ```json 2464 - { "items": [ { "uri": "at://did:plc:boltless/sh.tangled.repo/squid", "cid": "bafyrei...", "value": { } } ], "cursor": null } 2465 - ``` 2466 - 2467 - - Bobbin validates the subject per collection. Here a repo URI 2468 - is passed where a bare DID is required, so the call returns a 2469 - `400`: 2470 - 2471 - ```sh 2472 - curl "$BOBBIN/xrpc/sh.tangled.graph.listFollows?subject=at://did:plc:boltless/sh.tangled.repo/squid" 2473 - ``` 2474 - ```json 2475 - { "error": "InvalidRequest", "message": "invalid request: subject must be a bare did, got at-uri with collection sh.tangled.repo" } 2476 - ``` 2477 - 2478 - **Search** is a single endpoint over an in-mem full-text 2479 - index: 2480 - 2481 - ```sh 2482 - curl "$BOBBIN/xrpc/sh.tangled.search.query?q=tangled&limit=2" 2483 - ``` 2484 - ```json 2485 - { "hits": [ { "uri": "at://...", "cid": "...", "nsid": "sh.tangled.repo", "score": 27.1, "value": { } } ], "cursor": null } 2486 - ``` 2487 - 2488 - **Git data** such as blob, tree, diff, log, and archive proxies 2489 - straight to the repo's knot, streamed back without caching. 2490 - 2491 - ## Coverage and warm-up 2492 - 2493 - - While the edge index is catching up from Hydrant, 2494 - the aggregation count is a lower bound & may still climb. 2495 - - One endpoint reports how far along the backfill it is: 2496 - 2497 - ```sh 2498 - curl "$BOBBIN/xrpc/sh.tangled.bobbin.getCoverage" 2499 - ``` 2500 - 2501 - While warming up: 2502 - 2503 - ```json 2504 - { "ready": false, "eventsProcessed": 45588, "lastCursor": 51658 } 2505 - ``` 2506 - 2507 - Once caught up, Bobbin flips to ready: 2508 - 2509 - ```json 2510 - { "ready": true, "eventsProcessed": 106085, "lastCursor": 116527 } 2511 - ``` 2512 - 2513 - If starting up Hydrant for the first time, Hydrant itself 2514 - will take a decent while (a couple of hours) to backfill 2515 - from PDSes. Hydrant stores its backfill on disk. Bobbin 2516 - restart reaches `ready` in minutes by replaying event from 2517 - an already-populated Hydrant. If your Hydrant is new, expect 2518 - Bobbin to backfill in that same couple of hours that Hydrant 2519 - takes. 2520 - 2521 - ## Loose ends and not-gonna-impl 2522 - 2523 - - **No coverage signal for per-knot rosters yet.** 2524 - Coverage tracks the hydrant stream only. A v1.15 knot 2525 - that is unreachable serves a stale or empty member set 2526 - with nothing to flag it. 2527 - - **Knot eventstream fan-out isn't pooled.** 2528 - Bobbin opens one websocket per v1.15 2529 - knot on top of the hydrant subscription. A network with 2530 - thousands of knots wants pooling or a shared subscription. 2531 - - **No sequential issue or PR numbers.** bobbin returns rkeys, 2532 - not `#42` style ids like the web appview. A client 2533 - deriving a display number does it from creation order. But 2534 - why bother? rkeys are the IDs. 2535 - 2536 - # Hacking on Tangled 2537 - 2538 - We highly recommend [installing 2539 - Nix](https://nixos.org/download/) (the package manager) 2540 - before working on the codebase. The Nix flake provides a lot 2541 - of helpers to get started and most importantly, builds and 2542 - dev shells are entirely deterministic. 2543 - 2544 - To set up your dev environment: 2545 - 2546 - ```bash 2547 - nix develop 2548 - ``` 2549 - 2550 - Non-Nix users can look at the `devShell` attribute in the 2551 - `flake.nix` file to determine necessary dependencies. 2552 - 2553 - ## Running the appview 2554 - 2555 - The appview requires Redis and OAuth JWKs. Start these 2556 - first, before launching the appview itself. 2557 - 2558 - ```bash 2559 - # OAuth JWKs should already be set up by the Nix devshell: 2560 - echo $TANGLED_OAUTH_CLIENT_SECRET 2561 - z42ty4RT1ovnTopY8B8ekz9NuziF2CuMkZ7rbRFpAR9jBqMc 2562 - 2563 - echo $TANGLED_OAUTH_CLIENT_KID 2564 - 1761667908 2565 - 2566 - # if not, you can set it up yourself: 2567 - goat key generate -t P-256 2568 - Key Type: P-256 / secp256r1 / ES256 private key 2569 - Secret Key (Multibase Syntax): save this securely (eg, add to password manager) 2570 - z42tuPDKRfM2mz2Kv953ARen2jmrPA8S9LX9tRq4RVcUMwwL 2571 - Public Key (DID Key Syntax): share or publish this (eg, in DID document) 2572 - did:key:zDnaeUBxtG6Xuv3ATJE4GaWeyXM3jyamJsZw3bSPpxx4bNXDR 2573 - 2574 - # the secret key from above 2575 - export TANGLED_OAUTH_CLIENT_SECRET="z42tuP..." 2576 - 2577 - # Run Redis in a new shell to store OAuth sessions 2578 - redis-server 2579 - ``` 2580 - 2581 - The Nix flake exposes a few `app` attributes (run `nix 2582 - flake show` to see a full list of what the flake provides), 2583 - one of the apps runs the appview with the `air` 2584 - live-reloader: 2585 - 2586 - ```bash 2587 - TANGLED_DEV=true nix run .#watch-appview 2588 - 2589 - # TANGLED_DB_PATH might be of interest to point to 2590 - # different sqlite DBs 2591 - 2592 - # in a separate shell, you can live-reload tailwind 2593 - nix run .#watch-tailwind 2594 - ``` 2595 - 2596 - ## Running knots and spindles 2597 - 2598 - An end-to-end knot setup requires setting up a machine with 2599 - `sshd`, `AuthorizedKeysCommand`, and a Git user, which is 2600 - quite cumbersome. So the Nix flake provides a 2601 - `nixosConfiguration` to do so. 2602 - 2603 - <details> 2604 - <summary><strong>macOS users will have to set up a Nix Builder first</strong></summary> 2605 - 2606 - In order to build Tangled's dev VM on macOS, you will 2607 - first need to set up a Linux Nix builder. The recommended 2608 - way to do so is to run a [`darwin.linux-builder` 2609 - VM](https://nixos.org/manual/nixpkgs/unstable/#sec-darwin-builder) 2610 - and to register it in `nix.conf` as a builder for Linux 2611 - with the same architecture as your Mac (`linux-aarch64` if 2612 - you are using Apple Silicon). 2613 - 2614 - If you're on nix-darwin, you can simply add 2615 - 2616 - ``` 2617 - nix.linux-builder.enable = true; 2618 - ``` 2619 - 2620 - to your host's `configuration.nix`. 2621 - 2622 - Alternatively, you can use any other method to set up a 2623 - Linux machine with Nix installed that you can `sudo ssh` 2624 - into (in other words, root user on your Mac has to be able 2625 - to ssh into the Linux machine without entering a password) 2626 - and that has the same architecture as your Mac. See 2627 - [remote builder 2628 - instructions](https://nix.dev/manual/nix/2.28/advanced-topics/distributed-builds.html#requirements) 2629 - for how to register such a builder in `nix.conf`. 2630 - 2631 - > WARNING: If you'd like to use 2632 - > [`nixos-lima`](https://github.com/nixos-lima/nixos-lima) or 2633 - > [Orbstack](https://orbstack.dev/), note that setting them up so that `sudo 2634 - ssh` works can be tricky. It seems to be [possible with 2635 - > Orbstack](https://github.com/orgs/orbstack/discussions/1669). 2636 - 2637 - </details> 2638 - 2639 - To begin, grab your DID from http://localhost:3000/settings. 2640 - Then, set `TANGLED_VM_KNOT_OWNER` and 2641 - `TANGLED_VM_SPINDLE_OWNER` to your DID. You can now start a 2642 - lightweight NixOS VM like so: 2643 - 2644 - ```bash 2645 - nix run --impure .#vm 2646 - 2647 - # type `poweroff` at the shell to exit the VM 2648 - ``` 2649 - 2650 - This starts a knot on port 6444, a spindle on port 6555 2651 - with `ssh` exposed on port 2222. 2652 - 2653 - Once the services are running, head to 2654 - http://localhost:3000/settings/knots and hit "Verify". It should 2655 - verify the ownership of the services instantly if everything 2656 - went smoothly. 2657 - 2658 - You can push repositories to this VM with this ssh config 2659 - block on your main machine: 2660 - 2661 - ```bash 2662 - Host nixos-shell 2663 - Hostname localhost 2664 - Port 2222 2665 - User git 2666 - IdentityFile ~/.ssh/my_tangled_key 2667 - ``` 2668 - 2669 - Set up a remote called `local-dev` on a git repo: 2670 - 2671 - ```bash 2672 - git remote add local-dev git@nixos-shell:user/repo 2673 - git push local-dev main 2674 - ``` 2675 - 2676 - The above VM should already be running a spindle on 2677 - `localhost:6555`. Head to http://localhost:3000/settings/spindles and 2678 - hit "Verify". You can then configure each repository to use 2679 - this spindle and run CI jobs. 2680 - 2681 - Of interest when debugging spindles: 2682 - 2683 - ``` 2684 - # Service logs from journald: 2685 - journalctl -xeu spindle 2686 - 2687 - # CI job logs from disk: 2688 - ls /var/log/spindle 2689 - 2690 - # Debugging spindle database: 2691 - sqlite3 /var/lib/spindle/spindle.db 2692 - 2693 - # litecli has a nicer REPL interface: 2694 - litecli /var/lib/spindle/spindle.db 2695 - ``` 2696 - 2697 - If for any reason you wish to disable either one of the 2698 - services in the VM, modify [nix/vm.nix](/nix/vm.nix) and set 2699 - `services.tangled.spindle.enable` (or 2700 - `services.tangled.knot.enable`) to `false`. 2701 - 2702 - # Contribution guide 2703 - 2704 - ## Commit guidelines 2705 - 2706 - We follow a commit style similar to the Go project. Please keep commits: 2707 - 2708 - - **atomic**: each commit should represent one logical change 2709 - - **descriptive**: the commit message should clearly describe what the 2710 - change does and why it's needed 2711 - 2712 - ### Message format 2713 - 2714 - ``` 2715 - <service/top-level directory>/<affected package/directory>: <short summary of change> 2716 - 2717 - Optional longer description can go here, if necessary. Explain what the 2718 - change does and why, especially if not obvious. Reference relevant 2719 - issues or PRs when applicable. These can be links for now since we don't 2720 - auto-link issues/PRs yet. 2721 - ``` 2722 - 2723 - Here are some examples: 2724 - 2725 - ``` 2726 - appview/state: fix token expiry check in middleware 2727 - 2728 - The previous check did not account for clock drift, leading to premature 2729 - token invalidation. 2730 - ``` 2731 - 2732 - ``` 2733 - knotserver/git/service: improve error checking in upload-pack 2734 - ``` 2735 - 2736 - ### General notes 2737 - 2738 - - PRs get merged "as-is" (fast-forward)—like applying a patch-series 2739 - using `git am`. At present, there is no squashing—so please author 2740 - your commits as they would appear on `master`, following the above 2741 - guidelines. 2742 - - If there is a lot of nesting, for example "appview: 2743 - pages/templates/repo/fragments: ...", these can be truncated down to 2744 - just "appview: repo/fragments: ...". If the change affects a lot of 2745 - subdirectories, you may abbreviate to just the top-level names, e.g. 2746 - "appview: ..." or "knotserver: ...". 2747 - - Keep commits lowercased with no trailing period. 2748 - - Use the imperative mood in the summary line (e.g., "fix bug" not 2749 - "fixed bug" or "fixes bug"). 2750 - - Try to keep the summary line under 72 characters, but we aren't too 2751 - fussed about this. 2752 - - Follow the same formatting for PR titles if filled manually. 2753 - - Don't include unrelated changes in the same commit. 2754 - - Avoid noisy commit messages like "wip" or "final fix"—rewrite history 2755 - before submitting if necessary. 2756 - 2757 - ## Code formatting 2758 - 2759 - We use a variety of tools to format our code, and multiplex them with 2760 - [`treefmt`](https://treefmt.com). All you need to do to format your changes 2761 - is run `nix run .#fmt` (or just `treefmt` if you're in the devshell). 2762 - 2763 - ## Proposals for bigger changes 2764 - 2765 - Small fixes like typos, minor bugs, or trivial refactors can be 2766 - submitted directly as PRs. 2767 - 2768 - For larger changes—especially those introducing new features, significant 2769 - refactoring, or altering system behavior—please open a proposal first. This 2770 - helps us evaluate the scope, design, and potential impact before implementation. 2771 - 2772 - Create a new issue titled: 2773 - 2774 - ``` 2775 - proposal: <affected scope>: <summary of change> 2776 - ``` 2777 - 2778 - In the description, explain: 2779 - 2780 - - What the change is 2781 - - Why it's needed 2782 - - How you plan to implement it (roughly) 2783 - - Any open questions or tradeoffs 2784 - 2785 - We'll use the issue thread to discuss and refine the idea before moving 2786 - forward. 2787 - 2788 - ## Developer Certificate of Origin (DCO) 2789 - 2790 - We require all contributors to certify that they have the right to 2791 - submit the code they're contributing. To do this, we follow the 2792 - [Developer Certificate of Origin 2793 - (DCO)](https://developercertificate.org/). 2794 - 2795 - By signing your commits, you're stating that the contribution is your 2796 - own work, or that you have the right to submit it under the project's 2797 - license. This helps us keep things clean and legally sound. 2798 - 2799 - To sign your commit, just add the `-s` flag when committing: 2800 - 2801 - ```sh 2802 - git commit -s -m "your commit message" 2803 - ``` 2804 - 2805 - This appends a line like: 2806 - 2807 - ``` 2808 - Signed-off-by: Your Name <your.email@example.com> 2809 - ``` 2810 - 2811 - We won't merge commits if they aren't signed off. If you forget, you can 2812 - amend the last commit like this: 2813 - 2814 - ```sh 2815 - git commit --amend -s 2816 - ``` 2817 - 2818 - If you're submitting a PR with multiple commits, make sure each one is 2819 - signed. 2820 - 2821 - For [jj](https://jj-vcs.github.io/jj/latest/) users, you can run the following command 2822 - to make it sign off commits in the tangled repo: 2823 - 2824 - ```shell 2825 - # Safety check, should say "No matching config key..." 2826 - jj config list templates.commit_trailers 2827 - # The command below may need to be adjusted if the command above returned something. 2828 - jj config set --repo templates.commit_trailers "format_signed_off_by_trailer(self)" 2829 - ``` 2830 - 2831 - Refer to the [jujutsu 2832 - documentation](https://jj-vcs.github.io/jj/latest/config/#commit-trailers) 2833 - for more information. 2834 - 2835 - # Troubleshooting guide 2836 - 2837 - ## Login issues 2838 - 2839 - Owing to the distributed nature of OAuth on AT Protocol, you 2840 - may run into issues with logging in. If you run a 2841 - self-hosted PDS: 2842 - 2843 - - You may need to ensure that your PDS is timesynced using 2844 - NTP: 2845 - - Enable the `ntpd` service 2846 - - Run `ntpd -qg` to synchronize your clock 2847 - - You may need to increase the default request timeout: 2848 - `NODE_OPTIONS="--network-family-autoselection-attempt-timeout=500"` 2849 - 2850 - ## Empty punchcard 2851 - 2852 - For Tangled to register commits that you make across the 2853 - network, you need to setup one of following: 2854 - 2855 - - The committer email should be a verified email associated 2856 - to your account. You can add and verify emails on the 2857 - settings page. 2858 - - Or, the committer email should be set to your account's 2859 - DID: `git config user.email "did:plc:foobar"`. You can find 2860 - your account's DID on the settings page 2861 - 2862 - ## Commit is not marked as verified 2863 - 2864 - Tangled only supports SSH commit signatures. Ensure the SSH public key you use 2865 - for signing is uploaded to Tangled. 2866 - 2867 - To sign commits using an SSH key with git: 2868 - 2869 - ``` 2870 - git config --global gpg.format ssh 2871 - git config --global user.signingkey ~/.ssh/tangled-key 2872 - ``` 2873 - 2874 - To sign commits using an SSH key with jj, add this to your 2875 - config: 2876 - 2877 - ``` 2878 - [signing] 2879 - behavior = "own" 2880 - backend = "ssh" 2881 - key = "~/.ssh/tangled-key" 2882 - ``` 2883 - 2884 - ## Self-hosted knot issues 2885 - 2886 - If you need help troubleshooting a self-hosted knot, check 2887 - out the [knot troubleshooting 2888 - guide](/knot-self-hosting-guide.html#troubleshooting).
+120
docs/astro.config.mjs
··· 1 + // @ts-check 2 + import { defineConfig } from "astro/config"; 3 + import starlight from "@astrojs/starlight"; 4 + 5 + export default defineConfig({ 6 + site: "https://docs.tangled.org", 7 + integrations: [ 8 + starlight({ 9 + title: "Tangled Docs", 10 + titleDelimiter: "·", 11 + description: 12 + "Documentation for Tangled — decentralized code collaboration built on the AT Protocol.", 13 + favicon: "/favicon.svg", 14 + head: [ 15 + { 16 + tag: "link", 17 + attrs: { rel: "apple-touch-icon", href: "/apple-touch-icon.png" }, 18 + }, 19 + ], 20 + logo: { 21 + light: "./src/assets/logotype-light.svg", 22 + dark: "./src/assets/logotype-dark.svg", 23 + replacesTitle: true, 24 + }, 25 + social: [ 26 + { 27 + icon: "seti:git", 28 + label: "Source", 29 + href: "https://tangled.org/@tangled.org/core", 30 + }, 31 + ], 32 + editLink: { 33 + baseUrl: "https://tangled.org/@tangled.org/core/blob/master/docs/", 34 + }, 35 + customCss: [ 36 + "./src/styles/tangled.css", 37 + "./src/styles/custom.css", 38 + "./src/styles/sidebar-icons.css", 39 + ], 40 + components: { 41 + SocialIcons: "./src/components/HeaderLinks.astro", 42 + }, 43 + expressiveCode: { 44 + // same palettes as the appview's chroma stylesheet 45 + themes: ["catppuccin-macchiato", "catppuccin-latte"], 46 + styleOverrides: { 47 + borderRadius: "0.25rem", 48 + borderColor: "var(--sl-color-gray-5)", 49 + }, 50 + }, 51 + sidebar: [ 52 + { 53 + label: "Getting started", 54 + items: [ 55 + { slug: "quick-start", attrs: { "data-icon": "rocket" } }, 56 + { slug: "why-atproto", attrs: { "data-icon": "at-sign" } }, 57 + { slug: "sites", attrs: { "data-icon": "globe" } }, 58 + { slug: "troubleshooting", attrs: { "data-icon": "life-buoy" } }, 59 + ], 60 + }, 61 + { 62 + label: "Knots", 63 + items: [ 64 + { 65 + label: "What are knots?", 66 + slug: "knots", 67 + attrs: { "data-icon": "server" }, 68 + }, 69 + { 70 + label: "Self-hosting a knot", 71 + slug: "knots/self-hosting", 72 + attrs: { "data-icon": "hard-drive" }, 73 + }, 74 + ], 75 + }, 76 + { 77 + label: "Spindles", 78 + items: [ 79 + { 80 + label: "What are spindles?", 81 + slug: "spindles", 82 + attrs: { "data-icon": "workflow" }, 83 + }, 84 + { slug: "spindles/workflows", attrs: { "data-icon": "play" } }, 85 + { 86 + slug: "spindles/self-hosting", 87 + attrs: { "data-icon": "hard-drive" }, 88 + }, 89 + { slug: "spindles/secrets", attrs: { "data-icon": "key-round" } }, 90 + { 91 + slug: "spindles/architecture", 92 + attrs: { "data-icon": "network" }, 93 + }, 94 + ], 95 + }, 96 + { 97 + label: "Reference", 98 + items: [ 99 + { slug: "reference/webhooks", attrs: { "data-icon": "webhook" } }, 100 + { slug: "reference/bobbin", attrs: { "data-icon": "cable" } }, 101 + { 102 + slug: "reference/migrations", 103 + attrs: { "data-icon": "arrow-up-circle" }, 104 + }, 105 + ], 106 + }, 107 + { 108 + label: "Contributing", 109 + items: [ 110 + { slug: "contributing/hacking", attrs: { "data-icon": "hammer" } }, 111 + { 112 + slug: "contributing/guide", 113 + attrs: { "data-icon": "git-pull-request" }, 114 + }, 115 + ], 116 + }, 117 + ], 118 + }), 119 + ], 120 + });
-93
docs/highlight.theme
··· 1 - { 2 - "text-color": null, 3 - "background-color": null, 4 - "line-number-color": null, 5 - "line-number-background-color": null, 6 - "text-styles": { 7 - "Annotation": { 8 - "text-color": null, 9 - "background-color": null, 10 - "bold": false, 11 - "italic": true, 12 - "underline": false 13 - }, 14 - "ControlFlow": { 15 - "text-color": null, 16 - "background-color": null, 17 - "bold": true, 18 - "italic": false, 19 - "underline": false 20 - }, 21 - "Error": { 22 - "text-color": null, 23 - "background-color": null, 24 - "bold": true, 25 - "italic": false, 26 - "underline": false 27 - }, 28 - "Alert": { 29 - "text-color": null, 30 - "background-color": null, 31 - "bold": true, 32 - "italic": false, 33 - "underline": false 34 - }, 35 - "Preprocessor": { 36 - "text-color": null, 37 - "background-color": null, 38 - "bold": true, 39 - "italic": false, 40 - "underline": false 41 - }, 42 - "Information": { 43 - "text-color": null, 44 - "background-color": null, 45 - "bold": false, 46 - "italic": true, 47 - "underline": false 48 - }, 49 - "Warning": { 50 - "text-color": null, 51 - "background-color": null, 52 - "bold": false, 53 - "italic": true, 54 - "underline": false 55 - }, 56 - "Documentation": { 57 - "text-color": null, 58 - "background-color": null, 59 - "bold": false, 60 - "italic": true, 61 - "underline": false 62 - }, 63 - "DataType": { 64 - "text-color": "#8f4e8b", 65 - "background-color": null, 66 - "bold": false, 67 - "italic": false, 68 - "underline": false 69 - }, 70 - "Comment": { 71 - "text-color": null, 72 - "background-color": null, 73 - "bold": false, 74 - "italic": true, 75 - "underline": false 76 - }, 77 - "CommentVar": { 78 - "text-color": null, 79 - "background-color": null, 80 - "bold": false, 81 - "italic": true, 82 - "underline": false 83 - }, 84 - "Keyword": { 85 - "text-color": null, 86 - "background-color": null, 87 - "bold": true, 88 - "italic": false, 89 - "underline": false 90 - } 91 - } 92 - } 93 -
-6
docs/logo.html
··· 1 - <div class="flex items-center gap-2 w-fit mx-auto"> 2 - <span class="w-16 h-16 [&>svg]:w-full [&>svg]:h-full text-black dark:text-white"> 3 - ${ dolly.svg() } 4 - </span> 5 - <span class="font-bold text-4xl not-italic text-black dark:text-white">tangled</span> 6 - </div>
-3
docs/mode.html
··· 1 - <a class="px-4 py-2 mt-8 block text-center w-full rounded-sm shadow-sm border border-gray-200 dark:border-gray-700 no-underline hover:no-underline" href="$if(single-page)$/$else$/single-page.html$endif$"> 2 - $if(single-page)$View as multi-page$else$View as single-page$endif$ 3 - </a>
+7820
docs/package-lock.json
··· 1 + { 2 + "name": "tangled-docs", 3 + "version": "0.0.1", 4 + "lockfileVersion": 3, 5 + "requires": true, 6 + "packages": { 7 + "": { 8 + "name": "tangled-docs", 9 + "version": "0.0.1", 10 + "dependencies": { 11 + "@astrojs/starlight": "^0.36.0", 12 + "@fontsource-variable/inter": "^5.2.5", 13 + "@fontsource/ibm-plex-mono": "^5.2.5", 14 + "astro": "^5.14.0", 15 + "lucide-astro": "^0.545.0", 16 + "sharp": "^0.34.0" 17 + }, 18 + "devDependencies": { 19 + "@tailwindcss/typography": "^0.5.20", 20 + "tailwindcss": "^3.4.19" 21 + } 22 + }, 23 + "node_modules/@alloc/quick-lru": { 24 + "version": "5.2.0", 25 + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", 26 + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", 27 + "dev": true, 28 + "license": "MIT", 29 + "engines": { 30 + "node": ">=10" 31 + }, 32 + "funding": { 33 + "url": "https://github.com/sponsors/sindresorhus" 34 + } 35 + }, 36 + "node_modules/@astrojs/compiler": { 37 + "version": "2.13.1", 38 + "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.13.1.tgz", 39 + "integrity": "sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==", 40 + "license": "MIT" 41 + }, 42 + "node_modules/@astrojs/internal-helpers": { 43 + "version": "0.7.6", 44 + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.7.6.tgz", 45 + "integrity": "sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q==", 46 + "license": "MIT" 47 + }, 48 + "node_modules/@astrojs/markdown-remark": { 49 + "version": "6.3.11", 50 + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.3.11.tgz", 51 + "integrity": "sha512-hcaxX/5aC6lQgHeGh1i+aauvSwIT6cfyFjKWvExYSxUhZZBBdvCliOtu06gbQyhbe0pGJNoNmqNlQZ5zYUuIyQ==", 52 + "license": "MIT", 53 + "dependencies": { 54 + "@astrojs/internal-helpers": "0.7.6", 55 + "@astrojs/prism": "3.3.0", 56 + "github-slugger": "^2.0.0", 57 + "hast-util-from-html": "^2.0.3", 58 + "hast-util-to-text": "^4.0.2", 59 + "import-meta-resolve": "^4.2.0", 60 + "js-yaml": "^4.1.1", 61 + "mdast-util-definitions": "^6.0.0", 62 + "rehype-raw": "^7.0.0", 63 + "rehype-stringify": "^10.0.1", 64 + "remark-gfm": "^4.0.1", 65 + "remark-parse": "^11.0.0", 66 + "remark-rehype": "^11.1.2", 67 + "remark-smartypants": "^3.0.2", 68 + "shiki": "^3.21.0", 69 + "smol-toml": "^1.6.0", 70 + "unified": "^11.0.5", 71 + "unist-util-remove-position": "^5.0.0", 72 + "unist-util-visit": "^5.0.0", 73 + "unist-util-visit-parents": "^6.0.2", 74 + "vfile": "^6.0.3" 75 + } 76 + }, 77 + "node_modules/@astrojs/mdx": { 78 + "version": "4.3.14", 79 + "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-4.3.14.tgz", 80 + "integrity": "sha512-FBrqJQORVm+rkRa2TS5CjU9PBA6hkhrwLVBSS9A77gN2+iehvjq1w6yya/d0YKC7osiVorKkr3Qd9wNbl0ZkGA==", 81 + "license": "MIT", 82 + "dependencies": { 83 + "@astrojs/markdown-remark": "6.3.11", 84 + "@mdx-js/mdx": "^3.1.1", 85 + "acorn": "^8.15.0", 86 + "es-module-lexer": "^1.7.0", 87 + "estree-util-visit": "^2.0.0", 88 + "hast-util-to-html": "^9.0.5", 89 + "piccolore": "^0.1.3", 90 + "rehype-raw": "^7.0.0", 91 + "remark-gfm": "^4.0.1", 92 + "remark-smartypants": "^3.0.2", 93 + "source-map": "^0.7.6", 94 + "unist-util-visit": "^5.0.0", 95 + "vfile": "^6.0.3" 96 + }, 97 + "engines": { 98 + "node": "18.20.8 || ^20.3.0 || >=22.0.0" 99 + }, 100 + "peerDependencies": { 101 + "astro": "^5.0.0" 102 + } 103 + }, 104 + "node_modules/@astrojs/prism": { 105 + "version": "3.3.0", 106 + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.3.0.tgz", 107 + "integrity": "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==", 108 + "license": "MIT", 109 + "dependencies": { 110 + "prismjs": "^1.30.0" 111 + }, 112 + "engines": { 113 + "node": "18.20.8 || ^20.3.0 || >=22.0.0" 114 + } 115 + }, 116 + "node_modules/@astrojs/sitemap": { 117 + "version": "3.7.3", 118 + "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.3.tgz", 119 + "integrity": "sha512-f8euLVsyeAmAkSm/1M2Kb8sL8byQmfgbvBNaHFItCheTj/IpiJYSEWVcqDHZ/yEHxiS7+w87mQkzwZaPHmk5GA==", 120 + "license": "MIT", 121 + "dependencies": { 122 + "sitemap": "^9.0.0", 123 + "stream-replace-string": "^2.0.0", 124 + "zod": "^4.3.6" 125 + } 126 + }, 127 + "node_modules/@astrojs/starlight": { 128 + "version": "0.36.3", 129 + "resolved": "https://registry.npmjs.org/@astrojs/starlight/-/starlight-0.36.3.tgz", 130 + "integrity": "sha512-5cm4QVQHUP6ZE52O43TtUpsTvLKdZa9XEs4l3suzuY7Ymsbz4ojtoL9NhistbMqM+/qk6fm6SmxbOL6hQ/LfNA==", 131 + "license": "MIT", 132 + "dependencies": { 133 + "@astrojs/markdown-remark": "^6.3.1", 134 + "@astrojs/mdx": "^4.2.3", 135 + "@astrojs/sitemap": "^3.3.0", 136 + "@pagefind/default-ui": "^1.3.0", 137 + "@types/hast": "^3.0.4", 138 + "@types/js-yaml": "^4.0.9", 139 + "@types/mdast": "^4.0.4", 140 + "astro-expressive-code": "^0.41.1", 141 + "bcp-47": "^2.1.0", 142 + "hast-util-from-html": "^2.0.1", 143 + "hast-util-select": "^6.0.2", 144 + "hast-util-to-string": "^3.0.0", 145 + "hastscript": "^9.0.0", 146 + "i18next": "^23.11.5", 147 + "js-yaml": "^4.1.0", 148 + "klona": "^2.0.6", 149 + "mdast-util-directive": "^3.0.0", 150 + "mdast-util-to-markdown": "^2.1.0", 151 + "mdast-util-to-string": "^4.0.0", 152 + "pagefind": "^1.3.0", 153 + "rehype": "^13.0.1", 154 + "rehype-format": "^5.0.0", 155 + "remark-directive": "^3.0.0", 156 + "ultrahtml": "^1.6.0", 157 + "unified": "^11.0.5", 158 + "unist-util-visit": "^5.0.0", 159 + "vfile": "^6.0.2" 160 + }, 161 + "peerDependencies": { 162 + "astro": "^5.5.0" 163 + } 164 + }, 165 + "node_modules/@astrojs/telemetry": { 166 + "version": "3.3.0", 167 + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.0.tgz", 168 + "integrity": "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==", 169 + "license": "MIT", 170 + "dependencies": { 171 + "ci-info": "^4.2.0", 172 + "debug": "^4.4.0", 173 + "dlv": "^1.1.3", 174 + "dset": "^3.1.4", 175 + "is-docker": "^3.0.0", 176 + "is-wsl": "^3.1.0", 177 + "which-pm-runs": "^1.1.0" 178 + }, 179 + "engines": { 180 + "node": "18.20.8 || ^20.3.0 || >=22.0.0" 181 + } 182 + }, 183 + "node_modules/@babel/helper-string-parser": { 184 + "version": "7.29.7", 185 + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", 186 + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", 187 + "license": "MIT", 188 + "engines": { 189 + "node": ">=6.9.0" 190 + } 191 + }, 192 + "node_modules/@babel/helper-validator-identifier": { 193 + "version": "7.29.7", 194 + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", 195 + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", 196 + "license": "MIT", 197 + "engines": { 198 + "node": ">=6.9.0" 199 + } 200 + }, 201 + "node_modules/@babel/parser": { 202 + "version": "7.29.7", 203 + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", 204 + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", 205 + "license": "MIT", 206 + "dependencies": { 207 + "@babel/types": "^7.29.7" 208 + }, 209 + "bin": { 210 + "parser": "bin/babel-parser.js" 211 + }, 212 + "engines": { 213 + "node": ">=6.0.0" 214 + } 215 + }, 216 + "node_modules/@babel/runtime": { 217 + "version": "7.29.7", 218 + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", 219 + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", 220 + "license": "MIT", 221 + "engines": { 222 + "node": ">=6.9.0" 223 + } 224 + }, 225 + "node_modules/@babel/types": { 226 + "version": "7.29.7", 227 + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", 228 + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", 229 + "license": "MIT", 230 + "dependencies": { 231 + "@babel/helper-string-parser": "^7.29.7", 232 + "@babel/helper-validator-identifier": "^7.29.7" 233 + }, 234 + "engines": { 235 + "node": ">=6.9.0" 236 + } 237 + }, 238 + "node_modules/@capsizecss/unpack": { 239 + "version": "4.0.1", 240 + "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-4.0.1.tgz", 241 + "integrity": "sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==", 242 + "license": "MIT", 243 + "dependencies": { 244 + "fontkitten": "^1.0.3" 245 + }, 246 + "engines": { 247 + "node": ">=18" 248 + } 249 + }, 250 + "node_modules/@ctrl/tinycolor": { 251 + "version": "4.2.0", 252 + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz", 253 + "integrity": "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==", 254 + "license": "MIT", 255 + "engines": { 256 + "node": ">=14" 257 + } 258 + }, 259 + "node_modules/@emnapi/runtime": { 260 + "version": "1.11.2", 261 + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", 262 + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", 263 + "license": "MIT", 264 + "optional": true, 265 + "dependencies": { 266 + "tslib": "^2.4.0" 267 + } 268 + }, 269 + "node_modules/@esbuild/aix-ppc64": { 270 + "version": "0.27.7", 271 + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", 272 + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", 273 + "cpu": [ 274 + "ppc64" 275 + ], 276 + "license": "MIT", 277 + "optional": true, 278 + "os": [ 279 + "aix" 280 + ], 281 + "engines": { 282 + "node": ">=18" 283 + } 284 + }, 285 + "node_modules/@esbuild/android-arm": { 286 + "version": "0.27.7", 287 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", 288 + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", 289 + "cpu": [ 290 + "arm" 291 + ], 292 + "license": "MIT", 293 + "optional": true, 294 + "os": [ 295 + "android" 296 + ], 297 + "engines": { 298 + "node": ">=18" 299 + } 300 + }, 301 + "node_modules/@esbuild/android-arm64": { 302 + "version": "0.27.7", 303 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", 304 + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", 305 + "cpu": [ 306 + "arm64" 307 + ], 308 + "license": "MIT", 309 + "optional": true, 310 + "os": [ 311 + "android" 312 + ], 313 + "engines": { 314 + "node": ">=18" 315 + } 316 + }, 317 + "node_modules/@esbuild/android-x64": { 318 + "version": "0.27.7", 319 + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", 320 + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", 321 + "cpu": [ 322 + "x64" 323 + ], 324 + "license": "MIT", 325 + "optional": true, 326 + "os": [ 327 + "android" 328 + ], 329 + "engines": { 330 + "node": ">=18" 331 + } 332 + }, 333 + "node_modules/@esbuild/darwin-arm64": { 334 + "version": "0.27.7", 335 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", 336 + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", 337 + "cpu": [ 338 + "arm64" 339 + ], 340 + "license": "MIT", 341 + "optional": true, 342 + "os": [ 343 + "darwin" 344 + ], 345 + "engines": { 346 + "node": ">=18" 347 + } 348 + }, 349 + "node_modules/@esbuild/darwin-x64": { 350 + "version": "0.27.7", 351 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", 352 + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", 353 + "cpu": [ 354 + "x64" 355 + ], 356 + "license": "MIT", 357 + "optional": true, 358 + "os": [ 359 + "darwin" 360 + ], 361 + "engines": { 362 + "node": ">=18" 363 + } 364 + }, 365 + "node_modules/@esbuild/freebsd-arm64": { 366 + "version": "0.27.7", 367 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", 368 + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", 369 + "cpu": [ 370 + "arm64" 371 + ], 372 + "license": "MIT", 373 + "optional": true, 374 + "os": [ 375 + "freebsd" 376 + ], 377 + "engines": { 378 + "node": ">=18" 379 + } 380 + }, 381 + "node_modules/@esbuild/freebsd-x64": { 382 + "version": "0.27.7", 383 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", 384 + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", 385 + "cpu": [ 386 + "x64" 387 + ], 388 + "license": "MIT", 389 + "optional": true, 390 + "os": [ 391 + "freebsd" 392 + ], 393 + "engines": { 394 + "node": ">=18" 395 + } 396 + }, 397 + "node_modules/@esbuild/linux-arm": { 398 + "version": "0.27.7", 399 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", 400 + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", 401 + "cpu": [ 402 + "arm" 403 + ], 404 + "license": "MIT", 405 + "optional": true, 406 + "os": [ 407 + "linux" 408 + ], 409 + "engines": { 410 + "node": ">=18" 411 + } 412 + }, 413 + "node_modules/@esbuild/linux-arm64": { 414 + "version": "0.27.7", 415 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", 416 + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", 417 + "cpu": [ 418 + "arm64" 419 + ], 420 + "license": "MIT", 421 + "optional": true, 422 + "os": [ 423 + "linux" 424 + ], 425 + "engines": { 426 + "node": ">=18" 427 + } 428 + }, 429 + "node_modules/@esbuild/linux-ia32": { 430 + "version": "0.27.7", 431 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", 432 + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", 433 + "cpu": [ 434 + "ia32" 435 + ], 436 + "license": "MIT", 437 + "optional": true, 438 + "os": [ 439 + "linux" 440 + ], 441 + "engines": { 442 + "node": ">=18" 443 + } 444 + }, 445 + "node_modules/@esbuild/linux-loong64": { 446 + "version": "0.27.7", 447 + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", 448 + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", 449 + "cpu": [ 450 + "loong64" 451 + ], 452 + "license": "MIT", 453 + "optional": true, 454 + "os": [ 455 + "linux" 456 + ], 457 + "engines": { 458 + "node": ">=18" 459 + } 460 + }, 461 + "node_modules/@esbuild/linux-mips64el": { 462 + "version": "0.27.7", 463 + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", 464 + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", 465 + "cpu": [ 466 + "mips64el" 467 + ], 468 + "license": "MIT", 469 + "optional": true, 470 + "os": [ 471 + "linux" 472 + ], 473 + "engines": { 474 + "node": ">=18" 475 + } 476 + }, 477 + "node_modules/@esbuild/linux-ppc64": { 478 + "version": "0.27.7", 479 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", 480 + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", 481 + "cpu": [ 482 + "ppc64" 483 + ], 484 + "license": "MIT", 485 + "optional": true, 486 + "os": [ 487 + "linux" 488 + ], 489 + "engines": { 490 + "node": ">=18" 491 + } 492 + }, 493 + "node_modules/@esbuild/linux-riscv64": { 494 + "version": "0.27.7", 495 + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", 496 + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", 497 + "cpu": [ 498 + "riscv64" 499 + ], 500 + "license": "MIT", 501 + "optional": true, 502 + "os": [ 503 + "linux" 504 + ], 505 + "engines": { 506 + "node": ">=18" 507 + } 508 + }, 509 + "node_modules/@esbuild/linux-s390x": { 510 + "version": "0.27.7", 511 + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", 512 + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", 513 + "cpu": [ 514 + "s390x" 515 + ], 516 + "license": "MIT", 517 + "optional": true, 518 + "os": [ 519 + "linux" 520 + ], 521 + "engines": { 522 + "node": ">=18" 523 + } 524 + }, 525 + "node_modules/@esbuild/linux-x64": { 526 + "version": "0.27.7", 527 + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", 528 + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", 529 + "cpu": [ 530 + "x64" 531 + ], 532 + "license": "MIT", 533 + "optional": true, 534 + "os": [ 535 + "linux" 536 + ], 537 + "engines": { 538 + "node": ">=18" 539 + } 540 + }, 541 + "node_modules/@esbuild/netbsd-arm64": { 542 + "version": "0.27.7", 543 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", 544 + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", 545 + "cpu": [ 546 + "arm64" 547 + ], 548 + "license": "MIT", 549 + "optional": true, 550 + "os": [ 551 + "netbsd" 552 + ], 553 + "engines": { 554 + "node": ">=18" 555 + } 556 + }, 557 + "node_modules/@esbuild/netbsd-x64": { 558 + "version": "0.27.7", 559 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", 560 + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", 561 + "cpu": [ 562 + "x64" 563 + ], 564 + "license": "MIT", 565 + "optional": true, 566 + "os": [ 567 + "netbsd" 568 + ], 569 + "engines": { 570 + "node": ">=18" 571 + } 572 + }, 573 + "node_modules/@esbuild/openbsd-arm64": { 574 + "version": "0.27.7", 575 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", 576 + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", 577 + "cpu": [ 578 + "arm64" 579 + ], 580 + "license": "MIT", 581 + "optional": true, 582 + "os": [ 583 + "openbsd" 584 + ], 585 + "engines": { 586 + "node": ">=18" 587 + } 588 + }, 589 + "node_modules/@esbuild/openbsd-x64": { 590 + "version": "0.27.7", 591 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", 592 + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", 593 + "cpu": [ 594 + "x64" 595 + ], 596 + "license": "MIT", 597 + "optional": true, 598 + "os": [ 599 + "openbsd" 600 + ], 601 + "engines": { 602 + "node": ">=18" 603 + } 604 + }, 605 + "node_modules/@esbuild/openharmony-arm64": { 606 + "version": "0.27.7", 607 + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", 608 + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", 609 + "cpu": [ 610 + "arm64" 611 + ], 612 + "license": "MIT", 613 + "optional": true, 614 + "os": [ 615 + "openharmony" 616 + ], 617 + "engines": { 618 + "node": ">=18" 619 + } 620 + }, 621 + "node_modules/@esbuild/sunos-x64": { 622 + "version": "0.27.7", 623 + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", 624 + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", 625 + "cpu": [ 626 + "x64" 627 + ], 628 + "license": "MIT", 629 + "optional": true, 630 + "os": [ 631 + "sunos" 632 + ], 633 + "engines": { 634 + "node": ">=18" 635 + } 636 + }, 637 + "node_modules/@esbuild/win32-arm64": { 638 + "version": "0.27.7", 639 + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", 640 + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", 641 + "cpu": [ 642 + "arm64" 643 + ], 644 + "license": "MIT", 645 + "optional": true, 646 + "os": [ 647 + "win32" 648 + ], 649 + "engines": { 650 + "node": ">=18" 651 + } 652 + }, 653 + "node_modules/@esbuild/win32-ia32": { 654 + "version": "0.27.7", 655 + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", 656 + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", 657 + "cpu": [ 658 + "ia32" 659 + ], 660 + "license": "MIT", 661 + "optional": true, 662 + "os": [ 663 + "win32" 664 + ], 665 + "engines": { 666 + "node": ">=18" 667 + } 668 + }, 669 + "node_modules/@esbuild/win32-x64": { 670 + "version": "0.27.7", 671 + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", 672 + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", 673 + "cpu": [ 674 + "x64" 675 + ], 676 + "license": "MIT", 677 + "optional": true, 678 + "os": [ 679 + "win32" 680 + ], 681 + "engines": { 682 + "node": ">=18" 683 + } 684 + }, 685 + "node_modules/@expressive-code/core": { 686 + "version": "0.41.7", 687 + "resolved": "https://registry.npmjs.org/@expressive-code/core/-/core-0.41.7.tgz", 688 + "integrity": "sha512-ck92uZYZ9Wba2zxkiZLsZGi9N54pMSAVdrI9uW3Oo9AtLglD5RmrdTwbYPCT2S/jC36JGB2i+pnQtBm/Ib2+dg==", 689 + "license": "MIT", 690 + "dependencies": { 691 + "@ctrl/tinycolor": "^4.0.4", 692 + "hast-util-select": "^6.0.2", 693 + "hast-util-to-html": "^9.0.1", 694 + "hast-util-to-text": "^4.0.1", 695 + "hastscript": "^9.0.0", 696 + "postcss": "^8.4.38", 697 + "postcss-nested": "^6.0.1", 698 + "unist-util-visit": "^5.0.0", 699 + "unist-util-visit-parents": "^6.0.1" 700 + } 701 + }, 702 + "node_modules/@expressive-code/plugin-frames": { 703 + "version": "0.41.7", 704 + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-frames/-/plugin-frames-0.41.7.tgz", 705 + "integrity": "sha512-diKtxjQw/979cTglRFaMCY/sR6hWF0kSMg8jsKLXaZBSfGS0I/Hoe7Qds3vVEgeoW+GHHQzMcwvgx/MOIXhrTA==", 706 + "license": "MIT", 707 + "dependencies": { 708 + "@expressive-code/core": "^0.41.7" 709 + } 710 + }, 711 + "node_modules/@expressive-code/plugin-shiki": { 712 + "version": "0.41.7", 713 + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-shiki/-/plugin-shiki-0.41.7.tgz", 714 + "integrity": "sha512-DL605bLrUOgqTdZ0Ot5MlTaWzppRkzzqzeGEu7ODnHF39IkEBbFdsC7pbl3LbUQ1DFtnfx6rD54k/cdofbW6KQ==", 715 + "license": "MIT", 716 + "dependencies": { 717 + "@expressive-code/core": "^0.41.7", 718 + "shiki": "^3.2.2" 719 + } 720 + }, 721 + "node_modules/@expressive-code/plugin-text-markers": { 722 + "version": "0.41.7", 723 + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-text-markers/-/plugin-text-markers-0.41.7.tgz", 724 + "integrity": "sha512-Ewpwuc5t6eFdZmWlFyeuy3e1PTQC0jFvw2Q+2bpcWXbOZhPLsT7+h8lsSIJxb5mS7wZko7cKyQ2RLYDyK6Fpmw==", 725 + "license": "MIT", 726 + "dependencies": { 727 + "@expressive-code/core": "^0.41.7" 728 + } 729 + }, 730 + "node_modules/@fontsource-variable/inter": { 731 + "version": "5.2.8", 732 + "resolved": "https://registry.npmjs.org/@fontsource-variable/inter/-/inter-5.2.8.tgz", 733 + "integrity": "sha512-kOfP2D+ykbcX/P3IFnokOhVRNoTozo5/JxhAIVYLpea/UBmCQ/YWPBfWIDuBImXX/15KH+eKh4xpEUyS2sQQGQ==", 734 + "license": "OFL-1.1", 735 + "funding": { 736 + "url": "https://github.com/sponsors/ayuhito" 737 + } 738 + }, 739 + "node_modules/@fontsource/ibm-plex-mono": { 740 + "version": "5.2.7", 741 + "resolved": "https://registry.npmjs.org/@fontsource/ibm-plex-mono/-/ibm-plex-mono-5.2.7.tgz", 742 + "integrity": "sha512-MKAb8qV+CaiMQn2B0dIi1OV3565NYzp3WN5b4oT6LTkk+F0jR6j0ZN+5BKJiIhffDC3rtBULsYZE65+0018z9w==", 743 + "license": "OFL-1.1", 744 + "funding": { 745 + "url": "https://github.com/sponsors/ayuhito" 746 + } 747 + }, 748 + "node_modules/@img/colour": { 749 + "version": "1.1.0", 750 + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", 751 + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", 752 + "license": "MIT", 753 + "engines": { 754 + "node": ">=18" 755 + } 756 + }, 757 + "node_modules/@img/sharp-darwin-arm64": { 758 + "version": "0.34.5", 759 + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", 760 + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", 761 + "cpu": [ 762 + "arm64" 763 + ], 764 + "license": "Apache-2.0", 765 + "optional": true, 766 + "os": [ 767 + "darwin" 768 + ], 769 + "engines": { 770 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 771 + }, 772 + "funding": { 773 + "url": "https://opencollective.com/libvips" 774 + }, 775 + "optionalDependencies": { 776 + "@img/sharp-libvips-darwin-arm64": "1.2.4" 777 + } 778 + }, 779 + "node_modules/@img/sharp-darwin-x64": { 780 + "version": "0.34.5", 781 + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", 782 + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", 783 + "cpu": [ 784 + "x64" 785 + ], 786 + "license": "Apache-2.0", 787 + "optional": true, 788 + "os": [ 789 + "darwin" 790 + ], 791 + "engines": { 792 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 793 + }, 794 + "funding": { 795 + "url": "https://opencollective.com/libvips" 796 + }, 797 + "optionalDependencies": { 798 + "@img/sharp-libvips-darwin-x64": "1.2.4" 799 + } 800 + }, 801 + "node_modules/@img/sharp-libvips-darwin-arm64": { 802 + "version": "1.2.4", 803 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", 804 + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", 805 + "cpu": [ 806 + "arm64" 807 + ], 808 + "license": "LGPL-3.0-or-later", 809 + "optional": true, 810 + "os": [ 811 + "darwin" 812 + ], 813 + "funding": { 814 + "url": "https://opencollective.com/libvips" 815 + } 816 + }, 817 + "node_modules/@img/sharp-libvips-darwin-x64": { 818 + "version": "1.2.4", 819 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", 820 + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", 821 + "cpu": [ 822 + "x64" 823 + ], 824 + "license": "LGPL-3.0-or-later", 825 + "optional": true, 826 + "os": [ 827 + "darwin" 828 + ], 829 + "funding": { 830 + "url": "https://opencollective.com/libvips" 831 + } 832 + }, 833 + "node_modules/@img/sharp-libvips-linux-arm": { 834 + "version": "1.2.4", 835 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", 836 + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", 837 + "cpu": [ 838 + "arm" 839 + ], 840 + "libc": [ 841 + "glibc" 842 + ], 843 + "license": "LGPL-3.0-or-later", 844 + "optional": true, 845 + "os": [ 846 + "linux" 847 + ], 848 + "funding": { 849 + "url": "https://opencollective.com/libvips" 850 + } 851 + }, 852 + "node_modules/@img/sharp-libvips-linux-arm64": { 853 + "version": "1.2.4", 854 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", 855 + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", 856 + "cpu": [ 857 + "arm64" 858 + ], 859 + "libc": [ 860 + "glibc" 861 + ], 862 + "license": "LGPL-3.0-or-later", 863 + "optional": true, 864 + "os": [ 865 + "linux" 866 + ], 867 + "funding": { 868 + "url": "https://opencollective.com/libvips" 869 + } 870 + }, 871 + "node_modules/@img/sharp-libvips-linux-ppc64": { 872 + "version": "1.2.4", 873 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", 874 + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", 875 + "cpu": [ 876 + "ppc64" 877 + ], 878 + "libc": [ 879 + "glibc" 880 + ], 881 + "license": "LGPL-3.0-or-later", 882 + "optional": true, 883 + "os": [ 884 + "linux" 885 + ], 886 + "funding": { 887 + "url": "https://opencollective.com/libvips" 888 + } 889 + }, 890 + "node_modules/@img/sharp-libvips-linux-riscv64": { 891 + "version": "1.2.4", 892 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", 893 + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", 894 + "cpu": [ 895 + "riscv64" 896 + ], 897 + "libc": [ 898 + "glibc" 899 + ], 900 + "license": "LGPL-3.0-or-later", 901 + "optional": true, 902 + "os": [ 903 + "linux" 904 + ], 905 + "funding": { 906 + "url": "https://opencollective.com/libvips" 907 + } 908 + }, 909 + "node_modules/@img/sharp-libvips-linux-s390x": { 910 + "version": "1.2.4", 911 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", 912 + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", 913 + "cpu": [ 914 + "s390x" 915 + ], 916 + "libc": [ 917 + "glibc" 918 + ], 919 + "license": "LGPL-3.0-or-later", 920 + "optional": true, 921 + "os": [ 922 + "linux" 923 + ], 924 + "funding": { 925 + "url": "https://opencollective.com/libvips" 926 + } 927 + }, 928 + "node_modules/@img/sharp-libvips-linux-x64": { 929 + "version": "1.2.4", 930 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", 931 + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", 932 + "cpu": [ 933 + "x64" 934 + ], 935 + "libc": [ 936 + "glibc" 937 + ], 938 + "license": "LGPL-3.0-or-later", 939 + "optional": true, 940 + "os": [ 941 + "linux" 942 + ], 943 + "funding": { 944 + "url": "https://opencollective.com/libvips" 945 + } 946 + }, 947 + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { 948 + "version": "1.2.4", 949 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", 950 + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", 951 + "cpu": [ 952 + "arm64" 953 + ], 954 + "libc": [ 955 + "musl" 956 + ], 957 + "license": "LGPL-3.0-or-later", 958 + "optional": true, 959 + "os": [ 960 + "linux" 961 + ], 962 + "funding": { 963 + "url": "https://opencollective.com/libvips" 964 + } 965 + }, 966 + "node_modules/@img/sharp-libvips-linuxmusl-x64": { 967 + "version": "1.2.4", 968 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", 969 + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", 970 + "cpu": [ 971 + "x64" 972 + ], 973 + "libc": [ 974 + "musl" 975 + ], 976 + "license": "LGPL-3.0-or-later", 977 + "optional": true, 978 + "os": [ 979 + "linux" 980 + ], 981 + "funding": { 982 + "url": "https://opencollective.com/libvips" 983 + } 984 + }, 985 + "node_modules/@img/sharp-linux-arm": { 986 + "version": "0.34.5", 987 + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", 988 + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", 989 + "cpu": [ 990 + "arm" 991 + ], 992 + "libc": [ 993 + "glibc" 994 + ], 995 + "license": "Apache-2.0", 996 + "optional": true, 997 + "os": [ 998 + "linux" 999 + ], 1000 + "engines": { 1001 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 1002 + }, 1003 + "funding": { 1004 + "url": "https://opencollective.com/libvips" 1005 + }, 1006 + "optionalDependencies": { 1007 + "@img/sharp-libvips-linux-arm": "1.2.4" 1008 + } 1009 + }, 1010 + "node_modules/@img/sharp-linux-arm64": { 1011 + "version": "0.34.5", 1012 + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", 1013 + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", 1014 + "cpu": [ 1015 + "arm64" 1016 + ], 1017 + "libc": [ 1018 + "glibc" 1019 + ], 1020 + "license": "Apache-2.0", 1021 + "optional": true, 1022 + "os": [ 1023 + "linux" 1024 + ], 1025 + "engines": { 1026 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 1027 + }, 1028 + "funding": { 1029 + "url": "https://opencollective.com/libvips" 1030 + }, 1031 + "optionalDependencies": { 1032 + "@img/sharp-libvips-linux-arm64": "1.2.4" 1033 + } 1034 + }, 1035 + "node_modules/@img/sharp-linux-ppc64": { 1036 + "version": "0.34.5", 1037 + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", 1038 + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", 1039 + "cpu": [ 1040 + "ppc64" 1041 + ], 1042 + "libc": [ 1043 + "glibc" 1044 + ], 1045 + "license": "Apache-2.0", 1046 + "optional": true, 1047 + "os": [ 1048 + "linux" 1049 + ], 1050 + "engines": { 1051 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 1052 + }, 1053 + "funding": { 1054 + "url": "https://opencollective.com/libvips" 1055 + }, 1056 + "optionalDependencies": { 1057 + "@img/sharp-libvips-linux-ppc64": "1.2.4" 1058 + } 1059 + }, 1060 + "node_modules/@img/sharp-linux-riscv64": { 1061 + "version": "0.34.5", 1062 + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", 1063 + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", 1064 + "cpu": [ 1065 + "riscv64" 1066 + ], 1067 + "libc": [ 1068 + "glibc" 1069 + ], 1070 + "license": "Apache-2.0", 1071 + "optional": true, 1072 + "os": [ 1073 + "linux" 1074 + ], 1075 + "engines": { 1076 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 1077 + }, 1078 + "funding": { 1079 + "url": "https://opencollective.com/libvips" 1080 + }, 1081 + "optionalDependencies": { 1082 + "@img/sharp-libvips-linux-riscv64": "1.2.4" 1083 + } 1084 + }, 1085 + "node_modules/@img/sharp-linux-s390x": { 1086 + "version": "0.34.5", 1087 + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", 1088 + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", 1089 + "cpu": [ 1090 + "s390x" 1091 + ], 1092 + "libc": [ 1093 + "glibc" 1094 + ], 1095 + "license": "Apache-2.0", 1096 + "optional": true, 1097 + "os": [ 1098 + "linux" 1099 + ], 1100 + "engines": { 1101 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 1102 + }, 1103 + "funding": { 1104 + "url": "https://opencollective.com/libvips" 1105 + }, 1106 + "optionalDependencies": { 1107 + "@img/sharp-libvips-linux-s390x": "1.2.4" 1108 + } 1109 + }, 1110 + "node_modules/@img/sharp-linux-x64": { 1111 + "version": "0.34.5", 1112 + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", 1113 + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", 1114 + "cpu": [ 1115 + "x64" 1116 + ], 1117 + "libc": [ 1118 + "glibc" 1119 + ], 1120 + "license": "Apache-2.0", 1121 + "optional": true, 1122 + "os": [ 1123 + "linux" 1124 + ], 1125 + "engines": { 1126 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 1127 + }, 1128 + "funding": { 1129 + "url": "https://opencollective.com/libvips" 1130 + }, 1131 + "optionalDependencies": { 1132 + "@img/sharp-libvips-linux-x64": "1.2.4" 1133 + } 1134 + }, 1135 + "node_modules/@img/sharp-linuxmusl-arm64": { 1136 + "version": "0.34.5", 1137 + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", 1138 + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", 1139 + "cpu": [ 1140 + "arm64" 1141 + ], 1142 + "libc": [ 1143 + "musl" 1144 + ], 1145 + "license": "Apache-2.0", 1146 + "optional": true, 1147 + "os": [ 1148 + "linux" 1149 + ], 1150 + "engines": { 1151 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 1152 + }, 1153 + "funding": { 1154 + "url": "https://opencollective.com/libvips" 1155 + }, 1156 + "optionalDependencies": { 1157 + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" 1158 + } 1159 + }, 1160 + "node_modules/@img/sharp-linuxmusl-x64": { 1161 + "version": "0.34.5", 1162 + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", 1163 + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", 1164 + "cpu": [ 1165 + "x64" 1166 + ], 1167 + "libc": [ 1168 + "musl" 1169 + ], 1170 + "license": "Apache-2.0", 1171 + "optional": true, 1172 + "os": [ 1173 + "linux" 1174 + ], 1175 + "engines": { 1176 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 1177 + }, 1178 + "funding": { 1179 + "url": "https://opencollective.com/libvips" 1180 + }, 1181 + "optionalDependencies": { 1182 + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" 1183 + } 1184 + }, 1185 + "node_modules/@img/sharp-wasm32": { 1186 + "version": "0.34.5", 1187 + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", 1188 + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", 1189 + "cpu": [ 1190 + "wasm32" 1191 + ], 1192 + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", 1193 + "optional": true, 1194 + "dependencies": { 1195 + "@emnapi/runtime": "^1.7.0" 1196 + }, 1197 + "engines": { 1198 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 1199 + }, 1200 + "funding": { 1201 + "url": "https://opencollective.com/libvips" 1202 + } 1203 + }, 1204 + "node_modules/@img/sharp-win32-arm64": { 1205 + "version": "0.34.5", 1206 + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", 1207 + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", 1208 + "cpu": [ 1209 + "arm64" 1210 + ], 1211 + "license": "Apache-2.0 AND LGPL-3.0-or-later", 1212 + "optional": true, 1213 + "os": [ 1214 + "win32" 1215 + ], 1216 + "engines": { 1217 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 1218 + }, 1219 + "funding": { 1220 + "url": "https://opencollective.com/libvips" 1221 + } 1222 + }, 1223 + "node_modules/@img/sharp-win32-ia32": { 1224 + "version": "0.34.5", 1225 + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", 1226 + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", 1227 + "cpu": [ 1228 + "ia32" 1229 + ], 1230 + "license": "Apache-2.0 AND LGPL-3.0-or-later", 1231 + "optional": true, 1232 + "os": [ 1233 + "win32" 1234 + ], 1235 + "engines": { 1236 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 1237 + }, 1238 + "funding": { 1239 + "url": "https://opencollective.com/libvips" 1240 + } 1241 + }, 1242 + "node_modules/@img/sharp-win32-x64": { 1243 + "version": "0.34.5", 1244 + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", 1245 + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", 1246 + "cpu": [ 1247 + "x64" 1248 + ], 1249 + "license": "Apache-2.0 AND LGPL-3.0-or-later", 1250 + "optional": true, 1251 + "os": [ 1252 + "win32" 1253 + ], 1254 + "engines": { 1255 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 1256 + }, 1257 + "funding": { 1258 + "url": "https://opencollective.com/libvips" 1259 + } 1260 + }, 1261 + "node_modules/@jridgewell/gen-mapping": { 1262 + "version": "0.3.13", 1263 + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", 1264 + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", 1265 + "dev": true, 1266 + "license": "MIT", 1267 + "dependencies": { 1268 + "@jridgewell/sourcemap-codec": "^1.5.0", 1269 + "@jridgewell/trace-mapping": "^0.3.24" 1270 + } 1271 + }, 1272 + "node_modules/@jridgewell/resolve-uri": { 1273 + "version": "3.1.2", 1274 + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 1275 + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 1276 + "dev": true, 1277 + "license": "MIT", 1278 + "engines": { 1279 + "node": ">=6.0.0" 1280 + } 1281 + }, 1282 + "node_modules/@jridgewell/sourcemap-codec": { 1283 + "version": "1.5.5", 1284 + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", 1285 + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", 1286 + "license": "MIT" 1287 + }, 1288 + "node_modules/@jridgewell/trace-mapping": { 1289 + "version": "0.3.31", 1290 + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", 1291 + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", 1292 + "dev": true, 1293 + "license": "MIT", 1294 + "dependencies": { 1295 + "@jridgewell/resolve-uri": "^3.1.0", 1296 + "@jridgewell/sourcemap-codec": "^1.4.14" 1297 + } 1298 + }, 1299 + "node_modules/@mdx-js/mdx": { 1300 + "version": "3.1.1", 1301 + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz", 1302 + "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==", 1303 + "license": "MIT", 1304 + "dependencies": { 1305 + "@types/estree": "^1.0.0", 1306 + "@types/estree-jsx": "^1.0.0", 1307 + "@types/hast": "^3.0.0", 1308 + "@types/mdx": "^2.0.0", 1309 + "acorn": "^8.0.0", 1310 + "collapse-white-space": "^2.0.0", 1311 + "devlop": "^1.0.0", 1312 + "estree-util-is-identifier-name": "^3.0.0", 1313 + "estree-util-scope": "^1.0.0", 1314 + "estree-walker": "^3.0.0", 1315 + "hast-util-to-jsx-runtime": "^2.0.0", 1316 + "markdown-extensions": "^2.0.0", 1317 + "recma-build-jsx": "^1.0.0", 1318 + "recma-jsx": "^1.0.0", 1319 + "recma-stringify": "^1.0.0", 1320 + "rehype-recma": "^1.0.0", 1321 + "remark-mdx": "^3.0.0", 1322 + "remark-parse": "^11.0.0", 1323 + "remark-rehype": "^11.0.0", 1324 + "source-map": "^0.7.0", 1325 + "unified": "^11.0.0", 1326 + "unist-util-position-from-estree": "^2.0.0", 1327 + "unist-util-stringify-position": "^4.0.0", 1328 + "unist-util-visit": "^5.0.0", 1329 + "vfile": "^6.0.0" 1330 + }, 1331 + "funding": { 1332 + "type": "opencollective", 1333 + "url": "https://opencollective.com/unified" 1334 + } 1335 + }, 1336 + "node_modules/@nodelib/fs.scandir": { 1337 + "version": "2.1.5", 1338 + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 1339 + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 1340 + "dev": true, 1341 + "license": "MIT", 1342 + "dependencies": { 1343 + "@nodelib/fs.stat": "2.0.5", 1344 + "run-parallel": "^1.1.9" 1345 + }, 1346 + "engines": { 1347 + "node": ">= 8" 1348 + } 1349 + }, 1350 + "node_modules/@nodelib/fs.stat": { 1351 + "version": "2.0.5", 1352 + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 1353 + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 1354 + "dev": true, 1355 + "license": "MIT", 1356 + "engines": { 1357 + "node": ">= 8" 1358 + } 1359 + }, 1360 + "node_modules/@nodelib/fs.walk": { 1361 + "version": "1.2.8", 1362 + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 1363 + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 1364 + "dev": true, 1365 + "license": "MIT", 1366 + "dependencies": { 1367 + "@nodelib/fs.scandir": "2.1.5", 1368 + "fastq": "^1.6.0" 1369 + }, 1370 + "engines": { 1371 + "node": ">= 8" 1372 + } 1373 + }, 1374 + "node_modules/@oslojs/encoding": { 1375 + "version": "1.1.0", 1376 + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", 1377 + "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", 1378 + "license": "MIT" 1379 + }, 1380 + "node_modules/@pagefind/darwin-arm64": { 1381 + "version": "1.5.2", 1382 + "resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.5.2.tgz", 1383 + "integrity": "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ==", 1384 + "cpu": [ 1385 + "arm64" 1386 + ], 1387 + "license": "MIT", 1388 + "optional": true, 1389 + "os": [ 1390 + "darwin" 1391 + ] 1392 + }, 1393 + "node_modules/@pagefind/darwin-x64": { 1394 + "version": "1.5.2", 1395 + "resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.5.2.tgz", 1396 + "integrity": "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw==", 1397 + "cpu": [ 1398 + "x64" 1399 + ], 1400 + "license": "MIT", 1401 + "optional": true, 1402 + "os": [ 1403 + "darwin" 1404 + ] 1405 + }, 1406 + "node_modules/@pagefind/default-ui": { 1407 + "version": "1.5.2", 1408 + "resolved": "https://registry.npmjs.org/@pagefind/default-ui/-/default-ui-1.5.2.tgz", 1409 + "integrity": "sha512-pm1LMnQg8N2B3n2TnjKlhaFihpz6zTiA4HiGQ6/slKO/+8K9CAU5kcjdSSPgpuk1PMuuN4hxLipUIifnrkl3Sg==", 1410 + "license": "MIT" 1411 + }, 1412 + "node_modules/@pagefind/freebsd-x64": { 1413 + "version": "1.5.2", 1414 + "resolved": "https://registry.npmjs.org/@pagefind/freebsd-x64/-/freebsd-x64-1.5.2.tgz", 1415 + "integrity": "sha512-7EVzo9+0w+2cbe671BtMj10UlNo83I+HrLVLfRxO731svHRJKUfJ/mo05gU14pe9PCfpKNQT8FS3Xc/oDN6pOA==", 1416 + "cpu": [ 1417 + "x64" 1418 + ], 1419 + "license": "MIT", 1420 + "optional": true, 1421 + "os": [ 1422 + "freebsd" 1423 + ] 1424 + }, 1425 + "node_modules/@pagefind/linux-arm64": { 1426 + "version": "1.5.2", 1427 + "resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.5.2.tgz", 1428 + "integrity": "sha512-Ovt9+K35sqzn8H3ZMXGwls4TD/wMJuvRtShHIsmUQREmaxjrDEX7gHckRCrwYJ4XE1H1p6HkLz3wukrAnsfXQw==", 1429 + "cpu": [ 1430 + "arm64" 1431 + ], 1432 + "license": "MIT", 1433 + "optional": true, 1434 + "os": [ 1435 + "linux" 1436 + ] 1437 + }, 1438 + "node_modules/@pagefind/linux-x64": { 1439 + "version": "1.5.2", 1440 + "resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.5.2.tgz", 1441 + "integrity": "sha512-V+tFqHKXhQKq/WqPBD67AFy7scn1/aZID00ws4fSDd+1daSi5UHR9VVlRrOUYKxn3VuFQYRD7lYXdZK1WED1YA==", 1442 + "cpu": [ 1443 + "x64" 1444 + ], 1445 + "license": "MIT", 1446 + "optional": true, 1447 + "os": [ 1448 + "linux" 1449 + ] 1450 + }, 1451 + "node_modules/@pagefind/windows-arm64": { 1452 + "version": "1.5.2", 1453 + "resolved": "https://registry.npmjs.org/@pagefind/windows-arm64/-/windows-arm64-1.5.2.tgz", 1454 + "integrity": "sha512-hN9Nh90fNW61nNRCW9ZyQrAj/mD0eRvmJ8NlTUzkbuW8kIzGJUi3cxjFkEcMZ5h/8FsKWD/VcouZl4yo1F7B6g==", 1455 + "cpu": [ 1456 + "arm64" 1457 + ], 1458 + "license": "MIT", 1459 + "optional": true, 1460 + "os": [ 1461 + "win32" 1462 + ] 1463 + }, 1464 + "node_modules/@pagefind/windows-x64": { 1465 + "version": "1.5.2", 1466 + "resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.5.2.tgz", 1467 + "integrity": "sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg==", 1468 + "cpu": [ 1469 + "x64" 1470 + ], 1471 + "license": "MIT", 1472 + "optional": true, 1473 + "os": [ 1474 + "win32" 1475 + ] 1476 + }, 1477 + "node_modules/@rollup/pluginutils": { 1478 + "version": "5.4.0", 1479 + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", 1480 + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", 1481 + "license": "MIT", 1482 + "dependencies": { 1483 + "@types/estree": "^1.0.0", 1484 + "estree-walker": "^2.0.2", 1485 + "picomatch": "^4.0.2" 1486 + }, 1487 + "engines": { 1488 + "node": ">=14.0.0" 1489 + }, 1490 + "peerDependencies": { 1491 + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" 1492 + }, 1493 + "peerDependenciesMeta": { 1494 + "rollup": { 1495 + "optional": true 1496 + } 1497 + } 1498 + }, 1499 + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { 1500 + "version": "2.0.2", 1501 + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 1502 + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 1503 + "license": "MIT" 1504 + }, 1505 + "node_modules/@rollup/rollup-android-arm-eabi": { 1506 + "version": "4.62.2", 1507 + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", 1508 + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", 1509 + "cpu": [ 1510 + "arm" 1511 + ], 1512 + "license": "MIT", 1513 + "optional": true, 1514 + "os": [ 1515 + "android" 1516 + ] 1517 + }, 1518 + "node_modules/@rollup/rollup-android-arm64": { 1519 + "version": "4.62.2", 1520 + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", 1521 + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", 1522 + "cpu": [ 1523 + "arm64" 1524 + ], 1525 + "license": "MIT", 1526 + "optional": true, 1527 + "os": [ 1528 + "android" 1529 + ] 1530 + }, 1531 + "node_modules/@rollup/rollup-darwin-arm64": { 1532 + "version": "4.62.2", 1533 + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", 1534 + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", 1535 + "cpu": [ 1536 + "arm64" 1537 + ], 1538 + "license": "MIT", 1539 + "optional": true, 1540 + "os": [ 1541 + "darwin" 1542 + ] 1543 + }, 1544 + "node_modules/@rollup/rollup-darwin-x64": { 1545 + "version": "4.62.2", 1546 + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", 1547 + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", 1548 + "cpu": [ 1549 + "x64" 1550 + ], 1551 + "license": "MIT", 1552 + "optional": true, 1553 + "os": [ 1554 + "darwin" 1555 + ] 1556 + }, 1557 + "node_modules/@rollup/rollup-freebsd-arm64": { 1558 + "version": "4.62.2", 1559 + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", 1560 + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", 1561 + "cpu": [ 1562 + "arm64" 1563 + ], 1564 + "license": "MIT", 1565 + "optional": true, 1566 + "os": [ 1567 + "freebsd" 1568 + ] 1569 + }, 1570 + "node_modules/@rollup/rollup-freebsd-x64": { 1571 + "version": "4.62.2", 1572 + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", 1573 + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", 1574 + "cpu": [ 1575 + "x64" 1576 + ], 1577 + "license": "MIT", 1578 + "optional": true, 1579 + "os": [ 1580 + "freebsd" 1581 + ] 1582 + }, 1583 + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 1584 + "version": "4.62.2", 1585 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", 1586 + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", 1587 + "cpu": [ 1588 + "arm" 1589 + ], 1590 + "libc": [ 1591 + "glibc" 1592 + ], 1593 + "license": "MIT", 1594 + "optional": true, 1595 + "os": [ 1596 + "linux" 1597 + ] 1598 + }, 1599 + "node_modules/@rollup/rollup-linux-arm-musleabihf": { 1600 + "version": "4.62.2", 1601 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", 1602 + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", 1603 + "cpu": [ 1604 + "arm" 1605 + ], 1606 + "libc": [ 1607 + "musl" 1608 + ], 1609 + "license": "MIT", 1610 + "optional": true, 1611 + "os": [ 1612 + "linux" 1613 + ] 1614 + }, 1615 + "node_modules/@rollup/rollup-linux-arm64-gnu": { 1616 + "version": "4.62.2", 1617 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", 1618 + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", 1619 + "cpu": [ 1620 + "arm64" 1621 + ], 1622 + "libc": [ 1623 + "glibc" 1624 + ], 1625 + "license": "MIT", 1626 + "optional": true, 1627 + "os": [ 1628 + "linux" 1629 + ] 1630 + }, 1631 + "node_modules/@rollup/rollup-linux-arm64-musl": { 1632 + "version": "4.62.2", 1633 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", 1634 + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", 1635 + "cpu": [ 1636 + "arm64" 1637 + ], 1638 + "libc": [ 1639 + "musl" 1640 + ], 1641 + "license": "MIT", 1642 + "optional": true, 1643 + "os": [ 1644 + "linux" 1645 + ] 1646 + }, 1647 + "node_modules/@rollup/rollup-linux-loong64-gnu": { 1648 + "version": "4.62.2", 1649 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", 1650 + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", 1651 + "cpu": [ 1652 + "loong64" 1653 + ], 1654 + "libc": [ 1655 + "glibc" 1656 + ], 1657 + "license": "MIT", 1658 + "optional": true, 1659 + "os": [ 1660 + "linux" 1661 + ] 1662 + }, 1663 + "node_modules/@rollup/rollup-linux-loong64-musl": { 1664 + "version": "4.62.2", 1665 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", 1666 + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", 1667 + "cpu": [ 1668 + "loong64" 1669 + ], 1670 + "libc": [ 1671 + "musl" 1672 + ], 1673 + "license": "MIT", 1674 + "optional": true, 1675 + "os": [ 1676 + "linux" 1677 + ] 1678 + }, 1679 + "node_modules/@rollup/rollup-linux-ppc64-gnu": { 1680 + "version": "4.62.2", 1681 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", 1682 + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", 1683 + "cpu": [ 1684 + "ppc64" 1685 + ], 1686 + "libc": [ 1687 + "glibc" 1688 + ], 1689 + "license": "MIT", 1690 + "optional": true, 1691 + "os": [ 1692 + "linux" 1693 + ] 1694 + }, 1695 + "node_modules/@rollup/rollup-linux-ppc64-musl": { 1696 + "version": "4.62.2", 1697 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", 1698 + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", 1699 + "cpu": [ 1700 + "ppc64" 1701 + ], 1702 + "libc": [ 1703 + "musl" 1704 + ], 1705 + "license": "MIT", 1706 + "optional": true, 1707 + "os": [ 1708 + "linux" 1709 + ] 1710 + }, 1711 + "node_modules/@rollup/rollup-linux-riscv64-gnu": { 1712 + "version": "4.62.2", 1713 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", 1714 + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", 1715 + "cpu": [ 1716 + "riscv64" 1717 + ], 1718 + "libc": [ 1719 + "glibc" 1720 + ], 1721 + "license": "MIT", 1722 + "optional": true, 1723 + "os": [ 1724 + "linux" 1725 + ] 1726 + }, 1727 + "node_modules/@rollup/rollup-linux-riscv64-musl": { 1728 + "version": "4.62.2", 1729 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", 1730 + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", 1731 + "cpu": [ 1732 + "riscv64" 1733 + ], 1734 + "libc": [ 1735 + "musl" 1736 + ], 1737 + "license": "MIT", 1738 + "optional": true, 1739 + "os": [ 1740 + "linux" 1741 + ] 1742 + }, 1743 + "node_modules/@rollup/rollup-linux-s390x-gnu": { 1744 + "version": "4.62.2", 1745 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", 1746 + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", 1747 + "cpu": [ 1748 + "s390x" 1749 + ], 1750 + "libc": [ 1751 + "glibc" 1752 + ], 1753 + "license": "MIT", 1754 + "optional": true, 1755 + "os": [ 1756 + "linux" 1757 + ] 1758 + }, 1759 + "node_modules/@rollup/rollup-linux-x64-gnu": { 1760 + "version": "4.62.2", 1761 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", 1762 + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", 1763 + "cpu": [ 1764 + "x64" 1765 + ], 1766 + "libc": [ 1767 + "glibc" 1768 + ], 1769 + "license": "MIT", 1770 + "optional": true, 1771 + "os": [ 1772 + "linux" 1773 + ] 1774 + }, 1775 + "node_modules/@rollup/rollup-linux-x64-musl": { 1776 + "version": "4.62.2", 1777 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", 1778 + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", 1779 + "cpu": [ 1780 + "x64" 1781 + ], 1782 + "libc": [ 1783 + "musl" 1784 + ], 1785 + "license": "MIT", 1786 + "optional": true, 1787 + "os": [ 1788 + "linux" 1789 + ] 1790 + }, 1791 + "node_modules/@rollup/rollup-openbsd-x64": { 1792 + "version": "4.62.2", 1793 + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", 1794 + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", 1795 + "cpu": [ 1796 + "x64" 1797 + ], 1798 + "license": "MIT", 1799 + "optional": true, 1800 + "os": [ 1801 + "openbsd" 1802 + ] 1803 + }, 1804 + "node_modules/@rollup/rollup-openharmony-arm64": { 1805 + "version": "4.62.2", 1806 + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", 1807 + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", 1808 + "cpu": [ 1809 + "arm64" 1810 + ], 1811 + "license": "MIT", 1812 + "optional": true, 1813 + "os": [ 1814 + "openharmony" 1815 + ] 1816 + }, 1817 + "node_modules/@rollup/rollup-win32-arm64-msvc": { 1818 + "version": "4.62.2", 1819 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", 1820 + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", 1821 + "cpu": [ 1822 + "arm64" 1823 + ], 1824 + "license": "MIT", 1825 + "optional": true, 1826 + "os": [ 1827 + "win32" 1828 + ] 1829 + }, 1830 + "node_modules/@rollup/rollup-win32-ia32-msvc": { 1831 + "version": "4.62.2", 1832 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", 1833 + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", 1834 + "cpu": [ 1835 + "ia32" 1836 + ], 1837 + "license": "MIT", 1838 + "optional": true, 1839 + "os": [ 1840 + "win32" 1841 + ] 1842 + }, 1843 + "node_modules/@rollup/rollup-win32-x64-gnu": { 1844 + "version": "4.62.2", 1845 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", 1846 + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", 1847 + "cpu": [ 1848 + "x64" 1849 + ], 1850 + "license": "MIT", 1851 + "optional": true, 1852 + "os": [ 1853 + "win32" 1854 + ] 1855 + }, 1856 + "node_modules/@rollup/rollup-win32-x64-msvc": { 1857 + "version": "4.62.2", 1858 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", 1859 + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", 1860 + "cpu": [ 1861 + "x64" 1862 + ], 1863 + "license": "MIT", 1864 + "optional": true, 1865 + "os": [ 1866 + "win32" 1867 + ] 1868 + }, 1869 + "node_modules/@shikijs/core": { 1870 + "version": "3.23.0", 1871 + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.23.0.tgz", 1872 + "integrity": "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==", 1873 + "license": "MIT", 1874 + "dependencies": { 1875 + "@shikijs/types": "3.23.0", 1876 + "@shikijs/vscode-textmate": "^10.0.2", 1877 + "@types/hast": "^3.0.4", 1878 + "hast-util-to-html": "^9.0.5" 1879 + } 1880 + }, 1881 + "node_modules/@shikijs/engine-javascript": { 1882 + "version": "3.23.0", 1883 + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.23.0.tgz", 1884 + "integrity": "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==", 1885 + "license": "MIT", 1886 + "dependencies": { 1887 + "@shikijs/types": "3.23.0", 1888 + "@shikijs/vscode-textmate": "^10.0.2", 1889 + "oniguruma-to-es": "^4.3.4" 1890 + } 1891 + }, 1892 + "node_modules/@shikijs/engine-oniguruma": { 1893 + "version": "3.23.0", 1894 + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz", 1895 + "integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==", 1896 + "license": "MIT", 1897 + "dependencies": { 1898 + "@shikijs/types": "3.23.0", 1899 + "@shikijs/vscode-textmate": "^10.0.2" 1900 + } 1901 + }, 1902 + "node_modules/@shikijs/langs": { 1903 + "version": "3.23.0", 1904 + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz", 1905 + "integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==", 1906 + "license": "MIT", 1907 + "dependencies": { 1908 + "@shikijs/types": "3.23.0" 1909 + } 1910 + }, 1911 + "node_modules/@shikijs/themes": { 1912 + "version": "3.23.0", 1913 + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz", 1914 + "integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==", 1915 + "license": "MIT", 1916 + "dependencies": { 1917 + "@shikijs/types": "3.23.0" 1918 + } 1919 + }, 1920 + "node_modules/@shikijs/types": { 1921 + "version": "3.23.0", 1922 + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz", 1923 + "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==", 1924 + "license": "MIT", 1925 + "dependencies": { 1926 + "@shikijs/vscode-textmate": "^10.0.2", 1927 + "@types/hast": "^3.0.4" 1928 + } 1929 + }, 1930 + "node_modules/@shikijs/vscode-textmate": { 1931 + "version": "10.0.2", 1932 + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", 1933 + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", 1934 + "license": "MIT" 1935 + }, 1936 + "node_modules/@tailwindcss/typography": { 1937 + "version": "0.5.20", 1938 + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.20.tgz", 1939 + "integrity": "sha512-hwbzQuNUfcPvbegQFatVPl/MY/tcM9KLl963hQ5laJKPh81TEZ1+dNG9PirGvcaDBkp+BCshExAyKVPW91dozw==", 1940 + "dev": true, 1941 + "license": "MIT", 1942 + "dependencies": { 1943 + "postcss-selector-parser": "6.0.10" 1944 + }, 1945 + "peerDependencies": { 1946 + "tailwindcss": ">=3.0.0 || >=4.0.0 || insiders" 1947 + } 1948 + }, 1949 + "node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": { 1950 + "version": "6.0.10", 1951 + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", 1952 + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", 1953 + "dev": true, 1954 + "license": "MIT", 1955 + "dependencies": { 1956 + "cssesc": "^3.0.0", 1957 + "util-deprecate": "^1.0.2" 1958 + }, 1959 + "engines": { 1960 + "node": ">=4" 1961 + } 1962 + }, 1963 + "node_modules/@types/debug": { 1964 + "version": "4.1.13", 1965 + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", 1966 + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", 1967 + "license": "MIT", 1968 + "dependencies": { 1969 + "@types/ms": "*" 1970 + } 1971 + }, 1972 + "node_modules/@types/estree": { 1973 + "version": "1.0.9", 1974 + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", 1975 + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", 1976 + "license": "MIT" 1977 + }, 1978 + "node_modules/@types/estree-jsx": { 1979 + "version": "1.0.5", 1980 + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", 1981 + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", 1982 + "license": "MIT", 1983 + "dependencies": { 1984 + "@types/estree": "*" 1985 + } 1986 + }, 1987 + "node_modules/@types/hast": { 1988 + "version": "3.0.5", 1989 + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", 1990 + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", 1991 + "license": "MIT", 1992 + "dependencies": { 1993 + "@types/unist": "*" 1994 + } 1995 + }, 1996 + "node_modules/@types/js-yaml": { 1997 + "version": "4.0.9", 1998 + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", 1999 + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", 2000 + "license": "MIT" 2001 + }, 2002 + "node_modules/@types/mdast": { 2003 + "version": "4.0.4", 2004 + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", 2005 + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", 2006 + "license": "MIT", 2007 + "dependencies": { 2008 + "@types/unist": "*" 2009 + } 2010 + }, 2011 + "node_modules/@types/mdx": { 2012 + "version": "2.0.14", 2013 + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.14.tgz", 2014 + "integrity": "sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg==", 2015 + "license": "MIT" 2016 + }, 2017 + "node_modules/@types/ms": { 2018 + "version": "2.1.0", 2019 + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", 2020 + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", 2021 + "license": "MIT" 2022 + }, 2023 + "node_modules/@types/nlcst": { 2024 + "version": "2.0.3", 2025 + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", 2026 + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", 2027 + "license": "MIT", 2028 + "dependencies": { 2029 + "@types/unist": "*" 2030 + } 2031 + }, 2032 + "node_modules/@types/node": { 2033 + "version": "24.13.3", 2034 + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz", 2035 + "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==", 2036 + "license": "MIT", 2037 + "dependencies": { 2038 + "undici-types": "~7.18.0" 2039 + } 2040 + }, 2041 + "node_modules/@types/sax": { 2042 + "version": "1.2.7", 2043 + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", 2044 + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", 2045 + "license": "MIT", 2046 + "dependencies": { 2047 + "@types/node": "*" 2048 + } 2049 + }, 2050 + "node_modules/@types/unist": { 2051 + "version": "3.0.3", 2052 + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", 2053 + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", 2054 + "license": "MIT" 2055 + }, 2056 + "node_modules/@ungap/structured-clone": { 2057 + "version": "1.3.3", 2058 + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", 2059 + "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", 2060 + "license": "ISC" 2061 + }, 2062 + "node_modules/acorn": { 2063 + "version": "8.17.0", 2064 + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", 2065 + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", 2066 + "license": "MIT", 2067 + "bin": { 2068 + "acorn": "bin/acorn" 2069 + }, 2070 + "engines": { 2071 + "node": ">=0.4.0" 2072 + } 2073 + }, 2074 + "node_modules/acorn-jsx": { 2075 + "version": "5.3.2", 2076 + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", 2077 + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", 2078 + "license": "MIT", 2079 + "peerDependencies": { 2080 + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" 2081 + } 2082 + }, 2083 + "node_modules/ansi-align": { 2084 + "version": "3.0.1", 2085 + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", 2086 + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", 2087 + "license": "ISC", 2088 + "dependencies": { 2089 + "string-width": "^4.1.0" 2090 + } 2091 + }, 2092 + "node_modules/ansi-align/node_modules/ansi-regex": { 2093 + "version": "5.0.1", 2094 + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 2095 + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 2096 + "license": "MIT", 2097 + "engines": { 2098 + "node": ">=8" 2099 + } 2100 + }, 2101 + "node_modules/ansi-align/node_modules/emoji-regex": { 2102 + "version": "8.0.0", 2103 + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 2104 + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 2105 + "license": "MIT" 2106 + }, 2107 + "node_modules/ansi-align/node_modules/string-width": { 2108 + "version": "4.2.3", 2109 + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 2110 + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 2111 + "license": "MIT", 2112 + "dependencies": { 2113 + "emoji-regex": "^8.0.0", 2114 + "is-fullwidth-code-point": "^3.0.0", 2115 + "strip-ansi": "^6.0.1" 2116 + }, 2117 + "engines": { 2118 + "node": ">=8" 2119 + } 2120 + }, 2121 + "node_modules/ansi-align/node_modules/strip-ansi": { 2122 + "version": "6.0.1", 2123 + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 2124 + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 2125 + "license": "MIT", 2126 + "dependencies": { 2127 + "ansi-regex": "^5.0.1" 2128 + }, 2129 + "engines": { 2130 + "node": ">=8" 2131 + } 2132 + }, 2133 + "node_modules/ansi-regex": { 2134 + "version": "6.2.2", 2135 + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", 2136 + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", 2137 + "license": "MIT", 2138 + "engines": { 2139 + "node": ">=12" 2140 + }, 2141 + "funding": { 2142 + "url": "https://github.com/chalk/ansi-regex?sponsor=1" 2143 + } 2144 + }, 2145 + "node_modules/ansi-styles": { 2146 + "version": "6.2.3", 2147 + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", 2148 + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", 2149 + "license": "MIT", 2150 + "engines": { 2151 + "node": ">=12" 2152 + }, 2153 + "funding": { 2154 + "url": "https://github.com/chalk/ansi-styles?sponsor=1" 2155 + } 2156 + }, 2157 + "node_modules/any-promise": { 2158 + "version": "1.3.0", 2159 + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", 2160 + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", 2161 + "dev": true, 2162 + "license": "MIT" 2163 + }, 2164 + "node_modules/anymatch": { 2165 + "version": "3.1.3", 2166 + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 2167 + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 2168 + "license": "ISC", 2169 + "dependencies": { 2170 + "normalize-path": "^3.0.0", 2171 + "picomatch": "^2.0.4" 2172 + }, 2173 + "engines": { 2174 + "node": ">= 8" 2175 + } 2176 + }, 2177 + "node_modules/anymatch/node_modules/picomatch": { 2178 + "version": "2.3.2", 2179 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", 2180 + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", 2181 + "license": "MIT", 2182 + "engines": { 2183 + "node": ">=8.6" 2184 + }, 2185 + "funding": { 2186 + "url": "https://github.com/sponsors/jonschlinkert" 2187 + } 2188 + }, 2189 + "node_modules/arg": { 2190 + "version": "5.0.2", 2191 + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", 2192 + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", 2193 + "license": "MIT" 2194 + }, 2195 + "node_modules/argparse": { 2196 + "version": "2.0.1", 2197 + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 2198 + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 2199 + "license": "Python-2.0" 2200 + }, 2201 + "node_modules/aria-query": { 2202 + "version": "5.3.2", 2203 + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", 2204 + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", 2205 + "license": "Apache-2.0", 2206 + "engines": { 2207 + "node": ">= 0.4" 2208 + } 2209 + }, 2210 + "node_modules/array-iterate": { 2211 + "version": "2.0.1", 2212 + "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", 2213 + "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", 2214 + "license": "MIT", 2215 + "funding": { 2216 + "type": "github", 2217 + "url": "https://github.com/sponsors/wooorm" 2218 + } 2219 + }, 2220 + "node_modules/astring": { 2221 + "version": "1.9.0", 2222 + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", 2223 + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", 2224 + "license": "MIT", 2225 + "bin": { 2226 + "astring": "bin/astring" 2227 + } 2228 + }, 2229 + "node_modules/astro": { 2230 + "version": "5.18.2", 2231 + "resolved": "https://registry.npmjs.org/astro/-/astro-5.18.2.tgz", 2232 + "integrity": "sha512-TnFwLnAXty5MXKPDGuKXqK4AMBXG+FH6RUdK7Oyc3gyfNoFIthT+4eRbzOK43bdRlLaZuxgciDSjgtggZ3OtGQ==", 2233 + "license": "MIT", 2234 + "dependencies": { 2235 + "@astrojs/compiler": "^2.13.0", 2236 + "@astrojs/internal-helpers": "0.7.6", 2237 + "@astrojs/markdown-remark": "6.3.11", 2238 + "@astrojs/telemetry": "3.3.0", 2239 + "@capsizecss/unpack": "^4.0.0", 2240 + "@oslojs/encoding": "^1.1.0", 2241 + "@rollup/pluginutils": "^5.3.0", 2242 + "acorn": "^8.15.0", 2243 + "aria-query": "^5.3.2", 2244 + "axobject-query": "^4.1.0", 2245 + "boxen": "8.0.1", 2246 + "ci-info": "^4.3.1", 2247 + "clsx": "^2.1.1", 2248 + "common-ancestor-path": "^1.0.1", 2249 + "cookie": "^1.1.1", 2250 + "cssesc": "^3.0.0", 2251 + "debug": "^4.4.3", 2252 + "deterministic-object-hash": "^2.0.2", 2253 + "devalue": "^5.6.2", 2254 + "diff": "^8.0.3", 2255 + "dlv": "^1.1.3", 2256 + "dset": "^3.1.4", 2257 + "es-module-lexer": "^1.7.0", 2258 + "esbuild": "^0.27.3", 2259 + "estree-walker": "^3.0.3", 2260 + "flattie": "^1.1.1", 2261 + "fontace": "~0.4.0", 2262 + "github-slugger": "^2.0.0", 2263 + "html-escaper": "3.0.3", 2264 + "http-cache-semantics": "^4.2.0", 2265 + "import-meta-resolve": "^4.2.0", 2266 + "js-yaml": "^4.1.1", 2267 + "magic-string": "^0.30.21", 2268 + "magicast": "^0.5.1", 2269 + "mrmime": "^2.0.1", 2270 + "neotraverse": "^0.6.18", 2271 + "p-limit": "^6.2.0", 2272 + "p-queue": "^8.1.1", 2273 + "package-manager-detector": "^1.6.0", 2274 + "piccolore": "^0.1.3", 2275 + "picomatch": "^4.0.3", 2276 + "prompts": "^2.4.2", 2277 + "rehype": "^13.0.2", 2278 + "semver": "^7.7.3", 2279 + "shiki": "^3.21.0", 2280 + "smol-toml": "^1.6.0", 2281 + "svgo": "^4.0.0", 2282 + "tinyexec": "^1.0.2", 2283 + "tinyglobby": "^0.2.15", 2284 + "tsconfck": "^3.1.6", 2285 + "ultrahtml": "^1.6.0", 2286 + "unifont": "~0.7.3", 2287 + "unist-util-visit": "^5.0.0", 2288 + "unstorage": "^1.17.4", 2289 + "vfile": "^6.0.3", 2290 + "vite": "^6.4.1", 2291 + "vitefu": "^1.1.1", 2292 + "xxhash-wasm": "^1.1.0", 2293 + "yargs-parser": "^21.1.1", 2294 + "yocto-spinner": "^0.2.3", 2295 + "zod": "^3.25.76", 2296 + "zod-to-json-schema": "^3.25.1", 2297 + "zod-to-ts": "^1.2.0" 2298 + }, 2299 + "bin": { 2300 + "astro": "astro.js" 2301 + }, 2302 + "engines": { 2303 + "node": "18.20.8 || ^20.3.0 || >=22.0.0", 2304 + "npm": ">=9.6.5", 2305 + "pnpm": ">=7.1.0" 2306 + }, 2307 + "funding": { 2308 + "type": "opencollective", 2309 + "url": "https://opencollective.com/astrodotbuild" 2310 + }, 2311 + "optionalDependencies": { 2312 + "sharp": "^0.34.0" 2313 + } 2314 + }, 2315 + "node_modules/astro-expressive-code": { 2316 + "version": "0.41.7", 2317 + "resolved": "https://registry.npmjs.org/astro-expressive-code/-/astro-expressive-code-0.41.7.tgz", 2318 + "integrity": "sha512-hUpogGc6DdAd+I7pPXsctyYPRBJDK7Q7d06s4cyP0Vz3OcbziP3FNzN0jZci1BpCvLn9675DvS7B9ctKKX64JQ==", 2319 + "license": "MIT", 2320 + "dependencies": { 2321 + "rehype-expressive-code": "^0.41.7" 2322 + }, 2323 + "peerDependencies": { 2324 + "astro": "^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta" 2325 + } 2326 + }, 2327 + "node_modules/astro/node_modules/zod": { 2328 + "version": "3.25.76", 2329 + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", 2330 + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", 2331 + "license": "MIT", 2332 + "funding": { 2333 + "url": "https://github.com/sponsors/colinhacks" 2334 + } 2335 + }, 2336 + "node_modules/astro/node_modules/zod-to-ts": { 2337 + "version": "1.2.0", 2338 + "resolved": "https://registry.npmjs.org/zod-to-ts/-/zod-to-ts-1.2.0.tgz", 2339 + "integrity": "sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==", 2340 + "peerDependencies": { 2341 + "typescript": "^4.9.4 || ^5.0.2", 2342 + "zod": "^3" 2343 + } 2344 + }, 2345 + "node_modules/axobject-query": { 2346 + "version": "4.1.0", 2347 + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", 2348 + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", 2349 + "license": "Apache-2.0", 2350 + "engines": { 2351 + "node": ">= 0.4" 2352 + } 2353 + }, 2354 + "node_modules/bail": { 2355 + "version": "2.0.2", 2356 + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", 2357 + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", 2358 + "license": "MIT", 2359 + "funding": { 2360 + "type": "github", 2361 + "url": "https://github.com/sponsors/wooorm" 2362 + } 2363 + }, 2364 + "node_modules/base-64": { 2365 + "version": "1.0.0", 2366 + "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", 2367 + "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", 2368 + "license": "MIT" 2369 + }, 2370 + "node_modules/bcp-47": { 2371 + "version": "2.1.1", 2372 + "resolved": "https://registry.npmjs.org/bcp-47/-/bcp-47-2.1.1.tgz", 2373 + "integrity": "sha512-KLw+H/gd2p4zly1X7Yh/qziuyae5/w/QFnvTng9eZL5fvszL7Whl3MBoWF8yxL7ksUjBfOD+OxkytiqbBpG+Fw==", 2374 + "license": "MIT", 2375 + "dependencies": { 2376 + "is-alphabetical": "^2.0.0", 2377 + "is-alphanumerical": "^2.0.0", 2378 + "is-decimal": "^2.0.0" 2379 + }, 2380 + "funding": { 2381 + "type": "github", 2382 + "url": "https://github.com/sponsors/wooorm" 2383 + } 2384 + }, 2385 + "node_modules/bcp-47-match": { 2386 + "version": "2.0.3", 2387 + "resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz", 2388 + "integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==", 2389 + "license": "MIT", 2390 + "funding": { 2391 + "type": "github", 2392 + "url": "https://github.com/sponsors/wooorm" 2393 + } 2394 + }, 2395 + "node_modules/binary-extensions": { 2396 + "version": "2.3.0", 2397 + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", 2398 + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", 2399 + "dev": true, 2400 + "license": "MIT", 2401 + "engines": { 2402 + "node": ">=8" 2403 + }, 2404 + "funding": { 2405 + "url": "https://github.com/sponsors/sindresorhus" 2406 + } 2407 + }, 2408 + "node_modules/boolbase": { 2409 + "version": "1.0.0", 2410 + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", 2411 + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", 2412 + "license": "ISC" 2413 + }, 2414 + "node_modules/boxen": { 2415 + "version": "8.0.1", 2416 + "resolved": "https://registry.npmjs.org/boxen/-/boxen-8.0.1.tgz", 2417 + "integrity": "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==", 2418 + "license": "MIT", 2419 + "dependencies": { 2420 + "ansi-align": "^3.0.1", 2421 + "camelcase": "^8.0.0", 2422 + "chalk": "^5.3.0", 2423 + "cli-boxes": "^3.0.0", 2424 + "string-width": "^7.2.0", 2425 + "type-fest": "^4.21.0", 2426 + "widest-line": "^5.0.0", 2427 + "wrap-ansi": "^9.0.0" 2428 + }, 2429 + "engines": { 2430 + "node": ">=18" 2431 + }, 2432 + "funding": { 2433 + "url": "https://github.com/sponsors/sindresorhus" 2434 + } 2435 + }, 2436 + "node_modules/braces": { 2437 + "version": "3.0.3", 2438 + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 2439 + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 2440 + "dev": true, 2441 + "license": "MIT", 2442 + "dependencies": { 2443 + "fill-range": "^7.1.1" 2444 + }, 2445 + "engines": { 2446 + "node": ">=8" 2447 + } 2448 + }, 2449 + "node_modules/camelcase": { 2450 + "version": "8.0.0", 2451 + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", 2452 + "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", 2453 + "license": "MIT", 2454 + "engines": { 2455 + "node": ">=16" 2456 + }, 2457 + "funding": { 2458 + "url": "https://github.com/sponsors/sindresorhus" 2459 + } 2460 + }, 2461 + "node_modules/camelcase-css": { 2462 + "version": "2.0.1", 2463 + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", 2464 + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", 2465 + "dev": true, 2466 + "license": "MIT", 2467 + "engines": { 2468 + "node": ">= 6" 2469 + } 2470 + }, 2471 + "node_modules/ccount": { 2472 + "version": "2.0.1", 2473 + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", 2474 + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", 2475 + "license": "MIT", 2476 + "funding": { 2477 + "type": "github", 2478 + "url": "https://github.com/sponsors/wooorm" 2479 + } 2480 + }, 2481 + "node_modules/chalk": { 2482 + "version": "5.6.2", 2483 + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", 2484 + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", 2485 + "license": "MIT", 2486 + "engines": { 2487 + "node": "^12.17.0 || ^14.13 || >=16.0.0" 2488 + }, 2489 + "funding": { 2490 + "url": "https://github.com/chalk/chalk?sponsor=1" 2491 + } 2492 + }, 2493 + "node_modules/character-entities": { 2494 + "version": "2.0.2", 2495 + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", 2496 + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", 2497 + "license": "MIT", 2498 + "funding": { 2499 + "type": "github", 2500 + "url": "https://github.com/sponsors/wooorm" 2501 + } 2502 + }, 2503 + "node_modules/character-entities-html4": { 2504 + "version": "2.1.0", 2505 + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", 2506 + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", 2507 + "license": "MIT", 2508 + "funding": { 2509 + "type": "github", 2510 + "url": "https://github.com/sponsors/wooorm" 2511 + } 2512 + }, 2513 + "node_modules/character-entities-legacy": { 2514 + "version": "3.0.0", 2515 + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", 2516 + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", 2517 + "license": "MIT", 2518 + "funding": { 2519 + "type": "github", 2520 + "url": "https://github.com/sponsors/wooorm" 2521 + } 2522 + }, 2523 + "node_modules/character-reference-invalid": { 2524 + "version": "2.0.1", 2525 + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", 2526 + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", 2527 + "license": "MIT", 2528 + "funding": { 2529 + "type": "github", 2530 + "url": "https://github.com/sponsors/wooorm" 2531 + } 2532 + }, 2533 + "node_modules/chokidar": { 2534 + "version": "5.0.0", 2535 + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", 2536 + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", 2537 + "license": "MIT", 2538 + "dependencies": { 2539 + "readdirp": "^5.0.0" 2540 + }, 2541 + "engines": { 2542 + "node": ">= 20.19.0" 2543 + }, 2544 + "funding": { 2545 + "url": "https://paulmillr.com/funding/" 2546 + } 2547 + }, 2548 + "node_modules/ci-info": { 2549 + "version": "4.4.0", 2550 + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", 2551 + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", 2552 + "funding": [ 2553 + { 2554 + "type": "github", 2555 + "url": "https://github.com/sponsors/sibiraj-s" 2556 + } 2557 + ], 2558 + "license": "MIT", 2559 + "engines": { 2560 + "node": ">=8" 2561 + } 2562 + }, 2563 + "node_modules/cli-boxes": { 2564 + "version": "3.0.0", 2565 + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", 2566 + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", 2567 + "license": "MIT", 2568 + "engines": { 2569 + "node": ">=10" 2570 + }, 2571 + "funding": { 2572 + "url": "https://github.com/sponsors/sindresorhus" 2573 + } 2574 + }, 2575 + "node_modules/clsx": { 2576 + "version": "2.1.1", 2577 + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", 2578 + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", 2579 + "license": "MIT", 2580 + "engines": { 2581 + "node": ">=6" 2582 + } 2583 + }, 2584 + "node_modules/collapse-white-space": { 2585 + "version": "2.1.0", 2586 + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", 2587 + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", 2588 + "license": "MIT", 2589 + "funding": { 2590 + "type": "github", 2591 + "url": "https://github.com/sponsors/wooorm" 2592 + } 2593 + }, 2594 + "node_modules/comma-separated-tokens": { 2595 + "version": "2.0.3", 2596 + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", 2597 + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", 2598 + "license": "MIT", 2599 + "funding": { 2600 + "type": "github", 2601 + "url": "https://github.com/sponsors/wooorm" 2602 + } 2603 + }, 2604 + "node_modules/commander": { 2605 + "version": "11.1.0", 2606 + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", 2607 + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", 2608 + "license": "MIT", 2609 + "engines": { 2610 + "node": ">=16" 2611 + } 2612 + }, 2613 + "node_modules/common-ancestor-path": { 2614 + "version": "1.0.1", 2615 + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", 2616 + "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", 2617 + "license": "ISC" 2618 + }, 2619 + "node_modules/cookie": { 2620 + "version": "1.1.1", 2621 + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", 2622 + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", 2623 + "license": "MIT", 2624 + "engines": { 2625 + "node": ">=18" 2626 + }, 2627 + "funding": { 2628 + "type": "opencollective", 2629 + "url": "https://opencollective.com/express" 2630 + } 2631 + }, 2632 + "node_modules/cookie-es": { 2633 + "version": "1.2.3", 2634 + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.3.tgz", 2635 + "integrity": "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==", 2636 + "license": "MIT" 2637 + }, 2638 + "node_modules/crossws": { 2639 + "version": "0.3.5", 2640 + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", 2641 + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", 2642 + "license": "MIT", 2643 + "dependencies": { 2644 + "uncrypto": "^0.1.3" 2645 + } 2646 + }, 2647 + "node_modules/css-select": { 2648 + "version": "5.2.2", 2649 + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", 2650 + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", 2651 + "license": "BSD-2-Clause", 2652 + "dependencies": { 2653 + "boolbase": "^1.0.0", 2654 + "css-what": "^6.1.0", 2655 + "domhandler": "^5.0.2", 2656 + "domutils": "^3.0.1", 2657 + "nth-check": "^2.0.1" 2658 + }, 2659 + "funding": { 2660 + "url": "https://github.com/sponsors/fb55" 2661 + } 2662 + }, 2663 + "node_modules/css-selector-parser": { 2664 + "version": "3.3.0", 2665 + "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.3.0.tgz", 2666 + "integrity": "sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==", 2667 + "funding": [ 2668 + { 2669 + "type": "github", 2670 + "url": "https://github.com/sponsors/mdevils" 2671 + }, 2672 + { 2673 + "type": "patreon", 2674 + "url": "https://patreon.com/mdevils" 2675 + } 2676 + ], 2677 + "license": "MIT" 2678 + }, 2679 + "node_modules/css-tree": { 2680 + "version": "3.2.1", 2681 + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", 2682 + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", 2683 + "license": "MIT", 2684 + "dependencies": { 2685 + "mdn-data": "2.27.1", 2686 + "source-map-js": "^1.2.1" 2687 + }, 2688 + "engines": { 2689 + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" 2690 + } 2691 + }, 2692 + "node_modules/css-what": { 2693 + "version": "6.2.2", 2694 + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", 2695 + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", 2696 + "license": "BSD-2-Clause", 2697 + "engines": { 2698 + "node": ">= 6" 2699 + }, 2700 + "funding": { 2701 + "url": "https://github.com/sponsors/fb55" 2702 + } 2703 + }, 2704 + "node_modules/cssesc": { 2705 + "version": "3.0.0", 2706 + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", 2707 + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", 2708 + "license": "MIT", 2709 + "bin": { 2710 + "cssesc": "bin/cssesc" 2711 + }, 2712 + "engines": { 2713 + "node": ">=4" 2714 + } 2715 + }, 2716 + "node_modules/csso": { 2717 + "version": "5.0.5", 2718 + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", 2719 + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", 2720 + "license": "MIT", 2721 + "dependencies": { 2722 + "css-tree": "~2.2.0" 2723 + }, 2724 + "engines": { 2725 + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", 2726 + "npm": ">=7.0.0" 2727 + } 2728 + }, 2729 + "node_modules/csso/node_modules/css-tree": { 2730 + "version": "2.2.1", 2731 + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", 2732 + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", 2733 + "license": "MIT", 2734 + "dependencies": { 2735 + "mdn-data": "2.0.28", 2736 + "source-map-js": "^1.0.1" 2737 + }, 2738 + "engines": { 2739 + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", 2740 + "npm": ">=7.0.0" 2741 + } 2742 + }, 2743 + "node_modules/csso/node_modules/mdn-data": { 2744 + "version": "2.0.28", 2745 + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", 2746 + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", 2747 + "license": "CC0-1.0" 2748 + }, 2749 + "node_modules/debug": { 2750 + "version": "4.4.3", 2751 + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", 2752 + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", 2753 + "license": "MIT", 2754 + "dependencies": { 2755 + "ms": "^2.1.3" 2756 + }, 2757 + "engines": { 2758 + "node": ">=6.0" 2759 + }, 2760 + "peerDependenciesMeta": { 2761 + "supports-color": { 2762 + "optional": true 2763 + } 2764 + } 2765 + }, 2766 + "node_modules/decode-named-character-reference": { 2767 + "version": "1.3.0", 2768 + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", 2769 + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", 2770 + "license": "MIT", 2771 + "dependencies": { 2772 + "character-entities": "^2.0.0" 2773 + }, 2774 + "funding": { 2775 + "type": "github", 2776 + "url": "https://github.com/sponsors/wooorm" 2777 + } 2778 + }, 2779 + "node_modules/defu": { 2780 + "version": "6.1.7", 2781 + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", 2782 + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", 2783 + "license": "MIT" 2784 + }, 2785 + "node_modules/dequal": { 2786 + "version": "2.0.3", 2787 + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", 2788 + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", 2789 + "license": "MIT", 2790 + "engines": { 2791 + "node": ">=6" 2792 + } 2793 + }, 2794 + "node_modules/destr": { 2795 + "version": "2.0.5", 2796 + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", 2797 + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", 2798 + "license": "MIT" 2799 + }, 2800 + "node_modules/detect-libc": { 2801 + "version": "2.1.2", 2802 + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", 2803 + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", 2804 + "license": "Apache-2.0", 2805 + "engines": { 2806 + "node": ">=8" 2807 + } 2808 + }, 2809 + "node_modules/deterministic-object-hash": { 2810 + "version": "2.0.2", 2811 + "resolved": "https://registry.npmjs.org/deterministic-object-hash/-/deterministic-object-hash-2.0.2.tgz", 2812 + "integrity": "sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==", 2813 + "license": "MIT", 2814 + "dependencies": { 2815 + "base-64": "^1.0.0" 2816 + }, 2817 + "engines": { 2818 + "node": ">=18" 2819 + } 2820 + }, 2821 + "node_modules/devalue": { 2822 + "version": "5.8.1", 2823 + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.8.1.tgz", 2824 + "integrity": "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==", 2825 + "license": "MIT" 2826 + }, 2827 + "node_modules/devlop": { 2828 + "version": "1.1.0", 2829 + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", 2830 + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", 2831 + "license": "MIT", 2832 + "dependencies": { 2833 + "dequal": "^2.0.0" 2834 + }, 2835 + "funding": { 2836 + "type": "github", 2837 + "url": "https://github.com/sponsors/wooorm" 2838 + } 2839 + }, 2840 + "node_modules/didyoumean": { 2841 + "version": "1.2.2", 2842 + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", 2843 + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", 2844 + "dev": true, 2845 + "license": "Apache-2.0" 2846 + }, 2847 + "node_modules/diff": { 2848 + "version": "8.0.4", 2849 + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", 2850 + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", 2851 + "license": "BSD-3-Clause", 2852 + "engines": { 2853 + "node": ">=0.3.1" 2854 + } 2855 + }, 2856 + "node_modules/direction": { 2857 + "version": "2.0.1", 2858 + "resolved": "https://registry.npmjs.org/direction/-/direction-2.0.1.tgz", 2859 + "integrity": "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==", 2860 + "license": "MIT", 2861 + "bin": { 2862 + "direction": "cli.js" 2863 + }, 2864 + "funding": { 2865 + "type": "github", 2866 + "url": "https://github.com/sponsors/wooorm" 2867 + } 2868 + }, 2869 + "node_modules/dlv": { 2870 + "version": "1.1.3", 2871 + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", 2872 + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", 2873 + "license": "MIT" 2874 + }, 2875 + "node_modules/dom-serializer": { 2876 + "version": "2.0.0", 2877 + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", 2878 + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", 2879 + "license": "MIT", 2880 + "dependencies": { 2881 + "domelementtype": "^2.3.0", 2882 + "domhandler": "^5.0.2", 2883 + "entities": "^4.2.0" 2884 + }, 2885 + "funding": { 2886 + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" 2887 + } 2888 + }, 2889 + "node_modules/dom-serializer/node_modules/entities": { 2890 + "version": "4.5.0", 2891 + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", 2892 + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", 2893 + "license": "BSD-2-Clause", 2894 + "engines": { 2895 + "node": ">=0.12" 2896 + }, 2897 + "funding": { 2898 + "url": "https://github.com/fb55/entities?sponsor=1" 2899 + } 2900 + }, 2901 + "node_modules/domelementtype": { 2902 + "version": "2.3.0", 2903 + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", 2904 + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", 2905 + "funding": [ 2906 + { 2907 + "type": "github", 2908 + "url": "https://github.com/sponsors/fb55" 2909 + } 2910 + ], 2911 + "license": "BSD-2-Clause" 2912 + }, 2913 + "node_modules/domhandler": { 2914 + "version": "5.0.3", 2915 + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", 2916 + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", 2917 + "license": "BSD-2-Clause", 2918 + "dependencies": { 2919 + "domelementtype": "^2.3.0" 2920 + }, 2921 + "engines": { 2922 + "node": ">= 4" 2923 + }, 2924 + "funding": { 2925 + "url": "https://github.com/fb55/domhandler?sponsor=1" 2926 + } 2927 + }, 2928 + "node_modules/domutils": { 2929 + "version": "3.2.2", 2930 + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", 2931 + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", 2932 + "license": "BSD-2-Clause", 2933 + "dependencies": { 2934 + "dom-serializer": "^2.0.0", 2935 + "domelementtype": "^2.3.0", 2936 + "domhandler": "^5.0.3" 2937 + }, 2938 + "funding": { 2939 + "url": "https://github.com/fb55/domutils?sponsor=1" 2940 + } 2941 + }, 2942 + "node_modules/dset": { 2943 + "version": "3.1.4", 2944 + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", 2945 + "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==", 2946 + "license": "MIT", 2947 + "engines": { 2948 + "node": ">=4" 2949 + } 2950 + }, 2951 + "node_modules/emoji-regex": { 2952 + "version": "10.6.0", 2953 + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", 2954 + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", 2955 + "license": "MIT" 2956 + }, 2957 + "node_modules/entities": { 2958 + "version": "6.0.1", 2959 + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", 2960 + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", 2961 + "license": "BSD-2-Clause", 2962 + "engines": { 2963 + "node": ">=0.12" 2964 + }, 2965 + "funding": { 2966 + "url": "https://github.com/fb55/entities?sponsor=1" 2967 + } 2968 + }, 2969 + "node_modules/es-errors": { 2970 + "version": "1.3.0", 2971 + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", 2972 + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", 2973 + "dev": true, 2974 + "license": "MIT", 2975 + "engines": { 2976 + "node": ">= 0.4" 2977 + } 2978 + }, 2979 + "node_modules/es-module-lexer": { 2980 + "version": "1.7.0", 2981 + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", 2982 + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", 2983 + "license": "MIT" 2984 + }, 2985 + "node_modules/esast-util-from-estree": { 2986 + "version": "2.0.0", 2987 + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", 2988 + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", 2989 + "license": "MIT", 2990 + "dependencies": { 2991 + "@types/estree-jsx": "^1.0.0", 2992 + "devlop": "^1.0.0", 2993 + "estree-util-visit": "^2.0.0", 2994 + "unist-util-position-from-estree": "^2.0.0" 2995 + }, 2996 + "funding": { 2997 + "type": "opencollective", 2998 + "url": "https://opencollective.com/unified" 2999 + } 3000 + }, 3001 + "node_modules/esast-util-from-js": { 3002 + "version": "2.0.1", 3003 + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", 3004 + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", 3005 + "license": "MIT", 3006 + "dependencies": { 3007 + "@types/estree-jsx": "^1.0.0", 3008 + "acorn": "^8.0.0", 3009 + "esast-util-from-estree": "^2.0.0", 3010 + "vfile-message": "^4.0.0" 3011 + }, 3012 + "funding": { 3013 + "type": "opencollective", 3014 + "url": "https://opencollective.com/unified" 3015 + } 3016 + }, 3017 + "node_modules/esbuild": { 3018 + "version": "0.27.7", 3019 + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", 3020 + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", 3021 + "hasInstallScript": true, 3022 + "license": "MIT", 3023 + "bin": { 3024 + "esbuild": "bin/esbuild" 3025 + }, 3026 + "engines": { 3027 + "node": ">=18" 3028 + }, 3029 + "optionalDependencies": { 3030 + "@esbuild/aix-ppc64": "0.27.7", 3031 + "@esbuild/android-arm": "0.27.7", 3032 + "@esbuild/android-arm64": "0.27.7", 3033 + "@esbuild/android-x64": "0.27.7", 3034 + "@esbuild/darwin-arm64": "0.27.7", 3035 + "@esbuild/darwin-x64": "0.27.7", 3036 + "@esbuild/freebsd-arm64": "0.27.7", 3037 + "@esbuild/freebsd-x64": "0.27.7", 3038 + "@esbuild/linux-arm": "0.27.7", 3039 + "@esbuild/linux-arm64": "0.27.7", 3040 + "@esbuild/linux-ia32": "0.27.7", 3041 + "@esbuild/linux-loong64": "0.27.7", 3042 + "@esbuild/linux-mips64el": "0.27.7", 3043 + "@esbuild/linux-ppc64": "0.27.7", 3044 + "@esbuild/linux-riscv64": "0.27.7", 3045 + "@esbuild/linux-s390x": "0.27.7", 3046 + "@esbuild/linux-x64": "0.27.7", 3047 + "@esbuild/netbsd-arm64": "0.27.7", 3048 + "@esbuild/netbsd-x64": "0.27.7", 3049 + "@esbuild/openbsd-arm64": "0.27.7", 3050 + "@esbuild/openbsd-x64": "0.27.7", 3051 + "@esbuild/openharmony-arm64": "0.27.7", 3052 + "@esbuild/sunos-x64": "0.27.7", 3053 + "@esbuild/win32-arm64": "0.27.7", 3054 + "@esbuild/win32-ia32": "0.27.7", 3055 + "@esbuild/win32-x64": "0.27.7" 3056 + } 3057 + }, 3058 + "node_modules/escape-string-regexp": { 3059 + "version": "5.0.0", 3060 + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", 3061 + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", 3062 + "license": "MIT", 3063 + "engines": { 3064 + "node": ">=12" 3065 + }, 3066 + "funding": { 3067 + "url": "https://github.com/sponsors/sindresorhus" 3068 + } 3069 + }, 3070 + "node_modules/estree-util-attach-comments": { 3071 + "version": "3.0.0", 3072 + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", 3073 + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", 3074 + "license": "MIT", 3075 + "dependencies": { 3076 + "@types/estree": "^1.0.0" 3077 + }, 3078 + "funding": { 3079 + "type": "opencollective", 3080 + "url": "https://opencollective.com/unified" 3081 + } 3082 + }, 3083 + "node_modules/estree-util-build-jsx": { 3084 + "version": "3.0.1", 3085 + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", 3086 + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", 3087 + "license": "MIT", 3088 + "dependencies": { 3089 + "@types/estree-jsx": "^1.0.0", 3090 + "devlop": "^1.0.0", 3091 + "estree-util-is-identifier-name": "^3.0.0", 3092 + "estree-walker": "^3.0.0" 3093 + }, 3094 + "funding": { 3095 + "type": "opencollective", 3096 + "url": "https://opencollective.com/unified" 3097 + } 3098 + }, 3099 + "node_modules/estree-util-is-identifier-name": { 3100 + "version": "3.0.0", 3101 + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", 3102 + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", 3103 + "license": "MIT", 3104 + "funding": { 3105 + "type": "opencollective", 3106 + "url": "https://opencollective.com/unified" 3107 + } 3108 + }, 3109 + "node_modules/estree-util-scope": { 3110 + "version": "1.0.0", 3111 + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", 3112 + "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", 3113 + "license": "MIT", 3114 + "dependencies": { 3115 + "@types/estree": "^1.0.0", 3116 + "devlop": "^1.0.0" 3117 + }, 3118 + "funding": { 3119 + "type": "opencollective", 3120 + "url": "https://opencollective.com/unified" 3121 + } 3122 + }, 3123 + "node_modules/estree-util-to-js": { 3124 + "version": "2.0.0", 3125 + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", 3126 + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", 3127 + "license": "MIT", 3128 + "dependencies": { 3129 + "@types/estree-jsx": "^1.0.0", 3130 + "astring": "^1.8.0", 3131 + "source-map": "^0.7.0" 3132 + }, 3133 + "funding": { 3134 + "type": "opencollective", 3135 + "url": "https://opencollective.com/unified" 3136 + } 3137 + }, 3138 + "node_modules/estree-util-visit": { 3139 + "version": "2.0.0", 3140 + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", 3141 + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", 3142 + "license": "MIT", 3143 + "dependencies": { 3144 + "@types/estree-jsx": "^1.0.0", 3145 + "@types/unist": "^3.0.0" 3146 + }, 3147 + "funding": { 3148 + "type": "opencollective", 3149 + "url": "https://opencollective.com/unified" 3150 + } 3151 + }, 3152 + "node_modules/estree-walker": { 3153 + "version": "3.0.3", 3154 + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", 3155 + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", 3156 + "license": "MIT", 3157 + "dependencies": { 3158 + "@types/estree": "^1.0.0" 3159 + } 3160 + }, 3161 + "node_modules/eventemitter3": { 3162 + "version": "5.0.4", 3163 + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", 3164 + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", 3165 + "license": "MIT" 3166 + }, 3167 + "node_modules/expressive-code": { 3168 + "version": "0.41.7", 3169 + "resolved": "https://registry.npmjs.org/expressive-code/-/expressive-code-0.41.7.tgz", 3170 + "integrity": "sha512-2wZjC8OQ3TaVEMcBtYY4Va3lo6J+Ai9jf3d4dbhURMJcU4Pbqe6EcHe424MIZI0VHUA1bR6xdpoHYi3yxokWqA==", 3171 + "license": "MIT", 3172 + "dependencies": { 3173 + "@expressive-code/core": "^0.41.7", 3174 + "@expressive-code/plugin-frames": "^0.41.7", 3175 + "@expressive-code/plugin-shiki": "^0.41.7", 3176 + "@expressive-code/plugin-text-markers": "^0.41.7" 3177 + } 3178 + }, 3179 + "node_modules/extend": { 3180 + "version": "3.0.2", 3181 + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 3182 + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", 3183 + "license": "MIT" 3184 + }, 3185 + "node_modules/fast-glob": { 3186 + "version": "3.3.3", 3187 + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", 3188 + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", 3189 + "dev": true, 3190 + "license": "MIT", 3191 + "dependencies": { 3192 + "@nodelib/fs.stat": "^2.0.2", 3193 + "@nodelib/fs.walk": "^1.2.3", 3194 + "glob-parent": "^5.1.2", 3195 + "merge2": "^1.3.0", 3196 + "micromatch": "^4.0.8" 3197 + }, 3198 + "engines": { 3199 + "node": ">=8.6.0" 3200 + } 3201 + }, 3202 + "node_modules/fast-glob/node_modules/glob-parent": { 3203 + "version": "5.1.2", 3204 + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 3205 + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 3206 + "dev": true, 3207 + "license": "ISC", 3208 + "dependencies": { 3209 + "is-glob": "^4.0.1" 3210 + }, 3211 + "engines": { 3212 + "node": ">= 6" 3213 + } 3214 + }, 3215 + "node_modules/fastq": { 3216 + "version": "1.20.1", 3217 + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", 3218 + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", 3219 + "dev": true, 3220 + "license": "ISC", 3221 + "dependencies": { 3222 + "reusify": "^1.0.4" 3223 + } 3224 + }, 3225 + "node_modules/fdir": { 3226 + "version": "6.5.0", 3227 + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", 3228 + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", 3229 + "license": "MIT", 3230 + "engines": { 3231 + "node": ">=12.0.0" 3232 + }, 3233 + "peerDependencies": { 3234 + "picomatch": "^3 || ^4" 3235 + }, 3236 + "peerDependenciesMeta": { 3237 + "picomatch": { 3238 + "optional": true 3239 + } 3240 + } 3241 + }, 3242 + "node_modules/fill-range": { 3243 + "version": "7.1.1", 3244 + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 3245 + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 3246 + "dev": true, 3247 + "license": "MIT", 3248 + "dependencies": { 3249 + "to-regex-range": "^5.0.1" 3250 + }, 3251 + "engines": { 3252 + "node": ">=8" 3253 + } 3254 + }, 3255 + "node_modules/flattie": { 3256 + "version": "1.1.1", 3257 + "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", 3258 + "integrity": "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==", 3259 + "license": "MIT", 3260 + "engines": { 3261 + "node": ">=8" 3262 + } 3263 + }, 3264 + "node_modules/fontace": { 3265 + "version": "0.4.1", 3266 + "resolved": "https://registry.npmjs.org/fontace/-/fontace-0.4.1.tgz", 3267 + "integrity": "sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==", 3268 + "license": "MIT", 3269 + "dependencies": { 3270 + "fontkitten": "^1.0.2" 3271 + } 3272 + }, 3273 + "node_modules/fontkitten": { 3274 + "version": "1.0.3", 3275 + "resolved": "https://registry.npmjs.org/fontkitten/-/fontkitten-1.0.3.tgz", 3276 + "integrity": "sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==", 3277 + "license": "MIT", 3278 + "dependencies": { 3279 + "tiny-inflate": "^1.0.3" 3280 + }, 3281 + "engines": { 3282 + "node": ">=20" 3283 + } 3284 + }, 3285 + "node_modules/fsevents": { 3286 + "version": "2.3.3", 3287 + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 3288 + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 3289 + "hasInstallScript": true, 3290 + "license": "MIT", 3291 + "optional": true, 3292 + "os": [ 3293 + "darwin" 3294 + ], 3295 + "engines": { 3296 + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 3297 + } 3298 + }, 3299 + "node_modules/function-bind": { 3300 + "version": "1.1.2", 3301 + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 3302 + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 3303 + "dev": true, 3304 + "license": "MIT", 3305 + "funding": { 3306 + "url": "https://github.com/sponsors/ljharb" 3307 + } 3308 + }, 3309 + "node_modules/get-east-asian-width": { 3310 + "version": "1.6.0", 3311 + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", 3312 + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", 3313 + "license": "MIT", 3314 + "engines": { 3315 + "node": ">=18" 3316 + }, 3317 + "funding": { 3318 + "url": "https://github.com/sponsors/sindresorhus" 3319 + } 3320 + }, 3321 + "node_modules/github-slugger": { 3322 + "version": "2.0.0", 3323 + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", 3324 + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", 3325 + "license": "ISC" 3326 + }, 3327 + "node_modules/glob-parent": { 3328 + "version": "6.0.2", 3329 + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", 3330 + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 3331 + "dev": true, 3332 + "license": "ISC", 3333 + "dependencies": { 3334 + "is-glob": "^4.0.3" 3335 + }, 3336 + "engines": { 3337 + "node": ">=10.13.0" 3338 + } 3339 + }, 3340 + "node_modules/h3": { 3341 + "version": "1.15.11", 3342 + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz", 3343 + "integrity": "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==", 3344 + "license": "MIT", 3345 + "dependencies": { 3346 + "cookie-es": "^1.2.3", 3347 + "crossws": "^0.3.5", 3348 + "defu": "^6.1.6", 3349 + "destr": "^2.0.5", 3350 + "iron-webcrypto": "^1.2.1", 3351 + "node-mock-http": "^1.0.4", 3352 + "radix3": "^1.1.2", 3353 + "ufo": "^1.6.3", 3354 + "uncrypto": "^0.1.3" 3355 + } 3356 + }, 3357 + "node_modules/hasown": { 3358 + "version": "2.0.4", 3359 + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", 3360 + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", 3361 + "dev": true, 3362 + "license": "MIT", 3363 + "dependencies": { 3364 + "function-bind": "^1.1.2" 3365 + }, 3366 + "engines": { 3367 + "node": ">= 0.4" 3368 + } 3369 + }, 3370 + "node_modules/hast-util-embedded": { 3371 + "version": "3.0.0", 3372 + "resolved": "https://registry.npmjs.org/hast-util-embedded/-/hast-util-embedded-3.0.0.tgz", 3373 + "integrity": "sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==", 3374 + "license": "MIT", 3375 + "dependencies": { 3376 + "@types/hast": "^3.0.0", 3377 + "hast-util-is-element": "^3.0.0" 3378 + }, 3379 + "funding": { 3380 + "type": "opencollective", 3381 + "url": "https://opencollective.com/unified" 3382 + } 3383 + }, 3384 + "node_modules/hast-util-format": { 3385 + "version": "1.1.0", 3386 + "resolved": "https://registry.npmjs.org/hast-util-format/-/hast-util-format-1.1.0.tgz", 3387 + "integrity": "sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==", 3388 + "license": "MIT", 3389 + "dependencies": { 3390 + "@types/hast": "^3.0.0", 3391 + "hast-util-embedded": "^3.0.0", 3392 + "hast-util-minify-whitespace": "^1.0.0", 3393 + "hast-util-phrasing": "^3.0.0", 3394 + "hast-util-whitespace": "^3.0.0", 3395 + "html-whitespace-sensitive-tag-names": "^3.0.0", 3396 + "unist-util-visit-parents": "^6.0.0" 3397 + }, 3398 + "funding": { 3399 + "type": "opencollective", 3400 + "url": "https://opencollective.com/unified" 3401 + } 3402 + }, 3403 + "node_modules/hast-util-from-html": { 3404 + "version": "2.0.3", 3405 + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", 3406 + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", 3407 + "license": "MIT", 3408 + "dependencies": { 3409 + "@types/hast": "^3.0.0", 3410 + "devlop": "^1.1.0", 3411 + "hast-util-from-parse5": "^8.0.0", 3412 + "parse5": "^7.0.0", 3413 + "vfile": "^6.0.0", 3414 + "vfile-message": "^4.0.0" 3415 + }, 3416 + "funding": { 3417 + "type": "opencollective", 3418 + "url": "https://opencollective.com/unified" 3419 + } 3420 + }, 3421 + "node_modules/hast-util-from-parse5": { 3422 + "version": "8.0.3", 3423 + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", 3424 + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", 3425 + "license": "MIT", 3426 + "dependencies": { 3427 + "@types/hast": "^3.0.0", 3428 + "@types/unist": "^3.0.0", 3429 + "devlop": "^1.0.0", 3430 + "hastscript": "^9.0.0", 3431 + "property-information": "^7.0.0", 3432 + "vfile": "^6.0.0", 3433 + "vfile-location": "^5.0.0", 3434 + "web-namespaces": "^2.0.0" 3435 + }, 3436 + "funding": { 3437 + "type": "opencollective", 3438 + "url": "https://opencollective.com/unified" 3439 + } 3440 + }, 3441 + "node_modules/hast-util-has-property": { 3442 + "version": "3.0.0", 3443 + "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-3.0.0.tgz", 3444 + "integrity": "sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==", 3445 + "license": "MIT", 3446 + "dependencies": { 3447 + "@types/hast": "^3.0.0" 3448 + }, 3449 + "funding": { 3450 + "type": "opencollective", 3451 + "url": "https://opencollective.com/unified" 3452 + } 3453 + }, 3454 + "node_modules/hast-util-is-body-ok-link": { 3455 + "version": "3.0.1", 3456 + "resolved": "https://registry.npmjs.org/hast-util-is-body-ok-link/-/hast-util-is-body-ok-link-3.0.1.tgz", 3457 + "integrity": "sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==", 3458 + "license": "MIT", 3459 + "dependencies": { 3460 + "@types/hast": "^3.0.0" 3461 + }, 3462 + "funding": { 3463 + "type": "opencollective", 3464 + "url": "https://opencollective.com/unified" 3465 + } 3466 + }, 3467 + "node_modules/hast-util-is-element": { 3468 + "version": "3.0.0", 3469 + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", 3470 + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", 3471 + "license": "MIT", 3472 + "dependencies": { 3473 + "@types/hast": "^3.0.0" 3474 + }, 3475 + "funding": { 3476 + "type": "opencollective", 3477 + "url": "https://opencollective.com/unified" 3478 + } 3479 + }, 3480 + "node_modules/hast-util-minify-whitespace": { 3481 + "version": "1.0.1", 3482 + "resolved": "https://registry.npmjs.org/hast-util-minify-whitespace/-/hast-util-minify-whitespace-1.0.1.tgz", 3483 + "integrity": "sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==", 3484 + "license": "MIT", 3485 + "dependencies": { 3486 + "@types/hast": "^3.0.0", 3487 + "hast-util-embedded": "^3.0.0", 3488 + "hast-util-is-element": "^3.0.0", 3489 + "hast-util-whitespace": "^3.0.0", 3490 + "unist-util-is": "^6.0.0" 3491 + }, 3492 + "funding": { 3493 + "type": "opencollective", 3494 + "url": "https://opencollective.com/unified" 3495 + } 3496 + }, 3497 + "node_modules/hast-util-parse-selector": { 3498 + "version": "4.0.0", 3499 + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", 3500 + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", 3501 + "license": "MIT", 3502 + "dependencies": { 3503 + "@types/hast": "^3.0.0" 3504 + }, 3505 + "funding": { 3506 + "type": "opencollective", 3507 + "url": "https://opencollective.com/unified" 3508 + } 3509 + }, 3510 + "node_modules/hast-util-phrasing": { 3511 + "version": "3.0.1", 3512 + "resolved": "https://registry.npmjs.org/hast-util-phrasing/-/hast-util-phrasing-3.0.1.tgz", 3513 + "integrity": "sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==", 3514 + "license": "MIT", 3515 + "dependencies": { 3516 + "@types/hast": "^3.0.0", 3517 + "hast-util-embedded": "^3.0.0", 3518 + "hast-util-has-property": "^3.0.0", 3519 + "hast-util-is-body-ok-link": "^3.0.0", 3520 + "hast-util-is-element": "^3.0.0" 3521 + }, 3522 + "funding": { 3523 + "type": "opencollective", 3524 + "url": "https://opencollective.com/unified" 3525 + } 3526 + }, 3527 + "node_modules/hast-util-raw": { 3528 + "version": "9.1.0", 3529 + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", 3530 + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", 3531 + "license": "MIT", 3532 + "dependencies": { 3533 + "@types/hast": "^3.0.0", 3534 + "@types/unist": "^3.0.0", 3535 + "@ungap/structured-clone": "^1.0.0", 3536 + "hast-util-from-parse5": "^8.0.0", 3537 + "hast-util-to-parse5": "^8.0.0", 3538 + "html-void-elements": "^3.0.0", 3539 + "mdast-util-to-hast": "^13.0.0", 3540 + "parse5": "^7.0.0", 3541 + "unist-util-position": "^5.0.0", 3542 + "unist-util-visit": "^5.0.0", 3543 + "vfile": "^6.0.0", 3544 + "web-namespaces": "^2.0.0", 3545 + "zwitch": "^2.0.0" 3546 + }, 3547 + "funding": { 3548 + "type": "opencollective", 3549 + "url": "https://opencollective.com/unified" 3550 + } 3551 + }, 3552 + "node_modules/hast-util-select": { 3553 + "version": "6.0.4", 3554 + "resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-6.0.4.tgz", 3555 + "integrity": "sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==", 3556 + "license": "MIT", 3557 + "dependencies": { 3558 + "@types/hast": "^3.0.0", 3559 + "@types/unist": "^3.0.0", 3560 + "bcp-47-match": "^2.0.0", 3561 + "comma-separated-tokens": "^2.0.0", 3562 + "css-selector-parser": "^3.0.0", 3563 + "devlop": "^1.0.0", 3564 + "direction": "^2.0.0", 3565 + "hast-util-has-property": "^3.0.0", 3566 + "hast-util-to-string": "^3.0.0", 3567 + "hast-util-whitespace": "^3.0.0", 3568 + "nth-check": "^2.0.0", 3569 + "property-information": "^7.0.0", 3570 + "space-separated-tokens": "^2.0.0", 3571 + "unist-util-visit": "^5.0.0", 3572 + "zwitch": "^2.0.0" 3573 + }, 3574 + "funding": { 3575 + "type": "opencollective", 3576 + "url": "https://opencollective.com/unified" 3577 + } 3578 + }, 3579 + "node_modules/hast-util-to-estree": { 3580 + "version": "3.1.3", 3581 + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", 3582 + "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", 3583 + "license": "MIT", 3584 + "dependencies": { 3585 + "@types/estree": "^1.0.0", 3586 + "@types/estree-jsx": "^1.0.0", 3587 + "@types/hast": "^3.0.0", 3588 + "comma-separated-tokens": "^2.0.0", 3589 + "devlop": "^1.0.0", 3590 + "estree-util-attach-comments": "^3.0.0", 3591 + "estree-util-is-identifier-name": "^3.0.0", 3592 + "hast-util-whitespace": "^3.0.0", 3593 + "mdast-util-mdx-expression": "^2.0.0", 3594 + "mdast-util-mdx-jsx": "^3.0.0", 3595 + "mdast-util-mdxjs-esm": "^2.0.0", 3596 + "property-information": "^7.0.0", 3597 + "space-separated-tokens": "^2.0.0", 3598 + "style-to-js": "^1.0.0", 3599 + "unist-util-position": "^5.0.0", 3600 + "zwitch": "^2.0.0" 3601 + }, 3602 + "funding": { 3603 + "type": "opencollective", 3604 + "url": "https://opencollective.com/unified" 3605 + } 3606 + }, 3607 + "node_modules/hast-util-to-html": { 3608 + "version": "9.0.5", 3609 + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", 3610 + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", 3611 + "license": "MIT", 3612 + "dependencies": { 3613 + "@types/hast": "^3.0.0", 3614 + "@types/unist": "^3.0.0", 3615 + "ccount": "^2.0.0", 3616 + "comma-separated-tokens": "^2.0.0", 3617 + "hast-util-whitespace": "^3.0.0", 3618 + "html-void-elements": "^3.0.0", 3619 + "mdast-util-to-hast": "^13.0.0", 3620 + "property-information": "^7.0.0", 3621 + "space-separated-tokens": "^2.0.0", 3622 + "stringify-entities": "^4.0.0", 3623 + "zwitch": "^2.0.4" 3624 + }, 3625 + "funding": { 3626 + "type": "opencollective", 3627 + "url": "https://opencollective.com/unified" 3628 + } 3629 + }, 3630 + "node_modules/hast-util-to-jsx-runtime": { 3631 + "version": "2.3.6", 3632 + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", 3633 + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", 3634 + "license": "MIT", 3635 + "dependencies": { 3636 + "@types/estree": "^1.0.0", 3637 + "@types/hast": "^3.0.0", 3638 + "@types/unist": "^3.0.0", 3639 + "comma-separated-tokens": "^2.0.0", 3640 + "devlop": "^1.0.0", 3641 + "estree-util-is-identifier-name": "^3.0.0", 3642 + "hast-util-whitespace": "^3.0.0", 3643 + "mdast-util-mdx-expression": "^2.0.0", 3644 + "mdast-util-mdx-jsx": "^3.0.0", 3645 + "mdast-util-mdxjs-esm": "^2.0.0", 3646 + "property-information": "^7.0.0", 3647 + "space-separated-tokens": "^2.0.0", 3648 + "style-to-js": "^1.0.0", 3649 + "unist-util-position": "^5.0.0", 3650 + "vfile-message": "^4.0.0" 3651 + }, 3652 + "funding": { 3653 + "type": "opencollective", 3654 + "url": "https://opencollective.com/unified" 3655 + } 3656 + }, 3657 + "node_modules/hast-util-to-parse5": { 3658 + "version": "8.0.1", 3659 + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz", 3660 + "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==", 3661 + "license": "MIT", 3662 + "dependencies": { 3663 + "@types/hast": "^3.0.0", 3664 + "comma-separated-tokens": "^2.0.0", 3665 + "devlop": "^1.0.0", 3666 + "property-information": "^7.0.0", 3667 + "space-separated-tokens": "^2.0.0", 3668 + "web-namespaces": "^2.0.0", 3669 + "zwitch": "^2.0.0" 3670 + }, 3671 + "funding": { 3672 + "type": "opencollective", 3673 + "url": "https://opencollective.com/unified" 3674 + } 3675 + }, 3676 + "node_modules/hast-util-to-string": { 3677 + "version": "3.0.1", 3678 + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz", 3679 + "integrity": "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==", 3680 + "license": "MIT", 3681 + "dependencies": { 3682 + "@types/hast": "^3.0.0" 3683 + }, 3684 + "funding": { 3685 + "type": "opencollective", 3686 + "url": "https://opencollective.com/unified" 3687 + } 3688 + }, 3689 + "node_modules/hast-util-to-text": { 3690 + "version": "4.0.2", 3691 + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", 3692 + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", 3693 + "license": "MIT", 3694 + "dependencies": { 3695 + "@types/hast": "^3.0.0", 3696 + "@types/unist": "^3.0.0", 3697 + "hast-util-is-element": "^3.0.0", 3698 + "unist-util-find-after": "^5.0.0" 3699 + }, 3700 + "funding": { 3701 + "type": "opencollective", 3702 + "url": "https://opencollective.com/unified" 3703 + } 3704 + }, 3705 + "node_modules/hast-util-whitespace": { 3706 + "version": "3.0.0", 3707 + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", 3708 + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", 3709 + "license": "MIT", 3710 + "dependencies": { 3711 + "@types/hast": "^3.0.0" 3712 + }, 3713 + "funding": { 3714 + "type": "opencollective", 3715 + "url": "https://opencollective.com/unified" 3716 + } 3717 + }, 3718 + "node_modules/hastscript": { 3719 + "version": "9.0.1", 3720 + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", 3721 + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", 3722 + "license": "MIT", 3723 + "dependencies": { 3724 + "@types/hast": "^3.0.0", 3725 + "comma-separated-tokens": "^2.0.0", 3726 + "hast-util-parse-selector": "^4.0.0", 3727 + "property-information": "^7.0.0", 3728 + "space-separated-tokens": "^2.0.0" 3729 + }, 3730 + "funding": { 3731 + "type": "opencollective", 3732 + "url": "https://opencollective.com/unified" 3733 + } 3734 + }, 3735 + "node_modules/html-escaper": { 3736 + "version": "3.0.3", 3737 + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", 3738 + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", 3739 + "license": "MIT" 3740 + }, 3741 + "node_modules/html-void-elements": { 3742 + "version": "3.0.0", 3743 + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", 3744 + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", 3745 + "license": "MIT", 3746 + "funding": { 3747 + "type": "github", 3748 + "url": "https://github.com/sponsors/wooorm" 3749 + } 3750 + }, 3751 + "node_modules/html-whitespace-sensitive-tag-names": { 3752 + "version": "3.0.1", 3753 + "resolved": "https://registry.npmjs.org/html-whitespace-sensitive-tag-names/-/html-whitespace-sensitive-tag-names-3.0.1.tgz", 3754 + "integrity": "sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==", 3755 + "license": "MIT", 3756 + "funding": { 3757 + "type": "opencollective", 3758 + "url": "https://opencollective.com/unified" 3759 + } 3760 + }, 3761 + "node_modules/http-cache-semantics": { 3762 + "version": "4.2.0", 3763 + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", 3764 + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", 3765 + "license": "BSD-2-Clause" 3766 + }, 3767 + "node_modules/i18next": { 3768 + "version": "23.16.8", 3769 + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.8.tgz", 3770 + "integrity": "sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg==", 3771 + "funding": [ 3772 + { 3773 + "type": "individual", 3774 + "url": "https://locize.com" 3775 + }, 3776 + { 3777 + "type": "individual", 3778 + "url": "https://locize.com/i18next.html" 3779 + }, 3780 + { 3781 + "type": "individual", 3782 + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" 3783 + } 3784 + ], 3785 + "license": "MIT", 3786 + "dependencies": { 3787 + "@babel/runtime": "^7.23.2" 3788 + } 3789 + }, 3790 + "node_modules/import-meta-resolve": { 3791 + "version": "4.2.0", 3792 + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", 3793 + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", 3794 + "license": "MIT", 3795 + "funding": { 3796 + "type": "github", 3797 + "url": "https://github.com/sponsors/wooorm" 3798 + } 3799 + }, 3800 + "node_modules/inline-style-parser": { 3801 + "version": "0.2.7", 3802 + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", 3803 + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", 3804 + "license": "MIT" 3805 + }, 3806 + "node_modules/iron-webcrypto": { 3807 + "version": "1.2.1", 3808 + "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", 3809 + "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==", 3810 + "license": "MIT", 3811 + "funding": { 3812 + "url": "https://github.com/sponsors/brc-dd" 3813 + } 3814 + }, 3815 + "node_modules/is-alphabetical": { 3816 + "version": "2.0.1", 3817 + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", 3818 + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", 3819 + "license": "MIT", 3820 + "funding": { 3821 + "type": "github", 3822 + "url": "https://github.com/sponsors/wooorm" 3823 + } 3824 + }, 3825 + "node_modules/is-alphanumerical": { 3826 + "version": "2.0.1", 3827 + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", 3828 + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", 3829 + "license": "MIT", 3830 + "dependencies": { 3831 + "is-alphabetical": "^2.0.0", 3832 + "is-decimal": "^2.0.0" 3833 + }, 3834 + "funding": { 3835 + "type": "github", 3836 + "url": "https://github.com/sponsors/wooorm" 3837 + } 3838 + }, 3839 + "node_modules/is-binary-path": { 3840 + "version": "2.1.0", 3841 + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 3842 + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 3843 + "dev": true, 3844 + "license": "MIT", 3845 + "dependencies": { 3846 + "binary-extensions": "^2.0.0" 3847 + }, 3848 + "engines": { 3849 + "node": ">=8" 3850 + } 3851 + }, 3852 + "node_modules/is-core-module": { 3853 + "version": "2.16.2", 3854 + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", 3855 + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", 3856 + "dev": true, 3857 + "license": "MIT", 3858 + "dependencies": { 3859 + "hasown": "^2.0.3" 3860 + }, 3861 + "engines": { 3862 + "node": ">= 0.4" 3863 + }, 3864 + "funding": { 3865 + "url": "https://github.com/sponsors/ljharb" 3866 + } 3867 + }, 3868 + "node_modules/is-decimal": { 3869 + "version": "2.0.1", 3870 + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", 3871 + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", 3872 + "license": "MIT", 3873 + "funding": { 3874 + "type": "github", 3875 + "url": "https://github.com/sponsors/wooorm" 3876 + } 3877 + }, 3878 + "node_modules/is-docker": { 3879 + "version": "3.0.0", 3880 + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", 3881 + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", 3882 + "license": "MIT", 3883 + "bin": { 3884 + "is-docker": "cli.js" 3885 + }, 3886 + "engines": { 3887 + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 3888 + }, 3889 + "funding": { 3890 + "url": "https://github.com/sponsors/sindresorhus" 3891 + } 3892 + }, 3893 + "node_modules/is-extglob": { 3894 + "version": "2.1.1", 3895 + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 3896 + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 3897 + "dev": true, 3898 + "license": "MIT", 3899 + "engines": { 3900 + "node": ">=0.10.0" 3901 + } 3902 + }, 3903 + "node_modules/is-fullwidth-code-point": { 3904 + "version": "3.0.0", 3905 + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 3906 + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 3907 + "license": "MIT", 3908 + "engines": { 3909 + "node": ">=8" 3910 + } 3911 + }, 3912 + "node_modules/is-glob": { 3913 + "version": "4.0.3", 3914 + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 3915 + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 3916 + "dev": true, 3917 + "license": "MIT", 3918 + "dependencies": { 3919 + "is-extglob": "^2.1.1" 3920 + }, 3921 + "engines": { 3922 + "node": ">=0.10.0" 3923 + } 3924 + }, 3925 + "node_modules/is-hexadecimal": { 3926 + "version": "2.0.1", 3927 + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", 3928 + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", 3929 + "license": "MIT", 3930 + "funding": { 3931 + "type": "github", 3932 + "url": "https://github.com/sponsors/wooorm" 3933 + } 3934 + }, 3935 + "node_modules/is-inside-container": { 3936 + "version": "1.0.0", 3937 + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", 3938 + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", 3939 + "license": "MIT", 3940 + "dependencies": { 3941 + "is-docker": "^3.0.0" 3942 + }, 3943 + "bin": { 3944 + "is-inside-container": "cli.js" 3945 + }, 3946 + "engines": { 3947 + "node": ">=14.16" 3948 + }, 3949 + "funding": { 3950 + "url": "https://github.com/sponsors/sindresorhus" 3951 + } 3952 + }, 3953 + "node_modules/is-number": { 3954 + "version": "7.0.0", 3955 + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 3956 + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 3957 + "dev": true, 3958 + "license": "MIT", 3959 + "engines": { 3960 + "node": ">=0.12.0" 3961 + } 3962 + }, 3963 + "node_modules/is-plain-obj": { 3964 + "version": "4.1.0", 3965 + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", 3966 + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", 3967 + "license": "MIT", 3968 + "engines": { 3969 + "node": ">=12" 3970 + }, 3971 + "funding": { 3972 + "url": "https://github.com/sponsors/sindresorhus" 3973 + } 3974 + }, 3975 + "node_modules/is-wsl": { 3976 + "version": "3.1.1", 3977 + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", 3978 + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", 3979 + "license": "MIT", 3980 + "dependencies": { 3981 + "is-inside-container": "^1.0.0" 3982 + }, 3983 + "engines": { 3984 + "node": ">=16" 3985 + }, 3986 + "funding": { 3987 + "url": "https://github.com/sponsors/sindresorhus" 3988 + } 3989 + }, 3990 + "node_modules/jiti": { 3991 + "version": "1.21.7", 3992 + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", 3993 + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", 3994 + "devOptional": true, 3995 + "license": "MIT", 3996 + "bin": { 3997 + "jiti": "bin/jiti.js" 3998 + } 3999 + }, 4000 + "node_modules/js-yaml": { 4001 + "version": "4.3.0", 4002 + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", 4003 + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", 4004 + "funding": [ 4005 + { 4006 + "type": "github", 4007 + "url": "https://github.com/sponsors/puzrin" 4008 + }, 4009 + { 4010 + "type": "github", 4011 + "url": "https://github.com/sponsors/nodeca" 4012 + } 4013 + ], 4014 + "license": "MIT", 4015 + "dependencies": { 4016 + "argparse": "^2.0.1" 4017 + }, 4018 + "bin": { 4019 + "js-yaml": "bin/js-yaml.js" 4020 + } 4021 + }, 4022 + "node_modules/kleur": { 4023 + "version": "3.0.3", 4024 + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", 4025 + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", 4026 + "license": "MIT", 4027 + "engines": { 4028 + "node": ">=6" 4029 + } 4030 + }, 4031 + "node_modules/klona": { 4032 + "version": "2.0.6", 4033 + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", 4034 + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", 4035 + "license": "MIT", 4036 + "engines": { 4037 + "node": ">= 8" 4038 + } 4039 + }, 4040 + "node_modules/lilconfig": { 4041 + "version": "3.1.3", 4042 + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", 4043 + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", 4044 + "dev": true, 4045 + "license": "MIT", 4046 + "engines": { 4047 + "node": ">=14" 4048 + }, 4049 + "funding": { 4050 + "url": "https://github.com/sponsors/antonk52" 4051 + } 4052 + }, 4053 + "node_modules/lines-and-columns": { 4054 + "version": "1.2.4", 4055 + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", 4056 + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", 4057 + "dev": true, 4058 + "license": "MIT" 4059 + }, 4060 + "node_modules/longest-streak": { 4061 + "version": "3.1.0", 4062 + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", 4063 + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", 4064 + "license": "MIT", 4065 + "funding": { 4066 + "type": "github", 4067 + "url": "https://github.com/sponsors/wooorm" 4068 + } 4069 + }, 4070 + "node_modules/lru-cache": { 4071 + "version": "11.5.2", 4072 + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", 4073 + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", 4074 + "license": "BlueOak-1.0.0", 4075 + "engines": { 4076 + "node": "20 || >=22" 4077 + } 4078 + }, 4079 + "node_modules/lucide-astro": { 4080 + "version": "0.545.0", 4081 + "resolved": "https://registry.npmjs.org/lucide-astro/-/lucide-astro-0.545.0.tgz", 4082 + "integrity": "sha512-KBSQTlW4e+tT6DvWEWcqxWa2WubWdqhLG7/WQgnAawQ29ZAEUfTqo2At9IW9xlrG1k8qrVwzeGQfeumiMsgI6Q==", 4083 + "deprecated": "Deprecated: Use `@lucide/astro`", 4084 + "license": "MIT", 4085 + "peerDependencies": { 4086 + "astro": ">=2.7.1" 4087 + } 4088 + }, 4089 + "node_modules/magic-string": { 4090 + "version": "0.30.21", 4091 + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", 4092 + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", 4093 + "license": "MIT", 4094 + "dependencies": { 4095 + "@jridgewell/sourcemap-codec": "^1.5.5" 4096 + } 4097 + }, 4098 + "node_modules/magicast": { 4099 + "version": "0.5.3", 4100 + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", 4101 + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", 4102 + "license": "MIT", 4103 + "dependencies": { 4104 + "@babel/parser": "^7.29.3", 4105 + "@babel/types": "^7.29.0", 4106 + "source-map-js": "^1.2.1" 4107 + } 4108 + }, 4109 + "node_modules/markdown-extensions": { 4110 + "version": "2.0.0", 4111 + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", 4112 + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", 4113 + "license": "MIT", 4114 + "engines": { 4115 + "node": ">=16" 4116 + }, 4117 + "funding": { 4118 + "url": "https://github.com/sponsors/sindresorhus" 4119 + } 4120 + }, 4121 + "node_modules/markdown-table": { 4122 + "version": "3.0.4", 4123 + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", 4124 + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", 4125 + "license": "MIT", 4126 + "funding": { 4127 + "type": "github", 4128 + "url": "https://github.com/sponsors/wooorm" 4129 + } 4130 + }, 4131 + "node_modules/mdast-util-definitions": { 4132 + "version": "6.0.0", 4133 + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz", 4134 + "integrity": "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==", 4135 + "license": "MIT", 4136 + "dependencies": { 4137 + "@types/mdast": "^4.0.0", 4138 + "@types/unist": "^3.0.0", 4139 + "unist-util-visit": "^5.0.0" 4140 + }, 4141 + "funding": { 4142 + "type": "opencollective", 4143 + "url": "https://opencollective.com/unified" 4144 + } 4145 + }, 4146 + "node_modules/mdast-util-directive": { 4147 + "version": "3.1.0", 4148 + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.1.0.tgz", 4149 + "integrity": "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==", 4150 + "license": "MIT", 4151 + "dependencies": { 4152 + "@types/mdast": "^4.0.0", 4153 + "@types/unist": "^3.0.0", 4154 + "ccount": "^2.0.0", 4155 + "devlop": "^1.0.0", 4156 + "mdast-util-from-markdown": "^2.0.0", 4157 + "mdast-util-to-markdown": "^2.0.0", 4158 + "parse-entities": "^4.0.0", 4159 + "stringify-entities": "^4.0.0", 4160 + "unist-util-visit-parents": "^6.0.0" 4161 + }, 4162 + "funding": { 4163 + "type": "opencollective", 4164 + "url": "https://opencollective.com/unified" 4165 + } 4166 + }, 4167 + "node_modules/mdast-util-find-and-replace": { 4168 + "version": "3.0.2", 4169 + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", 4170 + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", 4171 + "license": "MIT", 4172 + "dependencies": { 4173 + "@types/mdast": "^4.0.0", 4174 + "escape-string-regexp": "^5.0.0", 4175 + "unist-util-is": "^6.0.0", 4176 + "unist-util-visit-parents": "^6.0.0" 4177 + }, 4178 + "funding": { 4179 + "type": "opencollective", 4180 + "url": "https://opencollective.com/unified" 4181 + } 4182 + }, 4183 + "node_modules/mdast-util-from-markdown": { 4184 + "version": "2.0.3", 4185 + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", 4186 + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", 4187 + "license": "MIT", 4188 + "dependencies": { 4189 + "@types/mdast": "^4.0.0", 4190 + "@types/unist": "^3.0.0", 4191 + "decode-named-character-reference": "^1.0.0", 4192 + "devlop": "^1.0.0", 4193 + "mdast-util-to-string": "^4.0.0", 4194 + "micromark": "^4.0.0", 4195 + "micromark-util-decode-numeric-character-reference": "^2.0.0", 4196 + "micromark-util-decode-string": "^2.0.0", 4197 + "micromark-util-normalize-identifier": "^2.0.0", 4198 + "micromark-util-symbol": "^2.0.0", 4199 + "micromark-util-types": "^2.0.0", 4200 + "unist-util-stringify-position": "^4.0.0" 4201 + }, 4202 + "funding": { 4203 + "type": "opencollective", 4204 + "url": "https://opencollective.com/unified" 4205 + } 4206 + }, 4207 + "node_modules/mdast-util-gfm": { 4208 + "version": "3.1.0", 4209 + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", 4210 + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", 4211 + "license": "MIT", 4212 + "dependencies": { 4213 + "mdast-util-from-markdown": "^2.0.0", 4214 + "mdast-util-gfm-autolink-literal": "^2.0.0", 4215 + "mdast-util-gfm-footnote": "^2.0.0", 4216 + "mdast-util-gfm-strikethrough": "^2.0.0", 4217 + "mdast-util-gfm-table": "^2.0.0", 4218 + "mdast-util-gfm-task-list-item": "^2.0.0", 4219 + "mdast-util-to-markdown": "^2.0.0" 4220 + }, 4221 + "funding": { 4222 + "type": "opencollective", 4223 + "url": "https://opencollective.com/unified" 4224 + } 4225 + }, 4226 + "node_modules/mdast-util-gfm-autolink-literal": { 4227 + "version": "2.0.1", 4228 + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", 4229 + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", 4230 + "license": "MIT", 4231 + "dependencies": { 4232 + "@types/mdast": "^4.0.0", 4233 + "ccount": "^2.0.0", 4234 + "devlop": "^1.0.0", 4235 + "mdast-util-find-and-replace": "^3.0.0", 4236 + "micromark-util-character": "^2.0.0" 4237 + }, 4238 + "funding": { 4239 + "type": "opencollective", 4240 + "url": "https://opencollective.com/unified" 4241 + } 4242 + }, 4243 + "node_modules/mdast-util-gfm-footnote": { 4244 + "version": "2.1.0", 4245 + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", 4246 + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", 4247 + "license": "MIT", 4248 + "dependencies": { 4249 + "@types/mdast": "^4.0.0", 4250 + "devlop": "^1.1.0", 4251 + "mdast-util-from-markdown": "^2.0.0", 4252 + "mdast-util-to-markdown": "^2.0.0", 4253 + "micromark-util-normalize-identifier": "^2.0.0" 4254 + }, 4255 + "funding": { 4256 + "type": "opencollective", 4257 + "url": "https://opencollective.com/unified" 4258 + } 4259 + }, 4260 + "node_modules/mdast-util-gfm-strikethrough": { 4261 + "version": "2.0.0", 4262 + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", 4263 + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", 4264 + "license": "MIT", 4265 + "dependencies": { 4266 + "@types/mdast": "^4.0.0", 4267 + "mdast-util-from-markdown": "^2.0.0", 4268 + "mdast-util-to-markdown": "^2.0.0" 4269 + }, 4270 + "funding": { 4271 + "type": "opencollective", 4272 + "url": "https://opencollective.com/unified" 4273 + } 4274 + }, 4275 + "node_modules/mdast-util-gfm-table": { 4276 + "version": "2.0.0", 4277 + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", 4278 + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", 4279 + "license": "MIT", 4280 + "dependencies": { 4281 + "@types/mdast": "^4.0.0", 4282 + "devlop": "^1.0.0", 4283 + "markdown-table": "^3.0.0", 4284 + "mdast-util-from-markdown": "^2.0.0", 4285 + "mdast-util-to-markdown": "^2.0.0" 4286 + }, 4287 + "funding": { 4288 + "type": "opencollective", 4289 + "url": "https://opencollective.com/unified" 4290 + } 4291 + }, 4292 + "node_modules/mdast-util-gfm-task-list-item": { 4293 + "version": "2.0.0", 4294 + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", 4295 + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", 4296 + "license": "MIT", 4297 + "dependencies": { 4298 + "@types/mdast": "^4.0.0", 4299 + "devlop": "^1.0.0", 4300 + "mdast-util-from-markdown": "^2.0.0", 4301 + "mdast-util-to-markdown": "^2.0.0" 4302 + }, 4303 + "funding": { 4304 + "type": "opencollective", 4305 + "url": "https://opencollective.com/unified" 4306 + } 4307 + }, 4308 + "node_modules/mdast-util-mdx": { 4309 + "version": "3.0.0", 4310 + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", 4311 + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", 4312 + "license": "MIT", 4313 + "dependencies": { 4314 + "mdast-util-from-markdown": "^2.0.0", 4315 + "mdast-util-mdx-expression": "^2.0.0", 4316 + "mdast-util-mdx-jsx": "^3.0.0", 4317 + "mdast-util-mdxjs-esm": "^2.0.0", 4318 + "mdast-util-to-markdown": "^2.0.0" 4319 + }, 4320 + "funding": { 4321 + "type": "opencollective", 4322 + "url": "https://opencollective.com/unified" 4323 + } 4324 + }, 4325 + "node_modules/mdast-util-mdx-expression": { 4326 + "version": "2.0.1", 4327 + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", 4328 + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", 4329 + "license": "MIT", 4330 + "dependencies": { 4331 + "@types/estree-jsx": "^1.0.0", 4332 + "@types/hast": "^3.0.0", 4333 + "@types/mdast": "^4.0.0", 4334 + "devlop": "^1.0.0", 4335 + "mdast-util-from-markdown": "^2.0.0", 4336 + "mdast-util-to-markdown": "^2.0.0" 4337 + }, 4338 + "funding": { 4339 + "type": "opencollective", 4340 + "url": "https://opencollective.com/unified" 4341 + } 4342 + }, 4343 + "node_modules/mdast-util-mdx-jsx": { 4344 + "version": "3.2.0", 4345 + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", 4346 + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", 4347 + "license": "MIT", 4348 + "dependencies": { 4349 + "@types/estree-jsx": "^1.0.0", 4350 + "@types/hast": "^3.0.0", 4351 + "@types/mdast": "^4.0.0", 4352 + "@types/unist": "^3.0.0", 4353 + "ccount": "^2.0.0", 4354 + "devlop": "^1.1.0", 4355 + "mdast-util-from-markdown": "^2.0.0", 4356 + "mdast-util-to-markdown": "^2.0.0", 4357 + "parse-entities": "^4.0.0", 4358 + "stringify-entities": "^4.0.0", 4359 + "unist-util-stringify-position": "^4.0.0", 4360 + "vfile-message": "^4.0.0" 4361 + }, 4362 + "funding": { 4363 + "type": "opencollective", 4364 + "url": "https://opencollective.com/unified" 4365 + } 4366 + }, 4367 + "node_modules/mdast-util-mdxjs-esm": { 4368 + "version": "2.0.1", 4369 + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", 4370 + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", 4371 + "license": "MIT", 4372 + "dependencies": { 4373 + "@types/estree-jsx": "^1.0.0", 4374 + "@types/hast": "^3.0.0", 4375 + "@types/mdast": "^4.0.0", 4376 + "devlop": "^1.0.0", 4377 + "mdast-util-from-markdown": "^2.0.0", 4378 + "mdast-util-to-markdown": "^2.0.0" 4379 + }, 4380 + "funding": { 4381 + "type": "opencollective", 4382 + "url": "https://opencollective.com/unified" 4383 + } 4384 + }, 4385 + "node_modules/mdast-util-phrasing": { 4386 + "version": "4.1.0", 4387 + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", 4388 + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", 4389 + "license": "MIT", 4390 + "dependencies": { 4391 + "@types/mdast": "^4.0.0", 4392 + "unist-util-is": "^6.0.0" 4393 + }, 4394 + "funding": { 4395 + "type": "opencollective", 4396 + "url": "https://opencollective.com/unified" 4397 + } 4398 + }, 4399 + "node_modules/mdast-util-to-hast": { 4400 + "version": "13.2.1", 4401 + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", 4402 + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", 4403 + "license": "MIT", 4404 + "dependencies": { 4405 + "@types/hast": "^3.0.0", 4406 + "@types/mdast": "^4.0.0", 4407 + "@ungap/structured-clone": "^1.0.0", 4408 + "devlop": "^1.0.0", 4409 + "micromark-util-sanitize-uri": "^2.0.0", 4410 + "trim-lines": "^3.0.0", 4411 + "unist-util-position": "^5.0.0", 4412 + "unist-util-visit": "^5.0.0", 4413 + "vfile": "^6.0.0" 4414 + }, 4415 + "funding": { 4416 + "type": "opencollective", 4417 + "url": "https://opencollective.com/unified" 4418 + } 4419 + }, 4420 + "node_modules/mdast-util-to-markdown": { 4421 + "version": "2.1.2", 4422 + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", 4423 + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", 4424 + "license": "MIT", 4425 + "dependencies": { 4426 + "@types/mdast": "^4.0.0", 4427 + "@types/unist": "^3.0.0", 4428 + "longest-streak": "^3.0.0", 4429 + "mdast-util-phrasing": "^4.0.0", 4430 + "mdast-util-to-string": "^4.0.0", 4431 + "micromark-util-classify-character": "^2.0.0", 4432 + "micromark-util-decode-string": "^2.0.0", 4433 + "unist-util-visit": "^5.0.0", 4434 + "zwitch": "^2.0.0" 4435 + }, 4436 + "funding": { 4437 + "type": "opencollective", 4438 + "url": "https://opencollective.com/unified" 4439 + } 4440 + }, 4441 + "node_modules/mdast-util-to-string": { 4442 + "version": "4.0.0", 4443 + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", 4444 + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", 4445 + "license": "MIT", 4446 + "dependencies": { 4447 + "@types/mdast": "^4.0.0" 4448 + }, 4449 + "funding": { 4450 + "type": "opencollective", 4451 + "url": "https://opencollective.com/unified" 4452 + } 4453 + }, 4454 + "node_modules/mdn-data": { 4455 + "version": "2.27.1", 4456 + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", 4457 + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", 4458 + "license": "CC0-1.0" 4459 + }, 4460 + "node_modules/merge2": { 4461 + "version": "1.4.1", 4462 + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 4463 + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 4464 + "dev": true, 4465 + "license": "MIT", 4466 + "engines": { 4467 + "node": ">= 8" 4468 + } 4469 + }, 4470 + "node_modules/micromark": { 4471 + "version": "4.0.2", 4472 + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", 4473 + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", 4474 + "funding": [ 4475 + { 4476 + "type": "GitHub Sponsors", 4477 + "url": "https://github.com/sponsors/unifiedjs" 4478 + }, 4479 + { 4480 + "type": "OpenCollective", 4481 + "url": "https://opencollective.com/unified" 4482 + } 4483 + ], 4484 + "license": "MIT", 4485 + "dependencies": { 4486 + "@types/debug": "^4.0.0", 4487 + "debug": "^4.0.0", 4488 + "decode-named-character-reference": "^1.0.0", 4489 + "devlop": "^1.0.0", 4490 + "micromark-core-commonmark": "^2.0.0", 4491 + "micromark-factory-space": "^2.0.0", 4492 + "micromark-util-character": "^2.0.0", 4493 + "micromark-util-chunked": "^2.0.0", 4494 + "micromark-util-combine-extensions": "^2.0.0", 4495 + "micromark-util-decode-numeric-character-reference": "^2.0.0", 4496 + "micromark-util-encode": "^2.0.0", 4497 + "micromark-util-normalize-identifier": "^2.0.0", 4498 + "micromark-util-resolve-all": "^2.0.0", 4499 + "micromark-util-sanitize-uri": "^2.0.0", 4500 + "micromark-util-subtokenize": "^2.0.0", 4501 + "micromark-util-symbol": "^2.0.0", 4502 + "micromark-util-types": "^2.0.0" 4503 + } 4504 + }, 4505 + "node_modules/micromark-core-commonmark": { 4506 + "version": "2.0.3", 4507 + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", 4508 + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", 4509 + "funding": [ 4510 + { 4511 + "type": "GitHub Sponsors", 4512 + "url": "https://github.com/sponsors/unifiedjs" 4513 + }, 4514 + { 4515 + "type": "OpenCollective", 4516 + "url": "https://opencollective.com/unified" 4517 + } 4518 + ], 4519 + "license": "MIT", 4520 + "dependencies": { 4521 + "decode-named-character-reference": "^1.0.0", 4522 + "devlop": "^1.0.0", 4523 + "micromark-factory-destination": "^2.0.0", 4524 + "micromark-factory-label": "^2.0.0", 4525 + "micromark-factory-space": "^2.0.0", 4526 + "micromark-factory-title": "^2.0.0", 4527 + "micromark-factory-whitespace": "^2.0.0", 4528 + "micromark-util-character": "^2.0.0", 4529 + "micromark-util-chunked": "^2.0.0", 4530 + "micromark-util-classify-character": "^2.0.0", 4531 + "micromark-util-html-tag-name": "^2.0.0", 4532 + "micromark-util-normalize-identifier": "^2.0.0", 4533 + "micromark-util-resolve-all": "^2.0.0", 4534 + "micromark-util-subtokenize": "^2.0.0", 4535 + "micromark-util-symbol": "^2.0.0", 4536 + "micromark-util-types": "^2.0.0" 4537 + } 4538 + }, 4539 + "node_modules/micromark-extension-directive": { 4540 + "version": "3.0.2", 4541 + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.2.tgz", 4542 + "integrity": "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==", 4543 + "license": "MIT", 4544 + "dependencies": { 4545 + "devlop": "^1.0.0", 4546 + "micromark-factory-space": "^2.0.0", 4547 + "micromark-factory-whitespace": "^2.0.0", 4548 + "micromark-util-character": "^2.0.0", 4549 + "micromark-util-symbol": "^2.0.0", 4550 + "micromark-util-types": "^2.0.0", 4551 + "parse-entities": "^4.0.0" 4552 + }, 4553 + "funding": { 4554 + "type": "opencollective", 4555 + "url": "https://opencollective.com/unified" 4556 + } 4557 + }, 4558 + "node_modules/micromark-extension-gfm": { 4559 + "version": "3.0.0", 4560 + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", 4561 + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", 4562 + "license": "MIT", 4563 + "dependencies": { 4564 + "micromark-extension-gfm-autolink-literal": "^2.0.0", 4565 + "micromark-extension-gfm-footnote": "^2.0.0", 4566 + "micromark-extension-gfm-strikethrough": "^2.0.0", 4567 + "micromark-extension-gfm-table": "^2.0.0", 4568 + "micromark-extension-gfm-tagfilter": "^2.0.0", 4569 + "micromark-extension-gfm-task-list-item": "^2.0.0", 4570 + "micromark-util-combine-extensions": "^2.0.0", 4571 + "micromark-util-types": "^2.0.0" 4572 + }, 4573 + "funding": { 4574 + "type": "opencollective", 4575 + "url": "https://opencollective.com/unified" 4576 + } 4577 + }, 4578 + "node_modules/micromark-extension-gfm-autolink-literal": { 4579 + "version": "2.1.0", 4580 + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", 4581 + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", 4582 + "license": "MIT", 4583 + "dependencies": { 4584 + "micromark-util-character": "^2.0.0", 4585 + "micromark-util-sanitize-uri": "^2.0.0", 4586 + "micromark-util-symbol": "^2.0.0", 4587 + "micromark-util-types": "^2.0.0" 4588 + }, 4589 + "funding": { 4590 + "type": "opencollective", 4591 + "url": "https://opencollective.com/unified" 4592 + } 4593 + }, 4594 + "node_modules/micromark-extension-gfm-footnote": { 4595 + "version": "2.1.0", 4596 + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", 4597 + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", 4598 + "license": "MIT", 4599 + "dependencies": { 4600 + "devlop": "^1.0.0", 4601 + "micromark-core-commonmark": "^2.0.0", 4602 + "micromark-factory-space": "^2.0.0", 4603 + "micromark-util-character": "^2.0.0", 4604 + "micromark-util-normalize-identifier": "^2.0.0", 4605 + "micromark-util-sanitize-uri": "^2.0.0", 4606 + "micromark-util-symbol": "^2.0.0", 4607 + "micromark-util-types": "^2.0.0" 4608 + }, 4609 + "funding": { 4610 + "type": "opencollective", 4611 + "url": "https://opencollective.com/unified" 4612 + } 4613 + }, 4614 + "node_modules/micromark-extension-gfm-strikethrough": { 4615 + "version": "2.1.0", 4616 + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", 4617 + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", 4618 + "license": "MIT", 4619 + "dependencies": { 4620 + "devlop": "^1.0.0", 4621 + "micromark-util-chunked": "^2.0.0", 4622 + "micromark-util-classify-character": "^2.0.0", 4623 + "micromark-util-resolve-all": "^2.0.0", 4624 + "micromark-util-symbol": "^2.0.0", 4625 + "micromark-util-types": "^2.0.0" 4626 + }, 4627 + "funding": { 4628 + "type": "opencollective", 4629 + "url": "https://opencollective.com/unified" 4630 + } 4631 + }, 4632 + "node_modules/micromark-extension-gfm-table": { 4633 + "version": "2.1.1", 4634 + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", 4635 + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", 4636 + "license": "MIT", 4637 + "dependencies": { 4638 + "devlop": "^1.0.0", 4639 + "micromark-factory-space": "^2.0.0", 4640 + "micromark-util-character": "^2.0.0", 4641 + "micromark-util-symbol": "^2.0.0", 4642 + "micromark-util-types": "^2.0.0" 4643 + }, 4644 + "funding": { 4645 + "type": "opencollective", 4646 + "url": "https://opencollective.com/unified" 4647 + } 4648 + }, 4649 + "node_modules/micromark-extension-gfm-tagfilter": { 4650 + "version": "2.0.0", 4651 + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", 4652 + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", 4653 + "license": "MIT", 4654 + "dependencies": { 4655 + "micromark-util-types": "^2.0.0" 4656 + }, 4657 + "funding": { 4658 + "type": "opencollective", 4659 + "url": "https://opencollective.com/unified" 4660 + } 4661 + }, 4662 + "node_modules/micromark-extension-gfm-task-list-item": { 4663 + "version": "2.1.0", 4664 + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", 4665 + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", 4666 + "license": "MIT", 4667 + "dependencies": { 4668 + "devlop": "^1.0.0", 4669 + "micromark-factory-space": "^2.0.0", 4670 + "micromark-util-character": "^2.0.0", 4671 + "micromark-util-symbol": "^2.0.0", 4672 + "micromark-util-types": "^2.0.0" 4673 + }, 4674 + "funding": { 4675 + "type": "opencollective", 4676 + "url": "https://opencollective.com/unified" 4677 + } 4678 + }, 4679 + "node_modules/micromark-extension-mdx-expression": { 4680 + "version": "3.0.1", 4681 + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", 4682 + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", 4683 + "funding": [ 4684 + { 4685 + "type": "GitHub Sponsors", 4686 + "url": "https://github.com/sponsors/unifiedjs" 4687 + }, 4688 + { 4689 + "type": "OpenCollective", 4690 + "url": "https://opencollective.com/unified" 4691 + } 4692 + ], 4693 + "license": "MIT", 4694 + "dependencies": { 4695 + "@types/estree": "^1.0.0", 4696 + "devlop": "^1.0.0", 4697 + "micromark-factory-mdx-expression": "^2.0.0", 4698 + "micromark-factory-space": "^2.0.0", 4699 + "micromark-util-character": "^2.0.0", 4700 + "micromark-util-events-to-acorn": "^2.0.0", 4701 + "micromark-util-symbol": "^2.0.0", 4702 + "micromark-util-types": "^2.0.0" 4703 + } 4704 + }, 4705 + "node_modules/micromark-extension-mdx-jsx": { 4706 + "version": "3.0.2", 4707 + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", 4708 + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", 4709 + "license": "MIT", 4710 + "dependencies": { 4711 + "@types/estree": "^1.0.0", 4712 + "devlop": "^1.0.0", 4713 + "estree-util-is-identifier-name": "^3.0.0", 4714 + "micromark-factory-mdx-expression": "^2.0.0", 4715 + "micromark-factory-space": "^2.0.0", 4716 + "micromark-util-character": "^2.0.0", 4717 + "micromark-util-events-to-acorn": "^2.0.0", 4718 + "micromark-util-symbol": "^2.0.0", 4719 + "micromark-util-types": "^2.0.0", 4720 + "vfile-message": "^4.0.0" 4721 + }, 4722 + "funding": { 4723 + "type": "opencollective", 4724 + "url": "https://opencollective.com/unified" 4725 + } 4726 + }, 4727 + "node_modules/micromark-extension-mdx-md": { 4728 + "version": "2.0.0", 4729 + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", 4730 + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", 4731 + "license": "MIT", 4732 + "dependencies": { 4733 + "micromark-util-types": "^2.0.0" 4734 + }, 4735 + "funding": { 4736 + "type": "opencollective", 4737 + "url": "https://opencollective.com/unified" 4738 + } 4739 + }, 4740 + "node_modules/micromark-extension-mdxjs": { 4741 + "version": "3.0.0", 4742 + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", 4743 + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", 4744 + "license": "MIT", 4745 + "dependencies": { 4746 + "acorn": "^8.0.0", 4747 + "acorn-jsx": "^5.0.0", 4748 + "micromark-extension-mdx-expression": "^3.0.0", 4749 + "micromark-extension-mdx-jsx": "^3.0.0", 4750 + "micromark-extension-mdx-md": "^2.0.0", 4751 + "micromark-extension-mdxjs-esm": "^3.0.0", 4752 + "micromark-util-combine-extensions": "^2.0.0", 4753 + "micromark-util-types": "^2.0.0" 4754 + }, 4755 + "funding": { 4756 + "type": "opencollective", 4757 + "url": "https://opencollective.com/unified" 4758 + } 4759 + }, 4760 + "node_modules/micromark-extension-mdxjs-esm": { 4761 + "version": "3.0.0", 4762 + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", 4763 + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", 4764 + "license": "MIT", 4765 + "dependencies": { 4766 + "@types/estree": "^1.0.0", 4767 + "devlop": "^1.0.0", 4768 + "micromark-core-commonmark": "^2.0.0", 4769 + "micromark-util-character": "^2.0.0", 4770 + "micromark-util-events-to-acorn": "^2.0.0", 4771 + "micromark-util-symbol": "^2.0.0", 4772 + "micromark-util-types": "^2.0.0", 4773 + "unist-util-position-from-estree": "^2.0.0", 4774 + "vfile-message": "^4.0.0" 4775 + }, 4776 + "funding": { 4777 + "type": "opencollective", 4778 + "url": "https://opencollective.com/unified" 4779 + } 4780 + }, 4781 + "node_modules/micromark-factory-destination": { 4782 + "version": "2.0.1", 4783 + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", 4784 + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", 4785 + "funding": [ 4786 + { 4787 + "type": "GitHub Sponsors", 4788 + "url": "https://github.com/sponsors/unifiedjs" 4789 + }, 4790 + { 4791 + "type": "OpenCollective", 4792 + "url": "https://opencollective.com/unified" 4793 + } 4794 + ], 4795 + "license": "MIT", 4796 + "dependencies": { 4797 + "micromark-util-character": "^2.0.0", 4798 + "micromark-util-symbol": "^2.0.0", 4799 + "micromark-util-types": "^2.0.0" 4800 + } 4801 + }, 4802 + "node_modules/micromark-factory-label": { 4803 + "version": "2.0.1", 4804 + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", 4805 + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", 4806 + "funding": [ 4807 + { 4808 + "type": "GitHub Sponsors", 4809 + "url": "https://github.com/sponsors/unifiedjs" 4810 + }, 4811 + { 4812 + "type": "OpenCollective", 4813 + "url": "https://opencollective.com/unified" 4814 + } 4815 + ], 4816 + "license": "MIT", 4817 + "dependencies": { 4818 + "devlop": "^1.0.0", 4819 + "micromark-util-character": "^2.0.0", 4820 + "micromark-util-symbol": "^2.0.0", 4821 + "micromark-util-types": "^2.0.0" 4822 + } 4823 + }, 4824 + "node_modules/micromark-factory-mdx-expression": { 4825 + "version": "2.0.3", 4826 + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", 4827 + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", 4828 + "funding": [ 4829 + { 4830 + "type": "GitHub Sponsors", 4831 + "url": "https://github.com/sponsors/unifiedjs" 4832 + }, 4833 + { 4834 + "type": "OpenCollective", 4835 + "url": "https://opencollective.com/unified" 4836 + } 4837 + ], 4838 + "license": "MIT", 4839 + "dependencies": { 4840 + "@types/estree": "^1.0.0", 4841 + "devlop": "^1.0.0", 4842 + "micromark-factory-space": "^2.0.0", 4843 + "micromark-util-character": "^2.0.0", 4844 + "micromark-util-events-to-acorn": "^2.0.0", 4845 + "micromark-util-symbol": "^2.0.0", 4846 + "micromark-util-types": "^2.0.0", 4847 + "unist-util-position-from-estree": "^2.0.0", 4848 + "vfile-message": "^4.0.0" 4849 + } 4850 + }, 4851 + "node_modules/micromark-factory-space": { 4852 + "version": "2.0.1", 4853 + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", 4854 + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", 4855 + "funding": [ 4856 + { 4857 + "type": "GitHub Sponsors", 4858 + "url": "https://github.com/sponsors/unifiedjs" 4859 + }, 4860 + { 4861 + "type": "OpenCollective", 4862 + "url": "https://opencollective.com/unified" 4863 + } 4864 + ], 4865 + "license": "MIT", 4866 + "dependencies": { 4867 + "micromark-util-character": "^2.0.0", 4868 + "micromark-util-types": "^2.0.0" 4869 + } 4870 + }, 4871 + "node_modules/micromark-factory-title": { 4872 + "version": "2.0.1", 4873 + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", 4874 + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", 4875 + "funding": [ 4876 + { 4877 + "type": "GitHub Sponsors", 4878 + "url": "https://github.com/sponsors/unifiedjs" 4879 + }, 4880 + { 4881 + "type": "OpenCollective", 4882 + "url": "https://opencollective.com/unified" 4883 + } 4884 + ], 4885 + "license": "MIT", 4886 + "dependencies": { 4887 + "micromark-factory-space": "^2.0.0", 4888 + "micromark-util-character": "^2.0.0", 4889 + "micromark-util-symbol": "^2.0.0", 4890 + "micromark-util-types": "^2.0.0" 4891 + } 4892 + }, 4893 + "node_modules/micromark-factory-whitespace": { 4894 + "version": "2.0.1", 4895 + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", 4896 + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", 4897 + "funding": [ 4898 + { 4899 + "type": "GitHub Sponsors", 4900 + "url": "https://github.com/sponsors/unifiedjs" 4901 + }, 4902 + { 4903 + "type": "OpenCollective", 4904 + "url": "https://opencollective.com/unified" 4905 + } 4906 + ], 4907 + "license": "MIT", 4908 + "dependencies": { 4909 + "micromark-factory-space": "^2.0.0", 4910 + "micromark-util-character": "^2.0.0", 4911 + "micromark-util-symbol": "^2.0.0", 4912 + "micromark-util-types": "^2.0.0" 4913 + } 4914 + }, 4915 + "node_modules/micromark-util-character": { 4916 + "version": "2.1.1", 4917 + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", 4918 + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", 4919 + "funding": [ 4920 + { 4921 + "type": "GitHub Sponsors", 4922 + "url": "https://github.com/sponsors/unifiedjs" 4923 + }, 4924 + { 4925 + "type": "OpenCollective", 4926 + "url": "https://opencollective.com/unified" 4927 + } 4928 + ], 4929 + "license": "MIT", 4930 + "dependencies": { 4931 + "micromark-util-symbol": "^2.0.0", 4932 + "micromark-util-types": "^2.0.0" 4933 + } 4934 + }, 4935 + "node_modules/micromark-util-chunked": { 4936 + "version": "2.0.1", 4937 + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", 4938 + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", 4939 + "funding": [ 4940 + { 4941 + "type": "GitHub Sponsors", 4942 + "url": "https://github.com/sponsors/unifiedjs" 4943 + }, 4944 + { 4945 + "type": "OpenCollective", 4946 + "url": "https://opencollective.com/unified" 4947 + } 4948 + ], 4949 + "license": "MIT", 4950 + "dependencies": { 4951 + "micromark-util-symbol": "^2.0.0" 4952 + } 4953 + }, 4954 + "node_modules/micromark-util-classify-character": { 4955 + "version": "2.0.1", 4956 + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", 4957 + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", 4958 + "funding": [ 4959 + { 4960 + "type": "GitHub Sponsors", 4961 + "url": "https://github.com/sponsors/unifiedjs" 4962 + }, 4963 + { 4964 + "type": "OpenCollective", 4965 + "url": "https://opencollective.com/unified" 4966 + } 4967 + ], 4968 + "license": "MIT", 4969 + "dependencies": { 4970 + "micromark-util-character": "^2.0.0", 4971 + "micromark-util-symbol": "^2.0.0", 4972 + "micromark-util-types": "^2.0.0" 4973 + } 4974 + }, 4975 + "node_modules/micromark-util-combine-extensions": { 4976 + "version": "2.0.1", 4977 + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", 4978 + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", 4979 + "funding": [ 4980 + { 4981 + "type": "GitHub Sponsors", 4982 + "url": "https://github.com/sponsors/unifiedjs" 4983 + }, 4984 + { 4985 + "type": "OpenCollective", 4986 + "url": "https://opencollective.com/unified" 4987 + } 4988 + ], 4989 + "license": "MIT", 4990 + "dependencies": { 4991 + "micromark-util-chunked": "^2.0.0", 4992 + "micromark-util-types": "^2.0.0" 4993 + } 4994 + }, 4995 + "node_modules/micromark-util-decode-numeric-character-reference": { 4996 + "version": "2.0.2", 4997 + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", 4998 + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", 4999 + "funding": [ 5000 + { 5001 + "type": "GitHub Sponsors", 5002 + "url": "https://github.com/sponsors/unifiedjs" 5003 + }, 5004 + { 5005 + "type": "OpenCollective", 5006 + "url": "https://opencollective.com/unified" 5007 + } 5008 + ], 5009 + "license": "MIT", 5010 + "dependencies": { 5011 + "micromark-util-symbol": "^2.0.0" 5012 + } 5013 + }, 5014 + "node_modules/micromark-util-decode-string": { 5015 + "version": "2.0.1", 5016 + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", 5017 + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", 5018 + "funding": [ 5019 + { 5020 + "type": "GitHub Sponsors", 5021 + "url": "https://github.com/sponsors/unifiedjs" 5022 + }, 5023 + { 5024 + "type": "OpenCollective", 5025 + "url": "https://opencollective.com/unified" 5026 + } 5027 + ], 5028 + "license": "MIT", 5029 + "dependencies": { 5030 + "decode-named-character-reference": "^1.0.0", 5031 + "micromark-util-character": "^2.0.0", 5032 + "micromark-util-decode-numeric-character-reference": "^2.0.0", 5033 + "micromark-util-symbol": "^2.0.0" 5034 + } 5035 + }, 5036 + "node_modules/micromark-util-encode": { 5037 + "version": "2.0.1", 5038 + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", 5039 + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", 5040 + "funding": [ 5041 + { 5042 + "type": "GitHub Sponsors", 5043 + "url": "https://github.com/sponsors/unifiedjs" 5044 + }, 5045 + { 5046 + "type": "OpenCollective", 5047 + "url": "https://opencollective.com/unified" 5048 + } 5049 + ], 5050 + "license": "MIT" 5051 + }, 5052 + "node_modules/micromark-util-events-to-acorn": { 5053 + "version": "2.0.3", 5054 + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", 5055 + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", 5056 + "funding": [ 5057 + { 5058 + "type": "GitHub Sponsors", 5059 + "url": "https://github.com/sponsors/unifiedjs" 5060 + }, 5061 + { 5062 + "type": "OpenCollective", 5063 + "url": "https://opencollective.com/unified" 5064 + } 5065 + ], 5066 + "license": "MIT", 5067 + "dependencies": { 5068 + "@types/estree": "^1.0.0", 5069 + "@types/unist": "^3.0.0", 5070 + "devlop": "^1.0.0", 5071 + "estree-util-visit": "^2.0.0", 5072 + "micromark-util-symbol": "^2.0.0", 5073 + "micromark-util-types": "^2.0.0", 5074 + "vfile-message": "^4.0.0" 5075 + } 5076 + }, 5077 + "node_modules/micromark-util-html-tag-name": { 5078 + "version": "2.0.1", 5079 + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", 5080 + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", 5081 + "funding": [ 5082 + { 5083 + "type": "GitHub Sponsors", 5084 + "url": "https://github.com/sponsors/unifiedjs" 5085 + }, 5086 + { 5087 + "type": "OpenCollective", 5088 + "url": "https://opencollective.com/unified" 5089 + } 5090 + ], 5091 + "license": "MIT" 5092 + }, 5093 + "node_modules/micromark-util-normalize-identifier": { 5094 + "version": "2.0.1", 5095 + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", 5096 + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", 5097 + "funding": [ 5098 + { 5099 + "type": "GitHub Sponsors", 5100 + "url": "https://github.com/sponsors/unifiedjs" 5101 + }, 5102 + { 5103 + "type": "OpenCollective", 5104 + "url": "https://opencollective.com/unified" 5105 + } 5106 + ], 5107 + "license": "MIT", 5108 + "dependencies": { 5109 + "micromark-util-symbol": "^2.0.0" 5110 + } 5111 + }, 5112 + "node_modules/micromark-util-resolve-all": { 5113 + "version": "2.0.1", 5114 + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", 5115 + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", 5116 + "funding": [ 5117 + { 5118 + "type": "GitHub Sponsors", 5119 + "url": "https://github.com/sponsors/unifiedjs" 5120 + }, 5121 + { 5122 + "type": "OpenCollective", 5123 + "url": "https://opencollective.com/unified" 5124 + } 5125 + ], 5126 + "license": "MIT", 5127 + "dependencies": { 5128 + "micromark-util-types": "^2.0.0" 5129 + } 5130 + }, 5131 + "node_modules/micromark-util-sanitize-uri": { 5132 + "version": "2.0.1", 5133 + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", 5134 + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", 5135 + "funding": [ 5136 + { 5137 + "type": "GitHub Sponsors", 5138 + "url": "https://github.com/sponsors/unifiedjs" 5139 + }, 5140 + { 5141 + "type": "OpenCollective", 5142 + "url": "https://opencollective.com/unified" 5143 + } 5144 + ], 5145 + "license": "MIT", 5146 + "dependencies": { 5147 + "micromark-util-character": "^2.0.0", 5148 + "micromark-util-encode": "^2.0.0", 5149 + "micromark-util-symbol": "^2.0.0" 5150 + } 5151 + }, 5152 + "node_modules/micromark-util-subtokenize": { 5153 + "version": "2.1.0", 5154 + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", 5155 + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", 5156 + "funding": [ 5157 + { 5158 + "type": "GitHub Sponsors", 5159 + "url": "https://github.com/sponsors/unifiedjs" 5160 + }, 5161 + { 5162 + "type": "OpenCollective", 5163 + "url": "https://opencollective.com/unified" 5164 + } 5165 + ], 5166 + "license": "MIT", 5167 + "dependencies": { 5168 + "devlop": "^1.0.0", 5169 + "micromark-util-chunked": "^2.0.0", 5170 + "micromark-util-symbol": "^2.0.0", 5171 + "micromark-util-types": "^2.0.0" 5172 + } 5173 + }, 5174 + "node_modules/micromark-util-symbol": { 5175 + "version": "2.0.1", 5176 + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", 5177 + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", 5178 + "funding": [ 5179 + { 5180 + "type": "GitHub Sponsors", 5181 + "url": "https://github.com/sponsors/unifiedjs" 5182 + }, 5183 + { 5184 + "type": "OpenCollective", 5185 + "url": "https://opencollective.com/unified" 5186 + } 5187 + ], 5188 + "license": "MIT" 5189 + }, 5190 + "node_modules/micromark-util-types": { 5191 + "version": "2.0.2", 5192 + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", 5193 + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", 5194 + "funding": [ 5195 + { 5196 + "type": "GitHub Sponsors", 5197 + "url": "https://github.com/sponsors/unifiedjs" 5198 + }, 5199 + { 5200 + "type": "OpenCollective", 5201 + "url": "https://opencollective.com/unified" 5202 + } 5203 + ], 5204 + "license": "MIT" 5205 + }, 5206 + "node_modules/micromatch": { 5207 + "version": "4.0.8", 5208 + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", 5209 + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", 5210 + "dev": true, 5211 + "license": "MIT", 5212 + "dependencies": { 5213 + "braces": "^3.0.3", 5214 + "picomatch": "^2.3.1" 5215 + }, 5216 + "engines": { 5217 + "node": ">=8.6" 5218 + } 5219 + }, 5220 + "node_modules/micromatch/node_modules/picomatch": { 5221 + "version": "2.3.2", 5222 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", 5223 + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", 5224 + "dev": true, 5225 + "license": "MIT", 5226 + "engines": { 5227 + "node": ">=8.6" 5228 + }, 5229 + "funding": { 5230 + "url": "https://github.com/sponsors/jonschlinkert" 5231 + } 5232 + }, 5233 + "node_modules/mrmime": { 5234 + "version": "2.0.1", 5235 + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", 5236 + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", 5237 + "license": "MIT", 5238 + "engines": { 5239 + "node": ">=10" 5240 + } 5241 + }, 5242 + "node_modules/ms": { 5243 + "version": "2.1.3", 5244 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 5245 + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 5246 + "license": "MIT" 5247 + }, 5248 + "node_modules/mz": { 5249 + "version": "2.7.0", 5250 + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", 5251 + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", 5252 + "dev": true, 5253 + "license": "MIT", 5254 + "dependencies": { 5255 + "any-promise": "^1.0.0", 5256 + "object-assign": "^4.0.1", 5257 + "thenify-all": "^1.0.0" 5258 + } 5259 + }, 5260 + "node_modules/nanoid": { 5261 + "version": "3.3.16", 5262 + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", 5263 + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", 5264 + "funding": [ 5265 + { 5266 + "type": "github", 5267 + "url": "https://github.com/sponsors/ai" 5268 + } 5269 + ], 5270 + "license": "MIT", 5271 + "bin": { 5272 + "nanoid": "bin/nanoid.cjs" 5273 + }, 5274 + "engines": { 5275 + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 5276 + } 5277 + }, 5278 + "node_modules/neotraverse": { 5279 + "version": "0.6.18", 5280 + "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz", 5281 + "integrity": "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==", 5282 + "license": "MIT", 5283 + "engines": { 5284 + "node": ">= 10" 5285 + } 5286 + }, 5287 + "node_modules/nlcst-to-string": { 5288 + "version": "4.0.0", 5289 + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", 5290 + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", 5291 + "license": "MIT", 5292 + "dependencies": { 5293 + "@types/nlcst": "^2.0.0" 5294 + }, 5295 + "funding": { 5296 + "type": "opencollective", 5297 + "url": "https://opencollective.com/unified" 5298 + } 5299 + }, 5300 + "node_modules/node-fetch-native": { 5301 + "version": "1.6.7", 5302 + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", 5303 + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", 5304 + "license": "MIT" 5305 + }, 5306 + "node_modules/node-mock-http": { 5307 + "version": "1.0.4", 5308 + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.4.tgz", 5309 + "integrity": "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==", 5310 + "license": "MIT" 5311 + }, 5312 + "node_modules/normalize-path": { 5313 + "version": "3.0.0", 5314 + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 5315 + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 5316 + "license": "MIT", 5317 + "engines": { 5318 + "node": ">=0.10.0" 5319 + } 5320 + }, 5321 + "node_modules/nth-check": { 5322 + "version": "2.1.1", 5323 + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", 5324 + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", 5325 + "license": "BSD-2-Clause", 5326 + "dependencies": { 5327 + "boolbase": "^1.0.0" 5328 + }, 5329 + "funding": { 5330 + "url": "https://github.com/fb55/nth-check?sponsor=1" 5331 + } 5332 + }, 5333 + "node_modules/object-assign": { 5334 + "version": "4.1.1", 5335 + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 5336 + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", 5337 + "dev": true, 5338 + "license": "MIT", 5339 + "engines": { 5340 + "node": ">=0.10.0" 5341 + } 5342 + }, 5343 + "node_modules/object-hash": { 5344 + "version": "3.0.0", 5345 + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", 5346 + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", 5347 + "dev": true, 5348 + "license": "MIT", 5349 + "engines": { 5350 + "node": ">= 6" 5351 + } 5352 + }, 5353 + "node_modules/ofetch": { 5354 + "version": "1.5.1", 5355 + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", 5356 + "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", 5357 + "license": "MIT", 5358 + "dependencies": { 5359 + "destr": "^2.0.5", 5360 + "node-fetch-native": "^1.6.7", 5361 + "ufo": "^1.6.1" 5362 + } 5363 + }, 5364 + "node_modules/ohash": { 5365 + "version": "2.0.11", 5366 + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", 5367 + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", 5368 + "license": "MIT" 5369 + }, 5370 + "node_modules/oniguruma-parser": { 5371 + "version": "0.12.2", 5372 + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", 5373 + "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", 5374 + "license": "MIT" 5375 + }, 5376 + "node_modules/oniguruma-to-es": { 5377 + "version": "4.3.6", 5378 + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", 5379 + "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", 5380 + "license": "MIT", 5381 + "dependencies": { 5382 + "oniguruma-parser": "^0.12.2", 5383 + "regex": "^6.1.0", 5384 + "regex-recursion": "^6.0.2" 5385 + } 5386 + }, 5387 + "node_modules/p-limit": { 5388 + "version": "6.2.0", 5389 + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", 5390 + "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==", 5391 + "license": "MIT", 5392 + "dependencies": { 5393 + "yocto-queue": "^1.1.1" 5394 + }, 5395 + "engines": { 5396 + "node": ">=18" 5397 + }, 5398 + "funding": { 5399 + "url": "https://github.com/sponsors/sindresorhus" 5400 + } 5401 + }, 5402 + "node_modules/p-queue": { 5403 + "version": "8.1.1", 5404 + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.1.tgz", 5405 + "integrity": "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==", 5406 + "license": "MIT", 5407 + "dependencies": { 5408 + "eventemitter3": "^5.0.1", 5409 + "p-timeout": "^6.1.2" 5410 + }, 5411 + "engines": { 5412 + "node": ">=18" 5413 + }, 5414 + "funding": { 5415 + "url": "https://github.com/sponsors/sindresorhus" 5416 + } 5417 + }, 5418 + "node_modules/p-timeout": { 5419 + "version": "6.1.4", 5420 + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", 5421 + "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", 5422 + "license": "MIT", 5423 + "engines": { 5424 + "node": ">=14.16" 5425 + }, 5426 + "funding": { 5427 + "url": "https://github.com/sponsors/sindresorhus" 5428 + } 5429 + }, 5430 + "node_modules/package-manager-detector": { 5431 + "version": "1.7.0", 5432 + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.7.0.tgz", 5433 + "integrity": "sha512-xg1eHpwYL/D/HEdWw2goFZP6vV0FH7W+PZ5rFkGjdIDLtxq7EkzBUeT3m+lndYCt8wKbmofUu1MUdMCXkCk9ZQ==", 5434 + "license": "MIT" 5435 + }, 5436 + "node_modules/pagefind": { 5437 + "version": "1.5.2", 5438 + "resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.5.2.tgz", 5439 + "integrity": "sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q==", 5440 + "license": "MIT", 5441 + "bin": { 5442 + "pagefind": "lib/runner/bin.cjs" 5443 + }, 5444 + "optionalDependencies": { 5445 + "@pagefind/darwin-arm64": "1.5.2", 5446 + "@pagefind/darwin-x64": "1.5.2", 5447 + "@pagefind/freebsd-x64": "1.5.2", 5448 + "@pagefind/linux-arm64": "1.5.2", 5449 + "@pagefind/linux-x64": "1.5.2", 5450 + "@pagefind/windows-arm64": "1.5.2", 5451 + "@pagefind/windows-x64": "1.5.2" 5452 + } 5453 + }, 5454 + "node_modules/parse-entities": { 5455 + "version": "4.0.2", 5456 + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", 5457 + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", 5458 + "license": "MIT", 5459 + "dependencies": { 5460 + "@types/unist": "^2.0.0", 5461 + "character-entities-legacy": "^3.0.0", 5462 + "character-reference-invalid": "^2.0.0", 5463 + "decode-named-character-reference": "^1.0.0", 5464 + "is-alphanumerical": "^2.0.0", 5465 + "is-decimal": "^2.0.0", 5466 + "is-hexadecimal": "^2.0.0" 5467 + }, 5468 + "funding": { 5469 + "type": "github", 5470 + "url": "https://github.com/sponsors/wooorm" 5471 + } 5472 + }, 5473 + "node_modules/parse-entities/node_modules/@types/unist": { 5474 + "version": "2.0.11", 5475 + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", 5476 + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", 5477 + "license": "MIT" 5478 + }, 5479 + "node_modules/parse-latin": { 5480 + "version": "7.0.0", 5481 + "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", 5482 + "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", 5483 + "license": "MIT", 5484 + "dependencies": { 5485 + "@types/nlcst": "^2.0.0", 5486 + "@types/unist": "^3.0.0", 5487 + "nlcst-to-string": "^4.0.0", 5488 + "unist-util-modify-children": "^4.0.0", 5489 + "unist-util-visit-children": "^3.0.0", 5490 + "vfile": "^6.0.0" 5491 + }, 5492 + "funding": { 5493 + "type": "github", 5494 + "url": "https://github.com/sponsors/wooorm" 5495 + } 5496 + }, 5497 + "node_modules/parse5": { 5498 + "version": "7.3.0", 5499 + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", 5500 + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", 5501 + "license": "MIT", 5502 + "dependencies": { 5503 + "entities": "^6.0.0" 5504 + }, 5505 + "funding": { 5506 + "url": "https://github.com/inikulin/parse5?sponsor=1" 5507 + } 5508 + }, 5509 + "node_modules/path-parse": { 5510 + "version": "1.0.7", 5511 + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 5512 + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 5513 + "dev": true, 5514 + "license": "MIT" 5515 + }, 5516 + "node_modules/piccolore": { 5517 + "version": "0.1.3", 5518 + "resolved": "https://registry.npmjs.org/piccolore/-/piccolore-0.1.3.tgz", 5519 + "integrity": "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==", 5520 + "license": "ISC" 5521 + }, 5522 + "node_modules/picocolors": { 5523 + "version": "1.1.1", 5524 + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 5525 + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 5526 + "license": "ISC" 5527 + }, 5528 + "node_modules/picomatch": { 5529 + "version": "4.0.5", 5530 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", 5531 + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", 5532 + "license": "MIT", 5533 + "engines": { 5534 + "node": ">=12" 5535 + }, 5536 + "funding": { 5537 + "url": "https://github.com/sponsors/jonschlinkert" 5538 + } 5539 + }, 5540 + "node_modules/pify": { 5541 + "version": "2.3.0", 5542 + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 5543 + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", 5544 + "dev": true, 5545 + "license": "MIT", 5546 + "engines": { 5547 + "node": ">=0.10.0" 5548 + } 5549 + }, 5550 + "node_modules/pirates": { 5551 + "version": "4.0.7", 5552 + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", 5553 + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", 5554 + "dev": true, 5555 + "license": "MIT", 5556 + "engines": { 5557 + "node": ">= 6" 5558 + } 5559 + }, 5560 + "node_modules/postcss": { 5561 + "version": "8.5.19", 5562 + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.19.tgz", 5563 + "integrity": "sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==", 5564 + "funding": [ 5565 + { 5566 + "type": "opencollective", 5567 + "url": "https://opencollective.com/postcss/" 5568 + }, 5569 + { 5570 + "type": "tidelift", 5571 + "url": "https://tidelift.com/funding/github/npm/postcss" 5572 + }, 5573 + { 5574 + "type": "github", 5575 + "url": "https://github.com/sponsors/ai" 5576 + } 5577 + ], 5578 + "license": "MIT", 5579 + "dependencies": { 5580 + "nanoid": "^3.3.12", 5581 + "picocolors": "^1.1.1", 5582 + "source-map-js": "^1.2.1" 5583 + }, 5584 + "engines": { 5585 + "node": "^10 || ^12 || >=14" 5586 + } 5587 + }, 5588 + "node_modules/postcss-import": { 5589 + "version": "15.1.0", 5590 + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", 5591 + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", 5592 + "dev": true, 5593 + "license": "MIT", 5594 + "dependencies": { 5595 + "postcss-value-parser": "^4.0.0", 5596 + "read-cache": "^1.0.0", 5597 + "resolve": "^1.1.7" 5598 + }, 5599 + "engines": { 5600 + "node": ">=14.0.0" 5601 + }, 5602 + "peerDependencies": { 5603 + "postcss": "^8.0.0" 5604 + } 5605 + }, 5606 + "node_modules/postcss-js": { 5607 + "version": "4.1.0", 5608 + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", 5609 + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", 5610 + "dev": true, 5611 + "funding": [ 5612 + { 5613 + "type": "opencollective", 5614 + "url": "https://opencollective.com/postcss/" 5615 + }, 5616 + { 5617 + "type": "github", 5618 + "url": "https://github.com/sponsors/ai" 5619 + } 5620 + ], 5621 + "license": "MIT", 5622 + "dependencies": { 5623 + "camelcase-css": "^2.0.1" 5624 + }, 5625 + "engines": { 5626 + "node": "^12 || ^14 || >= 16" 5627 + }, 5628 + "peerDependencies": { 5629 + "postcss": "^8.4.21" 5630 + } 5631 + }, 5632 + "node_modules/postcss-load-config": { 5633 + "version": "6.0.1", 5634 + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", 5635 + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", 5636 + "dev": true, 5637 + "funding": [ 5638 + { 5639 + "type": "opencollective", 5640 + "url": "https://opencollective.com/postcss/" 5641 + }, 5642 + { 5643 + "type": "github", 5644 + "url": "https://github.com/sponsors/ai" 5645 + } 5646 + ], 5647 + "license": "MIT", 5648 + "dependencies": { 5649 + "lilconfig": "^3.1.1" 5650 + }, 5651 + "engines": { 5652 + "node": ">= 18" 5653 + }, 5654 + "peerDependencies": { 5655 + "jiti": ">=1.21.0", 5656 + "postcss": ">=8.0.9", 5657 + "tsx": "^4.8.1", 5658 + "yaml": "^2.4.2" 5659 + }, 5660 + "peerDependenciesMeta": { 5661 + "jiti": { 5662 + "optional": true 5663 + }, 5664 + "postcss": { 5665 + "optional": true 5666 + }, 5667 + "tsx": { 5668 + "optional": true 5669 + }, 5670 + "yaml": { 5671 + "optional": true 5672 + } 5673 + } 5674 + }, 5675 + "node_modules/postcss-nested": { 5676 + "version": "6.2.0", 5677 + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", 5678 + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", 5679 + "funding": [ 5680 + { 5681 + "type": "opencollective", 5682 + "url": "https://opencollective.com/postcss/" 5683 + }, 5684 + { 5685 + "type": "github", 5686 + "url": "https://github.com/sponsors/ai" 5687 + } 5688 + ], 5689 + "license": "MIT", 5690 + "dependencies": { 5691 + "postcss-selector-parser": "^6.1.1" 5692 + }, 5693 + "engines": { 5694 + "node": ">=12.0" 5695 + }, 5696 + "peerDependencies": { 5697 + "postcss": "^8.2.14" 5698 + } 5699 + }, 5700 + "node_modules/postcss-selector-parser": { 5701 + "version": "6.1.4", 5702 + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", 5703 + "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", 5704 + "license": "MIT", 5705 + "dependencies": { 5706 + "cssesc": "^3.0.0", 5707 + "util-deprecate": "^1.0.2" 5708 + }, 5709 + "engines": { 5710 + "node": ">=4" 5711 + } 5712 + }, 5713 + "node_modules/postcss-value-parser": { 5714 + "version": "4.2.0", 5715 + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", 5716 + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", 5717 + "dev": true, 5718 + "license": "MIT" 5719 + }, 5720 + "node_modules/prismjs": { 5721 + "version": "1.30.0", 5722 + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", 5723 + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", 5724 + "license": "MIT", 5725 + "engines": { 5726 + "node": ">=6" 5727 + } 5728 + }, 5729 + "node_modules/prompts": { 5730 + "version": "2.4.2", 5731 + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", 5732 + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", 5733 + "license": "MIT", 5734 + "dependencies": { 5735 + "kleur": "^3.0.3", 5736 + "sisteransi": "^1.0.5" 5737 + }, 5738 + "engines": { 5739 + "node": ">= 6" 5740 + } 5741 + }, 5742 + "node_modules/property-information": { 5743 + "version": "7.2.0", 5744 + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", 5745 + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", 5746 + "license": "MIT", 5747 + "funding": { 5748 + "type": "github", 5749 + "url": "https://github.com/sponsors/wooorm" 5750 + } 5751 + }, 5752 + "node_modules/queue-microtask": { 5753 + "version": "1.2.3", 5754 + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 5755 + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 5756 + "dev": true, 5757 + "funding": [ 5758 + { 5759 + "type": "github", 5760 + "url": "https://github.com/sponsors/feross" 5761 + }, 5762 + { 5763 + "type": "patreon", 5764 + "url": "https://www.patreon.com/feross" 5765 + }, 5766 + { 5767 + "type": "consulting", 5768 + "url": "https://feross.org/support" 5769 + } 5770 + ], 5771 + "license": "MIT" 5772 + }, 5773 + "node_modules/radix3": { 5774 + "version": "1.1.2", 5775 + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", 5776 + "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", 5777 + "license": "MIT" 5778 + }, 5779 + "node_modules/read-cache": { 5780 + "version": "1.0.0", 5781 + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", 5782 + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", 5783 + "dev": true, 5784 + "license": "MIT", 5785 + "dependencies": { 5786 + "pify": "^2.3.0" 5787 + } 5788 + }, 5789 + "node_modules/readdirp": { 5790 + "version": "5.0.0", 5791 + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", 5792 + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", 5793 + "license": "MIT", 5794 + "engines": { 5795 + "node": ">= 20.19.0" 5796 + }, 5797 + "funding": { 5798 + "type": "individual", 5799 + "url": "https://paulmillr.com/funding/" 5800 + } 5801 + }, 5802 + "node_modules/recma-build-jsx": { 5803 + "version": "1.0.0", 5804 + "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", 5805 + "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", 5806 + "license": "MIT", 5807 + "dependencies": { 5808 + "@types/estree": "^1.0.0", 5809 + "estree-util-build-jsx": "^3.0.0", 5810 + "vfile": "^6.0.0" 5811 + }, 5812 + "funding": { 5813 + "type": "opencollective", 5814 + "url": "https://opencollective.com/unified" 5815 + } 5816 + }, 5817 + "node_modules/recma-jsx": { 5818 + "version": "1.0.1", 5819 + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz", 5820 + "integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==", 5821 + "license": "MIT", 5822 + "dependencies": { 5823 + "acorn-jsx": "^5.0.0", 5824 + "estree-util-to-js": "^2.0.0", 5825 + "recma-parse": "^1.0.0", 5826 + "recma-stringify": "^1.0.0", 5827 + "unified": "^11.0.0" 5828 + }, 5829 + "funding": { 5830 + "type": "opencollective", 5831 + "url": "https://opencollective.com/unified" 5832 + }, 5833 + "peerDependencies": { 5834 + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" 5835 + } 5836 + }, 5837 + "node_modules/recma-parse": { 5838 + "version": "1.0.0", 5839 + "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", 5840 + "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", 5841 + "license": "MIT", 5842 + "dependencies": { 5843 + "@types/estree": "^1.0.0", 5844 + "esast-util-from-js": "^2.0.0", 5845 + "unified": "^11.0.0", 5846 + "vfile": "^6.0.0" 5847 + }, 5848 + "funding": { 5849 + "type": "opencollective", 5850 + "url": "https://opencollective.com/unified" 5851 + } 5852 + }, 5853 + "node_modules/recma-stringify": { 5854 + "version": "1.0.0", 5855 + "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", 5856 + "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", 5857 + "license": "MIT", 5858 + "dependencies": { 5859 + "@types/estree": "^1.0.0", 5860 + "estree-util-to-js": "^2.0.0", 5861 + "unified": "^11.0.0", 5862 + "vfile": "^6.0.0" 5863 + }, 5864 + "funding": { 5865 + "type": "opencollective", 5866 + "url": "https://opencollective.com/unified" 5867 + } 5868 + }, 5869 + "node_modules/regex": { 5870 + "version": "6.1.0", 5871 + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", 5872 + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", 5873 + "license": "MIT", 5874 + "dependencies": { 5875 + "regex-utilities": "^2.3.0" 5876 + } 5877 + }, 5878 + "node_modules/regex-recursion": { 5879 + "version": "6.0.2", 5880 + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", 5881 + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", 5882 + "license": "MIT", 5883 + "dependencies": { 5884 + "regex-utilities": "^2.3.0" 5885 + } 5886 + }, 5887 + "node_modules/regex-utilities": { 5888 + "version": "2.3.0", 5889 + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", 5890 + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", 5891 + "license": "MIT" 5892 + }, 5893 + "node_modules/rehype": { 5894 + "version": "13.0.2", 5895 + "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.2.tgz", 5896 + "integrity": "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==", 5897 + "license": "MIT", 5898 + "dependencies": { 5899 + "@types/hast": "^3.0.0", 5900 + "rehype-parse": "^9.0.0", 5901 + "rehype-stringify": "^10.0.0", 5902 + "unified": "^11.0.0" 5903 + }, 5904 + "funding": { 5905 + "type": "opencollective", 5906 + "url": "https://opencollective.com/unified" 5907 + } 5908 + }, 5909 + "node_modules/rehype-expressive-code": { 5910 + "version": "0.41.7", 5911 + "resolved": "https://registry.npmjs.org/rehype-expressive-code/-/rehype-expressive-code-0.41.7.tgz", 5912 + "integrity": "sha512-25f8ZMSF1d9CMscX7Cft0TSQIqdwjce2gDOvQ+d/w0FovsMwrSt3ODP4P3Z7wO1jsIJ4eYyaDRnIR/27bd/EMQ==", 5913 + "license": "MIT", 5914 + "dependencies": { 5915 + "expressive-code": "^0.41.7" 5916 + } 5917 + }, 5918 + "node_modules/rehype-format": { 5919 + "version": "5.0.1", 5920 + "resolved": "https://registry.npmjs.org/rehype-format/-/rehype-format-5.0.1.tgz", 5921 + "integrity": "sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==", 5922 + "license": "MIT", 5923 + "dependencies": { 5924 + "@types/hast": "^3.0.0", 5925 + "hast-util-format": "^1.0.0" 5926 + }, 5927 + "funding": { 5928 + "type": "opencollective", 5929 + "url": "https://opencollective.com/unified" 5930 + } 5931 + }, 5932 + "node_modules/rehype-parse": { 5933 + "version": "9.0.1", 5934 + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", 5935 + "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==", 5936 + "license": "MIT", 5937 + "dependencies": { 5938 + "@types/hast": "^3.0.0", 5939 + "hast-util-from-html": "^2.0.0", 5940 + "unified": "^11.0.0" 5941 + }, 5942 + "funding": { 5943 + "type": "opencollective", 5944 + "url": "https://opencollective.com/unified" 5945 + } 5946 + }, 5947 + "node_modules/rehype-raw": { 5948 + "version": "7.0.0", 5949 + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", 5950 + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", 5951 + "license": "MIT", 5952 + "dependencies": { 5953 + "@types/hast": "^3.0.0", 5954 + "hast-util-raw": "^9.0.0", 5955 + "vfile": "^6.0.0" 5956 + }, 5957 + "funding": { 5958 + "type": "opencollective", 5959 + "url": "https://opencollective.com/unified" 5960 + } 5961 + }, 5962 + "node_modules/rehype-recma": { 5963 + "version": "1.0.0", 5964 + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", 5965 + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", 5966 + "license": "MIT", 5967 + "dependencies": { 5968 + "@types/estree": "^1.0.0", 5969 + "@types/hast": "^3.0.0", 5970 + "hast-util-to-estree": "^3.0.0" 5971 + }, 5972 + "funding": { 5973 + "type": "opencollective", 5974 + "url": "https://opencollective.com/unified" 5975 + } 5976 + }, 5977 + "node_modules/rehype-stringify": { 5978 + "version": "10.0.1", 5979 + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", 5980 + "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==", 5981 + "license": "MIT", 5982 + "dependencies": { 5983 + "@types/hast": "^3.0.0", 5984 + "hast-util-to-html": "^9.0.0", 5985 + "unified": "^11.0.0" 5986 + }, 5987 + "funding": { 5988 + "type": "opencollective", 5989 + "url": "https://opencollective.com/unified" 5990 + } 5991 + }, 5992 + "node_modules/remark-directive": { 5993 + "version": "3.0.1", 5994 + "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.1.tgz", 5995 + "integrity": "sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==", 5996 + "license": "MIT", 5997 + "dependencies": { 5998 + "@types/mdast": "^4.0.0", 5999 + "mdast-util-directive": "^3.0.0", 6000 + "micromark-extension-directive": "^3.0.0", 6001 + "unified": "^11.0.0" 6002 + }, 6003 + "funding": { 6004 + "type": "opencollective", 6005 + "url": "https://opencollective.com/unified" 6006 + } 6007 + }, 6008 + "node_modules/remark-gfm": { 6009 + "version": "4.0.1", 6010 + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", 6011 + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", 6012 + "license": "MIT", 6013 + "dependencies": { 6014 + "@types/mdast": "^4.0.0", 6015 + "mdast-util-gfm": "^3.0.0", 6016 + "micromark-extension-gfm": "^3.0.0", 6017 + "remark-parse": "^11.0.0", 6018 + "remark-stringify": "^11.0.0", 6019 + "unified": "^11.0.0" 6020 + }, 6021 + "funding": { 6022 + "type": "opencollective", 6023 + "url": "https://opencollective.com/unified" 6024 + } 6025 + }, 6026 + "node_modules/remark-mdx": { 6027 + "version": "3.1.1", 6028 + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz", 6029 + "integrity": "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==", 6030 + "license": "MIT", 6031 + "dependencies": { 6032 + "mdast-util-mdx": "^3.0.0", 6033 + "micromark-extension-mdxjs": "^3.0.0" 6034 + }, 6035 + "funding": { 6036 + "type": "opencollective", 6037 + "url": "https://opencollective.com/unified" 6038 + } 6039 + }, 6040 + "node_modules/remark-parse": { 6041 + "version": "11.0.0", 6042 + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", 6043 + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", 6044 + "license": "MIT", 6045 + "dependencies": { 6046 + "@types/mdast": "^4.0.0", 6047 + "mdast-util-from-markdown": "^2.0.0", 6048 + "micromark-util-types": "^2.0.0", 6049 + "unified": "^11.0.0" 6050 + }, 6051 + "funding": { 6052 + "type": "opencollective", 6053 + "url": "https://opencollective.com/unified" 6054 + } 6055 + }, 6056 + "node_modules/remark-rehype": { 6057 + "version": "11.1.2", 6058 + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", 6059 + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", 6060 + "license": "MIT", 6061 + "dependencies": { 6062 + "@types/hast": "^3.0.0", 6063 + "@types/mdast": "^4.0.0", 6064 + "mdast-util-to-hast": "^13.0.0", 6065 + "unified": "^11.0.0", 6066 + "vfile": "^6.0.0" 6067 + }, 6068 + "funding": { 6069 + "type": "opencollective", 6070 + "url": "https://opencollective.com/unified" 6071 + } 6072 + }, 6073 + "node_modules/remark-smartypants": { 6074 + "version": "3.0.2", 6075 + "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.2.tgz", 6076 + "integrity": "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==", 6077 + "license": "MIT", 6078 + "dependencies": { 6079 + "retext": "^9.0.0", 6080 + "retext-smartypants": "^6.0.0", 6081 + "unified": "^11.0.4", 6082 + "unist-util-visit": "^5.0.0" 6083 + }, 6084 + "engines": { 6085 + "node": ">=16.0.0" 6086 + } 6087 + }, 6088 + "node_modules/remark-stringify": { 6089 + "version": "11.0.0", 6090 + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", 6091 + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", 6092 + "license": "MIT", 6093 + "dependencies": { 6094 + "@types/mdast": "^4.0.0", 6095 + "mdast-util-to-markdown": "^2.0.0", 6096 + "unified": "^11.0.0" 6097 + }, 6098 + "funding": { 6099 + "type": "opencollective", 6100 + "url": "https://opencollective.com/unified" 6101 + } 6102 + }, 6103 + "node_modules/resolve": { 6104 + "version": "1.22.12", 6105 + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", 6106 + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", 6107 + "dev": true, 6108 + "license": "MIT", 6109 + "dependencies": { 6110 + "es-errors": "^1.3.0", 6111 + "is-core-module": "^2.16.1", 6112 + "path-parse": "^1.0.7", 6113 + "supports-preserve-symlinks-flag": "^1.0.0" 6114 + }, 6115 + "bin": { 6116 + "resolve": "bin/resolve" 6117 + }, 6118 + "engines": { 6119 + "node": ">= 0.4" 6120 + }, 6121 + "funding": { 6122 + "url": "https://github.com/sponsors/ljharb" 6123 + } 6124 + }, 6125 + "node_modules/retext": { 6126 + "version": "9.0.0", 6127 + "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", 6128 + "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==", 6129 + "license": "MIT", 6130 + "dependencies": { 6131 + "@types/nlcst": "^2.0.0", 6132 + "retext-latin": "^4.0.0", 6133 + "retext-stringify": "^4.0.0", 6134 + "unified": "^11.0.0" 6135 + }, 6136 + "funding": { 6137 + "type": "opencollective", 6138 + "url": "https://opencollective.com/unified" 6139 + } 6140 + }, 6141 + "node_modules/retext-latin": { 6142 + "version": "4.0.0", 6143 + "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz", 6144 + "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==", 6145 + "license": "MIT", 6146 + "dependencies": { 6147 + "@types/nlcst": "^2.0.0", 6148 + "parse-latin": "^7.0.0", 6149 + "unified": "^11.0.0" 6150 + }, 6151 + "funding": { 6152 + "type": "opencollective", 6153 + "url": "https://opencollective.com/unified" 6154 + } 6155 + }, 6156 + "node_modules/retext-smartypants": { 6157 + "version": "6.2.0", 6158 + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz", 6159 + "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", 6160 + "license": "MIT", 6161 + "dependencies": { 6162 + "@types/nlcst": "^2.0.0", 6163 + "nlcst-to-string": "^4.0.0", 6164 + "unist-util-visit": "^5.0.0" 6165 + }, 6166 + "funding": { 6167 + "type": "opencollective", 6168 + "url": "https://opencollective.com/unified" 6169 + } 6170 + }, 6171 + "node_modules/retext-stringify": { 6172 + "version": "4.0.0", 6173 + "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz", 6174 + "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==", 6175 + "license": "MIT", 6176 + "dependencies": { 6177 + "@types/nlcst": "^2.0.0", 6178 + "nlcst-to-string": "^4.0.0", 6179 + "unified": "^11.0.0" 6180 + }, 6181 + "funding": { 6182 + "type": "opencollective", 6183 + "url": "https://opencollective.com/unified" 6184 + } 6185 + }, 6186 + "node_modules/reusify": { 6187 + "version": "1.1.0", 6188 + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", 6189 + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", 6190 + "dev": true, 6191 + "license": "MIT", 6192 + "engines": { 6193 + "iojs": ">=1.0.0", 6194 + "node": ">=0.10.0" 6195 + } 6196 + }, 6197 + "node_modules/rollup": { 6198 + "version": "4.62.2", 6199 + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", 6200 + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", 6201 + "license": "MIT", 6202 + "dependencies": { 6203 + "@types/estree": "1.0.9" 6204 + }, 6205 + "bin": { 6206 + "rollup": "dist/bin/rollup" 6207 + }, 6208 + "engines": { 6209 + "node": ">=18.0.0", 6210 + "npm": ">=8.0.0" 6211 + }, 6212 + "optionalDependencies": { 6213 + "@rollup/rollup-android-arm-eabi": "4.62.2", 6214 + "@rollup/rollup-android-arm64": "4.62.2", 6215 + "@rollup/rollup-darwin-arm64": "4.62.2", 6216 + "@rollup/rollup-darwin-x64": "4.62.2", 6217 + "@rollup/rollup-freebsd-arm64": "4.62.2", 6218 + "@rollup/rollup-freebsd-x64": "4.62.2", 6219 + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", 6220 + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", 6221 + "@rollup/rollup-linux-arm64-gnu": "4.62.2", 6222 + "@rollup/rollup-linux-arm64-musl": "4.62.2", 6223 + "@rollup/rollup-linux-loong64-gnu": "4.62.2", 6224 + "@rollup/rollup-linux-loong64-musl": "4.62.2", 6225 + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", 6226 + "@rollup/rollup-linux-ppc64-musl": "4.62.2", 6227 + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", 6228 + "@rollup/rollup-linux-riscv64-musl": "4.62.2", 6229 + "@rollup/rollup-linux-s390x-gnu": "4.62.2", 6230 + "@rollup/rollup-linux-x64-gnu": "4.62.2", 6231 + "@rollup/rollup-linux-x64-musl": "4.62.2", 6232 + "@rollup/rollup-openbsd-x64": "4.62.2", 6233 + "@rollup/rollup-openharmony-arm64": "4.62.2", 6234 + "@rollup/rollup-win32-arm64-msvc": "4.62.2", 6235 + "@rollup/rollup-win32-ia32-msvc": "4.62.2", 6236 + "@rollup/rollup-win32-x64-gnu": "4.62.2", 6237 + "@rollup/rollup-win32-x64-msvc": "4.62.2", 6238 + "fsevents": "~2.3.2" 6239 + } 6240 + }, 6241 + "node_modules/run-parallel": { 6242 + "version": "1.2.0", 6243 + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 6244 + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 6245 + "dev": true, 6246 + "funding": [ 6247 + { 6248 + "type": "github", 6249 + "url": "https://github.com/sponsors/feross" 6250 + }, 6251 + { 6252 + "type": "patreon", 6253 + "url": "https://www.patreon.com/feross" 6254 + }, 6255 + { 6256 + "type": "consulting", 6257 + "url": "https://feross.org/support" 6258 + } 6259 + ], 6260 + "license": "MIT", 6261 + "dependencies": { 6262 + "queue-microtask": "^1.2.2" 6263 + } 6264 + }, 6265 + "node_modules/sax": { 6266 + "version": "1.6.0", 6267 + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", 6268 + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", 6269 + "license": "BlueOak-1.0.0", 6270 + "engines": { 6271 + "node": ">=11.0.0" 6272 + } 6273 + }, 6274 + "node_modules/semver": { 6275 + "version": "7.8.5", 6276 + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", 6277 + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", 6278 + "license": "ISC", 6279 + "bin": { 6280 + "semver": "bin/semver.js" 6281 + }, 6282 + "engines": { 6283 + "node": ">=10" 6284 + } 6285 + }, 6286 + "node_modules/sharp": { 6287 + "version": "0.34.5", 6288 + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", 6289 + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", 6290 + "hasInstallScript": true, 6291 + "license": "Apache-2.0", 6292 + "dependencies": { 6293 + "@img/colour": "^1.0.0", 6294 + "detect-libc": "^2.1.2", 6295 + "semver": "^7.7.3" 6296 + }, 6297 + "engines": { 6298 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 6299 + }, 6300 + "funding": { 6301 + "url": "https://opencollective.com/libvips" 6302 + }, 6303 + "optionalDependencies": { 6304 + "@img/sharp-darwin-arm64": "0.34.5", 6305 + "@img/sharp-darwin-x64": "0.34.5", 6306 + "@img/sharp-libvips-darwin-arm64": "1.2.4", 6307 + "@img/sharp-libvips-darwin-x64": "1.2.4", 6308 + "@img/sharp-libvips-linux-arm": "1.2.4", 6309 + "@img/sharp-libvips-linux-arm64": "1.2.4", 6310 + "@img/sharp-libvips-linux-ppc64": "1.2.4", 6311 + "@img/sharp-libvips-linux-riscv64": "1.2.4", 6312 + "@img/sharp-libvips-linux-s390x": "1.2.4", 6313 + "@img/sharp-libvips-linux-x64": "1.2.4", 6314 + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", 6315 + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", 6316 + "@img/sharp-linux-arm": "0.34.5", 6317 + "@img/sharp-linux-arm64": "0.34.5", 6318 + "@img/sharp-linux-ppc64": "0.34.5", 6319 + "@img/sharp-linux-riscv64": "0.34.5", 6320 + "@img/sharp-linux-s390x": "0.34.5", 6321 + "@img/sharp-linux-x64": "0.34.5", 6322 + "@img/sharp-linuxmusl-arm64": "0.34.5", 6323 + "@img/sharp-linuxmusl-x64": "0.34.5", 6324 + "@img/sharp-wasm32": "0.34.5", 6325 + "@img/sharp-win32-arm64": "0.34.5", 6326 + "@img/sharp-win32-ia32": "0.34.5", 6327 + "@img/sharp-win32-x64": "0.34.5" 6328 + } 6329 + }, 6330 + "node_modules/shiki": { 6331 + "version": "3.23.0", 6332 + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.23.0.tgz", 6333 + "integrity": "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==", 6334 + "license": "MIT", 6335 + "dependencies": { 6336 + "@shikijs/core": "3.23.0", 6337 + "@shikijs/engine-javascript": "3.23.0", 6338 + "@shikijs/engine-oniguruma": "3.23.0", 6339 + "@shikijs/langs": "3.23.0", 6340 + "@shikijs/themes": "3.23.0", 6341 + "@shikijs/types": "3.23.0", 6342 + "@shikijs/vscode-textmate": "^10.0.2", 6343 + "@types/hast": "^3.0.4" 6344 + } 6345 + }, 6346 + "node_modules/sisteransi": { 6347 + "version": "1.0.5", 6348 + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", 6349 + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", 6350 + "license": "MIT" 6351 + }, 6352 + "node_modules/sitemap": { 6353 + "version": "9.0.1", 6354 + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-9.0.1.tgz", 6355 + "integrity": "sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ==", 6356 + "license": "MIT", 6357 + "dependencies": { 6358 + "@types/node": "^24.9.2", 6359 + "@types/sax": "^1.2.1", 6360 + "arg": "^5.0.0", 6361 + "sax": "^1.4.1" 6362 + }, 6363 + "bin": { 6364 + "sitemap": "dist/esm/cli.js" 6365 + }, 6366 + "engines": { 6367 + "node": ">=20.19.5", 6368 + "npm": ">=10.8.2" 6369 + } 6370 + }, 6371 + "node_modules/smol-toml": { 6372 + "version": "1.7.0", 6373 + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.0.tgz", 6374 + "integrity": "sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ==", 6375 + "license": "BSD-3-Clause", 6376 + "engines": { 6377 + "node": ">= 18" 6378 + }, 6379 + "funding": { 6380 + "url": "https://github.com/sponsors/cyyynthia" 6381 + } 6382 + }, 6383 + "node_modules/source-map": { 6384 + "version": "0.7.6", 6385 + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", 6386 + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", 6387 + "license": "BSD-3-Clause", 6388 + "engines": { 6389 + "node": ">= 12" 6390 + } 6391 + }, 6392 + "node_modules/source-map-js": { 6393 + "version": "1.2.1", 6394 + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 6395 + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 6396 + "license": "BSD-3-Clause", 6397 + "engines": { 6398 + "node": ">=0.10.0" 6399 + } 6400 + }, 6401 + "node_modules/space-separated-tokens": { 6402 + "version": "2.0.2", 6403 + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", 6404 + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", 6405 + "license": "MIT", 6406 + "funding": { 6407 + "type": "github", 6408 + "url": "https://github.com/sponsors/wooorm" 6409 + } 6410 + }, 6411 + "node_modules/stream-replace-string": { 6412 + "version": "2.0.0", 6413 + "resolved": "https://registry.npmjs.org/stream-replace-string/-/stream-replace-string-2.0.0.tgz", 6414 + "integrity": "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==", 6415 + "license": "MIT" 6416 + }, 6417 + "node_modules/string-width": { 6418 + "version": "7.2.0", 6419 + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", 6420 + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", 6421 + "license": "MIT", 6422 + "dependencies": { 6423 + "emoji-regex": "^10.3.0", 6424 + "get-east-asian-width": "^1.0.0", 6425 + "strip-ansi": "^7.1.0" 6426 + }, 6427 + "engines": { 6428 + "node": ">=18" 6429 + }, 6430 + "funding": { 6431 + "url": "https://github.com/sponsors/sindresorhus" 6432 + } 6433 + }, 6434 + "node_modules/stringify-entities": { 6435 + "version": "4.0.4", 6436 + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", 6437 + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", 6438 + "license": "MIT", 6439 + "dependencies": { 6440 + "character-entities-html4": "^2.0.0", 6441 + "character-entities-legacy": "^3.0.0" 6442 + }, 6443 + "funding": { 6444 + "type": "github", 6445 + "url": "https://github.com/sponsors/wooorm" 6446 + } 6447 + }, 6448 + "node_modules/strip-ansi": { 6449 + "version": "7.2.0", 6450 + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", 6451 + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", 6452 + "license": "MIT", 6453 + "dependencies": { 6454 + "ansi-regex": "^6.2.2" 6455 + }, 6456 + "engines": { 6457 + "node": ">=12" 6458 + }, 6459 + "funding": { 6460 + "url": "https://github.com/chalk/strip-ansi?sponsor=1" 6461 + } 6462 + }, 6463 + "node_modules/style-to-js": { 6464 + "version": "1.1.21", 6465 + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", 6466 + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", 6467 + "license": "MIT", 6468 + "dependencies": { 6469 + "style-to-object": "1.0.14" 6470 + } 6471 + }, 6472 + "node_modules/style-to-object": { 6473 + "version": "1.0.14", 6474 + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", 6475 + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", 6476 + "license": "MIT", 6477 + "dependencies": { 6478 + "inline-style-parser": "0.2.7" 6479 + } 6480 + }, 6481 + "node_modules/sucrase": { 6482 + "version": "3.35.1", 6483 + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", 6484 + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", 6485 + "dev": true, 6486 + "license": "MIT", 6487 + "dependencies": { 6488 + "@jridgewell/gen-mapping": "^0.3.2", 6489 + "commander": "^4.0.0", 6490 + "lines-and-columns": "^1.1.6", 6491 + "mz": "^2.7.0", 6492 + "pirates": "^4.0.1", 6493 + "tinyglobby": "^0.2.11", 6494 + "ts-interface-checker": "^0.1.9" 6495 + }, 6496 + "bin": { 6497 + "sucrase": "bin/sucrase", 6498 + "sucrase-node": "bin/sucrase-node" 6499 + }, 6500 + "engines": { 6501 + "node": ">=16 || 14 >=14.17" 6502 + } 6503 + }, 6504 + "node_modules/sucrase/node_modules/commander": { 6505 + "version": "4.1.1", 6506 + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", 6507 + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", 6508 + "dev": true, 6509 + "license": "MIT", 6510 + "engines": { 6511 + "node": ">= 6" 6512 + } 6513 + }, 6514 + "node_modules/supports-preserve-symlinks-flag": { 6515 + "version": "1.0.0", 6516 + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 6517 + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 6518 + "dev": true, 6519 + "license": "MIT", 6520 + "engines": { 6521 + "node": ">= 0.4" 6522 + }, 6523 + "funding": { 6524 + "url": "https://github.com/sponsors/ljharb" 6525 + } 6526 + }, 6527 + "node_modules/svgo": { 6528 + "version": "4.0.2", 6529 + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.2.tgz", 6530 + "integrity": "sha512-ekx94z1rRc5LDi6oSUaeRnYhd0UOJxdtQCL2rF8xpWxD3TPAsISWOrxezqGovqS38GRZOdpDfvQe3ts6F7nsng==", 6531 + "license": "MIT", 6532 + "dependencies": { 6533 + "commander": "^11.1.0", 6534 + "css-select": "^5.1.0", 6535 + "css-tree": "^3.0.1", 6536 + "css-what": "^6.1.0", 6537 + "csso": "^5.0.5", 6538 + "picocolors": "^1.1.1", 6539 + "sax": "^1.5.0" 6540 + }, 6541 + "bin": { 6542 + "svgo": "bin/svgo.js" 6543 + }, 6544 + "engines": { 6545 + "node": ">=16" 6546 + }, 6547 + "funding": { 6548 + "type": "opencollective", 6549 + "url": "https://opencollective.com/svgo" 6550 + } 6551 + }, 6552 + "node_modules/tailwindcss": { 6553 + "version": "3.4.19", 6554 + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", 6555 + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", 6556 + "dev": true, 6557 + "license": "MIT", 6558 + "dependencies": { 6559 + "@alloc/quick-lru": "^5.2.0", 6560 + "arg": "^5.0.2", 6561 + "chokidar": "^3.6.0", 6562 + "didyoumean": "^1.2.2", 6563 + "dlv": "^1.1.3", 6564 + "fast-glob": "^3.3.2", 6565 + "glob-parent": "^6.0.2", 6566 + "is-glob": "^4.0.3", 6567 + "jiti": "^1.21.7", 6568 + "lilconfig": "^3.1.3", 6569 + "micromatch": "^4.0.8", 6570 + "normalize-path": "^3.0.0", 6571 + "object-hash": "^3.0.0", 6572 + "picocolors": "^1.1.1", 6573 + "postcss": "^8.4.47", 6574 + "postcss-import": "^15.1.0", 6575 + "postcss-js": "^4.0.1", 6576 + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", 6577 + "postcss-nested": "^6.2.0", 6578 + "postcss-selector-parser": "^6.1.2", 6579 + "resolve": "^1.22.8", 6580 + "sucrase": "^3.35.0" 6581 + }, 6582 + "bin": { 6583 + "tailwind": "lib/cli.js", 6584 + "tailwindcss": "lib/cli.js" 6585 + }, 6586 + "engines": { 6587 + "node": ">=14.0.0" 6588 + } 6589 + }, 6590 + "node_modules/tailwindcss/node_modules/chokidar": { 6591 + "version": "3.6.0", 6592 + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", 6593 + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", 6594 + "dev": true, 6595 + "license": "MIT", 6596 + "dependencies": { 6597 + "anymatch": "~3.1.2", 6598 + "braces": "~3.0.2", 6599 + "glob-parent": "~5.1.2", 6600 + "is-binary-path": "~2.1.0", 6601 + "is-glob": "~4.0.1", 6602 + "normalize-path": "~3.0.0", 6603 + "readdirp": "~3.6.0" 6604 + }, 6605 + "engines": { 6606 + "node": ">= 8.10.0" 6607 + }, 6608 + "funding": { 6609 + "url": "https://paulmillr.com/funding/" 6610 + }, 6611 + "optionalDependencies": { 6612 + "fsevents": "~2.3.2" 6613 + } 6614 + }, 6615 + "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": { 6616 + "version": "5.1.2", 6617 + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 6618 + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 6619 + "dev": true, 6620 + "license": "ISC", 6621 + "dependencies": { 6622 + "is-glob": "^4.0.1" 6623 + }, 6624 + "engines": { 6625 + "node": ">= 6" 6626 + } 6627 + }, 6628 + "node_modules/tailwindcss/node_modules/picomatch": { 6629 + "version": "2.3.2", 6630 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", 6631 + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", 6632 + "dev": true, 6633 + "license": "MIT", 6634 + "engines": { 6635 + "node": ">=8.6" 6636 + }, 6637 + "funding": { 6638 + "url": "https://github.com/sponsors/jonschlinkert" 6639 + } 6640 + }, 6641 + "node_modules/tailwindcss/node_modules/readdirp": { 6642 + "version": "3.6.0", 6643 + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 6644 + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 6645 + "dev": true, 6646 + "license": "MIT", 6647 + "dependencies": { 6648 + "picomatch": "^2.2.1" 6649 + }, 6650 + "engines": { 6651 + "node": ">=8.10.0" 6652 + } 6653 + }, 6654 + "node_modules/thenify": { 6655 + "version": "3.3.1", 6656 + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", 6657 + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", 6658 + "dev": true, 6659 + "license": "MIT", 6660 + "dependencies": { 6661 + "any-promise": "^1.0.0" 6662 + } 6663 + }, 6664 + "node_modules/thenify-all": { 6665 + "version": "1.6.0", 6666 + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", 6667 + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", 6668 + "dev": true, 6669 + "license": "MIT", 6670 + "dependencies": { 6671 + "thenify": ">= 3.1.0 < 4" 6672 + }, 6673 + "engines": { 6674 + "node": ">=0.8" 6675 + } 6676 + }, 6677 + "node_modules/tiny-inflate": { 6678 + "version": "1.0.3", 6679 + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", 6680 + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", 6681 + "license": "MIT" 6682 + }, 6683 + "node_modules/tinyexec": { 6684 + "version": "1.2.4", 6685 + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", 6686 + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", 6687 + "license": "MIT", 6688 + "engines": { 6689 + "node": ">=18" 6690 + } 6691 + }, 6692 + "node_modules/tinyglobby": { 6693 + "version": "0.2.17", 6694 + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", 6695 + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", 6696 + "license": "MIT", 6697 + "dependencies": { 6698 + "fdir": "^6.5.0", 6699 + "picomatch": "^4.0.4" 6700 + }, 6701 + "engines": { 6702 + "node": ">=12.0.0" 6703 + }, 6704 + "funding": { 6705 + "url": "https://github.com/sponsors/SuperchupuDev" 6706 + } 6707 + }, 6708 + "node_modules/to-regex-range": { 6709 + "version": "5.0.1", 6710 + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 6711 + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 6712 + "dev": true, 6713 + "license": "MIT", 6714 + "dependencies": { 6715 + "is-number": "^7.0.0" 6716 + }, 6717 + "engines": { 6718 + "node": ">=8.0" 6719 + } 6720 + }, 6721 + "node_modules/trim-lines": { 6722 + "version": "3.0.1", 6723 + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", 6724 + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", 6725 + "license": "MIT", 6726 + "funding": { 6727 + "type": "github", 6728 + "url": "https://github.com/sponsors/wooorm" 6729 + } 6730 + }, 6731 + "node_modules/trough": { 6732 + "version": "2.2.0", 6733 + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", 6734 + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", 6735 + "license": "MIT", 6736 + "funding": { 6737 + "type": "github", 6738 + "url": "https://github.com/sponsors/wooorm" 6739 + } 6740 + }, 6741 + "node_modules/ts-interface-checker": { 6742 + "version": "0.1.13", 6743 + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", 6744 + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", 6745 + "dev": true, 6746 + "license": "Apache-2.0" 6747 + }, 6748 + "node_modules/tsconfck": { 6749 + "version": "3.1.6", 6750 + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", 6751 + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", 6752 + "deprecated": "unmaintained", 6753 + "license": "MIT", 6754 + "bin": { 6755 + "tsconfck": "bin/tsconfck.js" 6756 + }, 6757 + "engines": { 6758 + "node": "^18 || >=20" 6759 + }, 6760 + "peerDependencies": { 6761 + "typescript": "^5.0.0" 6762 + }, 6763 + "peerDependenciesMeta": { 6764 + "typescript": { 6765 + "optional": true 6766 + } 6767 + } 6768 + }, 6769 + "node_modules/tslib": { 6770 + "version": "2.8.1", 6771 + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", 6772 + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", 6773 + "license": "0BSD", 6774 + "optional": true 6775 + }, 6776 + "node_modules/type-fest": { 6777 + "version": "4.41.0", 6778 + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", 6779 + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", 6780 + "license": "(MIT OR CC0-1.0)", 6781 + "engines": { 6782 + "node": ">=16" 6783 + }, 6784 + "funding": { 6785 + "url": "https://github.com/sponsors/sindresorhus" 6786 + } 6787 + }, 6788 + "node_modules/typescript": { 6789 + "version": "5.9.3", 6790 + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", 6791 + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", 6792 + "license": "Apache-2.0", 6793 + "peer": true, 6794 + "bin": { 6795 + "tsc": "bin/tsc", 6796 + "tsserver": "bin/tsserver" 6797 + }, 6798 + "engines": { 6799 + "node": ">=14.17" 6800 + } 6801 + }, 6802 + "node_modules/ufo": { 6803 + "version": "1.6.4", 6804 + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", 6805 + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", 6806 + "license": "MIT" 6807 + }, 6808 + "node_modules/ultrahtml": { 6809 + "version": "1.7.0", 6810 + "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.7.0.tgz", 6811 + "integrity": "sha512-2xRd0VHoAQE4M+vF/DvFFB7pUV0ZxTW1TLi7lHQWnF/Sb5TPeEUV/l+hxcNnGO00ZXGnR0voCMmYRKQf+rvJ2g==", 6812 + "license": "MIT" 6813 + }, 6814 + "node_modules/uncrypto": { 6815 + "version": "0.1.3", 6816 + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", 6817 + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", 6818 + "license": "MIT" 6819 + }, 6820 + "node_modules/undici-types": { 6821 + "version": "7.18.2", 6822 + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", 6823 + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", 6824 + "license": "MIT" 6825 + }, 6826 + "node_modules/unified": { 6827 + "version": "11.0.5", 6828 + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", 6829 + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", 6830 + "license": "MIT", 6831 + "dependencies": { 6832 + "@types/unist": "^3.0.0", 6833 + "bail": "^2.0.0", 6834 + "devlop": "^1.0.0", 6835 + "extend": "^3.0.0", 6836 + "is-plain-obj": "^4.0.0", 6837 + "trough": "^2.0.0", 6838 + "vfile": "^6.0.0" 6839 + }, 6840 + "funding": { 6841 + "type": "opencollective", 6842 + "url": "https://opencollective.com/unified" 6843 + } 6844 + }, 6845 + "node_modules/unifont": { 6846 + "version": "0.7.4", 6847 + "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.4.tgz", 6848 + "integrity": "sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==", 6849 + "license": "MIT", 6850 + "dependencies": { 6851 + "css-tree": "^3.1.0", 6852 + "ofetch": "^1.5.1", 6853 + "ohash": "^2.0.11" 6854 + } 6855 + }, 6856 + "node_modules/unist-util-find-after": { 6857 + "version": "5.0.0", 6858 + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", 6859 + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", 6860 + "license": "MIT", 6861 + "dependencies": { 6862 + "@types/unist": "^3.0.0", 6863 + "unist-util-is": "^6.0.0" 6864 + }, 6865 + "funding": { 6866 + "type": "opencollective", 6867 + "url": "https://opencollective.com/unified" 6868 + } 6869 + }, 6870 + "node_modules/unist-util-is": { 6871 + "version": "6.0.1", 6872 + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", 6873 + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", 6874 + "license": "MIT", 6875 + "dependencies": { 6876 + "@types/unist": "^3.0.0" 6877 + }, 6878 + "funding": { 6879 + "type": "opencollective", 6880 + "url": "https://opencollective.com/unified" 6881 + } 6882 + }, 6883 + "node_modules/unist-util-modify-children": { 6884 + "version": "4.0.0", 6885 + "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-4.0.0.tgz", 6886 + "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==", 6887 + "license": "MIT", 6888 + "dependencies": { 6889 + "@types/unist": "^3.0.0", 6890 + "array-iterate": "^2.0.0" 6891 + }, 6892 + "funding": { 6893 + "type": "opencollective", 6894 + "url": "https://opencollective.com/unified" 6895 + } 6896 + }, 6897 + "node_modules/unist-util-position": { 6898 + "version": "5.0.0", 6899 + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", 6900 + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", 6901 + "license": "MIT", 6902 + "dependencies": { 6903 + "@types/unist": "^3.0.0" 6904 + }, 6905 + "funding": { 6906 + "type": "opencollective", 6907 + "url": "https://opencollective.com/unified" 6908 + } 6909 + }, 6910 + "node_modules/unist-util-position-from-estree": { 6911 + "version": "2.0.0", 6912 + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", 6913 + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", 6914 + "license": "MIT", 6915 + "dependencies": { 6916 + "@types/unist": "^3.0.0" 6917 + }, 6918 + "funding": { 6919 + "type": "opencollective", 6920 + "url": "https://opencollective.com/unified" 6921 + } 6922 + }, 6923 + "node_modules/unist-util-remove-position": { 6924 + "version": "5.0.0", 6925 + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", 6926 + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", 6927 + "license": "MIT", 6928 + "dependencies": { 6929 + "@types/unist": "^3.0.0", 6930 + "unist-util-visit": "^5.0.0" 6931 + }, 6932 + "funding": { 6933 + "type": "opencollective", 6934 + "url": "https://opencollective.com/unified" 6935 + } 6936 + }, 6937 + "node_modules/unist-util-stringify-position": { 6938 + "version": "4.0.0", 6939 + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", 6940 + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", 6941 + "license": "MIT", 6942 + "dependencies": { 6943 + "@types/unist": "^3.0.0" 6944 + }, 6945 + "funding": { 6946 + "type": "opencollective", 6947 + "url": "https://opencollective.com/unified" 6948 + } 6949 + }, 6950 + "node_modules/unist-util-visit": { 6951 + "version": "5.1.0", 6952 + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", 6953 + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", 6954 + "license": "MIT", 6955 + "dependencies": { 6956 + "@types/unist": "^3.0.0", 6957 + "unist-util-is": "^6.0.0", 6958 + "unist-util-visit-parents": "^6.0.0" 6959 + }, 6960 + "funding": { 6961 + "type": "opencollective", 6962 + "url": "https://opencollective.com/unified" 6963 + } 6964 + }, 6965 + "node_modules/unist-util-visit-children": { 6966 + "version": "3.0.0", 6967 + "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-3.0.0.tgz", 6968 + "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==", 6969 + "license": "MIT", 6970 + "dependencies": { 6971 + "@types/unist": "^3.0.0" 6972 + }, 6973 + "funding": { 6974 + "type": "opencollective", 6975 + "url": "https://opencollective.com/unified" 6976 + } 6977 + }, 6978 + "node_modules/unist-util-visit-parents": { 6979 + "version": "6.0.2", 6980 + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", 6981 + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", 6982 + "license": "MIT", 6983 + "dependencies": { 6984 + "@types/unist": "^3.0.0", 6985 + "unist-util-is": "^6.0.0" 6986 + }, 6987 + "funding": { 6988 + "type": "opencollective", 6989 + "url": "https://opencollective.com/unified" 6990 + } 6991 + }, 6992 + "node_modules/unstorage": { 6993 + "version": "1.17.5", 6994 + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.5.tgz", 6995 + "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==", 6996 + "license": "MIT", 6997 + "dependencies": { 6998 + "anymatch": "^3.1.3", 6999 + "chokidar": "^5.0.0", 7000 + "destr": "^2.0.5", 7001 + "h3": "^1.15.10", 7002 + "lru-cache": "^11.2.7", 7003 + "node-fetch-native": "^1.6.7", 7004 + "ofetch": "^1.5.1", 7005 + "ufo": "^1.6.3" 7006 + }, 7007 + "peerDependencies": { 7008 + "@azure/app-configuration": "^1.8.0", 7009 + "@azure/cosmos": "^4.2.0", 7010 + "@azure/data-tables": "^13.3.0", 7011 + "@azure/identity": "^4.6.0", 7012 + "@azure/keyvault-secrets": "^4.9.0", 7013 + "@azure/storage-blob": "^12.26.0", 7014 + "@capacitor/preferences": "^6 || ^7 || ^8", 7015 + "@deno/kv": ">=0.9.0", 7016 + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", 7017 + "@planetscale/database": "^1.19.0", 7018 + "@upstash/redis": "^1.34.3", 7019 + "@vercel/blob": ">=0.27.1", 7020 + "@vercel/functions": "^2.2.12 || ^3.0.0", 7021 + "@vercel/kv": "^1 || ^2 || ^3", 7022 + "aws4fetch": "^1.0.20", 7023 + "db0": ">=0.2.1", 7024 + "idb-keyval": "^6.2.1", 7025 + "ioredis": "^5.4.2", 7026 + "uploadthing": "^7.4.4" 7027 + }, 7028 + "peerDependenciesMeta": { 7029 + "@azure/app-configuration": { 7030 + "optional": true 7031 + }, 7032 + "@azure/cosmos": { 7033 + "optional": true 7034 + }, 7035 + "@azure/data-tables": { 7036 + "optional": true 7037 + }, 7038 + "@azure/identity": { 7039 + "optional": true 7040 + }, 7041 + "@azure/keyvault-secrets": { 7042 + "optional": true 7043 + }, 7044 + "@azure/storage-blob": { 7045 + "optional": true 7046 + }, 7047 + "@capacitor/preferences": { 7048 + "optional": true 7049 + }, 7050 + "@deno/kv": { 7051 + "optional": true 7052 + }, 7053 + "@netlify/blobs": { 7054 + "optional": true 7055 + }, 7056 + "@planetscale/database": { 7057 + "optional": true 7058 + }, 7059 + "@upstash/redis": { 7060 + "optional": true 7061 + }, 7062 + "@vercel/blob": { 7063 + "optional": true 7064 + }, 7065 + "@vercel/functions": { 7066 + "optional": true 7067 + }, 7068 + "@vercel/kv": { 7069 + "optional": true 7070 + }, 7071 + "aws4fetch": { 7072 + "optional": true 7073 + }, 7074 + "db0": { 7075 + "optional": true 7076 + }, 7077 + "idb-keyval": { 7078 + "optional": true 7079 + }, 7080 + "ioredis": { 7081 + "optional": true 7082 + }, 7083 + "uploadthing": { 7084 + "optional": true 7085 + } 7086 + } 7087 + }, 7088 + "node_modules/util-deprecate": { 7089 + "version": "1.0.2", 7090 + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 7091 + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 7092 + "license": "MIT" 7093 + }, 7094 + "node_modules/vfile": { 7095 + "version": "6.0.3", 7096 + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", 7097 + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", 7098 + "license": "MIT", 7099 + "dependencies": { 7100 + "@types/unist": "^3.0.0", 7101 + "vfile-message": "^4.0.0" 7102 + }, 7103 + "funding": { 7104 + "type": "opencollective", 7105 + "url": "https://opencollective.com/unified" 7106 + } 7107 + }, 7108 + "node_modules/vfile-location": { 7109 + "version": "5.0.3", 7110 + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", 7111 + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", 7112 + "license": "MIT", 7113 + "dependencies": { 7114 + "@types/unist": "^3.0.0", 7115 + "vfile": "^6.0.0" 7116 + }, 7117 + "funding": { 7118 + "type": "opencollective", 7119 + "url": "https://opencollective.com/unified" 7120 + } 7121 + }, 7122 + "node_modules/vfile-message": { 7123 + "version": "4.0.3", 7124 + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", 7125 + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", 7126 + "license": "MIT", 7127 + "dependencies": { 7128 + "@types/unist": "^3.0.0", 7129 + "unist-util-stringify-position": "^4.0.0" 7130 + }, 7131 + "funding": { 7132 + "type": "opencollective", 7133 + "url": "https://opencollective.com/unified" 7134 + } 7135 + }, 7136 + "node_modules/vite": { 7137 + "version": "6.4.3", 7138 + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", 7139 + "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", 7140 + "license": "MIT", 7141 + "dependencies": { 7142 + "esbuild": "^0.25.0", 7143 + "fdir": "^6.4.4", 7144 + "picomatch": "^4.0.2", 7145 + "postcss": "^8.5.3", 7146 + "rollup": "^4.34.9", 7147 + "tinyglobby": "^0.2.13" 7148 + }, 7149 + "bin": { 7150 + "vite": "bin/vite.js" 7151 + }, 7152 + "engines": { 7153 + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" 7154 + }, 7155 + "funding": { 7156 + "url": "https://github.com/vitejs/vite?sponsor=1" 7157 + }, 7158 + "optionalDependencies": { 7159 + "fsevents": "~2.3.3" 7160 + }, 7161 + "peerDependencies": { 7162 + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", 7163 + "jiti": ">=1.21.0", 7164 + "less": "*", 7165 + "lightningcss": "^1.21.0", 7166 + "sass": "*", 7167 + "sass-embedded": "*", 7168 + "stylus": "*", 7169 + "sugarss": "*", 7170 + "terser": "^5.16.0", 7171 + "tsx": "^4.8.1", 7172 + "yaml": "^2.4.2" 7173 + }, 7174 + "peerDependenciesMeta": { 7175 + "@types/node": { 7176 + "optional": true 7177 + }, 7178 + "jiti": { 7179 + "optional": true 7180 + }, 7181 + "less": { 7182 + "optional": true 7183 + }, 7184 + "lightningcss": { 7185 + "optional": true 7186 + }, 7187 + "sass": { 7188 + "optional": true 7189 + }, 7190 + "sass-embedded": { 7191 + "optional": true 7192 + }, 7193 + "stylus": { 7194 + "optional": true 7195 + }, 7196 + "sugarss": { 7197 + "optional": true 7198 + }, 7199 + "terser": { 7200 + "optional": true 7201 + }, 7202 + "tsx": { 7203 + "optional": true 7204 + }, 7205 + "yaml": { 7206 + "optional": true 7207 + } 7208 + } 7209 + }, 7210 + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { 7211 + "version": "0.25.12", 7212 + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", 7213 + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", 7214 + "cpu": [ 7215 + "ppc64" 7216 + ], 7217 + "license": "MIT", 7218 + "optional": true, 7219 + "os": [ 7220 + "aix" 7221 + ], 7222 + "engines": { 7223 + "node": ">=18" 7224 + } 7225 + }, 7226 + "node_modules/vite/node_modules/@esbuild/android-arm": { 7227 + "version": "0.25.12", 7228 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", 7229 + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", 7230 + "cpu": [ 7231 + "arm" 7232 + ], 7233 + "license": "MIT", 7234 + "optional": true, 7235 + "os": [ 7236 + "android" 7237 + ], 7238 + "engines": { 7239 + "node": ">=18" 7240 + } 7241 + }, 7242 + "node_modules/vite/node_modules/@esbuild/android-arm64": { 7243 + "version": "0.25.12", 7244 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", 7245 + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", 7246 + "cpu": [ 7247 + "arm64" 7248 + ], 7249 + "license": "MIT", 7250 + "optional": true, 7251 + "os": [ 7252 + "android" 7253 + ], 7254 + "engines": { 7255 + "node": ">=18" 7256 + } 7257 + }, 7258 + "node_modules/vite/node_modules/@esbuild/android-x64": { 7259 + "version": "0.25.12", 7260 + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", 7261 + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", 7262 + "cpu": [ 7263 + "x64" 7264 + ], 7265 + "license": "MIT", 7266 + "optional": true, 7267 + "os": [ 7268 + "android" 7269 + ], 7270 + "engines": { 7271 + "node": ">=18" 7272 + } 7273 + }, 7274 + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { 7275 + "version": "0.25.12", 7276 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", 7277 + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", 7278 + "cpu": [ 7279 + "arm64" 7280 + ], 7281 + "license": "MIT", 7282 + "optional": true, 7283 + "os": [ 7284 + "darwin" 7285 + ], 7286 + "engines": { 7287 + "node": ">=18" 7288 + } 7289 + }, 7290 + "node_modules/vite/node_modules/@esbuild/darwin-x64": { 7291 + "version": "0.25.12", 7292 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", 7293 + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", 7294 + "cpu": [ 7295 + "x64" 7296 + ], 7297 + "license": "MIT", 7298 + "optional": true, 7299 + "os": [ 7300 + "darwin" 7301 + ], 7302 + "engines": { 7303 + "node": ">=18" 7304 + } 7305 + }, 7306 + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { 7307 + "version": "0.25.12", 7308 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", 7309 + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", 7310 + "cpu": [ 7311 + "arm64" 7312 + ], 7313 + "license": "MIT", 7314 + "optional": true, 7315 + "os": [ 7316 + "freebsd" 7317 + ], 7318 + "engines": { 7319 + "node": ">=18" 7320 + } 7321 + }, 7322 + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { 7323 + "version": "0.25.12", 7324 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", 7325 + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", 7326 + "cpu": [ 7327 + "x64" 7328 + ], 7329 + "license": "MIT", 7330 + "optional": true, 7331 + "os": [ 7332 + "freebsd" 7333 + ], 7334 + "engines": { 7335 + "node": ">=18" 7336 + } 7337 + }, 7338 + "node_modules/vite/node_modules/@esbuild/linux-arm": { 7339 + "version": "0.25.12", 7340 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", 7341 + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", 7342 + "cpu": [ 7343 + "arm" 7344 + ], 7345 + "license": "MIT", 7346 + "optional": true, 7347 + "os": [ 7348 + "linux" 7349 + ], 7350 + "engines": { 7351 + "node": ">=18" 7352 + } 7353 + }, 7354 + "node_modules/vite/node_modules/@esbuild/linux-arm64": { 7355 + "version": "0.25.12", 7356 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", 7357 + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", 7358 + "cpu": [ 7359 + "arm64" 7360 + ], 7361 + "license": "MIT", 7362 + "optional": true, 7363 + "os": [ 7364 + "linux" 7365 + ], 7366 + "engines": { 7367 + "node": ">=18" 7368 + } 7369 + }, 7370 + "node_modules/vite/node_modules/@esbuild/linux-ia32": { 7371 + "version": "0.25.12", 7372 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", 7373 + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", 7374 + "cpu": [ 7375 + "ia32" 7376 + ], 7377 + "license": "MIT", 7378 + "optional": true, 7379 + "os": [ 7380 + "linux" 7381 + ], 7382 + "engines": { 7383 + "node": ">=18" 7384 + } 7385 + }, 7386 + "node_modules/vite/node_modules/@esbuild/linux-loong64": { 7387 + "version": "0.25.12", 7388 + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", 7389 + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", 7390 + "cpu": [ 7391 + "loong64" 7392 + ], 7393 + "license": "MIT", 7394 + "optional": true, 7395 + "os": [ 7396 + "linux" 7397 + ], 7398 + "engines": { 7399 + "node": ">=18" 7400 + } 7401 + }, 7402 + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { 7403 + "version": "0.25.12", 7404 + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", 7405 + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", 7406 + "cpu": [ 7407 + "mips64el" 7408 + ], 7409 + "license": "MIT", 7410 + "optional": true, 7411 + "os": [ 7412 + "linux" 7413 + ], 7414 + "engines": { 7415 + "node": ">=18" 7416 + } 7417 + }, 7418 + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { 7419 + "version": "0.25.12", 7420 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", 7421 + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", 7422 + "cpu": [ 7423 + "ppc64" 7424 + ], 7425 + "license": "MIT", 7426 + "optional": true, 7427 + "os": [ 7428 + "linux" 7429 + ], 7430 + "engines": { 7431 + "node": ">=18" 7432 + } 7433 + }, 7434 + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { 7435 + "version": "0.25.12", 7436 + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", 7437 + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", 7438 + "cpu": [ 7439 + "riscv64" 7440 + ], 7441 + "license": "MIT", 7442 + "optional": true, 7443 + "os": [ 7444 + "linux" 7445 + ], 7446 + "engines": { 7447 + "node": ">=18" 7448 + } 7449 + }, 7450 + "node_modules/vite/node_modules/@esbuild/linux-s390x": { 7451 + "version": "0.25.12", 7452 + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", 7453 + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", 7454 + "cpu": [ 7455 + "s390x" 7456 + ], 7457 + "license": "MIT", 7458 + "optional": true, 7459 + "os": [ 7460 + "linux" 7461 + ], 7462 + "engines": { 7463 + "node": ">=18" 7464 + } 7465 + }, 7466 + "node_modules/vite/node_modules/@esbuild/linux-x64": { 7467 + "version": "0.25.12", 7468 + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", 7469 + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", 7470 + "cpu": [ 7471 + "x64" 7472 + ], 7473 + "license": "MIT", 7474 + "optional": true, 7475 + "os": [ 7476 + "linux" 7477 + ], 7478 + "engines": { 7479 + "node": ">=18" 7480 + } 7481 + }, 7482 + "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { 7483 + "version": "0.25.12", 7484 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", 7485 + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", 7486 + "cpu": [ 7487 + "arm64" 7488 + ], 7489 + "license": "MIT", 7490 + "optional": true, 7491 + "os": [ 7492 + "netbsd" 7493 + ], 7494 + "engines": { 7495 + "node": ">=18" 7496 + } 7497 + }, 7498 + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { 7499 + "version": "0.25.12", 7500 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", 7501 + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", 7502 + "cpu": [ 7503 + "x64" 7504 + ], 7505 + "license": "MIT", 7506 + "optional": true, 7507 + "os": [ 7508 + "netbsd" 7509 + ], 7510 + "engines": { 7511 + "node": ">=18" 7512 + } 7513 + }, 7514 + "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { 7515 + "version": "0.25.12", 7516 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", 7517 + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", 7518 + "cpu": [ 7519 + "arm64" 7520 + ], 7521 + "license": "MIT", 7522 + "optional": true, 7523 + "os": [ 7524 + "openbsd" 7525 + ], 7526 + "engines": { 7527 + "node": ">=18" 7528 + } 7529 + }, 7530 + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { 7531 + "version": "0.25.12", 7532 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", 7533 + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", 7534 + "cpu": [ 7535 + "x64" 7536 + ], 7537 + "license": "MIT", 7538 + "optional": true, 7539 + "os": [ 7540 + "openbsd" 7541 + ], 7542 + "engines": { 7543 + "node": ">=18" 7544 + } 7545 + }, 7546 + "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { 7547 + "version": "0.25.12", 7548 + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", 7549 + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", 7550 + "cpu": [ 7551 + "arm64" 7552 + ], 7553 + "license": "MIT", 7554 + "optional": true, 7555 + "os": [ 7556 + "openharmony" 7557 + ], 7558 + "engines": { 7559 + "node": ">=18" 7560 + } 7561 + }, 7562 + "node_modules/vite/node_modules/@esbuild/sunos-x64": { 7563 + "version": "0.25.12", 7564 + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", 7565 + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", 7566 + "cpu": [ 7567 + "x64" 7568 + ], 7569 + "license": "MIT", 7570 + "optional": true, 7571 + "os": [ 7572 + "sunos" 7573 + ], 7574 + "engines": { 7575 + "node": ">=18" 7576 + } 7577 + }, 7578 + "node_modules/vite/node_modules/@esbuild/win32-arm64": { 7579 + "version": "0.25.12", 7580 + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", 7581 + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", 7582 + "cpu": [ 7583 + "arm64" 7584 + ], 7585 + "license": "MIT", 7586 + "optional": true, 7587 + "os": [ 7588 + "win32" 7589 + ], 7590 + "engines": { 7591 + "node": ">=18" 7592 + } 7593 + }, 7594 + "node_modules/vite/node_modules/@esbuild/win32-ia32": { 7595 + "version": "0.25.12", 7596 + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", 7597 + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", 7598 + "cpu": [ 7599 + "ia32" 7600 + ], 7601 + "license": "MIT", 7602 + "optional": true, 7603 + "os": [ 7604 + "win32" 7605 + ], 7606 + "engines": { 7607 + "node": ">=18" 7608 + } 7609 + }, 7610 + "node_modules/vite/node_modules/@esbuild/win32-x64": { 7611 + "version": "0.25.12", 7612 + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", 7613 + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", 7614 + "cpu": [ 7615 + "x64" 7616 + ], 7617 + "license": "MIT", 7618 + "optional": true, 7619 + "os": [ 7620 + "win32" 7621 + ], 7622 + "engines": { 7623 + "node": ">=18" 7624 + } 7625 + }, 7626 + "node_modules/vite/node_modules/esbuild": { 7627 + "version": "0.25.12", 7628 + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", 7629 + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", 7630 + "hasInstallScript": true, 7631 + "license": "MIT", 7632 + "bin": { 7633 + "esbuild": "bin/esbuild" 7634 + }, 7635 + "engines": { 7636 + "node": ">=18" 7637 + }, 7638 + "optionalDependencies": { 7639 + "@esbuild/aix-ppc64": "0.25.12", 7640 + "@esbuild/android-arm": "0.25.12", 7641 + "@esbuild/android-arm64": "0.25.12", 7642 + "@esbuild/android-x64": "0.25.12", 7643 + "@esbuild/darwin-arm64": "0.25.12", 7644 + "@esbuild/darwin-x64": "0.25.12", 7645 + "@esbuild/freebsd-arm64": "0.25.12", 7646 + "@esbuild/freebsd-x64": "0.25.12", 7647 + "@esbuild/linux-arm": "0.25.12", 7648 + "@esbuild/linux-arm64": "0.25.12", 7649 + "@esbuild/linux-ia32": "0.25.12", 7650 + "@esbuild/linux-loong64": "0.25.12", 7651 + "@esbuild/linux-mips64el": "0.25.12", 7652 + "@esbuild/linux-ppc64": "0.25.12", 7653 + "@esbuild/linux-riscv64": "0.25.12", 7654 + "@esbuild/linux-s390x": "0.25.12", 7655 + "@esbuild/linux-x64": "0.25.12", 7656 + "@esbuild/netbsd-arm64": "0.25.12", 7657 + "@esbuild/netbsd-x64": "0.25.12", 7658 + "@esbuild/openbsd-arm64": "0.25.12", 7659 + "@esbuild/openbsd-x64": "0.25.12", 7660 + "@esbuild/openharmony-arm64": "0.25.12", 7661 + "@esbuild/sunos-x64": "0.25.12", 7662 + "@esbuild/win32-arm64": "0.25.12", 7663 + "@esbuild/win32-ia32": "0.25.12", 7664 + "@esbuild/win32-x64": "0.25.12" 7665 + } 7666 + }, 7667 + "node_modules/vitefu": { 7668 + "version": "1.1.3", 7669 + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz", 7670 + "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==", 7671 + "license": "MIT", 7672 + "workspaces": [ 7673 + "tests/deps/*", 7674 + "tests/projects/*", 7675 + "tests/projects/workspace/packages/*" 7676 + ], 7677 + "peerDependencies": { 7678 + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" 7679 + }, 7680 + "peerDependenciesMeta": { 7681 + "vite": { 7682 + "optional": true 7683 + } 7684 + } 7685 + }, 7686 + "node_modules/web-namespaces": { 7687 + "version": "2.0.1", 7688 + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", 7689 + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", 7690 + "license": "MIT", 7691 + "funding": { 7692 + "type": "github", 7693 + "url": "https://github.com/sponsors/wooorm" 7694 + } 7695 + }, 7696 + "node_modules/which-pm-runs": { 7697 + "version": "1.1.0", 7698 + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", 7699 + "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", 7700 + "license": "MIT", 7701 + "engines": { 7702 + "node": ">=4" 7703 + } 7704 + }, 7705 + "node_modules/widest-line": { 7706 + "version": "5.0.0", 7707 + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz", 7708 + "integrity": "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==", 7709 + "license": "MIT", 7710 + "dependencies": { 7711 + "string-width": "^7.0.0" 7712 + }, 7713 + "engines": { 7714 + "node": ">=18" 7715 + }, 7716 + "funding": { 7717 + "url": "https://github.com/sponsors/sindresorhus" 7718 + } 7719 + }, 7720 + "node_modules/wrap-ansi": { 7721 + "version": "9.0.2", 7722 + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", 7723 + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", 7724 + "license": "MIT", 7725 + "dependencies": { 7726 + "ansi-styles": "^6.2.1", 7727 + "string-width": "^7.0.0", 7728 + "strip-ansi": "^7.1.0" 7729 + }, 7730 + "engines": { 7731 + "node": ">=18" 7732 + }, 7733 + "funding": { 7734 + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 7735 + } 7736 + }, 7737 + "node_modules/xxhash-wasm": { 7738 + "version": "1.1.0", 7739 + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", 7740 + "integrity": "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==", 7741 + "license": "MIT" 7742 + }, 7743 + "node_modules/yargs-parser": { 7744 + "version": "21.1.1", 7745 + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", 7746 + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", 7747 + "license": "ISC", 7748 + "engines": { 7749 + "node": ">=12" 7750 + } 7751 + }, 7752 + "node_modules/yocto-queue": { 7753 + "version": "1.2.2", 7754 + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", 7755 + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", 7756 + "license": "MIT", 7757 + "engines": { 7758 + "node": ">=12.20" 7759 + }, 7760 + "funding": { 7761 + "url": "https://github.com/sponsors/sindresorhus" 7762 + } 7763 + }, 7764 + "node_modules/yocto-spinner": { 7765 + "version": "0.2.3", 7766 + "resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-0.2.3.tgz", 7767 + "integrity": "sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==", 7768 + "license": "MIT", 7769 + "dependencies": { 7770 + "yoctocolors": "^2.1.1" 7771 + }, 7772 + "engines": { 7773 + "node": ">=18.19" 7774 + }, 7775 + "funding": { 7776 + "url": "https://github.com/sponsors/sindresorhus" 7777 + } 7778 + }, 7779 + "node_modules/yoctocolors": { 7780 + "version": "2.1.2", 7781 + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", 7782 + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", 7783 + "license": "MIT", 7784 + "engines": { 7785 + "node": ">=18" 7786 + }, 7787 + "funding": { 7788 + "url": "https://github.com/sponsors/sindresorhus" 7789 + } 7790 + }, 7791 + "node_modules/zod": { 7792 + "version": "4.4.3", 7793 + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", 7794 + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", 7795 + "license": "MIT", 7796 + "funding": { 7797 + "url": "https://github.com/sponsors/colinhacks" 7798 + } 7799 + }, 7800 + "node_modules/zod-to-json-schema": { 7801 + "version": "3.25.2", 7802 + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", 7803 + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", 7804 + "license": "ISC", 7805 + "peerDependencies": { 7806 + "zod": "^3.25.28 || ^4" 7807 + } 7808 + }, 7809 + "node_modules/zwitch": { 7810 + "version": "2.0.4", 7811 + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", 7812 + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", 7813 + "license": "MIT", 7814 + "funding": { 7815 + "type": "github", 7816 + "url": "https://github.com/sponsors/wooorm" 7817 + } 7818 + } 7819 + } 7820 + }
+23
docs/package.json
··· 1 + { 2 + "name": "tangled-docs", 3 + "type": "module", 4 + "version": "0.0.1", 5 + "private": true, 6 + "scripts": { 7 + "dev": "astro dev", 8 + "build": "astro build", 9 + "preview": "astro preview" 10 + }, 11 + "dependencies": { 12 + "@astrojs/starlight": "^0.36.0", 13 + "@fontsource-variable/inter": "^5.2.5", 14 + "@fontsource/ibm-plex-mono": "^5.2.5", 15 + "astro": "^5.14.0", 16 + "lucide-astro": "^0.545.0", 17 + "sharp": "^0.34.0" 18 + }, 19 + "devDependencies": { 20 + "@tailwindcss/typography": "^0.5.20", 21 + "tailwindcss": "^3.4.19" 22 + } 23 + }
+5
docs/postcss.config.cjs
··· 1 + module.exports = { 2 + plugins: { 3 + tailwindcss: { config: "./tailwind.config.cjs" }, 4 + }, 5 + };
+12
docs/public/_redirects
··· 1 + # redirects from the old pandoc-generated pages 2 + /quick-start-guide.html /quick-start/ 301 3 + /hosting-websites-on-tangled.html /sites/ 301 4 + /knot-self-hosting-guide.html /knots/self-hosting/ 301 5 + /spindles.html /spindles/workflows/ 301 6 + /webhooks.html /reference/webhooks/ 301 7 + /migrating-knots-and-spindles.html /reference/migrations/ 301 8 + /bobbin.html /reference/bobbin/ 301 9 + /hacking-on-tangled.html /contributing/hacking/ 301 10 + /contribution-guide.html /contributing/guide/ 301 11 + /troubleshooting-guide.html /troubleshooting/ 301 12 + /single-page.html / 301
docs/public/apple-touch-icon.png

This is a binary file and will not be displayed.

+21
docs/public/favicon.svg
··· 1 + 2 + <svg 3 + class="" 4 + viewBox="0 0 32 32" 5 + fill="currentColor" 6 + xmlns="http://www.w3.org/2000/svg"> 7 + 8 + <style> 9 + :root { 10 + color: #000000; 11 + } 12 + 13 + @media (prefers-color-scheme: dark) { 14 + :root { 15 + color: #ffffff; 16 + } 17 + } 18 + </style> 19 + 20 + <path d="M21.0971 30.866C20.0566 30.8575 19.2628 30.5542 18.4016 30.0269C17.1668 29.3753 16.2237 28.2808 15.5497 27.0739C14.4789 28.4065 13.0476 29.215 11.4453 29.6718C10.763 29.8705 9.56809 30.0721 7.58737 29.3523C4.73277 28.3905 2.65342 25.4114 2.88973 22.3758C2.8465 21.1175 3.30392 19.8825 3.95228 18.8208C2.22264 17.8897 0.81225 16.3266 0.272148 14.4098C-0.0560731 13.3604 -0.042271 12.2299 0.0787626 11.1512C0.512215 8.60429 2.41697 6.38956 4.86912 5.59294C5.8479 3.35574 7.98378 1.68743 10.4037 1.34778C12.0104 1.12338 13.6735 1.46075 15.0792 2.27979C17.1272 0.00158595 20.6952 -0.671697 23.4195 0.727793C25.4978 1.72322 26.9839 3.80003 27.3447 6.06471C29.3222 6.85928 30.9877 8.47971 31.6413 10.5368C32.0784 11.8104 32.0928 13.2132 31.8098 14.5209C31.3041 16.5615 29.8679 18.2987 28.009 19.2482C28.0135 19.6113 29.2037 22.2296 29.0047 24.2056C28.9612 26.676 27.399 29.0172 25.2325 30.1544C23.9683 30.8945 22.4702 30.8805 21.0971 30.866ZM15.1733 23.755C16.9256 23.5593 18.0743 22.0269 18.9665 20.6469C19.3883 20.0182 19.7105 19.3146 20.0306 18.6454C20.4458 19.0271 20.7975 19.7461 21.4541 19.9173C22.1457 20.1333 22.9566 19.9579 23.38 19.3277C24.1902 17.8118 23.7908 15.9827 23.319 14.4119C23.0284 13.5097 22.6472 12.5841 21.9218 11.9446C22.0765 10.85 21.4299 9.73834 20.5106 9.16542C19.7272 9.79198 18.5352 9.78821 17.7794 9.11795C16.3309 10.5997 15.0034 10.5505 13.7212 9.37618C13.4331 9.11226 12.8832 10.9871 10.9535 9.92506C9.84488 10.8567 8.98526 11.753 8.22356 13.0435C7.48342 14.4347 6.70829 15.6703 6.64151 17.1811C6.6094 18.0641 7.29731 18.9892 8.22942 18.9174C9.16105 19.0009 9.7952 18.0813 10.5006 17.6993C10.6058 18.9316 10.7243 20.2556 11.1395 21.4587C11.6161 23.0155 13.2947 24.005 14.8835 23.7784C14.9959 23.7696 15.1733 23.7549 15.1733 23.755ZM16.0828 19.1062C15.2306 18.5823 15.6407 17.4452 15.6066 16.6193C15.6914 15.6227 15.7594 14.575 16.2061 13.667C16.6788 13.0197 17.8318 13.2694 17.8827 14.0999C17.8488 14.9353 17.4664 15.767 17.5121 16.633C17.4129 17.3561 17.5839 18.1684 17.265 18.8293C17.0033 19.195 16.4703 19.3013 16.0828 19.1062ZM12.3606 18.6302C11.5578 18.1933 11.8129 17.0941 11.687 16.3298C11.7914 15.445 11.7045 14.3226 12.4431 13.7021C13.1653 13.1969 14.1485 14.0621 13.8069 14.8564C13.4426 15.8602 13.6814 16.957 13.6891 17.9748C13.5512 18.5752 12.911 18.894 12.3606 18.6302Z" fill="currentColor"/> 21 + </svg>
+34
docs/scripts/gen-ascii-dolly.mjs
··· 1 + // renders the dolly logo (public/apple-touch-icon.png) as ascii art 2 + // and prints it, ready to paste into the hero.image.html <pre> in 3 + // src/content/docs/index.mdx: 4 + // 5 + // node scripts/gen-ascii-dolly.mjs 6 + import { dirname, join } from "node:path"; 7 + import { fileURLToPath } from "node:url"; 8 + import sharp from "sharp"; 9 + 10 + // monospace glyphs are roughly twice as tall as they are wide 11 + const COLS = 46; 12 + const ROWS = 23; 13 + const RAMP = " .:-=+*#%@"; 14 + 15 + const root = join(dirname(fileURLToPath(import.meta.url)), ".."); 16 + const png = join(root, "public", "apple-touch-icon.png"); 17 + 18 + const { data, info } = await sharp(png) 19 + .resize(COLS, ROWS, { fit: "fill" }) 20 + .ensureAlpha() 21 + .raw() 22 + .toBuffer({ resolveWithObject: true }); 23 + 24 + const lines = []; 25 + for (let y = 0; y < info.height; y++) { 26 + let line = ""; 27 + for (let x = 0; x < info.width; x++) { 28 + const alpha = data[(y * info.width + x) * 4 + 3]; 29 + line += RAMP[Math.round((alpha / 255) * (RAMP.length - 1))]; 30 + } 31 + lines.push(line.trimEnd()); 32 + } 33 + 34 + console.log(lines.join("\n").replace(/^\n+|\n+$/g, ""));
+75
docs/scripts/gen-sidebar-icons.mjs
··· 1 + // generates src/styles/sidebar-icons.css from lucide-astro's icons. 2 + // sidebar entries opt in via `attrs: { "data-icon": "<name>" }` in 3 + // astro.config.mjs. to add an icon, extend the map below and run: 4 + // 5 + // node scripts/gen-sidebar-icons.mjs 6 + import { readFileSync, writeFileSync } from "node:fs"; 7 + import { dirname, join } from "node:path"; 8 + import { fileURLToPath } from "node:url"; 9 + 10 + // data-icon name -> lucide-astro component 11 + const ICONS = { 12 + rocket: "Rocket", 13 + "at-sign": "AtSign", 14 + globe: "Globe", 15 + "life-buoy": "LifeBuoy", 16 + server: "Server", 17 + "hard-drive": "HardDrive", 18 + workflow: "Workflow", 19 + play: "Play", 20 + "key-round": "KeyRound", 21 + network: "Network", 22 + webhook: "Webhook", 23 + cable: "Cable", 24 + "arrow-up-circle": "ArrowUpCircle", 25 + hammer: "Hammer", 26 + "git-pull-request": "GitPullRequest", 27 + }; 28 + 29 + const root = join(dirname(fileURLToPath(import.meta.url)), ".."); 30 + 31 + const svgFor = (component) => { 32 + const source = readFileSync( 33 + join(root, "node_modules/lucide-astro/dist", `${component}.astro`), 34 + "utf8", 35 + ); 36 + const body = source 37 + .split("\n") 38 + .filter((line) => line.trim().startsWith("<") && !line.includes("Layout")) 39 + .map((line) => line.trim()) 40 + .join(""); 41 + return ( 42 + '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" ' + 43 + 'stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' + 44 + body + 45 + "</svg>" 46 + ); 47 + }; 48 + 49 + let css = `/* GENERATED by scripts/gen-sidebar-icons.mjs — do not edit by hand */ 50 + 51 + #starlight__sidebar a[data-icon]::before { 52 + content: ""; 53 + display: inline-block; 54 + width: 1rem; 55 + height: 1rem; 56 + margin-inline-end: 0.4em; 57 + vertical-align: -0.19em; 58 + background-color: currentColor; 59 + -webkit-mask-size: 100%; 60 + mask-size: 100%; 61 + } 62 + `; 63 + 64 + for (const [name, component] of Object.entries(ICONS)) { 65 + const url = `url("data:image/svg+xml,${encodeURIComponent(svgFor(component))}")`; 66 + css += ` 67 + #starlight__sidebar a[data-icon="${name}"]::before { 68 + -webkit-mask-image: ${url}; 69 + mask-image: ${url}; 70 + } 71 + `; 72 + } 73 + 74 + writeFileSync(join(root, "src/styles/sidebar-icons.css"), css); 75 + console.log(`wrote src/styles/sidebar-icons.css (${Object.keys(ICONS).length} icons)`);
-1
docs/search.html
··· 1 - <div class="pagefind-search"></div>
+12
docs/src/assets/logotype-dark.svg
··· 1 + 2 + <svg class="" viewBox="0 0 118 31" fill="#ffffff" xmlns="http://www.w3.org/2000/svg"> 3 + 4 + <path fill-rule="evenodd" clip-rule="evenodd" d="M78.6118 9.75728C79.2832 9.75733 79.8454 9.87208 80.2983 10.101C80.7513 10.3249 81.1161 10.6064 81.3921 10.9448C81.6732 11.278 81.8895 11.6064 82.0405 11.9292H82.1655V9.91353H85.4702V22.0307C85.4702 23.0305 85.2201 23.8668 84.7202 24.5385C84.2203 25.2154 83.5273 25.7251 82.6421 26.0688C81.762 26.4125 80.7488 26.5844 79.603 26.5844C78.5252 26.5844 77.6012 26.4385 76.8306 26.1469C76.065 25.8553 75.4555 25.462 75.0024 24.9672C74.5495 24.4726 74.2551 23.9237 74.1196 23.3198L77.1978 22.9057C77.2915 23.1243 77.4401 23.3303 77.6431 23.5229C77.8461 23.7206 78.1147 23.8824 78.4478 24.0073C78.7861 24.1321 79.1973 24.1947 79.6812 24.1948C80.4049 24.1948 81.0016 24.0227 81.4702 23.6792C81.9441 23.3355 82.1811 22.7701 82.1812 21.9838V19.7885H82.0405C81.8947 20.1217 81.6758 20.4371 81.3843 20.7338C81.0927 21.0306 80.7174 21.273 80.2593 21.4604C79.8012 21.6477 79.2546 21.7416 78.6196 21.7417C77.7188 21.7417 76.8981 21.5332 76.1587 21.1167C75.4244 20.6948 74.8383 20.0514 74.4009 19.187C73.9686 18.3172 73.7524 17.2181 73.7524 15.8901C73.7524 14.5308 73.9738 13.3952 74.4165 12.4838C74.8592 11.5726 75.4479 10.89 76.1821 10.437C76.9216 9.98403 77.7318 9.75728 78.6118 9.75728ZM79.6733 12.4057C79.1269 12.4058 78.6663 12.5544 78.2915 12.851C77.9166 13.1426 77.6326 13.5491 77.4399 14.0698C77.2472 14.5906 77.1509 15.1922 77.1509 15.8745C77.1509 16.5671 77.2472 17.1662 77.4399 17.6713C77.6378 18.1712 77.9218 18.5594 78.2915 18.8354C78.6663 19.106 79.1269 19.2416 79.6733 19.2417C80.2096 19.2417 80.663 19.1087 81.0327 18.8432C81.4076 18.5724 81.6942 18.1868 81.8921 17.687C82.0952 17.1818 82.1968 16.5776 82.1968 15.8745C82.1968 15.1714 82.0978 14.5619 81.8999 14.0463C81.702 13.5256 81.4155 13.1218 81.0405 12.8354C80.6656 12.5491 80.2096 12.4057 79.6733 12.4057Z" fill="#ffffff"/> 5 + <path fill-rule="evenodd" clip-rule="evenodd" d="M98.7397 9.75728C99.531 9.75733 100.268 9.88506 100.95 10.1401C101.637 10.39 102.236 10.7679 102.747 11.2729C103.262 11.778 103.663 12.4137 103.95 13.1792C104.236 13.9395 104.379 14.8303 104.379 15.851V16.7651H96.2085V16.7729C96.2085 17.3666 96.3179 17.8797 96.5366 18.312C96.7606 18.7441 97.0758 19.0776 97.4819 19.312C97.888 19.5461 98.3694 19.6635 98.9263 19.6635C99.2959 19.6635 99.6347 19.6113 99.9419 19.5073C100.249 19.4032 100.512 19.2467 100.731 19.0385C100.95 18.8303 101.116 18.5749 101.231 18.2729L104.309 18.476C104.153 19.2155 103.832 19.8615 103.348 20.4135C102.869 20.9603 102.249 21.3876 101.489 21.6948C100.734 21.9967 99.8609 22.1479 98.8716 22.1479C97.6376 22.1478 96.5754 21.8977 95.6851 21.3979C94.7998 20.8928 94.1173 20.179 93.6382 19.2573C93.159 18.3302 92.9194 17.2338 92.9194 15.9682C92.9194 14.7339 93.159 13.6505 93.6382 12.7182C94.1173 11.7861 94.792 11.0593 95.6616 10.5385C96.5365 10.0179 97.5629 9.75728 98.7397 9.75728ZM98.7935 12.2417C98.2886 12.2417 97.8411 12.3591 97.4507 12.5932C97.0654 12.8223 96.7632 13.1324 96.5444 13.5229C96.3427 13.8784 96.2325 14.2718 96.2124 14.7026H101.247C101.247 14.2235 101.142 13.7989 100.934 13.4292C100.726 13.0595 100.437 12.7702 100.067 12.562C99.7024 12.3486 99.2776 12.2417 98.7935 12.2417Z" fill="#ffffff"/> 6 + <path fill-rule="evenodd" clip-rule="evenodd" d="M54.187 9.75728C54.8536 9.7573 55.4918 9.83543 56.1011 9.99165C56.7155 10.1479 57.26 10.3902 57.7339 10.7182C58.2128 11.0462 58.5897 11.4685 58.8657 11.9838C59.1417 12.4942 59.2798 13.1063 59.2798 13.8198V21.9135H56.1245V20.2495H56.0308C55.8381 20.6244 55.5802 20.9552 55.2573 21.2417C54.9345 21.5229 54.5463 21.7443 54.0933 21.9057C53.6402 22.0619 53.1166 22.1401 52.5229 22.1401C51.7574 22.1401 51.075 22.0072 50.4761 21.7417C49.8772 21.4709 49.4031 21.0723 49.0542 20.5463C48.7105 20.0152 48.5386 19.3535 48.5386 18.562C48.5386 17.8954 48.661 17.3354 48.9058 16.8823C49.1505 16.4292 49.4839 16.0646 49.9058 15.7885C50.3276 15.5125 50.8068 15.3041 51.3433 15.1635C51.8849 15.0229 52.4527 14.9239 53.0464 14.8667C53.7442 14.7937 54.3069 14.726 54.7339 14.6635C55.1608 14.5958 55.4709 14.4968 55.6636 14.3667C55.8561 14.2365 55.9526 14.0436 55.9526 13.7885V13.7417C55.9526 13.247 55.7963 12.864 55.4839 12.5932C55.1767 12.3224 54.7389 12.187 54.1714 12.187C53.5726 12.187 53.0958 12.3199 52.7417 12.5854C52.3876 12.8458 52.1532 13.174 52.0386 13.5698L48.9604 13.3198C49.1167 12.5907 49.424 11.9603 49.8823 11.4292C50.3406 10.8928 50.9319 10.4812 51.6558 10.1948C52.3848 9.90318 53.2288 9.75728 54.187 9.75728ZM55.9761 16.351C55.872 16.4187 55.7285 16.4813 55.5464 16.5385C55.3694 16.5906 55.1687 16.6401 54.9448 16.687C54.721 16.7286 54.4968 16.7677 54.2729 16.8042C54.0491 16.8354 53.8458 16.8641 53.6636 16.8901C53.273 16.9474 52.9318 17.0386 52.6401 17.1635C52.3485 17.2885 52.1219 17.4578 51.9604 17.6713C51.799 17.8797 51.7183 18.1401 51.7183 18.4526C51.7183 18.9056 51.8824 19.2521 52.2104 19.4917C52.5437 19.7259 52.9658 19.8432 53.4761 19.8432C53.9655 19.8432 54.398 19.7468 54.7729 19.5542C55.1479 19.3563 55.4423 19.0906 55.6558 18.7573C55.8693 18.424 55.9761 18.0463 55.9761 17.6245V16.351Z" fill="#ffffff"/> 7 + <path fill-rule="evenodd" clip-rule="evenodd" d="M117.127 21.9135H113.846V19.9917H113.706C113.549 20.3249 113.328 20.6558 113.042 20.9838C112.76 21.3067 112.393 21.575 111.94 21.7885C111.492 22.0021 110.945 22.1088 110.299 22.1088C109.388 22.1088 108.562 21.8744 107.823 21.4057C107.088 20.9318 106.505 20.2364 106.073 19.3198C105.646 18.398 105.432 17.2676 105.432 15.9292C105.432 14.5542 105.654 13.4109 106.096 12.4995C106.539 11.5829 107.128 10.8979 107.862 10.4448C108.601 9.98651 109.411 9.75728 110.292 9.75728C110.963 9.75729 111.523 9.87189 111.971 10.101C112.424 10.325 112.789 10.6063 113.065 10.9448C113.346 11.2781 113.56 11.6063 113.706 11.9292H113.807V5.91451H117.127V21.9135ZM111.354 12.4057C110.807 12.4057 110.346 12.5542 109.971 12.851C109.596 13.1479 109.312 13.5594 109.12 14.0854C108.927 14.6114 108.831 15.2209 108.831 15.9135C108.831 16.6114 108.927 17.2287 109.12 17.7651C109.318 18.2963 109.601 18.713 109.971 19.0151C110.346 19.3119 110.807 19.4604 111.354 19.4604C111.89 19.4604 112.344 19.3145 112.713 19.0229C113.088 18.726 113.375 18.3119 113.573 17.7807C113.776 17.2495 113.877 16.627 113.877 15.9135C113.877 15.2 113.778 14.5802 113.581 14.0542C113.383 13.5282 113.096 13.1218 112.721 12.8354C112.346 12.549 111.89 12.4057 111.354 12.4057Z" fill="#ffffff"/> 8 + <path d="M45.353 9.91353H47.6108V12.4135H45.353V18.226C45.353 18.5332 45.3999 18.7729 45.4937 18.9448C45.5874 19.1114 45.7177 19.2286 45.8843 19.2963C46.0561 19.364 46.2541 19.3979 46.478 19.3979C46.6342 19.3979 46.7906 19.3849 46.9468 19.3588C47.103 19.3276 47.2228 19.3042 47.3062 19.2885L47.8296 21.7651C47.6629 21.8172 47.4285 21.8771 47.1265 21.9448C46.8244 22.0177 46.4571 22.062 46.0249 22.0776C45.2229 22.1088 44.5196 22.002 43.9155 21.7573C43.3167 21.5125 42.8504 21.1322 42.5171 20.6167C42.1838 20.1011 42.0197 19.4499 42.0249 18.6635V12.4135H40.3843V9.91353H42.0249V7.03951H45.353V9.91353Z" fill="#ffffff"/> 9 + <path d="M90.7808 18.3198C90.786 18.6999 90.8537 18.9761 90.9839 19.1479C91.1193 19.3145 91.3486 19.3979 91.6714 19.3979C91.838 19.3927 91.9683 19.3823 92.062 19.3667C92.1557 19.351 92.2339 19.3302 92.2964 19.3042L92.8276 21.726C92.6558 21.7781 92.4448 21.8328 92.1948 21.8901C91.9501 21.9422 91.6192 21.976 91.2026 21.9917C89.9268 22.0385 88.9839 21.7988 88.3745 21.2729C87.7652 20.7417 87.4579 19.9056 87.4526 18.7651V5.91451H90.7808V18.3198Z" fill="#ffffff"/> 10 + <path d="M68.1138 9.75728C68.947 9.75728 69.6737 9.93962 70.2935 10.3042C70.9132 10.6687 71.395 11.1897 71.7388 11.8667C72.0825 12.5385 72.2544 13.3407 72.2544 14.2729V21.9135H68.9263V14.8667C68.9315 14.1324 68.744 13.5593 68.3638 13.1479C67.9836 12.7313 67.46 12.5229 66.7935 12.5229C66.3456 12.5229 65.9497 12.6193 65.606 12.812C65.2675 13.0047 65.0018 13.286 64.8091 13.6557C64.6216 14.0203 64.5252 14.4605 64.52 14.976V21.9135H61.1919V9.91353H64.3638V12.0307H64.5044C64.77 11.3329 65.2154 10.7807 65.8403 10.3745C66.4653 9.96305 67.2232 9.75728 68.1138 9.75728Z" fill="#ffffff"/> 11 + <path d="M21.0971 30.866C20.0566 30.8575 19.2628 30.5542 18.4016 30.0269C17.1668 29.3753 16.2237 28.2808 15.5497 27.0739C14.4789 28.4065 13.0476 29.215 11.4453 29.6718C10.763 29.8705 9.56809 30.0721 7.58737 29.3523C4.73277 28.3905 2.65342 25.4114 2.88973 22.3758C2.8465 21.1175 3.30391 19.8825 3.95227 18.8208C2.22264 17.8897 0.812251 16.3266 0.272149 14.4098C-0.0560728 13.3604 -0.0422712 12.2299 0.0787624 11.1512C0.512215 8.60429 2.41696 6.38956 4.86912 5.59294C5.8479 3.35574 7.98378 1.68743 10.4037 1.34778C12.0104 1.12338 13.6735 1.46075 15.0792 2.27979C17.1272 0.00158572 20.6952 -0.671697 23.4195 0.727793C25.4978 1.72322 26.9839 3.80003 27.3447 6.06471C29.3222 6.85928 30.9877 8.47971 31.6413 10.5368C32.0784 11.8104 32.0929 13.2132 31.8098 14.5209C31.3041 16.5615 29.8679 18.2987 28.009 19.2482C28.0135 19.6113 29.2037 22.2296 29.0047 24.2056C28.9612 26.676 27.399 29.0172 25.2325 30.1544C23.9683 30.8945 22.4702 30.8805 21.0971 30.866ZM15.1733 23.755C16.9256 23.5593 18.0743 22.0269 18.9665 20.6469C19.3883 20.0182 19.7105 19.3146 20.0306 18.6454C20.4458 19.027 20.7975 19.7461 21.4541 19.9173C22.1457 20.1333 22.9566 19.9579 23.38 19.3277C24.1902 17.8118 23.7908 15.9827 23.319 14.4119C23.0284 13.5097 22.6472 12.5841 21.9218 11.9446C22.0765 10.85 21.4299 9.73834 20.5106 9.16542C19.7272 9.79198 18.5352 9.78821 17.7794 9.11795C16.3309 10.5997 15.0034 10.5505 13.7212 9.37618C13.4331 9.11226 12.8832 10.9871 10.9535 9.92506C9.84488 10.8567 8.98526 11.753 8.22356 13.0435C7.48342 14.4347 6.70829 15.6703 6.64151 17.1811C6.6094 18.0641 7.29731 18.9892 8.22942 18.9174C9.16105 19.0009 9.7952 18.0813 10.5006 17.6993C10.6058 18.9316 10.7243 20.2556 11.1395 21.4587C11.6161 23.0155 13.2947 24.005 14.8835 23.7784C14.9959 23.7696 15.1733 23.755 15.1733 23.755ZM16.0828 19.1062C15.2306 18.5823 15.6407 17.4452 15.6066 16.6193C15.6914 15.6227 15.7594 14.575 16.2061 13.667C16.6788 13.0197 17.8318 13.2694 17.8827 14.0999C17.8488 14.9353 17.4664 15.767 17.5121 16.633C17.4129 17.3561 17.5839 18.1684 17.265 18.8293C17.0033 19.195 16.4703 19.3013 16.0828 19.1062ZM12.3606 18.6302C11.5578 18.1933 11.8129 17.0941 11.687 16.3298C11.7914 15.445 11.7045 14.3226 12.4431 13.7021C13.1653 13.1969 14.1485 14.0621 13.8069 14.8564C13.4426 15.8602 13.6814 16.957 13.6891 17.9748C13.5512 18.5752 12.911 18.894 12.3606 18.6302Z" fill="#ffffff"/> 12 + </svg>
+12
docs/src/assets/logotype-light.svg
··· 1 + 2 + <svg class="" viewBox="0 0 118 31" fill="#000000" xmlns="http://www.w3.org/2000/svg"> 3 + 4 + <path fill-rule="evenodd" clip-rule="evenodd" d="M78.6118 9.75728C79.2832 9.75733 79.8454 9.87208 80.2983 10.101C80.7513 10.3249 81.1161 10.6064 81.3921 10.9448C81.6732 11.278 81.8895 11.6064 82.0405 11.9292H82.1655V9.91353H85.4702V22.0307C85.4702 23.0305 85.2201 23.8668 84.7202 24.5385C84.2203 25.2154 83.5273 25.7251 82.6421 26.0688C81.762 26.4125 80.7488 26.5844 79.603 26.5844C78.5252 26.5844 77.6012 26.4385 76.8306 26.1469C76.065 25.8553 75.4555 25.462 75.0024 24.9672C74.5495 24.4726 74.2551 23.9237 74.1196 23.3198L77.1978 22.9057C77.2915 23.1243 77.4401 23.3303 77.6431 23.5229C77.8461 23.7206 78.1147 23.8824 78.4478 24.0073C78.7861 24.1321 79.1973 24.1947 79.6812 24.1948C80.4049 24.1948 81.0016 24.0227 81.4702 23.6792C81.9441 23.3355 82.1811 22.7701 82.1812 21.9838V19.7885H82.0405C81.8947 20.1217 81.6758 20.4371 81.3843 20.7338C81.0927 21.0306 80.7174 21.273 80.2593 21.4604C79.8012 21.6477 79.2546 21.7416 78.6196 21.7417C77.7188 21.7417 76.8981 21.5332 76.1587 21.1167C75.4244 20.6948 74.8383 20.0514 74.4009 19.187C73.9686 18.3172 73.7524 17.2181 73.7524 15.8901C73.7524 14.5308 73.9738 13.3952 74.4165 12.4838C74.8592 11.5726 75.4479 10.89 76.1821 10.437C76.9216 9.98403 77.7318 9.75728 78.6118 9.75728ZM79.6733 12.4057C79.1269 12.4058 78.6663 12.5544 78.2915 12.851C77.9166 13.1426 77.6326 13.5491 77.4399 14.0698C77.2472 14.5906 77.1509 15.1922 77.1509 15.8745C77.1509 16.5671 77.2472 17.1662 77.4399 17.6713C77.6378 18.1712 77.9218 18.5594 78.2915 18.8354C78.6663 19.106 79.1269 19.2416 79.6733 19.2417C80.2096 19.2417 80.663 19.1087 81.0327 18.8432C81.4076 18.5724 81.6942 18.1868 81.8921 17.687C82.0952 17.1818 82.1968 16.5776 82.1968 15.8745C82.1968 15.1714 82.0978 14.5619 81.8999 14.0463C81.702 13.5256 81.4155 13.1218 81.0405 12.8354C80.6656 12.5491 80.2096 12.4057 79.6733 12.4057Z" fill="#000000"/> 5 + <path fill-rule="evenodd" clip-rule="evenodd" d="M98.7397 9.75728C99.531 9.75733 100.268 9.88506 100.95 10.1401C101.637 10.39 102.236 10.7679 102.747 11.2729C103.262 11.778 103.663 12.4137 103.95 13.1792C104.236 13.9395 104.379 14.8303 104.379 15.851V16.7651H96.2085V16.7729C96.2085 17.3666 96.3179 17.8797 96.5366 18.312C96.7606 18.7441 97.0758 19.0776 97.4819 19.312C97.888 19.5461 98.3694 19.6635 98.9263 19.6635C99.2959 19.6635 99.6347 19.6113 99.9419 19.5073C100.249 19.4032 100.512 19.2467 100.731 19.0385C100.95 18.8303 101.116 18.5749 101.231 18.2729L104.309 18.476C104.153 19.2155 103.832 19.8615 103.348 20.4135C102.869 20.9603 102.249 21.3876 101.489 21.6948C100.734 21.9967 99.8609 22.1479 98.8716 22.1479C97.6376 22.1478 96.5754 21.8977 95.6851 21.3979C94.7998 20.8928 94.1173 20.179 93.6382 19.2573C93.159 18.3302 92.9194 17.2338 92.9194 15.9682C92.9194 14.7339 93.159 13.6505 93.6382 12.7182C94.1173 11.7861 94.792 11.0593 95.6616 10.5385C96.5365 10.0179 97.5629 9.75728 98.7397 9.75728ZM98.7935 12.2417C98.2886 12.2417 97.8411 12.3591 97.4507 12.5932C97.0654 12.8223 96.7632 13.1324 96.5444 13.5229C96.3427 13.8784 96.2325 14.2718 96.2124 14.7026H101.247C101.247 14.2235 101.142 13.7989 100.934 13.4292C100.726 13.0595 100.437 12.7702 100.067 12.562C99.7024 12.3486 99.2776 12.2417 98.7935 12.2417Z" fill="#000000"/> 6 + <path fill-rule="evenodd" clip-rule="evenodd" d="M54.187 9.75728C54.8536 9.7573 55.4918 9.83543 56.1011 9.99165C56.7155 10.1479 57.26 10.3902 57.7339 10.7182C58.2128 11.0462 58.5897 11.4685 58.8657 11.9838C59.1417 12.4942 59.2798 13.1063 59.2798 13.8198V21.9135H56.1245V20.2495H56.0308C55.8381 20.6244 55.5802 20.9552 55.2573 21.2417C54.9345 21.5229 54.5463 21.7443 54.0933 21.9057C53.6402 22.0619 53.1166 22.1401 52.5229 22.1401C51.7574 22.1401 51.075 22.0072 50.4761 21.7417C49.8772 21.4709 49.4031 21.0723 49.0542 20.5463C48.7105 20.0152 48.5386 19.3535 48.5386 18.562C48.5386 17.8954 48.661 17.3354 48.9058 16.8823C49.1505 16.4292 49.4839 16.0646 49.9058 15.7885C50.3276 15.5125 50.8068 15.3041 51.3433 15.1635C51.8849 15.0229 52.4527 14.9239 53.0464 14.8667C53.7442 14.7937 54.3069 14.726 54.7339 14.6635C55.1608 14.5958 55.4709 14.4968 55.6636 14.3667C55.8561 14.2365 55.9526 14.0436 55.9526 13.7885V13.7417C55.9526 13.247 55.7963 12.864 55.4839 12.5932C55.1767 12.3224 54.7389 12.187 54.1714 12.187C53.5726 12.187 53.0958 12.3199 52.7417 12.5854C52.3876 12.8458 52.1532 13.174 52.0386 13.5698L48.9604 13.3198C49.1167 12.5907 49.424 11.9603 49.8823 11.4292C50.3406 10.8928 50.9319 10.4812 51.6558 10.1948C52.3848 9.90318 53.2288 9.75728 54.187 9.75728ZM55.9761 16.351C55.872 16.4187 55.7285 16.4813 55.5464 16.5385C55.3694 16.5906 55.1687 16.6401 54.9448 16.687C54.721 16.7286 54.4968 16.7677 54.2729 16.8042C54.0491 16.8354 53.8458 16.8641 53.6636 16.8901C53.273 16.9474 52.9318 17.0386 52.6401 17.1635C52.3485 17.2885 52.1219 17.4578 51.9604 17.6713C51.799 17.8797 51.7183 18.1401 51.7183 18.4526C51.7183 18.9056 51.8824 19.2521 52.2104 19.4917C52.5437 19.7259 52.9658 19.8432 53.4761 19.8432C53.9655 19.8432 54.398 19.7468 54.7729 19.5542C55.1479 19.3563 55.4423 19.0906 55.6558 18.7573C55.8693 18.424 55.9761 18.0463 55.9761 17.6245V16.351Z" fill="#000000"/> 7 + <path fill-rule="evenodd" clip-rule="evenodd" d="M117.127 21.9135H113.846V19.9917H113.706C113.549 20.3249 113.328 20.6558 113.042 20.9838C112.76 21.3067 112.393 21.575 111.94 21.7885C111.492 22.0021 110.945 22.1088 110.299 22.1088C109.388 22.1088 108.562 21.8744 107.823 21.4057C107.088 20.9318 106.505 20.2364 106.073 19.3198C105.646 18.398 105.432 17.2676 105.432 15.9292C105.432 14.5542 105.654 13.4109 106.096 12.4995C106.539 11.5829 107.128 10.8979 107.862 10.4448C108.601 9.98651 109.411 9.75728 110.292 9.75728C110.963 9.75729 111.523 9.87189 111.971 10.101C112.424 10.325 112.789 10.6063 113.065 10.9448C113.346 11.2781 113.56 11.6063 113.706 11.9292H113.807V5.91451H117.127V21.9135ZM111.354 12.4057C110.807 12.4057 110.346 12.5542 109.971 12.851C109.596 13.1479 109.312 13.5594 109.12 14.0854C108.927 14.6114 108.831 15.2209 108.831 15.9135C108.831 16.6114 108.927 17.2287 109.12 17.7651C109.318 18.2963 109.601 18.713 109.971 19.0151C110.346 19.3119 110.807 19.4604 111.354 19.4604C111.89 19.4604 112.344 19.3145 112.713 19.0229C113.088 18.726 113.375 18.3119 113.573 17.7807C113.776 17.2495 113.877 16.627 113.877 15.9135C113.877 15.2 113.778 14.5802 113.581 14.0542C113.383 13.5282 113.096 13.1218 112.721 12.8354C112.346 12.549 111.89 12.4057 111.354 12.4057Z" fill="#000000"/> 8 + <path d="M45.353 9.91353H47.6108V12.4135H45.353V18.226C45.353 18.5332 45.3999 18.7729 45.4937 18.9448C45.5874 19.1114 45.7177 19.2286 45.8843 19.2963C46.0561 19.364 46.2541 19.3979 46.478 19.3979C46.6342 19.3979 46.7906 19.3849 46.9468 19.3588C47.103 19.3276 47.2228 19.3042 47.3062 19.2885L47.8296 21.7651C47.6629 21.8172 47.4285 21.8771 47.1265 21.9448C46.8244 22.0177 46.4571 22.062 46.0249 22.0776C45.2229 22.1088 44.5196 22.002 43.9155 21.7573C43.3167 21.5125 42.8504 21.1322 42.5171 20.6167C42.1838 20.1011 42.0197 19.4499 42.0249 18.6635V12.4135H40.3843V9.91353H42.0249V7.03951H45.353V9.91353Z" fill="#000000"/> 9 + <path d="M90.7808 18.3198C90.786 18.6999 90.8537 18.9761 90.9839 19.1479C91.1193 19.3145 91.3486 19.3979 91.6714 19.3979C91.838 19.3927 91.9683 19.3823 92.062 19.3667C92.1557 19.351 92.2339 19.3302 92.2964 19.3042L92.8276 21.726C92.6558 21.7781 92.4448 21.8328 92.1948 21.8901C91.9501 21.9422 91.6192 21.976 91.2026 21.9917C89.9268 22.0385 88.9839 21.7988 88.3745 21.2729C87.7652 20.7417 87.4579 19.9056 87.4526 18.7651V5.91451H90.7808V18.3198Z" fill="#000000"/> 10 + <path d="M68.1138 9.75728C68.947 9.75728 69.6737 9.93962 70.2935 10.3042C70.9132 10.6687 71.395 11.1897 71.7388 11.8667C72.0825 12.5385 72.2544 13.3407 72.2544 14.2729V21.9135H68.9263V14.8667C68.9315 14.1324 68.744 13.5593 68.3638 13.1479C67.9836 12.7313 67.46 12.5229 66.7935 12.5229C66.3456 12.5229 65.9497 12.6193 65.606 12.812C65.2675 13.0047 65.0018 13.286 64.8091 13.6557C64.6216 14.0203 64.5252 14.4605 64.52 14.976V21.9135H61.1919V9.91353H64.3638V12.0307H64.5044C64.77 11.3329 65.2154 10.7807 65.8403 10.3745C66.4653 9.96305 67.2232 9.75728 68.1138 9.75728Z" fill="#000000"/> 11 + <path d="M21.0971 30.866C20.0566 30.8575 19.2628 30.5542 18.4016 30.0269C17.1668 29.3753 16.2237 28.2808 15.5497 27.0739C14.4789 28.4065 13.0476 29.215 11.4453 29.6718C10.763 29.8705 9.56809 30.0721 7.58737 29.3523C4.73277 28.3905 2.65342 25.4114 2.88973 22.3758C2.8465 21.1175 3.30391 19.8825 3.95227 18.8208C2.22264 17.8897 0.812251 16.3266 0.272149 14.4098C-0.0560728 13.3604 -0.0422712 12.2299 0.0787624 11.1512C0.512215 8.60429 2.41696 6.38956 4.86912 5.59294C5.8479 3.35574 7.98378 1.68743 10.4037 1.34778C12.0104 1.12338 13.6735 1.46075 15.0792 2.27979C17.1272 0.00158572 20.6952 -0.671697 23.4195 0.727793C25.4978 1.72322 26.9839 3.80003 27.3447 6.06471C29.3222 6.85928 30.9877 8.47971 31.6413 10.5368C32.0784 11.8104 32.0929 13.2132 31.8098 14.5209C31.3041 16.5615 29.8679 18.2987 28.009 19.2482C28.0135 19.6113 29.2037 22.2296 29.0047 24.2056C28.9612 26.676 27.399 29.0172 25.2325 30.1544C23.9683 30.8945 22.4702 30.8805 21.0971 30.866ZM15.1733 23.755C16.9256 23.5593 18.0743 22.0269 18.9665 20.6469C19.3883 20.0182 19.7105 19.3146 20.0306 18.6454C20.4458 19.027 20.7975 19.7461 21.4541 19.9173C22.1457 20.1333 22.9566 19.9579 23.38 19.3277C24.1902 17.8118 23.7908 15.9827 23.319 14.4119C23.0284 13.5097 22.6472 12.5841 21.9218 11.9446C22.0765 10.85 21.4299 9.73834 20.5106 9.16542C19.7272 9.79198 18.5352 9.78821 17.7794 9.11795C16.3309 10.5997 15.0034 10.5505 13.7212 9.37618C13.4331 9.11226 12.8832 10.9871 10.9535 9.92506C9.84488 10.8567 8.98526 11.753 8.22356 13.0435C7.48342 14.4347 6.70829 15.6703 6.64151 17.1811C6.6094 18.0641 7.29731 18.9892 8.22942 18.9174C9.16105 19.0009 9.7952 18.0813 10.5006 17.6993C10.6058 18.9316 10.7243 20.2556 11.1395 21.4587C11.6161 23.0155 13.2947 24.005 14.8835 23.7784C14.9959 23.7696 15.1733 23.755 15.1733 23.755ZM16.0828 19.1062C15.2306 18.5823 15.6407 17.4452 15.6066 16.6193C15.6914 15.6227 15.7594 14.575 16.2061 13.667C16.6788 13.0197 17.8318 13.2694 17.8827 14.0999C17.8488 14.9353 17.4664 15.767 17.5121 16.633C17.4129 17.3561 17.5839 18.1684 17.265 18.8293C17.0033 19.195 16.4703 19.3013 16.0828 19.1062ZM12.3606 18.6302C11.5578 18.1933 11.8129 17.0941 11.687 16.3298C11.7914 15.445 11.7045 14.3226 12.4431 13.7021C13.1653 13.1969 14.1485 14.0621 13.8069 14.8564C13.4426 15.8602 13.6814 16.957 13.6891 17.9748C13.5512 18.5752 12.911 18.894 12.3606 18.6302Z" fill="#000000"/> 12 + </svg>
+23
docs/src/components/FeatureCard.astro
··· 1 + --- 2 + interface Props { 3 + title: string; 4 + href: string; 5 + } 6 + 7 + const { title, href } = Astro.props; 8 + --- 9 + 10 + <a 11 + class="btn feature-card h-full justify-start items-start text-left gap-3.5 p-5" 12 + href={href} 13 + > 14 + <span class="flex shrink-0 mt-0.5 [&_svg]:size-5"> 15 + <slot name="icon" /> 16 + </span> 17 + <span class="flex flex-col gap-1"> 18 + <span class="text-base font-semibold">{title}</span> 19 + <span class="text-sm font-normal text-gray-500 dark:text-gray-400"> 20 + <slot /> 21 + </span> 22 + </span> 23 + </a>
+9
docs/src/components/HeaderLinks.astro
··· 1 + --- 2 + // overrides starlight's SocialIcons slot to add plain text links 3 + // before the icons; styled in styles/tangled.css 4 + import Default from "@astrojs/starlight/components/SocialIcons.astro"; 5 + --- 6 + 7 + <a class="header-link" href="https://tangled.org">tangled.org</a> 8 + <a class="header-link" href="https://blog.tangled.org">blog</a> 9 + <Default><slot /></Default>
+7
docs/src/content.config.ts
··· 1 + import { defineCollection } from "astro:content"; 2 + import { docsLoader } from "@astrojs/starlight/loaders"; 3 + import { docsSchema } from "@astrojs/starlight/schema"; 4 + 5 + export const collections = { 6 + docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }), 7 + };
+136
docs/src/content/docs/contributing/guide.md
··· 1 + --- 2 + title: Contribution guide 3 + description: Commit guidelines, code formatting, proposals, and DCO. 4 + --- 5 + 6 + 7 + ## Commit guidelines 8 + 9 + We follow a commit style similar to the Go project. Please keep commits: 10 + 11 + - **atomic**: each commit should represent one logical change 12 + - **descriptive**: the commit message should clearly describe what the 13 + change does and why it's needed 14 + 15 + ### Message format 16 + 17 + ``` 18 + <service/top-level directory>/<affected package/directory>: <short summary of change> 19 + 20 + Optional longer description can go here, if necessary. Explain what the 21 + change does and why, especially if not obvious. Reference relevant 22 + issues or PRs when applicable. These can be links for now since we don't 23 + auto-link issues/PRs yet. 24 + ``` 25 + 26 + Here are some examples: 27 + 28 + ``` 29 + appview/state: fix token expiry check in middleware 30 + 31 + The previous check did not account for clock drift, leading to premature 32 + token invalidation. 33 + ``` 34 + 35 + ``` 36 + knotserver/git/service: improve error checking in upload-pack 37 + ``` 38 + 39 + ### General notes 40 + 41 + - PRs get merged "as-is" (fast-forward)—like applying a patch-series 42 + using `git am`. At present, there is no squashing—so please author 43 + your commits as they would appear on `master`, following the above 44 + guidelines. 45 + - If there is a lot of nesting, for example "appview: 46 + pages/templates/repo/fragments: ...", these can be truncated down to 47 + just "appview: repo/fragments: ...". If the change affects a lot of 48 + subdirectories, you may abbreviate to just the top-level names, e.g. 49 + "appview: ..." or "knotserver: ...". 50 + - Keep commits lowercased with no trailing period. 51 + - Use the imperative mood in the summary line (e.g., "fix bug" not 52 + "fixed bug" or "fixes bug"). 53 + - Try to keep the summary line under 72 characters, but we aren't too 54 + fussed about this. 55 + - Follow the same formatting for PR titles if filled manually. 56 + - Don't include unrelated changes in the same commit. 57 + - Avoid noisy commit messages like "wip" or "final fix"—rewrite history 58 + before submitting if necessary. 59 + 60 + ## Code formatting 61 + 62 + We use a variety of tools to format our code, and multiplex them with 63 + [`treefmt`](https://treefmt.com). All you need to do to format your changes 64 + is run `nix run .#fmt` (or just `treefmt` if you're in the devshell). 65 + 66 + ## Proposals for bigger changes 67 + 68 + Small fixes like typos, minor bugs, or trivial refactors can be 69 + submitted directly as PRs. 70 + 71 + For larger changes—especially those introducing new features, significant 72 + refactoring, or altering system behavior—please open a proposal first. This 73 + helps us evaluate the scope, design, and potential impact before implementation. 74 + 75 + Create a new issue titled: 76 + 77 + ``` 78 + proposal: <affected scope>: <summary of change> 79 + ``` 80 + 81 + In the description, explain: 82 + 83 + - What the change is 84 + - Why it's needed 85 + - How you plan to implement it (roughly) 86 + - Any open questions or tradeoffs 87 + 88 + We'll use the issue thread to discuss and refine the idea before moving 89 + forward. 90 + 91 + ## Developer Certificate of Origin (DCO) 92 + 93 + We require all contributors to certify that they have the right to 94 + submit the code they're contributing. To do this, we follow the 95 + [Developer Certificate of Origin 96 + (DCO)](https://developercertificate.org/). 97 + 98 + By signing your commits, you're stating that the contribution is your 99 + own work, or that you have the right to submit it under the project's 100 + license. This helps us keep things clean and legally sound. 101 + 102 + To sign your commit, just add the `-s` flag when committing: 103 + 104 + ```sh 105 + git commit -s -m "your commit message" 106 + ``` 107 + 108 + This appends a line like: 109 + 110 + ``` 111 + Signed-off-by: Your Name <your.email@example.com> 112 + ``` 113 + 114 + We won't merge commits if they aren't signed off. If you forget, you can 115 + amend the last commit like this: 116 + 117 + ```sh 118 + git commit --amend -s 119 + ``` 120 + 121 + If you're submitting a PR with multiple commits, make sure each one is 122 + signed. 123 + 124 + For [jj](https://jj-vcs.github.io/jj/latest/) users, you can run the following command 125 + to make it sign off commits in the tangled repo: 126 + 127 + ```shell 128 + # Safety check, should say "No matching config key..." 129 + jj config list templates.commit_trailers 130 + # The command below may need to be adjusted if the command above returned something. 131 + jj config set --repo templates.commit_trailers "format_signed_off_by_trailer(self)" 132 + ``` 133 + 134 + Refer to the [jujutsu 135 + documentation](https://jj-vcs.github.io/jj/latest/config/#commit-trailers) 136 + for more information.
+169
docs/src/content/docs/contributing/hacking.md
··· 1 + --- 2 + title: Hacking on Tangled 3 + description: Set up a dev environment and run the appview, knots, and spindles locally. 4 + --- 5 + 6 + 7 + We highly recommend [installing 8 + Nix](https://nixos.org/download/) (the package manager) 9 + before working on the codebase. The Nix flake provides a lot 10 + of helpers to get started and most importantly, builds and 11 + dev shells are entirely deterministic. 12 + 13 + To set up your dev environment: 14 + 15 + ```bash 16 + nix develop 17 + ``` 18 + 19 + Non-Nix users can look at the `devShell` attribute in the 20 + `flake.nix` file to determine necessary dependencies. 21 + 22 + ## Running the appview 23 + 24 + The appview requires Redis and OAuth JWKs. Start these 25 + first, before launching the appview itself. 26 + 27 + ```bash 28 + # OAuth JWKs should already be set up by the Nix devshell: 29 + echo $TANGLED_OAUTH_CLIENT_SECRET 30 + z42ty4RT1ovnTopY8B8ekz9NuziF2CuMkZ7rbRFpAR9jBqMc 31 + 32 + echo $TANGLED_OAUTH_CLIENT_KID 33 + 1761667908 34 + 35 + # if not, you can set it up yourself: 36 + goat key generate -t P-256 37 + Key Type: P-256 / secp256r1 / ES256 private key 38 + Secret Key (Multibase Syntax): save this securely (eg, add to password manager) 39 + z42tuPDKRfM2mz2Kv953ARen2jmrPA8S9LX9tRq4RVcUMwwL 40 + Public Key (DID Key Syntax): share or publish this (eg, in DID document) 41 + did:key:zDnaeUBxtG6Xuv3ATJE4GaWeyXM3jyamJsZw3bSPpxx4bNXDR 42 + 43 + # the secret key from above 44 + export TANGLED_OAUTH_CLIENT_SECRET="z42tuP..." 45 + 46 + # Run Redis in a new shell to store OAuth sessions 47 + redis-server 48 + ``` 49 + 50 + The Nix flake exposes a few `app` attributes (run `nix 51 + flake show` to see a full list of what the flake provides), 52 + one of the apps runs the appview with the `air` 53 + live-reloader: 54 + 55 + ```bash 56 + TANGLED_DEV=true nix run .#watch-appview 57 + 58 + # TANGLED_DB_PATH might be of interest to point to 59 + # different sqlite DBs 60 + 61 + # in a separate shell, you can live-reload tailwind 62 + nix run .#watch-tailwind 63 + ``` 64 + 65 + ## Running knots and spindles 66 + 67 + An end-to-end knot setup requires setting up a machine with 68 + `sshd`, `AuthorizedKeysCommand`, and a Git user, which is 69 + quite cumbersome. So the Nix flake provides a 70 + `nixosConfiguration` to do so. 71 + 72 + <details> 73 + <summary><strong>macOS users will have to set up a Nix Builder first</strong></summary> 74 + 75 + In order to build Tangled's dev VM on macOS, you will 76 + first need to set up a Linux Nix builder. The recommended 77 + way to do so is to run a [`darwin.linux-builder` 78 + VM](https://nixos.org/manual/nixpkgs/unstable/#sec-darwin-builder) 79 + and to register it in `nix.conf` as a builder for Linux 80 + with the same architecture as your Mac (`linux-aarch64` if 81 + you are using Apple Silicon). 82 + 83 + If you're on nix-darwin, you can simply add 84 + 85 + ``` 86 + nix.linux-builder.enable = true; 87 + ``` 88 + 89 + to your host's `configuration.nix`. 90 + 91 + Alternatively, you can use any other method to set up a 92 + Linux machine with Nix installed that you can `sudo ssh` 93 + into (in other words, root user on your Mac has to be able 94 + to ssh into the Linux machine without entering a password) 95 + and that has the same architecture as your Mac. See 96 + [remote builder 97 + instructions](https://nix.dev/manual/nix/2.28/advanced-topics/distributed-builds.html#requirements) 98 + for how to register such a builder in `nix.conf`. 99 + 100 + > WARNING: If you'd like to use 101 + > [`nixos-lima`](https://github.com/nixos-lima/nixos-lima) or 102 + > [Orbstack](https://orbstack.dev/), note that setting them up so that `sudo 103 + ssh` works can be tricky. It seems to be [possible with 104 + > Orbstack](https://github.com/orgs/orbstack/discussions/1669). 105 + 106 + </details> 107 + 108 + To begin, grab your DID from http://localhost:3000/settings. 109 + Then, set `TANGLED_VM_KNOT_OWNER` and 110 + `TANGLED_VM_SPINDLE_OWNER` to your DID. You can now start a 111 + lightweight NixOS VM like so: 112 + 113 + ```bash 114 + nix run --impure .#vm 115 + 116 + # type `poweroff` at the shell to exit the VM 117 + ``` 118 + 119 + This starts a knot on port 6444, a spindle on port 6555 120 + with `ssh` exposed on port 2222. 121 + 122 + Once the services are running, head to 123 + http://localhost:3000/settings/knots and hit "Verify". It should 124 + verify the ownership of the services instantly if everything 125 + went smoothly. 126 + 127 + You can push repositories to this VM with this ssh config 128 + block on your main machine: 129 + 130 + ```bash 131 + Host nixos-shell 132 + Hostname localhost 133 + Port 2222 134 + User git 135 + IdentityFile ~/.ssh/my_tangled_key 136 + ``` 137 + 138 + Set up a remote called `local-dev` on a git repo: 139 + 140 + ```bash 141 + git remote add local-dev git@nixos-shell:user/repo 142 + git push local-dev main 143 + ``` 144 + 145 + The above VM should already be running a spindle on 146 + `localhost:6555`. Head to http://localhost:3000/settings/spindles and 147 + hit "Verify". You can then configure each repository to use 148 + this spindle and run CI jobs. 149 + 150 + Of interest when debugging spindles: 151 + 152 + ``` 153 + # Service logs from journald: 154 + journalctl -xeu spindle 155 + 156 + # CI job logs from disk: 157 + ls /var/log/spindle 158 + 159 + # Debugging spindle database: 160 + sqlite3 /var/lib/spindle/spindle.db 161 + 162 + # litecli has a nicer REPL interface: 163 + litecli /var/lib/spindle/spindle.db 164 + ``` 165 + 166 + If for any reason you wish to disable either one of the 167 + services in the VM, modify [nix/vm.nix](https://tangled.org/@tangled.org/core/blob/master/nix/vm.nix) and set 168 + `services.tangled.spindle.enable` (or 169 + `services.tangled.knot.enable`) to `false`.
+144
docs/src/content/docs/index.mdx
··· 1 + --- 2 + title: Tangled Docs 3 + description: The next-generation social coding platform. 4 + head: 5 + - tag: title 6 + content: Tangled Docs 7 + template: splash 8 + hero: 9 + image: 10 + html: | 11 + <pre class="ascii-dolly" aria-hidden="true"> 12 + ..... :=*#%@@@%#+: 13 + :=*%%@@@%#*=#@@@@@@@@@@@@%= 14 + :#@@@@@@@@@@@@@@@@@@@@@@@@@@@#. 15 + =@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# 16 + .-*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*-. 17 + =%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*: 18 + .#@@@@@@@@@@@@@@@@@#%@@@%*#%#*%@@@@@@@@@@@@@= 19 + *@@@@@@@@@@@@@*:--: .---. .%@@@@@@@@@@@@@= 20 + @@@@@@@@@@@@#: -@@@@@@@@@@@@@% 21 + %@@@@@@@@@@* .-. :=: :@@@@@@@@@@@@@ 22 + +@@@@@@@@@+ #@# :@@+ =@@@@@@@@@@@* 23 + +@@@@@@@# :@@+ =@@: %@@@@@@@@@#. 24 + :#@@@@@* . .@@+ *@@. #@@@@@@@@+ 25 + .#@@@@*==*@: -=. -#+ -: :@@@@@@#=. 26 + :@@@@@@@@@@+ =@@#**%@@@@@@+ 27 + #@@@@@@@@@@%: .*@@@@@@@@@@@@@@: 28 + %@@@@@@@@@@@%=:. .:+%@@@@@@@@@@@@@@@* 29 + +@@@@@@@@@@@@@@%%%%@@@@@@@@@@@@@@@@@@* 30 + .#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@- 31 + +@@@@@@@@@@@@@@#*@@@@@@@@@@@@@@@@@+ 32 + .=#%@@@@@@@%*- -%@@@@@@@@@@@@@#- 33 + .:-===-. -+#%@@@@@%#+: 34 + .::::.. 35 + </pre> 36 + title: Docs and self-hosting guides for Tangled 37 + tagline: Tangled is a decentralized code hosting and collaboration platform built on the AT Protocol. Every component is open-source and self-hostable. 38 + actions: 39 + - text: Quick start 40 + link: /quick-start/ 41 + # lucide arrow-right, same as the appview home CTAs 42 + icon: '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>' 43 + variant: primary 44 + - text: What is Tangled? 45 + link: "#what-is-tangled" 46 + variant: minimal 47 + --- 48 + 49 + import FeatureCard from "../../components/FeatureCard.astro"; 50 + import { 51 + Rocket, 52 + Server, 53 + Workflow, 54 + Globe, 55 + Webhook, 56 + Cable, 57 + Hammer, 58 + GitPullRequest, 59 + LifeBuoy, 60 + ArrowUpCircle, 61 + } from "lucide-astro"; 62 + 63 + <div class="feature-grid"> 64 + <FeatureCard title="Quick start" href="/quick-start/"> 65 + <Rocket slot="icon" /> 66 + Create an account, add your SSH key, and push your first repository. 67 + </FeatureCard> 68 + <FeatureCard title="Knots" href="/knots/"> 69 + <Server slot="icon" /> 70 + Lightweight, headless git servers. Run one on anything from a Raspberry Pi 71 + to a community server. 72 + </FeatureCard> 73 + <FeatureCard title="Spindles" href="/spindles/"> 74 + <Workflow slot="icon" /> 75 + CI/CD runners for your repositories. Write workflows, or self-host your own 76 + spindle. 77 + </FeatureCard> 78 + <FeatureCard title="Sites" href="/sites/"> 79 + <Globe slot="icon" /> 80 + Serve static websites directly from your git repositories. 81 + </FeatureCard> 82 + <FeatureCard title="Webhooks" href="/reference/webhooks/"> 83 + <Webhook slot="icon" /> 84 + Receive HTTP notifications on repository events and integrate with external 85 + services. 86 + </FeatureCard> 87 + <FeatureCard title="Bobbin" href="/reference/bobbin/"> 88 + <Cable slot="icon" /> 89 + A read-only XRPC API appview for Tangled records. 90 + </FeatureCard> 91 + </div> 92 + 93 + <section class="landing-section"> 94 + 95 + ## What is Tangled? 96 + 97 + Tangled is a social coding platform built on an [open 98 + protocol](https://atproto.com). 99 + 100 + There are several models for decentralized code collaboration platforms, 101 + ranging from ActivityPub's (Forgejo) federated model, to Radicle's 102 + entirely P2P model. Our approach attempts to be the best of both worlds 103 + by adopting the [AT Protocol](https://atproto.com) — a protocol for 104 + building decentralized social applications with a central identity. 105 + 106 + Central to our approach is the idea of **knots**. Knots are lightweight, 107 + headless servers that enable users to host git repositories with ease. 108 + Knots are designed for either single or multi-tenant use, which is 109 + perfect for self-hosting on a Raspberry Pi at home, or larger 110 + "community" servers. By default, Tangled provides managed knots where 111 + you can host your repositories for free. 112 + 113 + The appview at [tangled.org](https://tangled.org) acts as a consolidated 114 + "view" into the whole network, allowing users to access, clone and 115 + contribute to repositories hosted across different knots seamlessly. 116 + 117 + Curious about the protocol choice? Read [why AT Protocol](/why-atproto/). 118 + 119 + </section> 120 + 121 + <section class="landing-section"> 122 + 123 + ## Resources 124 + 125 + <div class="feature-grid"> 126 + <FeatureCard title="Hacking on Tangled" href="/contributing/hacking/"> 127 + <Hammer slot="icon" /> 128 + Set up a dev environment and run the appview, knots, and spindles locally. 129 + </FeatureCard> 130 + <FeatureCard title="Contribution guide" href="/contributing/guide/"> 131 + <GitPullRequest slot="icon" /> 132 + Commit guidelines, code formatting, proposals, and signing your work. 133 + </FeatureCard> 134 + <FeatureCard title="Migrations" href="/reference/migrations/"> 135 + <ArrowUpCircle slot="icon" /> 136 + Upgrade guides for self-hosted knots and spindles. 137 + </FeatureCard> 138 + <FeatureCard title="Troubleshooting" href="/troubleshooting/"> 139 + <LifeBuoy slot="icon" /> 140 + Common issues with login, punchcards, and commit verification. 141 + </FeatureCard> 142 + </div> 143 + 144 + </section>
+60
docs/src/content/docs/knots/index.md
··· 1 + --- 2 + title: What are knots? 3 + description: Knots are lightweight, headless git servers — the foundation of Tangled's decentralized architecture. 4 + sidebar: 5 + order: 0 6 + --- 7 + 8 + Knots are the foundation of Tangled's distributed architecture: 9 + lightweight, headless servers that host git repositories. They are 10 + designed to be trivial to run, whether that's a single-tenant 11 + setup on a Raspberry Pi at home, or a larger multi-tenant 12 + "community" server shared by many users. 13 + 14 + There are several models for decentralized code collaboration, 15 + ranging from ActivityPub's (Forgejo) federated model to Radicle's 16 + entirely P2P model. Tangled takes a hybrid approach by building on 17 + the [AT Protocol](https://atproto.com): decentralized data and 18 + hosting, with a central identity. Your repositories live on a knot 19 + you choose (or run yourself), but your identity — and things like 20 + issues, pull requests, stars and follows — live in your AT 21 + Protocol account, owned by you. 22 + 23 + The appview at [tangled.org](https://tangled.org) ties the network 24 + together: it acts as a consolidated "view" into repositories 25 + hosted across all knots, so you can access, clone, and contribute 26 + to any of them seamlessly. A repository on a home server appears 27 + alongside one on a community knot, with no fragmentation. 28 + 29 + ## What a knot does 30 + 31 + A knot: 32 + 33 + - serves git over SSH (pushes) and HTTP (clones, fetches) 34 + - emits events — pushes, ref updates — that the appview and other 35 + services consume 36 + - owns its member list and per-repository collaborators, served 37 + over XRPC (as of v1.15) 38 + - assigns each repository a DID (as of v1.13), making repositories 39 + stable across renames and transfers 40 + 41 + By default, Tangled provides managed knots where you can host your 42 + repositories for free — you never have to run one yourself. But if 43 + you want your code on your own hardware, self-hosting is a first-class 44 + workflow. 45 + 46 + ## Run your own 47 + 48 + Head to the [self-hosting guide](/knots/self-hosting/) to set one 49 + up — there's a NixOS module, a Docker Compose setup, and a manual 50 + installation path. If you run into trouble, check the 51 + [troubleshooting section](/knots/self-hosting/#troubleshooting), 52 + and keep an eye on the [migration guides](/reference/migrations/) 53 + when upgrading. 54 + 55 + ## Further reading 56 + 57 + - [Introducing Tangled](https://blog.tangled.org/intro) — the 58 + original announcement, with more on the thinking behind knots 59 + - [Hacking on Tangled](/contributing/hacking/) — run a knot 60 + locally in a dev VM
+375
docs/src/content/docs/knots/self-hosting.md
··· 1 + --- 2 + title: Self-hosting a knot 3 + description: "Run your own knot: a lightweight, headless git server." 4 + --- 5 + 6 + 7 + So you want to run your own knot server? Great! Here are a few prerequisites: 8 + 9 + 1. A server of some kind (a VPS, a Raspberry Pi, etc.). Preferably running a Linux distribution of some kind. 10 + 2. A (sub)domain name. People generally use `knot.example.com`. 11 + 3. A valid SSL certificate for your domain. 12 + 13 + ## NixOS 14 + 15 + Refer to the [knot 16 + module](https://tangled.org/tangled.org/core/blob/master/nix/modules/knot.nix) 17 + for a full list of options. Sample configurations: 18 + 19 + - [The test VM](https://tangled.org/tangled.org/core/blob/master/nix/vm.nix#L85) 20 + - [@pyrox.dev/nix](https://tangled.org/pyrox.dev/nix/blob/c2b644c214d278af12523618de952ee2eab1af3d/hosts/marvin/services/tangled.nix#L15-26) 21 + 22 + ## Docker 23 + 24 + Refer to 25 + [@tangled.org/knot-docker](https://tangled.org/@tangled.org/knot-docker). 26 + Note that this is community maintained. 27 + 28 + ## Manual setup 29 + 30 + First, clone this repository: 31 + 32 + ``` 33 + git clone https://tangled.org/@tangled.org/core 34 + ``` 35 + 36 + Then, build the `knot` CLI. This is the knot administration 37 + and operation tool. For the purpose of this guide, we're 38 + only concerned with these subcommands: 39 + 40 + - `knot server`: the main knot server process, typically 41 + run as a supervised service 42 + - `knot guard`: handles role-based access control for git 43 + over SSH (you'll never have to run this yourself) 44 + - `knot keys`: fetches SSH keys associated with your knot; 45 + we'll use this to generate the SSH 46 + `AuthorizedKeysCommand` 47 + 48 + ``` 49 + cd core 50 + export CGO_ENABLED=1 51 + go build -o knot ./cmd/knot 52 + ``` 53 + 54 + Next, move the `knot` binary to a location owned by `root` -- 55 + `/usr/local/bin/` is a good choice. Make sure the binary itself is also owned by `root`: 56 + 57 + ``` 58 + sudo mv knot /usr/local/bin/knot 59 + sudo chown root:root /usr/local/bin/knot 60 + ``` 61 + 62 + This is necessary because SSH `AuthorizedKeysCommand` requires [really 63 + specific permissions](https://stackoverflow.com/a/27638306). The 64 + `AuthorizedKeysCommand` specifies a command that is run by `sshd` to 65 + retrieve a user's public SSH keys dynamically for authentication. Let's 66 + set that up. 67 + 68 + ``` 69 + sudo tee /etc/ssh/sshd_config.d/authorized_keys_command.conf <<EOF 70 + Match User git 71 + AuthorizedKeysCommand /usr/local/bin/knot keys -o authorized-keys 72 + AuthorizedKeysCommandUser nobody 73 + EOF 74 + ``` 75 + 76 + Then, reload `sshd`: 77 + 78 + ``` 79 + sudo systemctl reload ssh 80 + ``` 81 + 82 + Next, create the `git` user. We'll use the `git` user's home directory 83 + to store repositories: 84 + 85 + ``` 86 + sudo adduser git 87 + ``` 88 + 89 + Create `/home/git/.knot.env` with the following, updating the values as 90 + necessary. The `KNOT_SERVER_OWNER` should be set to your 91 + DID, you can find your DID in the [Settings](https://tangled.sh/settings) page. 92 + 93 + ``` 94 + KNOT_REPO_SCAN_PATH=/home/git 95 + KNOT_SERVER_HOSTNAME=knot.example.com 96 + APPVIEW_ENDPOINT=https://tangled.org 97 + KNOT_SERVER_OWNER=did:plc:foobar 98 + KNOT_SERVER_INTERNAL_LISTEN_ADDR=127.0.0.1:5444 99 + KNOT_SERVER_LISTEN_ADDR=127.0.0.1:5555 100 + ``` 101 + 102 + If you run a Linux distribution that uses systemd, you can 103 + use the provided service file to run the server. Copy 104 + [`knotserver.service`](https://tangled.org/tangled.org/core/blob/master/systemd/knotserver.service) 105 + to `/etc/systemd/system/`. Then, run: 106 + 107 + ``` 108 + systemctl enable knotserver 109 + systemctl start knotserver 110 + ``` 111 + 112 + The last step is to configure a reverse proxy like Nginx or Caddy to front your 113 + knot. Here's an example configuration for Nginx: 114 + 115 + ``` 116 + server { 117 + listen 80; 118 + listen [::]:80; 119 + server_name knot.example.com; 120 + 121 + location / { 122 + proxy_pass http://localhost:5555; 123 + proxy_set_header Host $host; 124 + proxy_set_header X-Real-IP $remote_addr; 125 + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 126 + proxy_set_header X-Forwarded-Proto $scheme; 127 + } 128 + 129 + # wss endpoint for git events 130 + location /events { 131 + proxy_set_header X-Forwarded-For $remote_addr; 132 + proxy_set_header Host $http_host; 133 + proxy_set_header Upgrade websocket; 134 + proxy_set_header Connection Upgrade; 135 + proxy_pass http://localhost:5555; 136 + } 137 + # additional config for SSL/TLS go here. 138 + } 139 + 140 + ``` 141 + 142 + Remember to use Let's Encrypt or similar to procure a certificate for your 143 + knot domain. 144 + 145 + You should now have a running knot server! You can finalize 146 + your registration by hitting the `verify` button on the 147 + [/settings/knots](https://tangled.org/settings/knots) page. This simply creates 148 + a record on your PDS to announce the existence of the knot. 149 + 150 + ### Custom paths 151 + 152 + (This section applies to manual setup only. Docker users should edit the mounts 153 + in `docker-compose.yml` instead.) 154 + 155 + Right now, the database and repositories of your knot lives in `/home/git`. You 156 + can move these paths if you'd like to store them in another folder. Be careful 157 + when adjusting these paths: 158 + 159 + - Stop your knot when moving data (e.g. `systemctl stop knotserver`) to prevent 160 + any possible side effects. Remember to restart it once you're done. 161 + - Make backups before moving in case something goes wrong. 162 + - Make sure the `git` user can read and write from the new paths. 163 + 164 + #### Database 165 + 166 + As an example, let's say the current database is at `/home/git/knotserver.db`, 167 + and we want to move it to `/home/git/database/knotserver.db`. 168 + 169 + Copy the current database to the new location. Make sure to copy the `.db-shm` 170 + and `.db-wal` files if they exist. 171 + 172 + ``` 173 + mkdir /home/git/database 174 + cp /home/git/knotserver.db* /home/git/database 175 + ``` 176 + 177 + In the environment (e.g. `/home/git/.knot.env`), set `KNOT_SERVER_DB_PATH` to 178 + the new file path (_not_ the directory): 179 + 180 + ``` 181 + KNOT_SERVER_DB_PATH=/home/git/database/knotserver.db 182 + ``` 183 + 184 + #### Repositories 185 + 186 + As an example, let's say the repositories are currently in `/home/git`, and we 187 + want to move them into `/home/git/repositories`. 188 + 189 + Create the new folder, then move the existing repositories (if there are any): 190 + 191 + ``` 192 + mkdir /home/git/repositories 193 + # move all DIDs into the new folder; these will vary for you! 194 + mv /home/git/did:plc:wshs7t2adsemcrrd4snkeqli /home/git/repositories 195 + ``` 196 + 197 + In the environment (e.g. `/home/git/.knot.env`), update `KNOT_REPO_SCAN_PATH` 198 + to the new directory: 199 + 200 + ``` 201 + KNOT_REPO_SCAN_PATH=/home/git/repositories 202 + ``` 203 + 204 + Similarly, update your `sshd` `AuthorizedKeysCommand` to use the updated 205 + repository path: 206 + 207 + ``` 208 + sudo tee /etc/ssh/sshd_config.d/authorized_keys_command.conf <<EOF 209 + Match User git 210 + AuthorizedKeysCommand /usr/local/bin/knot keys -o authorized-keys -git-dir /home/git/repositories 211 + AuthorizedKeysCommandUser nobody 212 + EOF 213 + ``` 214 + 215 + Make sure to restart your SSH server! 216 + 217 + #### MOTD (message of the day) 218 + 219 + To configure the MOTD used ("Welcome to this knot!" by default), edit the 220 + `/home/git/motd` file: 221 + 222 + ``` 223 + printf "Hi from this knot!\n" > /home/git/motd 224 + ``` 225 + 226 + Note that you should add a newline at the end if setting a non-empty message 227 + since the knot won't do this for you. 228 + 229 + ## Secure Mode 230 + 231 + Secure Mode isolates each `git` subprocess to the repository it is 232 + operating on, using two mechanisms: 233 + 234 + - **Linux Landlock** restricts the filesystem paths the subprocess 235 + can access -- it can only read/write its own repository and the 236 + system directories it needs to run. 237 + - **UID isolation** runs each subprocess as a virtual UID assigned 238 + to the repository owner, so that repositories belonging to 239 + different owners are isolated from each other at the OS level 240 + even if Landlock were somehow bypassed. 241 + 242 + Secure Mode requires: 243 + 244 + - Linux kernel >= 5.19 (Landlock V2). This is the minimum needed 245 + for `git push` to work, because receive-pack's quarantine 246 + migration uses cross-directory rename which requires the 247 + Landlock `REFER` access right (added in V2). Kernels 5.13-5.18 248 + support Landlock V1 and clones will work, but pushes will fail 249 + with cross-device link errors. On kernels without any Landlock 250 + support (< 5.13), the sandbox call is a no-op: UID isolation 251 + still applies but no filesystem restriction is enforced. 252 + - `CAP_SETUID`, `CAP_SETGID`, and `CAP_CHOWN` available to the 253 + knot process. The NixOS module grants these automatically; for 254 + manual setups see the `setcap` step below. 255 + 256 + ### NixOS 257 + 258 + Add `server.secureMode = true;` to your knot module configuration: 259 + 260 + ```nix 261 + services.tangled.knot = { 262 + server.secureMode = true; 263 + # ... other options 264 + }; 265 + ``` 266 + 267 + The NixOS module handles everything else automatically: 268 + 269 + - Grants the required capabilities to the knot service via 270 + `AmbientCapabilities` in the systemd unit. 271 + - Installs a capability-bearing wrapper at 272 + `/run/wrappers/bin/knot` via `security.wrappers`, so that 273 + SSH-invoked git operations (pushes) also run under the correct 274 + UID without requiring the service to run as root. 275 + - Runs `knot migrate-isolation` at service start to chown 276 + existing repositories to their virtual UIDs. 277 + 278 + ### Manual setup 279 + 280 + **Step 1.** Grant the required capabilities to the knot binary. 281 + This allows the knot process to switch to virtual UIDs at runtime 282 + without running as root. You will need to repeat this step 283 + whenever the binary is updated. 284 + 285 + ``` 286 + sudo setcap cap_setuid,cap_setgid,cap_chown+eip /usr/local/bin/knot 287 + ``` 288 + 289 + **Step 2.** Run the migration tool to assign virtual UIDs to all 290 + existing repositories and set their filesystem permissions. This 291 + must be run as root: 292 + 293 + ``` 294 + sudo knot migrate-isolation \ 295 + --git-dir /home/git \ 296 + --db /home/git/knotserver.db \ 297 + --internal-api 127.0.0.1:5444 298 + ``` 299 + 300 + You can re-run this at any time with `--force` to reapply 301 + permissions (e.g. after a manual repair or after updating the 302 + binary). 303 + 304 + **Step 2a.** Ensure the home directory is traversable by 305 + non-group users. Git subprocesses run as virtual UIDs that are 306 + not in the git group, and they need to resolve 307 + `$HOME/.config/git/config` to load the global config: 308 + 309 + ``` 310 + sudo chmod o+x /home/git 311 + ``` 312 + 313 + This adds only the execute bit, not read -- the virtual UIDs can 314 + traverse to known paths but cannot list directory contents. 315 + 316 + **Step 3.** Enable Secure Mode in your environment file: 317 + 318 + ``` 319 + KNOT_SERVER_SECURE_MODE=true 320 + ``` 321 + 322 + Or pass it as a flag: 323 + 324 + ``` 325 + knot server --secure-mode 326 + ``` 327 + 328 + **Step 4.** Regenerate the `AuthorizedKeysCommand` with the 329 + `-secure-mode` flag. This causes `knot keys` to emit guard 330 + command lines that include `-secure-mode`, so SSH pushes also 331 + get UID isolation: 332 + 333 + ``` 334 + sudo tee /etc/ssh/sshd_config.d/authorized_keys_command.conf <<EOF 335 + Match User git 336 + AuthorizedKeysCommand /usr/local/bin/knot keys \ 337 + -o authorized-keys -secure-mode 338 + AuthorizedKeysCommandUser nobody 339 + EOF 340 + ``` 341 + 342 + Reload `sshd` after making this change. 343 + 344 + > **Note:** the server will refuse to start in Secure Mode if any 345 + > repositories have not yet been isolation-migrated. Re-run 346 + > `migrate-isolation` if you see this error. 347 + 348 + ## Troubleshooting 349 + 350 + If you run your own knot, you may run into some of these 351 + common issues. You can always join the 352 + [IRC](https://web.libera.chat/#tangled) or 353 + [Discord](https://chat.tangled.org/) if this section does 354 + not help. 355 + 356 + ### Unable to push 357 + 358 + If you are unable to push to your knot or repository: 359 + 360 + 1. First, ensure that you have added your SSH public key to 361 + your account 362 + 2. Check to see that your knot has synced the key by running 363 + `knot keys` 364 + 3. Check to see if git is supplying the correct private key 365 + when pushing: `GIT_SSH_COMMAND="ssh -v" git push ...` 366 + 4. Check to see if `sshd` on the knot is rejecting the push 367 + for some reason: `journalctl -xeu ssh` (or `sshd`, 368 + depending on your machine). These logs are unavailable if 369 + using docker. 370 + 5. Check to see if the knot itself is rejecting the push, 371 + depending on your setup, the logs might be in one of the 372 + following paths: 373 + - `/tmp/knotguard.log` 374 + - `/home/git/log` 375 + - `/home/git/guard.log`
+251
docs/src/content/docs/quick-start.md
··· 1 + --- 2 + title: Quick start 3 + description: Create an account, add an SSH key, and push your first repository to Tangled. 4 + --- 5 + 6 + 7 + ## Login or sign up 8 + 9 + You can [login](https://tangled.org) by using your AT Protocol 10 + account. If you are unclear on what that means, simply head 11 + to the [signup](https://tangled.org/signup) page and create 12 + an account. By doing so, you will be choosing Tangled as 13 + your account provider (you will be granted a handle of the 14 + form `user.tngl.sh`). 15 + 16 + In the AT Protocol network, users are free to choose their account 17 + provider (known as a "Personal Data Service", or PDS), and 18 + login to applications that support AT accounts. 19 + 20 + You can think of it as "one account for all of the atmosphere"! 21 + 22 + If you already have an AT account (you may have one if you 23 + signed up to Bluesky, for example), you can login with the 24 + same handle on Tangled (so just use `user.bsky.social` on 25 + the login page). 26 + 27 + ## Add an SSH key 28 + 29 + Once you are logged in, you can start creating repositories 30 + and pushing code. Tangled supports pushing git repositories 31 + over SSH. 32 + 33 + First, you'll need to generate an SSH key if you don't 34 + already have one: 35 + 36 + ```bash 37 + ssh-keygen -t ed25519 -C "foo@bar.com" 38 + ``` 39 + 40 + When prompted, save the key to the default location 41 + (`~/.ssh/id_ed25519`) and optionally set a passphrase. 42 + 43 + Copy your public key to your clipboard: 44 + 45 + ```bash 46 + # on X11 47 + cat ~/.ssh/id_ed25519.pub | xclip -sel c 48 + 49 + # on wayland 50 + cat ~/.ssh/id_ed25519.pub | wl-copy 51 + 52 + # on macos 53 + cat ~/.ssh/id_ed25519.pub | pbcopy 54 + ``` 55 + 56 + Now, navigate to 'Settings' -> 'Keys' and hit 'Add Key', 57 + paste your public key, give it a descriptive name, and hit 58 + save. 59 + 60 + ## Create a repository 61 + 62 + Once your SSH key is added, create your first repository: 63 + 64 + 1. Hit the green `+` icon on the topbar, and select 65 + repository 66 + 2. Enter a repository name 67 + 3. Add a description 68 + 4. Choose a knotserver to host this repository on 69 + 5. Hit create 70 + 71 + Knots are self-hostable, lightweight Git servers that can 72 + host your repository. Unlike traditional code forges, your 73 + code can live on any server. Read the [Knots](/knots/self-hosting/) section 74 + for more. 75 + 76 + ## Configure SSH 77 + 78 + To ensure Git uses the correct SSH key and connects smoothly 79 + to Tangled, add this configuration to your `~/.ssh/config` 80 + file: 81 + 82 + ``` 83 + Host tangled.org 84 + Hostname tangled.org 85 + User git 86 + IdentityFile ~/.ssh/id_ed25519 87 + AddressFamily inet 88 + ``` 89 + 90 + This tells SSH to use your specific key when connecting to 91 + Tangled and prevents authentication issues if you have 92 + multiple SSH keys. 93 + 94 + Note that this configuration only works for knotservers that 95 + are hosted by tangled.org. If you use a custom knot, refer 96 + to the [Knots](/knots/self-hosting/) section. 97 + 98 + ## Push your first repository 99 + 100 + Initialize a new Git repository: 101 + 102 + ```bash 103 + mkdir my-project 104 + cd my-project 105 + 106 + git init 107 + echo "# My Project" > README.md 108 + ``` 109 + 110 + Add some content and push! 111 + 112 + ```bash 113 + git add README.md 114 + git commit -m "Initial commit" 115 + git remote add origin git@tangled.org:user.tngl.sh/my-project 116 + git push -u origin main 117 + ``` 118 + 119 + That's it! Your code is now hosted on Tangled. 120 + 121 + ## Migrating an existing repository 122 + 123 + Moving your repositories from GitHub, GitLab, Bitbucket, or 124 + any other Git forge to Tangled is straightforward. You'll 125 + simply change your repository's remote URL. At the moment, 126 + Tangled does not have any tooling to migrate data such as 127 + GitHub issues or pull requests. 128 + 129 + First, create a new repository on tangled.org as described 130 + in the [Quick Start Guide](#create-a-repository). 131 + 132 + Navigate to your existing local repository: 133 + 134 + ```bash 135 + cd /path/to/your/existing/repo 136 + ``` 137 + 138 + You can inspect your existing Git remote like so: 139 + 140 + ```bash 141 + git remote -v 142 + ``` 143 + 144 + You'll see something like: 145 + 146 + ```bash 147 + origin git@github.com:username/my-project.git (fetch) 148 + origin git@github.com:username/my-project.git (push) 149 + ``` 150 + 151 + Update the remote URL to point to tangled: 152 + 153 + ```bash 154 + git remote set-url origin git@tangled.org:user.tngl.sh/my-project 155 + ``` 156 + 157 + Verify the change: 158 + 159 + ```bash 160 + git remote -v 161 + ``` 162 + 163 + You should now see: 164 + 165 + ```bash 166 + origin git@tangled.org:user.tngl.sh/my-project (fetch) 167 + origin git@tangled.org:user.tngl.sh/my-project (push) 168 + ``` 169 + 170 + Push all your branches and tags to Tangled: 171 + 172 + ```bash 173 + git push -u origin --all 174 + git push -u origin --tags 175 + ``` 176 + 177 + Your repository is now migrated to Tangled! All commit 178 + history, branches, and tags have been preserved. 179 + 180 + ## Mirroring a repository to Tangled 181 + 182 + If you want to maintain your repository on multiple forges 183 + simultaneously, for example, keeping your primary repository 184 + on GitHub while mirroring to Tangled for backup or 185 + redundancy, you can do so by adding [multiple remotes](https://git-scm.com/docs/git-push#_remotes). 186 + 187 + You can configure your local repository to push to both 188 + Tangled and, say, GitHub. You may already have the following 189 + setup: 190 + 191 + ```bash 192 + $ git remote -v 193 + origin git@github.com:username/my-project.git (fetch) 194 + origin git@github.com:username/my-project.git (push) 195 + ``` 196 + 197 + Now add Tangled as an additional push URL to the same 198 + remote: 199 + 200 + ```bash 201 + git remote set-url --add --push origin git@tangled.org:user.tngl.sh/my-project 202 + ``` 203 + 204 + You also need to re-add the original URL as a push 205 + destination (Git will now use the original URL to fetch only): 206 + 207 + ```bash 208 + git remote set-url --add --push origin git@github.com:username/my-project.git 209 + ``` 210 + 211 + Verify your configuration: 212 + 213 + ```bash 214 + $ git remote -v 215 + origin git@github.com:username/my-project.git (fetch) 216 + origin git@tangled.org:user.tngl.sh/my-project (push) 217 + origin git@github.com:username/my-project.git (push) 218 + ``` 219 + 220 + Notice that there's one fetch URL (the primary remote) and 221 + two push URLs. Now, whenever you push, Git will 222 + automatically push to both remotes: 223 + 224 + ```bash 225 + git push origin main 226 + ``` 227 + 228 + This single command pushes your `main` branch to both GitHub 229 + and Tangled simultaneously. 230 + 231 + To push all branches and tags: 232 + 233 + ```bash 234 + git push origin --all 235 + git push origin --tags 236 + ``` 237 + 238 + If you prefer more control over which remote you push to, 239 + you can maintain separate remotes: 240 + 241 + ```bash 242 + git remote add github git@github.com:username/my-project.git 243 + git remote add tangled git@tangled.org:user.tngl.sh/my-project 244 + ``` 245 + 246 + Then push to each explicitly: 247 + 248 + ```bash 249 + git push github main 250 + git push tangled main 251 + ```
+239
docs/src/content/docs/reference/bobbin.md
··· 1 + --- 2 + title: Bobbin 3 + description: A read-only XRPC API appview for Tangled records. 4 + --- 5 + 6 + 7 + Bobbin is an API appview for Tangled records. It serves XRPC 8 + endpoints for `sh.tangled.*`, with it you can get repos, 9 + issues, pulls, comments, follows, stars, labels, pipelines, 10 + and profiles. It is read-only, there is no auth, since that 11 + should all be handled direct-to-PDS and knot respectively. 12 + 13 + **Bobbin has no permanent storage**. 14 + 15 + It is only a glorified edge index, in the graph theory 16 + sense. Additionally it has a record cache, re-filled on 17 + demand. All other data that Bobbin serves comes live from 18 + PDSes & knots. 19 + 20 + ## What Bobbin needs 21 + 22 + The way that Bobbin is able to pull off being 23 + so stateless is by moving state upstream. 24 + Primarily it depends on an instance of 25 + [Hydrant](https://tangled.org/did:plc:6v3ul2ptnqctyxwkz5ti4amn) 26 + , which is the service that gives an event stream 27 + for Bobbin to quickly backfill from on every restart. 28 + Backfilling ought to take less than a couple of minutes 29 + maximum. If the upstream instance of Hydrant fails 30 + while Bobbin is live, its list/count endpoints stop 31 + advancing and report a stale cursor. Single-lookups 32 + will continue working, due to the second dependency: 33 + [Slingshot](https://tangled.org/did:plc:c7mc2fn47ihdihul4vjwsuy3/tree/main/slingshot). 34 + Slingshot fetches individual records & resolves identities. 35 + If the upstream instance of Slingshot fails, single-lookups 36 + will fail with a `502` error. There are some aggregation 37 + endpoints that use Slingshot for hydrating, which will also 38 + fail. 39 + 40 + A soft dependency that ought to exist for Bobbin to operate 41 + correctly is simply the plethora of knots that are out 42 + there, that Bobbin talks to directly for git data and, for 43 + knots at v1.15+, members & collaborators. 44 + 45 + ## Building Bobbin 46 + 47 + Bobbin is under [Tangled's core monorepo, under bobbin/](https://tangled.org/did:plc:j5hmlfdrwkvtxm7cjmu7j2is/tree/master/bobbin). 48 + Here's an easy local debug-build: 49 + 50 + ```sh 51 + cargo build -p bobbin 52 + ``` 53 + 54 + Bobbin loves being in a container. When using 55 + `bobbin/containerfiles/bobbin.Containerfile`, it runs `cargo 56 + build --release --bin bobbin --package bobbin` within a 57 + little Debian runtime, exposing port 8090. 58 + 59 + ## Configuration 60 + 61 + The best way to configure Bobbin is via a toml config file. 62 + There's an `example.toml` in [Bobbin's subdir](https://tangled.org/did:plc:j5hmlfdrwkvtxm7cjmu7j2is/blob/master/bobbin/example.toml). 63 + Every value is overridable by a `BOBBIN_*` env var. 64 + The load order is env, then `--config <path>`, then 65 + `/etc/bobbin/config.toml`, then built-in defaults. 66 + 67 + Load and check a config without starting the server: 68 + 69 + ```sh 70 + bobbin --config config.toml validate 71 + ``` 72 + 73 + Minimal config is the two upstream URLs. The hydrant URL 74 + takes `ws://` or `wss://`. An `http://` or `https://` 75 + URL is rewritten to the matching websocket scheme at 76 + connection-time. 77 + 78 + ```toml 79 + [server] 80 + binds = ["127.0.0.1:8090"] 81 + 82 + # Loopback-only & can leave empty to disable debug introspection. 83 + debug_bind = "127.0.0.1:8091" 84 + 85 + [hydrant] 86 + url = "https://hydrant.example.com" 87 + 88 + [slingshot] 89 + url = "https://slingshot.example.com" 90 + ``` 91 + 92 + > 🦪 Lewis 93 + > 94 + > At time of writing, we (Tangled) don't host public 95 + > instances of Hydrant or Slingshot. You will have to 96 + > find public instances or spin these up yourself! :P 97 + 98 + Take a gander in the project's example.toml for an 99 + exhaustive list of things to configure. 100 + 101 + You will discover fun things such as a configurable adaptive 102 + loop that watches the cgroup memory limit & throttles heavy 103 + requests under pressure. It only works if it detects a 104 + cgroup limit is present. The config for that is in the 105 + `[backpressure]` block of the config template. 106 + 107 + ## Running Bobbin 108 + 109 + Start the server using a config toml: 110 + 111 + ```bash 112 + bobbin --config config.toml 113 + ``` 114 + Bobbin wakes up in a cold sweat and immediately gets to 115 + work: 116 + 1. It binds its listeners, connects to the Hydrant stream 117 + in the background. 118 + 2. It serves requests from the first 119 + moment it's alive, even before the Hydrant stream connects 120 + or finishes catching up. Having a cold Hydrant itself 121 + costs only latency and approximate counts. 122 + 123 + ## The API 124 + 125 + **Single lookups** take a record's AT-URI. 126 + 127 + - `getRepo` takes the repo URI: 128 + 129 + ```sh 130 + curl "$BOBBIN/xrpc/sh.tangled.repo.getRepo?repo=at://did:plc:boltless/sh.tangled.repo/squid" 131 + ``` 132 + ```json 133 + { 134 + "uri": "at://did:plc:boltless/sh.tangled.repo/squid", 135 + "cid": "bafyrei...", 136 + "value": { "$type": "sh.tangled.repo", "knot": "knot1.tangled.sh", "description": "...", "createdAt": "..." } 137 + } 138 + ``` 139 + 140 + - `getProfile` takes the full profile record URI, so a bare 141 + handle or DID will not resolve: 142 + 143 + ```sh 144 + curl "$BOBBIN/xrpc/sh.tangled.actor.getProfile?actor=at://did:plc:boltless/sh.tangled.actor.profile/self" 145 + ``` 146 + 147 + - If Slingshot cannot serve the record, the response is `502`: 148 + 149 + ```json 150 + { "error": "UpstreamFailed", "message": "upstream unavailable: ..." } 151 + ``` 152 + 153 + **Aggregation** endpoints come in `list*` and `count*` pairs, 154 + each with a `*By` sibling, and require a `subject` query param. 155 + 156 + - `listRepos` and `countRepos` key on the owner DID: 157 + 158 + ```sh 159 + curl "$BOBBIN/xrpc/sh.tangled.repo.countRepos?subject=did:plc:boltless" 160 + ``` 161 + ```json 162 + { "count": 7, "distinctAuthors": 1 } 163 + ``` 164 + 165 + ```sh 166 + curl "$BOBBIN/xrpc/sh.tangled.repo.listRepos?subject=did:plc:boltless&limit=3" 167 + ``` 168 + ```json 169 + { "items": [ { "uri": "at://did:plc:boltless/sh.tangled.repo/squid", "cid": "bafyrei...", "value": { } } ], "cursor": null } 170 + ``` 171 + 172 + - Bobbin validates the subject per collection. Here a repo URI 173 + is passed where a bare DID is required, so the call returns a 174 + `400`: 175 + 176 + ```sh 177 + curl "$BOBBIN/xrpc/sh.tangled.graph.listFollows?subject=at://did:plc:boltless/sh.tangled.repo/squid" 178 + ``` 179 + ```json 180 + { "error": "InvalidRequest", "message": "invalid request: subject must be a bare did, got at-uri with collection sh.tangled.repo" } 181 + ``` 182 + 183 + **Search** is a single endpoint over an in-mem full-text 184 + index: 185 + 186 + ```sh 187 + curl "$BOBBIN/xrpc/sh.tangled.search.query?q=tangled&limit=2" 188 + ``` 189 + ```json 190 + { "hits": [ { "uri": "at://...", "cid": "...", "nsid": "sh.tangled.repo", "score": 27.1, "value": { } } ], "cursor": null } 191 + ``` 192 + 193 + **Git data** such as blob, tree, diff, log, and archive proxies 194 + straight to the repo's knot, streamed back without caching. 195 + 196 + ## Coverage and warm-up 197 + 198 + - While the edge index is catching up from Hydrant, 199 + the aggregation count is a lower bound & may still climb. 200 + - One endpoint reports how far along the backfill it is: 201 + 202 + ```sh 203 + curl "$BOBBIN/xrpc/sh.tangled.bobbin.getCoverage" 204 + ``` 205 + 206 + While warming up: 207 + 208 + ```json 209 + { "ready": false, "eventsProcessed": 45588, "lastCursor": 51658 } 210 + ``` 211 + 212 + Once caught up, Bobbin flips to ready: 213 + 214 + ```json 215 + { "ready": true, "eventsProcessed": 106085, "lastCursor": 116527 } 216 + ``` 217 + 218 + If starting up Hydrant for the first time, Hydrant itself 219 + will take a decent while (a couple of hours) to backfill 220 + from PDSes. Hydrant stores its backfill on disk. Bobbin 221 + restart reaches `ready` in minutes by replaying event from 222 + an already-populated Hydrant. If your Hydrant is new, expect 223 + Bobbin to backfill in that same couple of hours that Hydrant 224 + takes. 225 + 226 + ## Loose ends and not-gonna-impl 227 + 228 + - **No coverage signal for per-knot rosters yet.** 229 + Coverage tracks the hydrant stream only. A v1.15 knot 230 + that is unreachable serves a stale or empty member set 231 + with nothing to flag it. 232 + - **Knot eventstream fan-out isn't pooled.** 233 + Bobbin opens one websocket per v1.15 234 + knot on top of the hydrant subscription. A network with 235 + thousands of knots wants pooling or a shared subscription. 236 + - **No sequential issue or PR numbers.** bobbin returns rkeys, 237 + not `#42` style ids like the web appview. A client 238 + deriving a display number does it from creation order. But 239 + why bother? rkeys are the IDs.
+138
docs/src/content/docs/reference/migrations.md
··· 1 + --- 2 + title: Migrating knots and spindles 3 + description: Upgrade guides for non-backwards compatible knot/spindle changes. 4 + --- 5 + 6 + 7 + Sometimes, non-backwards compatible changes are made to the 8 + knot/spindle XRPC APIs. If you host a knot or a spindle, you 9 + will need to follow this guide to upgrade. Typically, this 10 + only requires you to deploy the newest version. 11 + 12 + This document is laid out in reverse-chronological order. 13 + Newer migration guides are listed first, and older guides 14 + are further down the page. 15 + 16 + ## Upgrading to v1.16.0-alpha 17 + 18 + Starting with v1.16.0-alpha, spindles own CI pipeline data 19 + directly. The appview no longer stores pipeline runs or follows 20 + spindle event streams for pipeline history. Instead, it asks the 21 + configured spindle for pipeline lists, single pipeline details, 22 + workflow logs, retries, and cancellations over XRPC. 23 + 24 + This means that existing pipeline logs / runs won't appear after 25 + you upgrade. Existing pipeline history from the appview cannot be 26 + automatically migrated. If you want to migrate your data, you can 27 + reach out to us and we will send you an SQL file that'll add the data 28 + into your spindle. 29 + 30 + - Upgrade to the latest tag (v1.16.0 or above) 31 + - Head to the [spindle 32 + dashboard](https://tangled.org/settings/spindles) and hit the 33 + "retry" button to verify your spindle 34 + 35 + ## Upgrading to v1.15.0-alpha 36 + 37 + With v1.15.0-alpha, a knot itself owns its members and 38 + per-repo collaborators directly. Previously this data was sourced from 39 + PDS records (`sh.tangled.knot.member` and `sh.tangled.repo.collaborator`) 40 + that the appview and the knot both read off the firehose. 41 + The knot is now the source of truth and serves them over XRPC instead: 42 + 43 + - `sh.tangled.knot.addMember`, `sh.tangled.knot.removeMember`, `sh.tangled.knot.listMembers` 44 + - `sh.tangled.repo.addCollaborator`, `sh.tangled.repo.removeCollaborator`, `sh.tangled.repo.listCollaborators` 45 + 46 + Until your knot is upgraded, the appview keeps reading its 47 + members and collaborators from the old firehose-sourced records. 48 + Upgrade to move your knot onto knot-owned access control. 49 + 50 + - Upgrade to the latest tag (v1.15.0 or above) 51 + - Head to the [knot dashboard](https://tangled.org/settings/knots) and 52 + hit the "retry" button to verify your knot 53 + 54 + ## Upgrading to v1.14.0-alpha 55 + 56 + Starting with v1.14.0-alpha, the fully knot uses the repoDID as its 57 + canonical handle for repositories. This unlocks repository 58 + renames from the appview UI and changes the wire format for 59 + the following lexicons (`sh.tangled.repo.pull`, `sh.tangled.repo.collaborator`, 60 + `sh.tangled.repo.issue`, `sh.tangled.git.refUpdate`). 61 + 62 + Knots that have not been upgraded may silently drop new push 63 + events, pull requests, issues, and collaborator invites for 64 + repositories they host until upgraded. So upgrade please!!! 65 + 66 + - Upgrade to the latest tag (v1.14.0 or above) 67 + - Head to the [knot dashboard](https://tangled.org/settings/knots) and 68 + hit the "retry" button to verify your knot 69 + 70 + ## Upgrading to v1.13.0-alpha 71 + 72 + Starting with v1.13.0-alpha, every repository on a knot is 73 + assigned a DID. This makes repositories stable across 74 + renames and transfers. 75 + 76 + When you upgrade your knot to this version, the server will 77 + automatically mint DIDs for all existing repositories on 78 + startup. This is a one-time process and you may see 79 + additional log output during the first boot as DIDs are 80 + assigned. 81 + 82 + - Upgrade to the latest tag (v1.13.0 or above) 83 + - Head to the [knot dashboard](https://tangled.org/settings/knots) and 84 + hit the "retry" button to verify your knot 85 + 86 + ## Upgrading from v1.8.x 87 + 88 + After v1.8.2, the HTTP API for knots and spindles has been 89 + deprecated and replaced with XRPC. Repositories on outdated 90 + knots will not be viewable from the appview. Upgrading is 91 + straightforward however. 92 + 93 + For knots: 94 + 95 + - Upgrade to the latest tag (v1.9.0 or above) 96 + - Head to the [knot dashboard](https://tangled.org/settings/knots) and 97 + hit the "retry" button to verify your knot 98 + 99 + For spindles: 100 + 101 + - Upgrade to the latest tag (v1.9.0 or above) 102 + - Head to the [spindle 103 + dashboard](https://tangled.org/settings/spindles) and hit the 104 + "retry" button to verify your spindle 105 + 106 + ## Upgrading from v1.7.x 107 + 108 + After v1.7.0, knot secrets have been deprecated. You no 109 + longer need a secret from the appview to run a knot. All 110 + authorized commands to knots are managed via [Inter-Service 111 + Authentication](https://atproto.com/specs/xrpc#inter-service-authentication-jwt). 112 + Knots will be read-only until upgraded. 113 + 114 + Upgrading is quite easy, in essence: 115 + 116 + - `KNOT_SERVER_SECRET` is no more, you can remove this 117 + environment variable entirely 118 + - `KNOT_SERVER_OWNER` is now required on boot, set this to 119 + your DID. You can find your DID in the 120 + [settings](https://tangled.org/settings) page. 121 + - Restart your knot once you have replaced the environment 122 + variable 123 + - Head to the [knot dashboard](https://tangled.org/settings/knots) and 124 + hit the "retry" button to verify your knot. This simply 125 + writes a `sh.tangled.knot` record to your PDS. 126 + 127 + If you use the nix module, simply bump the flake to the 128 + latest revision, and change your config block like so: 129 + 130 + ```diff 131 + services.tangled.knot = { 132 + enable = true; 133 + server = { 134 + - secretFile = /path/to/secret; 135 + + owner = "did:plc:foo"; 136 + }; 137 + }; 138 + ```
+215
docs/src/content/docs/reference/webhooks.md
··· 1 + --- 2 + title: Webhooks 3 + description: Receive HTTP POST notifications when events occur in your repositories. 4 + --- 5 + 6 + 7 + Webhooks allow you to receive HTTP POST notifications when events occur in your repositories. This enables you to integrate Tangled with external services, trigger CI/CD pipelines, send notifications, or automate workflows. 8 + 9 + ## Overview 10 + 11 + Webhooks send HTTP POST requests to URLs you configure whenever specific events happen. Currently, Tangled supports push, repository rename, and pull request events, with more event types coming soon. 12 + 13 + ## Configuring webhooks 14 + 15 + To set up a webhook for your repository: 16 + 17 + 1. Navigate to your repository 18 + 2. Go to **Settings → Hooks** 19 + 3. Click **new webhook** 20 + 4. Configure your webhook: 21 + - **Payload URL**: The endpoint that will receive the webhook POST requests 22 + - **Secret**: An optional secret key for verifying webhook authenticity (leave blank to send unsigned webhooks) 23 + - **Events**: Select which events trigger the webhook 24 + - **Active**: Toggle whether the webhook is enabled 25 + 26 + ## Webhook payload 27 + 28 + ### Push 29 + 30 + When a push event occurs, Tangled sends a POST request with a JSON payload of the format: 31 + 32 + ```json 33 + { 34 + "after": "7b320e5cbee2734071e4310c1d9ae401d8f6cab5", 35 + "before": "c04ddf64eddc90e4e2a9846ba3b43e67a0e2865e", 36 + "pusher": { 37 + "did": "did:plc:hwevmowznbiukdf6uk5dwrrq" 38 + }, 39 + "ref": "refs/heads/main", 40 + "repository": { 41 + "clone_url": "https://tangled.org/did:plc:hwevmowznbiukdf6uk5dwrrq/some-repo", 42 + "created_at": "2025-09-15T08:57:23Z", 43 + "description": "an example repository", 44 + "fork": false, 45 + "full_name": "did:plc:hwevmowznbiukdf6uk5dwrrq/some-repo", 46 + "html_url": "https://tangled.org/did:plc:hwevmowznbiukdf6uk5dwrrq/some-repo", 47 + "name": "some-repo", 48 + "open_issues_count": 5, 49 + "owner": { 50 + "did": "did:plc:hwevmowznbiukdf6uk5dwrrq" 51 + }, 52 + "ssh_url": "ssh://git@tangled.org/did:plc:hwevmowznbiukdf6uk5dwrrq/some-repo", 53 + "stars_count": 1, 54 + "updated_at": "2025-09-15T08:57:23Z" 55 + } 56 + } 57 + ``` 58 + 59 + ### Pull request 60 + 61 + Pull request events are sent as separate event types, so you can subscribe to 62 + exactly the transitions you care about: 63 + 64 + - `pull_request:created` — a pull request was opened 65 + - `pull_request:resubmitted` — a new round (revision) was pushed to a pull request 66 + - `pull_request:merged` — a pull request was merged 67 + - `pull_request:closed` — a pull request was closed 68 + - `pull_request:reopened` — a closed pull request was reopened 69 + 70 + All pull request events share the same payload format: 71 + 72 + ```json 73 + { 74 + "action": "created", 75 + "pull_request": { 76 + "number": 4, 77 + "title": "add dark mode", 78 + "body": "implements dark mode as discussed in #2", 79 + "state": "open", 80 + "target_branch": "main", 81 + "source": { 82 + "branch": "dark-mode", 83 + "sha": "7b320e5cbee2734071e4310c1d9ae401d8f6cab5" 84 + }, 85 + "round_number": 0, 86 + "owner": { 87 + "did": "did:plc:hwevmowznbiukdf6uk5dwrrq" 88 + }, 89 + "html_url": "https://tangled.org/did:plc:hwevmowznbiukdf6uk5dwrrq/some-repo/pulls/4", 90 + "patch_url": "https://tangled.org/did:plc:hwevmowznbiukdf6uk5dwrrq/some-repo/pulls/4/round/0.patch", 91 + "created_at": "2025-09-15T08:57:23Z" 92 + }, 93 + "repository": { ... }, 94 + "sender": { 95 + "did": "did:plc:hwevmowznbiukdf6uk5dwrrq" 96 + } 97 + } 98 + ``` 99 + 100 + Notes: 101 + 102 + - `action` mirrors the event type suffix (`created`, `resubmitted`, `merged`, `closed`, `reopened`). 103 + - `repository` has the same format as in the push payload. 104 + - The patch itself is not embedded in the payload (patches can be large); fetch it from `patch_url` instead. `round_number` identifies the latest round, and `patch_url` always points at that round's patch. 105 + - `source` is only present for branch-based and fork-based pull requests; it is omitted for patch-based pulls. For fork-based pulls, `source.repo` contains the DID of the source repository. 106 + - `sender` is the user who performed the action. 107 + 108 + ## HTTP headers 109 + 110 + Each webhook request includes the following headers: 111 + 112 + - `Content-Type: application/json` 113 + - `User-Agent: Tangled-Hook/<short-sha>` — User agent with short SHA of the commit (push events); `Tangled-Hook/pull_request` for pull request events 114 + - `X-Tangled-Event: push` — The full event type (e.g. `push`, `pull_request:merged`) 115 + - `X-Tangled-Hook-ID: <webhook-id>` — The webhook ID 116 + - `X-Tangled-Delivery: <uuid>` — Unique delivery ID 117 + - `X-Tangled-Signature-256: sha256=<hmac>` — HMAC-SHA256 signature (if secret configured) 118 + 119 + ## Verifying webhook signatures 120 + 121 + If you configured a secret, you should verify the webhook signature to ensure requests are authentic. For example, in Go: 122 + 123 + ```go 124 + package main 125 + 126 + import ( 127 + "crypto/hmac" 128 + "crypto/sha256" 129 + "encoding/hex" 130 + "io" 131 + "net/http" 132 + "strings" 133 + ) 134 + 135 + func verifySignature(payload []byte, signatureHeader, secret string) bool { 136 + // Remove 'sha256=' prefix from signature header 137 + signature := strings.TrimPrefix(signatureHeader, "sha256=") 138 + 139 + // Compute expected signature 140 + mac := hmac.New(sha256.New, []byte(secret)) 141 + mac.Write(payload) 142 + expected := hex.EncodeToString(mac.Sum(nil)) 143 + 144 + // Use constant-time comparison to prevent timing attacks 145 + return hmac.Equal([]byte(signature), []byte(expected)) 146 + } 147 + 148 + func webhookHandler(w http.ResponseWriter, r *http.Request) { 149 + // Read the request body 150 + payload, err := io.ReadAll(r.Body) 151 + if err != nil { 152 + http.Error(w, "Bad request", http.StatusBadRequest) 153 + return 154 + } 155 + 156 + // Get signature from header 157 + signatureHeader := r.Header.Get("X-Tangled-Signature-256") 158 + 159 + // Verify signature 160 + if signatureHeader != "" && verifySignature(payload, signatureHeader, yourSecret) { 161 + // Webhook is authentic, process it 162 + processWebhook(payload) 163 + w.WriteHeader(http.StatusOK) 164 + } else { 165 + http.Error(w, "Invalid signature", http.StatusUnauthorized) 166 + } 167 + } 168 + ``` 169 + 170 + ## Delivery retries 171 + 172 + Webhooks are automatically retried on failure: 173 + 174 + - **3 total attempts** (1 initial + 2 retries) 175 + - **Exponential backoff** starting at 1 second, max 10 seconds 176 + - **Retried on**: 177 + - Network errors 178 + - HTTP 5xx server errors 179 + - **Not retried on**: 180 + - HTTP 4xx client errors (bad request, unauthorized, etc.) 181 + 182 + ### Timeouts 183 + 184 + Webhook requests timeout after 30 seconds. If your endpoint needs more time: 185 + 186 + 1. Respond with 200 OK immediately 187 + 2. Process the webhook asynchronously in the background 188 + 189 + ## Example integrations 190 + 191 + ### Discord notifications 192 + 193 + ```javascript 194 + app.post("/webhook", (req, res) => { 195 + const payload = req.body; 196 + 197 + fetch("https://discord.com/api/webhooks/...", { 198 + method: "POST", 199 + headers: { "Content-Type": "application/json" }, 200 + body: JSON.stringify({ 201 + content: `New push to ${payload.repository.full_name}`, 202 + embeds: [ 203 + { 204 + title: `${payload.pusher.did} pushed to ${payload.ref}`, 205 + url: payload.repository.html_url, 206 + color: 0x00ff00, 207 + }, 208 + ], 209 + }), 210 + }); 211 + 212 + res.status(200).send("OK"); 213 + }); 214 + ``` 215 +
+105
docs/src/content/docs/sites.md
··· 1 + --- 2 + title: Hosting websites 3 + description: Serve static websites directly from your git repositories on Tangled. 4 + --- 5 + 6 + 7 + You can serve static websites directly from your git repositories on 8 + Tangled. If you've used GitHub Pages or Codeberg Pages, this should feel 9 + familiar. 10 + 11 + ## Overview 12 + 13 + Every user gets a sites domain. If you signed up through Tangled's own 14 + PDS (`tngl.sh`), your sites domain is automatically 15 + `<your-handle>.tngl.sh` no setup needed. Otherwise, you can claim a 16 + `<subdomain>.tngl.io` domain from your settings. 17 + 18 + You can serve multiple sites per domain: 19 + 20 + - One **index site** served at the root of your domain (e.g. 21 + `alice.tngl.sh`) 22 + - Any number of **sub-path sites** served under the repository name 23 + (e.g. `alice.tngl.sh/my-project`) 24 + 25 + ## Claiming a domain 26 + 27 + If you don't have a `tngl.sh` handle, you need to claim a domain before 28 + publishing sites: 29 + 30 + 1. Go to **Settings → Sites** 31 + 2. Enter a subdomain (e.g. `alice` to claim `alice.tngl.io`) 32 + 3. Click **claim** 33 + 34 + You can only hold one domain at a time. Releasing a domain puts it in a 35 + 30-day cooldown before anyone else can claim it. 36 + 37 + ## Configuring a site for a repository 38 + 39 + 1. Navigate to your repository 40 + 2. Go to **Settings → Sites** 41 + 3. Choose a **branch** to deploy from 42 + 4. Set the **deploy directory** — the path within the repository 43 + containing your `index.html`. Use `/` for the root, or a subdirectory 44 + like `/docs` or `/public` 45 + 5. Choose the **site type**: 46 + - **Index site** — served at the root of your domain (e.g. 47 + `alice.tngl.sh`) 48 + - **Sub-path site** — served under the repository name (e.g. 49 + `alice.tngl.sh/my-project`) 50 + 6. Click **save** 51 + 52 + The site will be deployed automatically. You can see the status of your 53 + previous deploys in the **Recent Deploys** section at the bottom of the 54 + page. 55 + 56 + Sites are redeployed automatically on every push to the configured 57 + branch. 58 + 59 + ## Custom domains 60 + 61 + Tangled currently doesn't support custom domains for sites. This will be 62 + added in a future update. 63 + 64 + ## Deploy directory 65 + 66 + The deploy directory is the path within your repository that Tangled 67 + serves as the site root. It must contain an `index.html`. 68 + 69 + | Deploy directory | Result | 70 + |---|---| 71 + | `/` | Serves the repository root | 72 + | `/docs` | Serves the `docs/` subdirectory | 73 + | `/public` | Serves the `public/` subdirectory | 74 + 75 + Directories are served with automatic `index.html` resolution -- a 76 + request to `/about` will serve `/about/index.html` if it exists. 77 + 78 + ## Site types 79 + 80 + | Type | URL | 81 + |---|---| 82 + | Index site | `alice.tngl.sh` | 83 + | Sub-path site | `alice.tngl.sh/my-project` | 84 + 85 + Only one repository can be the index site for a given domain at a time. 86 + If another repository already holds the index site, you will see a 87 + notice in the settings and only the sub-path option will be available. 88 + 89 + ## Deploy triggers 90 + 91 + A deployment is triggered automatically when: 92 + 93 + - You push to the configured branch 94 + - You change the site configuration (branch, deploy directory, or site 95 + type) 96 + 97 + ## Disabling a site 98 + 99 + To stop serving a site, go to **Settings → Sites** in your repository 100 + and click **Disable**. This removes the site configuration and stops 101 + serving the site. The deployed files are also deleted from storage. 102 + 103 + Releasing your domain from **Settings → Sites** at the account level 104 + will disable all sites associated with it and delete their files. 105 +
+37
docs/src/content/docs/spindles/architecture.md
··· 1 + --- 2 + title: Architecture 3 + description: How spindle listens for records and executes pipelines. 4 + --- 5 + 6 + 7 + Spindle is a small CI runner service. Here's a high-level overview of how it operates: 8 + 9 + - Listens for [`sh.tangled.spindle.member`](https://tangled.org/@tangled.org/core/blob/master/lexicons/spindle/member.json) and 10 + [`sh.tangled.repo`](https://tangled.org/@tangled.org/core/blob/master/lexicons/repo.json) records on the Jetstream. 11 + - When a new repo record comes through (typically when you add a spindle to a 12 + repo from the settings), spindle then resolves the underlying knot and 13 + subscribes to repo events (see: 14 + [`sh.tangled.pipeline`](https://tangled.org/@tangled.org/core/blob/master/lexicons/pipeline.json)). 15 + - The spindle engine then handles execution of the pipeline, with results and 16 + logs beamed on the spindle event stream over WebSocket 17 + 18 + ## The engines 19 + 20 + Spindle has two execution backends, picked per-workflow with 21 + the [`engine`](#engine) field: 22 + 23 + - **nixery**: executes each step in a fresh Docker container 24 + (Podman works too, if Docker compatibility is enabled so 25 + that `/run/docker.sock` is created), with state persisted 26 + across steps within the `/tangled/workspace` directory. The 27 + base image for the container is constructed on the fly using 28 + [Nixery](https://nixery.dev), which is/rhandy for caching 29 + layers for frequently used packages. 30 + - **microvm**: runs the whole workflow inside its own 31 + microVM, supporting different images, with extra 32 + configuration for NixOS images (e.g. services in workflow file) 33 + See the [engine 34 + README](https://tangled.org/tangled.org/core/blob/master/spindle/engines/microvm/README.md) 35 + for the architecture in depth. 36 + 37 + The pipeline manifest is [specified here](/spindles/workflows/#pipelines).
+65
docs/src/content/docs/spindles/index.md
··· 1 + --- 2 + title: What are spindles? 3 + description: Spindles are Tangled's CI runners, built atop Nix and the AT Protocol. 4 + sidebar: 5 + order: 0 6 + --- 7 + 8 + Spindle is Tangled's continuous integration runner, built atop Nix 9 + and the AT Protocol. Like knots, spindles are self-hostable by 10 + design: you can use a managed spindle, or run your own and point 11 + your repositories at it. 12 + 13 + A spindle subscribes to repository events. When you push code or 14 + open a pull request, the knot hosting the repository emits an 15 + event; the spindle picks it up, reads the [workflow 16 + manifests](/spindles/workflows/) in `.tangled/workflows/`, spins 17 + up an execution environment, and runs your steps. Status and logs 18 + stream back over websockets, so you can watch runs live from the 19 + appview (or [tail them over SSH](https://blog.tangled.org/ssh)). 20 + 21 + Workflow manifests are intentionally simple. There is no 22 + "marketplace" of workflows or complex job orchestration — 23 + dependencies are just [nixpkgs](https://search.nixos.org) 24 + packages, listed by name, with no toolchain setup. 25 + 26 + ## Engines 27 + 28 + Spindles can execute workflows on two engines: 29 + 30 + - **nixery** runs each step in an OCI container (Docker, or 31 + Podman with Docker compatibility). Images are built on the fly 32 + by [Nixery](https://nixery.dev), which turns a list of Nix 33 + packages into a layered container image. 34 + - **microVM** runs the whole workflow inside a QEMU microVM — a 35 + VM with the boring parts removed: no BIOS, no PCI bus to probe, 36 + no emulated graphics. Boot times are fast, isolation is strong 37 + (isolated network namespaces, DNS filtering, blackholed 38 + special-use IP ranges), and workflows can declare NixOS 39 + configuration directly — `services.postgresql.enable: true` gets 40 + you a running database. Existing nixery workflows port over by 41 + changing `engine: nixery` to `engine: microvm`. 42 + 43 + Secrets use AT Protocol [service 44 + auth](https://atproto.com/specs/xrpc#inter-service-authentication-jwt): 45 + the appview makes a signed request using the logged-in user's DID 46 + key, and the spindle verifies the signature against the public key 47 + in their DID document. No shared secrets between services. 48 + 49 + ## Where to go next 50 + 51 + - [Workflows](/spindles/workflows/) — the manifest format: 52 + triggers, dependencies, engines, and example recipes 53 + - [Self-hosting a spindle](/spindles/self-hosting/) — run your own 54 + CI on your own machines 55 + - [Secrets with OpenBao](/spindles/secrets/) — back spindle 56 + secrets with OpenBao instead of SQLite 57 + - [Architecture](/spindles/architecture/) — how spindle consumes 58 + records and executes pipelines 59 + 60 + ## Further reading 61 + 62 + - [Introducing spindle](https://blog.tangled.org/ci) — the 63 + announcement post 64 + - [Tangled CI runs on microVMs](https://blog.tangled.org/spindle-microvm) 65 + — a deep dive into the QEMU-based microVM engine
+302
docs/src/content/docs/spindles/secrets.md
··· 1 + --- 2 + title: Secrets with OpenBao 3 + description: Use OpenBao Proxy for spindle secrets management instead of SQLite. 4 + --- 5 + 6 + 7 + This document covers setting up spindle to use OpenBao for secrets 8 + management via OpenBao Proxy instead of the default SQLite backend. 9 + 10 + ## Overview 11 + 12 + Spindle now uses OpenBao Proxy for secrets management. The proxy handles 13 + authentication automatically using AppRole credentials, while spindle 14 + connects to the local proxy instead of directly to the OpenBao server. 15 + 16 + This approach provides better security, automatic token renewal, and 17 + simplified application code. 18 + 19 + ## Installation 20 + 21 + Install OpenBao from Nixpkgs: 22 + 23 + ```bash 24 + nix shell nixpkgs#openbao # for a local server 25 + ``` 26 + 27 + ## Setup 28 + 29 + The setup process can is documented for both local development and production. 30 + 31 + ### Local development 32 + 33 + Start OpenBao in dev mode: 34 + 35 + ```bash 36 + bao server -dev -dev-root-token-id="root" -dev-listen-address=127.0.0.1:8201 37 + ``` 38 + 39 + This starts OpenBao on `http://localhost:8201` with a root token. 40 + 41 + Set up environment for bao CLI: 42 + 43 + ```bash 44 + export BAO_ADDR=http://localhost:8200 45 + export BAO_TOKEN=root 46 + ``` 47 + 48 + ### Production 49 + 50 + You would typically use a systemd service with a 51 + configuration file. Refer to 52 + [@tangled.org/infra](https://tangled.org/@tangled.org/infra) 53 + for how this can be achieved using Nix. 54 + 55 + Then, initialize the bao server: 56 + 57 + ```bash 58 + bao operator init -key-shares=1 -key-threshold=1 59 + ``` 60 + 61 + This will print out an unseal key and a root key. Save them 62 + somewhere (like a password manager). Then unseal the vault 63 + to begin setting it up: 64 + 65 + ```bash 66 + bao operator unseal <unseal_key> 67 + ``` 68 + 69 + All steps below remain the same across both dev and 70 + production setups. 71 + 72 + ### Configure openbao server 73 + 74 + Create the spindle KV mount: 75 + 76 + ```bash 77 + bao secrets enable -path=spindle -version=2 kv 78 + ``` 79 + 80 + Set up AppRole authentication and policy: 81 + 82 + Create a policy file `spindle-policy.hcl`: 83 + 84 + ```hcl 85 + # Full access to spindle KV v2 data 86 + path "spindle/data/*" { 87 + capabilities = ["create", "read", "update", "delete"] 88 + } 89 + 90 + # Access to metadata for listing and management 91 + path "spindle/metadata/*" { 92 + capabilities = ["list", "read", "delete", "update"] 93 + } 94 + 95 + # Allow listing at root level 96 + path "spindle/" { 97 + capabilities = ["list"] 98 + } 99 + 100 + # Required for connection testing and health checks 101 + path "auth/token/lookup-self" { 102 + capabilities = ["read"] 103 + } 104 + ``` 105 + 106 + Apply the policy and create an AppRole: 107 + 108 + ```bash 109 + bao policy write spindle-policy spindle-policy.hcl 110 + bao auth enable approle 111 + bao write auth/approle/role/spindle \ 112 + token_policies="spindle-policy" \ 113 + token_ttl=1h \ 114 + token_max_ttl=4h \ 115 + bind_secret_id=true \ 116 + secret_id_ttl=0 \ 117 + secret_id_num_uses=0 118 + ``` 119 + 120 + Get the credentials: 121 + 122 + ```bash 123 + # Get role ID (static) 124 + ROLE_ID=$(bao read -field=role_id auth/approle/role/spindle/role-id) 125 + 126 + # Generate secret ID 127 + SECRET_ID=$(bao write -f -field=secret_id auth/approle/role/spindle/secret-id) 128 + 129 + echo "Role ID: $ROLE_ID" 130 + echo "Secret ID: $SECRET_ID" 131 + ``` 132 + 133 + ### Create proxy configuration 134 + 135 + Create the credential files: 136 + 137 + ```bash 138 + # Create directory for OpenBao files 139 + mkdir -p /tmp/openbao 140 + 141 + # Save credentials 142 + echo "$ROLE_ID" > /tmp/openbao/role-id 143 + echo "$SECRET_ID" > /tmp/openbao/secret-id 144 + chmod 600 /tmp/openbao/role-id /tmp/openbao/secret-id 145 + ``` 146 + 147 + Create a proxy configuration file `/tmp/openbao/proxy.hcl`: 148 + 149 + ```hcl 150 + # OpenBao server connection 151 + vault { 152 + address = "http://localhost:8200" 153 + } 154 + 155 + # Auto-Auth using AppRole 156 + auto_auth { 157 + method "approle" { 158 + mount_path = "auth/approle" 159 + config = { 160 + role_id_file_path = "/tmp/openbao/role-id" 161 + secret_id_file_path = "/tmp/openbao/secret-id" 162 + } 163 + } 164 + 165 + # Optional: write token to file for debugging 166 + sink "file" { 167 + config = { 168 + path = "/tmp/openbao/token" 169 + mode = 0640 170 + } 171 + } 172 + } 173 + 174 + # Proxy listener for spindle 175 + listener "tcp" { 176 + address = "127.0.0.1:8201" 177 + tls_disable = true 178 + } 179 + 180 + # Enable API proxy with auto-auth token 181 + api_proxy { 182 + use_auto_auth_token = true 183 + } 184 + 185 + # Enable response caching 186 + cache { 187 + use_auto_auth_token = true 188 + } 189 + 190 + # Logging 191 + log_level = "info" 192 + ``` 193 + 194 + ### Start the proxy 195 + 196 + Start OpenBao Proxy: 197 + 198 + ```bash 199 + bao proxy -config=/tmp/openbao/proxy.hcl 200 + ``` 201 + 202 + The proxy will authenticate with OpenBao and start listening on 203 + `127.0.0.1:8201`. 204 + 205 + ### Configure spindle 206 + 207 + Set these environment variables for spindle: 208 + 209 + ```bash 210 + export SPINDLE_SERVER_SECRETS_PROVIDER=openbao 211 + export SPINDLE_SERVER_SECRETS_OPENBAO_PROXY_ADDR=http://127.0.0.1:8201 212 + export SPINDLE_SERVER_SECRETS_OPENBAO_MOUNT=spindle 213 + ``` 214 + 215 + On startup, spindle will now connect to the local proxy, 216 + which handles all authentication automatically. 217 + 218 + ## Production setup for proxy 219 + 220 + For production, you'll want to run the proxy as a service: 221 + 222 + Place your production configuration in 223 + `/etc/openbao/proxy.hcl` with proper TLS settings for the 224 + vault connection. 225 + 226 + ## Verifying setup 227 + 228 + Test the proxy directly: 229 + 230 + ```bash 231 + # Check proxy health 232 + curl -H "X-Vault-Request: true" http://127.0.0.1:8201/v1/sys/health 233 + 234 + # Test token lookup through proxy 235 + curl -H "X-Vault-Request: true" http://127.0.0.1:8201/v1/auth/token/lookup-self 236 + ``` 237 + 238 + Test OpenBao operations through the server: 239 + 240 + ```bash 241 + # List all secrets 242 + bao kv list spindle/ 243 + 244 + # Add a test secret via the spindle API, then check it exists 245 + bao kv list spindle/repos/ 246 + 247 + # Get a specific secret 248 + bao kv get spindle/repos/your_repo_path/SECRET_NAME 249 + ``` 250 + 251 + ## How it works 252 + 253 + - Spindle connects to OpenBao Proxy on localhost (typically 254 + port 8200 or 8201) 255 + - The proxy authenticates with OpenBao using AppRole 256 + credentials 257 + - All spindle requests go through the proxy, which injects 258 + authentication tokens 259 + - Secrets are stored at 260 + `spindle/repos/{sanitized_repo_path}/{secret_key}` 261 + - Repository paths like `did:plc:alice/myrepo` become 262 + `did_plc_alice_myrepo` 263 + - The proxy handles all token renewal automatically 264 + - Spindle no longer manages tokens or authentication 265 + directly 266 + 267 + ## Troubleshooting 268 + 269 + **Connection refused**: Check that the OpenBao Proxy is 270 + running and listening on the configured address. 271 + 272 + **403 errors**: Verify the AppRole credentials are correct 273 + and the policy has the necessary permissions. 274 + 275 + **404 route errors**: The spindle KV mount probably doesn't 276 + exist—run the mount creation step again. 277 + 278 + **Proxy authentication failures**: Check the proxy logs and 279 + verify the role-id and secret-id files are readable and 280 + contain valid credentials. 281 + 282 + **Secret not found after writing**: This can indicate policy 283 + permission issues. Verify the policy includes both 284 + `spindle/data/*` and `spindle/metadata/*` paths with 285 + appropriate capabilities. 286 + 287 + Check proxy logs: 288 + 289 + ```bash 290 + # If running as systemd service 291 + journalctl -u openbao-proxy -f 292 + 293 + # If running directly, check the console output 294 + ``` 295 + 296 + Test AppRole authentication manually: 297 + 298 + ```bash 299 + bao write auth/approle/login \ 300 + role_id="$(cat /tmp/openbao/role-id)" \ 301 + secret_id="$(cat /tmp/openbao/secret-id)" 302 + ```
+189
docs/src/content/docs/spindles/self-hosting.md
··· 1 + --- 2 + title: Self-hosting a spindle 3 + description: Run your own spindle CI runner, including microVM workflows. 4 + --- 5 + 6 + 7 + ## Prerequisites 8 + 9 + - Go 10 + - For the **nixery** engine: Docker (or Podman with Docker 11 + compatibility enabled). 12 + - For the **microVM** engine: a Linux host with KVM, plus the 13 + microVM host dependencies described in [Running microVM 14 + workflows](#running-microvm-workflows). 15 + 16 + ## Configuration 17 + 18 + Spindle is configured using environment variables. The following environment variables are available: 19 + 20 + - `SPINDLE_SERVER_LISTEN_ADDR`: The address the server listens on (default: `"0.0.0.0:6555"`). 21 + - `SPINDLE_SERVER_DB_PATH`: The path to the SQLite database file (default: `"spindle.db"`). 22 + - `SPINDLE_SERVER_HOSTNAME`: The hostname of the server (required). 23 + - `SPINDLE_SERVER_JETSTREAM_ENDPOINT`: The endpoint of the Jetstream server (default: `"wss://jetstream1.us-west.bsky.network/subscribe"`). 24 + - `SPINDLE_SERVER_DEV`: A boolean indicating whether the server is running in development mode (default: `false`). 25 + - `SPINDLE_SERVER_OWNER`: The DID of the owner (required). 26 + - `SPINDLE_SERVER_LOG_DIR`: The directory to store workflow logs (default: `"/var/log/spindle"`). 27 + - `SPINDLE_SERVER_DOCKER_SOCKET`: Path to Docker socket to expose to invoked Spindle containers (default: `""`). 28 + - `SPINDLE_PIPELINES_NIXERY`: The Nixery URL (default: `"nixery.tangled.sh"`). 29 + - `SPINDLE_PIPELINES_WORKFLOW_TIMEOUT`: The default workflow timeout (default: `"5m"`). 30 + 31 + For the microVM engine, the following are also available 32 + (prefix `SPINDLE_MICROVM_PIPELINES_`): 33 + 34 + - `SPINDLE_MICROVM_PIPELINES_IMAGE_DIR`: Directory containing 35 + microVM images (**required** to use the engine). See 36 + [Running microVM workflows](#running-microvm-workflows). 37 + - `SPINDLE_MICROVM_PIPELINES_DEFAULT_IMAGE`: Image used when a 38 + workflow doesn't set `image` (default: `"nixos-x86_64"`). 39 + - `SPINDLE_MICROVM_PIPELINES_OVERLAY_DIR`: Where per-workflow 40 + temporary disks are created (default: the system temp dir). 41 + - `SPINDLE_MICROVM_PIPELINES_ENABLE_KVM`: Use KVM hardware 42 + acceleration (default: `true`). Without KVM, guests fall 43 + back to slow software emulation. 44 + - `SPINDLE_MICROVM_PIPELINES_WORKFLOW_TIMEOUT`: Default 45 + workflow timeout (default: `"5m"`). 46 + 47 + Optional resource limits (a value of `0` disables that 48 + limit). The limits cap usage across all running microVM 49 + workflows: 50 + 51 + - `SPINDLE_MICROVM_PIPELINES_MAX_TOTAL_MEMORY_MIB` 52 + - `SPINDLE_MICROVM_PIPELINES_MAX_TOTAL_VCPUS` 53 + - `SPINDLE_MICROVM_PIPELINES_MAX_TOTAL_DISK_MIB` 54 + 55 + Optional cgroup enforcement: 56 + 57 + - `SPINDLE_MICROVM_PIPELINES_ENABLE_CGROUPS`: Place each 58 + workflow's QEMU and slirp4netns in a per-workflow cgroup= 59 + (default: `false`). 60 + - `SPINDLE_MICROVM_PIPELINES_CGROUP_PARENT`: Parent cgroup; 61 + `self` resolves the spindle service's own cgroup (default: 62 + `"self"`). 63 + - `SPINDLE_MICROVM_PIPELINES_CGROUP_PIDS_MAX`: Max processes 64 + per workflow cgroup (default: `4096`). 65 + - `SPINDLE_MICROVM_PIPELINES_CGROUP_SWAP_MAX_MIB`: Max swap 66 + per workflow cgroup (default: `0`, no swap). 67 + - `SPINDLE_MICROVM_PIPELINES_CGROUP_SUPERVISOR_MEMORY_MIN_MIB`: 68 + Memory protected for spindle itself so it isn't OOM-killed 69 + before the workflows (default: `512`). 70 + 71 + To push paths built inside microVMs back to a shared Nix 72 + cache (and read from it), configure the cache (prefix 73 + `SPINDLE_NIX_CACHE_`): 74 + 75 + - `SPINDLE_NIX_CACHE_READ_URLS`: Comma-separated binary cache 76 + URLs the guest reads from. 77 + - `SPINDLE_NIX_CACHE_TRUSTED_PUBLIC_KEYS`: Comma-separated 78 + trusted public keys for those caches. 79 + - `SPINDLE_NIX_CACHE_UPLOAD_URL`: Cache URL that paths built 80 + in the guest are uploaded to. 81 + 82 + ## Running spindle 83 + 84 + 1. **Set the environment variables.** For example: 85 + 86 + ```shell 87 + export SPINDLE_SERVER_HOSTNAME="your-hostname" 88 + export SPINDLE_SERVER_OWNER="your-did" 89 + ``` 90 + 91 + 2. **Build the Spindle binary.** 92 + 93 + ```shell 94 + cd core 95 + go mod download 96 + go build -o cmd/spindle/spindle cmd/spindle/main.go 97 + ``` 98 + 99 + 3. **Create the log directory.** 100 + 101 + ```shell 102 + sudo mkdir -p /var/log/spindle 103 + sudo chown $USER:$USER -R /var/log/spindle 104 + ``` 105 + 106 + 4. **Run the Spindle binary.** 107 + 108 + ```shell 109 + ./cmd/spindle/spindle 110 + ``` 111 + 112 + Spindle will now start, connect to the Jetstream server, and begin processing pipelines. 113 + 114 + ## Running microVM workflows 115 + 116 + The microVM engine needs a few extra things on the host, and 117 + it needs images to boot. 118 + 119 + ### Host dependencies 120 + 121 + microVM workflows depend on a handful of host tools and 122 + devices. spindle checks for the ones an image needs right 123 + before it launches, so a missing dependency surfaces as a 124 + clear error. You'll need: 125 + 126 + - `qemu`: the runner. The QEMU binary for the image's arch 127 + must be present (e.g. `qemu-system-x86_64`). 128 + - `mkfs.ext4` (from `e2fsprogs`): to format the per-workflow 129 + writable volumes. 130 + - [`slirp4netns`](https://github.com/rootless-containers/slirp4netns#install), 131 + `ip` (from `iproute2`), `mount` and `unshare` (from `util-linux`): 132 + used to sandbox guest networking. 133 + - `/dev/kvm`: for hardware acceleration (unless you disable 134 + KVM with `SPINDLE_MICROVM_PIPELINES_ENABLE_KVM=false`). 135 + - `/dev/vhost-vsock`: used by QEMU to enable guest-to-host vsock 136 + communication. 137 + - `/dev/vsock`: used by spindle on the host to listen on vsock ports 138 + and accept guest agent connections. 139 + - `/dev/net/tun`: required by `slirp4netns` to set up tap devices 140 + for sandboxed guest networking. 141 + 142 + On NixOS, the [spindle 143 + module](https://tangled.org/tangled.org/core/blob/master/nix/modules/spindle.nix) 144 + puts `qemu`, `e2fsprogs`, `slirp4netns`, `iproute2` and 145 + `util-linux` on the service's `PATH` for you. 146 + 147 + ### Container virtualization 148 + 149 + Running `spindle` inside a container (e.g., Docker, Podman, or LXD) requires passing host device nodes into the container and granting the runtime additional privileges. Because spindle uses nested namespaces (`unshare`) and helper tools (`slirp4netns`), the container configuration will require: 150 + 151 + - `/dev/vsock`, `/dev/vhost-vsock`, `/dev/kvm`, and `/dev/net/tun` mapped from the host. 152 + - `NET_ADMIN` and `SYS_ADMIN` capabilities to manage network namespaces and mounts inside the container. 153 + - Relaxed seccomp filters (e.g., `seccomp=unconfined`) and SELinux/AppArmor containment if they restrict namespace creation or device access. 154 + 155 + ### Building images 156 + 157 + Images are built with Nix. The flake exposes packages for the 158 + two stock images (use the `-tarball` prefixed ones for a gzipped 159 + tarball you can copy to another host): 160 + 161 + ```shell 162 + # a NixOS image 163 + nix build .#spindle-nixos-image 164 + # an Alpine image 165 + nix build .#spindle-alpine-image 166 + ``` 167 + 168 + ### Installing images 169 + 170 + Spindle looks for images in 171 + `SPINDLE_MICROVM_PIPELINES_IMAGE_DIR`. An image is resolved by 172 + the name a workflow puts in its `image` field, matched 173 + literally against what's on disk: 174 + 175 + 1. a directory `<name>/` containing a `spec.json` (next to the 176 + kernel/initrd/store-disk), or 177 + 2. a flat `<name>.json` self-contained spec. 178 + 179 + Resolution depends only on the name and what's on disk, never 180 + on the host doing the resolving, so the same workflow resolves 181 + to the same image on every spindle. If you keep multiple 182 + arches side by side, you can name them `<name>-<arch>` (e.g. 183 + `nixos-x86_64`, `alpine-aarch64`); the suffix is just part of 184 + the name. To make a name like `nixos` work if you are hosting 185 + multiple arches, you can use symlinks. 186 + 187 + On NixOS, you'll most likely want to use `systemd.tmpfiles.rules` 188 + to set these up declaratively. 189 +
+686
docs/src/content/docs/spindles/workflows.md
··· 1 + --- 2 + title: Workflows 3 + description: Write CI/CD pipelines for your repositories using spindle workflows. 4 + --- 5 + 6 + 7 + ## Pipelines 8 + 9 + Spindle workflows allow you to write CI/CD pipelines in a 10 + simple format. They're located in the `.tangled/workflows` 11 + directory at the root of your repository, and are defined 12 + using YAML. 13 + 14 + A workflow has a set of common fields that apply no matter 15 + which engine you pick: 16 + 17 + - [Trigger](#trigger): A **required** field that defines 18 + when a workflow should be triggered. 19 + - [Engine](#engine): A **required** field that defines which 20 + engine a workflow should run on. 21 + - [Clone options](#clone-options): An **optional** field 22 + that defines how the repository should be cloned. 23 + - [Environment](#environment): An **optional** field that 24 + allows you to define environment variables. 25 + - [Steps](#steps): An **optional** field that allows you to 26 + define what steps should run in the workflow. 27 + 28 + On top of these, each engine has its own options for things 29 + like dependencies and images. See [Engines](#engines) for 30 + the per-engine fields. 31 + 32 + ### Trigger 33 + 34 + The first thing to add to a workflow is the trigger, which 35 + defines when a workflow runs. This is defined using a `when` 36 + field, which takes in a list of conditions. Each condition 37 + has the following fields: 38 + 39 + - `event`: This is a **required** field that defines when 40 + your workflow should run. It's a list that can take one or 41 + more of the following values: 42 + - `push`: The workflow should run every time a commit is 43 + pushed to the repository. 44 + - `pull_request`: The workflow should run every time a 45 + pull request is made or updated. 46 + - `manual`: The workflow can be triggered manually. 47 + - `branch`: Defines which branches the workflow should run 48 + for. If used with the `push` event, commits to the 49 + branch(es) listed here will trigger the workflow. If used 50 + with the `pull_request` event, updates to pull requests 51 + targeting the branch(es) listed here will trigger the 52 + workflow. This field has no effect with the `manual` 53 + event. Supports glob patterns using `*` and `**` (e.g., 54 + `main`, `develop`, `release-*`). Either `branch` or `tag` 55 + (or both) must be specified for `push` events. 56 + - `tag`: Defines which tags the workflow should run for. 57 + Only used with the `push` event - when tags matching the 58 + pattern(s) listed here are pushed, the workflow will 59 + trigger. This field has no effect with `pull_request` or 60 + `manual` events. Supports glob patterns using `*` and `**` 61 + (e.g., `v*`, `v1.*`, `release-**`). Either `branch` or 62 + `tag` (or both) must be specified for `push` events. 63 + 64 + For example, if you'd like to define a workflow that runs 65 + when commits are pushed to the `main` and `develop` 66 + branches, or when pull requests that target the `main` 67 + branch are updated, or manually, you can do so with: 68 + 69 + ```yaml 70 + when: 71 + - event: ["push", "manual"] 72 + branch: ["main", "develop"] 73 + - event: ["pull_request"] 74 + branch: ["main"] 75 + ``` 76 + 77 + You can also trigger workflows on tag pushes. For instance, 78 + to run a deployment workflow when tags matching `v*` are 79 + pushed: 80 + 81 + ```yaml 82 + when: 83 + - event: ["push"] 84 + tag: ["v*"] 85 + ``` 86 + 87 + You can even combine branch and tag patterns in a single 88 + constraint (the workflow triggers if either matches): 89 + 90 + ```yaml 91 + when: 92 + - event: ["push"] 93 + branch: ["main", "release-*"] 94 + tag: ["v*", "stable"] 95 + ``` 96 + 97 + To skip CI for a push, pass a Git push option: 98 + 99 + ```sh 100 + git push -o skip-ci 101 + ``` 102 + 103 + `ci-skip` is also accepted. 104 + 105 + ### Engine 106 + 107 + Next is the engine on which the workflow should run, defined 108 + using the **required** `engine` field. The currently 109 + supported engines are: 110 + 111 + - `nixery`: This uses an instance of 112 + [Nixery](https://nixery.dev) to run steps, which allows 113 + you to add [dependencies](#dependencies) from 114 + Nixpkgs (https://github.com/NixOS/nixpkgs). You can 115 + search for packages on https://search.nixos.org, and 116 + there's a pretty good chance the package(s) you're looking 117 + for will be there. 118 + See [Nixery engine](#nixery-engine). 119 + - `microvm`: Runs the whole workflow inside its own 120 + microVM. Has configuration features for NixOS images 121 + that will let you enable services, do Docker-in-VM, etc. 122 + See [microVM engine](#microvm-engine). 123 + 124 + Example: 125 + 126 + ```yaml 127 + engine: "nixery" 128 + ``` 129 + 130 + Each engine also adds its own workflow fields (dependencies, 131 + images, services, and so on). These are documented under 132 + [Engines](#engines). 133 + 134 + ### Clone options 135 + 136 + When a workflow starts, the first step is to clone the 137 + repository. You can customize this behavior using the 138 + **optional** `clone` field. It has the following fields: 139 + 140 + - `skip`: Setting this to `true` will skip cloning the 141 + repository. This can be useful if your workflow is doing 142 + something that doesn't require anything from the 143 + repository itself. This is `false` by default. 144 + - `depth`: This sets the number of commits, or the "clone 145 + depth", to fetch from the repository. For example, if you 146 + set this to 2, the last 2 commits will be fetched. By 147 + default, the depth is set to 1, meaning only the most 148 + recent commit will be fetched, which is the commit that 149 + triggered the workflow. 150 + - `submodules`: If you use Git submodules 151 + (https://git-scm.com/book/en/v2/Git-Tools-Submodules) 152 + in your repository, setting this field to `true` will 153 + recursively fetch all submodules. This is `false` by 154 + default. 155 + 156 + The default settings are: 157 + 158 + ```yaml 159 + clone: 160 + skip: false 161 + depth: 1 162 + submodules: false 163 + ``` 164 + 165 + ### Environment 166 + 167 + The `environment` field allows you define environment 168 + variables that will be available throughout the entire 169 + workflow. **Do not put secrets here, these environment 170 + variables are visible to anyone viewing the repository. You 171 + can add secrets for pipelines in your repository's 172 + settings.** 173 + 174 + Example: 175 + 176 + ```yaml 177 + environment: 178 + GOOS: "linux" 179 + GOARCH: "arm64" 180 + NODE_ENV: "production" 181 + MY_ENV_VAR: "MY_ENV_VALUE" 182 + ``` 183 + 184 + By default, the following environment variables are set: 185 + 186 + - `CI` - Always set to `true` to indicate a CI environment 187 + - `TANGLED_PIPELINE_ID` - The AT URI of the current pipeline 188 + - `TANGLED_PIPELINE_KIND` - One of `push`, `pull_request` or 189 + `manual` 190 + - `TANGLED_REPO_KNOT` - The repository's knot hostname 191 + - `TANGLED_REPO_DID` - The DID of the repository owner 192 + - `TANGLED_REPO_NAME` - The name of the repository 193 + - `TANGLED_REPO_DEFAULT_BRANCH` - The default branch of the 194 + repository 195 + - `TANGLED_REPO_URL` - The full URL to the repository 196 + 197 + These variables are only available when the pipeline is 198 + triggered by a push: 199 + 200 + - `TANGLED_REF` - The full git reference (e.g., 201 + `refs/heads/main` or `refs/tags/v1.0.0`) 202 + - `TANGLED_REF_NAME` - The short name of the reference 203 + (e.g., `main` or `v1.0.0`) 204 + - `TANGLED_REF_TYPE` - The type of reference, either 205 + `branch` or `tag` 206 + - `TANGLED_SHA` - The commit SHA that triggered the pipeline 207 + - `TANGLED_COMMIT_SHA` - Alias for `TANGLED_SHA` 208 + 209 + These variables are only available when the pipeline is 210 + triggered by a pull request: 211 + 212 + - `TANGLED_PR_SOURCE_BRANCH` - The source branch of the pull 213 + request 214 + - `TANGLED_PR_TARGET_BRANCH` - The target branch of the pull 215 + request 216 + - `TANGLED_PR_SOURCE_SHA` - The commit SHA of the source 217 + branch 218 + 219 + ### Steps 220 + 221 + The `steps` field allows you to define what steps should run 222 + in the workflow. It's a list of step objects, each with the 223 + following fields: 224 + 225 + - `name`: This field allows you to give your step a name. 226 + This name is visible in your workflow runs, and is used to 227 + describe what the step is doing. 228 + - `command`: This field allows you to define a command to 229 + run in that step. The step is run in a Bash shell, and the 230 + logs from the command will be visible in the pipelines 231 + page on the Tangled website. Any dependencies you added in 232 + your engine's section (see [Engines](#engines)) will be 233 + available to use here. 234 + - `environment`: Similar to the global 235 + [environment](#environment) config, this **optional** 236 + field is a key-value map that allows you to set 237 + environment variables for the step. **Do not put secrets 238 + here, these environment variables are visible to anyone 239 + viewing the repository. You can add secrets for pipelines 240 + in your repository's settings.** 241 + 242 + Example: 243 + 244 + ```yaml 245 + steps: 246 + - name: "Build backend" 247 + command: "go build" 248 + environment: 249 + GOOS: "darwin" 250 + GOARCH: "arm64" 251 + - name: "Build frontend" 252 + command: "npm run build" 253 + environment: 254 + NODE_ENV: "production" 255 + ``` 256 + 257 + ## Engines 258 + 259 + The common fields above apply to every workflow. Each engine 260 + then adds its own fields on top. Pick an engine with the 261 + [`engine`](#engine) field and use the matching section below. 262 + 263 + ### Nixery engine 264 + 265 + #### Dependencies 266 + 267 + When you're running a workflow you'll usually need additional 268 + dependencies. The `dependencies` field lets you define which 269 + dependencies to get, and from where. It's a key-value map, 270 + with the key being the registry to fetch dependencies from, 271 + and the value being the list of dependencies to fetch. 272 + 273 + The registry URL syntax can be found [on the nix 274 + manual](https://nix.dev/manual/nix/2.18/command-ref/new-cli/nix3-registry-add). 275 + 276 + Say you want to fetch Node.js and Go from `nixpkgs`, and a 277 + package called `my_pkg` you've made from your own registry 278 + at your repository at 279 + `https://tangled.org/@example.com/my_pkg`. You can define 280 + those dependencies like so: 281 + 282 + ```yaml 283 + dependencies: 284 + # nixpkgs 285 + nixpkgs: 286 + - nodejs 287 + - go 288 + # unstable 289 + nixpkgs/nixpkgs-unstable: 290 + - bun 291 + # custom registry 292 + git+https://tangled.org/@example.com/my_pkg: 293 + - my_pkg 294 + ``` 295 + 296 + Now these dependencies are available to use in your 297 + workflow! 298 + 299 + #### Complete nixery workflow 300 + 301 + ```yaml 302 + # .tangled/workflows/build.yml 303 + 304 + when: 305 + - event: ["push", "manual"] 306 + branch: ["main", "develop"] 307 + - event: ["pull_request"] 308 + branch: ["main"] 309 + 310 + engine: "nixery" 311 + 312 + # using the default values 313 + clone: 314 + skip: false 315 + depth: 1 316 + submodules: false 317 + 318 + dependencies: 319 + # nixpkgs 320 + nixpkgs: 321 + - nodejs 322 + - go 323 + # custom registry 324 + git+https://tangled.org/@example.com/my_pkg: 325 + - my_pkg 326 + 327 + environment: 328 + GOOS: "linux" 329 + GOARCH: "arm64" 330 + NODE_ENV: "production" 331 + MY_ENV_VAR: "MY_ENV_VALUE" 332 + 333 + steps: 334 + - name: "Build backend" 335 + command: "go build" 336 + environment: 337 + GOOS: "darwin" 338 + GOARCH: "arm64" 339 + - name: "Build frontend" 340 + command: "npm run build" 341 + environment: 342 + NODE_ENV: "production" 343 + ``` 344 + 345 + If you want another example of a workflow, you can look at 346 + the one [Tangled uses to build the 347 + project](https://tangled.org/@tangled.org/core/blob/master/.tangled/workflows/build.yml). 348 + 349 + ### microVM engine 350 + 351 + #### Image 352 + 353 + A workflow picks the image to boot with the top-level `image` 354 + field: 355 + 356 + ```yaml 357 + engine: microvm 358 + image: nixos 359 + ``` 360 + 361 + There are two flavours of images: 362 + 363 + - **NixOS images** (e.g. `nixos`): the whole guest is built 364 + with Nix, so you can configure it from the workflow file 365 + itself. The `dependencies`, `services`, `virtualisation`, 366 + `registry` and `caches` fields below are all understood 367 + here, and the guest builds and activates that configuration 368 + before any of your steps run. 369 + - **Non-NixOS images** (e.g. `alpine`): there's no NixOS to 370 + configure, so the workflow-level config fields above have 371 + no effect. You still get a full machine to run steps in. 372 + 373 + The available image names depend on what the spindle operator 374 + has installed. `nixos` and `alpine` are examples. If `image` 375 + is omitted, the spindle's configured default image is used. 376 + 377 + #### Dependencies 378 + 379 + On the microVM engine, `dependencies` is a flat list of 380 + packages that are made available to every step. This field 381 + only applies to **NixOS images**; for other images you can 382 + use the package manager included in a step. 383 + 384 + The guest builds a [`nix develop`](https://nix.dev/manual/nix/2.18/command-ref/new-cli/nix3-develop)-style 385 + devshell from your dependencies and uses it for each step, 386 + so you can, for example, add `pkg-config` and `openssl` and 387 + have the `openssl-sys` crate while compiling a Rust project 388 + just work. 389 + 390 + A bare name like `go` is looked up in nixpkgs. You can also 391 + point at any flake with the `flakeref#attr` syntax, so 392 + `github:nixos/nixpkgs#hello` pulls `hello` straight out of 393 + that flake. 394 + 395 + ```yaml 396 + dependencies: 397 + - go 398 + - github:nixos/nixpkgs#hello 399 + ``` 400 + 401 + #### Registry 402 + 403 + The `registry` field remaps flake references, the same way 404 + `nix registry` does. This lets you pin or alias the flakes 405 + used by `dependencies`. 406 + 407 + For example, pin `nixpkgs` to `nixos-unstable` so that the 408 + bare `go` above resolves from unstable, and alias your own 409 + flake so you can use `myflake#tool` in `dependencies`: 410 + 411 + ```yaml 412 + registry: 413 + nixpkgs: github:nixos/nixpkgs/nixos-unstable 414 + myflake: github:me/x 415 + ``` 416 + 417 + #### Caches 418 + 419 + The `caches` field is a map of Nix binary cache URL to its 420 + trusted public key. These are fed into the spindle's read 421 + proxy, so the guest can substitute prebuilt paths from them 422 + instead of building everything from scratch. 423 + 424 + ```yaml 425 + caches: 426 + https://nix-community.cachix.org: "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" 427 + ``` 428 + 429 + #### Services and virtualisation 430 + 431 + The `services` and `virtualisation` fields are passed straight 432 + through to NixOS. Anything you could write under 433 + `services.*` or `virtualisation.*` in a NixOS configuration, 434 + you can write here, and it's brought up before any of your 435 + steps run. 436 + 437 + As a convenience, `true` works as shorthand for 438 + `.enable = true` anywhere an `enable` option exists (e.g. 439 + `virtualisation.docker: true`). 440 + 441 + ```yaml 442 + services: 443 + postgresql: 444 + enable: true 445 + ensureDatabases: ["spindle-workflow"] 446 + ensureUsers: 447 + - name: spindle-workflow 448 + ensureDBOwnership: true 449 + 450 + virtualisation: 451 + docker: true 452 + ``` 453 + 454 + #### Recipes 455 + 456 + ##### Lint, test and build a Node project 457 + 458 + ```yaml 459 + when: 460 + - event: ["push", "pull_request"] 461 + branch: ["main"] 462 + 463 + engine: microvm 464 + image: nixos 465 + 466 + dependencies: 467 + - pnpm 468 + 469 + steps: 470 + - name: "Install dependencies" 471 + command: pnpm install --frozen-lockfile 472 + - name: "Lint and test" 473 + command: | 474 + pnpm run lint 475 + pnpm test 476 + - name: "Build" 477 + command: pnpm run build 478 + ``` 479 + 480 + ##### Check formatting 481 + 482 + ```yaml 483 + when: 484 + - event: ["push", "pull_request"] 485 + branch: ["main"] 486 + 487 + engine: microvm 488 + image: alpine # slimmer image for checking the formatting 489 + 490 + steps: 491 + - name: "Install go" 492 + command: apk add go 493 + - name: "Check formatting" 494 + command: test -z $(gofmt -l .) 495 + ``` 496 + 497 + ##### Build a Rust project that links OpenSSL 498 + 499 + ```yaml 500 + when: 501 + - event: ["push", "pull_request"] 502 + branch: ["main"] 503 + 504 + engine: microvm 505 + image: nixos 506 + 507 + dependencies: 508 + - gcc 509 + - cargo 510 + - rustc 511 + - clippy 512 + - rustfmt 513 + - pkg-config # exports PKG_CONFIG_PATH for the libraries below 514 + - openssl # the C library + headers openssl-sys links against 515 + 516 + steps: 517 + - name: "Check formatting" 518 + command: cargo fmt --check 519 + - name: "Clippy" 520 + command: cargo clippy --all-targets -- -D warnings 521 + - name: "Test" 522 + command: cargo test --all 523 + - name: "Release build" 524 + command: cargo build --release 525 + ``` 526 + 527 + ##### Run migrations and integration tests against PostgreSQL 528 + 529 + ```yaml 530 + when: 531 + - event: ["push", "pull_request"] 532 + branch: ["main"] 533 + 534 + engine: microvm 535 + image: nixos 536 + 537 + environment: 538 + DATABASE_URL: "postgresql:///spindle-workflow?host=/run/postgresql" 539 + 540 + dependencies: 541 + - gcc 542 + - cargo 543 + - rustc 544 + - pkg-config 545 + - openssl 546 + - sqlx-cli 547 + 548 + services: 549 + postgresql: 550 + enable: true 551 + # has to be same name as the user for peer auth to work automatically 552 + ensureDatabases: ["spindle-workflow"] 553 + ensureUsers: 554 + - name: spindle-workflow 555 + ensureDBOwnership: true 556 + 557 + steps: 558 + - name: "Run migrations" 559 + command: sqlx migrate run 560 + - name: "Integration tests" 561 + command: cargo test --all 562 + ``` 563 + 564 + ##### Build and push a Docker image on tag 565 + 566 + ```yaml 567 + when: 568 + - event: ["push"] 569 + tag: ["v*"] 570 + 571 + engine: microvm 572 + image: nixos 573 + 574 + virtualisation: 575 + docker: true 576 + 577 + steps: 578 + - name: "Build and push to ghcr.io" 579 + command: | 580 + set -euo pipefail 581 + 582 + echo "$REGISTRY_TOKEN" | docker login ghcr.io -u "$REGISTRY_USER" --password-stdin 583 + image="ghcr.io/$REGISTRY_USER/myapp:$TANGLED_REF_NAME" 584 + 585 + docker build -t "$image" -t "ghcr.io/$REGISTRY_USER/myapp:latest" . 586 + docker push "$image" 587 + docker push "ghcr.io/$REGISTRY_USER/myapp:latest" 588 + ``` 589 + 590 + ##### Deploy to Cloudflare Workers on tag 591 + 592 + ```yaml 593 + # .tangled/workflows/deploy.yml 594 + when: 595 + - event: ["push"] 596 + tag: ["v*"] 597 + 598 + engine: microvm 599 + image: nixos 600 + 601 + dependencies: 602 + - pnpm 603 + 604 + steps: 605 + - name: "Install dependencies" 606 + command: pnpm install --frozen-lockfile 607 + - name: "Deploy worker" 608 + # `wrangler` picks up `CLOUDFLARE_API_TOKEN` from the env. 609 + # set it under **Settings → Secrets**. 610 + command: pnpm exec wrangler deploy 611 + ``` 612 + 613 + ##### Publish a release artifact 614 + 615 + ```yaml 616 + when: 617 + - event: ["push"] 618 + tag: ["v*"] # trigger on versions 619 + 620 + engine: microvm 621 + image: nixos 622 + 623 + dependencies: 624 + - go 625 + 626 + steps: 627 + - name: "Build release binary" 628 + command: | 629 + mkdir -p dist 630 + CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o dist/myapp ./cmd/myapp 631 + 632 + - name: "Publish artifact record" 633 + command: | 634 + set -euo pipefail 635 + # change this if you're not on `tngl.sh` 636 + PDS="https://tngl.sh" 637 + # also update this to your handle or did 638 + ATP_IDENTIFIER="user.tngl.sh" 639 + ARTIFACT_PATH="dist/myapp" 640 + ARTIFACT_NAME="myapp" 641 + 642 + # set `ATP_APP_PASSWORD` under **Settings → Secrets** 643 + session=$(curl -fsS -X POST "$PDS/xrpc/com.atproto.server.createSession" \ 644 + -H "Content-Type: application/json" \ 645 + -d "{\"identifier\":\"$ATP_IDENTIFIER\",\"password\":\"$ATP_APP_PASSWORD\"}") 646 + jwt=$(echo "$session" | jq -r .accessJwt) 647 + did=$(echo "$session" | jq -r .did) 648 + 649 + # upload the binary as a blob 650 + blob=$(curl -fsS -X POST "$PDS/xrpc/com.atproto.repo.uploadBlob" \ 651 + -H "Authorization: Bearer $jwt" \ 652 + -H "Content-Type: application/octet-stream" \ 653 + --data-binary @"$ARTIFACT_PATH") 654 + 655 + # note that this requires an annotated tag (`git tag -a v1.0.0 -m ...`) 656 + tag_hash=$(git rev-parse "$TANGLED_REF_NAME^{tag}") 657 + tag_bytes=$(printf '%s' "$tag_hash" | xxd -r -p | base64 | tr -d '=') 658 + 659 + # the sh.tangled.repo.artifact record for your artifact 660 + record=$(jq -n \ 661 + --arg did "$did" \ 662 + --arg tag "$tag_bytes" \ 663 + --arg name "$ARTIFACT_NAME" \ 664 + --arg repo "$TANGLED_REPO_URL" \ 665 + --arg created "$(date -Iseconds)" \ 666 + --argjson blob "$(echo "$blob" | jq .blob)" '{ 667 + repo: $did, 668 + collection: "sh.tangled.repo.artifact", 669 + validate: false, 670 + record: { 671 + "$type": "sh.tangled.repo.artifact", 672 + tag: {"$bytes": $tag}, 673 + name: $name, 674 + repo: $repo, 675 + artifact: $blob, 676 + createdAt: $created 677 + } 678 + }') 679 + 680 + # create the record on the PDS 681 + curl -fsS -X POST "$PDS/xrpc/com.atproto.repo.createRecord" \ 682 + -H "Authorization: Bearer $jwt" \ 683 + -H "Content-Type: application/json" \ 684 + -d "$record" 685 + ``` 686 +
+58
docs/src/content/docs/troubleshooting.md
··· 1 + --- 2 + title: Troubleshooting 3 + description: Common issues with login, punchcards, commit verification, and knots. 4 + --- 5 + 6 + 7 + ## Login issues 8 + 9 + Owing to the distributed nature of OAuth on AT Protocol, you 10 + may run into issues with logging in. If you run a 11 + self-hosted PDS: 12 + 13 + - You may need to ensure that your PDS is timesynced using 14 + NTP: 15 + - Enable the `ntpd` service 16 + - Run `ntpd -qg` to synchronize your clock 17 + - You may need to increase the default request timeout: 18 + `NODE_OPTIONS="--network-family-autoselection-attempt-timeout=500"` 19 + 20 + ## Empty punchcard 21 + 22 + For Tangled to register commits that you make across the 23 + network, you need to setup one of following: 24 + 25 + - The committer email should be a verified email associated 26 + to your account. You can add and verify emails on the 27 + settings page. 28 + - Or, the committer email should be set to your account's 29 + DID: `git config user.email "did:plc:foobar"`. You can find 30 + your account's DID on the settings page 31 + 32 + ## Commit is not marked as verified 33 + 34 + Tangled only supports SSH commit signatures. Ensure the SSH public key you use 35 + for signing is uploaded to Tangled. 36 + 37 + To sign commits using an SSH key with git: 38 + 39 + ``` 40 + git config --global gpg.format ssh 41 + git config --global user.signingkey ~/.ssh/tangled-key 42 + ``` 43 + 44 + To sign commits using an SSH key with jj, add this to your 45 + config: 46 + 47 + ``` 48 + [signing] 49 + behavior = "own" 50 + backend = "ssh" 51 + key = "~/.ssh/tangled-key" 52 + ``` 53 + 54 + ## Self-hosted knot issues 55 + 56 + If you need help troubleshooting a self-hosted knot, check 57 + out the [knot troubleshooting 58 + guide](/knots/self-hosting/#troubleshooting).
+101
docs/src/content/docs/why-atproto.md
··· 1 + --- 2 + title: Why AT Protocol? 3 + description: Why Tangled is built on the AT Protocol, and what that buys you over federated or P2P code forges. 4 + --- 5 + 6 + Code collaboration has one of the strongest network effects in 7 + software: your issues, pull requests, reviews, stars, and 8 + followers all live wherever your code lives. On a centralized 9 + forge, all of that belongs to one company. Leaving means starting 10 + over — new identity, new social graph, and years of collaboration 11 + history left behind. 12 + 13 + There are several models for decentralized code collaboration 14 + platforms, ranging from ActivityPub's (Forgejo) federated model, 15 + to Radicle's entirely P2P model. Each solves part of the problem: 16 + 17 + - **Federation** distributes hosting, but your identity is bound 18 + to your instance. If your instance shuts down or defederates, 19 + you lose your account, and cross-instance collaboration is only 20 + as good as the bridges between servers. 21 + - **P2P** gives you full sovereignty, but pushes a lot of 22 + complexity onto every user — key management, discovery, and 23 + availability become your problem. 24 + 25 + Our approach attempts to be the best of both worlds by adopting 26 + the [AT Protocol](https://atproto.com) — a protocol for building 27 + decentralized social applications with a **central identity**. 28 + 29 + ## Identity that survives everything 30 + 31 + On the AT Protocol, your identity is a 32 + [DID](https://atproto.com/specs/did) — a stable identifier that is 33 + independent of any server, fronted by a human-readable handle 34 + (usually a domain name you control). Your account lives on a 35 + Personal Data Server (PDS) of your choosing, and you can move 36 + between PDSes without changing who you are. Nothing on Tangled 37 + breaks when you do: your repositories, issues, and followers all 38 + reference your DID, not your server. 39 + 40 + You can think of it as "one account for all of the atmosphere": 41 + the same account you use on Bluesky or any other AT Protocol 42 + application signs you into Tangled. We believe AT Protocol has 43 + greatly simplified one of the hardest parts of social software — 44 + having your friends already on it. 45 + 46 + ## Your data, as records you own 47 + 48 + Everything social on Tangled — issues, pull requests, comments, 49 + stars, follows, profile — is stored as records under `sh.tangled.*` 50 + [lexicons](https://atproto.com/guides/lexicon) in *your* AT 51 + Protocol repository, on *your* PDS. Tangled reads them; it doesn't 52 + own them. 53 + 54 + This has practical consequences: 55 + 56 + - Any application can read (and build on) the same records — the 57 + appview at [tangled.org](https://tangled.org) is one view of the 58 + network, [Bobbin](/reference/bobbin/) is another, and anyone can 59 + build their own from the firehose. 60 + - Deleting or migrating your account takes your collaboration 61 + history with you. 62 + - There is no privileged write path: Tangled writes records to 63 + your PDS like any other client would. 64 + 65 + Git data itself is the one exception — repositories are too large 66 + and too specialized to live in a PDS, so they live on 67 + [knots](/knots/), which you can also self-host. Each repository 68 + gets its own DID too, making it stable across renames and 69 + transfers. 70 + 71 + ## Services that don't need to trust each other 72 + 73 + Tangled is composed of small, independently hostable services: 74 + knots host git, [spindles](/spindles/) run CI, and the appview 75 + ties the network together. They authenticate to each other with AT 76 + Protocol [service 77 + auth](https://atproto.com/specs/xrpc#inter-service-authentication-jwt): 78 + requests are signed with the user's DID key and verified against 79 + their public DID document. No shared secrets, no API tokens to 80 + provision — any knot can trust a request from any appview, and 81 + vice versa, because identity is cryptographic and global. 82 + 83 + ## The tenets 84 + 85 + Tangled's design goals, which the AT Protocol lets us hit all at 86 + once: 87 + 88 + 1. **Ownership of data** — your identity and social data are 89 + yours, portable across servers and applications. 90 + 2. **Low barrier to entry** — sign up in seconds on 91 + [tangled.org](https://tangled.org/signup), or bring an existing 92 + AT Protocol account. Self-hosting is optional, never required. 93 + 3. **No compromise on user-experience** — the appview gives the 94 + whole decentralized network the coherence of a single site. 95 + 96 + ## Further reading 97 + 98 + - [Introducing Tangled](https://blog.tangled.org/intro) — the 99 + announcement post 100 + - [What are knots?](/knots/) and [what are spindles?](/spindles/) 101 + - [AT Protocol documentation](https://atproto.com/docs)
+86
docs/src/styles/custom.css
··· 1 + @import "@fontsource-variable/inter"; 2 + @import "@fontsource/ibm-plex-mono/400.css"; 3 + @import "@fontsource/ibm-plex-mono/600.css"; 4 + 5 + /* 6 + * starlight theme mapped onto the appview's palette (tailwind grays, 7 + * slate-100/gray-900 body, monochrome accents). fonts prefer the 8 + * appview's self-hosted files (/static/fonts, present in the nix 9 + * build) and fall back to the fontsource copies in dev. 10 + */ 11 + :root { 12 + --sl-font: "InterVariable", "Inter Variable", system-ui, sans-serif; 13 + --sl-font-mono: "IBMPlexMono", "IBM Plex Mono", monospace; 14 + 15 + /* the appview topbar sits directly on the body background */ 16 + --sl-color-bg-nav: var(--sl-color-black); 17 + --sl-color-bg-sidebar: var(--sl-color-black); 18 + 19 + /* dark — appview dark mode: bg-gray-900, white text */ 20 + --sl-color-white: #ffffff; 21 + --sl-color-gray-1: #f3f4f6; /* gray-100 */ 22 + --sl-color-gray-2: #d1d5db; /* gray-300 */ 23 + --sl-color-gray-3: #9ca3af; /* gray-400 */ 24 + --sl-color-gray-4: #4b5563; /* gray-600 */ 25 + --sl-color-gray-5: #374151; /* gray-700 */ 26 + --sl-color-gray-6: #1f2937; /* gray-800 */ 27 + --sl-color-black: #111827; /* gray-900 */ 28 + 29 + --sl-color-accent-low: #374151; /* gray-700 */ 30 + --sl-color-accent: #6b7280; /* gray-500 */ 31 + --sl-color-accent-high: #d1d5db; /* gray-300 */ 32 + } 33 + 34 + :root[data-theme="light"] { 35 + /* light — white surfaces, black text */ 36 + --sl-color-white: #000000; 37 + --sl-color-gray-1: #1f2937; /* gray-800 */ 38 + --sl-color-gray-2: #374151; /* gray-700 */ 39 + --sl-color-gray-3: #6b7280; /* gray-500 */ 40 + --sl-color-gray-4: #9ca3af; /* gray-400 */ 41 + --sl-color-gray-5: #d1d5db; /* gray-300 */ 42 + --sl-color-gray-6: #f3f4f6; /* gray-100 */ 43 + --sl-color-gray-7: #f9fafb; /* gray-50 */ 44 + --sl-color-black: #ffffff; 45 + 46 + --sl-color-accent-low: #e5e7eb; /* gray-200 */ 47 + --sl-color-accent: #4b5563; /* gray-600 */ 48 + --sl-color-accent-high: #111827; /* gray-900 */ 49 + } 50 + 51 + /* landing page */ 52 + .feature-grid { 53 + display: grid; 54 + grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); 55 + gap: 1rem; 56 + margin-top: 2rem; 57 + } 58 + 59 + .landing-section { 60 + max-width: 46rem; 61 + margin-top: 2rem; 62 + } 63 + 64 + /* hero tweaks for the landing page */ 65 + [data-has-hero] .hero { 66 + padding-block: 3rem; 67 + } 68 + 69 + /* ascii dolly in the hero (see scripts/gen-ascii-dolly.mjs) */ 70 + .ascii-dolly { 71 + font-family: var(--sl-font-mono); 72 + font-size: 0.55rem; 73 + line-height: 1.2; 74 + color: var(--sl-color-white); 75 + background: none; 76 + border: none; 77 + padding: 0; 78 + margin: 0; 79 + overflow: hidden; 80 + user-select: none; 81 + } 82 + 83 + [data-has-hero] .hero h1 { 84 + font-size: clamp(2rem, 5vw, 3.25rem); 85 + letter-spacing: -0.02em; 86 + }
+88
docs/src/styles/sidebar-icons.css
··· 1 + /* GENERATED by scripts/gen-sidebar-icons.mjs — do not edit by hand */ 2 + 3 + #starlight__sidebar a[data-icon]::before { 4 + content: ""; 5 + display: inline-block; 6 + width: 1rem; 7 + height: 1rem; 8 + margin-inline-end: 0.4em; 9 + vertical-align: -0.19em; 10 + background-color: currentColor; 11 + -webkit-mask-size: 100%; 12 + mask-size: 100%; 13 + } 14 + 15 + #starlight__sidebar a[data-icon="rocket"]::before { 16 + -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M4.5%2016.5c-1.5%201.26-2%205-2%205s3.74-.5%205-2c.71-.84.7-2.13-.09-2.91a2.18%202.18%200%200%200-2.91-.09z%22%20%2F%3E%3Cpath%20d%3D%22m12%2015-3-3a22%2022%200%200%201%202-3.95A12.88%2012.88%200%200%201%2022%202c0%202.72-.78%207.5-6%2011a22.35%2022.35%200%200%201-4%202z%22%20%2F%3E%3Cpath%20d%3D%22M9%2012H4s.55-3.03%202-4c1.62-1.08%205%200%205%200%22%20%2F%3E%3Cpath%20d%3D%22M12%2015v5s3.03-.55%204-2c1.08-1.62%200-5%200-5%22%20%2F%3E%3C%2Fsvg%3E"); 17 + mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M4.5%2016.5c-1.5%201.26-2%205-2%205s3.74-.5%205-2c.71-.84.7-2.13-.09-2.91a2.18%202.18%200%200%200-2.91-.09z%22%20%2F%3E%3Cpath%20d%3D%22m12%2015-3-3a22%2022%200%200%201%202-3.95A12.88%2012.88%200%200%201%2022%202c0%202.72-.78%207.5-6%2011a22.35%2022.35%200%200%201-4%202z%22%20%2F%3E%3Cpath%20d%3D%22M9%2012H4s.55-3.03%202-4c1.62-1.08%205%200%205%200%22%20%2F%3E%3Cpath%20d%3D%22M12%2015v5s3.03-.55%204-2c1.08-1.62%200-5%200-5%22%20%2F%3E%3C%2Fsvg%3E"); 18 + } 19 + 20 + #starlight__sidebar a[data-icon="at-sign"]::before { 21 + -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%224%22%20%2F%3E%3Cpath%20d%3D%22M16%208v5a3%203%200%200%200%206%200v-1a10%2010%200%201%200-4%208%22%20%2F%3E%3C%2Fsvg%3E"); 22 + mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%224%22%20%2F%3E%3Cpath%20d%3D%22M16%208v5a3%203%200%200%200%206%200v-1a10%2010%200%201%200-4%208%22%20%2F%3E%3C%2Fsvg%3E"); 23 + } 24 + 25 + #starlight__sidebar a[data-icon="globe"]::before { 26 + -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2210%22%20%2F%3E%3Cpath%20d%3D%22M12%202a14.5%2014.5%200%200%200%200%2020%2014.5%2014.5%200%200%200%200-20%22%20%2F%3E%3Cpath%20d%3D%22M2%2012h20%22%20%2F%3E%3C%2Fsvg%3E"); 27 + mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2210%22%20%2F%3E%3Cpath%20d%3D%22M12%202a14.5%2014.5%200%200%200%200%2020%2014.5%2014.5%200%200%200%200-20%22%20%2F%3E%3Cpath%20d%3D%22M2%2012h20%22%20%2F%3E%3C%2Fsvg%3E"); 28 + } 29 + 30 + #starlight__sidebar a[data-icon="life-buoy"]::before { 31 + -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2210%22%20%2F%3E%3Cpath%20d%3D%22m4.93%204.93%204.24%204.24%22%20%2F%3E%3Cpath%20d%3D%22m14.83%209.17%204.24-4.24%22%20%2F%3E%3Cpath%20d%3D%22m14.83%2014.83%204.24%204.24%22%20%2F%3E%3Cpath%20d%3D%22m9.17%2014.83-4.24%204.24%22%20%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%224%22%20%2F%3E%3C%2Fsvg%3E"); 32 + mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2210%22%20%2F%3E%3Cpath%20d%3D%22m4.93%204.93%204.24%204.24%22%20%2F%3E%3Cpath%20d%3D%22m14.83%209.17%204.24-4.24%22%20%2F%3E%3Cpath%20d%3D%22m14.83%2014.83%204.24%204.24%22%20%2F%3E%3Cpath%20d%3D%22m9.17%2014.83-4.24%204.24%22%20%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%224%22%20%2F%3E%3C%2Fsvg%3E"); 33 + } 34 + 35 + #starlight__sidebar a[data-icon="server"]::before { 36 + -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Crect%20width%3D%2220%22%20height%3D%228%22%20x%3D%222%22%20y%3D%222%22%20rx%3D%222%22%20ry%3D%222%22%20%2F%3E%3Crect%20width%3D%2220%22%20height%3D%228%22%20x%3D%222%22%20y%3D%2214%22%20rx%3D%222%22%20ry%3D%222%22%20%2F%3E%3Cline%20x1%3D%226%22%20x2%3D%226.01%22%20y1%3D%226%22%20y2%3D%226%22%20%2F%3E%3Cline%20x1%3D%226%22%20x2%3D%226.01%22%20y1%3D%2218%22%20y2%3D%2218%22%20%2F%3E%3C%2Fsvg%3E"); 37 + mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Crect%20width%3D%2220%22%20height%3D%228%22%20x%3D%222%22%20y%3D%222%22%20rx%3D%222%22%20ry%3D%222%22%20%2F%3E%3Crect%20width%3D%2220%22%20height%3D%228%22%20x%3D%222%22%20y%3D%2214%22%20rx%3D%222%22%20ry%3D%222%22%20%2F%3E%3Cline%20x1%3D%226%22%20x2%3D%226.01%22%20y1%3D%226%22%20y2%3D%226%22%20%2F%3E%3Cline%20x1%3D%226%22%20x2%3D%226.01%22%20y1%3D%2218%22%20y2%3D%2218%22%20%2F%3E%3C%2Fsvg%3E"); 38 + } 39 + 40 + #starlight__sidebar a[data-icon="hard-drive"]::before { 41 + -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cline%20x1%3D%2222%22%20x2%3D%222%22%20y1%3D%2212%22%20y2%3D%2212%22%20%2F%3E%3Cpath%20d%3D%22M5.45%205.11%202%2012v6a2%202%200%200%200%202%202h16a2%202%200%200%200%202-2v-6l-3.45-6.89A2%202%200%200%200%2016.76%204H7.24a2%202%200%200%200-1.79%201.11z%22%20%2F%3E%3Cline%20x1%3D%226%22%20x2%3D%226.01%22%20y1%3D%2216%22%20y2%3D%2216%22%20%2F%3E%3Cline%20x1%3D%2210%22%20x2%3D%2210.01%22%20y1%3D%2216%22%20y2%3D%2216%22%20%2F%3E%3C%2Fsvg%3E"); 42 + mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cline%20x1%3D%2222%22%20x2%3D%222%22%20y1%3D%2212%22%20y2%3D%2212%22%20%2F%3E%3Cpath%20d%3D%22M5.45%205.11%202%2012v6a2%202%200%200%200%202%202h16a2%202%200%200%200%202-2v-6l-3.45-6.89A2%202%200%200%200%2016.76%204H7.24a2%202%200%200%200-1.79%201.11z%22%20%2F%3E%3Cline%20x1%3D%226%22%20x2%3D%226.01%22%20y1%3D%2216%22%20y2%3D%2216%22%20%2F%3E%3Cline%20x1%3D%2210%22%20x2%3D%2210.01%22%20y1%3D%2216%22%20y2%3D%2216%22%20%2F%3E%3C%2Fsvg%3E"); 43 + } 44 + 45 + #starlight__sidebar a[data-icon="workflow"]::before { 46 + -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Crect%20width%3D%228%22%20height%3D%228%22%20x%3D%223%22%20y%3D%223%22%20rx%3D%222%22%20%2F%3E%3Cpath%20d%3D%22M7%2011v4a2%202%200%200%200%202%202h4%22%20%2F%3E%3Crect%20width%3D%228%22%20height%3D%228%22%20x%3D%2213%22%20y%3D%2213%22%20rx%3D%222%22%20%2F%3E%3C%2Fsvg%3E"); 47 + mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Crect%20width%3D%228%22%20height%3D%228%22%20x%3D%223%22%20y%3D%223%22%20rx%3D%222%22%20%2F%3E%3Cpath%20d%3D%22M7%2011v4a2%202%200%200%200%202%202h4%22%20%2F%3E%3Crect%20width%3D%228%22%20height%3D%228%22%20x%3D%2213%22%20y%3D%2213%22%20rx%3D%222%22%20%2F%3E%3C%2Fsvg%3E"); 48 + } 49 + 50 + #starlight__sidebar a[data-icon="play"]::before { 51 + -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M5%205a2%202%200%200%201%203.008-1.728l11.997%206.998a2%202%200%200%201%20.003%203.458l-12%207A2%202%200%200%201%205%2019z%22%20%2F%3E%3C%2Fsvg%3E"); 52 + mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M5%205a2%202%200%200%201%203.008-1.728l11.997%206.998a2%202%200%200%201%20.003%203.458l-12%207A2%202%200%200%201%205%2019z%22%20%2F%3E%3C%2Fsvg%3E"); 53 + } 54 + 55 + #starlight__sidebar a[data-icon="key-round"]::before { 56 + -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M2.586%2017.414A2%202%200%200%200%202%2018.828V21a1%201%200%200%200%201%201h3a1%201%200%200%200%201-1v-1a1%201%200%200%201%201-1h1a1%201%200%200%200%201-1v-1a1%201%200%200%201%201-1h.172a2%202%200%200%200%201.414-.586l.814-.814a6.5%206.5%200%201%200-4-4z%22%20%2F%3E%3Ccircle%20cx%3D%2216.5%22%20cy%3D%227.5%22%20r%3D%22.5%22%20fill%3D%22currentColor%22%20%2F%3E%3C%2Fsvg%3E"); 57 + mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M2.586%2017.414A2%202%200%200%200%202%2018.828V21a1%201%200%200%200%201%201h3a1%201%200%200%200%201-1v-1a1%201%200%200%201%201-1h1a1%201%200%200%200%201-1v-1a1%201%200%200%201%201-1h.172a2%202%200%200%200%201.414-.586l.814-.814a6.5%206.5%200%201%200-4-4z%22%20%2F%3E%3Ccircle%20cx%3D%2216.5%22%20cy%3D%227.5%22%20r%3D%22.5%22%20fill%3D%22currentColor%22%20%2F%3E%3C%2Fsvg%3E"); 58 + } 59 + 60 + #starlight__sidebar a[data-icon="network"]::before { 61 + -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Crect%20x%3D%2216%22%20y%3D%2216%22%20width%3D%226%22%20height%3D%226%22%20rx%3D%221%22%20%2F%3E%3Crect%20x%3D%222%22%20y%3D%2216%22%20width%3D%226%22%20height%3D%226%22%20rx%3D%221%22%20%2F%3E%3Crect%20x%3D%229%22%20y%3D%222%22%20width%3D%226%22%20height%3D%226%22%20rx%3D%221%22%20%2F%3E%3Cpath%20d%3D%22M5%2016v-3a1%201%200%200%201%201-1h12a1%201%200%200%201%201%201v3%22%20%2F%3E%3Cpath%20d%3D%22M12%2012V8%22%20%2F%3E%3C%2Fsvg%3E"); 62 + mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Crect%20x%3D%2216%22%20y%3D%2216%22%20width%3D%226%22%20height%3D%226%22%20rx%3D%221%22%20%2F%3E%3Crect%20x%3D%222%22%20y%3D%2216%22%20width%3D%226%22%20height%3D%226%22%20rx%3D%221%22%20%2F%3E%3Crect%20x%3D%229%22%20y%3D%222%22%20width%3D%226%22%20height%3D%226%22%20rx%3D%221%22%20%2F%3E%3Cpath%20d%3D%22M5%2016v-3a1%201%200%200%201%201-1h12a1%201%200%200%201%201%201v3%22%20%2F%3E%3Cpath%20d%3D%22M12%2012V8%22%20%2F%3E%3C%2Fsvg%3E"); 63 + } 64 + 65 + #starlight__sidebar a[data-icon="webhook"]::before { 66 + -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M18%2016.98h-5.99c-1.1%200-1.95.94-2.48%201.9A4%204%200%200%201%202%2017c.01-.7.2-1.4.57-2%22%20%2F%3E%3Cpath%20d%3D%22m6%2017%203.13-5.78c.53-.97.1-2.18-.5-3.1a4%204%200%201%201%206.89-4.06%22%20%2F%3E%3Cpath%20d%3D%22m12%206%203.13%205.73C15.66%2012.7%2016.9%2013%2018%2013a4%204%200%200%201%200%208%22%20%2F%3E%3C%2Fsvg%3E"); 67 + mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M18%2016.98h-5.99c-1.1%200-1.95.94-2.48%201.9A4%204%200%200%201%202%2017c.01-.7.2-1.4.57-2%22%20%2F%3E%3Cpath%20d%3D%22m6%2017%203.13-5.78c.53-.97.1-2.18-.5-3.1a4%204%200%201%201%206.89-4.06%22%20%2F%3E%3Cpath%20d%3D%22m12%206%203.13%205.73C15.66%2012.7%2016.9%2013%2018%2013a4%204%200%200%201%200%208%22%20%2F%3E%3C%2Fsvg%3E"); 68 + } 69 + 70 + #starlight__sidebar a[data-icon="cable"]::before { 71 + -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M17%2019a1%201%200%200%201-1-1v-2a2%202%200%200%201%202-2h2a2%202%200%200%201%202%202v2a1%201%200%200%201-1%201z%22%20%2F%3E%3Cpath%20d%3D%22M17%2021v-2%22%20%2F%3E%3Cpath%20d%3D%22M19%2014V6.5a1%201%200%200%200-7%200v11a1%201%200%200%201-7%200V10%22%20%2F%3E%3Cpath%20d%3D%22M21%2021v-2%22%20%2F%3E%3Cpath%20d%3D%22M3%205V3%22%20%2F%3E%3Cpath%20d%3D%22M4%2010a2%202%200%200%201-2-2V6a1%201%200%200%201%201-1h4a1%201%200%200%201%201%201v2a2%202%200%200%201-2%202z%22%20%2F%3E%3Cpath%20d%3D%22M7%205V3%22%20%2F%3E%3C%2Fsvg%3E"); 72 + mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M17%2019a1%201%200%200%201-1-1v-2a2%202%200%200%201%202-2h2a2%202%200%200%201%202%202v2a1%201%200%200%201-1%201z%22%20%2F%3E%3Cpath%20d%3D%22M17%2021v-2%22%20%2F%3E%3Cpath%20d%3D%22M19%2014V6.5a1%201%200%200%200-7%200v11a1%201%200%200%201-7%200V10%22%20%2F%3E%3Cpath%20d%3D%22M21%2021v-2%22%20%2F%3E%3Cpath%20d%3D%22M3%205V3%22%20%2F%3E%3Cpath%20d%3D%22M4%2010a2%202%200%200%201-2-2V6a1%201%200%200%201%201-1h4a1%201%200%200%201%201%201v2a2%202%200%200%201-2%202z%22%20%2F%3E%3Cpath%20d%3D%22M7%205V3%22%20%2F%3E%3C%2Fsvg%3E"); 73 + } 74 + 75 + #starlight__sidebar a[data-icon="arrow-up-circle"]::before { 76 + -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2210%22%20%2F%3E%3Cpath%20d%3D%22m16%2012-4-4-4%204%22%20%2F%3E%3Cpath%20d%3D%22M12%2016V8%22%20%2F%3E%3C%2Fsvg%3E"); 77 + mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2210%22%20%2F%3E%3Cpath%20d%3D%22m16%2012-4-4-4%204%22%20%2F%3E%3Cpath%20d%3D%22M12%2016V8%22%20%2F%3E%3C%2Fsvg%3E"); 78 + } 79 + 80 + #starlight__sidebar a[data-icon="hammer"]::before { 81 + -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22m15%2012-9.373%209.373a1%201%200%200%201-3.001-3L12%209%22%20%2F%3E%3Cpath%20d%3D%22m18%2015%204-4%22%20%2F%3E%3Cpath%20d%3D%22m21.5%2011.5-1.914-1.914A2%202%200%200%201%2019%208.172v-.344a2%202%200%200%200-.586-1.414l-1.657-1.657A6%206%200%200%200%2012.516%203H9l1.243%201.243A6%206%200%200%201%2012%208.485V10l2%202h1.172a2%202%200%200%201%201.414.586L18.5%2014.5%22%20%2F%3E%3C%2Fsvg%3E"); 82 + mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22m15%2012-9.373%209.373a1%201%200%200%201-3.001-3L12%209%22%20%2F%3E%3Cpath%20d%3D%22m18%2015%204-4%22%20%2F%3E%3Cpath%20d%3D%22m21.5%2011.5-1.914-1.914A2%202%200%200%201%2019%208.172v-.344a2%202%200%200%200-.586-1.414l-1.657-1.657A6%206%200%200%200%2012.516%203H9l1.243%201.243A6%206%200%200%201%2012%208.485V10l2%202h1.172a2%202%200%200%201%201.414.586L18.5%2014.5%22%20%2F%3E%3C%2Fsvg%3E"); 83 + } 84 + 85 + #starlight__sidebar a[data-icon="git-pull-request"]::before { 86 + -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Ccircle%20cx%3D%2218%22%20cy%3D%2218%22%20r%3D%223%22%20%2F%3E%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20%2F%3E%3Cpath%20d%3D%22M13%206h3a2%202%200%200%201%202%202v7%22%20%2F%3E%3Cline%20x1%3D%226%22%20x2%3D%226%22%20y1%3D%229%22%20y2%3D%2221%22%20%2F%3E%3C%2Fsvg%3E"); 87 + mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Ccircle%20cx%3D%2218%22%20cy%3D%2218%22%20r%3D%223%22%20%2F%3E%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20%2F%3E%3Cpath%20d%3D%22M13%206h3a2%202%200%200%201%202%202v7%22%20%2F%3E%3Cline%20x1%3D%226%22%20x2%3D%226%22%20y1%3D%229%22%20y2%3D%2221%22%20%2F%3E%3C%2Fsvg%3E"); 88 + }
+97
docs/src/styles/tangled.css
··· 1 + /* 2 + * the appview's stylesheet, compiled against the docs tailwind 3 + * config (see tailwind.config.cjs). this brings in the base layer 4 + * (14px root font size, link/code styles, selection color) and the 5 + * component classes (.btn, .btn-create, .btn-flat, ...). 6 + */ 7 + @import "../../../input.css"; 8 + 9 + /* preflight is disabled (starlight has its own reset), but tailwind's 10 + * border utilities assume preflight's `border-style: solid` reset */ 11 + .btn, 12 + .hero .sl-link-button, 13 + [class*="border-"] { 14 + border-style: solid; 15 + } 16 + 17 + /* logo at the same size as the appview topbar logotype (h-8) */ 18 + .site-title img { 19 + @apply h-8; 20 + } 21 + 22 + /* markdown content, styled like the appview renders readmes: 23 + * plain black/white links, bordered h1/h2, gray inline code */ 24 + /* like `prose` links in appview readmes: underlined, medium weight. 25 + * NB: the card exclusion must not say `.btn` here — tailwind's @apply 26 + * of .btn/.btn-create elsewhere clones every rule that mentions .btn 27 + * in its selector, re-introducing the underline through the clone */ 28 + .sl-markdown-content a:not(.feature-card):not(:where(.not-content *)) { 29 + @apply text-black underline font-medium hover:text-gray-800 dark:text-white dark:hover:text-gray-300; 30 + } 31 + 32 + .sl-markdown-content h1:not(:where(.not-content *)) { 33 + @apply mt-3 pb-3 border-b border-gray-300 dark:border-gray-600; 34 + } 35 + 36 + .sl-markdown-content h2:not(:where(.not-content *)) { 37 + @apply mt-3 pb-3 border-b border-gray-200 dark:border-gray-700; 38 + } 39 + 40 + .sl-markdown-content code:not(:where(.not-content *)) { 41 + @apply font-mono rounded px-1 bg-gray-100 text-black dark:bg-gray-700 dark:text-white; 42 + } 43 + 44 + /* the appview's base `label` style (block, py-2, text-sm) clobbers 45 + * starlight's select labels — starlight's own styles live in css 46 + * cascade layers and lose to the unlayered appview css */ 47 + starlight-theme-select label, 48 + starlight-lang-select label { 49 + display: flex; 50 + padding: 0; 51 + font-size: unset; 52 + color: var(--sl-color-gray-1); 53 + } 54 + 55 + starlight-theme-select label:hover, 56 + starlight-lang-select label:hover { 57 + color: var(--sl-color-gray-2); 58 + } 59 + 60 + /* sidebar current-page pill, like the appview settings sidebar tabs */ 61 + .sidebar-content a[aria-current="page"], 62 + .sidebar-content a[aria-current="page"]:hover, 63 + .sidebar-content a[aria-current="page"]:focus { 64 + @apply bg-gray-100 text-black font-semibold dark:bg-gray-700 dark:text-white; 65 + } 66 + 67 + /* text links in the top bar (see components/HeaderLinks.astro) */ 68 + a.header-link, 69 + a.header-link:hover { 70 + @apply text-sm no-underline text-gray-500 hover:text-black dark:text-gray-400 dark:hover:text-white; 71 + } 72 + 73 + /* compact next/prev pagination links */ 74 + .pagination-links a { 75 + @apply p-3 gap-2 rounded no-underline hover:no-underline; 76 + } 77 + 78 + .pagination-links a .link-title { 79 + @apply text-base font-semibold; 80 + } 81 + 82 + .pagination-links a svg { 83 + @apply size-5; 84 + } 85 + 86 + /* restyle starlight's hero buttons with the appview button classes */ 87 + .hero .sl-link-button.primary { 88 + @apply btn-create text-base; 89 + } 90 + 91 + .hero .sl-link-button.primary:hover { 92 + @apply text-white no-underline; 93 + } 94 + 95 + .hero .sl-link-button.minimal { 96 + @apply btn-flat text-base; 97 + }
-216
docs/styles.css
··· 1 - :root { 2 - --pagefind-ui-scale: 0.875 !important; 3 - --pagefind-ui-border-width: 1px !important; 4 - --pagefind-ui-border-radius: 4px !important; 5 - --pagefind-ui-border: #d1d5db !important; 6 - --pagefind-ui-background: #f9fafb !important; 7 - --pagefind-ui-text: #111827 !important; 8 - --pagefind-ui-primary: #6b7280 !important; 9 - --pagefind-ui-font: inherit !important; 10 - } 11 - 12 - .pagefind-ui__search-input { 13 - font-weight: normal !important; 14 - } 15 - 16 - @media (prefers-color-scheme: dark) { 17 - :root { 18 - --pagefind-ui-border: #4b5563 !important; 19 - --pagefind-ui-background: #1f2937 !important; 20 - --pagefind-ui-text: #f9fafb !important; 21 - --pagefind-ui-primary: #9ca3af !important; 22 - } 23 - } 24 - 25 - @media (max-width: 768px) { 26 - .pagefind-ui__result-thumb { 27 - width: 0 !important; 28 - } 29 - .pagefind-ui__result-excerpt, 30 - .pagefind-ui__result-title { 31 - overflow-wrap: break-word; 32 - word-break: break-word; 33 - } 34 - .pagefind-ui__search-input, 35 - .pagefind-ui__search-clear { 36 - max-width: 100%; 37 - } 38 - .pagefind-ui__form { 39 - overflow: hidden; 40 - } 41 - } 42 - 43 - svg { 44 - width: 16px; 45 - height: 16px; 46 - } 47 - 48 - :root { 49 - --syntax-alert: #d20f39; 50 - --syntax-annotation: #fe640b; 51 - --syntax-attribute: #df8e1d; 52 - --syntax-basen: #40a02b; 53 - --syntax-builtin: #1e66f5; 54 - --syntax-controlflow: #8839ef; 55 - --syntax-char: #04a5e5; 56 - --syntax-constant: #fe640b; 57 - --syntax-comment: #9ca0b0; 58 - --syntax-commentvar: #7c7f93; 59 - --syntax-documentation: #9ca0b0; 60 - --syntax-datatype: #df8e1d; 61 - --syntax-decval: #40a02b; 62 - --syntax-error: #d20f39; 63 - --syntax-extension: #4c4f69; 64 - --syntax-float: #40a02b; 65 - --syntax-function: #1e66f5; 66 - --syntax-import: #40a02b; 67 - --syntax-information: #04a5e5; 68 - --syntax-keyword: #8839ef; 69 - --syntax-operator: #179299; 70 - --syntax-other: #8839ef; 71 - --syntax-preprocessor: #ea76cb; 72 - --syntax-specialchar: #04a5e5; 73 - --syntax-specialstring: #ea76cb; 74 - --syntax-string: #40a02b; 75 - --syntax-variable: #8839ef; 76 - --syntax-verbatimstring: #40a02b; 77 - --syntax-warning: #df8e1d; 78 - } 79 - 80 - @media (prefers-color-scheme: dark) { 81 - :root { 82 - --syntax-alert: #f38ba8; 83 - --syntax-annotation: #fab387; 84 - --syntax-attribute: #f9e2af; 85 - --syntax-basen: #a6e3a1; 86 - --syntax-builtin: #89b4fa; 87 - --syntax-controlflow: #cba6f7; 88 - --syntax-char: #89dceb; 89 - --syntax-constant: #fab387; 90 - --syntax-comment: #6c7086; 91 - --syntax-commentvar: #585b70; 92 - --syntax-documentation: #6c7086; 93 - --syntax-datatype: #f9e2af; 94 - --syntax-decval: #a6e3a1; 95 - --syntax-error: #f38ba8; 96 - --syntax-extension: #cdd6f4; 97 - --syntax-float: #a6e3a1; 98 - --syntax-function: #89b4fa; 99 - --syntax-import: #a6e3a1; 100 - --syntax-information: #89dceb; 101 - --syntax-keyword: #cba6f7; 102 - --syntax-operator: #94e2d5; 103 - --syntax-other: #cba6f7; 104 - --syntax-preprocessor: #f5c2e7; 105 - --syntax-specialchar: #89dceb; 106 - --syntax-specialstring: #f5c2e7; 107 - --syntax-string: #a6e3a1; 108 - --syntax-variable: #cba6f7; 109 - --syntax-verbatimstring: #a6e3a1; 110 - --syntax-warning: #f9e2af; 111 - } 112 - } 113 - 114 - /* pandoc syntax highlighting classes */ 115 - code span.al { 116 - color: var(--syntax-alert); 117 - font-weight: bold; 118 - } /* alert */ 119 - code span.an { 120 - color: var(--syntax-annotation); 121 - font-weight: bold; 122 - font-style: italic; 123 - } /* annotation */ 124 - code span.at { 125 - color: var(--syntax-attribute); 126 - } /* attribute */ 127 - code span.bn { 128 - color: var(--syntax-basen); 129 - } /* basen */ 130 - code span.bu { 131 - color: var(--syntax-builtin); 132 - } /* builtin */ 133 - code span.cf { 134 - color: var(--syntax-controlflow); 135 - font-weight: bold; 136 - } /* controlflow */ 137 - code span.ch { 138 - color: var(--syntax-char); 139 - } /* char */ 140 - code span.cn { 141 - color: var(--syntax-constant); 142 - } /* constant */ 143 - code span.co { 144 - color: var(--syntax-comment); 145 - font-style: italic; 146 - } /* comment */ 147 - code span.cv { 148 - color: var(--syntax-commentvar); 149 - font-weight: bold; 150 - font-style: italic; 151 - } /* commentvar */ 152 - code span.do { 153 - color: var(--syntax-documentation); 154 - font-style: italic; 155 - } /* documentation */ 156 - code span.dt { 157 - color: var(--syntax-datatype); 158 - } /* datatype */ 159 - code span.dv { 160 - color: var(--syntax-decval); 161 - } /* decval */ 162 - code span.er { 163 - color: var(--syntax-error); 164 - font-weight: bold; 165 - } /* error */ 166 - code span.ex { 167 - color: var(--syntax-extension); 168 - } /* extension */ 169 - code span.fl { 170 - color: var(--syntax-float); 171 - } /* float */ 172 - code span.fu { 173 - color: var(--syntax-function); 174 - } /* function */ 175 - code span.im { 176 - color: var(--syntax-import); 177 - font-weight: bold; 178 - } /* import */ 179 - code span.in { 180 - color: var(--syntax-information); 181 - font-weight: bold; 182 - font-style: italic; 183 - } /* information */ 184 - code span.kw { 185 - color: var(--syntax-keyword); 186 - font-weight: bold; 187 - } /* keyword */ 188 - code span.op { 189 - color: var(--syntax-operator); 190 - } /* operator */ 191 - code span.ot { 192 - color: var(--syntax-other); 193 - } /* other */ 194 - code span.pp { 195 - color: var(--syntax-preprocessor); 196 - } /* preprocessor */ 197 - code span.sc { 198 - color: var(--syntax-specialchar); 199 - } /* specialchar */ 200 - code span.ss { 201 - color: var(--syntax-specialstring); 202 - } /* specialstring */ 203 - code span.st { 204 - color: var(--syntax-string); 205 - } /* string */ 206 - code span.va { 207 - color: var(--syntax-variable); 208 - } /* variable */ 209 - code span.vs { 210 - color: var(--syntax-verbatimstring); 211 - } /* verbatimstring */ 212 - code span.wa { 213 - color: var(--syntax-warning); 214 - font-weight: bold; 215 - font-style: italic; 216 - } /* warning */
+35
docs/tailwind.config.cjs
··· 1 + // compiles the appview's input.css for the docs site. we can't require 2 + // the root tailwind.config.js here (it resolves its plugins from the 3 + // standalone tailwind CLI in the nix build), so the font stacks are 4 + // duplicated from it. differences from the appview config: 5 + // - scans the docs sources instead of appview templates 6 + // - keys dark mode off starlight's data-theme attribute instead of 7 + // prefers-color-scheme, so the theme toggle works 8 + // - disables preflight: starlight ships its own reset 9 + 10 + /** @type {import('tailwindcss').Config} */ 11 + module.exports = { 12 + content: ["./src/**/*.{astro,html,md,mdx}"], 13 + darkMode: ["class", '[data-theme="dark"]'], 14 + corePlugins: { 15 + preflight: false, 16 + }, 17 + theme: { 18 + extend: { 19 + fontFamily: { 20 + sans: ["InterVariable", "system-ui", "sans-serif", "ui-sans-serif"], 21 + mono: [ 22 + "IBMPlexMono", 23 + "ui-monospace", 24 + "SFMono-Regular", 25 + "Menlo", 26 + "Monaco", 27 + "Consolas", 28 + "Liberation Mono", 29 + "Courier New", 30 + "monospace", 31 + ], 32 + }, 33 + }, 34 + }, 35 + };
-175
docs/template.html
··· 1 - <!DOCTYPE html> 2 - <html xmlns="http://www.w3.org/1999/xhtml" lang="$lang$" xml:lang="$lang$"$if(dir)$ dir="$dir$"$endif$> 3 - <head> 4 - <meta charset="utf-8" /> 5 - <meta name="generator" content="pandoc" /> 6 - <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" /> 7 - $for(author-meta)$ 8 - <meta name="author" content="$author-meta$" /> 9 - $endfor$ 10 - 11 - $if(date-meta)$ 12 - <meta name="dcterms.date" content="$date-meta$" /> 13 - $endif$ 14 - 15 - $if(keywords)$ 16 - <meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" /> 17 - $endif$ 18 - 19 - $if(description-meta)$ 20 - <meta name="description" content="$description-meta$" /> 21 - $endif$ 22 - 23 - <title>$pagetitle$</title> 24 - 25 - <style> 26 - $styles.css()$ 27 - </style> 28 - 29 - $for(css)$ 30 - <link rel="stylesheet" href="$css$" /> 31 - $endfor$ 32 - 33 - $for(header-includes)$ 34 - $header-includes$ 35 - $endfor$ 36 - 37 - <link href="$root$pagefind/pagefind-ui.css" rel="stylesheet"> 38 - <script src="$root$pagefind/pagefind-ui.js"></script> 39 - <script> 40 - window.addEventListener("DOMContentLoaded", () => { 41 - document.querySelectorAll(".pagefind-search").forEach((el) => { 42 - new PagefindUI({ 43 - element: el, 44 - showSubResults: true, 45 - resetStyles: false, 46 - }); 47 - }); 48 - }); 49 - </script> 50 - <link rel="preload" href="$root$static/fonts/InterVariable.woff2" as="font" type="font/woff2" crossorigin /> 51 - <link rel="icon" href="$root$static/logos/dolly.ico" sizes="48x48"/> 52 - <link rel="icon" href="$root$static/logos/dolly.svg" sizes="any" type="image/svg+xml"/> 53 - <link rel="apple-touch-icon" href="$root$static/logos/dolly.png"/> 54 - 55 - </head> 56 - <body class="bg-white dark:bg-gray-900 flex flex-col min-h-svh"$if(single-page)$ data-pagefind-ignore$endif$> 57 - $for(include-before)$ 58 - $include-before$ 59 - $endfor$ 60 - 61 - $if(toc)$ 62 - <!-- mobile TOC trigger --> 63 - <div data-pagefind-ignore class="md:hidden px-6 py-4 border-b border-gray-200 dark:border-gray-700"> 64 - <button 65 - type="button" 66 - popovertarget="mobile-toc-popover" 67 - popovertargetaction="toggle" 68 - class="w-full flex gap-2 items-center text-sm font-semibold dark:text-white" 69 - > 70 - ${ menu.svg() } 71 - $if(toc-title)$$toc-title$$else$Table of Contents$endif$ 72 - </button> 73 - </div> 74 - 75 - <div 76 - id="mobile-toc-popover" 77 - popover 78 - data-pagefind-ignore 79 - class="mobile-toc-popover 80 - bg-gray-50 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 81 - h-full overflow-x-hidden overflow-y-auto shadow-sm 82 - px-6 py-4 fixed inset-x-0 top-0 w-fit max-w-4/5 m-0" 83 - > 84 - <div class="flex flex-col min-h-full"> 85 - <div class="flex-1 space-y-4"> 86 - <button 87 - type="button" 88 - popovertarget="mobile-toc-popover" 89 - popovertargetaction="toggle" 90 - class="w-full flex gap-2 items-center text-sm font-semibold dark:text-white mb-4"> 91 - ${ x.svg() } 92 - $if(toc-title)$$toc-title$$else$Table of Contents$endif$ 93 - </button> 94 - ${ logo.html() } 95 - ${ search.html() } 96 - ${ table-of-contents:toc.html() } 97 - </div> 98 - ${ single-page:mode.html() } 99 - </div> 100 - </div> 101 - 102 - <!-- desktop sidebar toc --> 103 - <nav 104 - id="$idprefix$TOC" 105 - role="doc-toc" 106 - data-pagefind-ignore 107 - class="hidden md:flex md:flex-col gap-4 fixed left-0 top-0 w-80 h-screen 108 - bg-gray-50 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 109 - p-4 z-50 overflow-y-auto"> 110 - ${ logo.html() } 111 - ${ search.html() } 112 - <div class="flex-1"> 113 - $if(toc-title)$ 114 - <h2 id="$idprefix$toc-title" class="text-lg font-semibold mb-4 text-gray-900">$toc-title$</h2> 115 - $endif$ 116 - ${ table-of-contents:toc.html() } 117 - </div> 118 - ${ single-page:mode.html() } 119 - </nav> 120 - $endif$ 121 - 122 - <div class="$if(toc)$md:ml-80$endif$ flex-1 flex flex-col"> 123 - <main class="max-w-4xl w-full mx-auto p-6 flex-1"> 124 - $if(top)$ 125 - $-- only print title block if this is NOT the top page 126 - $else$ 127 - $if(title)$ 128 - <header id="title-block-header" class="mb-8 pb-8 border-b border-gray-200 dark:border-gray-700"> 129 - <h1 class="text-4xl font-bold mb-2 text-black dark:text-white">$title$</h1> 130 - $if(subtitle)$ 131 - <p class="text-xl text-gray-500 dark:text-gray-400 mb-2">$subtitle$</p> 132 - $endif$ 133 - $for(author)$ 134 - <p class="text-sm text-gray-500 dark:text-gray-400">$author$</p> 135 - $endfor$ 136 - $if(date)$ 137 - <p class="text-sm text-gray-500 dark:text-gray-400">Updated on $date$</p> 138 - $endif$ 139 - $endif$ 140 - </header> 141 - $if(abstract)$ 142 - <article class="prose dark:prose-invert max-w-none"> 143 - $abstract$ 144 - </article> 145 - $endif$ 146 - $endif$ 147 - 148 - <article class="prose dark:prose-invert max-w-none"> 149 - $body$ 150 - </article> 151 - </main> 152 - <nav id="sitenav" class="border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800"> 153 - <div class="max-w-4xl mx-auto px-8 py-4"> 154 - <div class="flex justify-between gap-4"> 155 - <span class="flex-1"> 156 - $if(previous.url)$ 157 - <span class="text-xs text-gray-500 dark:text-gray-400 uppercase block mb-1">Previous</span> 158 - <a href="$previous.url$" accesskey="p" rel="previous">$previous.title$</a> 159 - $endif$ 160 - </span> 161 - <span class="flex-1 text-right"> 162 - $if(next.url)$ 163 - <span class="text-xs text-gray-500 dark:text-gray-400 uppercase block mb-1">Next</span> 164 - <a href="$next.url$" accesskey="n" rel="next">$next.title$</a> 165 - $endif$ 166 - </span> 167 - </div> 168 - </div> 169 - </nav> 170 - </div> 171 - $for(include-after)$ 172 - $include-after$ 173 - $endfor$ 174 - </body> 175 - </html>
-4
docs/toc.html
··· 1 - <div class="[&_ul]:space-y-6 [&_ul]:pl-0 [&_ul]:font-bold [&_ul_ul]:pl-4 [&_ul_ul]:font-normal [&_ul_ul]:space-y-2 [&_li]:space-y-2"> 2 - $table-of-contents$ 3 - </div> 4 -
+5
docs/tsconfig.json
··· 1 + { 2 + "extends": "astro/tsconfigs/strict", 3 + "include": [".astro/types.d.ts", "**/*"], 4 + "exclude": ["dist"] 5 + }