diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml
new file mode 100644
index 000000000..4e7a57eb6
--- /dev/null
+++ b/.github/workflows/check-links.yml
@@ -0,0 +1,38 @@
+name: Check Links
+
+on:
+ pull_request:
+ branches: [main]
+ push:
+ branches: [main]
+
+jobs:
+ check-links:
+ name: Check Internal Links
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v6
+
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v6
+ with:
+ node-version: '22'
+ cache: 'pnpm'
+
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile
+
+ - name: Build static site
+ run: pnpm build
+ env:
+ NODE_OPTIONS: --max-old-space-size=8192
+
+ - name: Check for broken links
+ run: node --import tsx scripts/check-broken-links.ts
diff --git a/app/posts/[slug]/page.tsx b/app/posts/[slug]/page.tsx
index a542b2363..4e9ded007 100644
--- a/app/posts/[slug]/page.tsx
+++ b/app/posts/[slug]/page.tsx
@@ -64,7 +64,6 @@ export async function generateMetadata({
],
publishedTime: post.publishedAt || post.date,
modifiedTime: post.updatedAt || post.date,
- authors: post.author ? [`https://devops-daily.com/authors/${post.author.slug}`] : undefined,
section: post.category?.name,
tags: post.tags,
},
diff --git a/components/post-header.tsx b/components/post-header.tsx
index 6d70d030a..88419d187 100644
--- a/components/post-header.tsx
+++ b/components/post-header.tsx
@@ -1,6 +1,6 @@
import Link from 'next/link';
import { Badge } from '@/components/ui/badge';
-import { Clock, Calendar, User, Info } from 'lucide-react';
+import { Clock, Calendar, Info } from 'lucide-react';
interface PostHeaderProps {
post: {
@@ -34,12 +34,6 @@ export function PostHeader({ post, hasAffiliateLinks = false }: PostHeaderProps)
{post.readingTime}
- {post.author && (
-
-
- {post.author.name}
-
- )}
{post.title}
{hasAffiliateLinks && (
diff --git a/content/exercises/terraform-digitalocean-droplet.json b/content/exercises/terraform-digitalocean-droplet.json
index cdd3b1caf..9dc79ba14 100644
--- a/content/exercises/terraform-digitalocean-droplet.json
+++ b/content/exercises/terraform-digitalocean-droplet.json
@@ -247,11 +247,6 @@
"url": "https://www.terraform.io/docs/cloud/guides/recommended-practices/index.html",
"type": "guide",
"external": true
- },
- {
- "title": "Infrastructure as Code Fundamentals",
- "url": "/posts/infrastructure-as-code-fundamentals",
- "type": "tutorial"
}
],
"troubleshooting": [
diff --git a/content/news/2026/week-4.md b/content/news/2026/week-4.md
index 870c250cc..b3651103b 100644
--- a/content/news/2026/week-4.md
+++ b/content/news/2026/week-4.md
@@ -184,7 +184,7 @@ On 2025-12-26, at 07:35 UTC, the SSL certificates for many *.bazel.build domains
**š
Jan 16, 2026** ⢠**š° Bazel Blog**
-[**š Read more**](/2026/01/16/ssl-cert-expiry.html)
+[**š Read more**](https://blog.bazel.build/2026/01/16/ssl-cert-expiry.html)
### š Building an agentic memory system for GitHub Copilot
diff --git a/content/news/2026/week-5.md b/content/news/2026/week-5.md
index 73603d26d..6e61f0449 100644
--- a/content/news/2026/week-5.md
+++ b/content/news/2026/week-5.md
@@ -232,7 +232,7 @@ We're pleased to announce the release of Bazel 9.0! This LTS release is the culm
**š
Jan 20, 2026** ⢠**š° Bazel Blog**
-[**š Read more**](/2026/01/20/bazel-9.html)
+[**š Read more**](https://blog.bazel.build/2026/01/20/bazel-9.html)
---
diff --git a/content/news/2026/week-9.md b/content/news/2026/week-9.md
index 59020be49..d71d2d925 100644
--- a/content/news/2026/week-9.md
+++ b/content/news/2026/week-9.md
@@ -152,7 +152,7 @@ We're thrilled to announce Bazel support in Dependabot Version Updates! š Thr
**š
Feb 20, 2026** ⢠**š° Bazel Blog**
-[**š Read more**](/2026/02/20/dependabot.html)
+[**š Read more**](https://blog.bazel.build/2026/02/20/dependabot.html)
### š How AI is reshaping developer choice (and Octoverse data proves it)
diff --git a/content/posts/deployment-strategies-guide.md b/content/posts/deployment-strategies-guide.md
index 80d6de92f..0ca7e8fbe 100644
--- a/content/posts/deployment-strategies-guide.md
+++ b/content/posts/deployment-strategies-guide.md
@@ -15,7 +15,7 @@ tags:
- DevOps
- Deployment
- Kubernetes
- - CI/CD
+ - CICD
- Blue-Green Deployment
- Canary Deployment
- Rolling Deployment
diff --git a/content/posts/designing-automation-with-failure-in-mind.md b/content/posts/designing-automation-with-failure-in-mind.md
index 98629b781..c1f491c98 100644
--- a/content/posts/designing-automation-with-failure-in-mind.md
+++ b/content/posts/designing-automation-with-failure-in-mind.md
@@ -13,7 +13,7 @@ author:
slug: 'devops-daily-team'
tags:
- DevOps
- - CI/CD
+ - CICD
- Kubernetes
- Terraform
- SRE
diff --git a/content/posts/detect-network-connection-type-android.md b/content/posts/detect-network-connection-type-android.md
index ccdfe7b81..e1d31e5d1 100644
--- a/content/posts/detect-network-connection-type-android.md
+++ b/content/posts/detect-network-connection-type-android.md
@@ -2,8 +2,8 @@
title: 'How to Detect Network Connection Type on Android'
excerpt: "Learn how to detect WiFi, cellular, and other network types in Android apps using ConnectivityManager, NetworkCapabilities, and handle network changes with callbacks."
category:
- name: 'Android'
- slug: 'android'
+ name: 'Networking'
+ slug: 'networking'
date: '2024-11-05'
publishedAt: '2024-11-05T12:00:00Z'
updatedAt: '2024-11-05T12:00:00Z'
diff --git a/content/posts/find-ssh-client-ip-address.md b/content/posts/find-ssh-client-ip-address.md
index 38b462fc0..28c725d98 100644
--- a/content/posts/find-ssh-client-ip-address.md
+++ b/content/posts/find-ssh-client-ip-address.md
@@ -2,8 +2,8 @@
title: 'How to Find the IP Address of an SSH Client'
excerpt: "Learn multiple ways to identify the IP address of clients connected to your SSH server, from environment variables to logs and active connection monitoring."
category:
- name: 'SSH'
- slug: 'ssh'
+ name: 'Networking'
+ slug: 'networking'
date: '2024-12-09'
publishedAt: '2024-12-09T14:00:00Z'
updatedAt: '2024-12-09T14:00:00Z'
diff --git a/content/posts/gitops-deploy-docker-containers-github-actions-argocd.md b/content/posts/gitops-deploy-docker-containers-github-actions-argocd.md
index 348fe2045..f61deb789 100644
--- a/content/posts/gitops-deploy-docker-containers-github-actions-argocd.md
+++ b/content/posts/gitops-deploy-docker-containers-github-actions-argocd.md
@@ -14,7 +14,7 @@ author:
tags:
- Docker
- GitHub Actions
- - CI/CD
+ - CICD
- GitOps
- ArgoCD
- Kubernetes
diff --git a/content/posts/how-to-close-tcp-and-udp-ports-via-windows-command-line.md b/content/posts/how-to-close-tcp-and-udp-ports-via-windows-command-line.md
index 650437ad1..f32394dad 100644
--- a/content/posts/how-to-close-tcp-and-udp-ports-via-windows-command-line.md
+++ b/content/posts/how-to-close-tcp-and-udp-ports-via-windows-command-line.md
@@ -2,8 +2,8 @@
title: 'How to Close TCP and UDP Ports via Windows Command Line'
excerpt: 'Learn how to close open ports on Windows using command-line tools. Find and terminate processes listening on ports, manage Windows Firewall rules, and stop services to free up ports.'
category:
- name: 'Windows'
- slug: 'windows'
+ name: 'Networking'
+ slug: 'networking'
date: '2025-03-28'
publishedAt: '2025-03-28T13:00:00Z'
updatedAt: '2025-03-28T13:00:00Z'
diff --git a/content/posts/introduction-to-argocd.md b/content/posts/introduction-to-argocd.md
index bfffab693..d89e28500 100644
--- a/content/posts/introduction-to-argocd.md
+++ b/content/posts/introduction-to-argocd.md
@@ -16,7 +16,7 @@ tags:
- GitOps
- ArgoCD
- Kubernetes
- - CI/CD
+ - CICD
- Automation
- Deployment
---
diff --git a/content/posts/ssh-could-not-resolve-hostname-error.md b/content/posts/ssh-could-not-resolve-hostname-error.md
index 8b29a8a8b..a031e4587 100644
--- a/content/posts/ssh-could-not-resolve-hostname-error.md
+++ b/content/posts/ssh-could-not-resolve-hostname-error.md
@@ -2,8 +2,8 @@
title: 'How to Fix SSH "Could Not Resolve Hostname" Error'
excerpt: "Troubleshoot and fix the SSH 'nodename nor servname provided, or not known' error with DNS checks, host file configuration, and SSH config debugging."
category:
- name: 'SSH'
- slug: 'ssh'
+ name: 'Networking'
+ slug: 'networking'
date: '2025-01-18'
publishedAt: '2025-01-18T09:30:00Z'
updatedAt: '2025-01-18T09:30:00Z'
diff --git a/content/posts/terraform-save-plan-apply-output-to-file.md b/content/posts/terraform-save-plan-apply-output-to-file.md
index c1b3175ed..ed6b78d6f 100644
--- a/content/posts/terraform-save-plan-apply-output-to-file.md
+++ b/content/posts/terraform-save-plan-apply-output-to-file.md
@@ -14,7 +14,7 @@ author:
tags:
- Terraform
- Infrastructure as Code
- - CI/CD
+ - CICD
- Best Practices
- DevOps
---
diff --git a/content/posts/using-ls-list-directories-sizes.md b/content/posts/using-ls-list-directories-sizes.md
index 74e7dc163..da3d1a4b6 100644
--- a/content/posts/using-ls-list-directories-sizes.md
+++ b/content/posts/using-ls-list-directories-sizes.md
@@ -2,8 +2,8 @@
title: 'Using ls to list directories and their total sizes'
excerpt: 'How to show directory sizes from the shell - practical commands for macOS and Linux, and why `ls` alone is not enough.'
category:
- name: 'Shell'
- slug: 'shell'
+ name: 'Bash'
+ slug: 'bash'
date: '2025-04-22'
publishedAt: '2025-04-22T09:00:00Z'
updatedAt: '2025-04-22T09:00:00Z'
diff --git a/content/posts/which-postgresql-version-am-i-running.md b/content/posts/which-postgresql-version-am-i-running.md
index becf75da6..6d6aa3017 100644
--- a/content/posts/which-postgresql-version-am-i-running.md
+++ b/content/posts/which-postgresql-version-am-i-running.md
@@ -2,8 +2,8 @@
title: 'How to Check Which Version of PostgreSQL You Are Running'
excerpt: "Learn multiple ways to check your PostgreSQL version, including psql commands, SQL queries, and system commands. Find version numbers from the server, client, and package manager."
category:
- name: 'Database'
- slug: 'database'
+ name: 'Linux'
+ slug: 'linux'
date: '2024-12-15'
publishedAt: '2024-12-15T09:00:00Z'
updatedAt: '2024-12-15T09:00:00Z'
diff --git a/content/posts/why-c-preprocessor-interprets-linux-as-one.md b/content/posts/why-c-preprocessor-interprets-linux-as-one.md
index 4b4ff08f9..58bc64e72 100644
--- a/content/posts/why-c-preprocessor-interprets-linux-as-one.md
+++ b/content/posts/why-c-preprocessor-interprets-linux-as-one.md
@@ -2,8 +2,8 @@
title: 'Why Does the C Preprocessor Interpret "linux" as "1"?'
excerpt: "Discover why the word 'linux' is predefined as the constant 1 in the C preprocessor on Linux systems, and how this historical quirk can cause unexpected compilation errors."
category:
- name: 'C'
- slug: 'c'
+ name: 'Linux'
+ slug: 'linux'
date: '2025-05-22'
publishedAt: '2025-05-22T09:00:00Z'
updatedAt: '2025-05-22T09:00:00Z'
diff --git a/content/posts/why-your-ci-pipeline-is-slower.md b/content/posts/why-your-ci-pipeline-is-slower.md
index 633b7a7a9..80d30701f 100644
--- a/content/posts/why-your-ci-pipeline-is-slower.md
+++ b/content/posts/why-your-ci-pipeline-is-slower.md
@@ -1,12 +1,16 @@
---
title: 'Why Your CI/CD Pipeline Is Slower Than It Should Be (and How to Fix It)'
excerpt: 'Small pipeline changes give big wins. Parallelize jobs, cache dependencies, pin images, reuse build artifacts, and run only the tests you need.'
-category: 'ci'
+category:
+ name: 'DevOps'
+ slug: 'devops'
date: '2025-06-10T09:00:00.000Z'
publishedAt: '2025-06-10T09:00:00.000Z'
updatedAt: '2025-06-10T09:00:00.000Z'
readingTime: 4
-author: 'DevOps Daily'
+author:
+ name: 'DevOps Daily Team'
+ slug: 'devops-daily-team'
tags:
- ci
- cicd
diff --git a/package.json b/package.json
index 2337f4b84..635d7e64a 100644
--- a/package.json
+++ b/package.json
@@ -41,7 +41,8 @@
"devops-daily:generate-news:no-ai": "tsx scripts/devops-daily/index.ts --skip-ai",
"og:validate": "tsx scripts/git-hooks/validate-og-data.ts",
"og:validate:staged": "tsx scripts/git-hooks/validate-og-data.ts --staged-only",
- "hooks:install": "sh scripts/git-hooks/install.sh"
+ "hooks:install": "sh scripts/git-hooks/install.sh",
+ "check-links": "node --import tsx scripts/check-broken-links.ts"
},
"dependencies": {
"@dnd-kit/core": "^6.3.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 39cdf2ab9..77e918e36 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -293,10 +293,13 @@ importers:
version: 5.9.3
vitest:
specifier: ^4.0.18
- version: 4.0.18(@types/node@25.2.3)(@vitest/ui@4.0.18)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)
+ version: 4.0.18(@types/node@25.2.3)(@vitest/ui@4.0.18)(jiti@2.6.1)(jsdom@28.1.0(canvas@3.2.1))(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)
packages:
+ '@acemir/cssom@0.9.31':
+ resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==}
+
'@alloc/quick-lru@5.2.0':
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
@@ -307,6 +310,16 @@ packages:
peerDependencies:
ajv: '>=8'
+ '@asamuzakjp/css-color@5.0.1':
+ resolution: {integrity: sha512-2SZFvqMyvboVV1d15lMf7XiI3m7SDqXUuKaTymJYLN6dSGadqp+fVojqJlVoMlbZnlTmu3S0TLwLTJpvBMO1Aw==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ '@asamuzakjp/dom-selector@6.8.1':
+ resolution: {integrity: sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==}
+
+ '@asamuzakjp/nwsapi@2.3.9':
+ resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==}
+
'@babel/code-frame@7.29.0':
resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
engines: {node: '>=6.9.0'}
@@ -802,6 +815,41 @@ packages:
resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
engines: {node: '>=6.9.0'}
+ '@bramus/specificity@2.4.2':
+ resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==}
+ hasBin: true
+
+ '@csstools/color-helpers@6.0.2':
+ resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==}
+ engines: {node: '>=20.19.0'}
+
+ '@csstools/css-calc@3.1.1':
+ resolution: {integrity: sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^4.0.0
+ '@csstools/css-tokenizer': ^4.0.0
+
+ '@csstools/css-color-parser@4.0.2':
+ resolution: {integrity: sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^4.0.0
+ '@csstools/css-tokenizer': ^4.0.0
+
+ '@csstools/css-parser-algorithms@4.0.0':
+ resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@csstools/css-tokenizer': ^4.0.0
+
+ '@csstools/css-syntax-patches-for-csstree@1.0.28':
+ resolution: {integrity: sha512-1NRf1CUBjnr3K7hu8BLxjQrKCxEe8FP/xmPTenAxCRZWVLbmGotkFvG9mfNpjA6k7Bw1bw4BilZq9cu19RA5pg==}
+
+ '@csstools/css-tokenizer@4.0.0':
+ resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==}
+ engines: {node: '>=20.19.0'}
+
'@date-fns/tz@1.4.1':
resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==}
@@ -1036,6 +1084,15 @@ packages:
resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@exodus/bytes@1.14.1':
+ resolution: {integrity: sha512-OhkBFWI6GcRMUroChZiopRiSp2iAMvEBK47NhJooDqz1RERO4QuZIZnjP63TXX8GAiLABkYmX+fuQsdJ1dd2QQ==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+ peerDependencies:
+ '@noble/hashes': ^1.8.0 || ^2.0.0
+ peerDependenciesMeta:
+ '@noble/hashes':
+ optional: true
+
'@floating-ui/core@1.7.4':
resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==}
@@ -1108,89 +1165,105 @@ packages:
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linux-arm@1.2.4':
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
cpu: [arm]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linux-ppc64@1.2.4':
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linux-riscv64@1.2.4':
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linux-s390x@1.2.4':
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linux-x64@1.2.4':
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@img/sharp-linux-arm64@0.34.5':
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@img/sharp-linux-arm@0.34.5':
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm]
os: [linux]
+ libc: [glibc]
'@img/sharp-linux-ppc64@0.34.5':
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@img/sharp-linux-riscv64@0.34.5':
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@img/sharp-linux-s390x@0.34.5':
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@img/sharp-linux-x64@0.34.5':
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@img/sharp-linuxmusl-arm64@0.34.5':
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@img/sharp-linuxmusl-x64@0.34.5':
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@img/sharp-wasm32@0.34.5':
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
@@ -1272,24 +1345,28 @@ packages:
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@next/swc-linux-arm64-musl@16.1.6':
resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@next/swc-linux-x64-gnu@16.1.6':
resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@next/swc-linux-x64-musl@16.1.6':
resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@next/swc-win32-arm64-msvc@16.1.6':
resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==}
@@ -2047,24 +2124,28 @@ packages:
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@resvg/resvg-js-linux-arm64-musl@2.6.2':
resolution: {integrity: sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@resvg/resvg-js-linux-x64-gnu@2.6.2':
resolution: {integrity: sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@resvg/resvg-js-linux-x64-musl@2.6.2':
resolution: {integrity: sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@resvg/resvg-js-win32-arm64-msvc@2.6.2':
resolution: {integrity: sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==}
@@ -2171,66 +2252,79 @@ packages:
resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==}
cpu: [arm]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.57.1':
resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==}
cpu: [arm]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.57.1':
resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.57.1':
resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-loong64-gnu@4.57.1':
resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==}
cpu: [loong64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-loong64-musl@4.57.1':
resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==}
cpu: [loong64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-ppc64-gnu@4.57.1':
resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-ppc64-musl@4.57.1':
resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==}
cpu: [ppc64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-riscv64-gnu@4.57.1':
resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.57.1':
resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==}
cpu: [riscv64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.57.1':
resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.57.1':
resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.57.1':
resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-openbsd-x64@4.57.1':
resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==}
@@ -2315,24 +2409,28 @@ packages:
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@tailwindcss/oxide-linux-arm64-musl@4.1.18':
resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@tailwindcss/oxide-linux-x64-gnu@4.1.18':
resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@tailwindcss/oxide-linux-x64-musl@4.1.18':
resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@tailwindcss/oxide-wasm32-wasi@4.1.18':
resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==}
@@ -2588,41 +2686,49 @@ packages:
resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@unrs/resolver-binding-linux-arm64-musl@1.11.1':
resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
cpu: [riscv64]
os: [linux]
+ libc: [musl]
'@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@unrs/resolver-binding-linux-x64-gnu@1.11.1':
resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@unrs/resolver-binding-linux-x64-musl@1.11.1':
resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@unrs/resolver-binding-wasm32-wasi@1.11.1':
resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
@@ -2747,6 +2853,10 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
+ agent-base@7.1.4:
+ resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
+ engines: {node: '>= 14'}
+
ajv-formats@2.1.1:
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
peerDependencies:
@@ -2891,6 +3001,9 @@ packages:
resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==}
hasBin: true
+ bidi-js@1.0.3:
+ resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
+
bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
@@ -3034,6 +3147,10 @@ packages:
resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==}
engines: {node: '>=8.0.0'}
+ css-tree@3.1.0:
+ resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+
css-what@6.2.2:
resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==}
engines: {node: '>= 6'}
@@ -3043,6 +3160,10 @@ packages:
engines: {node: '>=4'}
hasBin: true
+ cssstyle@6.1.0:
+ resolution: {integrity: sha512-Ml4fP2UT2K3CUBQnVlbdV/8aFDdlY69E+YnwJM+3VUWl08S3J8c8aRuJqCkD9Py8DHZ7zNNvsfKl8psocHZEFg==}
+ engines: {node: '>=20'}
+
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
@@ -3093,6 +3214,10 @@ packages:
damerau-levenshtein@1.0.8:
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
+ data-urls@7.0.0:
+ resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
data-view-buffer@1.0.2:
resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
engines: {node: '>= 0.4'}
@@ -3131,6 +3256,9 @@ packages:
decimal.js-light@2.5.1:
resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
+ decimal.js@10.6.0:
+ resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
+
decompress-response@6.0.0:
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
engines: {node: '>=10'}
@@ -3717,9 +3845,21 @@ packages:
resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==}
engines: {node: '>=12.0.0'}
+ html-encoding-sniffer@6.0.0:
+ resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
htmlparser2@10.1.0:
resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==}
+ http-proxy-agent@7.0.2:
+ resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
+ engines: {node: '>= 14'}
+
+ https-proxy-agent@7.0.6:
+ resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
+ engines: {node: '>= 14'}
+
hyphenate-style-name@1.1.0:
resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==}
@@ -3860,6 +4000,9 @@ packages:
resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==}
engines: {node: '>=0.10.0'}
+ is-potential-custom-element-name@1.0.1:
+ resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+
is-regex@1.2.1:
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
engines: {node: '>= 0.4'}
@@ -3941,6 +4084,15 @@ packages:
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
hasBin: true
+ jsdom@28.1.0:
+ resolution: {integrity: sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+ peerDependencies:
+ canvas: ^3.0.0
+ peerDependenciesMeta:
+ canvas:
+ optional: true
+
jsesc@3.1.0:
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
engines: {node: '>=6'}
@@ -4041,24 +4193,28 @@ packages:
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
lightningcss-linux-arm64-musl@1.30.2:
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
+ libc: [musl]
lightningcss-linux-x64-gnu@1.30.2:
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
+ libc: [glibc]
lightningcss-linux-x64-musl@1.30.2:
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
+ libc: [musl]
lightningcss-win32-arm64-msvc@1.30.2:
resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
@@ -4109,6 +4265,10 @@ packages:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
+ lru-cache@11.2.6:
+ resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==}
+ engines: {node: 20 || >=22}
+
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
@@ -4145,6 +4305,9 @@ packages:
mdn-data@2.0.14:
resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==}
+ mdn-data@2.12.2:
+ resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==}
+
merge-stream@2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
@@ -4349,6 +4512,9 @@ packages:
parse5@7.3.0:
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
+ parse5@8.0.0:
+ resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==}
+
path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@@ -4653,6 +4819,10 @@ packages:
resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==}
engines: {node: '>=11.0.0'}
+ saxes@6.0.0:
+ resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+ engines: {node: '>=v12.22.7'}
+
scheduler@0.27.0:
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
@@ -4888,6 +5058,9 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
+ symbol-tree@3.2.4:
+ resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+
synckit@0.11.12:
resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==}
engines: {node: ^14.18.0 || >=16.0.0}
@@ -4968,6 +5141,13 @@ packages:
resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==}
engines: {node: '>=14.0.0'}
+ tldts-core@7.0.23:
+ resolution: {integrity: sha512-0g9vrtDQLrNIiCj22HSe9d4mLVG3g5ph5DZ8zCKBr4OtrspmNB6ss7hVyzArAeE88ceZocIEGkyW1Ime7fxPtQ==}
+
+ tldts@7.0.23:
+ resolution: {integrity: sha512-ASdhgQIBSay0R/eXggAkQ53G4nTJqTXqC2kbaBbdDwM7SkjyZyO0OaaN1/FH7U/yCeqOHDwFO5j8+Os/IS1dXw==}
+ hasBin: true
+
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@@ -4979,9 +5159,17 @@ packages:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'}
+ tough-cookie@6.0.0:
+ resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==}
+ engines: {node: '>=16'}
+
tr46@1.0.1:
resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
+ tr46@6.0.0:
+ resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==}
+ engines: {node: '>=20'}
+
ts-api-utils@2.4.0:
resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==}
engines: {node: '>=18.12'}
@@ -5209,6 +5397,10 @@ packages:
jsdom:
optional: true
+ w3c-xmlserializer@5.0.0:
+ resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
+ engines: {node: '>=18'}
+
watchpack@2.5.1:
resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==}
engines: {node: '>=10.13.0'}
@@ -5216,6 +5408,10 @@ packages:
webidl-conversions@4.0.2:
resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
+ webidl-conversions@8.0.1:
+ resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==}
+ engines: {node: '>=20'}
+
webpack-sources@1.4.3:
resolution: {integrity: sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==}
@@ -5242,6 +5438,14 @@ packages:
resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
engines: {node: '>=18'}
+ whatwg-mimetype@5.0.0:
+ resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==}
+ engines: {node: '>=20'}
+
+ whatwg-url@16.0.1:
+ resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
whatwg-url@7.1.0:
resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==}
@@ -5337,6 +5541,10 @@ packages:
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+ xml-name-validator@5.0.0:
+ resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
+ engines: {node: '>=18'}
+
xml2js@0.5.0:
resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==}
engines: {node: '>=4.0.0'}
@@ -5345,6 +5553,9 @@ packages:
resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==}
engines: {node: '>=4.0'}
+ xmlchars@2.2.0:
+ resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+
yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
@@ -5363,6 +5574,9 @@ packages:
snapshots:
+ '@acemir/cssom@0.9.31':
+ optional: true
+
'@alloc/quick-lru@5.2.0': {}
'@apideck/better-ajv-errors@0.3.6(ajv@8.17.1)':
@@ -5372,6 +5586,27 @@ snapshots:
jsonpointer: 5.0.1
leven: 3.1.0
+ '@asamuzakjp/css-color@5.0.1':
+ dependencies:
+ '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-color-parser': 4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-tokenizer': 4.0.0
+ lru-cache: 11.2.6
+ optional: true
+
+ '@asamuzakjp/dom-selector@6.8.1':
+ dependencies:
+ '@asamuzakjp/nwsapi': 2.3.9
+ bidi-js: 1.0.3
+ css-tree: 3.1.0
+ is-potential-custom-element-name: 1.0.1
+ lru-cache: 11.2.6
+ optional: true
+
+ '@asamuzakjp/nwsapi@2.3.9':
+ optional: true
+
'@babel/code-frame@7.29.0':
dependencies:
'@babel/helper-validator-identifier': 7.28.5
@@ -6026,6 +6261,39 @@ snapshots:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
+ '@bramus/specificity@2.4.2':
+ dependencies:
+ css-tree: 3.1.0
+ optional: true
+
+ '@csstools/color-helpers@6.0.2':
+ optional: true
+
+ '@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)':
+ dependencies:
+ '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-tokenizer': 4.0.0
+ optional: true
+
+ '@csstools/css-color-parser@4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)':
+ dependencies:
+ '@csstools/color-helpers': 6.0.2
+ '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-tokenizer': 4.0.0
+ optional: true
+
+ '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)':
+ dependencies:
+ '@csstools/css-tokenizer': 4.0.0
+ optional: true
+
+ '@csstools/css-syntax-patches-for-csstree@1.0.28':
+ optional: true
+
+ '@csstools/css-tokenizer@4.0.0':
+ optional: true
+
'@date-fns/tz@1.4.1': {}
'@dnd-kit/accessibility@3.1.1(react@19.2.4)':
@@ -6208,6 +6476,9 @@ snapshots:
'@eslint/core': 0.17.0
levn: 0.4.1
+ '@exodus/bytes@1.14.1':
+ optional: true
+
'@floating-ui/core@1.7.4':
dependencies:
'@floating-ui/utils': 0.2.10
@@ -7764,7 +8035,7 @@ snapshots:
sirv: 3.0.2
tinyglobby: 0.2.15
tinyrainbow: 3.0.3
- vitest: 4.0.18(@types/node@25.2.3)(@vitest/ui@4.0.18)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)
+ vitest: 4.0.18(@types/node@25.2.3)(@vitest/ui@4.0.18)(jiti@2.6.1)(jsdom@28.1.0(canvas@3.2.1))(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)
'@vitest/utils@4.0.18':
dependencies:
@@ -7861,6 +8132,9 @@ snapshots:
acorn@8.16.0: {}
+ agent-base@7.1.4:
+ optional: true
+
ajv-formats@2.1.1(ajv@8.18.0):
optionalDependencies:
ajv: 8.18.0
@@ -8043,6 +8317,11 @@ snapshots:
baseline-browser-mapping@2.9.19: {}
+ bidi-js@1.0.3:
+ dependencies:
+ require-from-string: 2.0.2
+ optional: true
+
bl@4.1.0:
dependencies:
buffer: 5.7.1
@@ -8216,10 +8495,24 @@ snapshots:
mdn-data: 2.0.14
source-map: 0.6.1
+ css-tree@3.1.0:
+ dependencies:
+ mdn-data: 2.12.2
+ source-map-js: 1.2.1
+ optional: true
+
css-what@6.2.2: {}
cssesc@3.0.0: {}
+ cssstyle@6.1.0:
+ dependencies:
+ '@asamuzakjp/css-color': 5.0.1
+ '@csstools/css-syntax-patches-for-csstree': 1.0.28
+ css-tree: 3.1.0
+ lru-cache: 11.2.6
+ optional: true
+
csstype@3.2.3: {}
d3-array@3.2.4:
@@ -8262,6 +8555,14 @@ snapshots:
damerau-levenshtein@1.0.8: {}
+ data-urls@7.0.0:
+ dependencies:
+ whatwg-mimetype: 5.0.0
+ whatwg-url: 16.0.1
+ transitivePeerDependencies:
+ - '@noble/hashes'
+ optional: true
+
data-view-buffer@1.0.2:
dependencies:
call-bound: 1.0.4
@@ -8294,6 +8595,9 @@ snapshots:
decimal.js-light@2.5.1: {}
+ decimal.js@10.6.0:
+ optional: true
+
decompress-response@6.0.0:
dependencies:
mimic-response: 3.1.0
@@ -9022,6 +9326,13 @@ snapshots:
highlight.js@11.11.1: {}
+ html-encoding-sniffer@6.0.0:
+ dependencies:
+ '@exodus/bytes': 1.14.1
+ transitivePeerDependencies:
+ - '@noble/hashes'
+ optional: true
+
htmlparser2@10.1.0:
dependencies:
domelementtype: 2.3.0
@@ -9029,6 +9340,22 @@ snapshots:
domutils: 3.2.2
entities: 7.0.1
+ http-proxy-agent@7.0.2:
+ dependencies:
+ agent-base: 7.1.4
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+ optional: true
+
+ https-proxy-agent@7.0.6:
+ dependencies:
+ agent-base: 7.1.4
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+ optional: true
+
hyphenate-style-name@1.1.0: {}
iconv-lite@0.6.3:
@@ -9159,6 +9486,9 @@ snapshots:
is-obj@1.0.1: {}
+ is-potential-custom-element-name@1.0.1:
+ optional: true
+
is-regex@1.2.1:
dependencies:
call-bound: 1.0.4
@@ -9242,6 +9572,36 @@ snapshots:
dependencies:
argparse: 2.0.1
+ jsdom@28.1.0(canvas@3.2.1):
+ dependencies:
+ '@acemir/cssom': 0.9.31
+ '@asamuzakjp/dom-selector': 6.8.1
+ '@bramus/specificity': 2.4.2
+ '@exodus/bytes': 1.14.1
+ cssstyle: 6.1.0
+ data-urls: 7.0.0
+ decimal.js: 10.6.0
+ html-encoding-sniffer: 6.0.0
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.6
+ is-potential-custom-element-name: 1.0.1
+ parse5: 8.0.0
+ saxes: 6.0.0
+ symbol-tree: 3.2.4
+ tough-cookie: 6.0.0
+ undici: 7.21.0
+ w3c-xmlserializer: 5.0.0
+ webidl-conversions: 8.0.1
+ whatwg-mimetype: 5.0.0
+ whatwg-url: 16.0.1
+ xml-name-validator: 5.0.0
+ optionalDependencies:
+ canvas: 3.2.1
+ transitivePeerDependencies:
+ - '@noble/hashes'
+ - supports-color
+ optional: true
+
jsesc@3.1.0: {}
json-buffer@3.0.1: {}
@@ -9379,6 +9739,9 @@ snapshots:
dependencies:
js-tokens: 4.0.0
+ lru-cache@11.2.6:
+ optional: true
+
lru-cache@5.1.1:
dependencies:
yallist: 3.1.1
@@ -9410,6 +9773,9 @@ snapshots:
mdn-data@2.0.14: {}
+ mdn-data@2.12.2:
+ optional: true
+
merge-stream@2.0.0: {}
merge2@1.4.1: {}
@@ -9617,6 +9983,11 @@ snapshots:
dependencies:
entities: 6.0.1
+ parse5@8.0.0:
+ dependencies:
+ entities: 6.0.1
+ optional: true
+
path-exists@4.0.0: {}
path-is-absolute@1.0.1: {}
@@ -9969,6 +10340,11 @@ snapshots:
sax@1.4.4: {}
+ saxes@6.0.0:
+ dependencies:
+ xmlchars: 2.2.0
+ optional: true
+
scheduler@0.27.0: {}
schema-utils@4.3.3:
@@ -10253,6 +10629,9 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
+ symbol-tree@3.2.4:
+ optional: true
+
synckit@0.11.12:
dependencies:
'@pkgr/core': 0.2.9
@@ -10324,6 +10703,14 @@ snapshots:
tinyrainbow@3.0.3: {}
+ tldts-core@7.0.23:
+ optional: true
+
+ tldts@7.0.23:
+ dependencies:
+ tldts-core: 7.0.23
+ optional: true
+
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
@@ -10332,10 +10719,20 @@ snapshots:
totalist@3.0.1: {}
+ tough-cookie@6.0.0:
+ dependencies:
+ tldts: 7.0.23
+ optional: true
+
tr46@1.0.1:
dependencies:
punycode: 2.3.1
+ tr46@6.0.0:
+ dependencies:
+ punycode: 2.3.1
+ optional: true
+
ts-api-utils@2.4.0(typescript@5.9.3):
dependencies:
typescript: 5.9.3
@@ -10545,7 +10942,7 @@ snapshots:
terser: 5.46.0
tsx: 4.21.0
- vitest@4.0.18(@types/node@25.2.3)(@vitest/ui@4.0.18)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0):
+ vitest@4.0.18(@types/node@25.2.3)(@vitest/ui@4.0.18)(jiti@2.6.1)(jsdom@28.1.0(canvas@3.2.1))(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0):
dependencies:
'@vitest/expect': 4.0.18
'@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0))
@@ -10570,6 +10967,7 @@ snapshots:
optionalDependencies:
'@types/node': 25.2.3
'@vitest/ui': 4.0.18(vitest@4.0.18)
+ jsdom: 28.1.0(canvas@3.2.1)
transitivePeerDependencies:
- jiti
- less
@@ -10583,6 +10981,11 @@ snapshots:
- tsx
- yaml
+ w3c-xmlserializer@5.0.0:
+ dependencies:
+ xml-name-validator: 5.0.0
+ optional: true
+
watchpack@2.5.1:
dependencies:
glob-to-regexp: 0.4.1
@@ -10590,6 +10993,9 @@ snapshots:
webidl-conversions@4.0.2: {}
+ webidl-conversions@8.0.1:
+ optional: true
+
webpack-sources@1.4.3:
dependencies:
source-list-map: 2.0.1
@@ -10634,6 +11040,18 @@ snapshots:
whatwg-mimetype@4.0.0: {}
+ whatwg-mimetype@5.0.0:
+ optional: true
+
+ whatwg-url@16.0.1:
+ dependencies:
+ '@exodus/bytes': 1.14.1
+ tr46: 6.0.0
+ webidl-conversions: 8.0.1
+ transitivePeerDependencies:
+ - '@noble/hashes'
+ optional: true
+
whatwg-url@7.1.0:
dependencies:
lodash.sortby: 4.7.0
@@ -10862,6 +11280,9 @@ snapshots:
wrappy@1.0.2: {}
+ xml-name-validator@5.0.0:
+ optional: true
+
xml2js@0.5.0:
dependencies:
sax: 1.4.4
@@ -10869,6 +11290,9 @@ snapshots:
xmlbuilder@11.0.1: {}
+ xmlchars@2.2.0:
+ optional: true
+
yallist@3.1.1: {}
yocto-queue@0.1.0: {}
diff --git a/scripts/check-broken-links.ts b/scripts/check-broken-links.ts
new file mode 100644
index 000000000..9d6e44b1b
--- /dev/null
+++ b/scripts/check-broken-links.ts
@@ -0,0 +1,128 @@
+#!/usr/bin/env node
+
+import { readFileSync, readdirSync, statSync } from 'fs'
+import { join } from 'path'
+import * as cheerio from 'cheerio'
+
+/**
+ * Recursively get all HTML files from a directory
+ */
+function getHtmlFiles(dir: string): string[] {
+ const files: string[] = []
+ const items = readdirSync(dir)
+
+ for (const item of items) {
+ const fullPath = join(dir, item)
+ const stat = statSync(fullPath)
+
+ if (stat.isDirectory()) {
+ files.push(...getHtmlFiles(fullPath))
+ } else if (item.endsWith('.html')) {
+ files.push(fullPath)
+ }
+ }
+
+ return files
+}
+
+/**
+ * Extract all internal links from an HTML file
+ */
+function extractInternalLinks(htmlPath: string): string[] {
+ const html = readFileSync(htmlPath, 'utf-8')
+ const $ = cheerio.load(html)
+ const links: string[] = []
+
+ $('a[href]').each((_, element) => {
+ const href = $(element).attr('href')
+ if (href && href.startsWith('/') && !href.startsWith('//')) {
+ // Remove hash fragments and query params
+ const url = href.split('#')[0].split('?')[0]
+ if (url.length > 0) {
+ links.push(url)
+ }
+ }
+ })
+
+ return links
+}
+
+/**
+ * Check if a URL path exists in the static build output
+ */
+function urlExists(url: string, outDir: string): boolean {
+ // Remove leading slash
+ const path = url.startsWith('/') ? url.slice(1) : url
+
+ // Try multiple possible file locations
+ const possiblePaths = [
+ join(outDir, path), // Direct path
+ join(outDir, path, 'index.html'), // Directory with index.html
+ join(outDir, `${path}.html`), // .html extension
+ ]
+
+ for (const filePath of possiblePaths) {
+ try {
+ const stat = statSync(filePath)
+ if (stat.isFile() || stat.isDirectory()) {
+ return true
+ }
+ } catch {
+ // File doesn't exist, continue
+ }
+ }
+
+ return false
+}
+
+/**
+ * Main function to check for broken links
+ */
+function main() {
+ const outDir = join(process.cwd(), 'out')
+ console.log('\nš Checking for broken internal links...\n')
+
+ const htmlFiles = getHtmlFiles(outDir)
+ console.log(`š Found ${htmlFiles.length} HTML files to scan\n`)
+
+ const brokenLinks = new Map()
+
+ for (const htmlFile of htmlFiles) {
+ const links = extractInternalLinks(htmlFile)
+ const uniqueLinks = [...new Set(links)]
+
+ for (const link of uniqueLinks) {
+ if (!urlExists(link, outDir)) {
+ const relativePath = htmlFile.replace(outDir + '/', '')
+ if (!brokenLinks.has(link)) {
+ brokenLinks.set(link, [])
+ }
+ brokenLinks.get(link)!.push(relativePath)
+ }
+ }
+ }
+
+ if (brokenLinks.size === 0) {
+ console.log('ā
No broken internal links found!\n')
+ process.exit(0)
+ }
+
+ console.error(`ā Found ${brokenLinks.size} broken internal link(s):\n`)
+
+ for (const [link, sources] of brokenLinks.entries()) {
+ console.error(` ${link}`)
+ console.error(` Found in ${sources.length} file(s):${
+ sources.length <= 3
+ ? ''
+ : ` (showing first 3 of ${sources.length})`
+ }`)
+ for (const source of sources.slice(0, 3)) {
+ console.error(` - ${source}`)
+ }
+ console.error('')
+ }
+
+ process.exit(1)
+}
+
+main()