diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 9a9f82749..180a2fc44 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -50,7 +50,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6.3.0 with: - node-version: '22.x' + node-version: '24.x' cache: 'npm' - name: Install dependencies diff --git a/.github/workflows/migrations-preview.yml b/.github/workflows/migrations-preview.yml index 35cbedde5..43168f5b9 100644 --- a/.github/workflows/migrations-preview.yml +++ b/.github/workflows/migrations-preview.yml @@ -99,7 +99,7 @@ jobs: if: steps.gate.outputs.should_migrate == 'true' uses: actions/setup-node@v6.3.0 with: - node-version: '22.x' + node-version: '24.x' cache: 'npm' - name: Install dependencies diff --git a/.github/workflows/migrations-production.yml b/.github/workflows/migrations-production.yml index c9134236c..875487873 100644 --- a/.github/workflows/migrations-production.yml +++ b/.github/workflows/migrations-production.yml @@ -78,7 +78,7 @@ jobs: if: steps.gate.outputs.should_migrate == 'true' uses: actions/setup-node@v6.3.0 with: - node-version: '22.x' + node-version: '24.x' cache: 'npm' - name: Install dependencies diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 5ccc0d185..1089eeb22 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -52,7 +52,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6.3.0 with: - node-version: '22.x' + node-version: '24.x' cache: 'npm' - name: Install dependencies diff --git a/.github/workflows/search.yml b/.github/workflows/search.yml index 524d26c59..17d8a667d 100644 --- a/.github/workflows/search.yml +++ b/.github/workflows/search.yml @@ -50,7 +50,7 @@ jobs: if: steps.scope.outputs.should_index == 'true' uses: actions/setup-node@v6.3.0 with: - node-version: '22.x' + node-version: '24.x' - name: Validate Upstash credentials if: steps.scope.outputs.should_index == 'true' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index af154f500..5857601ed 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -53,7 +53,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6.3.0 with: - node-version: '22.x' + node-version: '24.x' cache: 'npm' - name: Install dependencies diff --git a/.nvmrc b/.nvmrc index 2daee9e88..e6dd3b132 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1,2 +1,2 @@ # allow running `nvm use` to automatically use a supported Node version -22.9.0 +24 diff --git a/_TODO.md b/_TODO.md index be7419cce..a7e3851ec 100644 --- a/_TODO.md +++ b/_TODO.md @@ -280,9 +280,32 @@ https://mermaid.js.org/config/directives.html src/content/articles/internal-developer-portal-platform-self-service-actions/pdf.mdx -## Prompt for Mermaid Images - ├── └── -jpg + + + + + + + + +[&>span]: +[&>*:first-child]: + + + + diff --git a/astro.config.ts b/astro.config.ts index 415461dca..d32bb9fd1 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -10,7 +10,7 @@ import vtbot from 'astro-vtbot' import { defineConfig } from 'astro/config' import type { AstroUserConfig } from 'astro' import { fileURLToPath } from 'node:url' -import type { PluginOption } from 'vite' +import { createLogger, type LogOptions, type PluginOption } from 'vite' /** * You cannot use path aliases (`@lib`, `@components`, etc.) in files that are * imported by astro.config.ts, because the path alias resolution happens @@ -40,6 +40,27 @@ import { createSerializeFunction, pagesJsonWriter } from './src/integrations/sit // Ensure Vite's HMR websocket connects through the same exposed dev server port used by Astro. const devServerPort = Number(process.env['DEV_SERVER_PORT'] ?? 4321) +const viteLogger = createLogger(undefined, { allowClearScreen: false }) + +const shouldSuppressViteWarning = (message: string): boolean => { + return ( + /resolve\.alias.*customResolver option/i.test(message) || + ( + /externalized for browser compatibility/i.test(message) && + /node_modules\/(?:@astrojs\/vercel|@astrojs\/internal-helpers|@vercel\/|esbuild\/lib\/main\.js|@mapbox\/node-pre-gyp|node-gyp-build|detect-libc|graceful-fs|bindings|resolve-from|file-uri-to-path|nopt)\//i.test(message) + ) + ) +} + +const shouldSuppressRollupWarning = (warning: { + code?: string | undefined + plugin?: string | undefined +}): boolean => { + return ( + warning.code === 'SOURCEMAP_BROKEN' && + warning.plugin === '@tailwindcss/vite:generate:build' + ) +} const standardIntegrations = [ AstroPWA(pwaConfig), @@ -99,8 +120,8 @@ export default defineConfig({ * unit testing integrations. */ integrations: standardIntegrations, - /** API routes are marked in their files for SSR */ - output: 'static', + /** Astro actions require server output in Astro 6. Individual routes can still opt into prerendering. */ + output: 'server', prefetch: true, image: { remotePatterns: [ @@ -115,6 +136,13 @@ export default defineConfig({ site: getSiteUrl(), trailingSlash: 'never', vite: { + customLogger: { + ...viteLogger, + warn: (message: string, options?: LogOptions) => { + if (shouldSuppressViteWarning(message)) return + viteLogger.warn(message, options) + }, + }, server: { hmr: { clientPort: devServerPort, @@ -135,6 +163,12 @@ export default defineConfig({ build: { /** Source map generation must be turned on for Sentry. */ sourcemap: true, + rollupOptions: { + onwarn(warning, warn) { + if (shouldSuppressRollupWarning(warning)) return + warn(warning) + }, + }, }, define: { /** @@ -156,10 +190,4 @@ export default defineConfig({ }, }, }, - experimental: { - /** - * Generate your styles and scripts in the order they are defined, instead of reversing them - */ - preserveScriptOrder: true, - }, }) diff --git a/package-lock.json b/package-lock.json index 0076d61ea..ec4063a45 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,29 +13,29 @@ ], "dependencies": { "@adobe/remark-gridtables": "^3.0.18", - "@astrojs/check": "0.9.6", - "@astrojs/db": "^0.19.0", - "@astrojs/mdx": "4.3.13", - "@astrojs/preact": "4.1.3", - "@astrojs/rss": "4.0.15", - "@astrojs/sitemap": "^3.7.0", - "@astrojs/vercel": "^9.0.4", + "@astrojs/check": "0.9.7", + "@astrojs/db": "^0.20.0", + "@astrojs/mdx": "5.0.0", + "@astrojs/preact": "5.0.0", + "@astrojs/rss": "4.0.17", + "@astrojs/sitemap": "^3.7.1", + "@astrojs/vercel": "^10.0.0", "@axe-core/playwright": "^4.11.1", "@eslint-community/eslint-plugin-eslint-comments": "^4.7.1", "@eslint/js": "10.0.1", "@github/relative-time-element": "^5.0.0", "@glidejs/glide": "^3.7.1", "@googlemaps/extended-component-library": "^0.6.14", - "@happy-dom/global-registrator": "^20.8.3", + "@happy-dom/global-registrator": "^20.8.4", "@lighthousejs/types": "^0.0.3", "@nanostores/lit": "^0.2.3", "@nanostores/persistent": "^1.3.3", "@playwright/browser-chromium": "^1.58.2", "@playwright/test": "1.58.2", - "@semantic-ui/astro-lit": "^5.1.1", - "@sentry/astro": "^10.42.0", - "@sentry/browser": "^10.42.0", - "@shikijs/transformers": "^4.0.1", + "@semantic-ui/astro-lit": "^5.1.2", + "@sentry/astro": "^10.43.0", + "@sentry/browser": "^10.43.0", + "@shikijs/transformers": "^4.0.2", "@tailwindcss/forms": "0.5.11", "@tailwindcss/typography": "0.5.19", "@tailwindcss/vite": "^4.2.1", @@ -52,14 +52,14 @@ "@types/hast": "^3.0.4", "@types/js-cookie": "^3.0.6", "@types/jsdom": "^28.0.0", - "@types/node": "^25.3.3", + "@types/node": "^25.5.0", "@types/nodemailer": "^7.0.11", "@types/pubsub-js": "^1.8.6", "@types/react": "^19.2.14", - "@types/sanitize-html": "^2.16.0", + "@types/sanitize-html": "^2.16.1", "@types/to-ico": "1.1.3", - "@typescript-eslint/eslint-plugin": "8.56.1", - "@typescript-eslint/parser": "8.56.1", + "@typescript-eslint/eslint-plugin": "8.57.0", + "@typescript-eslint/parser": "8.57.0", "@ungap/structured-clone": "^1.3.0", "@uppy/audio": "^3.1.0", "@uppy/box": "^4.1.0", @@ -70,16 +70,16 @@ "@uppy/onedrive": "^5.1.0", "@uppy/webcam": "^5.1.0", "@upstash/search": "^0.1.7", - "@vercel/analytics": "^1.6.1", + "@vercel/analytics": "^2.0.1", "@vite-pwa/astro": "^1.2.0", - "@vitest/coverage-v8": "^4.0.18", + "@vitest/coverage-v8": "^4.1.0", "@webcomponents/template-shadowroot": "^0.2.1", "alex": "^11.0.1", - "astro": "5.18.0", + "astro": "6.0.4", "astro-link-validator": "github:rodgtr1/astro-link-validator", "astro-og-canvas": "^0.10.1", - "astro-vtbot": "^2.1.11", - "baseline-browser-mapping": "^2.10.0", + "astro-vtbot": "^2.1.12", + "baseline-browser-mapping": "^2.10.7", "canvas-confetti": "^1.9.4", "confusing-browser-globals": "1.0.11", "cross-env": "^10.1.0", @@ -90,39 +90,39 @@ "email-validator": "^2.0.4", "embla-carousel": "^8.6.0", "embla-carousel-autoplay": "^8.6.0", - "eslint": "10.0.2", + "eslint": "10.0.3", "eslint-import-resolver-typescript": "^4.4.4", "eslint-plugin-astro": "1.6.0", "eslint-plugin-import": "2.32.0", - "eslint-plugin-jsdoc": "62.7.1", + "eslint-plugin-jsdoc": "62.8.0", "eslint-plugin-jsx-a11y": "6.10.2", "eslint-plugin-security": "4.0.0", "eslint-plugin-yml": "3.3.1", "focus-trap": "8.0.0", "gsap": "^3.14.2", - "happy-dom": "^20.8.3", + "happy-dom": "^20.8.4", "hast-util-heading-rank": "^3.0.0", "hast-util-is-element": "^3.0.0", "html-element-attributes": "^3.5.0", "husky": "^9.1.7", "install": "^0.13.0", "is-whitespace-character": "^2.0.1", - "isomorphic-git": "^1.37.2", + "isomorphic-git": "^1.37.4", "js-cookie": "^3.0.5", "jsdom": "^28.1.0", - "libphonenumber-js": "1.12.38", + "libphonenumber-js": "1.12.40", "lighthouse": "^13.0.3", "lit": "^3.3.2", "markdownlint-cli2": "^0.21.0", "md-attr-parser": "^1.3.0", - "mermaid": "^11.12.3", + "mermaid": "^11.13.0", "nanostores": "^1.1.1", - "nodemailer": "^8.0.1", - "npm": "^11.11.0", + "nodemailer": "^8.0.2", + "npm": "^11.11.1", "playwright-lighthouse": "^4.0.0", "postcss": "8.5.8", "postcss-html": "1.8.1", - "preact": "^10.28.4", + "preact": "^10.29.0", "prettier": "3.8.1", "prettier-plugin-astro": "0.14.1", "pubsub-js": "^1.9.5", @@ -156,29 +156,29 @@ "sanitize-html": "^2.17.1", "schema-dts": "^1.1.5", "sharp": "^0.34.5", - "shiki": "^4.0.1", + "shiki": "^4.0.2", "space-separated-tokens": "^2.0.2", "stylelint": "^17.4.0", "stylelint-config-standard": "^40.0.0", "stylelint-declaration-block-no-ignored-properties": "3.0.0", - "stylelint-order": "7.0.1", + "stylelint-order": "8.0.0", "tailwindcss": "^4.2.1", "temp-dir": "3.0.0", - "timezones-ical-library": "^2.1.2", + "timezones-ical-library": "^2.1.3", "title-case": "4.3.2", "to-ico": "1.1.5", "tslib": "2.8.1", "typescript": "5.9.3", - "typescript-eslint": "8.56.1", + "typescript-eslint": "8.57.0", "unified": "^11.0.5", "unist": "^0.0.1", "unist-util-inspect": "^8.1.0", "unist-util-is": "^6.0.1", "unist-util-visit": "^5.1.0", "uuid": "^13.0.0", - "vercel": "^50.28.0", - "vite": "^7.3.1", - "vitest": "4.0.18", + "vercel": "^50.32.5", + "vite": "^8.0.0", + "vitest": "4.1.0", "vitest-axe": "0.1.0", "workbox-build": "7.4.0", "zod": "4.3.6" @@ -295,13 +295,13 @@ "license": "MIT" }, "node_modules/@astrojs/check": { - "version": "0.9.6", - "resolved": "https://registry.npmjs.org/@astrojs/check/-/check-0.9.6.tgz", - "integrity": "sha512-jlaEu5SxvSgmfGIFfNgcn5/f+29H61NJzEMfAZ82Xopr4XBchXB1GVlcJsE+elUlsYSbXlptZLX+JMG3b/wZEA==", + "version": "0.9.7", + "resolved": "https://registry.npmjs.org/@astrojs/check/-/check-0.9.7.tgz", + "integrity": "sha512-dA7U5/OFg8/xaMUb2vUOOJuuJXnMpHy6F0BM8ZhL7WT5OkTBwJ0GoW38n4fC4CXt+lT9mLWL0y8Pa74tFByBpQ==", "license": "MIT", "dependencies": { "@astrojs/language-server": "^2.16.1", - "chokidar": "^4.0.1", + "chokidar": "^4.0.3", "kleur": "^4.1.5", "yargs": "^17.7.2" }, @@ -319,19 +319,19 @@ "license": "MIT" }, "node_modules/@astrojs/db": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/@astrojs/db/-/db-0.19.0.tgz", - "integrity": "sha512-YrVsqxwODr6Bid4nRgzGsF9K8K8xSoFd7j8bAU+4CxN3tSBx/1kmTE3BClwfVH2xO74wFVsyr7ucBzw/yEsEBw==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@astrojs/db/-/db-0.20.0.tgz", + "integrity": "sha512-NnVkcdPg6E4G4MyOT6qJKChRjKSB5lQWEkw/0PYP21Oxqd5Tk4/kbd/CtO6QziSkalMyiKd808yHHck2Lt0lkw==", "license": "MIT", "dependencies": { + "@clack/prompts": "^1.0.1", "@libsql/client": "^0.17.0", "deep-diff": "^1.0.2", "drizzle-orm": "^0.42.0", "nanoid": "^5.1.6", "piccolore": "^0.1.3", - "prompts": "^2.4.2", - "yargs-parser": "^21.1.1", - "zod": "^3.25.76" + "yargs-parser": "^22.0.0", + "zod": "^4.3.6" } }, "node_modules/@astrojs/db/node_modules/nanoid": { @@ -352,20 +352,35 @@ "node": "^18 || >=20" } }, - "node_modules/@astrojs/db/node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "node_modules/@astrojs/db/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/@astrojs/internal-helpers": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.7.5.tgz", - "integrity": "sha512-vreGnYSSKhAjFJCWAwe/CNhONvoc5lokxtRoZims+0wa3KbHBdPHSSthJsKxPd8d/aic6lWKpRTYGY/hsgK6EA==", - "license": "MIT" + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.8.0.tgz", + "integrity": "sha512-J56GrhEiV+4dmrGLPNOl2pZjpHXAndWVyiVDYGDuw6MWKpBSEMLdFxHzeM/6sqaknw9M+HFfHZAcvi3OfT3D/w==", + "license": "MIT", + "dependencies": { + "picomatch": "^4.0.3" + } + }, + "node_modules/@astrojs/internal-helpers/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, "node_modules/@astrojs/language-server": { "version": "2.16.1", @@ -409,17 +424,16 @@ } }, "node_modules/@astrojs/markdown-remark": { - "version": "6.3.10", - "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.3.10.tgz", - "integrity": "sha512-kk4HeYR6AcnzC4QV8iSlOfh+N8TZ3MEStxPyenyCtemqn8IpEATBFMTJcfrNW32dgpt6MY3oCkMM/Tv3/I4G3A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-7.0.0.tgz", + "integrity": "sha512-jTAXHPy45L7o1ljH4jYV+ShtOHtyQUa1mGp3a5fJp1soX8lInuTJQ6ihmldHzVM4Q7QptU4SzIDIcKbBJO7sXQ==", "license": "MIT", "dependencies": { - "@astrojs/internal-helpers": "0.7.5", - "@astrojs/prism": "3.3.0", + "@astrojs/internal-helpers": "0.8.0", + "@astrojs/prism": "4.0.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", - "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", @@ -428,102 +442,25 @@ "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", - "shiki": "^3.19.0", - "smol-toml": "^1.5.2", + "shiki": "^4.0.0", + "smol-toml": "^1.6.0", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", - "unist-util-visit": "^5.0.0", + "unist-util-visit": "^5.1.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, - "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/core": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.23.0.tgz", - "integrity": "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.23.0", - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4", - "hast-util-to-html": "^9.0.5" - } - }, - "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/engine-javascript": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.23.0.tgz", - "integrity": "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.23.0", - "@shikijs/vscode-textmate": "^10.0.2", - "oniguruma-to-es": "^4.3.4" - } - }, - "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/engine-oniguruma": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz", - "integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.23.0", - "@shikijs/vscode-textmate": "^10.0.2" - } - }, - "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/langs": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz", - "integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.23.0" - } - }, - "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/themes": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz", - "integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.23.0" - } - }, - "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/types": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz", - "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==", - "license": "MIT", - "dependencies": { - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" - } - }, - "node_modules/@astrojs/markdown-remark/node_modules/shiki": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.23.0.tgz", - "integrity": "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==", - "license": "MIT", - "dependencies": { - "@shikijs/core": "3.23.0", - "@shikijs/engine-javascript": "3.23.0", - "@shikijs/engine-oniguruma": "3.23.0", - "@shikijs/langs": "3.23.0", - "@shikijs/themes": "3.23.0", - "@shikijs/types": "3.23.0", - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" - } - }, "node_modules/@astrojs/mdx": { - "version": "4.3.13", - "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-4.3.13.tgz", - "integrity": "sha512-IHDHVKz0JfKBy3//52JSiyWv089b7GVSChIXLrlUOoTLWowG3wr2/8hkaEgEyd/vysvNQvGk+QhysXpJW5ve6Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-5.0.0.tgz", + "integrity": "sha512-J4rW6eT+qgVw7+RXdBYO4vYyWGeXXQp8wop9dXsOlLzIsVSxyttMCgkGCWvIR2ogBqKqeYgI6YDW93PaDHkCaA==", "license": "MIT", "dependencies": { - "@astrojs/markdown-remark": "6.3.10", + "@astrojs/markdown-remark": "7.0.0", "@mdx-js/mdx": "^3.1.1", - "acorn": "^8.15.0", - "es-module-lexer": "^1.7.0", + "acorn": "^8.16.0", + "es-module-lexer": "^2.0.0", "estree-util-visit": "^2.0.0", "hast-util-to-html": "^9.0.5", "piccolore": "^0.1.3", @@ -531,34 +468,56 @@ "remark-gfm": "^4.0.1", "remark-smartypants": "^3.0.2", "source-map": "^0.7.6", - "unist-util-visit": "^5.0.0", + "unist-util-visit": "^5.1.0", "vfile": "^6.0.3" }, "engines": { - "node": "18.20.8 || ^20.3.0 || >=22.0.0" + "node": "^20.19.1 || >=22.12.0" }, "peerDependencies": { - "astro": "^5.0.0" + "astro": "^6.0.0-alpha.0" } }, "node_modules/@astrojs/preact": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@astrojs/preact/-/preact-4.1.3.tgz", - "integrity": "sha512-Ph416wbgyumkmYr7erZ83l/d+LXdZethlHRRCbgoKEn8wo3Rkq13shKFp0QYXYSDYxVaA6UBdkdimeowy/lMLQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@astrojs/preact/-/preact-5.0.0.tgz", + "integrity": "sha512-KJBLQtKxmx/MnNMqDNFFp2N6o430eyx90uaLKJS4IzUnR0fOgekyGOPjE+3deuetIS+7uNcp1kALpLPG21/tFQ==", "license": "MIT", "dependencies": { - "@preact/preset-vite": "^2.10.2", - "@preact/signals": "^2.3.1", - "preact-render-to-string": "^6.6.1", - "vite": "^6.4.1" + "@astrojs/internal-helpers": "0.8.0", + "@preact/preset-vite": "^2.10.3", + "@preact/signals": "^2.8.1", + "devalue": "^5.6.3", + "preact-render-to-string": "^6.6.6", + "vite": "^7.3.1" }, "engines": { - "node": "18.20.8 || ^20.3.0 || >=22.0.0" + "node": "^20.19.1 || >=22.12.0" }, "peerDependencies": { "preact": "^10.6.5" } }, + "node_modules/@astrojs/preact/node_modules/@preact/preset-vite": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@preact/preset-vite/-/preset-vite-2.10.3.tgz", + "integrity": "sha512-1SiS+vFItpkNdBs7q585PSAIln0wBeBdcpJYbzPs1qipsb/FssnkUioNXuRsb8ZnU8YEQHr+3v8+/mzWSnTQmg==", + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.27.1", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@prefresh/vite": "^2.4.11", + "@rollup/pluginutils": "^5.0.0", + "babel-plugin-transform-hook-names": "^1.0.2", + "debug": "^4.4.3", + "picocolors": "^1.1.1", + "vite-prerender-plugin": "^0.5.8" + }, + "peerDependencies": { + "@babel/core": "7.x", + "vite": "2.x || 3.x || 4.x || 5.x || 6.x || 7.x" + } + }, "node_modules/@astrojs/preact/node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -603,23 +562,23 @@ } }, "node_modules/@astrojs/preact/node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -628,14 +587,14 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", - "less": "*", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" @@ -676,46 +635,55 @@ } } }, + "node_modules/@astrojs/preact/node_modules/vite-prerender-plugin": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/vite-prerender-plugin/-/vite-prerender-plugin-0.5.12.tgz", + "integrity": "sha512-EiwhbMn+flg14EysbLTmZSzq8NGTxhytgK3bf4aGRF1evWLGwZiHiUJ1KZDvbxgKbMf2pG6fJWGEa3UZXOnR1g==", + "license": "MIT", + "dependencies": { + "kolorist": "^1.8.0", + "magic-string": "0.x >= 0.26.0", + "node-html-parser": "^6.1.12", + "simple-code-frame": "^1.3.0", + "source-map": "^0.7.4", + "stack-trace": "^1.0.0-pre2" + }, + "peerDependencies": { + "vite": "5.x || 6.x || 7.x" + } + }, "node_modules/@astrojs/prism": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.3.0.tgz", - "integrity": "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.0.0.tgz", + "integrity": "sha512-NndtNPpxaGinRpRytljGBvYHpTOwHycSZ/c+lQi5cHvkqqrHKWdkPEhImlODBNmbuB+vyQUNUDXyjzt66CihJg==", "license": "MIT", "dependencies": { "prismjs": "^1.30.0" }, "engines": { - "node": "18.20.8 || ^20.3.0 || >=22.0.0" + "node": "^20.19.1 || >=22.12.0" } }, "node_modules/@astrojs/rss": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@astrojs/rss/-/rss-4.0.15.tgz", - "integrity": "sha512-uXO/k6AhRkIDXmRoc6xQpoPZrimQNUmS43X4+60yunfuMNHtSRN5e/FiSi7NApcZqmugSMc5+cJi8ovqgO+qIg==", + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@astrojs/rss/-/rss-4.0.17.tgz", + "integrity": "sha512-eV+wdMbeVKC9+sPaV0LN8JL1LGo9YAh3GKl4Ou4nzMNLmXM/aswYpSGxVEAuHilgBZ6/++/Pv08ICmuOqX107w==", "license": "MIT", "dependencies": { - "fast-xml-parser": "^5.3.3", - "piccolore": "^0.1.3" + "fast-xml-parser": "5.4.1", + "piccolore": "^0.1.3", + "zod": "^4.3.6" } }, "node_modules/@astrojs/sitemap": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.0.tgz", - "integrity": "sha512-+qxjUrz6Jcgh+D5VE1gKUJTA3pSthuPHe6Ao5JCxok794Lewx8hBFaWHtOnN0ntb2lfOf7gvOi9TefUswQ/ZVA==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.1.tgz", + "integrity": "sha512-IzQqdTeskaMX+QDZCzMuJIp8A8C1vgzMBp/NmHNnadepHYNHcxQdGLQZYfkbd2EbRXUfOS+UDIKx8sKg0oWVdw==", "license": "MIT", "dependencies": { - "sitemap": "^8.0.2", + "sitemap": "^9.0.0", "stream-replace-string": "^2.0.0", - "zod": "^3.25.76" - } - }, - "node_modules/@astrojs/sitemap/node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "zod": "^4.3.6" } }, "node_modules/@astrojs/telemetry": { @@ -737,21 +705,59 @@ } }, "node_modules/@astrojs/vercel": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@astrojs/vercel/-/vercel-9.0.4.tgz", - "integrity": "sha512-Nn5c0CODcx69FnNUhAcAhlDQ/Je2lLrlPmbMMI77ZvLMfyZI5NZyKD7MiKEeaYK/VTnx6fNI5rFHm6seqEPRtQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@astrojs/vercel/-/vercel-10.0.0.tgz", + "integrity": "sha512-U80Lswq1zZporn8DFBrtmAkjQyUns9lN22YPoFGV1NsvKJJy/2XGuoo+NDRK8C98eqpUOLtwXtFFmw0QDV5JYA==", "license": "MIT", "dependencies": { - "@astrojs/internal-helpers": "0.7.5", + "@astrojs/internal-helpers": "0.8.0", "@vercel/analytics": "^1.6.1", - "@vercel/functions": "^2.2.13", - "@vercel/nft": "0.30.4", - "@vercel/routing-utils": "^5.3.1", - "esbuild": "^0.25.0", + "@vercel/functions": "^3.4.3", + "@vercel/nft": "^1.3.2", + "@vercel/routing-utils": "^5.3.3", + "esbuild": "^0.27.3", "tinyglobby": "^0.2.15" }, "peerDependencies": { - "astro": "^5.0.0" + "astro": "^6.0.0-alpha.0" + } + }, + "node_modules/@astrojs/vercel/node_modules/@vercel/analytics": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.6.1.tgz", + "integrity": "sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==", + "license": "MPL-2.0", + "peerDependencies": { + "@remix-run/react": "^2", + "@sveltejs/kit": "^1 || ^2", + "next": ">= 13", + "react": "^18 || ^19 || ^19.0.0-rc", + "svelte": ">= 4", + "vue": "^3", + "vue-router": "^4" + }, + "peerDependenciesMeta": { + "@remix-run/react": { + "optional": true + }, + "@sveltejs/kit": { + "optional": true + }, + "next": { + "optional": true + }, + "react": { + "optional": true + }, + "svelte": { + "optional": true + }, + "vue": { + "optional": true + }, + "vue-router": { + "optional": true + } } }, "node_modules/@astrojs/yaml2ts": { @@ -776,12 +782,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -829,13 +835,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -949,13 +955,13 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -991,9 +997,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1101,12 +1107,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "license": "MIT", "dependencies": { - "@babel/types": "^7.28.5" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -1237,12 +1243,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1888,16 +1894,16 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", - "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.28.6.tgz", + "integrity": "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-syntax-jsx": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -2214,31 +2220,31 @@ } }, "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", "debug": "^4.3.1" }, "engines": { @@ -2246,9 +2252,9 @@ } }, "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -2360,44 +2366,63 @@ } }, "node_modules/@chevrotain/cst-dts-gen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.1.tgz", - "integrity": "sha512-fRHyv6/f542qQqiRGalrfJl/evD39mAvbJLCekPazhiextEatq1Jx1K/i9gSd5NNO0ds03ek0Cbo/4uVKmOBcw==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.2.tgz", + "integrity": "sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/gast": "11.1.1", - "@chevrotain/types": "11.1.1", + "@chevrotain/gast": "11.1.2", + "@chevrotain/types": "11.1.2", "lodash-es": "4.17.23" } }, "node_modules/@chevrotain/gast": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.1.tgz", - "integrity": "sha512-Ko/5vPEYy1vn5CbCjjvnSO4U7GgxyGm+dfUZZJIWTlQFkXkyym0jFYrWEU10hyCjrA7rQtiHtBr0EaZqvHFZvg==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.2.tgz", + "integrity": "sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/types": "11.1.1", + "@chevrotain/types": "11.1.2", "lodash-es": "4.17.23" } }, "node_modules/@chevrotain/regexp-to-ast": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.1.tgz", - "integrity": "sha512-ctRw1OKSXkOrR8VTvOxrQ5USEc4sNrfwXHa1NuTcR7wre4YbjPcKw+82C2uylg/TEwFRgwLmbhlln4qkmDyteg==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.2.tgz", + "integrity": "sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw==", "license": "Apache-2.0" }, "node_modules/@chevrotain/types": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.1.tgz", - "integrity": "sha512-wb2ToxG8LkgPYnKe9FH8oGn3TMCBdnwiuNC5l5y+CtlaVRbCytU0kbVsk6CGrqTL4ZN4ksJa0TXOYbxpbthtqw==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", "license": "Apache-2.0" }, "node_modules/@chevrotain/utils": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.1.tgz", - "integrity": "sha512-71eTYMzYXYSFPrbg/ZwftSaSDld7UYlS8OQa3lNnn9jzNtpFbaReRRyghzqS7rI3CDaorqpPJJcXGHK+FE1TVQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.2.tgz", + "integrity": "sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==", "license": "Apache-2.0" }, + "node_modules/@clack/core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.1.0.tgz", + "integrity": "sha512-SVcm4Dqm2ukn64/8Gub2wnlA5nS2iWJyCkdNHcvNHPIeBTGojpdJ+9cZKwLfmqy7irD4N5qLteSilJlE0WLAtA==", + "license": "MIT", + "dependencies": { + "sisteransi": "^1.0.5" + } + }, + "node_modules/@clack/prompts": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.1.0.tgz", + "integrity": "sha512-pkqbPGtohJAvm4Dphs2M8xE29ggupihHdy1x84HNojZuMtFsHiUlRvqD24tM2+XmI+61LlfNceM3Wr7U5QES5g==", + "license": "MIT", + "dependencies": { + "@clack/core": "1.1.0", + "sisteransi": "^1.0.5" + } + }, "node_modules/@csstools/color-helpers": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.1.tgz", @@ -2712,9 +2737,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", + "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", "cpu": [ "ppc64" ], @@ -2728,9 +2753,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", + "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", "cpu": [ "arm" ], @@ -2744,9 +2769,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", + "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", "cpu": [ "arm64" ], @@ -2760,9 +2785,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", + "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", "cpu": [ "x64" ], @@ -2776,9 +2801,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", + "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", "cpu": [ "arm64" ], @@ -2792,9 +2817,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", + "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", "cpu": [ "x64" ], @@ -2808,9 +2833,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", + "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", "cpu": [ "arm64" ], @@ -2824,9 +2849,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", + "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", "cpu": [ "x64" ], @@ -2840,9 +2865,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", + "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", "cpu": [ "arm" ], @@ -2856,9 +2881,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", + "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", "cpu": [ "arm64" ], @@ -2872,9 +2897,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", + "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", "cpu": [ "ia32" ], @@ -2888,9 +2913,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", + "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", "cpu": [ "loong64" ], @@ -2904,9 +2929,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", + "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", "cpu": [ "mips64el" ], @@ -2920,9 +2945,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", + "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", "cpu": [ "ppc64" ], @@ -2936,9 +2961,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", + "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", "cpu": [ "riscv64" ], @@ -2952,9 +2977,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", + "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", "cpu": [ "s390x" ], @@ -2968,9 +2993,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", + "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", "cpu": [ "x64" ], @@ -2984,9 +3009,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", + "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", "cpu": [ "arm64" ], @@ -3000,9 +3025,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", + "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", "cpu": [ "x64" ], @@ -3016,9 +3041,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", + "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", "cpu": [ "arm64" ], @@ -3032,9 +3057,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", + "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", "cpu": [ "x64" ], @@ -3048,9 +3073,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", + "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", "cpu": [ "arm64" ], @@ -3064,9 +3089,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", + "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", "cpu": [ "x64" ], @@ -3080,9 +3105,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", + "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", "cpu": [ "arm64" ], @@ -3096,9 +3121,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", + "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", "cpu": [ "ia32" ], @@ -3112,9 +3137,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", + "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", "cpu": [ "x64" ], @@ -3183,14 +3208,14 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.2.tgz", - "integrity": "sha512-YF+fE6LV4v5MGWRGj7G404/OZzGNepVF8fxk7jqmqo3lrza7a0uUcDnROGRBG1WFC1omYUS/Wp1f42i0M+3Q3A==", + "version": "0.23.3", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.3.tgz", + "integrity": "sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==", "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^3.0.2", + "@eslint/object-schema": "^3.0.3", "debug": "^4.3.1", - "minimatch": "^10.2.1" + "minimatch": "^10.2.4" }, "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" @@ -3206,9 +3231,9 @@ } }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -3245,9 +3270,9 @@ } }, "node_modules/@eslint/core": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.0.tgz", - "integrity": "sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.1.tgz", + "integrity": "sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==", "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" @@ -3277,21 +3302,21 @@ } }, "node_modules/@eslint/object-schema": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.2.tgz", - "integrity": "sha512-HOy56KJt48Bx8KmJ+XGQNSUMT/6dZee/M54XyUyuvTvPXJmsERRvBchsUVx1UMe1WwIH49XLAczNC7V2INsuUw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.3.tgz", + "integrity": "sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==", "license": "Apache-2.0", "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/plugin-kit": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.0.tgz", - "integrity": "sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.1.tgz", + "integrity": "sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==", "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^1.1.0", + "@eslint/core": "^1.1.1", "levn": "^0.4.1" }, "engines": { @@ -3499,13 +3524,13 @@ } }, "node_modules/@happy-dom/global-registrator": { - "version": "20.8.3", - "resolved": "https://registry.npmjs.org/@happy-dom/global-registrator/-/global-registrator-20.8.3.tgz", - "integrity": "sha512-9z6lLr6K6dIFLiB9jI0tKTlYzCComn5RL7L1mN3EdMSCyRQB8I6A0FO/On8yYKkXuunexzPDC98zDflvv2wDrQ==", + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@happy-dom/global-registrator/-/global-registrator-20.8.4.tgz", + "integrity": "sha512-cXGYd3xIAcviiGO6lPXdG6Yg244xwRgtY2dicAQ6HiB87E2IL2ekgfR5QIos18UtjiAsnCpLS3m78JfDorJcYg==", "license": "MIT", "dependencies": { "@types/node": ">=20.0.0", - "happy-dom": "^20.8.3" + "happy-dom": "^20.8.4" }, "engines": { "node": ">=20.0.0" @@ -4469,16 +4494,16 @@ } }, "node_modules/@mapbox/node-pre-gyp": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.2.tgz", - "integrity": "sha512-pppEzxuUFmNoMb5YObyc4AAr/NrQGhNU/ZuSMLFxkC1JzrfZ4if2O0vI1JuD/oqxf+z/MNTARIekLmgL1PZg/A==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.3.tgz", + "integrity": "sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==", "license": "BSD-3-Clause", "dependencies": { "consola": "^3.2.3", "detect-libc": "^2.0.0", "https-proxy-agent": "^7.0.5", "node-fetch": "^2.6.7", - "nopt": "^9.0.0", + "nopt": "^8.0.0", "semver": "^7.5.3", "tar": "^7.4.0" }, @@ -4512,9 +4537,9 @@ } }, "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -4561,9 +4586,9 @@ } }, "node_modules/@mermaid-js/parser": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.0.0.tgz", - "integrity": "sha512-vvK0Hi/VWndxoh03Mmz6wa1KDriSPjS2XMZL/1l19HFwygiObEEoEwSDxOqyLzzAI6J2PU3261JjTMTO7x+BPw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.0.1.tgz", + "integrity": "sha512-opmV19kN1JsK0T6HhhokHpcVkqKpF+x2pPDKKM2ThHtZAB5F4PROopk0amuVYK5qMrIA4erzpNm8gmPNJgMDxQ==", "license": "MIT", "dependencies": { "langium": "^4.0.0" @@ -5374,6 +5399,15 @@ "url": "https://github.com/sponsors/ota-meshi" } }, + "node_modules/@oxc-project/runtime": { + "version": "0.115.0", + "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.115.0.tgz", + "integrity": "sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ==", + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@oxc-project/types": { "version": "0.110.0", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.110.0.tgz", @@ -5829,33 +5863,13 @@ "node": ">=12" } }, - "node_modules/@preact/preset-vite": { - "version": "2.10.2", - "resolved": "https://registry.npmjs.org/@preact/preset-vite/-/preset-vite-2.10.2.tgz", - "integrity": "sha512-K9wHlJOtkE+cGqlyQ5v9kL3Ge0Ql4LlIZjkUTL+1zf3nNdF88F9UZN6VTV8jdzBX9Fl7WSzeNMSDG7qECPmSmg==", - "license": "MIT", - "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.22.15", - "@babel/plugin-transform-react-jsx-development": "^7.22.5", - "@prefresh/vite": "^2.4.1", - "@rollup/pluginutils": "^4.1.1", - "babel-plugin-transform-hook-names": "^1.0.2", - "debug": "^4.3.4", - "picocolors": "^1.1.1", - "vite-prerender-plugin": "^0.5.3" - }, - "peerDependencies": { - "@babel/core": "7.x", - "vite": "2.x || 3.x || 4.x || 5.x || 6.x || 7.x" - } - }, "node_modules/@preact/signals": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@preact/signals/-/signals-2.5.0.tgz", - "integrity": "sha512-+9KrYvCtnssF4Q7e5xdX08aERL2th4w8kkzPAgI3mSEu2FsVeI93hInS2ifwNIzpEw8+9+e5FPtR7di1WvZiWg==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@preact/signals/-/signals-2.8.2.tgz", + "integrity": "sha512-gym5yoa64c+0w2kL7zRAAjY548qzWXbbuOfjsK9F1nWrEqooDwyWnih5SNdonjhQSp27zUqYh7UrxIRnkCyFCA==", "license": "MIT", "dependencies": { - "@preact/signals-core": "^1.12.0" + "@preact/signals-core": "^1.14.0" }, "funding": { "type": "opencollective", @@ -5866,9 +5880,9 @@ } }, "node_modules/@preact/signals-core": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.12.1.tgz", - "integrity": "sha512-BwbTXpj+9QutoZLQvbttRg5x3l5468qaV2kufh+51yha1c53ep5dY4kTuZR35+3pAZxpfQerGJiQqg34ZNZ6uA==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.14.0.tgz", + "integrity": "sha512-AowtCcCU/33lFlh1zRFf/u+12rfrhtNakj7UpaGEsmMwUKpKWMVvcktOGcwBBNiB4lWrZWc01LhiyyzVklJyaQ==", "license": "MIT", "funding": { "type": "opencollective", @@ -5876,9 +5890,9 @@ } }, "node_modules/@prefresh/babel-plugin": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@prefresh/babel-plugin/-/babel-plugin-0.5.2.tgz", - "integrity": "sha512-AOl4HG6dAxWkJ5ndPHBgBa49oo/9bOiJuRDKHLSTyH+Fd9x00shTXpdiTj1W41l6oQIwUOAgJeHMn4QwIDpHkA==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@prefresh/babel-plugin/-/babel-plugin-0.5.3.tgz", + "integrity": "sha512-57LX2SHs4BX2s1IwCjNzTE2OJeEepRCNf1VTEpbNcUyHfMO68eeOWGDIt4ob9aYlW6PEWZ1SuwNikuoIXANDtQ==", "license": "MIT" }, "node_modules/@prefresh/core": { @@ -5897,13 +5911,13 @@ "license": "MIT" }, "node_modules/@prefresh/vite": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/@prefresh/vite/-/vite-2.4.11.tgz", - "integrity": "sha512-/XjURQqdRiCG3NpMmWqE9kJwrg9IchIOWHzulCfqg2sRe/8oQ1g5De7xrk9lbqPIQLn7ntBkKdqWXIj4E9YXyg==", + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/@prefresh/vite/-/vite-2.4.12.tgz", + "integrity": "sha512-FY1fzXpUjiuosznMV0YM7XAOPZjB5FIdWS0W24+XnlxYkt9hNAwwsiKYn+cuTEoMtD/ZVazS5QVssBr9YhpCQA==", "license": "MIT", "dependencies": { "@babel/core": "^7.22.1", - "@prefresh/babel-plugin": "0.5.2", + "@prefresh/babel-plugin": "^0.5.2", "@prefresh/core": "^1.5.0", "@prefresh/utils": "^1.2.0", "@rollup/pluginutils": "^4.2.1" @@ -5913,6 +5927,25 @@ "vite": ">=2.0.0" } }, + "node_modules/@prefresh/vite/node_modules/@rollup/pluginutils": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", + "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", + "license": "MIT", + "dependencies": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@prefresh/vite/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, "node_modules/@prisma/instrumentation": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@prisma/instrumentation/-/instrumentation-7.2.0.tgz", @@ -6109,6 +6142,38 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/binding-linux-x64-gnu": { "version": "1.0.0-rc.1", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.1.tgz", @@ -6251,7 +6316,29 @@ } } }, - "node_modules/@rollup/plugin-node-resolve/node_modules/@rollup/pluginutils": { + "node_modules/@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "license": "MIT", + "dependencies": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", @@ -6273,13 +6360,13 @@ } } }, - "node_modules/@rollup/plugin-node-resolve/node_modules/estree-walker": { + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "license": "MIT" }, - "node_modules/@rollup/plugin-node-resolve/node_modules/picomatch": { + "node_modules/@rollup/pluginutils/node_modules/picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", @@ -6291,47 +6378,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@rollup/plugin-terser": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", - "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", - "license": "MIT", - "dependencies": { - "serialize-javascript": "^6.0.1", - "smob": "^1.0.0", - "terser": "^5.17.4" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", - "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", - "license": "MIT", - "dependencies": { - "estree-walker": "^2.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" - }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.2.tgz", @@ -6625,103 +6671,80 @@ "license": "MIT" }, "node_modules/@semantic-ui/astro-lit": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@semantic-ui/astro-lit/-/astro-lit-5.1.1.tgz", - "integrity": "sha512-PFbWlSlG0uovWHbUeV4LZfFXCrqTHL+IuMlzqKPg664o0mdz/48gZaFxSdpJgJ88xda9+fqAupIIo4WYQjHfFQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@semantic-ui/astro-lit/-/astro-lit-5.1.2.tgz", + "integrity": "sha512-FZ7J9oLWX08WK8G87BtrDZ+wRbc3Ui83sDr3t2fkTp+ZsbU3vGsywq7jS9SMyIaGbFNUARk7kUTUsSBtpLDLpg==", "license": "MIT", "dependencies": { "@lit-labs/ssr": "^3.3.1", "@lit-labs/ssr-client": "^1.1.7", - "@lit-labs/ssr-dom-shim": "^1.4.0", - "parse5": "^8.0.0" + "@lit-labs/ssr-dom-shim": "^1.3.0", + "parse5": "^7.2.1" }, "peerDependencies": { - "@webcomponents/template-shadowroot": "^0.2.1" - } - }, - "node_modules/@semantic-ui/astro-lit/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/@semantic-ui/astro-lit/node_modules/parse5": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", - "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", - "license": "MIT", - "dependencies": { - "entities": "^6.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "@webcomponents/template-shadowroot": "^0.2.1", + "lit": "^3.2.0" } }, "node_modules/@sentry-internal/browser-utils": { - "version": "10.42.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.42.0.tgz", - "integrity": "sha512-HCEICKvepxN4/6NYfnMMMlppcSwIEwtS66X6d1/mwaHdi2ivw0uGl52p7Nfhda/lIJArbrkWprxl0WcjZajhQA==", + "version": "10.43.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.43.0.tgz", + "integrity": "sha512-8zYTnzhAPvNkVH1Irs62wl0J/c+0QcJ62TonKnzpSFUUD3V5qz8YDZbjIDGfxy+1EB9fO0sxtddKCzwTHF/MbQ==", "license": "MIT", "dependencies": { - "@sentry/core": "10.42.0" + "@sentry/core": "10.43.0" }, "engines": { "node": ">=18" } }, "node_modules/@sentry-internal/feedback": { - "version": "10.42.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.42.0.tgz", - "integrity": "sha512-lpPcHsog10MVYFTWE0Pf8vQRqQWwZHJpkVl2FEb9/HDdHFyTBUhCVoWo1KyKaG7GJl9AVKMAg7bp9SSNArhFNQ==", + "version": "10.43.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.43.0.tgz", + "integrity": "sha512-YoXuwluP6eOcQxTeTtaWb090++MrLyWOVsUTejzUQQ6LFL13Jwt+bDPF1kvBugMq4a7OHw/UNKQfd6//rZMn2g==", "license": "MIT", "dependencies": { - "@sentry/core": "10.42.0" + "@sentry/core": "10.43.0" }, "engines": { "node": ">=18" } }, "node_modules/@sentry-internal/replay": { - "version": "10.42.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.42.0.tgz", - "integrity": "sha512-Zh3EoaH39x2lqVY1YyVB2vJEyCIrT+YLUQxYl1yvP0MJgLxaR6akVjkgxbSUJahan4cX5DxpZiEHfzdlWnYPyQ==", + "version": "10.43.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.43.0.tgz", + "integrity": "sha512-khCXlGrlH1IU7P5zCEAJFestMeH97zDVCekj8OsNNDtN/1BmCJ46k6Xi0EqAUzdJgrOLJeLdoYdgtiIjovZ8Sg==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "10.42.0", - "@sentry/core": "10.42.0" + "@sentry-internal/browser-utils": "10.43.0", + "@sentry/core": "10.43.0" }, "engines": { "node": ">=18" } }, "node_modules/@sentry-internal/replay-canvas": { - "version": "10.42.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.42.0.tgz", - "integrity": "sha512-am3m1Fj8ihoPfoYo41Qq4KeCAAICn4bySso8Oepu9dMNe9Lcnsf+reMRS2qxTPg3pZDc4JEMOcLyNCcgnAfrHw==", + "version": "10.43.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.43.0.tgz", + "integrity": "sha512-ZIw1UNKOFXo1LbPCJPMAx9xv7D8TMZQusLDUgb6BsPQJj0igAuwd7KRGTkjjgnrwBp2O/sxcQFRhQhknWk7QPg==", "license": "MIT", "dependencies": { - "@sentry-internal/replay": "10.42.0", - "@sentry/core": "10.42.0" + "@sentry-internal/replay": "10.43.0", + "@sentry/core": "10.43.0" }, "engines": { "node": ">=18" } }, "node_modules/@sentry/astro": { - "version": "10.42.0", - "resolved": "https://registry.npmjs.org/@sentry/astro/-/astro-10.42.0.tgz", - "integrity": "sha512-0IYborFhKQqdr4junfej/RHarrZp+SElkYpwfdbXAFCrdD8ImMfgmUuj7RPj90nuiUQtwpg9lF3eSc507ashqQ==", + "version": "10.43.0", + "resolved": "https://registry.npmjs.org/@sentry/astro/-/astro-10.43.0.tgz", + "integrity": "sha512-9xN86+dDTa4yv0zRlp+761s2H6jq0Q4GSRDniMC7cJ+o0aDN4C3YRvg43HKUYjzvR8cty/EFSHG5goIxeFP6Vg==", "license": "MIT", "dependencies": { - "@sentry/browser": "10.42.0", - "@sentry/core": "10.42.0", - "@sentry/node": "10.42.0", + "@sentry/browser": "10.43.0", + "@sentry/core": "10.43.0", + "@sentry/node": "10.43.0", "@sentry/vite-plugin": "^5.1.0" }, "engines": { @@ -6741,16 +6764,16 @@ } }, "node_modules/@sentry/browser": { - "version": "10.42.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.42.0.tgz", - "integrity": "sha512-iXxYjXNEBwY1MH4lDSDZZUNjzPJDK7/YLwVIJq/3iBYpIQVIhaJsoJnf3clx9+NfJ8QFKyKfcvgae61zm+hgTA==", + "version": "10.43.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.43.0.tgz", + "integrity": "sha512-2V3I3sXi3SMeiZpKixd9ztokSgK27cmvsD9J5oyOyjhGLTW/6QKCwHbKnluMgQMXq20nixQk5zN4wRjRUma3sg==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "10.42.0", - "@sentry-internal/feedback": "10.42.0", - "@sentry-internal/replay": "10.42.0", - "@sentry-internal/replay-canvas": "10.42.0", - "@sentry/core": "10.42.0" + "@sentry-internal/browser-utils": "10.43.0", + "@sentry-internal/feedback": "10.43.0", + "@sentry-internal/replay": "10.43.0", + "@sentry-internal/replay-canvas": "10.43.0", + "@sentry/core": "10.43.0" }, "engines": { "node": ">=18" @@ -7030,18 +7053,18 @@ } }, "node_modules/@sentry/core": { - "version": "10.42.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.42.0.tgz", - "integrity": "sha512-L4rMrXMqUKBanpjpMT+TuAVk6xAijz6AWM6RiEYpohAr7SGcCEc1/T0+Ep1eLV8+pwWacfU27OvELIyNeOnGzA==", + "version": "10.43.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.43.0.tgz", + "integrity": "sha512-l0SszQAPiQGWl/ferw8GP3ALyHXiGiRKJaOvNmhGO+PrTQyZTZ6OYyPnGijAFRg58dE1V3RCH/zw5d2xSUIiNg==", "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/@sentry/node": { - "version": "10.42.0", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-10.42.0.tgz", - "integrity": "sha512-ZZfU3Fnni7Aj0lTX4e3QpY3UxK4FGuzfM20316UAJycBGnripm+sDHwcekPMGfLnk/FrN9wa1atspVlHvOI0WQ==", + "version": "10.43.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-10.43.0.tgz", + "integrity": "sha512-oNwXcuZUc4uTTr0WbHZBBIKsKwAKvNMTgbXwxfB37CfzV18wbTirbQABZ/Ir3WNxSgi6ZcnC6UE013jF5XWPqw==", "license": "MIT", "dependencies": { "@fastify/otel": "0.16.0", @@ -7075,9 +7098,9 @@ "@opentelemetry/sdk-trace-base": "^2.5.1", "@opentelemetry/semantic-conventions": "^1.39.0", "@prisma/instrumentation": "7.2.0", - "@sentry/core": "10.42.0", - "@sentry/node-core": "10.42.0", - "@sentry/opentelemetry": "10.42.0", + "@sentry/core": "10.43.0", + "@sentry/node-core": "10.43.0", + "@sentry/opentelemetry": "10.43.0", "import-in-the-middle": "^2.0.6" }, "engines": { @@ -7085,13 +7108,13 @@ } }, "node_modules/@sentry/node-core": { - "version": "10.42.0", - "resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-10.42.0.tgz", - "integrity": "sha512-9tf3fPV6M071aps72D+PEtdQPTuj+SuqO2+PpTfdPP5ZL4TTKYo3VK0li76SL+5wGdTFGV5qmsokHq9IRBA0iA==", + "version": "10.43.0", + "resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-10.43.0.tgz", + "integrity": "sha512-w2H3NSkNMoYOS7o7mR55BM7+xL++dPxMSv1/XDfsra9FYHGppO+Mxk667Ee5k+uDi+wNIioICIh+5XOvZh4+HQ==", "license": "MIT", "dependencies": { - "@sentry/core": "10.42.0", - "@sentry/opentelemetry": "10.42.0", + "@sentry/core": "10.43.0", + "@sentry/opentelemetry": "10.43.0", "import-in-the-middle": "^2.0.6" }, "engines": { @@ -7131,12 +7154,12 @@ } }, "node_modules/@sentry/opentelemetry": { - "version": "10.42.0", - "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-10.42.0.tgz", - "integrity": "sha512-5vsYz683iihzlIj3sT1+tEixf0awwXK86a+aYsnMHrTXJDrkBDq4U0ZT+yxdPfJlkaxRtYycFR08SXr2pSm7Eg==", + "version": "10.43.0", + "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-10.43.0.tgz", + "integrity": "sha512-+fIcnnLdvBHdq4nKq23t9v/B9D4L97fPWEDksXbpGs11o6BsqY4Tlzmce6cP95iiQhPckCEag3FthSND+BYtYQ==", "license": "MIT", "dependencies": { - "@sentry/core": "10.42.0" + "@sentry/core": "10.43.0" }, "engines": { "node": ">=18" @@ -7179,13 +7202,13 @@ } }, "node_modules/@shikijs/core": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.0.1.tgz", - "integrity": "sha512-vWvqi9JNgz1dRL9Nvog5wtx7RuNkf7MEPl2mU/cyUUxJeH1CAr3t+81h8zO8zs7DK6cKLMoU9TvukWIDjP4Lzg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.0.2.tgz", + "integrity": "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw==", "license": "MIT", "dependencies": { - "@shikijs/primitive": "4.0.1", - "@shikijs/types": "4.0.1", + "@shikijs/primitive": "4.0.2", + "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" @@ -7195,12 +7218,12 @@ } }, "node_modules/@shikijs/engine-javascript": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.0.1.tgz", - "integrity": "sha512-DJK9NiwtGYqMuKCRO4Ip0FKNDQpmaiS+K5bFjJ7DWFn4zHueDWgaUG8kAofkrnXF6zPPYYQY7J5FYVW9MbZyBg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.0.2.tgz", + "integrity": "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.0.1", + "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" }, @@ -7209,12 +7232,12 @@ } }, "node_modules/@shikijs/engine-oniguruma": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.0.1.tgz", - "integrity": "sha512-oCWdCTDch3J8Kc0OZJ98KuUPC02O1VqIE3W/e2uvrHqTxYRR21RGEJMtchrgrxhsoJJCzmIciKsqG+q/yD+Cxg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.0.2.tgz", + "integrity": "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.0.1", + "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2" }, "engines": { @@ -7222,24 +7245,24 @@ } }, "node_modules/@shikijs/langs": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.0.1.tgz", - "integrity": "sha512-v/mluaybWdnGJR4GqAR6zh8qAZohW9k+cGYT28Y7M8+jLbC0l4yG085O1A+WkseHTn+awd+P3UBymb2+MXFc8w==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.0.2.tgz", + "integrity": "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.0.1" + "@shikijs/types": "4.0.2" }, "engines": { "node": ">=20" } }, "node_modules/@shikijs/primitive": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.0.1.tgz", - "integrity": "sha512-ns0hHZc5eWZuvuIEJz2pTx3Qecz0aRVYumVQJ8JgWY2tq/dH8WxdcVM49Fc2NsHEILNIT6vfdW9MF26RANWiTA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.0.2.tgz", + "integrity": "sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.0.1", + "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" }, @@ -7248,34 +7271,34 @@ } }, "node_modules/@shikijs/themes": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.0.1.tgz", - "integrity": "sha512-FW41C/D6j/yKQkzVdjrRPiJCtgeDaYRJFEyCKFCINuRJRj9WcmubhP4KQHPZ4+9eT87jruSrYPyoblNRyDFzvA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.0.2.tgz", + "integrity": "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.0.1" + "@shikijs/types": "4.0.2" }, "engines": { "node": ">=20" } }, "node_modules/@shikijs/transformers": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-4.0.1.tgz", - "integrity": "sha512-oE46W2eHpvD06+C0MBthd2YrDM6cktvJDFl764tOEXxfr3dAJhxMc0uNZ2tQXp+bkMgl4E7IL88Mj9RnSqiayw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-4.0.2.tgz", + "integrity": "sha512-1+L0gf9v+SdDXs08vjaLb3mBFa8U7u37cwcBQIv/HCocLwX69Tt6LpUCjtB+UUTvQxI7BnjZKhN/wMjhHBcJGg==", "license": "MIT", "dependencies": { - "@shikijs/core": "4.0.1", - "@shikijs/types": "4.0.1" + "@shikijs/core": "4.0.2", + "@shikijs/types": "4.0.2" }, "engines": { "node": ">=20" } }, "node_modules/@shikijs/types": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.1.tgz", - "integrity": "sha512-EaygPEn57+jJ76mw+nTLvIpJMAcMPokFbrF8lufsZP7Ukk+ToJYEcswN1G0e49nUZAq7aCQtoeW219A8HK1ZOw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz", + "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==", "license": "MIT", "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", @@ -7884,9 +7907,9 @@ } }, "node_modules/@ts-morph/common/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -8422,9 +8445,9 @@ } }, "node_modules/@types/node": { - "version": "25.3.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.3.tgz", - "integrity": "sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==", + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", + "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", "license": "MIT", "dependencies": { "undici-types": "~7.18.0" @@ -8493,18 +8516,30 @@ "license": "MIT" }, "node_modules/@types/sanitize-html": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.16.0.tgz", - "integrity": "sha512-l6rX1MUXje5ztPT0cAFtUayXF06DqPhRyfVXareEN5gGCFaP/iwsxIyKODr9XDhfxPpN6vXUFNfo5kZMXCxBtw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.16.1.tgz", + "integrity": "sha512-n9wjs8bCOTyN/ynwD8s/nTcTreIHB1vf31vhLMGqUPNHaweKC4/fAl4Dj+hUlCTKYgm4P3k83fmiFfzkZ6sgMA==", "license": "MIT", "dependencies": { - "htmlparser2": "^8.0.0" + "htmlparser2": "^10.1" + } + }, + "node_modules/@types/sanitize-html/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/@types/sanitize-html/node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", { @@ -8516,8 +8551,8 @@ "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" + "domutils": "^3.2.2", + "entities": "^7.0.1" } }, "node_modules/@types/sax": { @@ -8603,16 +8638,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", - "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.0.tgz", + "integrity": "sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ==", "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/type-utils": "8.56.1", - "@typescript-eslint/utils": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", + "@typescript-eslint/scope-manager": "8.57.0", + "@typescript-eslint/type-utils": "8.57.0", + "@typescript-eslint/utils": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" @@ -8625,7 +8660,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.56.1", + "@typescript-eslint/parser": "^8.57.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -8640,15 +8675,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", - "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.0.tgz", + "integrity": "sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==", "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", + "@typescript-eslint/scope-manager": "8.57.0", + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/typescript-estree": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.0", "debug": "^4.4.3" }, "engines": { @@ -8664,13 +8699,13 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", - "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.0.tgz", + "integrity": "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==", "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.56.1", - "@typescript-eslint/types": "^8.56.1", + "@typescript-eslint/tsconfig-utils": "^8.57.0", + "@typescript-eslint/types": "^8.57.0", "debug": "^4.4.3" }, "engines": { @@ -8685,13 +8720,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", - "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.0.tgz", + "integrity": "sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1" + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8702,9 +8737,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", - "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.0.tgz", + "integrity": "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8718,14 +8753,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", - "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.0.tgz", + "integrity": "sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/typescript-estree": "8.57.0", + "@typescript-eslint/utils": "8.57.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, @@ -8742,9 +8777,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", - "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.0.tgz", + "integrity": "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8755,15 +8790,15 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", - "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.0.tgz", + "integrity": "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==", "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.56.1", - "@typescript-eslint/tsconfig-utils": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", + "@typescript-eslint/project-service": "8.57.0", + "@typescript-eslint/tsconfig-utils": "8.57.0", + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -8791,9 +8826,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -8830,15 +8865,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", - "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.0.tgz", + "integrity": "sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1" + "@typescript-eslint/scope-manager": "8.57.0", + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/typescript-estree": "8.57.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8853,12 +8888,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", - "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.0.tgz", + "integrity": "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/types": "8.57.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -9380,6 +9415,16 @@ "@uppy/core": "^5.2.0" } }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "license": "MIT", + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, "node_modules/@upstash/search": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/@upstash/search/-/search-0.1.7.tgz", @@ -9396,14 +9441,15 @@ "license": "MIT" }, "node_modules/@vercel/analytics": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.6.1.tgz", - "integrity": "sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==", - "license": "MPL-2.0", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-2.0.1.tgz", + "integrity": "sha512-MTQG6V9qQrt1tsDeF+2Uoo5aPjqbVPys1xvnIftXSJYG2SrwXRHnqEvVoYID7BTruDz4lCd2Z7rM1BdkUehk2g==", + "license": "MIT", "peerDependencies": { "@remix-run/react": "^2", "@sveltejs/kit": "^1 || ^2", "next": ">= 13", + "nuxt": ">= 3", "react": "^18 || ^19 || ^19.0.0-rc", "svelte": ">= 4", "vue": "^3", @@ -9419,6 +9465,9 @@ "next": { "optional": true }, + "nuxt": { + "optional": true + }, "react": { "optional": true }, @@ -9434,12 +9483,12 @@ } }, "node_modules/@vercel/backends": { - "version": "0.0.41", - "resolved": "https://registry.npmjs.org/@vercel/backends/-/backends-0.0.41.tgz", - "integrity": "sha512-XjikuYlrvVQEjfcdPIAQNrT4GqHJid1k1aueRIxtX33kvsCaMqd1xz2PwrNcyEHmwR7JRgGI1A8Twx9QDMq9eg==", + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/@vercel/backends/-/backends-0.0.45.tgz", + "integrity": "sha512-KIdt/z4LfH7NgFMqgSuKi0H9UIasly7ByzP+/ZXulgNrWyeJKT9KCas3SDT65o5tU6x1D/jBysZA9AnOt8Ivew==", "license": "Apache-2.0", "dependencies": { - "@vercel/build-utils": "13.6.3", + "@vercel/build-utils": "13.8.0", "@vercel/nft": "1.3.0", "execa": "3.2.0", "fs-extra": "11.1.0", @@ -9455,28 +9504,6 @@ "typescript": "^4.0.0 || ^5.0.0" } }, - "node_modules/@vercel/backends/node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, "node_modules/@vercel/backends/node_modules/@vercel/nft": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-1.3.0.tgz", @@ -9658,21 +9685,21 @@ } }, "node_modules/@vercel/build-utils": { - "version": "13.6.3", - "resolved": "https://registry.npmjs.org/@vercel/build-utils/-/build-utils-13.6.3.tgz", - "integrity": "sha512-KOxkJ38uzZoxvto1fL6H2Vxm69vbbKgpY7vq07M1mVdRM9q2jXFN5Lo6bebtuH/kuv0cLZNXCE1r8aFmaTwpTg==", + "version": "13.8.0", + "resolved": "https://registry.npmjs.org/@vercel/build-utils/-/build-utils-13.8.0.tgz", + "integrity": "sha512-moQS4Qd0pvluPd6WRTHxLN3Hh0oSObVNdFv3V0spiEmCk/wm6571up3n1th2PQFqf1a3gheNfxzL7h4I9CWs2A==", "license": "Apache-2.0", "dependencies": { - "@vercel/python-analysis": "0.8.2" + "@vercel/python-analysis": "0.9.1" } }, "node_modules/@vercel/cervel": { - "version": "0.0.28", - "resolved": "https://registry.npmjs.org/@vercel/cervel/-/cervel-0.0.28.tgz", - "integrity": "sha512-JanW95I8imjFzve1NCHv2JK5Bd/vd6DKULPaELAkC5pFV1lnqDHKmJEf21Trbg2qi9Rg5x0z08DbF44pcd6X+g==", + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@vercel/cervel/-/cervel-0.0.32.tgz", + "integrity": "sha512-g/LIa97d/m3yIZGyBjwl4FOQK1Lg5HU2+N3uHiGVajLoSgJM2aBiwETDZc8bVCr8IO3IqXZQsT2hGy1Jnyko1g==", "license": "Apache-2.0", "dependencies": { - "@vercel/backends": "0.0.41" + "@vercel/backends": "0.0.45" }, "bin": { "cervel": "bin/cervel.mjs" @@ -9682,22 +9709,22 @@ } }, "node_modules/@vercel/detect-agent": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@vercel/detect-agent/-/detect-agent-1.1.0.tgz", - "integrity": "sha512-Zfq6FbIcYl9gaAmVu6ROsqUiCNwpEj3Ljz/tMX5fl12Z95OFOxzf7vlO03WE5JBU/ri1tBDFHnW41dihMINOPQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vercel/detect-agent/-/detect-agent-1.2.1.tgz", + "integrity": "sha512-U/BJCltQSTFTHwaiCQQTQG3GonTbRoEewjV+OU2mMjcHLAoPOh6CP1SXA2XNmqiqI3c82nkRNJ7piZ14RqmTXw==", "license": "Apache-2.0", "engines": { "node": ">=14" } }, "node_modules/@vercel/elysia": { - "version": "0.1.44", - "resolved": "https://registry.npmjs.org/@vercel/elysia/-/elysia-0.1.44.tgz", - "integrity": "sha512-GYpOziLqPHoNopgpeogo20teEkcs2/2sbfitPd94UR+zpILHgaYXLAvk0im1OkOlRmptJACCGdD/O3Pc9flpnA==", + "version": "0.1.48", + "resolved": "https://registry.npmjs.org/@vercel/elysia/-/elysia-0.1.48.tgz", + "integrity": "sha512-QlmOHUSOx/uE67Y6u/o8VbNF7ebZ8SZFbrEoBo7iZAd0MC2Vn4xUmlrHFXNR/FEkHFXWkhFKda5Ade3XMqMY8A==", "license": "Apache-2.0", "dependencies": { - "@vercel/node": "5.6.11", - "@vercel/static-config": "3.1.2" + "@vercel/node": "5.6.15", + "@vercel/static-config": "3.2.0" } }, "node_modules/@vercel/error-utils": { @@ -9707,43 +9734,21 @@ "license": "Apache-2.0" }, "node_modules/@vercel/express": { - "version": "0.1.53", - "resolved": "https://registry.npmjs.org/@vercel/express/-/express-0.1.53.tgz", - "integrity": "sha512-rgKtIsqv0g+q+78CIEt2sl4l7lFBa/VX1Curivj9E088BkC7GFEjHUHvmCp0pZ9zX7irpt5zRtSErQM63+U3Qg==", + "version": "0.1.57", + "resolved": "https://registry.npmjs.org/@vercel/express/-/express-0.1.57.tgz", + "integrity": "sha512-/Ih1eiJrBGSW6JPzexB8y8AMX/8MzuDUf0xzmpYbKLCbehp3NNuxde5RxT+6cALglFivDETsJBCFwaFuIh3ZqQ==", "license": "Apache-2.0", "dependencies": { - "@vercel/cervel": "0.0.28", + "@vercel/cervel": "0.0.32", "@vercel/nft": "1.1.1", - "@vercel/node": "5.6.11", - "@vercel/static-config": "3.1.2", + "@vercel/node": "5.6.15", + "@vercel/static-config": "3.2.0", "fs-extra": "11.1.0", "path-to-regexp": "8.3.0", "ts-morph": "12.0.0", "zod": "3.22.4" } }, - "node_modules/@vercel/express/node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, "node_modules/@vercel/express/node_modules/@vercel/nft": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-1.1.1.tgz", @@ -9900,13 +9905,13 @@ } }, "node_modules/@vercel/fastify": { - "version": "0.1.47", - "resolved": "https://registry.npmjs.org/@vercel/fastify/-/fastify-0.1.47.tgz", - "integrity": "sha512-lg0X5RuIGXP9Dkg7Kzs3f1XVjD7wHvpuUlVZyhmvmOsMn5nYDB4vo8QrLaDaWJo10PVDppm9BVBfdKp2HWvFQw==", + "version": "0.1.51", + "resolved": "https://registry.npmjs.org/@vercel/fastify/-/fastify-0.1.51.tgz", + "integrity": "sha512-c9CwFQqmoUm5eEGwAcqb98DcxsRmSZGngCAo1B+nlDhaACKcrJ7Ro0tYdTDhi8Lkt+OcPnRWr4+pepgWwH94GQ==", "license": "Apache-2.0", "dependencies": { - "@vercel/node": "5.6.11", - "@vercel/static-config": "3.1.2" + "@vercel/node": "5.6.15", + "@vercel/static-config": "3.2.0" } }, "node_modules/@vercel/fun": { @@ -10036,15 +10041,15 @@ "license": "ISC" }, "node_modules/@vercel/functions": { - "version": "2.2.13", - "resolved": "https://registry.npmjs.org/@vercel/functions/-/functions-2.2.13.tgz", - "integrity": "sha512-14ArBSIIcOBx9nrEgaJb4Bw+en1gl6eSoJWh8qjifLl5G3E4dRXCFOT8HP+w66vb9Wqyd1lAQBrmRhRwOj9X9A==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@vercel/functions/-/functions-3.4.3.tgz", + "integrity": "sha512-kA14KIUVgAY6VXbhZ5jjY+s0883cV3cZqIU3WhrSRxuJ9KvxatMjtmzl0K23HK59oOUjYl7HaE/eYMmhmqpZzw==", "license": "Apache-2.0", "dependencies": { - "@vercel/oidc": "2.0.2" + "@vercel/oidc": "3.2.0" }, "engines": { - "node": ">= 18" + "node": ">= 20" }, "peerDependencies": { "@aws-sdk/credential-provider-web-identity": "*" @@ -10065,13 +10070,13 @@ } }, "node_modules/@vercel/gatsby-plugin-vercel-builder": { - "version": "2.0.143", - "resolved": "https://registry.npmjs.org/@vercel/gatsby-plugin-vercel-builder/-/gatsby-plugin-vercel-builder-2.0.143.tgz", - "integrity": "sha512-UO0BLWfxi8SFQwSpMNNNRHvai5+cElRUzqasxFgC1zGyo7Bbw0FZA6JTkIIJ1Rdk/rHr9xhn7/8R8fGIvmGaKA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vercel/gatsby-plugin-vercel-builder/-/gatsby-plugin-vercel-builder-2.1.0.tgz", + "integrity": "sha512-avJ5IFev2h2K6E/Pd7qd00cFLALj3OyEmQE3UoGs1dmoncINFqa1RoIZDJ9wIhWm1Euan4wrFMRsXkCwNhEGhw==", "license": "Apache-2.0", "dependencies": { "@sinclair/typebox": "0.25.24", - "@vercel/build-utils": "13.6.3", + "@vercel/build-utils": "13.8.0", "esbuild": "0.27.0", "etag": "1.8.1", "fs-extra": "11.1.0" @@ -10549,58 +10554,36 @@ } }, "node_modules/@vercel/go": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/@vercel/go/-/go-3.4.3.tgz", - "integrity": "sha512-LDT4wpx7SW2UJHd3rOL4+2m2V4w7a5zjyuU0pu0yDBiuxp9bEh7QuAH5qZC7pINGLC3vGftiFVzynd5N454sVA==", + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/@vercel/go/-/go-3.4.5.tgz", + "integrity": "sha512-eTWsdXawkSsG5TP+1BJUo+wRnoG9uH51MRID0YlwMMvollG5q7CrYisg859koy8MzGjQAcu3ff5v/WwRbwXwgQ==", "license": "Apache-2.0" }, "node_modules/@vercel/h3": { - "version": "0.1.53", - "resolved": "https://registry.npmjs.org/@vercel/h3/-/h3-0.1.53.tgz", - "integrity": "sha512-98KBB5XFdvezLRzlFNUJKQEgoDRrwsJaied3fUCcMzWYy5FXqvO+XqmWUGk4bApOM86MFkCsp6h9KqIZkn53uA==", + "version": "0.1.57", + "resolved": "https://registry.npmjs.org/@vercel/h3/-/h3-0.1.57.tgz", + "integrity": "sha512-I7Q1ity7xEdIVw4OQuKOAR8i6DrvfjpKy+y2uTwbqBD80Gg0KpsMS/KKA+UjvCuclFmP/EHYS3kpMLc/O1rVqg==", "license": "Apache-2.0", "dependencies": { - "@vercel/node": "5.6.11", - "@vercel/static-config": "3.1.2" + "@vercel/node": "5.6.15", + "@vercel/static-config": "3.2.0" } }, "node_modules/@vercel/hono": { - "version": "0.2.47", - "resolved": "https://registry.npmjs.org/@vercel/hono/-/hono-0.2.47.tgz", - "integrity": "sha512-JgS1j45JugQ4QXjkUZ7DFABZQ0AVIPbxF+IAlpfcKPUHViE1HKwsw7TnfY2zKktaMIY5EutkimDvQV1KtFmYjg==", + "version": "0.2.51", + "resolved": "https://registry.npmjs.org/@vercel/hono/-/hono-0.2.51.tgz", + "integrity": "sha512-iYEjjF4qR3gTZpVoB4sMQNm5OOdKw5/P2bL1CtolDTeGaea9KwqUrLyXmdK4N41HIRZr/wduID31mmHhSdC3sA==", "license": "Apache-2.0", "dependencies": { "@vercel/nft": "1.1.1", - "@vercel/node": "5.6.11", - "@vercel/static-config": "3.1.2", + "@vercel/node": "5.6.15", + "@vercel/static-config": "3.2.0", "fs-extra": "11.1.0", "path-to-regexp": "8.3.0", "ts-morph": "12.0.0", "zod": "3.22.4" } }, - "node_modules/@vercel/hono/node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, "node_modules/@vercel/hono/node_modules/@vercel/nft": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-1.1.1.tgz", @@ -10757,66 +10740,44 @@ } }, "node_modules/@vercel/hydrogen": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@vercel/hydrogen/-/hydrogen-1.3.5.tgz", - "integrity": "sha512-7EE6yVKcCnjMb1io9y069GkLyGyIzRbW3Krm3Q7EEfJ3P46h9xe9v/O5UhBoPrwtqDUHxmDngZp9YyfgY8IITA==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@vercel/hydrogen/-/hydrogen-1.3.6.tgz", + "integrity": "sha512-Ec8dKEjGIM4BfThcRLtQs5zaJ4+iJbgLZwkytwi7Blk8VrK6W2F1dtLDmVQYZdVnQcnmHmTx8mxUuMkfP06Mnw==", "license": "Apache-2.0", "dependencies": { - "@vercel/static-config": "3.1.2", + "@vercel/static-config": "3.2.0", "ts-morph": "12.0.0" } }, "node_modules/@vercel/koa": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/@vercel/koa/-/koa-0.1.27.tgz", - "integrity": "sha512-3fPAVVSMYRFhuz8BKh0yvDTmwp2q6KPodqYcNt10TvsMvU5RiQUVPxjgEUAS7a5dtI4J5lCGQ+7aG1Qeso8S+w==", + "version": "0.1.31", + "resolved": "https://registry.npmjs.org/@vercel/koa/-/koa-0.1.31.tgz", + "integrity": "sha512-Gj4sjqNA80/gnHpC0tRPCTtVEct69tUK21fsjVmawCa+nDNQ4bqXu3dSewna7GtCcp9KnrWgzAIaeVAQUl53mQ==", "license": "Apache-2.0", "dependencies": { - "@vercel/node": "5.6.11", - "@vercel/static-config": "3.1.2" + "@vercel/node": "5.6.15", + "@vercel/static-config": "3.2.0" } }, "node_modules/@vercel/nestjs": { - "version": "0.2.48", - "resolved": "https://registry.npmjs.org/@vercel/nestjs/-/nestjs-0.2.48.tgz", - "integrity": "sha512-bYdyQt0ew1nY5SGdkByXpwoDwBwtCwkyKBuxypc+bFeTksNkp09YnoUYo8ppqhGoXFre9ZEubvVLwIOGS1/aLw==", + "version": "0.2.52", + "resolved": "https://registry.npmjs.org/@vercel/nestjs/-/nestjs-0.2.52.tgz", + "integrity": "sha512-yfy4rpWJ1BRWZ1xBBPew0egVIblFe6G7laCKDzyESnbw19zY0F16g9HCu1H/0IfuKIQvOc95dtbmBsqLm9jyqw==", "license": "Apache-2.0", "dependencies": { - "@vercel/node": "5.6.11", - "@vercel/static-config": "3.1.2" + "@vercel/node": "5.6.15", + "@vercel/static-config": "3.2.0" } }, "node_modules/@vercel/next": { - "version": "4.15.41", - "resolved": "https://registry.npmjs.org/@vercel/next/-/next-4.15.41.tgz", - "integrity": "sha512-xOU0/AT5UJuSoO6huVnYqmBNoGApbflzujsAe55ypiHW34d+Auv0BuP3cYvFCVFlp/YR61q27O/T5HQajBd5qA==", + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@vercel/next/-/next-4.16.1.tgz", + "integrity": "sha512-gwy3XQRZ/f6RdKuC7BZIRMAzUOQf/R5+k9LMf1LcOm1CVZOLpDhDkeZMTG5vb3Lk9LWwBrJJ2ohhZaYuYEOHaw==", "license": "Apache-2.0", "dependencies": { "@vercel/nft": "1.1.1" } }, - "node_modules/@vercel/next/node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, "node_modules/@vercel/next/node_modules/@vercel/nft": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-1.1.1.tgz", @@ -10940,9 +10901,9 @@ } }, "node_modules/@vercel/nft": { - "version": "0.30.4", - "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.30.4.tgz", - "integrity": "sha512-wE6eAGSXScra60N2l6jWvNtVK0m+sh873CpfZW4KI2v8EHuUQp+mSEi4T+IcdPCSEDgCdAS/7bizbhQlkjzrSA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-1.3.2.tgz", + "integrity": "sha512-HC8venRc4Ya7vNeBsJneKHHMDDWpQie7VaKhAIOst3MKO+DES+Y/SbzSp8mFkD7OzwAE2HhHkeSuSmwS20mz3A==", "license": "MIT", "dependencies": { "@mapbox/node-pre-gyp": "^2.0.0", @@ -10952,7 +10913,7 @@ "async-sema": "^3.1.1", "bindings": "^1.4.0", "estree-walker": "2.0.2", - "glob": "^10.5.0", + "glob": "^13.0.0", "graceful-fs": "^4.2.9", "node-gyp-build": "^4.2.2", "picomatch": "^4.0.2", @@ -10962,29 +10923,28 @@ "nft": "out/cli.js" }, "engines": { - "node": ">=18" + "node": ">=20" } }, - "node_modules/@vercel/nft/node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "node_modules/@vercel/nft/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@vercel/nft/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" + "balanced-match": "^4.0.2" }, "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "node": "18 || 20 || >=22" } }, "node_modules/@vercel/nft/node_modules/estree-walker": { @@ -10993,6 +10953,63 @@ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "license": "MIT" }, + "node_modules/@vercel/nft/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vercel/nft/node_modules/lru-cache": { + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@vercel/nft/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vercel/nft/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@vercel/nft/node_modules/picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", @@ -11006,19 +11023,19 @@ } }, "node_modules/@vercel/node": { - "version": "5.6.11", - "resolved": "https://registry.npmjs.org/@vercel/node/-/node-5.6.11.tgz", - "integrity": "sha512-nzoS+ufkxpT4JxEzrjSA9vCEr4XzjCsHvGzi37+O+wajMldxsfcrvk9xHHuz1ZRzclwuPhcvLOMrs+ViJu63oA==", + "version": "5.6.15", + "resolved": "https://registry.npmjs.org/@vercel/node/-/node-5.6.15.tgz", + "integrity": "sha512-xc5fxmdk8jtuUY8y9/8W5UhTn8R1Ii1Fb3q+V8Zv+2moU9enrrBADA9ercHgE0/DtoiNDpb9Wmvnrb4bUcFOzA==", "license": "Apache-2.0", "dependencies": { "@edge-runtime/node-utils": "2.3.0", "@edge-runtime/primitives": "4.1.0", "@edge-runtime/vm": "3.2.0", "@types/node": "20.11.0", - "@vercel/build-utils": "13.6.3", + "@vercel/build-utils": "13.8.0", "@vercel/error-utils": "2.0.3", "@vercel/nft": "1.1.1", - "@vercel/static-config": "3.1.2", + "@vercel/static-config": "3.2.0", "async-listen": "3.0.0", "cjs-module-lexer": "1.2.3", "edge-runtime": "2.5.9", @@ -11451,28 +11468,6 @@ "node": ">=18" } }, - "node_modules/@vercel/node/node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, "node_modules/@vercel/node/node_modules/@types/node": { "version": "20.11.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.0.tgz", @@ -11705,31 +11700,27 @@ "license": "MIT" }, "node_modules/@vercel/oidc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-2.0.2.tgz", - "integrity": "sha512-59PBFx3T+k5hLTEWa3ggiMpGRz1OVvl9eN8SUai+A43IsqiOuAe7qPBf+cray/Fj6mkgnxm/D7IAtjc8zSHi7g==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.2.0.tgz", + "integrity": "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==", "license": "Apache-2.0", - "dependencies": { - "@types/ms": "2.1.0", - "ms": "2.1.3" - }, "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@vercel/python": { - "version": "6.20.2", - "resolved": "https://registry.npmjs.org/@vercel/python/-/python-6.20.2.tgz", - "integrity": "sha512-8RY+LlSDxOaCToLp77uPXn4cC1leoUIRdfLsq87wiIR8trnhUHIjHpBC39dm4B5MoyFPZPRLirIsBond4kB3RQ==", + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/@vercel/python/-/python-6.23.0.tgz", + "integrity": "sha512-P4cwbfk1zaVfX6obR3h+tEiuRIMX1cHyqmOlsbi9CBrHsxEbw45rtvXQLe29MErzUKO90kzbnQ4NbVQ8d4jt0g==", "license": "Apache-2.0", "dependencies": { - "@vercel/python-analysis": "0.8.2" + "@vercel/python-analysis": "0.9.1" } }, "node_modules/@vercel/python-analysis": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/@vercel/python-analysis/-/python-analysis-0.8.2.tgz", - "integrity": "sha512-tLYH5LydD3deJio2/T7FxMRuW0Vvqhlo0Fy24fgZBQipqpOE7aMODoKTulHx5Z1b/tFLCPOV8NkbpwOY0EVa5g==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@vercel/python-analysis/-/python-analysis-0.9.1.tgz", + "integrity": "sha512-ZwEi/F2DPxFPYmfjHFy7qM3+JTWRxD1EMpbIotNNhUyd/pnIG0wNt7S73RJSx62n1Y7pmFOFowoImnhULQgKvA==", "license": "Apache-2.0", "dependencies": { "@bytecodealliance/preview2-shim": "0.17.6", @@ -11737,7 +11728,7 @@ "fs-extra": "11.1.1", "js-yaml": "4.1.1", "minimatch": "10.1.1", - "pip-requirements-js": "1.0.2", + "pip-requirements-js": "1.0.3", "smol-toml": "1.5.2", "zod": "3.22.4" } @@ -11793,48 +11784,17 @@ } }, "node_modules/@vercel/redwood": { - "version": "2.4.9", - "resolved": "https://registry.npmjs.org/@vercel/redwood/-/redwood-2.4.9.tgz", - "integrity": "sha512-U7bYIuWfMEFMIcKKbX7lTT8pFNjig9Q3vLeCYRYQUrKVP8xLoUBXSEfW3ijtWJBUV8GmbZCDI30A16uUfNhN+g==", + "version": "2.4.10", + "resolved": "https://registry.npmjs.org/@vercel/redwood/-/redwood-2.4.10.tgz", + "integrity": "sha512-7C5lUn9g9kLm1KpX55b8iizVPOB6087+kVyQyKyXGk8bbkYySL26yb+LIwyL/7mXwHlq/JTC0AxVdC3nNmPZuw==", "license": "Apache-2.0", "dependencies": { "@vercel/nft": "1.1.1", - "@vercel/static-config": "3.1.2", + "@vercel/static-config": "3.2.0", "semver": "6.3.1", "ts-morph": "12.0.0" } }, - "node_modules/@vercel/redwood/node_modules/@isaacs/cliui": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz", - "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/@vercel/redwood/node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, "node_modules/@vercel/redwood/node_modules/@vercel/nft": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-1.1.1.tgz", @@ -11862,27 +11822,24 @@ } }, "node_modules/@vercel/redwood/node_modules/balanced-match": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.2.tgz", - "integrity": "sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "license": "MIT", - "dependencies": { - "jackspeak": "^4.2.3" - }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" } }, "node_modules/@vercel/redwood/node_modules/brace-expansion": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz", - "integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" } }, "node_modules/@vercel/redwood/node_modules/estree-walker": { @@ -11892,32 +11849,17 @@ "license": "MIT" }, "node_modules/@vercel/redwood/node_modules/glob": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.3.tgz", - "integrity": "sha512-/g3B0mC+4x724v1TgtBlBtt2hPi/EWptsIAmXUx9Z2rvBYleQcsrmaOzd5LyL50jf/Soi83ZDJmw2+XqvH/EeA==", - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.2.0", - "minipass": "^7.1.2", - "path-scurry": "^2.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@vercel/redwood/node_modules/jackspeak": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz", - "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==", + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/cliui": "^9.0.0" + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -11933,31 +11875,31 @@ } }, "node_modules/@vercel/redwood/node_modules/minimatch": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.0.tgz", - "integrity": "sha512-ugkC31VaVg9cF0DFVoADH12k6061zNZkZON+aX8AWsR9GhPcErkcMBceb6znR8wLERM2AkkOxy2nWRLpT9Jq5w==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "license": "BlueOak-1.0.0", "dependencies": { "brace-expansion": "^5.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@vercel/redwood/node_modules/path-scurry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", - "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -11976,41 +11918,19 @@ } }, "node_modules/@vercel/remix-builder": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@vercel/remix-builder/-/remix-builder-5.6.0.tgz", - "integrity": "sha512-neTpO4aGksYcPJjTbAEUhWmsOdFqgx02H47RUsXBKHdMTW4ZKrL9oAKT3pD+Bv9kUgj7uRzqAr8JeiPILPWybg==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@vercel/remix-builder/-/remix-builder-5.7.0.tgz", + "integrity": "sha512-R44EHl+PQjX5PrCmyGust+bk+65eT5omxOLhEIJkSI90Kx/vvuyKnFNic/Zwo//GCMjxt9httvQUr/6vIBbjHg==", "license": "Apache-2.0", "dependencies": { "@vercel/error-utils": "2.0.3", "@vercel/nft": "1.1.1", - "@vercel/static-config": "3.1.2", + "@vercel/static-config": "3.2.0", "path-to-regexp": "6.1.0", "path-to-regexp-updated": "npm:path-to-regexp@6.3.0", "ts-morph": "12.0.0" } }, - "node_modules/@vercel/remix-builder/node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, "node_modules/@vercel/remix-builder/node_modules/@vercel/nft": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-1.1.1.tgz", @@ -12047,9 +11967,9 @@ } }, "node_modules/@vercel/remix-builder/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -12134,9 +12054,9 @@ } }, "node_modules/@vercel/routing-utils": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@vercel/routing-utils/-/routing-utils-5.3.1.tgz", - "integrity": "sha512-HlqFRdB6Dm20xgEWtEatchf9X28NifweXPdDoEGyj5ItngaiqpywtkgkuiAk3xK9eAu2oXM36wEJbDDTxMblUg==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@vercel/routing-utils/-/routing-utils-5.3.3.tgz", + "integrity": "sha512-KYm2sLNUD48gDScv8ob4ejc3Gww2jcJyW80hTdYlenAPz/5BQar1Gyh38xrUuZ532TUwSb5mV1uRbAuiykq0EQ==", "license": "Apache-2.0", "dependencies": { "path-to-regexp": "6.1.0", @@ -12213,21 +12133,21 @@ "license": "ISC" }, "node_modules/@vercel/static-build": { - "version": "2.8.45", - "resolved": "https://registry.npmjs.org/@vercel/static-build/-/static-build-2.8.45.tgz", - "integrity": "sha512-eIQBLGzCTgCMGYS4wu4OSUMENFOR7yl8dzd7xURh/AnZ42ypAa5sKc7u85Z5MSY9G3o+1It/8cxlD1RDgQa/XA==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@vercel/static-build/-/static-build-2.9.0.tgz", + "integrity": "sha512-3SHWntz8swxL6ve750dY8kyl4NwVUplYtun/ei7y11q2UnI70WnWmm6L9fi02Wy1o3RGhbvOnlFLcHOUBm3DXQ==", "license": "Apache-2.0", "dependencies": { "@vercel/gatsby-plugin-vercel-analytics": "1.0.11", - "@vercel/gatsby-plugin-vercel-builder": "2.0.143", - "@vercel/static-config": "3.1.2", + "@vercel/gatsby-plugin-vercel-builder": "2.1.0", + "@vercel/static-config": "3.2.0", "ts-morph": "12.0.0" } }, "node_modules/@vercel/static-config": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@vercel/static-config/-/static-config-3.1.2.tgz", - "integrity": "sha512-2d+TXr6K30w86a+WbMbGm2W91O0UzO5VeemZYBBUJbCjk/5FLLGIi8aV6RS2+WmaRvtcqNTn2pUA7nCOK3bGcQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@vercel/static-config/-/static-config-3.2.0.tgz", + "integrity": "sha512-UpOEIgWxWx0M+mDe1IMdHS6JuWM/L5nNIJ4ixX8v9JgBAejymo88OkgnmfLCNMem0Wd+b5vcQPWLdZybCndlsA==", "license": "Apache-2.0", "dependencies": { "ajv": "8.6.3", @@ -12279,29 +12199,180 @@ } } }, + "node_modules/@vite-pwa/astro/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/@vite-pwa/astro/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/@vite-pwa/astro/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@vite-pwa/astro/node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/@vite-pwa/astro/node_modules/vite-plugin-pwa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-1.2.0.tgz", + "integrity": "sha512-a2xld+SJshT9Lgcv8Ji4+srFJL4k/1bVbd1x06JIkvecpQkwkvCncD1+gSzcdm3s+owWLpMJerG3aN5jupJEVw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.6", + "pretty-bytes": "^6.1.1", + "tinyglobby": "^0.2.10", + "workbox-build": "^7.4.0", + "workbox-window": "^7.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vite-pwa/assets-generator": "^1.0.0", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "workbox-build": "^7.4.0", + "workbox-window": "^7.4.0" + }, + "peerDependenciesMeta": { + "@vite-pwa/assets-generator": { + "optional": true + } + } + }, "node_modules/@vitest/coverage-v8": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz", - "integrity": "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.0.tgz", + "integrity": "sha512-nDWulKeik2bL2Va/Wl4x7DLuTKAXa906iRFooIRPR+huHkcvp9QDkPQ2RJdmjOFrqOqvNfoSQLF68deE3xC3CQ==", "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.0.18", - "ast-v8-to-istanbul": "^0.3.10", + "@vitest/utils": "4.1.0", + "ast-v8-to-istanbul": "^1.0.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.2.0", - "magicast": "^0.5.1", + "magicast": "^0.5.2", "obug": "^2.1.1", - "std-env": "^3.10.0", + "std-env": "^4.0.0-rc.1", "tinyrainbow": "^3.0.3" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "4.0.18", - "vitest": "4.0.18" + "@vitest/browser": "4.1.0", + "vitest": "4.1.0" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -12310,16 +12381,16 @@ } }, "node_modules/@vitest/expect": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", - "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.0.tgz", + "integrity": "sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==", "license": "MIT", "dependencies": { - "@standard-schema/spec": "^1.0.0", + "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "chai": "^6.2.1", + "@vitest/spy": "4.1.0", + "@vitest/utils": "4.1.0", + "chai": "^6.2.2", "tinyrainbow": "^3.0.3" }, "funding": { @@ -12327,12 +12398,12 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", - "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.0.tgz", + "integrity": "sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==", "license": "MIT", "dependencies": { - "@vitest/spy": "4.0.18", + "@vitest/spy": "4.1.0", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -12341,7 +12412,7 @@ }, "peerDependencies": { "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0-0" + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0" }, "peerDependenciesMeta": { "msw": { @@ -12353,9 +12424,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", - "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.0.tgz", + "integrity": "sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==", "license": "MIT", "dependencies": { "tinyrainbow": "^3.0.3" @@ -12365,31 +12436,26 @@ } }, "node_modules/@vitest/runner": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", - "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.0.tgz", + "integrity": "sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==", "license": "MIT", "dependencies": { - "@vitest/utils": "4.0.18", + "@vitest/utils": "4.1.0", "pathe": "^2.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/runner/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "license": "MIT" - }, "node_modules/@vitest/snapshot": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", - "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.0.tgz", + "integrity": "sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==", "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.18", + "@vitest/pretty-format": "4.1.0", + "@vitest/utils": "4.1.0", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -12397,28 +12463,23 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/snapshot/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "license": "MIT" - }, "node_modules/@vitest/spy": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", - "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.0.tgz", + "integrity": "sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==", "license": "MIT", "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/utils": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", - "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.0.tgz", + "integrity": "sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==", "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.18", + "@vitest/pretty-format": "4.1.0", + "convert-source-map": "^2.0.0", "tinyrainbow": "^3.0.3" }, "funding": { @@ -12556,9 +12617,9 @@ } }, "node_modules/@vtbag/utensil-drawer": { - "version": "1.2.15", - "resolved": "https://registry.npmjs.org/@vtbag/utensil-drawer/-/utensil-drawer-1.2.15.tgz", - "integrity": "sha512-qiNobbwTnpaX9o+Jxf/GZIBA/lMJdORHxsa3nTpIlKqYWoyBR6cvxEVpjNg60/ur1nzGAHULMQGnsR9IHNh/Ow==", + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@vtbag/utensil-drawer/-/utensil-drawer-1.2.16.tgz", + "integrity": "sha512-RSahZXk4NAFTF3zDYQH1x4qv8gFLcWus7qD//D0b58zoZIeqa2uKePLMy4lSHagYdkwBlKXKlfcDSrqUvWmxnw==", "license": "ISC", "funding": { "type": "github", @@ -12587,12 +12648,12 @@ } }, "node_modules/abbrev": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz", - "integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", + "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", "license": "ISC", "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/abort-controller": { @@ -14392,20 +14453,20 @@ "license": "MIT" }, "node_modules/ast-v8-to-istanbul": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.10.tgz", - "integrity": "sha512-p4K7vMz2ZSk3wN8l5o3y2bJAoZXT3VuJI5OLTATY/01CYWumWvwkUw0SqDBnNq6IiTO3qDa1eSQDibAV8g7XOQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz", + "integrity": "sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==", "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.31", "estree-walker": "^3.0.3", - "js-tokens": "^9.0.1" + "js-tokens": "^10.0.0" } }, "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", "license": "MIT" }, "node_modules/astral-regex": { @@ -14427,80 +14488,72 @@ } }, "node_modules/astro": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/astro/-/astro-5.18.0.tgz", - "integrity": "sha512-CHiohwJIS4L0G6/IzE1Fx3dgWqXBCXus/od0eGUfxrZJD2um2pE7ehclMmgL/fXqbU7NfE1Ze2pq34h2QaA6iQ==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/astro/-/astro-6.0.4.tgz", + "integrity": "sha512-1piLJCPTL/x7AMO2cjVFSTFyRqKuC3W8sSEySCt1aJio+p/wGs5H3K+Xr/rE9ftKtknLUtjxCqCE7/0NsXfGpQ==", "license": "MIT", "dependencies": { - "@astrojs/compiler": "^2.13.0", - "@astrojs/internal-helpers": "0.7.5", - "@astrojs/markdown-remark": "6.3.10", + "@astrojs/compiler": "^3.0.0", + "@astrojs/internal-helpers": "0.8.0", + "@astrojs/markdown-remark": "7.0.0", "@astrojs/telemetry": "3.3.0", "@capsizecss/unpack": "^4.0.0", + "@clack/prompts": "^1.0.1", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.3.0", - "acorn": "^8.15.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", - "boxen": "8.0.1", - "ci-info": "^4.3.1", + "ci-info": "^4.4.0", "clsx": "^2.1.1", - "common-ancestor-path": "^1.0.1", + "common-ancestor-path": "^2.0.0", "cookie": "^1.1.1", - "cssesc": "^3.0.0", - "debug": "^4.4.3", - "deterministic-object-hash": "^2.0.2", - "devalue": "^5.6.2", + "devalue": "^5.6.3", "diff": "^8.0.3", "dlv": "^1.1.3", "dset": "^3.1.4", - "es-module-lexer": "^1.7.0", + "es-module-lexer": "^2.0.0", "esbuild": "^0.27.3", - "estree-walker": "^3.0.3", "flattie": "^1.1.1", - "fontace": "~0.4.0", + "fontace": "~0.4.1", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", - "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "magic-string": "^0.30.21", - "magicast": "^0.5.1", + "magicast": "^0.5.2", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", - "p-limit": "^6.2.0", - "p-queue": "^8.1.1", + "obug": "^2.1.1", + "p-limit": "^7.3.0", + "p-queue": "^9.1.0", "package-manager-detector": "^1.6.0", "piccolore": "^0.1.3", "picomatch": "^4.0.3", - "prompts": "^2.4.2", "rehype": "^13.0.2", - "semver": "^7.7.3", - "shiki": "^3.21.0", + "semver": "^7.7.4", + "shiki": "^4.0.0", "smol-toml": "^1.6.0", "svgo": "^4.0.0", + "tinyclip": "^0.1.6", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", - "unifont": "~0.7.3", - "unist-util-visit": "^5.0.0", + "unifont": "~0.7.4", + "unist-util-visit": "^5.1.0", "unstorage": "^1.17.4", "vfile": "^6.0.3", - "vite": "^6.4.1", - "vitefu": "^1.1.1", + "vite": "^7.3.1", + "vitefu": "^1.1.2", "xxhash-wasm": "^1.1.0", - "yargs-parser": "^21.1.1", - "yocto-spinner": "^0.2.3", - "zod": "^3.25.76", - "zod-to-json-schema": "^3.25.1", - "zod-to-ts": "^1.2.0" + "yargs-parser": "^22.0.0", + "zod": "^4.3.6" }, "bin": { - "astro": "astro.js" + "astro": "bin/astro.mjs" }, "engines": { - "node": "18.20.8 || ^20.3.0 || >=22.0.0", + "node": "^20.19.1 || >=22.12.0", "npm": ">=9.6.5", "pnpm": ">=7.1.0" }, @@ -14613,527 +14666,28 @@ } }, "node_modules/astro-vtbot": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/astro-vtbot/-/astro-vtbot-2.1.11.tgz", - "integrity": "sha512-M0b2y2Kh4BcHryfY2dP+xrZOH2zYHEYM+x+1NFvCoK+g8iGRE/va6DxPN/zJ07IwWYjGl9PizLA0ZLJJl0a2sg==", + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/astro-vtbot/-/astro-vtbot-2.1.12.tgz", + "integrity": "sha512-6RlA0rdVPLT24FAyxsHAI71quTrLWuMXOADhcx8uEMTfuIVRhg4GajzmZmOiX6/nHA9p1gaIBuaTF3jVE1XWSA==", "license": "ISC", "dependencies": { "@vtbag/cam-shaft": "^1.0.6", "@vtbag/element-crossing": "^1.1.0", "@vtbag/inspection-chamber": "^1.0.24", "@vtbag/turn-signal": "^1.3.1", - "@vtbag/utensil-drawer": "^1.2.15" + "@vtbag/utensil-drawer": "^1.2.16" }, "funding": { "type": "github", "url": "https://github.com/sponsors/martrapp" } }, - "node_modules/astro/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", - "cpu": [ - "mips64el" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/astro/node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "node_modules/astro/node_modules/@astrojs/compiler": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-3.0.0.tgz", + "integrity": "sha512-MwAbDE5mawZ1SS+D8qWiHdprdME5Tlj2e0YjxnEICvcOpbSukNS7Sa7hA5PK+6RrmUr/t6Gi5YgrdZKjbO/WPQ==", "license": "MIT" }, - "node_modules/astro/node_modules/@shikijs/core": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.23.0.tgz", - "integrity": "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.23.0", - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4", - "hast-util-to-html": "^9.0.5" - } - }, - "node_modules/astro/node_modules/@shikijs/engine-javascript": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.23.0.tgz", - "integrity": "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.23.0", - "@shikijs/vscode-textmate": "^10.0.2", - "oniguruma-to-es": "^4.3.4" - } - }, - "node_modules/astro/node_modules/@shikijs/engine-oniguruma": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz", - "integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.23.0", - "@shikijs/vscode-textmate": "^10.0.2" - } - }, - "node_modules/astro/node_modules/@shikijs/langs": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz", - "integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.23.0" - } - }, - "node_modules/astro/node_modules/@shikijs/themes": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz", - "integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.23.0" - } - }, - "node_modules/astro/node_modules/@shikijs/types": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz", - "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==", - "license": "MIT", - "dependencies": { - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" - } - }, "node_modules/astro/node_modules/aria-query": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", @@ -15188,47 +14742,6 @@ "node": ">=0.3.1" } }, - "node_modules/astro/node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" - } - }, "node_modules/astro/node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -15266,6 +14779,34 @@ "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", "license": "CC0-1.0" }, + "node_modules/astro/node_modules/p-queue": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.1.0.tgz", + "integrity": "sha512-O/ZPaXuQV29uSLbxWBGGZO1mCQXV2BLIwUr59JUU9SoH76mnYvtms7aafH/isNSNGwuEfP6W/4xD0/TJXxrizw==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^7.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/astro/node_modules/p-timeout": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz", + "integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/astro/node_modules/picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", @@ -15279,9 +14820,9 @@ } }, "node_modules/astro/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -15290,22 +14831,6 @@ "node": ">=10" } }, - "node_modules/astro/node_modules/shiki": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.23.0.tgz", - "integrity": "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==", - "license": "MIT", - "dependencies": { - "@shikijs/core": "3.23.0", - "@shikijs/engine-javascript": "3.23.0", - "@shikijs/engine-oniguruma": "3.23.0", - "@shikijs/langs": "3.23.0", - "@shikijs/themes": "3.23.0", - "@shikijs/types": "3.23.0", - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" - } - }, "node_modules/astro/node_modules/svgo": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.0.tgz", @@ -15332,23 +14857,23 @@ } }, "node_modules/astro/node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -15357,14 +14882,14 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", - "less": "*", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" @@ -15405,479 +14930,13 @@ } } }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/astro/node_modules/vite/node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, + "node_modules/astro/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "license": "ISC", "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" - } - }, - "node_modules/astro/node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/astro/node_modules/zod-to-ts": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/zod-to-ts/-/zod-to-ts-1.2.0.tgz", - "integrity": "sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==", - "peerDependencies": { - "typescript": "^4.9.4 || ^5.0.2", - "zod": "^3" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/astrojs-compiler-sync": { @@ -16209,9 +15268,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", - "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "version": "2.10.7", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.7.tgz", + "integrity": "sha512-1ghYO3HnxGec0TCGBXiDLVns4eCSx4zJpxnHrlqFQajmhfKMQBzUGDdkMK7fUW7PTHTeLf+j87aTuKuuwWzMGw==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -16277,28 +15336,6 @@ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "license": "ISC" }, - "node_modules/boxen": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-8.0.1.tgz", - "integrity": "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==", - "license": "MIT", - "dependencies": { - "ansi-align": "^3.0.1", - "camelcase": "^8.0.0", - "chalk": "^5.3.0", - "cli-boxes": "^3.0.0", - "string-width": "^7.2.0", - "type-fest": "^4.21.0", - "widest-line": "^5.0.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/brace-expansion": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", @@ -16574,18 +15611,6 @@ "node": ">=6" } }, - "node_modules/camelcase": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", - "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/camelcase-keys": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-8.0.2.tgz", @@ -16817,16 +15842,16 @@ } }, "node_modules/chevrotain": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.1.tgz", - "integrity": "sha512-f0yv5CPKaFxfsPTBzX7vGuim4oIC1/gcS7LUGdBSwl2dU6+FON6LVUksdOo1qJjoUvXNn45urgh8C+0a24pACQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.2.tgz", + "integrity": "sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/cst-dts-gen": "11.1.1", - "@chevrotain/gast": "11.1.1", - "@chevrotain/regexp-to-ast": "11.1.1", - "@chevrotain/types": "11.1.1", - "@chevrotain/utils": "11.1.1", + "@chevrotain/cst-dts-gen": "11.1.2", + "@chevrotain/gast": "11.1.2", + "@chevrotain/regexp-to-ast": "11.1.2", + "@chevrotain/types": "11.1.2", + "@chevrotain/utils": "11.1.2", "lodash-es": "4.17.23" } }, @@ -16934,9 +15959,9 @@ } }, "node_modules/ci-info": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", - "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", "funding": [ { "type": "github", @@ -17155,10 +16180,13 @@ } }, "node_modules/common-ancestor-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", - "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", - "license": "ISC" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-2.0.0.tgz", + "integrity": "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">= 18" + } }, "node_modules/common-tags": { "version": "1.8.2", @@ -17843,9 +16871,9 @@ } }, "node_modules/d3-format": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", - "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", "license": "ISC", "engines": { "node": ">=12" @@ -18079,9 +17107,9 @@ } }, "node_modules/dagre-d3-es": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.13.tgz", - "integrity": "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", + "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", "license": "MIT", "dependencies": { "d3": "^7.9.0", @@ -19264,9 +18292,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "license": "MIT" }, "node_modules/es-object-atoms": { @@ -19358,9 +18386,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", + "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -19370,32 +18398,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" + "@esbuild/aix-ppc64": "0.27.4", + "@esbuild/android-arm": "0.27.4", + "@esbuild/android-arm64": "0.27.4", + "@esbuild/android-x64": "0.27.4", + "@esbuild/darwin-arm64": "0.27.4", + "@esbuild/darwin-x64": "0.27.4", + "@esbuild/freebsd-arm64": "0.27.4", + "@esbuild/freebsd-x64": "0.27.4", + "@esbuild/linux-arm": "0.27.4", + "@esbuild/linux-arm64": "0.27.4", + "@esbuild/linux-ia32": "0.27.4", + "@esbuild/linux-loong64": "0.27.4", + "@esbuild/linux-mips64el": "0.27.4", + "@esbuild/linux-ppc64": "0.27.4", + "@esbuild/linux-riscv64": "0.27.4", + "@esbuild/linux-s390x": "0.27.4", + "@esbuild/linux-x64": "0.27.4", + "@esbuild/netbsd-arm64": "0.27.4", + "@esbuild/netbsd-x64": "0.27.4", + "@esbuild/openbsd-arm64": "0.27.4", + "@esbuild/openbsd-x64": "0.27.4", + "@esbuild/openharmony-arm64": "0.27.4", + "@esbuild/sunos-x64": "0.27.4", + "@esbuild/win32-arm64": "0.27.4", + "@esbuild/win32-ia32": "0.27.4", + "@esbuild/win32-x64": "0.27.4" } }, "node_modules/escalade": { @@ -19463,17 +18491,17 @@ } }, "node_modules/eslint": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.0.2.tgz", - "integrity": "sha512-uYixubwmqJZH+KLVYIVKY1JQt7tysXhtj21WSvjcSmU5SVNzMus1bgLe+pAt816yQ8opKfheVVoPLqvVMGejYw==", + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.0.3.tgz", + "integrity": "sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", - "@eslint/config-array": "^0.23.2", + "@eslint/config-array": "^0.23.3", "@eslint/config-helpers": "^0.5.2", - "@eslint/core": "^1.1.0", - "@eslint/plugin-kit": "^0.6.0", + "@eslint/core": "^1.1.1", + "@eslint/plugin-kit": "^0.6.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -19482,7 +18510,7 @@ "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^9.1.1", + "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "espree": "^11.1.1", "esquery": "^1.7.0", @@ -19495,7 +18523,7 @@ "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "minimatch": "^10.2.1", + "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -19763,9 +18791,9 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "62.7.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.7.1.tgz", - "integrity": "sha512-4Zvx99Q7d1uggYBUX/AIjvoyqXhluGbbKrRmG8SQTLprPFg6fa293tVJH1o1GQwNe3lUydd8ZHzn37OaSncgSQ==", + "version": "62.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.8.0.tgz", + "integrity": "sha512-hu3r9/6JBmPG6wTcqtYzgZAnjEG2eqRUATfkFscokESg1VDxZM21ZaMire0KjeMwfj+SXvgB4Rvh5LBuesj92w==", "license": "BSD-3-Clause", "dependencies": { "@es-joy/jsdoccomment": "~0.84.0", @@ -19993,9 +19021,9 @@ } }, "node_modules/eslint/node_modules/eslint-scope": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.1.tgz", - "integrity": "sha512-GaUN0sWim5qc8KVErfPBWmc31LEsOkrUJbvJZV+xuL3u2phMUK4HIvXlWAakfC8W4nzlK+chPEAkYOYb5ZScIw==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", "license": "BSD-2-Clause", "dependencies": { "@types/esrecurse": "^4.3.1", @@ -20339,9 +19367,9 @@ "license": "MIT" }, "node_modules/expect-type": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", - "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", "license": "Apache-2.0", "engines": { "node": ">=12.0.0" @@ -20456,10 +19484,25 @@ ], "license": "BSD-3-Clause" }, + "node_modules/fast-xml-builder": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.3.tgz", + "integrity": "sha512-1o60KoFw2+LWKQu3IdcfcFlGTW4dpqEWmjhYec6H82AYZU2TVBXep6tMl8Z1Y+wM+ZrzCwe3BZ9Vyd9N2rIvmg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.1.3" + } + }, "node_modules/fast-xml-parser": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.8.tgz", - "integrity": "sha512-53jIF4N6u/pxvaL1eb/hEZts/cFLWZ92eCfLrNyCI0k38lettCG/Bs40W9pPwoPXyHQlKu2OUbQtiEIZK/J6Vw==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.4.1.tgz", + "integrity": "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A==", "funding": [ { "type": "github", @@ -20468,6 +19511,7 @@ ], "license": "MIT", "dependencies": { + "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { @@ -20671,18 +19715,18 @@ } }, "node_modules/fontace": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/fontace/-/fontace-0.4.0.tgz", - "integrity": "sha512-moThBCItUe2bjZip5PF/iZClpKHGLwMvR79Kp8XpGRBrvoRSnySN4VcILdv3/MJzbhvUA5WeiUXF5o538m5fvg==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/fontace/-/fontace-0.4.1.tgz", + "integrity": "sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==", "license": "MIT", "dependencies": { - "fontkitten": "^1.0.0" + "fontkitten": "^1.0.2" } }, "node_modules/fontkitten": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fontkitten/-/fontkitten-1.0.0.tgz", - "integrity": "sha512-b0RdzQeztiiUFWEDzq6Ka26qkNVNLCehoRtifOIGNbQ4CfxyYRh73fyWaQX/JshPVcueITOEeoSWPy5XQv8FUg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fontkitten/-/fontkitten-1.0.3.tgz", + "integrity": "sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==", "license": "MIT", "dependencies": { "tiny-inflate": "^1.0.3" @@ -21338,9 +20382,9 @@ "license": "MIT" }, "node_modules/happy-dom": { - "version": "20.8.3", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.8.3.tgz", - "integrity": "sha512-lMHQRRwIPyJ70HV0kkFT7jH/gXzSI7yDkQFe07E2flwmNDFoWUTRMKpW2sglsnpeA7b6S2TJPp98EbQxai8eaQ==", + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.8.4.tgz", + "integrity": "sha512-GKhjq4OQCYB4VLFBzv8mmccUadwlAusOZOI7hC1D9xDIT5HhzkJK17c4el2f6R6C715P9xB4uiMxeKUa2nHMwQ==", "license": "MIT", "dependencies": { "@types/node": ">=20.0.0", @@ -23373,9 +22417,9 @@ "license": "ISC" }, "node_modules/isomorphic-git": { - "version": "1.37.2", - "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.37.2.tgz", - "integrity": "sha512-HCQBBKmXIMPdHgYGstSBNp6MNmVcMQBbUqJF8xfywFmlpNseO4KKex59YlXqNxhRxmv3fUZwvNWvMyOdc1VvhA==", + "version": "1.37.4", + "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.37.4.tgz", + "integrity": "sha512-fNnCEJtI1refeVxysiuqGP9cubUoLibUS6UIDUWSy5Op6sVdFwGv/SpzfhMFiDkfgYoXKqurZ+LVxEeesy+T0Q==", "license": "MIT", "dependencies": { "async-lock": "^1.4.1", @@ -24032,9 +23076,9 @@ } }, "node_modules/libphonenumber-js": { - "version": "1.12.38", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.38.tgz", - "integrity": "sha512-vwzxmasAy9hZigxtqTbFEwp8ZdZ975TiqVDwj5bKx5sR+zi5ucUQy9mbVTkKM9GzqdLdxux/hTw2nmN5J7POMA==", + "version": "1.12.40", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.40.tgz", + "integrity": "sha512-HKGs7GowShNls3Zh+7DTr6wYpPk5jC78l508yQQY3e8ZgJChM3A9JZghmMJZuK+5bogSfuTafpjksGSR3aMIEg==", "license": "MIT" }, "node_modules/libsql": { @@ -25318,13 +24362,13 @@ } }, "node_modules/magicast": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.1.tgz", - "integrity": "sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", + "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "source-map-js": "^1.2.1" } }, @@ -26902,27 +25946,28 @@ } }, "node_modules/mermaid": { - "version": "11.12.3", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.3.tgz", - "integrity": "sha512-wN5ZSgJQIC+CHJut9xaKWsknLxaFBwCPwPkGTSUYrTiHORWvpT8RxGk849HPnpUAQ+/9BPRqYb80jTpearrHzQ==", + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.13.0.tgz", + "integrity": "sha512-fEnci+Immw6lKMFI8sqzjlATTyjLkRa6axrEgLV2yHTfv8r+h1wjFbV6xeRtd4rUV1cS4EpR9rwp3Rci7TRWDw==", "license": "MIT", "dependencies": { "@braintree/sanitize-url": "^7.1.1", - "@iconify/utils": "^3.0.1", - "@mermaid-js/parser": "^1.0.0", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^1.0.1", "@types/d3": "^7.4.3", - "cytoscape": "^3.29.3", + "@upsetjs/venn.js": "^2.0.0", + "cytoscape": "^3.33.1", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", - "dagre-d3-es": "7.0.13", - "dayjs": "^1.11.18", - "dompurify": "^3.2.5", - "katex": "^0.16.22", + "dagre-d3-es": "7.0.14", + "dayjs": "^1.11.19", + "dompurify": "^3.3.1", + "katex": "^0.16.25", "khroma": "^2.1.0", "lodash-es": "^4.17.23", - "marked": "^16.2.1", + "marked": "^16.3.0", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", @@ -28049,12 +27094,6 @@ "ufo": "^1.6.1" } }, - "node_modules/mlly/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "license": "MIT" - }, "node_modules/module-details-from-path": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", @@ -28436,27 +27475,27 @@ "license": "MIT" }, "node_modules/nodemailer": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.1.tgz", - "integrity": "sha512-5kcldIXmaEjZcHR6F28IKGSgpmZHaF1IXLWFTG+Xh3S+Cce4MiakLtWY+PlBU69fLbRa8HlaGIrC/QolUpHkhg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.2.tgz", + "integrity": "sha512-zbj002pZAIkWQFxyAaqoxvn+zoIwRnS40hgjqTXudKOOJkiFFgBeNqjgD3/YCR12sZnrghWYBY+yP1ZucdDRpw==", "license": "MIT-0", "engines": { "node": ">=6.0.0" } }, "node_modules/nopt": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-9.0.0.tgz", - "integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", "license": "ISC", "dependencies": { - "abbrev": "^4.0.0" + "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" }, "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/normalize-package-data": { @@ -28508,9 +27547,9 @@ } }, "node_modules/npm": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/npm/-/npm-11.11.0.tgz", - "integrity": "sha512-82gRxKrh/eY5UnNorkTFcdBQAGpgjWehkfGVqAGlJjejEtJZGGJUqjo3mbBTNbc5BTnPKGVtGPBZGhElujX5cw==", + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/npm/-/npm-11.11.1.tgz", + "integrity": "sha512-asazCodkFdz1ReQzukyzS/DD77uGCIqUFeRG3gtaT8b9UR0ne1m9QOBuMgT72ij1rt7TRrOox4A1WzntMWIuEg==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -28588,7 +27627,7 @@ ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^9.4.0", + "@npmcli/arborist": "^9.4.1", "@npmcli/config": "^10.7.1", "@npmcli/fs": "^5.0.0", "@npmcli/map-workspaces": "^5.0.3", @@ -28596,7 +27635,7 @@ "@npmcli/package-json": "^7.0.5", "@npmcli/promise-spawn": "^9.0.1", "@npmcli/redact": "^4.0.0", - "@npmcli/run-script": "^10.0.3", + "@npmcli/run-script": "^10.0.4", "@sigstore/tuf": "^4.0.1", "abbrev": "^4.0.0", "archy": "~1.0.0", @@ -28613,17 +27652,17 @@ "is-cidr": "^6.0.3", "json-parse-even-better-errors": "^5.0.0", "libnpmaccess": "^10.0.3", - "libnpmdiff": "^8.1.3", - "libnpmexec": "^10.2.3", - "libnpmfund": "^7.0.17", + "libnpmdiff": "^8.1.4", + "libnpmexec": "^10.2.4", + "libnpmfund": "^7.0.18", "libnpmorg": "^8.0.1", - "libnpmpack": "^9.1.3", + "libnpmpack": "^9.1.4", "libnpmpublish": "^11.1.3", "libnpmsearch": "^9.0.1", "libnpmteam": "^8.0.2", "libnpmversion": "^8.0.3", "make-fetch-happen": "^15.0.4", - "minimatch": "^10.2.2", + "minimatch": "^10.2.4", "minipass": "^7.1.3", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", @@ -28637,7 +27676,7 @@ "npm-registry-fetch": "^19.1.1", "npm-user-validate": "^4.0.0", "p-map": "^7.0.4", - "pacote": "^21.4.0", + "pacote": "^21.5.0", "parse-conflict-json": "^5.0.1", "proc-log": "^6.1.0", "qrcode-terminal": "^0.12.0", @@ -28646,7 +27685,7 @@ "spdx-expression-parse": "^4.0.0", "ssri": "^13.0.1", "supports-color": "^10.2.2", - "tar": "^7.5.9", + "tar": "^7.5.11", "text-table": "~0.2.0", "tiny-relative-date": "^2.0.2", "treeverse": "^3.0.0", @@ -28733,10 +27772,11 @@ } }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "9.4.0", + "version": "9.4.1", "inBundle": true, "license": "ISC", "dependencies": { + "@gar/promise-retry": "^1.0.0", "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^5.0.0", "@npmcli/installed-package-contents": "^4.0.0", @@ -28933,7 +27973,7 @@ } }, "node_modules/npm/node_modules/@npmcli/run-script": { - "version": "10.0.3", + "version": "10.0.4", "inBundle": true, "license": "ISC", "dependencies": { @@ -28941,8 +27981,7 @@ "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "node-gyp": "^12.1.0", - "proc-log": "^6.0.0", - "which": "^6.0.0" + "proc-log": "^6.0.0" }, "engines": { "node": "^20.17.0 || >=22.9.0" @@ -29097,7 +28136,7 @@ } }, "node_modules/npm/node_modules/brace-expansion": { - "version": "5.0.3", + "version": "5.0.4", "inBundle": true, "license": "MIT", "dependencies": { @@ -29451,11 +28490,11 @@ } }, "node_modules/npm/node_modules/libnpmdiff": { - "version": "8.1.3", + "version": "8.1.4", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^9.4.0", + "@npmcli/arborist": "^9.4.1", "@npmcli/installed-package-contents": "^4.0.0", "binary-extensions": "^3.0.0", "diff": "^8.0.2", @@ -29469,12 +28508,12 @@ } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "10.2.3", + "version": "10.2.4", "inBundle": true, "license": "ISC", "dependencies": { "@gar/promise-retry": "^1.0.0", - "@npmcli/arborist": "^9.4.0", + "@npmcli/arborist": "^9.4.1", "@npmcli/package-json": "^7.0.0", "@npmcli/run-script": "^10.0.0", "ci-info": "^4.0.0", @@ -29491,11 +28530,11 @@ } }, "node_modules/npm/node_modules/libnpmfund": { - "version": "7.0.17", + "version": "7.0.18", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^9.4.0" + "@npmcli/arborist": "^9.4.1" }, "engines": { "node": "^20.17.0 || >=22.9.0" @@ -29514,11 +28553,11 @@ } }, "node_modules/npm/node_modules/libnpmpack": { - "version": "9.1.3", + "version": "9.1.4", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^9.4.0", + "@npmcli/arborist": "^9.4.1", "@npmcli/run-script": "^10.0.0", "npm-package-arg": "^13.0.0", "pacote": "^21.0.2" @@ -29613,7 +28652,7 @@ } }, "node_modules/npm/node_modules/minimatch": { - "version": "10.2.2", + "version": "10.2.4", "inBundle": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -29923,7 +28962,7 @@ } }, "node_modules/npm/node_modules/pacote": { - "version": "21.4.0", + "version": "21.5.0", "inBundle": true, "license": "ISC", "dependencies": { @@ -30202,7 +29241,7 @@ } }, "node_modules/npm/node_modules/tar": { - "version": "7.5.9", + "version": "7.5.11", "inBundle": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -30347,11 +29386,10 @@ } }, "node_modules/npm/node_modules/write-file-atomic": { - "version": "7.0.0", + "version": "7.0.1", "inBundle": true, "license": "ISC", "dependencies": { - "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" }, "engines": { @@ -30726,15 +29764,15 @@ } }, "node_modules/p-limit": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", - "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.0.tgz", + "integrity": "sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw==", "license": "MIT", "dependencies": { - "yocto-queue": "^1.1.1" + "yocto-queue": "^1.2.1" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -31265,6 +30303,21 @@ "node": ">=8" } }, + "node_modules/path-expression-matcher": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.1.3.tgz", + "integrity": "sha512-qdVgY8KXmVdJZRSS1JdEPOKPdTiEK/pi0RkcT2sw1RhXxohdujUlJFPuS1TSkevZ9vzd3ZlL7ULl1MHGTApKzQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -31315,6 +30368,12 @@ "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", "license": "MIT" }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, "node_modules/pause-stream": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", @@ -31438,9 +30497,9 @@ } }, "node_modules/pip-requirements-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pip-requirements-js/-/pip-requirements-js-1.0.2.tgz", - "integrity": "sha512-awqoNOSOl4Blu4E4Hzp7jL0g8WKEhCwO+s7C2ibtIW3CAJMwspgoTXd4vnHd21UmhdrsI44Pn8FFSuA8QKrzvg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pip-requirements-js/-/pip-requirements-js-1.0.3.tgz", + "integrity": "sha512-1O9Bx0mPOZht3tW4LuxOA46qkD8A1AGymWXz3UwIMqGQgiTiOaFptsCf+9IE67qcbBrg8KHG6l8ePF7CoFRW/A==", "license": "MPL-2.0", "dependencies": { "ohm-js": "^17.1.0" @@ -31469,12 +30528,6 @@ "pathe": "^2.0.1" } }, - "node_modules/pkg-types/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "license": "MIT" - }, "node_modules/playwright": { "version": "1.58.2", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", @@ -31705,9 +30758,9 @@ } }, "node_modules/postcss-sorting": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-9.1.0.tgz", - "integrity": "sha512-Mn8KJ45HNNG6JBpBizXcyf6LqY/qyqetGcou/nprDnFwBFBLGj0j/sNKV2lj2KMOVOwdXu14aEzqJv8CIV6e8g==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-10.0.0.tgz", + "integrity": "sha512-TXbU+h6vVRW+86c/+ewhWq9k7pr7ijASTnepVhCQiC87zAOTkvB1v2dHyWP+ggstSTX/PNvjzS+IOqzejndz9w==", "license": "MIT", "peerDependencies": { "postcss": "^8.4.20" @@ -31759,9 +30812,9 @@ } }, "node_modules/preact": { - "version": "10.28.4", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.4.tgz", - "integrity": "sha512-uKFfOHWuSNpRFVTnljsCluEFq57OKT+0QdOiQo8XWnQ/pSvg7OpX5eNOejELXJMWy+BwM2nobz0FkvzmnpCNsQ==", + "version": "10.29.0", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.0.tgz", + "integrity": "sha512-wSAGyk2bYR1c7t3SZ3jHcM6xy0lcBcDel6lODcs9ME6Th++Dx2KU+6D3HD8wMMKGA8Wpw7OMd3/4RGzYRpzwRg==", "license": "MIT", "funding": { "type": "opencollective", @@ -31769,9 +30822,9 @@ } }, "node_modules/preact-render-to-string": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.6.3.tgz", - "integrity": "sha512-7oHG7jzjriqsFPkSPiPnzrQ0GcxFm6wOkYWNdStK5Ks9YlWSQQXKGBRAX4nKDdqX7HAQuRvI4pZNZMycK4WwDw==", + "version": "6.6.6", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.6.6.tgz", + "integrity": "sha512-EfqZJytnjJldV+YaaqhthU2oXsEf5e+6rDv957p+zxAvNfFLQOPfvBOTncscQ+akzu6Wrl7s3Pa0LjUQmWJsGQ==", "license": "MIT", "peerDependencies": { "preact": ">=10 || >= 11.0.0-0" @@ -31910,28 +30963,6 @@ "integrity": "sha512-V6TbZDJ/ZswevgkDNpGt/YqNCiZP9ASfgU+p83uJE6NrGtvSGoOcHLiDCqkMs2+yg7F5qHdLV8d0aS8O26G/KA==", "license": "MIT" }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prompts/node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/property-information": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", @@ -35567,17 +34598,17 @@ } }, "node_modules/shiki": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.0.1.tgz", - "integrity": "sha512-EkAEhDTN5WhpoQFXFw79OHIrSAfHhlImeCdSyg4u4XvrpxKEmdo/9x/HWSowujAnUrFsGOwWiE58a6GVentMnQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.0.2.tgz", + "integrity": "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==", "license": "MIT", "dependencies": { - "@shikijs/core": "4.0.1", - "@shikijs/engine-javascript": "4.0.1", - "@shikijs/engine-oniguruma": "4.0.1", - "@shikijs/langs": "4.0.1", - "@shikijs/themes": "4.0.1", - "@shikijs/types": "4.0.1", + "@shikijs/core": "4.0.2", + "@shikijs/engine-javascript": "4.0.2", + "@shikijs/engine-oniguruma": "4.0.2", + "@shikijs/langs": "4.0.2", + "@shikijs/themes": "4.0.2", + "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" }, @@ -35742,28 +34773,37 @@ "license": "MIT" }, "node_modules/sitemap": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-8.0.2.tgz", - "integrity": "sha512-LwktpJcyZDoa0IL6KT++lQ53pbSrx2c9ge41/SeLTyqy2XUNA6uR4+P9u5IVo5lPeL2arAcOKn1aZAxoYbCKlQ==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-9.0.1.tgz", + "integrity": "sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ==", "license": "MIT", "dependencies": { - "@types/node": "^17.0.5", + "@types/node": "^24.9.2", "@types/sax": "^1.2.1", "arg": "^5.0.0", "sax": "^1.4.1" }, "bin": { - "sitemap": "dist/cli.js" + "sitemap": "dist/esm/cli.js" }, "engines": { - "node": ">=14.0.0", - "npm": ">=6.0.0" + "node": ">=20.19.5", + "npm": ">=10.8.2" } }, "node_modules/sitemap/node_modules/@types/node": { - "version": "17.0.45", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "version": "24.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz", + "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/sitemap/node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, "node_modules/skin-tone": { @@ -36274,9 +35314,9 @@ } }, "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.0.0.tgz", + "integrity": "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==", "license": "MIT" }, "node_modules/stop-iteration-iterator": { @@ -36386,23 +35426,6 @@ "safe-buffer": "~5.2.0" } }, - "node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", @@ -36436,12 +35459,6 @@ "node": ">=8" } }, - "node_modules/string-width/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "license": "MIT" - }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -36647,9 +35664,9 @@ } }, "node_modules/strnum": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz", - "integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.0.tgz", + "integrity": "sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==", "funding": [ { "type": "github", @@ -36812,13 +35829,13 @@ } }, "node_modules/stylelint-order": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-7.0.1.tgz", - "integrity": "sha512-GWPei1zBVDDjxM+/BmcSCiOcHNd8rSqW6FUZtqQGlTRpD0Z5nSzspzWD8rtKif5KPdzUG68DApKEV/y/I9VbTw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-8.0.0.tgz", + "integrity": "sha512-1oAwPRz6Ba8u9LPjgvdbeMjZszHhjY6DBBK+xMlS3IC89GdTsvAPpGYvW+dkn6pxc4ZaI1S959g4c8CftZbhIg==", "license": "MIT", "dependencies": { - "postcss": "^8.5.6", - "postcss-sorting": "^9.1.0" + "postcss": "^8.5.8", + "postcss-sorting": "^10.0.0" }, "engines": { "node": ">=20.19.0" @@ -37385,12 +36402,12 @@ } }, "node_modules/timezones-ical-library": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/timezones-ical-library/-/timezones-ical-library-2.1.2.tgz", - "integrity": "sha512-VW7gTRzrveUNdLaztWKlsgHRn1eagubRA/HHembnrh9xYDtDRwRWN+zWcNIE3QM+TpXikSJLp/jwxYQv7IJJvg==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/timezones-ical-library/-/timezones-ical-library-2.1.3.tgz", + "integrity": "sha512-3ihogrr88TefPpa2og2fHw22VsWxlPUN4YDiLZRV9pbRsmguMyDsHhm8i0kkj7ihQYFgERZkj6eVOYY+TSOaOw==", "license": "Apache-2.0", "engines": { - "node": ">=22.20.0", + "node": ">=22.18.0", "npm": ">=10.9.3" } }, @@ -37406,6 +36423,15 @@ "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "license": "MIT" }, + "node_modules/tinyclip": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-0.1.12.tgz", + "integrity": "sha512-Ae3OVUqifDw0wBriIBS7yVaW44Dp6eSHQcyq4Igc7eN2TJH/2YsicswaW+J/OuMvhpDPOKEgpAZCjkb4hpoyeA==", + "license": "MIT", + "engines": { + "node": "^16.14.0 || >= 17.3.0" + } + }, "node_modules/tinycolor2": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", @@ -37813,463 +36839,6 @@ "fsevents": "~2.3.3" } }, - "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", - "cpu": [ - "mips64el" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" - } - }, "node_modules/tsx/node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -38462,15 +37031,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.56.1.tgz", - "integrity": "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.0.tgz", + "integrity": "sha512-W8GcigEMEeB07xEZol8oJ26rigm3+bfPHxHvwbYUlu1fUDsGuQ7Hiskx5xGW/xM4USc9Ephe3jtv7ZYPQntHeA==", "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.56.1", - "@typescript-eslint/parser": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/utils": "8.56.1" + "@typescript-eslint/eslint-plugin": "8.57.0", + "@typescript-eslint/parser": "8.57.0", + "@typescript-eslint/typescript-estree": "8.57.0", + "@typescript-eslint/utils": "8.57.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -38952,9 +37521,9 @@ } }, "node_modules/unifont": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.3.tgz", - "integrity": "sha512-b0GtQzKCyuSHGsfj5vyN8st7muZ6VCI4XD4vFlr7Uy1rlWVYxC3npnfk8MyreHxJYrz1ooLDqDzFe9XqQTlAhA==", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.4.tgz", + "integrity": "sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==", "license": "MIT", "dependencies": { "css-tree": "^3.1.0", @@ -39586,33 +38155,33 @@ } }, "node_modules/vercel": { - "version": "50.28.0", - "resolved": "https://registry.npmjs.org/vercel/-/vercel-50.28.0.tgz", - "integrity": "sha512-h4J4Xv04oxNIdS6Bp72GbXRC1N1cJN6q5uTe7CBMjPxZ/Usg4twn+l716X4ZxHro1AydjJa2iuAsIxjudjeYsg==", + "version": "50.32.5", + "resolved": "https://registry.npmjs.org/vercel/-/vercel-50.32.5.tgz", + "integrity": "sha512-gwxkUgVLQGSUV3EgsJa3rbBXDgoKIjp73bxEgZm+BgSRDSG8sMJD1shozgu5NI+Od8HkzvsZBIX5c2XOsLH8+w==", "license": "Apache-2.0", "dependencies": { - "@vercel/backends": "0.0.41", + "@vercel/backends": "0.0.45", "@vercel/blob": "2.3.0", - "@vercel/build-utils": "13.6.3", - "@vercel/detect-agent": "1.1.0", - "@vercel/elysia": "0.1.44", - "@vercel/express": "0.1.53", - "@vercel/fastify": "0.1.47", + "@vercel/build-utils": "13.8.0", + "@vercel/detect-agent": "1.2.1", + "@vercel/elysia": "0.1.48", + "@vercel/express": "0.1.57", + "@vercel/fastify": "0.1.51", "@vercel/fun": "1.3.0", - "@vercel/go": "3.4.3", - "@vercel/h3": "0.1.53", - "@vercel/hono": "0.2.47", - "@vercel/hydrogen": "1.3.5", - "@vercel/koa": "0.1.27", - "@vercel/nestjs": "0.2.48", - "@vercel/next": "4.15.41", - "@vercel/node": "5.6.11", - "@vercel/python": "6.20.2", - "@vercel/redwood": "2.4.9", - "@vercel/remix-builder": "5.6.0", + "@vercel/go": "3.4.5", + "@vercel/h3": "0.1.57", + "@vercel/hono": "0.2.51", + "@vercel/hydrogen": "1.3.6", + "@vercel/koa": "0.1.31", + "@vercel/nestjs": "0.2.52", + "@vercel/next": "4.16.1", + "@vercel/node": "5.6.15", + "@vercel/python": "6.23.0", + "@vercel/redwood": "2.4.10", + "@vercel/remix-builder": "5.7.0", "@vercel/ruby": "2.3.2", "@vercel/rust": "1.0.5", - "@vercel/static-build": "2.8.45", + "@vercel/static-build": "2.9.0", "chokidar": "4.0.0", "esbuild": "0.27.0", "form-data": "^4.0.0", @@ -40494,16 +39063,16 @@ } }, "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.0.tgz", + "integrity": "sha512-fPGaRNj9Zytaf8LEiBhY7Z6ijnFKdzU/+mL8EFBaKr7Vw1/FWcTBAMW0wLPJAGMPX38ZPVCVgLceWiEqeoqL2Q==", "license": "MIT", "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", + "@oxc-project/runtime": "0.115.0", + "lightningcss": "^1.32.0", "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", + "postcss": "^8.5.8", + "rolldown": "1.0.0-rc.9", "tinyglobby": "^0.2.15" }, "bin": { @@ -40520,9 +39089,10 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.0.0-alpha.31", + "esbuild": "^0.27.0", "jiti": ">=1.21.0", "less": "^4.0.0", - "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", @@ -40535,13 +39105,16 @@ "@types/node": { "optional": true }, - "jiti": { + "@vitejs/devtools": { "optional": true }, - "less": { + "esbuild": { "optional": true }, - "lightningcss": { + "jiti": { + "optional": true + }, + "less": { "optional": true }, "sass": { @@ -40567,75 +39140,37 @@ } } }, - "node_modules/vite-plugin-pwa": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-1.2.0.tgz", - "integrity": "sha512-a2xld+SJshT9Lgcv8Ji4+srFJL4k/1bVbd1x06JIkvecpQkwkvCncD1+gSzcdm3s+owWLpMJerG3aN5jupJEVw==", + "node_modules/vite/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", + "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", "license": "MIT", + "optional": true, "dependencies": { - "debug": "^4.3.6", - "pretty-bytes": "^6.1.1", - "tinyglobby": "^0.2.10", - "workbox-build": "^7.4.0", - "workbox-window": "^7.4.0" - }, - "engines": { - "node": ">=16.0.0" + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" }, "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vite-pwa/assets-generator": "^1.0.0", - "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", - "workbox-build": "^7.4.0", - "workbox-window": "^7.4.0" - }, - "peerDependenciesMeta": { - "@vite-pwa/assets-generator": { - "optional": true - } - } - }, - "node_modules/vite-prerender-plugin": { - "version": "0.5.12", - "resolved": "https://registry.npmjs.org/vite-prerender-plugin/-/vite-prerender-plugin-0.5.12.tgz", - "integrity": "sha512-EiwhbMn+flg14EysbLTmZSzq8NGTxhytgK3bf4aGRF1evWLGwZiHiUJ1KZDvbxgKbMf2pG6fJWGEa3UZXOnR1g==", - "license": "MIT", - "dependencies": { - "kolorist": "^1.8.0", - "magic-string": "0.x >= 0.26.0", - "node-html-parser": "^6.1.12", - "simple-code-frame": "^1.3.0", - "source-map": "^0.7.4", - "stack-trace": "^1.0.0-pre2" - }, - "peerDependencies": { - "vite": "5.x || 6.x || 7.x" + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.1.tgz", - "integrity": "sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==", - "cpu": [ - "ppc64" - ], + "node_modules/vite/node_modules/@oxc-project/types": { + "version": "0.115.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.115.0.tgz", + "integrity": "sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==", "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" + "funding": { + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.1.tgz", - "integrity": "sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==", + "node_modules/vite/node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.9.tgz", + "integrity": "sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==", "cpu": [ - "arm" + "arm64" ], "license": "MIT", "optional": true, @@ -40643,111 +39178,111 @@ "android" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.1.tgz", - "integrity": "sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==", + "node_modules/vite/node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.9.tgz", + "integrity": "sha512-J7Zk3kLYFsLtuH6U+F4pS2sYVzac0qkjcO5QxHS7OS7yZu2LRs+IXo+uvJ/mvpyUljDJ3LROZPoQfgBIpCMhdQ==", "cpu": [ "arm64" ], "license": "MIT", "optional": true, "os": [ - "android" + "darwin" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.1.tgz", - "integrity": "sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==", + "node_modules/vite/node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.9.tgz", + "integrity": "sha512-iwtmmghy8nhfRGeNAIltcNXzD0QMNaaA5U/NyZc1Ia4bxrzFByNMDoppoC+hl7cDiUq5/1CnFthpT9n+UtfFyg==", "cpu": [ "x64" ], "license": "MIT", "optional": true, "os": [ - "android" + "darwin" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.1.tgz", - "integrity": "sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==", + "node_modules/vite/node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.9.tgz", + "integrity": "sha512-DLFYI78SCiZr5VvdEplsVC2Vx53lnA4/Ga5C65iyldMVaErr86aiqCoNBLl92PXPfDtUYjUh+xFFor40ueNs4Q==", "cpu": [ - "arm64" + "x64" ], "license": "MIT", "optional": true, "os": [ - "darwin" + "freebsd" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.1.tgz", - "integrity": "sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==", + "node_modules/vite/node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.9.tgz", + "integrity": "sha512-CsjTmTwd0Hri6iTw/DRMK7kOZ7FwAkrO4h8YWKoX/kcj833e4coqo2wzIFywtch/8Eb5enQ/lwLM7w6JX1W5RQ==", "cpu": [ - "x64" + "arm" ], "license": "MIT", "optional": true, "os": [ - "darwin" + "linux" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.1.tgz", - "integrity": "sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==", + "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg==", "cpu": [ "arm64" ], "license": "MIT", "optional": true, "os": [ - "freebsd" + "linux" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.1.tgz", - "integrity": "sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==", + "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.9.tgz", + "integrity": "sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==", "cpu": [ - "x64" + "arm64" ], "license": "MIT", "optional": true, "os": [ - "freebsd" + "linux" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.1.tgz", - "integrity": "sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==", + "node_modules/vite/node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==", "cpu": [ - "arm" + "x64" ], "license": "MIT", "optional": true, @@ -40755,15 +39290,15 @@ "linux" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.1.tgz", - "integrity": "sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==", + "node_modules/vite/node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.9.tgz", + "integrity": "sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==", "cpu": [ - "arm64" + "x64" ], "license": "MIT", "optional": true, @@ -40771,335 +39306,340 @@ "linux" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.1.tgz", - "integrity": "sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==", + "node_modules/vite/node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.9.tgz", + "integrity": "sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog==", "cpu": [ - "ia32" + "arm64" ], "license": "MIT", "optional": true, "os": [ - "linux" + "openharmony" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.1.tgz", - "integrity": "sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==", + "node_modules/vite/node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.9.tgz", + "integrity": "sha512-rgFN6sA/dyebil3YTlL2evvi/M+ivhfnyxec7AccTpRPccno/rPoNlqybEZQBkcbZu8Hy+eqNJCqfBR8P7Pg8g==", "cpu": [ - "loong64" + "wasm32" ], "license": "MIT", "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, "engines": { - "node": ">=18" + "node": ">=14.0.0" } }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.1.tgz", - "integrity": "sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==", + "node_modules/vite/node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.9.tgz", + "integrity": "sha512-lHVNUG/8nlF1IQk1C0Ci574qKYyty2goMiPlRqkC5R+3LkXDkL5Dhx8ytbxq35m+pkHVIvIxviD+TWLdfeuadA==", "cpu": [ - "mips64el" + "arm64" ], "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.1.tgz", - "integrity": "sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==", + "node_modules/vite/node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.9.tgz", + "integrity": "sha512-G0oA4+w1iY5AGi5HcDTxWsoxF509hrFIPB2rduV5aDqS9FtDg1CAfa7V34qImbjfhIcA8C+RekocJZA96EarwQ==", "cpu": [ - "ppc64" + "x64" ], "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.1.tgz", - "integrity": "sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==", - "cpu": [ - "riscv64" - ], + "node_modules/vite/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.9.tgz", + "integrity": "sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==", + "license": "MIT" + }, + "node_modules/vite/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" ], "engines": { - "node": ">=18" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.1.tgz", - "integrity": "sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==", + "node_modules/vite/node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/vite/node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", "cpu": [ - "s390x" + "arm64" ], - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "linux" + "android" ], "engines": { - "node": ">=18" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.1.tgz", - "integrity": "sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==", + "node_modules/vite/node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", "cpu": [ - "x64" + "arm64" ], - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "linux" + "darwin" ], "engines": { - "node": ">=18" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.1.tgz", - "integrity": "sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==", + "node_modules/vite/node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", "cpu": [ - "arm64" + "x64" ], - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "netbsd" + "darwin" ], "engines": { - "node": ">=18" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.1.tgz", - "integrity": "sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==", + "node_modules/vite/node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", "cpu": [ "x64" ], - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "netbsd" + "freebsd" ], "engines": { - "node": ">=18" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.1.tgz", - "integrity": "sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==", + "node_modules/vite/node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", "cpu": [ - "arm64" + "arm" ], - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "openbsd" + "linux" ], "engines": { - "node": ">=18" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.1.tgz", - "integrity": "sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==", + "node_modules/vite/node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", "cpu": [ - "x64" + "arm64" ], - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "openbsd" + "linux" ], "engines": { - "node": ">=18" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.1.tgz", - "integrity": "sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==", + "node_modules/vite/node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", "cpu": [ "arm64" ], - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "openharmony" + "linux" ], "engines": { - "node": ">=18" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.1.tgz", - "integrity": "sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==", + "node_modules/vite/node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", "cpu": [ "x64" ], - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "sunos" + "linux" ], "engines": { - "node": ">=18" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.1.tgz", - "integrity": "sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==", + "node_modules/vite/node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", "cpu": [ - "arm64" + "x64" ], - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "win32" + "linux" ], "engines": { - "node": ">=18" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.1.tgz", - "integrity": "sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==", + "node_modules/vite/node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", "cpu": [ - "ia32" + "arm64" ], - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=18" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.1.tgz", - "integrity": "sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==", + "node_modules/vite/node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", "cpu": [ "x64" ], - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.1.tgz", - "integrity": "sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.1", - "@esbuild/android-arm": "0.27.1", - "@esbuild/android-arm64": "0.27.1", - "@esbuild/android-x64": "0.27.1", - "@esbuild/darwin-arm64": "0.27.1", - "@esbuild/darwin-x64": "0.27.1", - "@esbuild/freebsd-arm64": "0.27.1", - "@esbuild/freebsd-x64": "0.27.1", - "@esbuild/linux-arm": "0.27.1", - "@esbuild/linux-arm64": "0.27.1", - "@esbuild/linux-ia32": "0.27.1", - "@esbuild/linux-loong64": "0.27.1", - "@esbuild/linux-mips64el": "0.27.1", - "@esbuild/linux-ppc64": "0.27.1", - "@esbuild/linux-riscv64": "0.27.1", - "@esbuild/linux-s390x": "0.27.1", - "@esbuild/linux-x64": "0.27.1", - "@esbuild/netbsd-arm64": "0.27.1", - "@esbuild/netbsd-x64": "0.27.1", - "@esbuild/openbsd-arm64": "0.27.1", - "@esbuild/openbsd-x64": "0.27.1", - "@esbuild/openharmony-arm64": "0.27.1", - "@esbuild/sunos-x64": "0.27.1", - "@esbuild/win32-arm64": "0.27.1", - "@esbuild/win32-ia32": "0.27.1", - "@esbuild/win32-x64": "0.27.1" - } - }, - "node_modules/vite/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" + "node": ">= 12.0.0" }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, "node_modules/vite/node_modules/picomatch": { @@ -41114,10 +39654,43 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/vite/node_modules/rolldown": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.9.tgz", + "integrity": "sha512-9EbgWge7ZH+yqb4d2EnELAntgPTWbfL8ajiTW+SyhJEC4qhBbkCKbqFV4Ge4zmu5ziQuVbWxb/XwLZ+RIO7E8Q==", + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.115.0", + "@rolldown/pluginutils": "1.0.0-rc.9" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.9", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.9", + "@rolldown/binding-darwin-x64": "1.0.0-rc.9", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.9", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.9", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.9", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.9", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.9", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.9", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.9", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.9", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.9", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.9", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.9", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.9" + } + }, "node_modules/vitefu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz", - "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.2.tgz", + "integrity": "sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==", "license": "MIT", "workspaces": [ "tests/deps/*", @@ -41125,7 +39698,7 @@ "tests/projects/workspace/packages/*" ], "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0" }, "peerDependenciesMeta": { "vite": { @@ -41134,30 +39707,30 @@ } }, "node_modules/vitest": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", - "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", - "license": "MIT", - "dependencies": { - "@vitest/expect": "4.0.18", - "@vitest/mocker": "4.0.18", - "@vitest/pretty-format": "4.0.18", - "@vitest/runner": "4.0.18", - "@vitest/snapshot": "4.0.18", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "es-module-lexer": "^1.7.0", - "expect-type": "^1.2.2", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.0.tgz", + "integrity": "sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==", + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.0", + "@vitest/mocker": "4.1.0", + "@vitest/pretty-format": "4.1.0", + "@vitest/runner": "4.1.0", + "@vitest/snapshot": "4.1.0", + "@vitest/spy": "4.1.0", + "@vitest/utils": "4.1.0", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", - "std-env": "^3.10.0", + "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.0.3", - "vite": "^6.0.0 || ^7.0.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0", "why-is-node-running": "^2.3.0" }, "bin": { @@ -41173,12 +39746,13 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.0.18", - "@vitest/browser-preview": "4.0.18", - "@vitest/browser-webdriverio": "4.0.18", - "@vitest/ui": "4.0.18", + "@vitest/browser-playwright": "4.1.0", + "@vitest/browser-preview": "4.1.0", + "@vitest/browser-webdriverio": "4.1.0", + "@vitest/ui": "4.1.0", "happy-dom": "*", - "jsdom": "*" + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0" }, "peerDependenciesMeta": { "@edge-runtime/vm": { @@ -41207,6 +39781,9 @@ }, "jsdom": { "optional": true + }, + "vite": { + "optional": false } } }, @@ -41227,12 +39804,6 @@ "vitest": ">=0.16.0" } }, - "node_modules/vitest/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "license": "MIT" - }, "node_modules/vitest/node_modules/picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", @@ -41725,21 +40296,6 @@ "integrity": "sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==", "license": "MIT" }, - "node_modules/widest-line": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz", - "integrity": "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==", - "license": "MIT", - "dependencies": { - "string-width": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/wildcard": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-1.1.2.tgz", @@ -42203,23 +40759,6 @@ "workbox-core": "7.4.0" } }, - "node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", @@ -42285,18 +40824,6 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -42681,33 +41208,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yocto-spinner": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-0.2.3.tgz", - "integrity": "sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==", - "license": "MIT", - "dependencies": { - "yoctocolors": "^2.1.1" - }, - "engines": { - "node": ">=18.19" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yoctocolors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", - "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/zod": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", @@ -42717,15 +41217,6 @@ "url": "https://github.com/sponsors/colinhacks" } }, - "node_modules/zod-to-json-schema": { - "version": "3.25.1", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", - "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.25 || ^4" - } - }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/package.json b/package.json index b65d388f3..61f89cbfb 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ }, "private": "true", "engines": { - "node": ">=22.0.0 <23.0.0", + "node": ">=24.0.0 <25.0.0", "npm": ">=10.0.0" }, "type": "module", @@ -67,29 +67,29 @@ }, "dependencies": { "@adobe/remark-gridtables": "^3.0.18", - "@astrojs/check": "0.9.6", - "@astrojs/db": "^0.19.0", - "@astrojs/mdx": "4.3.13", - "@astrojs/preact": "4.1.3", - "@astrojs/rss": "4.0.15", - "@astrojs/sitemap": "^3.7.0", - "@astrojs/vercel": "^9.0.4", + "@astrojs/check": "0.9.7", + "@astrojs/db": "^0.20.0", + "@astrojs/mdx": "5.0.0", + "@astrojs/preact": "5.0.0", + "@astrojs/rss": "4.0.17", + "@astrojs/sitemap": "^3.7.1", + "@astrojs/vercel": "^10.0.0", "@axe-core/playwright": "^4.11.1", "@eslint-community/eslint-plugin-eslint-comments": "^4.7.1", "@eslint/js": "10.0.1", "@github/relative-time-element": "^5.0.0", "@glidejs/glide": "^3.7.1", "@googlemaps/extended-component-library": "^0.6.14", - "@happy-dom/global-registrator": "^20.8.3", + "@happy-dom/global-registrator": "^20.8.4", "@lighthousejs/types": "^0.0.3", "@nanostores/lit": "^0.2.3", "@nanostores/persistent": "^1.3.3", "@playwright/browser-chromium": "^1.58.2", "@playwright/test": "1.58.2", - "@semantic-ui/astro-lit": "^5.1.1", - "@sentry/astro": "^10.42.0", - "@sentry/browser": "^10.42.0", - "@shikijs/transformers": "^4.0.1", + "@semantic-ui/astro-lit": "^5.1.2", + "@sentry/astro": "^10.43.0", + "@sentry/browser": "^10.43.0", + "@shikijs/transformers": "^4.0.2", "@tailwindcss/forms": "0.5.11", "@tailwindcss/typography": "0.5.19", "@tailwindcss/vite": "^4.2.1", @@ -106,14 +106,14 @@ "@types/hast": "^3.0.4", "@types/js-cookie": "^3.0.6", "@types/jsdom": "^28.0.0", - "@types/node": "^25.3.3", + "@types/node": "^25.5.0", "@types/nodemailer": "^7.0.11", "@types/pubsub-js": "^1.8.6", "@types/react": "^19.2.14", - "@types/sanitize-html": "^2.16.0", + "@types/sanitize-html": "^2.16.1", "@types/to-ico": "1.1.3", - "@typescript-eslint/eslint-plugin": "8.56.1", - "@typescript-eslint/parser": "8.56.1", + "@typescript-eslint/eslint-plugin": "8.57.0", + "@typescript-eslint/parser": "8.57.0", "@ungap/structured-clone": "^1.3.0", "@uppy/audio": "^3.1.0", "@uppy/box": "^4.1.0", @@ -124,16 +124,16 @@ "@uppy/onedrive": "^5.1.0", "@uppy/webcam": "^5.1.0", "@upstash/search": "^0.1.7", - "@vercel/analytics": "^1.6.1", + "@vercel/analytics": "^2.0.1", "@vite-pwa/astro": "^1.2.0", - "@vitest/coverage-v8": "^4.0.18", + "@vitest/coverage-v8": "^4.1.0", "@webcomponents/template-shadowroot": "^0.2.1", "alex": "^11.0.1", - "astro": "5.18.0", + "astro": "6.0.4", "astro-link-validator": "github:rodgtr1/astro-link-validator", "astro-og-canvas": "^0.10.1", - "astro-vtbot": "^2.1.11", - "baseline-browser-mapping": "^2.10.0", + "astro-vtbot": "^2.1.12", + "baseline-browser-mapping": "^2.10.7", "canvas-confetti": "^1.9.4", "confusing-browser-globals": "1.0.11", "cross-env": "^10.1.0", @@ -144,39 +144,39 @@ "email-validator": "^2.0.4", "embla-carousel": "^8.6.0", "embla-carousel-autoplay": "^8.6.0", - "eslint": "10.0.2", + "eslint": "10.0.3", "eslint-import-resolver-typescript": "^4.4.4", "eslint-plugin-astro": "1.6.0", "eslint-plugin-import": "2.32.0", - "eslint-plugin-jsdoc": "62.7.1", + "eslint-plugin-jsdoc": "62.8.0", "eslint-plugin-jsx-a11y": "6.10.2", "eslint-plugin-security": "4.0.0", "eslint-plugin-yml": "3.3.1", "focus-trap": "8.0.0", "gsap": "^3.14.2", - "happy-dom": "^20.8.3", + "happy-dom": "^20.8.4", "hast-util-heading-rank": "^3.0.0", "hast-util-is-element": "^3.0.0", "html-element-attributes": "^3.5.0", "husky": "^9.1.7", "install": "^0.13.0", "is-whitespace-character": "^2.0.1", - "isomorphic-git": "^1.37.2", + "isomorphic-git": "^1.37.4", "js-cookie": "^3.0.5", "jsdom": "^28.1.0", - "libphonenumber-js": "1.12.38", + "libphonenumber-js": "1.12.40", "lighthouse": "^13.0.3", "lit": "^3.3.2", "markdownlint-cli2": "^0.21.0", "md-attr-parser": "^1.3.0", - "mermaid": "^11.12.3", + "mermaid": "^11.13.0", "nanostores": "^1.1.1", - "nodemailer": "^8.0.1", - "npm": "^11.11.0", + "nodemailer": "^8.0.2", + "npm": "^11.11.1", "playwright-lighthouse": "^4.0.0", "postcss": "8.5.8", "postcss-html": "1.8.1", - "preact": "^10.28.4", + "preact": "^10.29.0", "prettier": "3.8.1", "prettier-plugin-astro": "0.14.1", "pubsub-js": "^1.9.5", @@ -210,29 +210,29 @@ "sanitize-html": "^2.17.1", "schema-dts": "^1.1.5", "sharp": "^0.34.5", - "shiki": "^4.0.1", + "shiki": "^4.0.2", "space-separated-tokens": "^2.0.2", "stylelint": "^17.4.0", "stylelint-config-standard": "^40.0.0", "stylelint-declaration-block-no-ignored-properties": "3.0.0", - "stylelint-order": "7.0.1", + "stylelint-order": "8.0.0", "tailwindcss": "^4.2.1", "temp-dir": "3.0.0", - "timezones-ical-library": "^2.1.2", + "timezones-ical-library": "^2.1.3", "title-case": "4.3.2", "to-ico": "1.1.5", "tslib": "2.8.1", "typescript": "5.9.3", - "typescript-eslint": "8.56.1", + "typescript-eslint": "8.57.0", "unified": "^11.0.5", "unist": "^0.0.1", "unist-util-inspect": "^8.1.0", "unist-util-is": "^6.0.1", "unist-util-visit": "^5.1.0", "uuid": "^13.0.0", - "vercel": "^50.28.0", - "vite": "^7.3.1", - "vitest": "4.0.18", + "vercel": "^50.32.5", + "vite": "^8.0.0", + "vitest": "4.1.0", "vitest-axe": "0.1.0", "workbox-build": "7.4.0", "zod": "4.3.6" diff --git a/servers/companion/package.json b/servers/companion/package.json index 0b435ef9c..2356124b3 100644 --- a/servers/companion/package.json +++ b/servers/companion/package.json @@ -17,7 +17,7 @@ }, "private": "true", "engines": { - "node": ">=22.0.0 <23.0.0", + "node": ">=24.0.0 <25.0.0", "npm": ">=10.0.0" }, "type": "module" diff --git a/servers/tus/package.json b/servers/tus/package.json index 4b63e70ac..017f7525b 100644 --- a/servers/tus/package.json +++ b/servers/tus/package.json @@ -17,7 +17,7 @@ }, "private": "true", "engines": { - "node": ">=22.0.0 <23.0.0", + "node": ">=24.0.0 <25.0.0", "npm": ">=10.0.0" }, "type": "module" diff --git a/src/actions/contact/__tests__/domain.spec.ts b/src/actions/contact/__tests__/domain.spec.ts index 78427ff8d..beddab16c 100644 --- a/src/actions/contact/__tests__/domain.spec.ts +++ b/src/actions/contact/__tests__/domain.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest' +import { z } from 'astro/zod' import { contactFormInputSchema } from '../domain' @@ -48,7 +49,7 @@ describe('contact domain validation', () => { if (result.success) { throw new Error('Expected schema validation to fail') } - expect(result.error.flatten().fieldErrors['timeline']).toContain('Invalid project timeline') + expect(z.flattenError(result.error).fieldErrors['timeline']).toContain('Invalid project timeline') }) it('rejects messages that appear to contain spam', () => { @@ -64,6 +65,6 @@ describe('contact domain validation', () => { if (result.success) { throw new Error('Expected schema validation to fail') } - expect(result.error.flatten().fieldErrors['message']).toContain('Message appears to contain spam') + expect(z.flattenError(result.error).fieldErrors['message']).toContain('Message appears to contain spam') }) }) diff --git a/src/actions/contact/domain.ts b/src/actions/contact/domain.ts index a85feba24..262977ce9 100644 --- a/src/actions/contact/domain.ts +++ b/src/actions/contact/domain.ts @@ -10,6 +10,9 @@ import { containsSpam, } from '@actions/contact/utils' +const emailStringError = (issue: { input?: unknown }): string => + issue.input === undefined ? 'Email is required' : 'Invalid email format' + export const contactFormInputSchema = z .object({ /** Core fields used by the action. */ @@ -23,14 +26,13 @@ export const contactFormInputSchema = z emptyStringToUndefined, z .string({ - required_error: 'Email is required', - invalid_type_error: 'Invalid email format', + error: emailStringError, }) .max(254, { message: 'Email must be less than 254 characters' }) .superRefine((value, context) => { if (!emailValidator.validate(value)) { context.addIssue({ - code: z.ZodIssueCode.custom, + code: 'custom', message: 'Invalid email address', }) } @@ -57,7 +59,7 @@ export const contactFormInputSchema = z consent: z.preprocess(value => (value === 'true' ? true : false), z.boolean()).optional(), /** Optional hidden field supported by the action. */ - DataSubjectId: z.preprocess(emptyStringToUndefined, z.string().uuid().optional()), + DataSubjectId: z.preprocess(emptyStringToUndefined, z.uuid().optional()), /** Backwards-compatible optional fields (older contact forms). */ service: optionalTrimmedString(100), @@ -70,12 +72,12 @@ export const contactFormInputSchema = z file4: optionalFile(), file5: optionalFile(), }) - .passthrough() + .catchall(z.unknown()) .superRefine((data, context) => { const messageContent = `${data.name} ${data.email} ${data.message}` if (containsSpam(messageContent)) { context.addIssue({ - code: z.ZodIssueCode.custom, + code: 'custom', message: 'Message appears to contain spam', path: ['message'], }) diff --git a/src/actions/contact/utils.ts b/src/actions/contact/utils.ts index 506e76e09..8f33a3e3f 100644 --- a/src/actions/contact/utils.ts +++ b/src/actions/contact/utils.ts @@ -5,6 +5,12 @@ import type { } from '@actions/contact/@types' import { isAllowedTimeline } from './responder' +const requiredStringError = ( + requiredMessage: string, + invalidTypeMessage: string +) => (issue: { input?: unknown }): string => + issue.input === undefined ? requiredMessage : invalidTypeMessage + export function escapeHtml(text: string): string { const map: Record = { '&': '&', @@ -53,8 +59,7 @@ export const requiredString = (options: RequiredStringOptions) => { emptyStringToUndefined, z .string({ - required_error: options.required_error, - invalid_type_error: options.invalid_type_error, + error: requiredStringError(options.required_error, options.invalid_type_error), }) .min(options.min.value, { message: options.min.message }) .max(options.max.value, { message: options.max.message }) diff --git a/src/actions/downloads/action.ts b/src/actions/downloads/action.ts index e720b1b4c..3d40fd757 100644 --- a/src/actions/downloads/action.ts +++ b/src/actions/downloads/action.ts @@ -16,7 +16,7 @@ export const inputSchema = z.object({ jobTitle: z.string().trim().min(1), companyName: z.string().trim().min(1), consent: z.boolean().optional(), - DataSubjectId: z.string().uuid().optional(), + DataSubjectId: z.uuid().optional(), }) export type DownloadsSubmitInput = z.infer diff --git a/src/actions/gdpr/action.ts b/src/actions/gdpr/action.ts index 75e5c897f..56de7038f 100644 --- a/src/actions/gdpr/action.ts +++ b/src/actions/gdpr/action.ts @@ -1,7 +1,7 @@ import emailValidator from 'email-validator' import { validate as uuidValidate } from 'uuid' -import { z } from 'astro:schema' import { defineAction } from 'astro:actions' +import { z } from 'astro/zod' import { checkRateLimit, rateLimiters diff --git a/src/actions/gdpr/domain.ts b/src/actions/gdpr/domain.ts index 286ecfcb2..008004735 100644 --- a/src/actions/gdpr/domain.ts +++ b/src/actions/gdpr/domain.ts @@ -1,4 +1,4 @@ -import { z } from 'astro:schema' +import { z } from 'astro/zod' import type { ConsentRequest } from '@actions/gdpr/@types' export const consentCreateSchema = z.custom() diff --git a/src/actions/newsletter/action.ts b/src/actions/newsletter/action.ts index 6fa4e3db8..f8bddc32d 100644 --- a/src/actions/newsletter/action.ts +++ b/src/actions/newsletter/action.ts @@ -1,6 +1,6 @@ import { v4 as uuidv4, validate as uuidValidate } from 'uuid' import { defineAction } from 'astro:actions' -import { z } from 'astro:schema' +import { z } from 'astro/zod' import { getPrivacyPolicyVersion } from '@actions/utils/environment/environmentActions' import { checkRateLimit, rateLimiters } from '@actions/utils/rateLimit' import { buildRequestFingerprint, createRateLimitIdentifier } from '@actions/utils/requestContext' diff --git a/src/components/CallToAction/Newsletter/client/__tests__/selectors.spec.ts b/src/components/CallToAction/Newsletter/client/__tests__/selectors.spec.ts index 9ceec0fea..ce1859341 100644 --- a/src/components/CallToAction/Newsletter/client/__tests__/selectors.spec.ts +++ b/src/components/CallToAction/Newsletter/client/__tests__/selectors.spec.ts @@ -75,7 +75,7 @@ describe('Newsletter selector utilities', () => { await renderNewsletter(async ({ element }) => { element.querySelector(SELECTORS.emailInput)?.remove() - expect(() => getNewsletterElements(element)).toThrowError('Email input element not found') + expect(() => getNewsletterElements(element)).toThrow('Email input element not found') }) }) }) diff --git a/src/components/Code/CodeTabs/client/selectors.ts b/src/components/Code/CodeTabs/client/selectors.ts index 99caedc7e..184499468 100644 --- a/src/components/Code/CodeTabs/client/selectors.ts +++ b/src/components/Code/CodeTabs/client/selectors.ts @@ -71,11 +71,3 @@ export function queryCodeTabsIconMarkup(params: { const markup = iconHostCandidate.innerHTML.trim() return markup ? markup : null } - -export function hasHighlighterElement(scope: ParentNode = document): boolean { - return scope.querySelector('highlighter-element') !== null -} - -export function hasMastodonModalElement(scope: ParentNode = document): boolean { - return scope.querySelector('mastodon-modal-element') !== null -} diff --git a/src/components/Code/CodeTabs/index.astro b/src/components/Code/CodeTabs/index.astro index 066a9b5fd..a50265939 100644 --- a/src/components/Code/CodeTabs/index.astro +++ b/src/components/Code/CodeTabs/index.astro @@ -16,35 +16,6 @@ const iconBankId = 'code-tabs-icon-bank' diff --git a/src/components/Consent/Banner/client/__tests__/selectors.spec.ts b/src/components/Consent/Banner/client/__tests__/selectors.spec.ts index ff01c78bd..7b3b0b325 100644 --- a/src/components/Consent/Banner/client/__tests__/selectors.spec.ts +++ b/src/components/Consent/Banner/client/__tests__/selectors.spec.ts @@ -110,7 +110,7 @@ describe('Consent Banner Selectors', () => { await renderConsentBanner(() => { document.getElementById('consent-modal-id')?.remove() - expect(() => getConsentWrapper()).toThrowError(ClientScriptError) + expect(() => getConsentWrapper()).toThrow(ClientScriptError) }) }) }) diff --git a/src/components/Content/Layout/index.astro b/src/components/Content/Layout/index.astro index e7db83c14..99b715426 100644 --- a/src/components/Content/Layout/index.astro +++ b/src/components/Content/Layout/index.astro @@ -68,6 +68,8 @@ const isDeepDive = section === 'Deep Dive Articles' sizes="100vw" formats={['avif', 'webp', 'jpeg']} layout="constrained" + loading="eager" + fetchpriority="high" fit="cover" position="center" class="absolute inset-0 h-full w-full" diff --git a/src/components/Diagram/index.astro b/src/components/Diagram/index.astro index 677e913c9..0b1c5501d 100644 --- a/src/components/Diagram/index.astro +++ b/src/components/Diagram/index.astro @@ -1,33 +1,38 @@ --- import type { ImageMetadata } from 'astro' -import { Picture } from 'astro:assets' +import Image from '@components/Image/index.astro' + +type ImageSource = ImageMetadata export interface Props { /** The image source for the diagram */ - src?: ImageMetadata + src?: ImageSource | undefined + /** The desktop preview max width token for the diagram image */ + size?: 'full' | '3xl' | '2xl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs' | undefined + /** The magnify button corner for the preview image */ + magnifyButtonPosition?: 'top-right' | 'bottom-right' | 'top-left' | 'bottom-left' | undefined /** The title of the diagram */ title: string /** A detailed description of the diagram for vision-impaired users */ description: string } -const { src, title, description } = Astro.props +const { src, title, description, magnifyButtonPosition = 'top-right', size } = Astro.props as Props +const imageVariant = size === 'full' ? 'full' : 'center' +const imageProps = { + ...(typeof size !== 'undefined' && size !== 'full' ? { size } : {}), + ...(typeof magnifyButtonPosition !== 'undefined' ? { magnifyButtonPosition } : {}), +} const hasDefaultSlot = Astro.slots.has('default') ---
{src && ( - )} diff --git a/src/components/Footer/server/__tests__/index.spec.ts b/src/components/Footer/server/__tests__/index.spec.ts index 2663d8d89..3775c11b2 100644 --- a/src/components/Footer/server/__tests__/index.spec.ts +++ b/src/components/Footer/server/__tests__/index.spec.ts @@ -29,15 +29,15 @@ describe(`formatPhoneNumber helper`, () => { }) test(`throws BuildError for invalid phone number`, () => { - expect(() => formatPhoneNumber('invalid')).toThrowError(BuildError) + expect(() => formatPhoneNumber('invalid')).toThrow(BuildError) }) test(`throws BuildError for empty string`, () => { - expect(() => formatPhoneNumber('')).toThrowError(BuildError) + expect(() => formatPhoneNumber('')).toThrow(BuildError) }) test(`throws BuildError for number without country code`, () => { - expect(() => formatPhoneNumber('2133734253')).toThrowError(BuildError) + expect(() => formatPhoneNumber('2133734253')).toThrow(BuildError) }) test(`handles phone number with extra characters`, () => { diff --git a/src/components/Icon/icons/availability.astro b/src/components/Icon/icons/availability.astro new file mode 100644 index 000000000..1d2f6a6bc --- /dev/null +++ b/src/components/Icon/icons/availability.astro @@ -0,0 +1,42 @@ +--- +export type Props = { + color: string + classes?: string + size: number + accessible: boolean + focusable: boolean + isListMarker?: boolean + id?: string +} + +const { color, classes, size, accessible, focusable, isListMarker, id } = Astro.props +--- + + + {accessible && Availability Icon} + + + + + diff --git a/src/components/Icon/icons/minus.astro b/src/components/Icon/icons/minus.astro new file mode 100644 index 000000000..329ddcafa --- /dev/null +++ b/src/components/Icon/icons/minus.astro @@ -0,0 +1,32 @@ +--- +export type Props = { + color: string + classes?: string + size: number + accessible: boolean + focusable: boolean + isListMarker?: boolean + id?: string +} + +const { color, classes, size, accessible, focusable, isListMarker, id } = Astro.props +--- + + + {accessible && Minus Symbol Icon} + + diff --git a/src/components/Icon/server/__tests__/index.spec.ts b/src/components/Icon/server/__tests__/index.spec.ts index 54b26cea7..7a2e66fe5 100644 --- a/src/components/Icon/server/__tests__/index.spec.ts +++ b/src/components/Icon/server/__tests__/index.spec.ts @@ -18,7 +18,7 @@ describe('getIconComponent', () => { }) it('throws a descriptive error when icon is missing', () => { - expect(() => getIconComponent(undefined, {})).toThrowError( + expect(() => getIconComponent(undefined, {})).toThrow( 'Icon: missing icon value. Expected an icon name that maps to src/components/Icon/icons/.astro' ) }) @@ -29,7 +29,7 @@ describe('getIconComponent', () => { '../icons/company.astro': { default: companyIcon }, } - expect(() => getIconComponent('download', markerComponents)).toThrowError( + expect(() => getIconComponent('download', markerComponents)).toThrow( 'Icon: icon file "download.astro" was not found in src/components/Icon/icons/. Requested icon path: "../icons/download.astro". Available icons: avatar.astro, company.astro' ) }) diff --git a/src/components/Image/client/__fixtures__/index.fixture.astro b/src/components/Image/client/__fixtures__/index.fixture.astro new file mode 100644 index 000000000..69ccb5117 --- /dev/null +++ b/src/components/Image/client/__fixtures__/index.fixture.astro @@ -0,0 +1,30 @@ +--- +import Image from '@components/Image/index.astro' +import backstageBackground from '@assets/images/backstage-background.jpg' + +export interface Props { + alt?: string + variant?: 'left' | 'right' | 'center' | 'full' + size?: '3xl' | '2xl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs' + magnifyButtonPosition?: 'top-right' | 'bottom-right' | 'top-left' | 'bottom-left' +} + +const { + alt = 'Backstage background test image', + variant = 'center', + size, + magnifyButtonPosition = 'top-right', +}: Props = Astro.props + +const imageProps = { + ...(typeof size !== 'undefined' ? { size } : {}), + ...(typeof magnifyButtonPosition !== 'undefined' ? { magnifyButtonPosition } : {}), +} +--- + + \ No newline at end of file diff --git a/src/components/Image/client/__tests__/index.spec.ts b/src/components/Image/client/__tests__/index.spec.ts new file mode 100644 index 000000000..a8953588e --- /dev/null +++ b/src/components/Image/client/__tests__/index.spec.ts @@ -0,0 +1,151 @@ +import { beforeEach, describe, expect, test } from 'vitest' +import { experimental_AstroContainer as AstroContainer } from 'astro/container' +import ImageFixture from '@components/Image/client/__fixtures__/index.fixture.astro' +import type { ImageElement as ImageElementInstance } from '@components/Image/client' +import type { WebComponentModule } from '@components/scripts/@types/webComponentModule' +import { executeRender } from '@test/unit/helpers/litRuntime' + +type ImageModule = WebComponentModule + +const getMainImage = (element: ImageElementInstance): HTMLImageElement | null => + element.querySelector('[data-image-figure] img') + +const getFigure = (element: ImageElementInstance): HTMLElement | null => + element.querySelector('[data-image-figure]') + +const getOpenButton = (element: ImageElementInstance): HTMLButtonElement | null => + element.querySelector('[data-image-open]') + +const getDialog = (element: ImageElementInstance): HTMLElement | null => + element.querySelector('[data-image-dialog]') + +const getModalImage = (element: ImageElementInstance): HTMLImageElement | null => + element.querySelector('[data-image-modal-asset]') + +describe('Image web component', () => { + let container: AstroContainer + + beforeEach(async () => { + container = await AstroContainer.create() + }) + + const renderImage = async ( + props: { + alt?: string + variant?: 'left' | 'right' | 'center' | 'full' + size?: '3xl' | '2xl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs' + magnifyButtonPosition?: 'top-right' | 'bottom-right' | 'top-left' | 'bottom-left' + }, + assertion: (_context: { + element: ImageElementInstance + window: Window & typeof globalThis + }) => Promise | void + ) => { + await executeRender({ + container, + component: ImageFixture, + moduleSpecifier: '@components/Image/client/index', + args: { props }, + waitForReady: async element => { + await element.updateComplete + }, + assert: async ({ element, window }) => { + await assertion({ element, window: window as Window & typeof globalThis }) + }, + }) + } + + const renderImageToString = (props: { + alt?: string + variant?: 'left' | 'right' | 'center' | 'full' + size?: '3xl' | '2xl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs' | 'invalid' + magnifyButtonPosition?: 'top-right' | 'bottom-right' | 'top-left' | 'bottom-left' + }) => { + return container.renderToString(ImageFixture, { + props, + }) + } + + test('renders centered image markup by default', async () => { + await renderImage({}, async ({ element }) => { + expect(element.getAttribute('data-image-variant')).toBe('center') + + const mainImage = getMainImage(element) + expect(mainImage?.getAttribute('alt')).toBe('Backstage background test image') + + const openButton = getOpenButton(element) + expect(openButton?.getAttribute('aria-label')).toContain('Backstage background test image') + + const dialog = getDialog(element) + expect(dialog?.hasAttribute('hidden')).toBe(true) + }) + }) + + test('applies the requested magnify button corner', async () => { + await renderImage({ magnifyButtonPosition: 'bottom-left' }, async ({ element }) => { + const openButton = getOpenButton(element) + expect(openButton?.getAttribute('data-image-open-position')).toBe('bottom-left') + expect(openButton?.className).toContain('left-2') + expect(openButton?.className).toContain('bottom-2') + }) + }) + + test('applies the requested desktop size token to centered images', async () => { + await renderImage({ size: 'xl' }, async ({ element }) => { + const figure = getFigure(element) + expect(figure?.className).toContain('md:max-w-xl') + + const mainImage = getMainImage(element) + expect(mainImage?.getAttribute('sizes')).toBe('(min-width: 768px) 36rem, 100vw') + }) + }) + + test('opens the modal when the magnify button is activated', async () => { + await renderImage({ variant: 'right' }, async ({ element, window }) => { + expect(element.getAttribute('data-image-variant')).toBe('right') + + const openButton = getOpenButton(element) + openButton?.dispatchEvent(new window.Event('click', { bubbles: true })) + await element.updateComplete + + const dialog = getDialog(element) + expect(dialog?.hasAttribute('hidden')).toBe(false) + expect(dialog?.getAttribute('aria-label')).toContain('Backstage background test image') + + const modalImage = getModalImage(element) + expect(modalImage?.getAttribute('alt')).toBe('Backstage background test image') + + const closeIcon = element.querySelector( + 'button[aria-label="Close image dialog"] svg' + ) as SVGElement | null + expect(closeIcon?.getAttribute('aria-hidden')).toBe('true') + expect(closeIcon?.getAttribute('focusable')).toBe('false') + }) + }) + + test('closes the modal on Escape', async () => { + await renderImage({}, async ({ element, window }) => { + const openButton = getOpenButton(element) + openButton?.dispatchEvent(new window.Event('click', { bubbles: true })) + await element.updateComplete + + window.document.dispatchEvent(new window.KeyboardEvent('keydown', { key: 'Escape' })) + await element.updateComplete + + const dialog = getDialog(element) + expect(dialog?.hasAttribute('hidden')).toBe(true) + }) + }) + + test('throws for an invalid size value', async () => { + await expect(renderImageToString({ size: 'invalid' })).rejects.toThrow( + 'Image: invalid size "invalid". Expected one of: 3xl, 2xl, xl, lg, md, sm, xs' + ) + }) + + test('throws when size is used with the full variant', async () => { + await expect(renderImageToString({ variant: 'full', size: 'lg' })).rejects.toThrow( + 'Image: size cannot be used with variant "full". The "full" variant always renders at the full available container width on desktop. Use variant "center", "left", or "right" if you want to control the image max width with size.' + ) + }) +}) diff --git a/src/components/Image/client/index.ts b/src/components/Image/client/index.ts new file mode 100644 index 000000000..26c7bfe5d --- /dev/null +++ b/src/components/Image/client/index.ts @@ -0,0 +1,198 @@ +import { LitElement, html } from 'lit' +import { unsafeHTML } from 'lit/directives/unsafe-html.js' +import { defineCustomElement } from '@components/scripts/utils/defineCustomElement' +import type { WebComponentModule } from '@components/scripts/@types/webComponentModule' +import { + getImageModalRoot, + queryImageCloseButton, + queryImageIconMarkup, +} from './selectors' + +const COMPONENT_TAG_NAME = 'content-image' + +const parseDimension = (value: string | null): number | undefined => { + if (!value) { + return undefined + } + + const parsed = Number(value) + return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined +} + +const isElement = (value: EventTarget | null): value is Element => value instanceof Element +const dialogClasses = 'fixed inset-0 z-(--z-modal) flex items-center justify-center p-4 md:p-8' +const backdropClasses = 'absolute inset-0 bg-content opacity-[0.72]' +const panelClasses = + 'relative flex w-full max-w-[min(92vw,90rem)] max-h-[calc(100vh-2rem)] items-center justify-center overflow-hidden rounded-2xl border border-trim bg-page-base px-4 pt-12 pb-4 md:max-h-[calc(100vh-4rem)] md:px-6 md:pt-14 md:pb-6' +const closeButtonClasses = + "absolute right-3 top-3 inline-flex size-8 items-center justify-center rounded-full border-0 bg-gray-200 p-0 text-icons transition-colors duration-150 ease-linear hover:text-icons-active focus-visible:text-icons-active focus-visible:outline-none after:pointer-events-none after:absolute after:content-[''] after:inset-0 after:rounded-none after:border-2 after:border-transparent after:opacity-0 after:transition-opacity after:duration-150 after:ease-out focus-visible:after:opacity-100 focus-visible:after:-inset-1 focus-visible:after:border-spotlight" +const modalAssetClasses = + 'mx-auto block h-auto max-h-[calc(100vh-6rem)] max-w-full w-auto object-contain md:max-h-[calc(100vh-8rem)]' + +export class ImageElement extends LitElement { + static registeredName = COMPONENT_TAG_NAME + + static override properties = { + open: { type: Boolean, reflect: true }, + imageSrc: { type: String, attribute: 'image-src' }, + imageAlt: { type: String, attribute: 'image-alt' }, + imageWidth: { type: Number, attribute: 'image-width' }, + imageHeight: { type: Number, attribute: 'image-height' }, + iconBankId: { type: String, attribute: 'icon-bank-id' }, + } + + declare open: boolean + declare imageSrc: string + declare imageAlt: string + declare imageWidth: number | undefined + declare imageHeight: number | undefined + declare iconBankId: string + + private opener: HTMLElement | null = null + + constructor() { + super() + this.open = false + this.imageSrc = '' + this.imageAlt = '' + this.imageWidth = undefined + this.imageHeight = undefined + this.iconBankId = '' + } + + protected override createRenderRoot(): HTMLElement | DocumentFragment { + return getImageModalRoot(this) ?? this + } + + public override connectedCallback(): void { + super.connectedCallback() + + this.imageWidth = parseDimension(this.getAttribute('image-width')) + this.imageHeight = parseDimension(this.getAttribute('image-height')) + + this.addEventListener('click', this.handleHostClick) + document.addEventListener('keydown', this.handleKeyDown) + } + + public override disconnectedCallback(): void { + this.removeEventListener('click', this.handleHostClick) + document.removeEventListener('keydown', this.handleKeyDown) + super.disconnectedCallback() + } + + private readonly handleHostClick = (event: Event): void => { + if (!isElement(event.target)) { + return + } + + const openButton = event.target.closest('[data-image-open]') + if (!openButton || !this.contains(openButton)) { + return + } + + event.preventDefault() + this.opener = openButton instanceof HTMLElement ? openButton : null + this.openModal() + } + + private readonly handleKeyDown = (event: KeyboardEvent): void => { + if (!this.open || event.key !== 'Escape') { + return + } + + event.preventDefault() + this.closeModal() + } + + private openModal(): void { + if (!this.imageSrc) { + return + } + + this.open = true + + this.updateComplete + .then(() => { + const closeButton = queryImageCloseButton(this.renderRoot) + if (closeButton) { + closeButton.focus() + } + }) + .catch(() => {}) + } + + private closeModal(): void { + if (!this.open) { + return + } + + this.open = false + this.opener?.focus() + } + + protected override render() { + const closeIconMarkup = + typeof document !== 'undefined' + ? queryImageIconMarkup({ + iconBankId: this.iconBankId, + iconName: 'close', + root: document, + }) + : null + + const dialogLabel = this.imageAlt ? `Expanded view for ${this.imageAlt}` : 'Expanded image' + + return html` + + ` + } +} + +export const registerWebComponent = (tagName = ImageElement.registeredName) => { + if (typeof window === 'undefined') { + return + } + + defineCustomElement(tagName, ImageElement) +} + +export const registerImageWebComponent = registerWebComponent + +export const webComponentModule: WebComponentModule = { + registeredName: COMPONENT_TAG_NAME, + componentCtor: ImageElement, + registerWebComponent, +} diff --git a/src/components/Image/client/selectors.ts b/src/components/Image/client/selectors.ts new file mode 100644 index 000000000..9aa4ad0cb --- /dev/null +++ b/src/components/Image/client/selectors.ts @@ -0,0 +1,45 @@ +import { + isButtonElement, + isDivElement, + isSpanElement, +} from '@components/scripts/assertions/elements' + +export const SELECTORS = { + closeButton: '[data-image-close]', + modalRoot: '[data-image-modal-root]', +} as const + +export const getImageModalRoot = (context: Element): HTMLDivElement | null => { + const candidate = context.querySelector(SELECTORS.modalRoot) + return isDivElement(candidate) ? candidate : null +} + +export const queryImageCloseButton = (root: ParentNode): HTMLButtonElement | null => { + const candidate = root.querySelector(SELECTORS.closeButton) + return isButtonElement(candidate) ? candidate : null +} + +export const queryImageIconMarkup = (params: { + iconBankId: string + iconName: 'close' + root?: Document +}): string | null => { + const { iconBankId, iconName, root = document } = params + + if (!iconBankId || !iconName) { + return null + } + + const iconBankCandidate = root.getElementById(iconBankId) + if (!isDivElement(iconBankCandidate)) { + return null + } + + const iconHostCandidate = iconBankCandidate.querySelector(`[data-image-icon="${iconName}"]`) + if (!isSpanElement(iconHostCandidate)) { + return null + } + + const markup = iconHostCandidate.innerHTML.trim() + return markup ? markup : null +} \ No newline at end of file diff --git a/src/components/Image/index.astro b/src/components/Image/index.astro index e69de29bb..075d74b27 100644 --- a/src/components/Image/index.astro +++ b/src/components/Image/index.astro @@ -0,0 +1,153 @@ +--- +import type { ImageMetadata } from 'astro' +import { Image as AstroImage } from 'astro:assets' +import Icon from '@components/Icon/index.astro' + +type ImageSource = ImageMetadata + +type MagnifyButtonPosition = 'top-right' | 'bottom-right' | 'top-left' | 'bottom-left' +type ImageSize = '3xl' | '2xl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs' + +export interface Props { + src?: ImageSource | undefined + alt?: string | undefined + variant?: 'left' | 'right' | 'center' | 'full' | undefined + size?: ImageSize | undefined + magnifyButtonPosition?: MagnifyButtonPosition | undefined + loading?: 'lazy' | 'eager' | undefined +} + +const { + src, + alt = '', + variant = 'center', + loading = 'lazy', +}: Omit = Astro.props + +const requestedMagnifyButtonPosition = Astro.props.magnifyButtonPosition as string | undefined +const requestedSize = Astro.props.size as string | undefined +const allowedVariants = ['left', 'right', 'center', 'full'] as const +const allowedMagnifyButtonPositions = ['top-right', 'bottom-right', 'top-left', 'bottom-left'] as const +const allowedSizes = ['3xl', '2xl', 'xl', 'lg', 'md', 'sm', 'xs'] as const + +if ( + typeof requestedMagnifyButtonPosition !== 'undefined' && + !allowedMagnifyButtonPositions.includes(requestedMagnifyButtonPosition as MagnifyButtonPosition) +) { + throw new Error( + `Image: invalid magnifyButtonPosition "${requestedMagnifyButtonPosition}". Expected one of: ${allowedMagnifyButtonPositions.join(', ')}` + ) +} + +if (typeof requestedSize !== 'undefined' && !allowedSizes.includes(requestedSize as ImageSize)) { + throw new Error( + `Image: invalid size "${requestedSize}". Expected one of: ${allowedSizes.join(', ')}` + ) +} + +const resolvedVariant = allowedVariants.includes(variant) ? variant : 'center' +const resolvedMagnifyButtonPosition = + (requestedMagnifyButtonPosition as MagnifyButtonPosition | undefined) ?? 'top-right' +const resolvedSize = (requestedSize as ImageSize | undefined) ?? '3xl' + +if (typeof requestedSize !== 'undefined' && resolvedVariant === 'full') { + throw new Error( + 'Image: size cannot be used with variant "full". The "full" variant always renders at the full available container width on desktop. Use variant "center", "left", or "right" if you want to control the image max width with size.' + ) +} + +const iconBankId = `content-image-icon-bank-${Math.random().toString(36).slice(2)}` +const openLabel = alt ? `Open expanded view for ${alt}` : 'Open expanded image' +const hostClasses = 'my-6 block w-full' +const sizeMaxWidthClasses = { + 'xs': 'md:max-w-xs', + 'sm': 'md:max-w-sm', + 'md': 'md:max-w-md', + 'lg': 'md:max-w-lg', + 'xl': 'md:max-w-xl', + '2xl': 'md:max-w-2xl', + '3xl': 'md:max-w-3xl', +} as const +const sizeDesktopWidths = { + 'xs': '20rem', + 'sm': '24rem', + 'md': '28rem', + 'lg': '32rem', + 'xl': '36rem', + '2xl': '42rem', + '3xl': '48rem', +} as const +const figureClassesByVariant = { + center: `m-0 w-full max-w-full md:mx-auto ${sizeMaxWidthClasses[resolvedSize]}`, + left: `m-0 w-full max-w-full md:mr-auto ${sizeMaxWidthClasses[resolvedSize]}`, + right: `m-0 w-full max-w-full md:ml-auto ${sizeMaxWidthClasses[resolvedSize]}`, + full: 'm-0 w-full max-w-full', +} as const +const figureClasses = figureClassesByVariant[resolvedVariant] +const imageSizesAttr = + resolvedVariant === 'full' ? '100vw' : `(min-width: 768px) ${sizeDesktopWidths[resolvedSize]}, 100vw` +const surfaceClasses = 'relative overflow-hidden rounded-xl border border-trim bg-page-offset' +const assetClasses = 'block h-auto w-full' +const openButtonPositionClasses = { + 'top-right': 'top-2 right-2', + 'bottom-right': 'right-2 bottom-2', + 'top-left': 'top-2 left-2', + 'bottom-left': 'left-2 bottom-2', +} as const +const openButtonBaseClasses = + "absolute hidden size-9 items-center justify-center rounded-full border-0 bg-gray-200 p-0 text-icons transition-[color,transform] duration-150 ease-linear hover:scale-[1.03] hover:text-icons-active focus-visible:scale-[1.03] focus-visible:text-icons-active focus-visible:outline-none md:inline-flex after:pointer-events-none after:absolute after:content-[''] after:inset-0 after:rounded-none after:border-2 after:border-transparent after:opacity-0 after:transition-opacity after:duration-150 after:ease-out focus-visible:after:opacity-100 focus-visible:after:-inset-1 focus-visible:after:border-spotlight" +const openButtonClasses = `${openButtonBaseClasses} ${openButtonPositionClasses[resolvedMagnifyButtonPosition]}` +--- + +{src && ( + <> + + + +
+
+ + + {/** Intentionally not using Button component. */} + +
+
+ +
+
+ + + +)} diff --git a/src/components/Inset/__tests__/index.spec.ts b/src/components/Inset/__tests__/index.spec.ts new file mode 100644 index 000000000..4cce1867e --- /dev/null +++ b/src/components/Inset/__tests__/index.spec.ts @@ -0,0 +1,93 @@ +import { beforeEach, describe, expect, test } from 'vitest' +import { experimental_AstroContainer as AstroContainer } from 'astro/container' +import { withJsdomEnvironment } from '@test/unit/helpers/litRuntime' + +describe('Inset (Astro)', () => { + let container: AstroContainer + + beforeEach(async () => { + container = await AstroContainer.create() + }) + + test('renders a figure caption below the inset body when provided', async () => { + const Inset = (await import('@components/Inset/index.astro')).default + + const renderedHtml = await container.renderToString(Inset, { + props: { + color: 'warning-inverse', + figure: 'Retry budget pseudocode', + variant: 'default', + }, + slots: { + default: 'if (!budget.canRetry()) return false;', + }, + }) + + await withJsdomEnvironment(async ({ window }) => { + window.document.body.innerHTML = renderedHtml + + const figure = window.document.querySelector('figure') + expect(figure).toBeTruthy() + expect(figure?.className).toContain('mb-8') + + const figcaption = figure?.querySelector('figcaption') + expect(figcaption).toBeTruthy() + expect(figcaption?.textContent).toContain('Retry budget pseudocode') + expect(figcaption?.className).toContain('italic') + expect(figcaption?.className).toContain('text-center') + + const insetBody = figure?.querySelector('div') + expect(insetBody).toBeTruthy() + expect(insetBody?.className).toContain('w-full') + expect(insetBody?.textContent).toContain('if (!budget.canRetry()) return false;') + }) + }) + + test('renders a fit-width inset when fullWidth is false', async () => { + const Inset = (await import('@components/Inset/index.astro')).default + + const renderedHtml = await container.renderToString(Inset, { + props: { + fullWidth: false, + variant: 'default', + }, + slots: { + default: 'const fallback = queueForRetry(request)', + }, + }) + + await withJsdomEnvironment(async ({ window }) => { + window.document.body.innerHTML = renderedHtml + + const figure = window.document.querySelector('figure') + expect(figure).toBeTruthy() + const insetBody = figure?.querySelector('div') + expect(insetBody).toBeTruthy() + expect(insetBody?.className).toContain('w-fit') + expect(insetBody?.className).toContain('max-w-full') + expect(insetBody?.className).toContain('mx-auto') + }) + }) + + test('omits the figcaption when no figure text is provided', async () => { + const Inset = (await import('@components/Inset/index.astro')).default + + const renderedHtml = await container.renderToString(Inset, { + props: { + variant: 'default', + }, + slots: { + default: 'const circuit = new CircuitBreaker(service, config)', + }, + }) + + await withJsdomEnvironment(async ({ window }) => { + window.document.body.innerHTML = renderedHtml + + expect(window.document.querySelector('figcaption')).toBeNull() + expect(window.document.querySelector('figure div')?.textContent).toContain( + 'const circuit = new CircuitBreaker(service, config)' + ) + }) + }) +}) \ No newline at end of file diff --git a/src/components/Inset/index.astro b/src/components/Inset/index.astro index f25e68060..daac5a6dd 100644 --- a/src/components/Inset/index.astro +++ b/src/components/Inset/index.astro @@ -3,26 +3,35 @@ import DefaultInset from './layouts/DefaultInset.astro' export type Props = { classes?: { + figure?: string layout?: string wrapper?: string } color?: string | undefined + figure?: string + fullWidth?: boolean size?: number variant: string } -const { variant = 'default', classes, color } = Astro.props +const { variant = 'default', classes, color, figure, fullWidth = true } = Astro.props +const layoutClasses: NonNullable, 'layout'>> = { + ...(classes?.layout !== undefined ? { layout: classes.layout } : {}), +} +const defaultInsetProps = { + ...(Object.keys(layoutClasses).length > 0 ? { classes: layoutClasses } : {}), + ...(color !== undefined ? { color } : {}), + fullWidth, +} --- -
- {variant === 'default' && - (classes?.layout !== undefined ? ( - - - - ) : ( - - - - ))} -
+
+ {variant === 'default' && ( + + + + )} + {figure && ( +
+ )} +
diff --git a/src/components/Inset/layouts/DefaultInset.astro b/src/components/Inset/layouts/DefaultInset.astro index d1d74472e..5e57d43e3 100644 --- a/src/components/Inset/layouts/DefaultInset.astro +++ b/src/components/Inset/layouts/DefaultInset.astro @@ -1,17 +1,19 @@ --- export type Props = { classes?: { - layout?: string + layout?: string | undefined } color?: string | undefined + fullWidth?: boolean } -const { classes, color }: Props = Astro.props +const { classes, color, fullWidth = true }: Props = Astro.props const backgroundClass = color ? `bg-${color}` : 'bg-content-inverse-active' -const layoutClass = `font-mono ${backgroundClass} border-2 border-trim rounded-md px-6 pt-6` +const layoutClass = `font-mono whitespace-pre-wrap ${backgroundClass} border-2 border-trim rounded-md px-6 pt-6` +const wrapperClass = fullWidth ? 'w-full' : 'mx-auto w-fit max-w-full' --- -
+
diff --git a/src/components/List/__tests__/index.spec.ts b/src/components/List/__tests__/index.spec.ts new file mode 100644 index 000000000..dfb8d8794 --- /dev/null +++ b/src/components/List/__tests__/index.spec.ts @@ -0,0 +1,135 @@ +import { beforeEach, describe, expect, test } from 'vitest' +import { experimental_AstroContainer as AstroContainer } from 'astro/container' +import { withJsdomEnvironment } from '@test/unit/helpers/litRuntime' + +describe('List (Astro)', () => { + let container: AstroContainer + + beforeEach(async () => { + container = await AstroContainer.create() + }) + + test('renders the chat-bubbles variant as question and answer definition pairs', async () => { + const List = (await import('@components/List/index.astro')).default + + const renderedHtml = await container.renderToString(List, { + props: { + variant: 'chat-bubbles', + size: '2xl', + items: [ + { + lead: 'Why did the system go down?', + text: 'Because a config change broke it.', + }, + { + lead: 'Why did the config change break it?', + text: 'Because the engineer made a mistake.', + }, + ], + }, + }) + + await withJsdomEnvironment(async ({ window }) => { + window.document.body.innerHTML = renderedHtml + + const definitionList = window.document.querySelector('dl') + expect(definitionList).toBeTruthy() + expect(definitionList?.className).toContain('max-w-2xl') + expect(definitionList?.className).toContain('mx-auto') + + const questions = window.document.querySelectorAll('dt') + const answers = window.document.querySelectorAll('dd') + + expect(questions).toHaveLength(2) + expect(answers).toHaveLength(2) + expect(questions[0]?.textContent).toContain('Q:') + expect(questions[0]?.textContent).toContain('Why did the system go down?') + expect(answers[0]?.textContent).toContain('A:') + expect(answers[0]?.textContent).toContain('Because a config change broke it.') + expect(answers[0]?.className).toContain('bg-secondary') + }) + }) + + test('throws for an invalid chat-bubbles size', async () => { + const List = (await import('@components/List/index.astro')).default + + await expect( + container.renderToString(List, { + props: { + variant: 'chat-bubbles', + size: '3xl', + items: [ + { + lead: 'Why did the system go down?', + text: 'Because a config change broke it.', + }, + ], + }, + }) + ).rejects.toThrow('ChatBubbles: invalid size "3xl". Expected one of: lg, xl, 2xl.') + }) + + test('starts numbering at the provided startNumber and applies the provided color for the numbered-with-background-list variant', async () => { + const List = (await import('@components/List/index.astro')).default + + const renderedHtml = await container.renderToString(List, { + props: { + variant: 'numbered-with-background-list', + color: 'info', + startNumber: 4, + items: [ + { + lead: 'Step one', + text: 'First item.', + }, + { + lead: 'Step two', + text: 'Second item.', + }, + ], + }, + }) + + await withJsdomEnvironment(async ({ window }) => { + window.document.body.innerHTML = renderedHtml + + const badges = Array.from(window.document.querySelectorAll('li > span:first-child')) + const leads = Array.from(window.document.querySelectorAll('li em')) + + expect(badges).toHaveLength(2) + expect(leads).toHaveLength(2) + expect(badges[0]?.textContent?.trim()).toBe('4') + expect(badges[1]?.textContent?.trim()).toBe('5') + expect(badges[0]?.getAttribute('style')).toContain('background-color: var(--color-info);') + expect(leads[0]?.getAttribute('style')).toContain('color: var(--color-info);') + }) + }) + + test('uses the default marker color for numbered-with-background-list when no color is provided', async () => { + const List = (await import('@components/List/index.astro')).default + + const renderedHtml = await container.renderToString(List, { + props: { + variant: 'numbered-with-background-list', + items: [ + { + lead: 'Default step', + text: 'Uses the default marker color.', + }, + ], + }, + }) + + await withJsdomEnvironment(async ({ window }) => { + window.document.body.innerHTML = renderedHtml + + const badge = window.document.querySelector('li > span:first-child') + const lead = window.document.querySelector('li em') + + expect(badge?.className).toContain('bg-primary-offset') + expect(lead?.className).toContain('text-primary-offset') + expect(badge?.getAttribute('style')).toBeNull() + expect(lead?.getAttribute('style')).toBeNull() + }) + }) +}) \ No newline at end of file diff --git a/src/components/List/index.astro b/src/components/List/index.astro index c9c1c5860..4bbdb63c9 100644 --- a/src/components/List/index.astro +++ b/src/components/List/index.astro @@ -2,6 +2,7 @@ import AccentBorderLeftList from '@components/List/layouts/AccentBorderLeftList.astro' import BadgeList from '@components/List/layouts/BadgeList.astro' import CardGridList from '@components/List/layouts/CardGridList.astro' +import ChatBubbles from '@components/List/layouts/ChatBubbles.astro' import CheckIconsList from '@components/List/layouts/CheckIconsList.astro' import ChevronList from '@components/List/layouts/ChevronList.astro' import ColoredMarkerList from '@components/List/layouts/ColoredMarkerList.astro' @@ -37,14 +38,19 @@ export type Props = { text?: string wrapper?: string } - size?: number + size?: number | 'lg' | 'xl' | '2xl' + color?: string + startNumber?: number variant: string style?: Record } -const { items, size, variant = 'default', classes, style } = Astro.props +const { items, size, color, startNumber, variant = 'default', classes, style } = Astro.props const classesProps = classes ? { classes } : {} -const sizeProps = size !== undefined ? { size } : {} +const numericSizeProps = typeof size === 'number' ? { size } : {} +const chatBubbleSizeProps = typeof size === 'string' ? { size } : {} +const colorProps = typeof color === 'string' && color.trim().length > 0 ? { color } : {} +const startNumberProps = typeof startNumber === 'number' ? { startNumber } : {} const styleProps = style ? { style } : {} const itemsWithColor = items as Array<{ title?: string @@ -71,15 +77,16 @@ const plainIconItems = items.filter((item): item is Props['items'][number] & { i {variant === 'accent-border-left-list' && } {variant === 'badge-list' && } {variant === 'card-grid-list' && } + {variant === 'chat-bubbles' && } {variant === 'check-icons-list' && } {variant === 'chevron-list' && } - {variant === 'colored-marker-list' && } - {variant === 'numbered-with-background-list' && } - {variant === 'plain-icon-list' && } + {variant === 'colored-marker-list' && } + {variant === 'numbered-with-background-list' && } + {variant === 'plain-icon-list' && } {variant === 'side-by-side-list' && } {variant === 'timeline-list' && } - {variant === 'two-column-check-icons-list' && } - {variant === 'two-column-icon-list' && } - {variant === 'three-column-icon-list' && } + {variant === 'two-column-check-icons-list' && } + {variant === 'two-column-icon-list' && } + {variant === 'three-column-icon-list' && } {variant === 'zebra-list' && }
diff --git a/src/components/List/layouts/BadgeList.astro b/src/components/List/layouts/BadgeList.astro index b3cc2dfe2..141ded47f 100644 --- a/src/components/List/layouts/BadgeList.astro +++ b/src/components/List/layouts/BadgeList.astro @@ -19,12 +19,12 @@ const { items, classes }: Props = Astro.props const ulClass = ["space-y-4 sm:space-y-0 sm:table sm:border-separate sm:border-spacing-x-4 sm:border-spacing-y-4", classes?.ul] const liClass = ["flex flex-col gap-2 sm:table-row", classes?.li] -const titleCellClass = "sm:table-cell sm:align-baseline" +const titleCellClass = "sm:table-cell sm:align-top" const titleClass = [ - "inline-block px-2 py-1 rounded bg-content text-page-base font-mono text-xs font-bold", + "inline-block px-2 py-1 rounded bg-content text-page-base font-mono text-xs font-bold sm:mt-1", classes?.titleClass, ] -const bodyClass = ["sm:table-cell sm:align-baseline", classes?.content] +const bodyClass = ["sm:table-cell sm:align-top", classes?.content] const emClass = ["text-content font-bold not-italic mr-2", classes?.em] --- diff --git a/src/components/List/layouts/ChatBubbles.astro b/src/components/List/layouts/ChatBubbles.astro new file mode 100644 index 000000000..15cbae1a1 --- /dev/null +++ b/src/components/List/layouts/ChatBubbles.astro @@ -0,0 +1,55 @@ +--- +export type Props = { + items: { + lead?: string + text: string + }[] + size?: 'lg' | 'xl' | '2xl' + classes?: { + ul?: string + li?: string + em?: string + } +} + +const { items, classes, size = 'lg' }: Props = Astro.props + +const maxWidthClasses = { + lg: 'max-w-lg', + xl: 'max-w-xl', + '2xl': 'max-w-2xl', +} as const + +if (!(size in maxWidthClasses)) { + throw new Error(`ChatBubbles: invalid size "${String(size)}". Expected one of: lg, xl, 2xl.`) +} + +const dlClass = ['mx-auto flex w-full flex-col space-y-8', maxWidthClasses[size], classes?.ul] +const itemClass = ['flex flex-col space-y-2', classes?.li] +const dtClass = [ + 'max-w-[85%] self-start rounded-2xl rounded-tl-sm bg-page-offset px-6 py-3 text-lg font-medium text-content-active shadow-sm', + classes?.em, +] +const ddClass = [ + 'max-w-[85%] self-end rounded-2xl rounded-tr-sm bg-secondary px-6 py-4 text-secondary-inverse shadow-sm', +] +--- + +
+ { + items.map((item) => ( +
+ {item.lead && ( +
+ + +
+ )} +
+ + +
+
+ )) + } +
\ No newline at end of file diff --git a/src/components/List/layouts/CheckIconsList.astro b/src/components/List/layouts/CheckIconsList.astro index 2181d5f66..c8268da55 100644 --- a/src/components/List/layouts/CheckIconsList.astro +++ b/src/components/List/layouts/CheckIconsList.astro @@ -11,6 +11,7 @@ export type Props = { ul?: string li?: string em?: string + text?: string } } @@ -19,6 +20,7 @@ const { items, classes }: Props = Astro.props const ulClass = ["space-y-3", classes?.ul] const liClass = ["flex items-start gap-3", classes?.li] const emClass = ["text-content font-semibold not-italic", classes?.em] +const textClass = ["text-content-offset", classes?.text] ---
    @@ -38,7 +40,7 @@ const emClass = ["text-content font-semibold not-italic", classes?.em] )} - + )) diff --git a/src/components/List/layouts/NumberedWithBackgroundList.astro b/src/components/List/layouts/NumberedWithBackgroundList.astro index ee0f7e610..62dc9d228 100644 --- a/src/components/List/layouts/NumberedWithBackgroundList.astro +++ b/src/components/List/layouts/NumberedWithBackgroundList.astro @@ -4,6 +4,8 @@ export type Props = { lead?: string text: string }[] + color?: string + startNumber?: number classes?: { ol?: string li?: string @@ -11,20 +13,32 @@ export type Props = { } } -const { items, classes }: Props = Astro.props +const { items, classes, color, startNumber = 1 }: Props = Astro.props +const resolvedColor = typeof color === 'string' && color.trim().length > 0 ? color.trim() : undefined +const safeColorToken = resolvedColor && /^[-a-z0-9]+$/i.test(resolvedColor) ? resolvedColor : undefined +const pillStyle = safeColorToken ? `background-color: var(--color-${safeColorToken});` : undefined +const leadStyle = safeColorToken ? `color: var(--color-${safeColorToken});` : undefined const olClass = ["space-y-3", classes?.ol] const liClass = ["flex items-start gap-4 bg-page-offset/50 rounded-lg p-4", classes?.li] -const emClass = ["text-primary-offset font-semibold not-italic", classes?.em] +const emClass = ["font-semibold not-italic", !safeColorToken && 'text-primary-offset', classes?.em] ---
      { items.map((item, index) => (
    1. - {index + 1} + + {startNumber + index} +
      - {item.lead && } + {item.lead && }
    2. diff --git a/src/components/Social/Highlighter/HighlighterIconBank.astro b/src/components/Social/Highlighter/HighlighterIconBank.astro new file mode 100644 index 000000000..c57af7b89 --- /dev/null +++ b/src/components/Social/Highlighter/HighlighterIconBank.astro @@ -0,0 +1,18 @@ +--- +/** + * HighlighterIconBank + * + * Renders the hidden SVG icon bank used by all HighlighterElement instances on the page. + * Must be rendered exactly once per page, outside any paragraph or phrasing-content context. + * MarkdownLayout.astro owns this responsibility. + */ +import Icon from '@components/Icon/index.astro' +--- + + diff --git a/src/components/Social/Highlighter/client/__tests__/index.spec.ts b/src/components/Social/Highlighter/client/__tests__/index.spec.ts index b5bcb26d1..d2a09d961 100644 --- a/src/components/Social/Highlighter/client/__tests__/index.spec.ts +++ b/src/components/Social/Highlighter/client/__tests__/index.spec.ts @@ -162,6 +162,7 @@ describe('HighlighterElement', () => { const trigger = element.querySelector('.highlighter__trigger') as HTMLButtonElement | null expect(trigger).toBeTruthy() expect(trigger?.getAttribute('aria-label')).toBeNull() + expect(trigger?.getAttribute('type')).toBe('button') expect(trigger?.textContent).toContain(defaultProps.content) const dialog = element.querySelector('.share-dialog') as HTMLElement | null diff --git a/src/components/Social/Highlighter/client/__tests__/selectors.spec.ts b/src/components/Social/Highlighter/client/__tests__/selectors.spec.ts index 1fa68156f..74be4e66c 100644 --- a/src/components/Social/Highlighter/client/__tests__/selectors.spec.ts +++ b/src/components/Social/Highlighter/client/__tests__/selectors.spec.ts @@ -41,7 +41,7 @@ describe('HighlighterElement selectors', () => { expect( wrapper, 'HighlighterElement should render a wrapper with .highlighter__wrapper' - ).toBeInstanceOf(HTMLDivElement) + ).toBeInstanceOf(HTMLSpanElement) expect( trigger, 'HighlighterElement should render a trigger with .highlighter__trigger' @@ -49,7 +49,7 @@ describe('HighlighterElement selectors', () => { expect( dialog, 'HighlighterElement should render a share dialog with .share-dialog' - ).toBeInstanceOf(HTMLDivElement) + ).toBeInstanceOf(HTMLSpanElement) expect( status, 'HighlighterElement should render a status element with [data-highlighter-status]' @@ -66,6 +66,7 @@ describe('HighlighterElement selectors', () => { const describedBy = trigger.getAttribute('aria-describedby') expect(describedBy, 'HighlighterElement trigger should set aria-describedby').toBeTruthy() + expect(trigger.getAttribute('type')).toBe('button') const hint = describedBy ? queryElementById(element, describedBy) : null expect( diff --git a/src/components/Social/Highlighter/client/index.ts b/src/components/Social/Highlighter/client/index.ts index 72adc81a5..455b373f1 100644 --- a/src/components/Social/Highlighter/client/index.ts +++ b/src/components/Social/Highlighter/client/index.ts @@ -50,7 +50,7 @@ export class HighlighterElement extends LitElement { private contentCaptured = false private boundButtons = new WeakSet() private triggerButton: HTMLButtonElement | null = null - private wrapperElement: HTMLDivElement | null = null + private wrapperElement: HTMLSpanElement | null = null private readonly dialogId: string private readonly hintId: string private readonly statusId: string @@ -126,7 +126,7 @@ export class HighlighterElement extends LitElement { protected override render() { return html` -
      +
      - - + + + - + ` } @@ -213,7 +213,7 @@ export class HighlighterElement extends LitElement { const trigger = queryHighlighterTrigger(this) if (!trigger || trigger === this.triggerButton) return this.triggerButton = trigger - this.triggerButton.style.cursor = 'pointer' + addButtonEventListeners( trigger, event => { diff --git a/src/components/Social/Highlighter/client/selectors.ts b/src/components/Social/Highlighter/client/selectors.ts index 9af92e0a2..e7fd27f23 100644 --- a/src/components/Social/Highlighter/client/selectors.ts +++ b/src/components/Social/Highlighter/client/selectors.ts @@ -1,6 +1,5 @@ import { isButtonElement, - isDivElement, isSpanElement, isType1Element, } from '@components/scripts/assertions/elements' @@ -16,9 +15,9 @@ export const SELECTORS = { status: '[data-highlighter-status]', } as const -export const queryHighlighterWrapper = (context: Element): HTMLDivElement | null => { +export const queryHighlighterWrapper = (context: Element): HTMLSpanElement | null => { const wrapper = context.querySelector(SELECTORS.wrapper) - return isDivElement(wrapper) ? wrapper : null + return isSpanElement(wrapper) ? wrapper : null } export const queryHighlighterTrigger = (context: Element): HTMLButtonElement | null => { @@ -26,9 +25,9 @@ export const queryHighlighterTrigger = (context: Element): HTMLButtonElement | n return isButtonElement(trigger) ? trigger : null } -export const queryShareDialog = (context: Element): HTMLDivElement | null => { +export const queryShareDialog = (context: Element): HTMLSpanElement | null => { const dialog = context.querySelector(SELECTORS.dialog) - return isDivElement(dialog) ? dialog : null + return isSpanElement(dialog) ? dialog : null } export const queryShareButtons = (context: Element): HTMLButtonElement[] => { @@ -37,9 +36,9 @@ export const queryShareButtons = (context: Element): HTMLButtonElement[] => { ) } -export const queryShareDialogArrow = (context: Element): HTMLDivElement | null => { +export const queryShareDialogArrow = (context: Element): HTMLSpanElement | null => { const arrow = context.querySelector(SELECTORS.dialogArrow) - return isDivElement(arrow) ? arrow : null + return isSpanElement(arrow) ? arrow : null } export const queryShareIcon = (context: Element): SVGSVGElement | null => { diff --git a/src/components/Social/Highlighter/index.astro b/src/components/Social/Highlighter/index.astro index 786719550..dda50b878 100644 --- a/src/components/Social/Highlighter/index.astro +++ b/src/components/Social/Highlighter/index.astro @@ -17,8 +17,6 @@ * important insight * ``` */ -import Icon from '@components/Icon/index.astro' -import './index.css' export interface Props { /** @@ -36,21 +34,4 @@ export interface Props { const { ariaLabel, class: className } = Astro.props --- - - - - - - - - - + diff --git a/src/components/Social/Highlighter/index.css b/src/components/Social/Highlighter/index.css index f63bc4a91..88546232d 100644 --- a/src/components/Social/Highlighter/index.css +++ b/src/components/Social/Highlighter/index.css @@ -1,39 +1,40 @@ -:where(highlighter-element) { - display: inline-block; +highlighter-element { + display: inline; position: relative; } -:where(highlighter-element) .highlighter__wrapper { - display: inline-flex; - flex-direction: column; +highlighter-element .highlighter__wrapper { + display: inline; position: relative; } -:where(highlighter-element) .highlighter__trigger { +highlighter-element .highlighter__trigger { + appearance: none; background: transparent; border: none; color: inherit; - cursor: inherit; - display: inline-flex; + cursor: pointer; + display: contents; font: inherit; - margin: 0; padding: 0; text-align: left; + vertical-align: baseline; + white-space: normal; } -:where(highlighter-element) .highlighter__trigger:focus-visible { - outline: 2px solid var(--color-spotlight); - outline-offset: 2px; -} - -:where(highlighter-element) .highlighter__content { +highlighter-element .highlighter__content { background-color: transparent; border-radius: 0; color: inherit; padding: 0; } -:where(highlighter-element) .share-dialog { +highlighter-element .highlighter__trigger:focus-visible .highlighter__content { + outline: 2px solid var(--color-spotlight); + outline-offset: 2px; +} + +highlighter-element .share-dialog { background-color: var(--color-page-offset); border-radius: 0.5rem; bottom: calc(100% + 0.75rem); @@ -46,8 +47,8 @@ z-index: var(--z-content-floating); } -:where(highlighter-element) .share-dialog::before, -:where(highlighter-element) .share-dialog::after { +highlighter-element .share-dialog::before, +highlighter-element .share-dialog::after { background: transparent; content: ''; height: 0.75rem; @@ -57,26 +58,27 @@ right: 0; } -:where(highlighter-element) .share-dialog::before { +highlighter-element .share-dialog::before { top: -0.75rem; } -:where(highlighter-element) .share-dialog::after { +highlighter-element .share-dialog::after { bottom: -0.75rem; } -:where(highlighter-element) .share-dialog[aria-hidden="false"] { +highlighter-element .share-dialog[aria-hidden="false"] { display: block; } -:where(highlighter-element) .share-dialog__buttons { +highlighter-element .share-dialog__buttons { align-items: center; display: flex; gap: 0.25rem; } -:where(highlighter-element) .share-button { +highlighter-element .share-button { align-items: center; + appearance: none; background-color: transparent; border: none; border-radius: 9999px; @@ -89,27 +91,27 @@ width: 2.5rem; } -:where(highlighter-element) .share-button:hover { +highlighter-element .share-button:focus-visible { + outline: 2px solid var(--color-spotlight); + outline-offset: 2px; +} + +highlighter-element .share-button:hover { background-color: var(--color-page-base); transform: translateY(-1px); } -:where(highlighter-element) .share-button:active { +highlighter-element .share-button:active { transform: translateY(0); } -:where(highlighter-element) .share-button:focus-visible { - outline: 2px solid var(--color-spotlight); - outline-offset: 2px; -} - -:where(highlighter-element) .share-icon { +highlighter-element .share-icon { fill: currentcolor; height: 1.25rem; width: 1.25rem; } -:where(highlighter-element) .share-dialog__arrow { +highlighter-element .share-dialog__arrow { border-left: 0.5rem solid transparent; border-right: 0.5rem solid transparent; border-top: 0.5rem solid var(--color-page-offset); diff --git a/src/components/Table/layouts/semantic-coloring.astro b/src/components/Table/layouts/semantic-coloring.astro index c5110f133..ff74ed67b 100644 --- a/src/components/Table/layouts/semantic-coloring.astro +++ b/src/components/Table/layouts/semantic-coloring.astro @@ -39,6 +39,11 @@ const tbodyClass = '' const tfootClass = '' const stateClasses = { + accent: { + rowBgClass: 'bg-accent-offset/20', + barClass: 'bg-accent-offset', + textClass: 'text-accent-offset', + }, note: { rowBgClass: 'bg-note-inverse', barClass: 'bg-note', @@ -67,11 +72,43 @@ const stateClasses = { } as const type SemanticStateName = keyof typeof stateClasses +const allowedSemanticStates: SemanticStateName[] = ['accent', 'note', 'success', 'warning', 'danger', 'info'] const isSemanticStateName = (value: string): value is SemanticStateName => { - return value === 'note' || value === 'success' || value === 'warning' || value === 'danger' || value === 'info' + return allowedSemanticStates.includes(value as SemanticStateName) +} + +const assertValidSemanticColor = (color: string | undefined, location: string) => { + if (!color || isSemanticStateName(color)) { + return + } + + throw new Error( + `semantic-coloring-table: invalid color "${color}" at ${location}. ` + + `Expected one of: ${allowedSemanticStates.join(', ')}.` + ) } +content.tbody.tr.forEach((row, rowIndex) => { + if (typeof row.th === 'object') { + assertValidSemanticColor(row.th.color, `tbody row ${rowIndex + 1} header`) + } + + row.td.forEach((cell, cellIndex) => { + if (typeof cell === 'object') { + assertValidSemanticColor(cell.color, `tbody row ${rowIndex + 1} cell ${cellIndex + 1}`) + } + }) +}) + +content.tfoot?.tr.forEach((row, rowIndex) => { + row.td.forEach((cell, cellIndex) => { + if (typeof cell === 'object') { + assertValidSemanticColor(cell.color, `tfoot row ${rowIndex + 1} cell ${cellIndex + 1}`) + } + }) +}) + const firstBodyRow = content.tbody.tr[0] const hasRowHeaders = content.tbody.tr.some(row => row.th !== undefined) const bodyColumnCount = hasRowHeaders diff --git a/src/components/ThemePicker/client/__tests__/selectors.spec.ts b/src/components/ThemePicker/client/__tests__/selectors.spec.ts index e36683922..3dba99d9b 100644 --- a/src/components/ThemePicker/client/__tests__/selectors.spec.ts +++ b/src/components/ThemePicker/client/__tests__/selectors.spec.ts @@ -70,7 +70,7 @@ describe('ThemePicker selectors', () => { await renderThemePickerDom(({ element }) => { element.querySelector('[data-theme-modal]')?.remove() - expect(() => getThemePickerModal(element)).toThrowError(ClientScriptError) + expect(() => getThemePickerModal(element)).toThrow(ClientScriptError) }) }) @@ -93,7 +93,7 @@ describe('ThemePicker selectors', () => { await renderThemePickerDom(() => { document.querySelector('[data-theme-toggle]')?.remove() - expect(() => getThemePickerToggleBtn()).toThrowError(ClientScriptError) + expect(() => getThemePickerToggleBtn()).toThrow(ClientScriptError) }) }) @@ -116,7 +116,7 @@ describe('ThemePicker selectors', () => { await renderThemePickerDom(({ element }) => { element.querySelector('[data-theme-close]')?.remove() - expect(() => getThemePickerCloseBtn(element)).toThrowError(ClientScriptError) + expect(() => getThemePickerCloseBtn(element)).toThrow(ClientScriptError) }) }) @@ -163,9 +163,9 @@ describe('ThemePicker selectors', () => { element.querySelector('[data-theme-embla-prev]')?.remove() element.querySelector('[data-theme-embla-next]')?.remove() - expect(() => getThemePickerEmblaViewport(element)).toThrowError(ClientScriptError) - expect(() => getThemePickerEmblaPrevBtn(element)).toThrowError(ClientScriptError) - expect(() => getThemePickerEmblaNextBtn(element)).toThrowError(ClientScriptError) + expect(() => getThemePickerEmblaViewport(element)).toThrow(ClientScriptError) + expect(() => getThemePickerEmblaPrevBtn(element)).toThrow(ClientScriptError) + expect(() => getThemePickerEmblaNextBtn(element)).toThrow(ClientScriptError) }) }) @@ -184,7 +184,7 @@ describe('ThemePicker selectors', () => { await renderThemePickerDom(({ element }) => { element.querySelectorAll('[data-theme]').forEach(button => button.remove()) - expect(() => getThemeSelectBtns(element)).toThrowError(ClientScriptError) + expect(() => getThemeSelectBtns(element)).toThrow(ClientScriptError) }) }) }) diff --git a/src/content.config.ts b/src/content.config.ts index 8fb27b2f3..42d4d843a 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -8,8 +8,9 @@ * The 'email' collection is included in the src/content directory, but is not handled by * Astro's collections systems. It is used by files in src/pages/api. */ -import { defineCollection, reference, z, type SchemaContext } from 'astro:content' +import { defineCollection, reference, type SchemaContext } from 'astro:content' import { glob, file } from 'astro/loaders' +import { z } from 'astro/zod' /** * Wraps a collection schema with a refinement that enforces breadcrumb title length limits */ @@ -52,7 +53,7 @@ const createSocialCollectionSchema = () => z.object({ network: z.string(), name: z.string(), - url: z.string().url(), + url: z.url(), order: z.number(), }) ) @@ -206,7 +207,7 @@ const authorsCollection = defineCollection({ z.object({ id: z.string(), name: z.string(), - email: z.string().email(), + email: z.email(), avatar: z.string(), social: createSocialCollectionSchema(), }), @@ -219,7 +220,7 @@ const contactDataCollection = defineCollection({ loader: file('./src/content/contact.json'), schema: z.object({ name: z.string(), - email: z.string().email(), + email: z.email(), address: z.string(), city: z.string(), state: z.string().length(2), diff --git a/src/content/articles/alert-fatigue-reduction-triage-actionable-alerts/pdf.mdx b/src/content/articles/alert-fatigue-reduction-triage-actionable-alerts/pdf.mdx index 94fa15203..0ffe3d689 100644 --- a/src/content/articles/alert-fatigue-reduction-triage-actionable-alerts/pdf.mdx +++ b/src/content/articles/alert-fatigue-reduction-triage-actionable-alerts/pdf.mdx @@ -385,7 +385,7 @@ Build your inhibition rules to match your architecture. Common patterns: diff --git a/src/content/articles/api-deprecation-sunset-headers-consumer-migration/index.mdx b/src/content/articles/api-deprecation-sunset-headers-consumer-migration/index.mdx index 585175e8a..ee82a276b 100644 --- a/src/content/articles/api-deprecation-sunset-headers-consumer-migration/index.mdx +++ b/src/content/articles/api-deprecation-sunset-headers-consumer-migration/index.mdx @@ -27,7 +27,7 @@ Your consumers have no inherent motivation to migrate. They have working code. M The common approach — send an announcement email, add deprecation headers, hope for the best — fails because it treats deprecation as an information problem. If consumers just _knew_ the API was deprecated, surely they would migrate. But they do know. They are ignoring you. -What actually works is treating deprecation as a _coordination_ problem. You need three things: +What actually works is treating deprecation as a _coordination_ problem. You need three things: @@ -145,7 +146,7 @@ The header format is straightforward, but there are common implementation mistak Metrics show aggregate health, but when something goes wrong, you need to see what happened to _specific requests_. Distributed tracing provides that request-level visibility by tracking individual requests across services. The gateway is the most critical point for trace context propagation. If the gateway doesn't forward trace headers to backends, your traces stop at the gateway boundary — you see the consumer-to-gateway span, but not the gateway-to-backend spans. The request flow becomes invisible exactly where you need it most. @@ -330,7 +330,7 @@ Find slow traces for the affected route in your tracing UI (Jaeger, Tempo, AWS X diff --git a/src/content/articles/api-gateway-metrics-traces-logs-debugging/pdf.mdx b/src/content/articles/api-gateway-metrics-traces-logs-debugging/pdf.mdx index 53d808dfb..35979889b 100644 --- a/src/content/articles/api-gateway-metrics-traces-logs-debugging/pdf.mdx +++ b/src/content/articles/api-gateway-metrics-traces-logs-debugging/pdf.mdx @@ -49,6 +49,8 @@ The fundamental difference is scope: every request passes through the gateway. W @@ -64,7 +66,7 @@ Each observability pillar answers different questions, and gateway debugging typ consumer_id only on counters, not histograms', }, { text: "Roll up consumer metrics to a separate, lower-resolution store", @@ -483,7 +486,7 @@ At high traffic volumes, you cannot keep every trace — storage costs and query @@ -1118,7 +1122,7 @@ Search your tracing system for spans with status code 503 during the error windo Without measurement, you're guessing at capacity planning, pricing decisions become political negotiations, and cost allocation is fiction. APIs aren't free to operate. Every request costs compute time, network transfer, and storage. Usage patterns vary wildly: one consumer might make 100 requests per day, another 10 million. The pattern I've seen repeatedly: teams build APIs focused on functionality, ship them, then realize months later they can't answer basic questions. Which team is driving costs? Which endpoints are expensive? Should we charge for this feature? By then, changing the contract is organizational surgery. @@ -30,6 +30,9 @@ The dimensions you capture become your billable units and cost attribution keys. +Pick idempotency keys if you're using PostgreSQL or TimescaleDB — they support unique constraints natively and give you exact deduplication. Use time-window deduplication if you're on ClickHouse or Prometheus where unique constraints aren't available. The storage cost of keeping event IDs is negligible compared to the cost of billing disputes. + ## Enforcing Quotas Before Costs Explode ### Rate Limits vs Quotas @@ -260,8 +265,6 @@ Send proactive alerts at 50%, 75%, and 90% of quota usage. At 90%, a consumer ha When the billing period ends and quotas reset to zero, requests immediately succeed again. The Redis key expires and the counter starts fresh. But watch for clock skew in distributed systems — use a grace period (2-5 minutes) where requests near the reset boundary are allowed even if the counter hasn't fully reset. -Implement this in your application logic: if a request is denied due to quota but the timestamp is within 5 minutes of the period boundary, check if the next period has started. If so, allow the request and count it against the new period. This prevents frustrating "429 errors at midnight" support tickets. - +Implement this in your application logic: if a request is denied due to quota but the timestamp is within 5 minutes of the period boundary, check if the next period has started. If so, allow the request and count it against the new period. This prevents frustrating "429 errors at midnight" support tickets. + ## Getting Started: Your First 30 Days You don't need to implement everything at once. Here's the path that works: You can't manage API costs you don't measure. Without usage metering, you're flying blind on capacity planning, pricing decisions, and cost allocation. +The pattern I've seen repeatedly: teams build APIs focused on functionality, ship them, then realize months later they can't answer basic questions. Which team is driving costs? Which endpoints are expensive? Should we charge for this feature? By then, changing the contract is organizational surgery. + ## The Metering Foundation ### What to Meter @@ -94,12 +94,12 @@ For storage-backed APIs (document processing, media transcoding, backup systems) The first question: should metering be synchronous or asynchronous? Synchronous metering blocks the request until the usage event is recorded. It's accurate but adds latency to every request. Asynchronous metering emits the event and continues processing — it's fast but introduces eventual consistency challenges. -For high-throughput APIs, async metering is usually the right call. Billing doesn't need millisecond accuracy. If a usage event takes 50ms to persist but your API target is sub-100ms latency, synchronous metering breaks your SLA. Emit events to a message queue and process them out-of-band. - Synchronous metering adds latency to every request. For high-throughput APIs, use asynchronous metering with eventual consistency — billing doesn't need millisecond accuracy. +For high-throughput APIs, async metering is usually the right call. Billing doesn't need millisecond accuracy. If a usage event takes 50ms to persist but your API target is sub-100ms latency, synchronous metering breaks your SLA. Emit events to a message queue and process them out-of-band. + ```yaml title="async-metering-architecture.yaml" # Deployed as sidecar or separate service components: @@ -172,10 +172,13 @@ Key decisions: team_analytics) not email addresses or names. Consumer IDs should be stable — if a team renames themselves, the ID stays constant.', }, { lead: "Timestamps:", @@ -183,11 +186,11 @@ Key decisions: }, { lead: "Status codes:", - text: "Separate billable requests (2xx) from errors (4xx, 5xx). You probably don't want to charge for failed requests.", + text: 'Separate billable requests (2xx) from errors (4xx, 5xx). You probably don\'t want to charge for failed requests.', }, { lead: "Cardinality:", - text: "Avoid unbounded fields like IP addresses or user agents in dimensions you'll aggregate by. Route patterns (`/users/:id`) are fine, raw paths (`/users/12345`) are not.", + text: 'Avoid unbounded fields like IP addresses or user agents in dimensions you\'ll aggregate by. Route patterns (/users/:id) are fine, raw paths (/users/12345) are not.', }, ]} /> @@ -491,6 +494,9 @@ Three common approaches: @@ -693,7 +700,7 @@ There's a spectrum between "no cost visibility" and "full chargebacks." Most org 5 for: 15m labels: @@ -1074,7 +1089,7 @@ The order matters: build metering first (you need data), then reporting (visibil When sync fails, you need to understand what ArgoCD is actually doing underneath the abstraction. ## What ArgoCD Is Actually Doing @@ -96,14 +96,16 @@ The wave numbers themselves are arbitrary — what matters is the relative order Sync waves control ordering _within_ the apply phase. But what if you need to run something _before_ sync starts, or _after_ it completes? -Hooks let you run resources _outside_ the normal apply process — before sync starts (PreSync), after it completes (PostSync), or when it fails (SyncFail). The most common use case is database migrations: run them after new code deploys but before traffic shifts. + -Hooks are typically Kubernetes Jobs. The critical thing to understand: ArgoCD waits for hooks to complete before proceeding. If a hook hangs, your entire sync hangs — with no timeout by default. +Hooks let you run resources _outside_ the normal apply process — before sync starts (PreSync), after it completes (PostSync), or when it fails (SyncFail). The most common use case is database migrations: run them after new code deploys but before traffic shifts. Always set `activeDeadlineSeconds` on hook Jobs. Without it, ArgoCD will wait forever for a stuck hook. +Hooks are typically Kubernetes Jobs. The critical thing to understand is that ArgoCD waits for hooks to complete before proceeding. If a hook hangs, the entire sync hangs with it — and by default, ArgoCD won't time it out for you. + ## The Four-Step Debugging Workflow When sync fails, resist the urge to poke at random things. A systematic approach gets you to the root cause faster. @@ -152,8 +154,6 @@ The output tells you sync status (Synced, OutOfSync, Unknown) and health status The `--show-operation` flag shows which phase the sync is in. "Running PreSync hooks" means a hook is stuck. "Sync error" with a message means apply failed. - - ### Step 2: Examine ArgoCD Logs ArgoCD has several components, each handling different parts: @@ -215,6 +215,9 @@ Once you've gathered information, match it against these common patterns:
@@ -242,7 +243,7 @@ When a dependency is missing, pods fail to start with characteristic error messa @@ -812,6 +820,9 @@ Beyond per-resource protection, ArgoCD offers several application-level sync opt
Alert on sync failures early. A 10-minute OutOfSync alert gives you time to investigate before users notice. A 30-minute stuck sync is almost always a real problem requiring intervention. +The runbook link in the annotations is critical. When an engineer gets paged at 3 AM, they shouldn't have to remember the debugging workflow — they should be able to follow a documented procedure. Link each alert to a runbook that walks through the investigation steps. + ## Advanced Troubleshooting When the standard debugging workflow doesn't reveal the problem, you need to dig deeper into ArgoCD's internals. These techniques address edge cases that arise in complex deployments or after upgrades. @@ -987,6 +998,9 @@ The table below summarizes when to use each tracking method:
This is the trap: availability targeting becomes a badge of engineering honor rather than an economic decision. Let me show you the math that kills the five nines argument. ## The Math That Kills Five Nines diff --git a/src/content/articles/backpressure-load-shedding-admission-control-overload/index.mdx b/src/content/articles/backpressure-load-shedding-admission-control-overload/index.mdx index 480f9ffdb..bf77396dd 100644 --- a/src/content/articles/backpressure-load-shedding-admission-control-overload/index.mdx +++ b/src/content/articles/backpressure-load-shedding-admission-control-overload/index.mdx @@ -24,7 +24,7 @@ I watched an e-commerce platform collapse during a flash sale. Traffic spiked to The fix wasn't more capacity. It was teaching the system to say "no." -Most systems don't fail because they can't handle load. They fail because they try to handle _all_ the load. Without explicit overload handling, a system accepts work it cannot complete, queues grow unbounded, and what starts as a traffic spike becomes a prolonged outage. +Most systems don't fail because they can't handle load. They fail because they try to handle _all_ the load. Without explicit overload handling, a system accepts work it cannot complete, queues grow unbounded, and what starts as a traffic spike becomes a prolonged outage. A system without backpressure will accept work until it collapses. The goal isn't handling unlimited load — it's handling your design capacity reliably and degrading gracefully beyond it. @@ -38,6 +38,7 @@ Overload doesn't just make systems slow — it makes them _worse_. There's a vic @@ -61,7 +62,7 @@ Consider a system processing 100 RPS with 200ms latency — that's 20 requests i Here's a counterintuitive truth: throughput can _increase_ during overload while your system becomes effectively useless. The distinction is between throughput (work attempted) and goodput (work successfully completed).
+ Admission control works the same way: decide _upfront_ whether to accept work, rather than accepting everything and failing later. A request rejected at the door costs almost nothing. A request that gets halfway through your system before timing out has consumed database connections, CPU cycles, and memory — resources that could have served requests you _could_ complete. Here's how that flow looks in practice: @@ -113,7 +116,7 @@ It's better to reject 20% of requests immediately than to accept 100% and fail 4 I've found four approaches cover most scenarios: +Of these, latency-based admission gives you the tightest feedback loop. Here's how it works as Express middleware: + ```typescript title="latency-admission-middleware.ts" // Express middleware for latency-based admission control import { Request, Response, NextFunction } from 'express'; @@ -225,8 +230,6 @@ Code: Priority-based routing reserves capacity for critical traffic. The key insight is that critical traffic can _borrow_ capacity from lower tiers. If the anonymous quota is exhausted but the critical quota has room, anonymous requests are rejected while payments keep flowing. - - ## Load Shedding and Graceful Degradation ### Choosing What to Shed @@ -234,7 +237,7 @@ The key insight is that critical traffic can _borrow_ capacity from lower tiers. Load shedding is the deliberate dropping of work to preserve system stability. It sounds brutal, but the alternative is worse. When you're drowning, you throw cargo overboard to keep the ship afloat.
**Application equivalent:** -1. Service advertises capacity (rate limits, queue depth) -2. Clients limit concurrent requests -3. As service recovers, capacity opens -4. If service is slow, clients back off + The elegance of TCP's approach is that backpressure is _automatic_. The receiver doesn't have to decide when to apply pressure — the window size naturally reflects its processing capacity. Application-level backpressure often requires more explicit coordination, but the principle is the same: consumers must be able to tell producers "slow down." @@ -573,7 +613,10 @@ Load shedding is the deliberate dropping of work to preserve system stability. I The key insight is that _some_ work completing successfully is better than _all_ work failing. If your system can handle 1,000 RPS but 2,000 are arriving, you have a choice: accept all 2,000 and watch goodput collapse to 400 (because everything times out), or shed 1,000 immediately and successfully serve the other 1,000.
@@ -635,18 +682,19 @@ Consider a queue with 100 requests where processing takes 100ms each: **LIFO shedding (counterintuitive but effective):** @@ -823,7 +871,11 @@ Graceful degradation requires knowing which features are expendable. Work with p Backpressure only works if clients understand the signal. HTTP provides specific status codes for communicating overload — use them correctly, and well-behaved clients will back off automatically.
@@ -1538,17 +1591,32 @@ The key is the assertions — don't just measure throughput, explicitly verify t Load testing validates behavior under high request volume. Chaos engineering validates behavior under _unexpected failures_—the scenarios that trigger backpressure mechanisms in ways traffic alone can't simulate.
concurrent_requests crosses 90% of your concurrency limit, you\'re not in trouble yet — but you\'re one traffic spike away. When queue_depth grows faster than it drains, backpressure is about to kick in. These metrics let you see overload coming before users notice.', }, { lead: "Backpressure indicators:", - text: "tell you when protection mechanisms are active. A spike in `requests_rejected` with reason `rate_limit` means your rate limiter is doing its job. If you see rejections with reason `circuit_open`, a downstream dependency is struggling. The `shed_requests` counter broken down by tier shows which degradation level you're operating at. These metrics answer the question: \"Is the system protecting itself correctly?\"", + text: 'Tells you when protection mechanisms are active. A spike in requests_rejected with reason rate_limit means your rate limiter is doing its job. If you see rejections with reason circuit_open, a downstream dependency is struggling. The `shed_requests` counter broken down by tier shows which degradation level you\'re operating at. These metrics answer the question: "Is the system protecting itself correctly?"', }, { lead: "Health indicators:", - text: "are the bottom line. `goodput_ratio` is the most important — it's the percentage of requests that actually succeeded. A 503 is a successful rejection (the system protected itself), but it's not goodput. If goodput drops below your SLO, users are suffering regardless of how well your backpressure mechanisms work. Latency percentiles matter too: p99 staying bounded while p50 degrades slightly is healthy backpressure; p99 exploding means something's queuing that shouldn't be.", + text: 'The bottom line. goodput_ratio is the most important — it\'s the percentage of requests that actually succeeded. A 503 is a successful rejection (the system protected itself), but it\'s not goodput. If goodput drops below your SLO, users are suffering regardless of how well your backpressure mechanisms work. Latency percentiles matter too: p99 staying bounded while p50 degrades slightly is healthy backpressure; p99 exploding means something\'s queuing that shouldn\'t be.', }, ]} /> +Of those three categories, the rejection metrics are usually the fastest way to identify which protective layer is currently absorbing the pressure. + -The `requests_rejected` label `reason` is critical. During an incident, you need to know _which_ mechanism is rejecting — rate limiter, circuit breaker, queue full, or admission control. Different reasons point to different root causes. +The requests_rejected label reason is critical. During an incident, you need to know _which_ mechanism is rejecting — rate limiter, circuit breaker, queue full, or admission control. Different reasons point to different root causes. ### Dashboard Layout @@ -1930,7 +2005,7 @@ The `requests_rejected` label `reason` is critical. During an incident, you need A good overload dashboard tells a story at a glance. When you're paged at 3 AM, you shouldn't have to hunt through 15 panels to understand what's happening. I've found a four-section layout works well:
+That layout works because each section answers a different on-call question, and the order mirrors how you triage an overload event in real time. + div]:pr-4", + }} items={[ { lead: "Load & Capacity:", - text: "goes at the top because it's your first question: \"How much traffic are we getting, and how close are we to limits?\" Show request rate as a line with capacity threshold as a horizontal marker. Show concurrency and queue depth as gauges with red zones. At a glance, you should see whether you're at 50% capacity or 95%.", + text: "Goes at the top because it's your first question: \"How much traffic are we getting, and how close are we to limits?\" Show request rate as a line with capacity threshold as a horizontal marker. Show concurrency and queue depth as gauges with red zones. At a glance, you should see whether you're at 50% capacity or 95%.", }, { lead: "Backpressure Activity:", - text: "answers the second question: \"Is the system protecting itself?\" Show rejection rates by type—429s (rate limiting), 503s (admission control), circuit breaker state (open/closed/half-open). If these counters are at zero, you're not in overload. If they're spiking, the system is actively shedding load. This section turns from green to yellow to red as backpressure intensifies.", + text: "Answers the second question: \"Is the system protecting itself?\" Show rejection rates by type—429s (rate limiting), 503s (admission control), circuit breaker state (open/closed/half-open). If these counters are at zero, you're not in overload. If they're spiking, the system is actively shedding load. This section turns from green to yellow to red as backpressure intensifies.", }, { lead: "Health Indicators:", - text: "answer the critical question: \"Are users being served?\" Goodput percentage should be front and center — if it's above 95%, things are okay even if you're shedding some load. P99 latency shows whether successful requests are still fast. Error rate distinguishes between deliberate rejections (503s you sent) and unexpected failures (5xxs from bugs).", + text: "Answers the critical question: \"Are users being served?\" Goodput percentage should be front and center — if it's above 95%, things are okay even if you're shedding some load. P99 latency shows whether successful requests are still fast. Error rate distinguishes between deliberate rejections (503s you sent) and unexpected failures (5xxs from bugs).", }, { lead: "Degradation State:", - text: "shows operational mode at a glance. If you've implemented graceful degradation tiers, show the current tier prominently — a big \"ELEVATED\" or \"CRITICAL\" badge tells the on-call engineer immediately that the system is in a degraded state. List which features are disabled so they don't waste time investigating why search isn't working.", + text: "Shows operational mode at a glance. If you've implemented graceful degradation tiers, show the current tier prominently — a big \"ELEVATED\" or \"CRITICAL\" badge tells the on-call engineer immediately that the system is in a degraded state. List which features are disabled so they don't waste time investigating why search isn't working.", }, ]} /> +When those sections are arranged well, the dashboard stops being a wall of charts and starts reading like a short incident narrative. + During an incident, read the dashboard top to bottom: "We're at 120% capacity (Load), rejecting 20% of requests (Backpressure), maintaining 85% goodput (Health), in ELEVATED mode with recommendations disabled (Degradation)." That's a complete situational picture in 10 seconds. @@ -1991,6 +2073,9 @@ Here's what that looks like in practice: Instead of asking "who screwed up?" blameless postmortems ask: Why could a single engineer make that change without review? Why was there no canary deployment? Why didn't monitoring catch the error before customers did? That investigation finds five systemic improvements instead of one scapegoat. ## Why Blame Feels Right But Fails @@ -26,7 +26,10 @@ Blame provides closure. We have a narrative: someone did something wrong, we ide But blame produces terrible outcomes. When people fear punishment for mistakes, they stop reporting near-misses. They hedge their language in postmortems. They cover their tracks. The information you need to prevent future incidents disappears into self-protective silence.
@@ -138,47 +144,63 @@ The phrase "root cause" implies there's one cause at the bottom of the causal ch The Five Whys technique — keep asking "why" until you reach an actionable cause — is popular but easily misused. Here's what going wrong looks like: -```text title="five-whys-antipattern.txt" -Q: Why did the system go down? -A: Because a config change broke it. - -Q: Why did the config change break it? -A: Because the engineer made a mistake. - -Q: Why did the engineer make a mistake? -A: Because they were careless. + -[Investigation stops at blame — nothing actionable learned] -``` -Code: Five Whys antipattern that terminates at human blame. +Five Whys antipattern that stops at blame — nothing actionable learned. And here's the same incident investigated properly: -```text title="five-whys-systemic.txt" -Q: Why did the system go down? -A: Because a config change disabled authentication. - -Q: Why did the config change disable authentication? -A: Because the config schema changed and old values became invalid. - -Q: Why did old values become invalid? -A: Because the migration script didn't update existing configs. - -Q: Why didn't the migration update existing configs? -A: Because no one knew configs existed in that format. - -Q: Why didn't anyone know? -A: Because documentation was outdated and there was no config inventory. + -[Five actionable systemic issues identified] -``` -Code: Five Whys done well, leading to systemic improvements. +Five Whys done well, leading to systemic improvements from actionable issues. The difference is where you choose to stop. If you reach a human attribute — careless, rushed, didn't know — that's a signal you've taken a wrong turn. Human attributes aren't fixable. But every human attribute has a system context: Why was carelessness possible? What created the rush? Why wasn't the knowledge available? @@ -193,7 +215,7 @@ The analysis is only as valuable as the actions it produces. I've seen beautiful Good action items share specific characteristics:
+Those characteristics sound straightforward in the abstract, but the difference shows up quickly when you compare action items side by side. One set points to concrete engineering changes you can implement and verify; the other just restates frustration in softer language. + An incident without completed action items is an incident that will recur. Track actions to completion, verify they work, and close the loop in a follow-up meeting. +Here's a useful test: if someone else picked up the action item, would they know exactly what to build or change? If the answer is no, refine it until they would. + ## The Path Forward Blameless postmortems aren't soft — they're more rigorous than blame culture. They demand that we find _all_ the contributing factors, not just the most obvious one. They demand _real_ fixes, not just "be more careful." They demand measurement to verify fixes actually work. @@ -276,20 +303,20 @@ The core principles: variant="check-icons-list" items={[ { - lead: "Human error is where investigation begins, not where it ends:", - text: "The interesting question is always: what made that action likely, possible, and undetected?", + lead: "Human error is where investigation begins, not where it ends", + text: "the interesting question is always: what made that action likely, possible, and undetected?", }, { - lead: "Blame produces hiding; systems thinking produces learning:", - text: "When people fear punishment, they stop reporting. When they feel safe, they share near-misses that prevent future incidents.", + lead: "Blame produces hiding; systems thinking produces learning", + text: "when people fear punishment, they stop reporting. When they feel safe, they share near-misses that prevent future incidents.", }, { - lead: "Incidents have contributing factors, not root causes:", - text: "Complex failures arise from multiple interacting conditions. Identify them all before deciding which to fix.", + lead: "Incidents have contributing factors, not root causes", + text: "complex failures arise from multiple interacting conditions. Identify them all before deciding which to fix.", }, { - lead: "Effective remediation requires specific, systemic action items tracked to completion:", - text: "Vague actions don't get done. Person-focused actions don't prevent recurrence.", + lead: "Effective remediation requires specific, systemic action items tracked to completion", + text: "vague actions don't get done. Person-focused actions don't prevent recurrence.", }, ]} /> diff --git a/src/content/articles/blameless-postmortem-incident-analysis-systemic-causes/pdf.mdx b/src/content/articles/blameless-postmortem-incident-analysis-systemic-causes/pdf.mdx index 084fbc150..c06501065 100644 --- a/src/content/articles/blameless-postmortem-incident-analysis-systemic-causes/pdf.mdx +++ b/src/content/articles/blameless-postmortem-incident-analysis-systemic-causes/pdf.mdx @@ -29,12 +29,12 @@ This feels satisfying — we found the problem and addressed it. But three month The blameless investigation asks different questions: Why could a single engineer make that change without review? Why was there no canary deployment? Why didn't monitoring catch the error rate spike before customers did? Why was the config format so easy to break? That investigation finds five systemic improvements instead of one scapegoat. -This isn't about being soft on mistakes. It's about being rigorous enough to find causes that actually prevent recurrence. If you're responsible for incident response, reliability engineering, or leading engineering teams, this guide will help you build postmortem practices that actually improve your systems. - "Human error" is not a root cause — it's the starting point for investigation. Every incident involves human actions, but the interesting question is: what about the system made that action likely, possible, and undetected? +This isn't about being soft on mistakes. It's about being rigorous enough to find causes that actually prevent recurrence. If you're responsible for incident response, reliability engineering, or leading engineering teams, this guide will help you build postmortem practices that actually improve your systems. + ## The Case Against Blame ### Why Blame Feels Right But Fails @@ -44,7 +44,10 @@ Blame feels right because it provides closure. We have a narrative: someone did But blame produces terrible outcomes. When people fear punishment for mistakes, they stop reporting near-misses. They hedge their language in postmortems. They cover their tracks. The information you need to prevent future incidents disappears into self-protective silence.
@@ -124,7 +130,10 @@ If the answer to the last question is "hundreds of times," then the action itsel "Blameless" is frequently misunderstood. It doesn't mean no one is accountable. It doesn't mean we ignore mistakes or lower our standards. It means we hold the _right things_ accountable — and in complex systems, that's almost never an individual human making a one-off error.
+These categories aren't always clear-cut in the moment. The table below summarizes each behavior type with a concrete example and the appropriate organizational response, so facilitators can reference it during postmortem discussions. +
@@ -391,6 +410,7 @@ The words we use shape the investigation. Blame-oriented language ("they should
-[Investigation stops at blame — nothing actionable learned] -``` -Code: Five Whys antipattern that terminates at human blame. +Five Whys antipattern that stops at blame — nothing actionable learned. And here's the same incident investigated properly: -```text title="five-whys-systemic.txt" -Five Whys - The Systems Path: - -Q: Why did the system go down? -A: Because a config change disabled authentication. - -Q: Why did the config change disable authentication? -A: Because the config schema changed and old values became invalid. - -Q: Why did old values become invalid? -A: Because the migration script did not update existing configs. - -Q: Why did the migration not update existing configs? -A: Because no one knew configs existed in that format. - -Q: Why did no one know? -A: Because the documentation was outdated and there was no config inventory. - -[Five actionable systemic issues identified] -``` -Code: Five Whys done well, leading to systemic improvements. + The difference is where you choose to stop. If you reach a human attribute — careless, rushed, didn't know — that's a signal you've taken a wrong turn. Human attributes aren't fixable. But every human attribute has a system context: Why was carelessness possible? What created the rush? Why wasn't the knowledge available? @@ -499,7 +528,7 @@ There are real limitations to Five Whys even when done well: -- __Knowledge limits__: You can only ask "why" about things you know happened. Unknown factors don't get investigated. - For simple incidents with clear causation, Five Whys is often sufficient. For complex incidents with multiple interacting factors, you'll need more sophisticated analysis frameworks. ### STAMP/CAST Analysis for Complex Incidents @@ -537,7 +568,7 @@ STAMP treats safety as a control problem. Systems fail not because of component The insight is that the engineer making a config change is just the _lowest level_ of control. If you only investigate at that level, you're ignoring all the levels above that enabled, permitted, or encouraged the action. CAST asks questions at every level:
+In practice, the gap between good and bad action items is immediately obvious when you put them next to each other. Notice how the effective examples describe a specific engineering change, while the ineffective ones could mean almost anything — or nothing at all. +
"Implement 1% canary with automatic rollback on error spike."

"Add config change review requirement to deploy pipeline."', }, { lead: "Bad examples:", - text: "\"Be more careful with config changes.\" \"Engineer X needs training.\" \"Review all configs.\" \"Improve monitoring.\"", + text: '"Be more careful with config changes."

"Engineer X needs training."

"Review all configs."

"Improve monitoring."', }, ]} /> @@ -680,30 +713,30 @@ The "bad" examples deserve some attention because they're so common. "Be more ca Here's a useful test: if someone else picked up the action item, would they know exactly what to build or change? If the answer is no, the action item needs refinement.
@@ -913,7 +946,7 @@ Store postmortems in a searchable, centralized location — a wiki, Confluence, A single postmortem document serves readers with very different needs. The executive wants to know business impact in thirty seconds. The on-call engineer wants to know what to do if this recurs at 3 AM. Future investigators want every detail you can provide. Somehow, the document needs to work for all of them.
@@ -1015,25 +1055,28 @@ culture_metrics: Code: Balanced metrics across process, outcomes, and culture.
@@ -1103,32 +1146,31 @@ The harder path — blameless investigation — requires discipline. It means as Let's recap the core principles: - Blameless culture isn't soft. It's more rigorous than blame culture, not less. It demands that we find _all_ the contributing factors, not just the most obvious one. It demands that we implement _real_ fixes, not just "be more careful." It demands that we measure whether our fixes actually work. That's harder than pointing at a person and saying "don't do that again." -The organizations that learn fastest are the ones where people feel safe enough to say "I made a mistake, and here's what we should change so it doesn't happen again." Building that safety — and that rigor — is the work. - The goal of incident analysis is not to find who to blame. It's to find what to change so that the same class of incident becomes less likely. A blameless postmortem that produces no systemic improvements has failed — not because it didn't assign blame, but because it didn't learn. + +The organizations that learn fastest are the ones where people feel safe enough to say "I made a mistake, and here's what we should change so it doesn't happen again." Building that safety — and that rigor — is the work. diff --git a/src/content/articles/blue-green-canary-deployment-strategy-comparison/diagrams/canary-deployment-progression-with-traffic-percentage-increase.jpg b/src/content/articles/blue-green-canary-deployment-strategy-comparison/diagrams/canary-deployment-progression-with-traffic-percentage-increase.jpg index 8a356c9fa..7c393364b 100644 Binary files a/src/content/articles/blue-green-canary-deployment-strategy-comparison/diagrams/canary-deployment-progression-with-traffic-percentage-increase.jpg and b/src/content/articles/blue-green-canary-deployment-strategy-comparison/diagrams/canary-deployment-progression-with-traffic-percentage-increase.jpg differ diff --git a/src/content/articles/blue-green-canary-deployment-strategy-comparison/diagrams/key-challenges-with-blue-green-deployment-strategy.jpg b/src/content/articles/blue-green-canary-deployment-strategy-comparison/diagrams/key-challenges-with-blue-green-deployment-strategy.jpg index 6628f53e6..9e8ed918e 100644 Binary files a/src/content/articles/blue-green-canary-deployment-strategy-comparison/diagrams/key-challenges-with-blue-green-deployment-strategy.jpg and b/src/content/articles/blue-green-canary-deployment-strategy-comparison/diagrams/key-challenges-with-blue-green-deployment-strategy.jpg differ diff --git a/src/content/articles/blue-green-canary-deployment-strategy-comparison/index.mdx b/src/content/articles/blue-green-canary-deployment-strategy-comparison/index.mdx index 5c35e9f0c..c05806ba5 100644 --- a/src/content/articles/blue-green-canary-deployment-strategy-comparison/index.mdx +++ b/src/content/articles/blue-green-canary-deployment-strategy-comparison/index.mdx @@ -21,14 +21,28 @@ Here's the uncomfortable truth most deployment strategy comparisons skip: the "b Before we dive into the database problem, let's establish baseline understanding of what these strategies actually do. -__Blue/green deployment__ maintains two identical production environments. Blue runs your current version. When you're ready to release, you deploy to green, test it thoroughly, then switch all traffic at once. If something breaks, you switch back to blue. - -__Canary deployment__ takes the opposite approach. Instead of switching everyone simultaneously, you route a small percentage of traffic — say, 5%—to the new version. You watch metrics, gradually increase the percentage, and only complete the rollout once you're confident the new version is healthy. + The fundamental difference comes down to exposure:
- - - This pattern works with both strategies, but it's __mandatory__ for canary deployments. Blue/green can sometimes shortcut this with careful timing and instant cutover, but you're accepting more risk. ```sql @@ -121,12 +135,14 @@ The teams that struggle with deployment strategies are usually the ones trying t Now that we've established database compatibility as the primary constraint, the decision framework becomes clearer. Here's how to choose. -### Choose Blue/Green When +### Choose Blue / Green When Your deployments frequently include database migrations that can't easily follow expand-contract patterns. Legacy systems with tightly coupled schemas often fall into this category. You need instant, complete rollback. Blue/green's traffic switch is as close to "undo" as deployments get. If your downtime tolerance is measured in seconds rather than minutes, this matters. + + Your team is smaller or less experienced with progressive delivery. Blue/green is conceptually simpler: deploy, test, switch. There's less tooling to maintain and fewer operational scenarios to train for. You can afford the infrastructure cost. Running two complete environments doubles your compute costs during deployments. For many organizations, this is acceptable for the operational simplicity it provides. @@ -151,6 +167,10 @@ Many mature organizations don't choose one strategy — they use both. Schema mi The key insight is that the database constraint drives the decision __per deployment__, not as a blanket policy. A team might deploy three canary releases in a row, then switch to blue/green for a migration, then back to canary. The tooling supports both; the deployment contents determine which to use. +## Conclusion + +The deployment strategy debate often focuses on the wrong things — rollback speed, blast radius, tooling sophistication. These matter, but they're secondary to the fundamental question: what are you actually deploying? + -## Conclusion - -The deployment strategy debate often focuses on the wrong things — rollback speed, blast radius, tooling sophistication. These matter, but they're secondary to the fundamental question: what are you actually deploying? - For database schema changes, blue/green's instant cutover is often the only safe option. For application logic changes, canary's gradual rollout provides better production validation with limited risk. Most real-world systems need both approaches, selected based on what each specific deployment contains. The best deployment strategy isn't the most technically impressive one. It's the one your team can operate reliably, that matches your database change patterns, and that you'll actually use consistently. Start with the simpler option that works for your constraints, and add sophistication only when you have specific problems that require it. diff --git a/src/content/articles/blue-green-canary-deployment-strategy-comparison/pdf.mdx b/src/content/articles/blue-green-canary-deployment-strategy-comparison/pdf.mdx index 0f8773aa7..5255daca4 100644 --- a/src/content/articles/blue-green-canary-deployment-strategy-comparison/pdf.mdx +++ b/src/content/articles/blue-green-canary-deployment-strategy-comparison/pdf.mdx @@ -1,8 +1,8 @@ --- -title: "Blue/Green vs Canary: Choosing Deployment Strategies" +title: "Blue/green vs Canary: Choosing Deployment Strategies" description: "Tradeoffs between deployment strategies for stateless and stateful workloads, with and without service mesh." cover: "./cover.jpg" -coverAlt: "Deployment strategy spectrum showing progression from simple to complex: Recreate, Rolling, Blue/Green, Canary, and Progressive deployment patterns" +coverAlt: "Deployment strategy spectrum showing progression from simple to complex: Recreate, Rolling, Blue/green, Canary, and Progressive deployment patterns" author: "kevin-brown" publishDate: 2023-08-20 tags: ["build-and-deploy", "kubernetes", "aws", "python", "prometheus", "typescript"] @@ -60,7 +60,7 @@ Before diving into blue/green and canary specifically, it helps to see where the td: ["No*", "Minutes", "1x-1.5x", "Low"], }, { - th: "Blue/Green", + th: "Blue/green", td: ["No", "Seconds", "2x", "Medium"], }, { @@ -76,29 +76,30 @@ Before diving into blue/green and canary specifically, it helps to see where the }} /> +The numbers tell part of the story, but the real differences are in how each strategy behaves when things go wrong. Here's what those tradeoffs actually look like in practice: + - ### When Simple Wins I've seen teams implement canary deployments for services that deploy once a month. The infrastructure sat idle 99% of the time, and when they did deploy, no one remembered how the analysis worked. A rolling update with good smoke tests would have been simpler and just as effective. @@ -113,9 +114,9 @@ The questions that actually matter: That last question is the one teams most often ignore. If your schema migration breaks the old version, it doesn't matter whether you're doing blue/green, canary, or rolling — you've got a problem. We'll cover this in detail later. -## Blue/Green Deployments +## Blue/green Deployments -### How Blue/Green Works +### How Blue/green Works Blue/green deployment maintains two identical production environments. At any time, one is "live" (receiving traffic) and one is "idle" (ready for the next deployment). When you deploy, you update the idle environment, validate it, then switch traffic. The old live environment becomes the new idle — ready for instant rollback if needed. @@ -196,30 +197,30 @@ Code: Kubernetes blue/green deployment using label selectors. The cutover is a single `kubectl patch` command. No pods restart, no gradual rollout — traffic shifts immediately. And because the old version keeps running, rollback is equally instant — just point traffic back.
-### Blue/Green Challenges +### Blue/green Challenges Blue/green isn't free. The tradeoffs are real, and ignoring them leads to surprises. @@ -250,7 +252,7 @@ __Warmup time__ catches teams off guard. The green environment might be "up" but You can mitigate the resource cost:

", + lead: "Must be version-aware.", + text: "Your metrics need to distinguish canary from stable so you can compare error rates and latencies. \"Overall error rate is 0.5%\" doesn't help — you need \"canary error rate is 2%, stable is 0.3%.\" This means version labels on all metrics, dashboards that compare versions side by side, and alerting that understands the traffic split.", }, { - lead: "Stateful requests:", - text: "create consistency problems. If a user's session spans multiple requests, they might hit v1.0 for the first request and v1.1 for the second. For stateless APIs this is fine, but for stateful workflows it can cause bugs that only appear in production during canary.", + title: "Stateful requests:", + lead: "Creates consistency problems.", + text: "If a user's session spans multiple requests, they might hit v1.0 for the first request and v1.1 for the second. For stateless APIs this is fine, but for stateful workflows it can cause bugs that only appear in production during canary.", }, { - lead: "Database schema:", - text: "affects canary exactly as it affects blue/green — both versions must work with the same schema. Canary doesn't solve this problem; it just means both versions run simultaneously for longer.", + title: "Database schema:", + lead: "Affects canary exactly as it affects blue/green.", + text: "Both versions must work with the same schema. Canary doesn't solve this problem; it just means both versions run simultaneously for longer.", }, ]} /> @@ -536,10 +543,14 @@ The key insight is using both absolute thresholds (error rate > 5% is always bad With both strategies understood, the choice comes down to your constraints and priorities. This matrix summarizes the trade-offs:
+Here's how those advantages compare when you put canary routing, feature flags, and the combined approach side by side: +
+Those qualitative differences translate into concrete numbers that matter during an incident, when seconds count and mixed-version windows create real risk: +
@@ -883,18 +906,24 @@ Consider a scenario: v1.1 adds a `preferences_json` column and starts writing us The solutions are all variations of "design for this upfront": The goal isn't the most sophisticated deployment strategy — it's reliable deployments with fast recovery. A well-operated blue/green deployment is better than a poorly-operated canary. Choose the strategy you can do well. + +Start simple. If you're currently doing manual deployments with downtime, rolling updates are a meaningful improvement. If rolling updates work well but you want faster rollback, blue/green is the next step. If blue/green works well but you've been burned by staging-production differences, then consider canary. + +The best deployment strategy is the one your team can operate reliably at 3 AM when something goes wrong. diff --git a/src/content/articles/cdn-edge-caching-cache-keys-vary-headers/index.mdx b/src/content/articles/cdn-edge-caching-cache-keys-vary-headers/index.mdx index 2fa127889..2dfae9281 100644 --- a/src/content/articles/cdn-edge-caching-cache-keys-vary-headers/index.mdx +++ b/src/content/articles/cdn-edge-caching-cache-keys-vary-headers/index.mdx @@ -18,7 +18,7 @@ The cache hit ratio looked fantastic. 94% of requests served from edge. Response This is the fundamental tension in edge caching. Aggressive caching dramatically improves performance and reduces origin load, but incorrect configuration serves wrong content to users — sometimes catastrophically. Edge caching is a __data integrity__ problem first, performance problem second. -The good news: two concepts cause the vast majority of CDN cache bugs, and once you understand them, you can cache aggressively without fear. Those concepts are cache keys and Vary headers. +The good news: two concepts cause the vast majority of CDN cache bugs, and once you understand them, you can cache aggressively without fear. Those concepts are cache keys and Vary headers. ## Cache Keys Determine Correctness @@ -26,7 +26,7 @@ A cache key is the identifier the CDN uses to store and retrieve cached response By default, most CDNs use a simplified version of the URL: -```text + Default cache key: SCHEME + HOST + PATH + QUERY_STRING @@ -35,7 +35,7 @@ Example request: Cache key: "https://example.com/api/products?category=shoes" -``` + This seems straightforward, but the details matter enormously. Two requests that __should__ return identical content but generate different cache keys create duplicate cache entries — wasting storage and reducing hit ratios. Two requests that __should__ return different content but generate the same cache key serve wrong content to users — exactly the bug we opened with. @@ -45,15 +45,15 @@ The rule is simple: every attribute that affects your response must be in the ca Query parameters are the most common source of cache key problems. Consider these two URLs: -```text + Problem: Query parameter order These are the same request but different cache keys: - /products?color=red&size=large - /products?size=large&color=red +   /products?color=red&size=large +   /products?size=large&color=red Result: Two cache entries for identical content -``` + Different parameter order, different cache keys, same content — you're now storing two copies and reducing your hit ratio. Marketing teams compound this by adding tracking parameters to URLs. Every `utm_source`, `fbclid`, and `gclid` creates a unique cache key for content that's identical regardless of how the user arrived. @@ -89,6 +89,8 @@ Query parameter pollution is one of the most common causes of poor cache hit rat The `Vary` header tells caches "this response differs based on these request headers." It's the origin's way of saying "I returned different content to different clients based on header X, so you need to store separate cached versions." + + When a CDN sees `Vary: Accept-Language`, it doesn't just store one cached response per URL — it stores one per URL __per unique Accept-Language value__. The cache key effectively becomes URL + the values of all headers listed in Vary. ```http title="vary-example.http" @@ -105,7 +107,8 @@ With two headers in Vary, you get a combinatorial explosion of cache variants. E The guideline: only vary on headers with a small, known set of values.
- ### The Cookie Vary Trap The most common Vary mistake is `Vary: Cookie`. It seems logical — if your response depends on cookies, tell the cache to vary on them. But cookies include session IDs, authentication tokens, and tracking identifiers that are unique per user. Even when the actual content-affecting cookie (`preferences=dark`) is the same, the unique session IDs create separate cache entries. @@ -188,14 +189,31 @@ Understanding cache keys and Vary headers lets you avoid the two most dangerous This is the bug from our opening story — serving one user's content to another. It happens when: -- Your origin returns `Cache-Control: public` for personalized responses -- You vary on session cookie but session IDs still contaminate the cache key -- You cache without checking for authentication headers +Cache-Control: public for personalized responses', + }, + { + color: "bg-danger-offset", + text: "You vary on session cookie but session IDs still contaminate the cache key", + }, + { + color: "bg-danger-offset", + text: "You cache without checking for authentication headers", + }, + ]} +/> The patterns that keep you safe:
-## Getting It Right - -Both of these bugs — and most CDN issues you'll encounter — stem from the same root cause: a mismatch between what's in the cache key and what actually affects the response. - A properly-configured cache with 70% hit ratio beats a misconfigured cache with 95% hit ratio. The latter is serving wrong content to 95% of users — or worse, leaking private data between users. Start with serving correct content: audit your cache keys, normalize your Vary headers, and verify that personalized content can never be cached. Once you've established that foundation, you can optimize for performance with confidence. diff --git a/src/content/articles/cdn-edge-caching-cache-keys-vary-headers/pdf.mdx b/src/content/articles/cdn-edge-caching-cache-keys-vary-headers/pdf.mdx index f2050e8af..d56ce3dc1 100644 --- a/src/content/articles/cdn-edge-caching-cache-keys-vary-headers/pdf.mdx +++ b/src/content/articles/cdn-edge-caching-cache-keys-vary-headers/pdf.mdx @@ -28,12 +28,12 @@ The cache hit ratio looked fantastic. 94% of requests served from edge. Response This is the fundamental tension in edge caching. Aggressive caching dramatically improves performance and reduces origin load, but incorrect configuration serves wrong content to users — sometimes catastrophically. Edge caching is a __correctness__ problem first, performance problem second. -The techniques in this article address that tension: how to design cache keys that prevent content cross-contamination, how to use Vary headers without destroying hit ratios, and how to invalidate content without leaving stale data at the edge. Get the correctness right, and you can cache aggressively. Get it wrong, and your CDN becomes a liability. - A cache that serves incorrect content is worse than no cache at all. Before optimizing cache hit ratios, ensure your cache configuration cannot serve one user's content to another. +The techniques in this article address that tension: how to design cache keys that prevent content cross-contamination, how to use Vary headers without destroying hit ratios, and how to invalidate content without leaving stale data at the edge. Get the correctness right, and you can cache aggressively. Get it wrong, and your CDN becomes a liability. + ## How Edge Caching Works ### The Request Flow @@ -53,7 +53,7 @@ The performance difference is dramatic. A cache hit typically returns in 10-50ms Not every response can be cached, and CDNs apply conservative defaults. Understanding what triggers caching — and what prevents it — is essential for both maximizing hit ratios and avoiding correctness bugs.
`s-maxage` controls shared cache (CDN) TTL separately from `max-age` which controls browser cache. This lets you cache aggressively at the edge (24 hours) while keeping browser caches short (1 hour) for faster updates when you purge. @@ -127,16 +129,16 @@ A cache key is the identifier the CDN uses to store and retrieve cached response By default, most CDNs use a simplified version of the URL as the cache key: -```text -Default cache key (simplified): + +Default cache key: SCHEME + HOST + PATH + QUERY_STRING -Example: +Example request: https://example.com/api/products?category=shoes Cache key: "https://example.com/api/products?category=shoes" -``` + This seems straightforward, but the details matter enormously. Two requests that should return identical content but generate different cache keys create duplicate cache entries — wasting storage and reducing hit ratios. Two requests that should return different content but generate the same cache key serve wrong content to users — the correctness bug we're trying to avoid. @@ -177,15 +179,16 @@ The defaults are conservative: most request attributes are excluded from the cac Query parameters are the most common source of cache key problems. Consider these two URLs: -```text + Problem: Query parameter order These are the same request but different cache keys: - /products?color=red&size=large - /products?size=large&color=red -Result: Two cache entries for identical content (cache pollution) -``` +   /products?color=red&size=large +   /products?size=large&color=red + +Result: Two cache entries for identical content + Different parameter order, different cache keys, same content — you're now storing two copies and reducing your hit ratio. Marketing teams compound this by adding tracking parameters to URLs. Every `utm_source`, `fbclid`, and `gclid` creates a unique cache key for content that's identical regardless of how the user arrived. @@ -244,10 +247,11 @@ Vary: Accept-Encoding, Accept-Language With two headers in Vary, you get a combinatorial explosion of cache variants: -```text + Vary: Accept-Encoding, Accept-Language Creates cache variants: + Cache key + Accept-Encoding: gzip + Accept-Language: en-US Cache key + Accept-Encoding: gzip + Accept-Language: es-ES Cache key + Accept-Encoding: br + Accept-Language: en-US @@ -256,7 +260,7 @@ Creates cache variants: ... Each unique combination = separate cache entry -``` + This is powerful — it lets you cache content that legitimately varies by request attributes. But it's also dangerous, because Vary headers with high-cardinality values can destroy your cache effectiveness entirely. @@ -265,7 +269,7 @@ This is powerful — it lets you cache content that legitimately varies by reque The rule is simple: only vary on headers with a small, known set of values. The more unique values a header can have, the more cache entries you create and the lower your hit ratio drops.
+These patterns are easy to identify in a table, but catching them in a running system requires automated enforcement. The following middleware intercepts outgoing responses and checks for the most dangerous combination — personalized content paired with a public cache header — overriding it before the response reaches the CDN. + ```typescript [g2:Express Middleware] // Middleware to prevent accidental caching of personalized content @@ -886,7 +892,15 @@ This vulnerability is common because web frameworks often trust proxy headers by Cache Poisoning Attack: -1. Attacker sends request with malicious header: + ```http GET /page HTTP/1.1 @@ -894,21 +908,52 @@ Host: example.com X-Forwarded-Host: evil.com ``` -2. Vulnerable origin reflects header in response: + ```html ``` -3. Response is cached (`X-Forwarded-Host` not in cache key) - -4. Legitimate users get poisoned cached response + Prevention: -- Include attack vectors in cache key, OR -- Normalize/validate headers at edge before forwarding -- Do not reflect untrusted headers in responses + ```yaml [g3:Pseudocode] # Pseudocode CDN cache poisoning prevention policy @@ -1003,7 +1048,7 @@ E-commerce sites often return different content based on the user's location — This bug is insidious because it often goes unnoticed during development. Your test users are all in the same country, so everyone sees correct content. The first German user to hit a cached US response discovers the problem — usually at checkout when the currency doesn't match.
GET /products', 'GET /products'], }, { - th: "2. Cache status", - td: ["MISS", "HIT (User A's response)"], + th: "Cache status", + td: ['MISS', 'HIT (User A\'s response)'], }, { - th: "3. Response", - td: ["Prices in EUR ✓", "Prices in EUR ✗"], + th: "Response", + td: ['Prices in EUR ', 'Prices in EUR '], }, { - th: "4. Outcome", - td: ["Correct experience", "Checkout fails — wrong currency"], + th: "Outcome", + td: ['Correct experience', 'Checkout fails — wrong currency'], }, ], }, @@ -1037,7 +1082,7 @@ No geographic variation in cache key. Both users hit the same cache entry despit
CF-IPCountry (or equivalent) to cache key', "Automatic, per-country caching", "Many cache variants, cold caches per region", ], @@ -1056,7 +1101,7 @@ No geographic variation in cache key. Both users hit the same cache entry despit { th: "Separate endpoints", td: [ - "Use explicit country param: `/api/products?country=DE`", + 'Use explicit country param: /api/products?country=DE', "Explicit, highly cacheable", "Client must know country", ], @@ -1118,7 +1163,7 @@ Cache hit ratio is the percentage of requests served from cache versus total req The strategies below are ordered by impact-to-effort ratio. Query string normalization and cache key simplification typically yield the largest improvements with the least work. Content negotiation and TTL tuning require more analysis but can push hit ratios from good to excellent.
utm_*, fbclid, gclid); remove empty parameters', ], }, { @@ -1147,7 +1192,7 @@ The strategies below are ordered by impact-to-effort ratio. Query string normali td: [ "Medium", "Medium", - "Reduce language variants; limit Accept-Encoding values; avoid User-Agent variations", + 'Reduce language variants; limit Accept-Encoding values; avoid User-Agent variations', ], }, { @@ -1155,7 +1200,7 @@ The strategies below are ordered by impact-to-effort ratio. Query string normali td: [ "High", "Low", - "Use immutable for versioned assets; extend TTL with stale-while-revalidate; implement proper invalidation", + 'Use immutable for versioned assets; extend TTL with stale-while-revalidate; implement proper invalidation', ], }, ], @@ -1168,7 +1213,8 @@ The strategies below are ordered by impact-to-effort ratio. Query string normali You can't optimize what you don't measure. These metrics tell you whether your cache is working correctly and where to focus optimization efforts. Most CDNs expose these through dashboards and APIs — set up monitoring before you need to debug a production issue.
-__Interpreting these metrics in context:__ +Interpreting these metrics in context: +Translating these observations into automated monitoring requires dashboards that surface anomalies before they become incidents. The following Datadog configuration tracks the metrics above and alerts on the thresholds that typically indicate configuration problems rather than traffic changes. + ```json title="cache-monitoring.json" { "_comment": "Datadog config example", @@ -1273,6 +1321,8 @@ __Interpreting these metrics in context:__ ``` Code: Cache monitoring dashboard configuration. +When your dashboard flags a dip, resist the urge to increase TTLs blindly — the hit ratio itself is the diagnostic starting point. + A cache hit ratio below 70% often indicates a configuration problem, not a traffic problem. Before adding more edge capacity, audit your cache keys and Vary headers. @@ -1329,14 +1379,6 @@ This checklist consolidates the key configuration points covered throughout the ``` Code: Comprehensive CDN configuration checklist. -## Further Reading - -- [RFC 9111: HTTP Caching](https://www.rfc-editor.org/rfc/rfc9111.html) — The authoritative specification for HTTP caching semantics, including Cache-Control directives and Vary header behavior. -- [AWS CloudFront Developer Guide: Caching](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cache-key-understand-cache-policy.html) — CloudFront-specific cache key policies and configuration options. -- [Cloudflare Cache Documentation](https://developers.cloudflare.com/cache/) — Cloudflare's caching features, including cache tags (Surrogate-Key), purge APIs, and edge compute with Workers. -- [Fastly VCL Reference](https://developer.fastly.com/reference/vcl/) — Fastly's Varnish Configuration Language for fine-grained cache control. -- [Web Caching Explained by Ryan Prior](https://web-caching.readthedocs.io/) — A comprehensive guide to HTTP caching concepts and best practices. - ## Conclusion Edge caching is a correctness problem disguised as a performance optimization. The techniques in this article all serve one goal: ensuring the right content reaches the right user while maximizing cache efficiency. @@ -1345,6 +1387,9 @@ The key principles to remember: Edge caching is one of the highest-leverage performance optimizations available, but only when configured correctly. Invest time in cache key design, Vary header normalization, and monitoring — the performance gains are dramatic and the correctness risks are real. + +## Further Reading + +- [RFC 9111: HTTP Caching](https://www.rfc-editor.org/rfc/rfc9111.html) — The authoritative specification for HTTP caching semantics, including Cache-Control directives and Vary header behavior. +- [AWS CloudFront Developer Guide: Caching](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cache-key-understand-cache-policy.html) — CloudFront-specific cache key policies and configuration options. +- [Cloudflare Cache Documentation](https://developers.cloudflare.com/cache/) — Cloudflare's caching features, including cache tags (Surrogate-Key), purge APIs, and edge compute with Workers. +- [Fastly VCL Reference](https://developer.fastly.com/reference/vcl/) — Fastly's Varnish Configuration Language for fine-grained cache control. +- [Web Caching Explained by Ryan Prior](https://web-caching.readthedocs.io/) — A comprehensive guide to HTTP caching concepts and best practices. diff --git a/src/content/articles/chaos-engineering-failure-injection-low-cost-experiments/diagrams/the-scientific-cycle-of-chaos-engineering.jpg b/src/content/articles/chaos-engineering-failure-injection-low-cost-experiments/diagrams/the-scientific-cycle-of-chaos-engineering.jpg index 5215feafb..c4c0ab60a 100644 Binary files a/src/content/articles/chaos-engineering-failure-injection-low-cost-experiments/diagrams/the-scientific-cycle-of-chaos-engineering.jpg and b/src/content/articles/chaos-engineering-failure-injection-low-cost-experiments/diagrams/the-scientific-cycle-of-chaos-engineering.jpg differ diff --git a/src/content/articles/chaos-engineering-failure-injection-low-cost-experiments/index.mdx b/src/content/articles/chaos-engineering-failure-injection-low-cost-experiments/index.mdx index 77b5d7f85..1b41bfa8a 100644 --- a/src/content/articles/chaos-engineering-failure-injection-low-cost-experiments/index.mdx +++ b/src/content/articles/chaos-engineering-failure-injection-low-cost-experiments/index.mdx @@ -26,10 +26,11 @@ This article covers what chaos engineering actually is (hint: it's not random de The term "chaos engineering" sounds destructive, which leads to a common misconception: that it's about randomly breaking things to see what happens. That's not chaos engineering — that's just chaos. -Real chaos engineering follows the scientific method. You form a hypothesis about how your system should behave under specific failure conditions, you design a controlled experiment to test that hypothesis, and you observe whether reality matches your expectations. The goal isn't to cause outages; it's to build confidence that your system handles failures gracefully — or to learn exactly how it doesn't. +Real chaos engineering follows the scientific method. You form a hypothesis about how your system should behave under specific failure conditions, you design a controlled experiment to test that hypothesis, and you observe whether reality matches your expectations. The goal isn't to cause outages; it's to build confidence that your system handles failures gracefully — or to learn exactly how it doesn't.
1 (so traffic continues on surviving pods during recovery)", }, { + icon: "availability", + color: "page-inverse", + bgColor: "note-inverse", text: "Health checks (liveness and readiness probes) are configured", }, { + icon: "observability-and-telemetry", + color: "page-inverse", + bgColor: "note-inverse", text: "You have monitoring in place to observe the experiment", }, ]} @@ -107,6 +120,9 @@ The simplest and most valuable first experiment is killing a pod. If you've neve - These findings alone justify the experiment. And you can run it in staging today, with no budget approval, no platform purchase, and no dedicated chaos team. diff --git a/src/content/articles/chaos-engineering-failure-injection-low-cost-experiments/pdf.mdx b/src/content/articles/chaos-engineering-failure-injection-low-cost-experiments/pdf.mdx index 534c61cb3..d0d45501b 100644 --- a/src/content/articles/chaos-engineering-failure-injection-low-cost-experiments/pdf.mdx +++ b/src/content/articles/chaos-engineering-failure-injection-low-cost-experiments/pdf.mdx @@ -47,7 +47,8 @@ The term "chaos engineering" sounds destructive, which leads to a common misconc Real chaos engineering follows the scientific method. You form a hypothesis about how your system should behave under specific failure conditions, design a controlled experiment to test that hypothesis, and observe whether reality matches your expectations. The goal isn't to cause outages; it's to build confidence that your system handles failures gracefully — or to learn exactly how it doesn't.
@@ -142,6 +145,8 @@ From there, you can progress to experiments during business hours with real traf @@ -415,33 +420,33 @@ Code: LitmusChaos network latency experiment. The tradeoff with LitmusChaos is complexity. You need to install the LitmusChaos operator, set up service accounts with appropriate permissions, and understand the CRD-based workflow. For teams already deep in Kubernetes and GitOps, this feels natural. For teams just starting with chaos engineering, Chaos Toolkit's simpler CLI-based approach might be easier to adopt.
@@ -654,24 +660,23 @@ Watch for the new pod scheduling, the health check passing, and traffic resuming What teams commonly discover from this experiment: - ### Experiment 2: Dependency Latency Most production incidents aren't clean crashes — they're slowdowns. A database that responds in 500ms instead of 10ms is technically "up," but your service might as well be down if it can't handle the latency gracefully. This experiment reveals whether your timeouts, circuit breakers, and connection pools are configured correctly. @@ -708,7 +713,7 @@ Success looks like: service remains responsive (P99 under 3 seconds), no cascadi What teams commonly discover: @@ -859,42 +865,42 @@ The progression takes time — typically a year or more to go from first experim Here's a realistic four-quarter roadmap for building a chaos engineering practice from scratch:
You don't need an enterprise chaos platform to start chaos engineering. You need a hypothesis, a safe experiment, monitoring to observe the results, and the discipline to fix what you find. Start small, learn, and expand. + +Once you've mastered the four experiments in this guide, the path forward opens up. You can explore zone and region failures to test geographic redundancy. You can inject clock skew to find time-sensitive bugs. You can simulate certificate expiration, DNS failures, or cloud provider API throttling. Each new experiment type reveals a different class of bugs — and each one can be done with free tools. + +The barrier to starting isn't tooling or budget. It's deciding to run that first experiment. Pick a service. Form a hypothesis. Open your monitoring dashboard. Kill a pod. Watch what happens. diff --git a/src/content/articles/ci-pipeline-caching-docker-layers-dependency-cache/index.mdx b/src/content/articles/ci-pipeline-caching-docker-layers-dependency-cache/index.mdx index bc4be74c4..a2a2766bf 100644 --- a/src/content/articles/ci-pipeline-caching-docker-layers-dependency-cache/index.mdx +++ b/src/content/articles/ci-pipeline-caching-docker-layers-dependency-cache/index.mdx @@ -13,7 +13,7 @@ featured: true CI caching is one of those optimizations that looks straightforward until it isn't. The pitch is simple: cache dependencies and build artifacts so you don't re-download and re-compile the same code on every build. Teams routinely cut 45-minute builds down to 8 minutes. That's real productivity — more deploys per day, faster feedback loops, happier engineers. -But here's what nobody mentions in the "speed up your CI" blog posts: incorrect caching produces builds that pass CI and fail in production. +But here's what nobody mentions in the "speed up your CI" blog posts. Incorrect caching produces builds that pass CI and fail in production. I've seen this pattern more than once. A team aggressively caches everything, build times plummet, everyone celebrates. Three weeks later, a security patch lands in a transitive dependency. The team runs `npm audit fix`, but they're caching `node_modules` with a key that only hashes `package-lock.json`. The lockfile didn't change (the patch was already in the allowed semver range), so the cache hits and the old, vulnerable version keeps getting restored. The vulnerability makes it to production. The rollback takes longer than all the time they saved. @@ -30,19 +30,22 @@ A cache key is a string that uniquely identifies a cached artifact. When your bu The key to effective caching is designing keys that change when (and only when) the cached content should change. A good cache key has three components: v1-deps-*)', }, { lead: "Dynamic components", - text: "that capture everything affecting the cached content (e.g., lockfile hash)", + text: "Captures everything affecting the cached content (e.g., lockfile hash)", }, { lead: "Optionally, a version or OS component", - text: "for environment-specific caches (e.g., `runner.os`)", + text: 'For environment-specific caches (e.g., runner.os)', }, ]} /> @@ -67,7 +70,7 @@ The `hashFiles()` function computes a hash of the specified files — when `pack Three principles determine whether a cache is safe to use: A fast build that produces incorrect artifacts is worse than a slow build. Before optimizing cache hit ratio, ensure your cache keys capture everything that affects build output. +This article covers the fundamentals of CI caching (cache keys, restore keys, and correctness principles), dependency caching across language ecosystems, Docker layer caching and BuildKit features, the pitfalls that turn caching into a footgun, and how to measure whether your caching is actually working. + ## The Fundamentals of CI Caching ### Why CI Builds Are Slow @@ -34,7 +34,8 @@ A fast build that produces incorrect artifacts is worse than a slow build. Befor Before optimizing, it helps to know where the time actually goes. Here's a breakdown of typical CI pipeline phases and their caching potential:
v1-deps-*)', }, { lead: "Dynamic components", - text: "that capture everything affecting the cached content (e.g., lockfile hash)", + text: "Captures everything affecting the cached content (e.g., lockfile hash)", }, { lead: "Optionally, a version or OS component", - text: "for environment-specific caches (e.g., `runner.os`)", + text: 'For environment-specific caches (e.g., runner.os)', }, ]} /> @@ -124,25 +128,27 @@ Restore keys provide fallback options when the exact cache key doesn't match. Th Three principles determine whether a cache is safe to use: +These three principles are easy to state but surprisingly easy to violate. The table below maps each principle to the rule it enforces and the mistake that breaks it — a useful checklist when something is caching incorrectly. +
npm install instead of npm ci allows the package manager to resolve different versions on different runs, even with the same lockfile.', }, { lead: "Timestamps", - text: "If your build embeds the current timestamp in artifacts, a cached artifact won't match a fresh build. Use `SOURCE_DATE_EPOCH` for reproducible builds.", + text: 'If your build embeds the current timestamp in artifacts, a cached artifact won\'t match a fresh build. Use SOURCE_DATE_EPOCH for reproducible builds.', }, { lead: "Parallel race conditions", @@ -743,11 +749,11 @@ GitHub Actions shows cache hit/miss in workflow logs and provides cache manageme Four metrics tell you whether caching is working: cache_hits / (cache_hits + cache_misses). A healthy ratio is above 80%. Below 50% for more than a day means something is wrong with your cache key design.', }, { lead: "Time saved", @@ -805,22 +811,22 @@ Code: Script to list cache entries via GitHub API. Common causes of unexpected misses: @@ -978,7 +984,10 @@ __GitLab cache gotcha__: If you're using Kubernetes executors with distributed r CI caching is deceptively simple on the surface: save files, restore files, skip work. But effective caching requires understanding the principles beneath the configuration. Retries without limits are a distributed denial-of-service attack against your own infrastructure. Every retry multiplies load on an already struggling service. +Circuit breakers and retry budgets exist to break this cycle. A circuit breaker monitors failure rates and "opens" when a downstream service is unhealthy, failing requests immediately instead of adding load to a struggling service. A retry budget limits the total number of retries across all requests, preventing the exponential amplification that turns a minor issue into a major outage. + ## The Cascade Failure Pattern -Understanding the mechanics of cascade failures requires tracing the path from initial symptom to system-wide collapse. The pattern is predictable, which means it's also preventable. +Understanding the mechanics of cascade failures requires tracing the path from initial symptom to system-wide collapse. The pattern is predictable, which means it's also preventable. Consider a typical service chain: an API gateway calls a checkout service, which calls an inventory service, which queries a database. Each layer has timeouts and retry logic configured independently. Nobody coordinated these settings because each team was responsible for their own service. The failure starts at the bottom. A database experiences momentary slowness — maybe a long-running query, maybe garbage collection, maybe a network hiccup. What happens next follows a predictable sequence: -```text -Timeline of a cascade failure: - -T+0: Database slow (100ms → 2s response time) -T+10s: Service C queues grow, some requests timeout -T+20s: Service B sees C timeouts, starts retrying -T+30s: Service A sees B timeouts, starts retrying -T+45s: All services at maximum queue depth -T+60s: Database recovers, but services cannot — queues too deep -T+2min: Manual intervention required -T+5min: Services restarted, queues cleared -T+10min: Full recovery - -Root cause: 30 second database slowdown -Actual outage: 10 minutes -Amplification factor: 20x -``` -Figure: Timeline showing how a brief database slowdown cascades into a 10-minute outage. +Timeline of a cascade failure showing how a brief database slowdown cascades into a 10-minute outage: + + + +The timeline above shows the domino effect, but the summary tells the real story: + + -The database recovered at T+60s, but the cascade continued for another 9 minutes. By the time the database was healthy, each upstream service had thousands of requests queued. Those queued requests kept hammering downstream services, preventing recovery. The system needed manual intervention — draining queues, restarting services — to return to normal operation. +The database recovered at `T+60s`, but the cascade continued for another 9 minutes. By the time the database was healthy, each upstream service had thousands of requests queued. Those queued requests kept hammering downstream services, preventing recovery. The system needed manual intervention — draining queues, restarting services — to return to normal operation. ### Retry Amplification @@ -66,7 +114,8 @@ The math behind retry amplification is straightforward, and terrifying. Each ser The formula is simple: $$(r + 1)^n$$ where $$r$$ is retries per service and $$n$$ is the number of services in the chain. With 3 services each retrying 3 times, that's $$4^3 = 64x$$ load amplification.
Retries without limits are a distributed denial-of-service attack against your own infrastructure. Every retry multiplies load on an already struggling service. +These aren't nice-to-have resilience patterns. They're survival mechanisms for any system with service dependencies. + ## The Cascade Failure Pattern ### How Failures Cascade @@ -43,23 +43,70 @@ Consider a typical service chain: an API gateway calls a checkout service, which The failure starts at the bottom. A database experiences momentary slowness — maybe a long-running query, maybe garbage collection, maybe a network hiccup. What happens next follows a depressingly predictable sequence: -```text -Timeline of a cascade failure: - -T+0: Database slow (100ms → 2s response time) -T+10s: Service C queues grow, some requests timeout -T+20s: Service B sees C timeouts, starts retrying -T+30s: Service A sees B timeouts, starts retrying -T+45s: All services at maximum queue depth -T+60s: Database recovers, but services cannot — queues too deep -T+2min: Manual intervention required -T+5min: Services restarted, queues cleared -T+10min: Full recovery - -Root cause: 30 second database slowdown -Actual outage: 10 minutes -Amplification factor: 20x -``` + + +The timeline above shows the domino effect, but the summary tells the real story: + + The database recovered at T+60s, but the cascade continued for another 9 minutes. By the time the database was healthy, each upstream service had thousands of requests queued. Those queued requests kept hammering downstream services, preventing recovery. The system needed manual intervention — draining queues, restarting services — to return to normal operation. @@ -72,7 +119,8 @@ The formula is simple: $$(r + 1)^n$$ where $$r$$ is retries per service and $$n$ The table below shows how quickly this gets out of hand. These numbers assume every request at every layer fails and triggers full retries — a worst case, but exactly what happens during a cascade failure:
DestinationRule above)', + text: 'Handles circuit breaking at the infrastructure layer. Your application code stays simple — it just makes HTTP calls — while Envoy sidecars handle failure detection and traffic shifting. The downside is complexity: you need a mesh deployed, and debugging "why didn\'t my request go through" now involves understanding Envoy configs and mesh telemetry. Service meshes work best when you want consistent resilience policies across many services without modifying application code.', }, { - lead: "Application libraries", - text: "like opossum (Node.js), resilience4j (Java), or gobreaker (Go) give you fine-grained control. You can configure different thresholds per endpoint, implement custom fallback logic, and emit metrics that tie directly to your application's business logic. The tradeoff is that every service needs to implement and configure the library correctly — there's no centralized policy enforcement.", + lead: "Application libraries like opossum (Node.js), resilience4j (Java), or gobreaker (Go)", + text: "Gives you fine-grained control. You can configure different thresholds per endpoint, implement custom fallback logic, and emit metrics that tie directly to your application's business logic. The tradeoff is that every service needs to implement and configure the library correctly — there's no centralized policy enforcement.", }, { - lead: "API gateways and load balancers", - text: "(AWS ALB, Kong, NGINX) can implement basic circuit breaking at the edge. This protects your backend from external traffic surges but doesn't help with service-to-service calls within your infrastructure.", + lead: "API gateways and load balancers (like AWS ALB, Kong, NGINX)", + text: "Can implement basic circuit breaking at the edge. This protects your backend from external traffic surges but doesn't help with service-to-service calls within your infrastructure.", }, ]} /> @@ -245,8 +296,11 @@ const recommendations = await productCircuit.execute( ``` Code: Fallback strategy implementations for circuit breakers. +Each strategy fits a different failure mode. The table below maps them to the right context and the cost you accept when using them: +
@@ -313,16 +370,19 @@ __Traditional Retries:__ __Retry Budget:__ @@ -330,13 +390,16 @@ __Retry Budget:__ __Under failure:__ @@ -499,30 +562,38 @@ The `circuit_state` gauge tells you at a glance which circuits are open. The `ci Your circuit breaker dashboard should answer three questions at a glance: which circuits are open, why did they open, and how much traffic is being rejected? -```text -+------------------------------------------+ -| CIRCUIT STATES | -| [Service A: CLOSED] [Service B: OPEN] | + +{String.raw` ++-------------------------------------------+ +| CIRCUIT STATES | +| [Service A: CLOSED] [Service B: OPEN] | | [Service C: HALF_OPEN] [Service D: CLOSED]| -+------------------------------------------+ -| STATE TRANSITIONS (24h) | -| Timeline showing open/closed transitions | -+------------------------------------------+ -| FAILURE RATES BY SERVICE | -| Service A: 0.1% ████░░░░░░ | -| Service B: 45% ████████████████████░░ | -| Service C: 12% ████████░░░░░░░░░░░░░░ | -+------------------------------------------+ -| RETRY BUDGET UTILIZATION | -| Service A: 5% ██░░░░░░░░░░ | ++-------------------------------------------+ +| STATE TRANSITIONS (24h) | +| Timeline showing open/closed transitions | ++-------------------------------------------+ +| FAILURE RATES BY SERVICE | +| Service A: 0.1% ████░░░░░░ | +| Service B: 45% ████████████████████░░ | +| Service C: 12% ████████░░░░░░░░░░░░░░ | ++-------------------------------------------+ +| RETRY BUDGET UTILIZATION | +| Service A: 5% ██░░░░░░░░░░ | | Service B: 100% ████████████████████████ | -| Service C: 35% ██████████░░░░░░░░░░░░░ | -+------------------------------------------+ -| REQUESTS REJECTED (Circuit Open) | -| [Graph showing rejected requests/min] | -+------------------------------------------+ -``` -Code: Circuit Breaker Dashboard Layout +| Service C: 35% ██████████░░░░░░░░░░░░░ | ++-------------------------------------------+ +| REQUESTS REJECTED (Circuit Open) | +| [Graph showing rejected requests/min] | ++-------------------------------------------+ +`} + The state transition timeline is particularly useful for post-incident analysis. You can correlate circuit opens with deployment events, traffic spikes, or downstream service issues. A circuit that opened 30 seconds after a deploy is telling you something different than one that opened during peak traffic. @@ -598,7 +669,10 @@ When a circuit isn't behaving as expected, the problem usually falls into one of __Circuit opens unexpectedly:__
failure_threshold and minimum_requests'], }, { th: "Timeouts causing false failures", @@ -615,7 +689,7 @@ __Circuit opens unexpectedly:__ }, { th: "Window too short", - td: ["Increase `window_duration` for bursty traffic patterns"], + td: ['Increase window_duration for bursty traffic patterns'], }, ], }, @@ -625,7 +699,10 @@ __Circuit opens unexpectedly:__ __Circuit not opening:__
failure_conditions includes the error types you expect'], }, { - th: "`minimum_requests` too high", + th: 'minimum_requests too high', td: ["Lower it for low-traffic services"], }, { th: "Window too long", - td: ["Decrease `window_duration` to detect failures faster"], + td: ['Decrease window_duration to detect failures faster'], }, ], }, @@ -652,7 +729,10 @@ __Circuit not opening:__ __Circuit not closing:__
success_threshold too high', + td: ['Reduce half_open.success_threshold'], }, ], }, @@ -770,15 +850,23 @@ When every service in a call chain uses the same timeout value, you get cascadin Timeouts should decrease as you go down the call stack. If A has a 10-second timeout, B should use 5 seconds, and C should use 2 seconds. This gives each layer time to handle failures gracefully rather than racing against the clock. -```text + // BAD: Identical timeouts -A (timeout: 5s) → B (timeout: 5s) → C (timeout: 5s) // C takes 4s, B returns at 4s, but A times out at 5s total +A (timeout: 5s) → B (timeout: 5s) → C (timeout: 5s) // GOOD: Decreasing timeouts -A (timeout: 10s) → B (timeout: 5s) → C (timeout: 2s) // Each layer has headroom for retries and error handling -``` +A (timeout: 10s) → B (timeout: 5s) → C (timeout: 2s) + + +The decreasing-timeout pattern above is necessary but not sufficient on its own — you also need to think about what happens when a downstream service is completely unreachable rather than just slow. Coordinate timeout budgets across your service chain. If you don't control all services in the chain, at minimum ensure your timeout is longer than the timeout of services you call. In gRPC systems, consider propagating deadlines via metadata headers so downstream services know how much time remains and can fail fast if the budget is already exhausted. @@ -791,23 +879,23 @@ Coordinate timeout budgets across your service chain. If you don't control all s Most languages have mature circuit breaker implementations. The choice usually comes down to whether you want a focused library that does one thing well, or a comprehensive resilience toolkit. @@ -853,10 +941,10 @@ Circuit breakers and retry budgets address two sides of the same problem. Circui These mechanisms work together. The retry budget prevents overwhelming a service __before__ the circuit opens. The circuit breaker stops traffic __after__ sustained failures are detected. Neither alone is sufficient: circuit breakers without retry budgets still allow amplification during the detection window, and retry budgets without circuit breakers still send initial requests to a service that's clearly down. -The goal isn't perfect availability — it's graceful degradation. When a dependency fails, your service should continue operating in a reduced capacity rather than collapsing entirely. Cached responses, default values, and degraded experiences are all preferable to error pages or timeouts that propagate up the stack. - -Observability makes the difference between "it worked" and "I understand how it worked." A circuit breaker that opens silently is better than none, but a circuit breaker with metrics, dashboards, and alerts lets you tune thresholds, correlate failures with deployments, and catch problems before users notice. Instrument from day one. - Start with your most critical downstream dependency. Add a circuit breaker with opossum or resilience4j this week. Instrument the metrics. Watch how it behaves under normal load. Then expand to other dependencies. The best time to implement these patterns is before your first cascade failure, not after. + +The goal isn't perfect availability — it's graceful degradation. When a dependency fails, your service should continue operating in a reduced capacity rather than collapsing entirely. Cached responses, default values, and degraded experiences are all preferable to error pages or timeouts that propagate up the stack. + +Observability makes the difference between "it worked" and "I understand how it worked." A circuit breaker that opens silently is better than none, but a circuit breaker with metrics, dashboards, and alerts lets you tune thresholds, correlate failures with deployments, and catch problems before users notice. Instrument from day one. diff --git a/src/content/articles/consumer-driven-contract-testing-pact-internal-apis/index.mdx b/src/content/articles/consumer-driven-contract-testing-pact-internal-apis/index.mdx index 8fb7531f1..abee60493 100644 --- a/src/content/articles/consumer-driven-contract-testing-pact-internal-apis/index.mdx +++ b/src/content/articles/consumer-driven-contract-testing-pact-internal-apis/index.mdx @@ -31,7 +31,7 @@ The problems compound quickly. Shared test databases accumulate garbage data fro When an integration test fails, debugging becomes archaeology. A failure in Service X might be caused by a change in Service Y, but the stack trace only shows where the exception was thrown, not where the problem originated. Reproducing the failure locally requires spinning up the entire environment, which often behaves differently than CI.
diff --git a/src/layouts/MarkdownLayout.astro b/src/layouts/MarkdownLayout.astro index 68bacdc81..7dd37c2e4 100644 --- a/src/layouts/MarkdownLayout.astro +++ b/src/layouts/MarkdownLayout.astro @@ -24,6 +24,7 @@ import Diagram from '@components/Diagram/index.astro' import Download from '@components/CallToAction/Download/index.astro' import Embed from '@components/Social/Embed/index.astro' import Highlighter from '@components/Social/Highlighter/index.astro' +import HighlighterIconBank from '@components/Social/Highlighter/HighlighterIconBank.astro' import Icon from '@components/Icon/index.astro' import Inset from '@components/Inset/index.astro' import List from '@components/List/index.astro' @@ -34,6 +35,7 @@ import Table from '@components/Table/index.astro' import Time from '@components/Time/index.astro' import Testimonials from '@components/Testimonials/index.astro' import CodeTabs from '@components/Code/CodeTabs/index.astro' +import '@components/Social/Highlighter/index.css' /** Export components for use in MDX */ const Components = { @@ -191,6 +193,22 @@ const shouldRenderToc = showToc !== false && tocHeadings.length > 0 + + + + + diff --git a/src/lib/config/__tests__/siteUrlServer.spec.ts b/src/lib/config/__tests__/siteUrlServer.spec.ts index e6b2cfa32..d0037de5c 100644 --- a/src/lib/config/__tests__/siteUrlServer.spec.ts +++ b/src/lib/config/__tests__/siteUrlServer.spec.ts @@ -36,8 +36,8 @@ describe('getSiteUrl', () => { isGitHubMock.mockReturnValue(false) const invokeGetSiteUrl = () => getSiteUrl() - expect(invokeGetSiteUrl).toThrowError(BuildError) - expect(invokeGetSiteUrl).toThrowError( + expect(invokeGetSiteUrl).toThrow(BuildError) + expect(invokeGetSiteUrl).toThrow( '❌ Build runs on GitHub, so this build-time getSiteUrl() function should never be called on Vercel.' ) }) diff --git a/src/lib/helpers/__tests__/breadcrumbTitleLengthRefinement.spec.ts b/src/lib/helpers/__tests__/breadcrumbTitleLengthRefinement.spec.ts index 0c1c1abe2..543c7c5c4 100644 --- a/src/lib/helpers/__tests__/breadcrumbTitleLengthRefinement.spec.ts +++ b/src/lib/helpers/__tests__/breadcrumbTitleLengthRefinement.spec.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi, afterEach } from 'vitest' -import { z } from 'astro:content' +import { z } from 'astro/zod' const LONG_TITLE = 'A'.repeat(61) const SHORT_TITLE = 'Short title' diff --git a/src/lib/helpers/breadcrumbTitleLengthRefinement.ts b/src/lib/helpers/breadcrumbTitleLengthRefinement.ts index 66a58dbc3..e1be3a503 100644 --- a/src/lib/helpers/breadcrumbTitleLengthRefinement.ts +++ b/src/lib/helpers/breadcrumbTitleLengthRefinement.ts @@ -1,4 +1,4 @@ -import { z } from 'astro:content' +import type { ZodObject, ZodRawShape } from 'astro/zod' const MAX_BREADCRUMB_TITLE_LENGTH = 60 const loggedBreadcrumbTitleWarnings = new Set() @@ -25,11 +25,11 @@ export const warnOnBreadcrumbTitleLength = (title: string, collectionName: strin * @param collectionName Name of the collection, used to scope warning messages * @returns Zod schema augmented with breadcrumb title length validation */ -export const withBreadcrumbTitleWarning = ( - schema: z.ZodObject, +export const withBreadcrumbTitleWarning = ( + schema: ZodObject, collectionName: string ) => - schema.superRefine(data => { + schema.superRefine((data: { title?: string }) => { const candidateTitle = (data as { title?: string }).title if (typeof candidateTitle === 'string') { warnOnBreadcrumbTitleLength(candidateTitle, collectionName) diff --git a/src/lib/plugins/fixContentAssetPropagation.ts b/src/lib/plugins/fixContentAssetPropagation.ts index 39090677e..09b5bf888 100644 --- a/src/lib/plugins/fixContentAssetPropagation.ts +++ b/src/lib/plugins/fixContentAssetPropagation.ts @@ -32,6 +32,30 @@ type TransformFn = ( _options?: { ssr?: boolean }, ) => unknown +type TransformHook = + | TransformFn + | { + filter?: unknown + handler: TransformFn + } + +const forceNonSsrTransform = (transform: TransformHook): TransformHook => { + const wrapHandler = (handler: TransformFn): TransformFn => { + return function (this: unknown, code: string, id: string, options?: { ssr?: boolean }) { + return handler.call(this, code, id, { ...options, ssr: false }) + } + } + + if (typeof transform === 'function') { + return wrapHandler(transform) + } + + return { + ...transform, + handler: wrapHandler(transform.handler), + } +} + export function fixContentAssetPropagation(): PluginOption { return { name: 'fix-content-asset-propagation', @@ -41,18 +65,8 @@ export function fixContentAssetPropagation(): PluginOption { (p: Plugin) => p.name === 'astro:content-asset-propagation', ) if (!plugin?.transform) return - const originalTransform = (plugin.transform as TransformFn).bind(plugin) as TransformFn const pluginRecord = plugin as unknown as Record - pluginRecord['transform'] = function ( - this: unknown, - code: string, - id: string, - options?: { ssr?: boolean }, - ) { - // Force non-SSR path to avoid devModuleLoader, which was contaminated - // by the DB integration's temp server during astro:build:setup. - return originalTransform.call(this, code, id, { ...options, ssr: false }) - } + pluginRecord['transform'] = forceNonSsrTransform(plugin.transform as TransformHook) }, } } diff --git a/src/pages/articles/[...slug].astro b/src/pages/articles/[...slug].astro index 5e93efa20..147a38107 100644 --- a/src/pages/articles/[...slug].astro +++ b/src/pages/articles/[...slug].astro @@ -1,4 +1,6 @@ --- +export const prerender = true + import { type CollectionEntry, getCollection, getEntry } from 'astro:content' import { isDev } from '@lib/config/environmentServer' import { getReadingTimeLabel } from '@lib/markdown/utils/readingTime' diff --git a/src/pages/case-studies/[slug].astro b/src/pages/case-studies/[slug].astro index e6382f34b..24f2d03f5 100644 --- a/src/pages/case-studies/[slug].astro +++ b/src/pages/case-studies/[slug].astro @@ -1,4 +1,6 @@ --- +export const prerender = true + import { getCollection } from 'astro:content' import { Picture } from 'astro:assets' import MarkdownLayout from '@layouts/MarkdownLayout.astro' @@ -45,6 +47,8 @@ const section = 'Case Studies' sizes="100vw" formats={['avif', 'webp', 'jpeg']} layout="constrained" + loading="eager" + fetchpriority="high" fit="cover" position="center" class="absolute inset-0 h-full w-full" diff --git a/src/pages/deep-dive/[...slug].astro b/src/pages/deep-dive/[...slug].astro index 7c7882c5b..07cb58c86 100644 --- a/src/pages/deep-dive/[...slug].astro +++ b/src/pages/deep-dive/[...slug].astro @@ -1,4 +1,6 @@ --- +export const prerender = true + import { type CollectionEntry, getCollection, getEntry } from 'astro:content' import { isDev } from '@lib/config/environmentServer' import { getReadingTimeLabel } from '@lib/markdown/utils/readingTime' diff --git a/src/pages/downloads/[...slug].astro b/src/pages/downloads/[...slug].astro index abfc6c7a2..63996b7db 100644 --- a/src/pages/downloads/[...slug].astro +++ b/src/pages/downloads/[...slug].astro @@ -1,4 +1,6 @@ --- +export const prerender = true + import { type CollectionEntry, getCollection } from 'astro:content' import { isDev } from '@lib/config/environmentServer' import PageLayout from '@layouts/PageLayout.astro' diff --git a/src/pages/rss.xml.ts b/src/pages/rss.xml.ts index 70312f03d..df3271118 100644 --- a/src/pages/rss.xml.ts +++ b/src/pages/rss.xml.ts @@ -35,7 +35,9 @@ export async function GET() { pubDate: article.data.publishDate, description: article.data.description, link: `/articles/${article.id}`, - categories: (article.data.tags ?? []).map(toCategory).filter((c): c is string => Boolean(c)), + categories: (article.data.tags ?? []) + .map(toCategory) + .filter((category): category is string => Boolean(category)), })), customData: `en-us`, }) diff --git a/src/pages/tags/[tag].astro b/src/pages/tags/[tag].astro index 2c125e8c1..5d9032969 100644 --- a/src/pages/tags/[tag].astro +++ b/src/pages/tags/[tag].astro @@ -1,4 +1,6 @@ --- +export const prerender = true + import { type CollectionEntry, getCollection, render } from 'astro:content' import { Picture } from 'astro:assets' import { isDev } from '@lib/config/environmentServer' @@ -18,7 +20,7 @@ export async function getStaticPaths() { const allArticles = await getCollection('articles', ({ data }) => isDev() || data.isDraft !== true) const articleHasTag = (article: CollectionEntry<'articles'>, tagEntry: CollectionEntry<'tags'>) => { - return article.data.tags.some(tagRef => tagRef.id === tagEntry.id) + return article.data.tags.some((tagRef: { id: string }) => tagRef.id === tagEntry.id) } return allTags.map(tagEntry => { @@ -33,7 +35,7 @@ export async function getStaticPaths() { } const { tag } = Astro.params -const { content: allTagContent } = Astro.props +const { content: allTagContent } = Astro.props as Props const [tagEntry] = await getCollection('tags', ({ data }) => data.slug === tag) if (!tagEntry) { diff --git a/src/pages/testing/comps/scratchpad.astro b/src/pages/testing/comps/scratchpad.astro index 04fe8ec11..bf1185707 100644 --- a/src/pages/testing/comps/scratchpad.astro +++ b/src/pages/testing/comps/scratchpad.astro @@ -1,12 +1,48 @@ --- import BaseLayout from '@layouts/BaseLayout.astro' +import List from '@components/List/index.astro' const pageTitle = 'Scratchpad' const pageDescription = 'Styling Variants' const path = '/testing/comps/scratchpad' +const chatBubbleItems = [ + { + lead: 'Why did the system go down?', + text: 'Because a config change broke it.', + }, + { + lead: 'Why did the config change break it?', + text: 'Because the engineer made a mistake.', + }, + { + lead: 'Why did the engineer make a mistake?', + text: 'Because they were careless.', + }, +] ---
+ +

Variant 6 — Chat Bubbles

+ + + +

Variant 8 — Elevated Hover Cards

+
+
+
Why did the system go down?
+
Because a config change broke it.
+
+
+
Why did the config change break it?
+
Because the engineer made a mistake.
+
+
+
Why did the engineer make a mistake?
+
Because they were careless.
+
+
+
diff --git a/vitest.config.ts b/vitest.config.ts index 7464169bb..0856df4f3 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -153,4 +153,8 @@ export default getViteConfig({ }, }, // eslint-disable-next-line @typescript-eslint/no-explicit-any -} as any) +} as any, { + // Astro actions require server output. Override the app's static output only + // for Vitest so unit tests can load the Astro config without changing runtime behavior. + output: 'server', +})