diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..6c3959b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +version: 2 +updates: + - package-ecosystem: npm + directory: / + schedule: + interval: monthly + groups: + version-updates: + applies-to: version-updates + patterns: + - "*" + security-updates: + applies-to: security-updates + patterns: + - "*" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4eba68a..1b539b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,6 +31,8 @@ jobs: cache: npm - name: Install locked dependencies run: npm ci + - name: Audit critical vulnerabilities + run: npm audit --audit-level=critical - name: Type-check run: npm run check - name: Unit tests diff --git a/.planning/audits/dependency-security-2026-08-29.md b/.planning/audits/dependency-security-2026-08-29.md new file mode 100644 index 0000000..437b010 --- /dev/null +++ b/.planning/audits/dependency-security-2026-08-29.md @@ -0,0 +1,135 @@ +# Dependency security residual risk and Astro 7 handoff — 2026-08-29 + +## Status and scope + +Stage 1 reduced the vulnerable dependency graph without crossing the approved +Astro/Cloudflare major-version boundary. The remaining findings are maintenance +risk, not evidence of an active incident. The source conditions described below +make the examined direct advisories currently unreachable or inapplicable, but +those conditions are conditional mitigations, not upstream patches. The project +still needs the separately reviewed Stage 2 migration. + +This record was checked against the committed `package-lock.json`, the installed +graph, live npm audit output, repository source, and the linked primary GitHub +Advisory Database records on 2026-08-29. + +## Stage 1 evidence + +`npm audit` reports vulnerable package keys, not unique advisories. One package +key can aggregate several advisory records and dependency effects. + +| Graph | Before Stage 1 | After corrected Stage 1 | +| --- | ---: | ---: | +| Full | 29 keys: 1 low, 12 moderate, 15 high, 1 critical | 10 keys: 0 low, 4 moderate, 6 high, 0 critical | +| `--omit=dev` | 27 keys: 1 low, 12 moderate, 14 high, 0 critical | 10 keys: 0 low, 4 moderate, 6 high, 0 critical | + +The corrected full and `--omit=dev` audits now agree because six build-only +packages were reclassified as development dependencies: `@astrojs/check`, +`@tailwindcss/vite`, `@types/react`, `@types/react-dom`, `tailwindcss`, and +`typescript`. That makes the production audit graph meaningful rather than +allowing build tooling to be counted as deployed application dependencies. + +Stage 1 removed the Vitest critical path. It also updated Resend and removed the +reported `svix`/`uuid` chain; neither package is present in the current installed +graph or lockfile. The ten residual vulnerable keys are: + +- `@astrojs/cloudflare` +- `@astrojs/react` +- `astro` +- `esbuild` +- `miniflare` +- `sharp` +- `undici` +- `vite` +- `wrangler` +- `ws` + +Astro 5.18.2 is an interim compatibility update, not remediation of the Astro +advisories. A live standard, non-forced `npm audit fix --dry-run --json` reported +zero packages added, changed, or removed. Further audit remediation therefore +crosses the approved Stage 1 major-version boundaries. + +## Dependabot external gate (post-merge) + +As verified 2026-08-30, GitHub reports Dependabot security updates (automated +security fixes) disabled for this repository. `.github/dependabot.yml` defines +the reviewed update-grouping policy, but that file cannot enable the separate +repository setting. Advisory-triggered Dependabot updates must not be described +as active while GitHub continues to report the setting disabled. + +This is intentionally a post-merge external gate: the default branch must first +contain the reviewed grouping policy before activation. After this branch +reaches the default branch, separately authorize enabling Dependabot security +updates, enable the repository setting, and verify that GitHub reports it as +enabled. This record does not authorize or claim that external change. + +## Direct residual advisories + +The live audit reports the following direct Astro and Cloudflare-adapter +advisories. "Current condition" is repository-specific reachability evidence, +not a claim that the vulnerable dependency code has been patched locally. + +| Advisory | Primary title | Severity | Affected / patched | Current repository condition | +| --- | --- | --- | --- | --- | +| [GHSA-j687-52p2-xcff](https://github.com/advisories/GHSA-j687-52p2-xcff) | Astro: XSS in `define:vars` via incomplete `` tag sanitization | Moderate | Astro `<6.1.6` / `6.1.6` | No `define:vars` directive is used. The `define` key in `astro.config.mjs` is Vite build configuration and is unrelated. | +| [GHSA-xr5h-phrj-8vxv](https://github.com/advisories/GHSA-xr5h-phrj-8vxv) | Astro: Server island encrypted parameters vulnerable to cross-component replay | Low | Astro `<6.1.10` / `6.1.10` | No server islands (`server:defer`) are used. | +| [GHSA-jrpj-wcv7-9fh9](https://github.com/advisories/GHSA-jrpj-wcv7-9fh9) | Astro: XSS via Unescaped Attribute Names in Spread Props | Moderate | Astro `<6.4.6` / `6.4.6` | No spread attributes occur in `.astro` templates. | +| [GHSA-f48w-9m4c-m7f5](https://github.com/advisories/GHSA-f48w-9m4c-m7f5) | Astro: XSS via unescaped spread attribute names in `renderHTMLElement` (incomplete fix for CVE-2026-54298) | Moderate | Astro `<7.0.6` / `7.0.6` | No spread attributes occur in `.astro` templates, so the advisory's untrusted-keyed spread-prop path is absent. | +| [GHSA-7pw4-f3q4-r2p2](https://github.com/advisories/GHSA-7pw4-f3q4-r2p2) | Astro: Cross-site scripting via unescaped `transition:*` directive values on hydrated islands | Low | Astro `>=3.10.0 <7.0.4` / `7.0.4` | No Astro `transition:*` directive is used. | +| [GHSA-4g3v-8h47-v7g6](https://github.com/advisories/GHSA-4g3v-8h47-v7g6) | Astro: Reflected XSS via unescaped View Transition animation properties | Moderate | Astro `>=2.9.0 <=7.0.9` / `7.1.0` | No `ViewTransitions` or `ClientRouter` import is used, and no Astro transition directive is present. | +| [GHSA-2pvr-wf23-7pc7](https://github.com/advisories/GHSA-2pvr-wf23-7pc7) | Astro: Host header SSRF in prerendered error page fetch | High | Astro `<6.4.6` / `6.4.6` | Not reachable through this deployment: the primary advisory explicitly lists `@astrojs/cloudflare` as unaffected because it reads error pages through the ASSETS binding. | +| [GHSA-8hv8-536x-4wqp](https://github.com/advisories/GHSA-8hv8-536x-4wqp) | Astro: Reflected XSS via unescaped slot name | High | Astro `<6.3.3` / `6.3.3` | Current named slots are static: the only name is the literal `icon`; the remaining slots are default slots. No attacker-controlled or dynamic Astro slot name is used. | +| [GHSA-88gm-j2wx-58h6](https://github.com/advisories/GHSA-88gm-j2wx-58h6) | Cloudflare has SSRF via redirect following through its image-binding-transform endpoint (incomplete fix for GHSA-qpr4) | Low | `@astrojs/cloudflare <13.1.10` / `13.1.10` | The required remote-image path is not configured or used: there is no `image.domains`, `image.remotePatterns`, `astro:assets`, Astro ``, or Astro ``. This low-severity advisory does not independently increase urgency under the current configuration. | + +The image search also found ordinary verification-image storage and admin-route +text. Those are R2-backed verification uploads, not Astro's remote image service, +and are not evidence that the Cloudflare image advisory is reachable. Likewise, +the only source match for `transition:` is a React inline CSS transition in +`BuildingMap.tsx`; it is not an Astro template directive or View Transition API. + +These conclusions must be revisited if the project introduces any construct on +which they rely, changes adapters, or exposes a relevant value to attacker +control. Any such change advances the Stage 2 priority and requires security +review before release. + +## Stage 2 migration boundary + +Stage 2 is a coordinated, separately reviewed major migration with these package +targets: + +- `astro` 7.2.9 +- `@astrojs/cloudflare` 14.2.5 +- `@astrojs/react` 6.0.4 +- a current compatible `@cloudflare/workers-types` (5.20260829.1 was current when + this record was verified) +- `react` and `react-dom` remain at 18.3.1 + +Astro 7.1.0 is the security floor because it contains the View Transition fix; +7.0.x is not acceptable. The approved Astro 7.2.9 target provides margin above +that floor and matches the Cloudflare adapter's published Astro `^7.2.0` peer +range. Astro 7.2.9 requires Node 22.12.0 or newer. + +Implementation must review both official migration guides before changing the +graph: + +- [Upgrade to Astro v6 (5→6)](https://docs.astro.build/en/guides/upgrade-to/v6/) +- [Upgrade to Astro v7 (6→7)](https://docs.astro.build/en/guides/upgrade-to/v7/) + +After migration 0028, re-audit all of the following against the migrated runtime, +not only against compile-time success: + +- Astro `security.checkOrigin`, authenticated and unauthenticated POST routes, + the `application/json` gap, and SameSite cookie behavior; +- SSR behavior; Cloudflare D1 and R2 bindings; authentication; and image routes; +- `getEnv`, `fireAndForget`, `ctx.waitUntil`, fail-closed rate limiting, and + destructive-action audit-log writes. + +The release gate is `npm run check`, `npm test`, `npm run build`, and the complete +E2E suite, followed by an immutable exact-SHA preview and explicit preview smoke. +After that passes, verify production-only Turnstile and map behavior plus every +user flow affected by the migration. Preview cannot establish the Turnstile or +map results. + +Staying on the current Astro major is therefore operational security work: the +examined fixes were not backported to Astro 5. Current source conditions reduce +exposure, but they do not remove the maintenance obligation or replace Stage 2. diff --git a/docs/superpowers/plans/2026-08-29-dependency-security-refresh.md b/docs/superpowers/plans/2026-08-29-dependency-security-refresh.md new file mode 100644 index 0000000..68e1ddb --- /dev/null +++ b/docs/superpowers/plans/2026-08-29-dependency-security-refresh.md @@ -0,0 +1,58 @@ +# Dependency security refresh implementation plan + +**Approved:** 2026-08-29 + +**Branch:** `codex/dependency-security-refresh` + +**Base:** `origin/main` at `a18254a89132ff8ed4da4ef4ae40af3677a12795` + +## Goal + +Remove the critical dependency advisory and most compatible advisory debt without changing intended product behavior, make dependency risk visible in CI, and leave a verified handoff for the separately reviewed Astro 7 migration. + +## Global constraints + +- Do not change application features, copy, scoring, database schema or data, Cloudflare settings, environment variables, authentication, moderation, or privacy behavior. +- Do not use `npm audit fix --force`, unsupported dependency overrides, or unreviewed broad rewrites. +- Raise direct dependency floors in `package.json` and commit the reproducible `package-lock.json` resolution. +- Astro 5.18.2 is a compatible interim update, not a complete remediation of Astro advisory debt. +- Stage 2 targets Astro 7.2.9. The security floor is 7.1.0; no 7.0.x version is an acceptable stopping point. +- Keep React and React DOM on 18.3.1 in this stage. +- `main` auto-deploys. Do not push, open a PR, or merge without the user's separate approval gates. +- Preserve the user-owned untracked `src/pages/api/admin/verification/[id] (1).ts` in the root checkout; all work occurs in this isolated worktree. + +## Task 1: Pages install authority and pre-change baseline + +1. Record the Pages install evidence. Cloudflare's documented default installs all dependencies, but the account API token cannot read project configuration. Treat an exact-SHA Pages preview built after reclassification as the authoritative pre-merge proof that build-time devDependencies are installed. +2. Run a clean `npm ci` from the current lockfile. +3. Record the full and `--omit=dev` audit counts. +4. Run `npm run check`, `npm test`, `npm run build`, and `npm run e2e` before dependency changes. Stop on an unexplained failure. + +## Task 2: Compatible dependency refresh + +1. Raise direct floors to Astro 5.18.2, Vitest 4.1.11, happy-dom 20.11.13, Resend 6.25.0, and `@astrojs/check` 0.9.10. +2. Move `@astrojs/check`, TypeScript, both React type packages, `@tailwindcss/vite`, and Tailwind CSS from `dependencies` to `devDependencies`. +3. Refresh compatible transitive resolutions without `--force` and review the lockfile changes. +4. Reproduce the expected full audit reduction from 29 to approximately 10, with zero critical findings. Record the actual result rather than forcing it to match the simulation. +5. Run check, unit tests, and build after the dependency refresh. + +## Task 3: Dependency guardrails + +1. Add a failing workflow-contract test that requires CI to run `npm audit --audit-level=critical` after `npm ci` and before check/test/build. +2. Add the minimal CI workflow change that makes the contract pass. +3. Add `.github/dependabot.yml` for grouped monthly npm version updates and grouped advisory-triggered security updates. Do not describe security updates as weekly; GitHub triggers them from advisories. +4. Add contract coverage for the low-noise Dependabot policy where it protects repository-owned behavior rather than merely mirroring arbitrary YAML text. + +## Task 4: Residual advisory and Stage 2 handoff + +1. Add a dated planning note that records the actual post-Stage-1 full and production-graph audit counts. +2. Name the residual Astro advisories and the current reachability conditions being relied upon: no attacker-controlled dynamic slots, no remote image allowlist or Astro image components, no transition directives or View Transition imports, and no Astro spread attributes. +3. Record that a change to any relied-upon condition advances the Astro 7 migration priority. +4. Record the approved Stage 2 target and checks: Astro 7.2.9, Cloudflare adapter 14.2.5, React adapter 6.0.4, current compatible Workers types, both migration guides, CSRF re-audit, `getEnv`/`ctx.waitUntil`, fail-closed rate limiting, audit-log writes, D1/R2 bindings, auth, SSR, image route, E2E, immutable preview, and production verification. + +## Task 5: Final verification and review + +1. Run `npm ci`, both audit views, `npm run check`, `npm test`, `npm run build`, and `npm run e2e` from the committed candidate. +2. Review the complete branch diff, including direct version floors, dependency classification, lockfile, workflows, Dependabot policy, tests, and documentation. +3. Obtain a broad whole-branch review and resolve all load-bearing findings. +4. Present the diff and verification evidence for separate push/PR approval. Do not push during implementation. diff --git a/e2e/admin-actions.spec.ts b/e2e/admin-actions.spec.ts index d721b7f..9c65b34 100644 --- a/e2e/admin-actions.spec.ts +++ b/e2e/admin-actions.spec.ts @@ -43,10 +43,11 @@ test.describe('Review Moderation (E2E-07)', () => { // Use the second review card to avoid any collision with the approve test card. // All seed reviews are 'approved' — expand the second card. const reviewCards = adminPage.locator('.cursor-pointer'); - await reviewCards.nth(1).click(); + const secondReviewHeader = reviewCards.nth(1); + await secondReviewHeader.click(); - // Scope all subsequent actions to the expanded card (second card container) - const secondCard = adminPage.locator('.bg-white.rounded-xl').nth(1); + // Scope all subsequent actions to the expanded card containing that header. + const secondCard = secondReviewHeader.locator('..'); // Click "Reset to Pending" within the second card to expose the Reject button await secondCard.locator('button', { hasText: 'Reset to Pending' }).click(); @@ -55,7 +56,7 @@ test.describe('Review Moderation (E2E-07)', () => { await expect(secondCard.locator('span.rounded-full')).toContainText('pending'); // Click Reject within the same card - await secondCard.locator('button', { hasText: 'Reject' }).click(); + await secondCard.locator('button', { hasText: 'Reject' }).first().click(); // Assert status badge within the card updated to 'rejected' await expect(secondCard.locator('span.rounded-full')).toContainText('rejected'); diff --git a/e2e/admin-pages.spec.ts b/e2e/admin-pages.spec.ts index 2f6c62f..744daab 100644 --- a/e2e/admin-pages.spec.ts +++ b/e2e/admin-pages.spec.ts @@ -6,7 +6,7 @@ import { test, expect } from './fixtures'; test.describe('Admin Page Navigation', () => { test('admin navigation bar contains all page links', async ({ adminPage }) => { await adminPage.goto('/admin'); - await expect(adminPage.locator('h1')).toContainText('Dashboard Overview'); + await expect(adminPage.locator('h1')).toContainText('Dashboard overview'); // Assert all 9 nav links are present await expect(adminPage.locator('nav a[href="/admin"]').first()).toBeVisible(); @@ -27,24 +27,24 @@ test.describe('Admin Dashboard', () => { await adminPage.goto('/admin'); // Heading - await expect(adminPage.locator('h1')).toContainText('Dashboard Overview'); + await expect(adminPage.locator('h1')).toContainText('Dashboard overview'); // Stats card labels - await expect(adminPage.locator('text=Total Users')).toBeVisible(); - await expect(adminPage.locator('text=Total Reviews')).toBeVisible(); + await expect(adminPage.locator('text=Total users')).toBeVisible(); + await expect(adminPage.locator('text=Total reviews')).toBeVisible(); await expect(adminPage.locator('p.text-sm.font-medium', { hasText: 'Buildings' })).toBeVisible(); await expect(adminPage.locator('text=Verifications')).toBeVisible(); // Section headings on dashboard - await expect(adminPage.locator('text=Review Status Breakdown')).toBeVisible(); - await expect(adminPage.locator('text=Recent Reviews')).toBeVisible(); + await expect(adminPage.locator('text=Review status breakdown')).toBeVisible(); + await expect(adminPage.locator('text=Recent reviews')).toBeVisible(); }); }); test.describe('Admin Pages Render', () => { test('users page renders', async ({ adminPage }) => { await adminPage.goto('/admin/users'); - await expect(adminPage.locator('h1')).toContainText('User Management'); + await expect(adminPage.locator('h1')).toContainText('Users'); await adminPage.waitForLoadState('networkidle'); // React island rendered — table or content should be present await expect(adminPage.locator('h1')).toBeVisible(); @@ -52,7 +52,7 @@ test.describe('Admin Pages Render', () => { test('reviews page renders', async ({ adminPage }) => { await adminPage.goto('/admin/reviews'); - await expect(adminPage.locator('h1')).toContainText('Review Management'); + await expect(adminPage.locator('h1')).toContainText('Reviews'); await adminPage.waitForLoadState('networkidle'); // Status filter buttons should be visible after React island loads await expect(adminPage.locator('button').filter({ hasText: /All \(/ })).toBeVisible(); @@ -60,35 +60,35 @@ test.describe('Admin Pages Render', () => { test('buildings page renders', async ({ adminPage }) => { await adminPage.goto('/admin/buildings'); - await expect(adminPage.locator('h1')).toContainText('Building Management'); + await expect(adminPage.locator('h1')).toContainText('Buildings'); await adminPage.waitForLoadState('networkidle'); await expect(adminPage.locator('h1')).toBeVisible(); }); test('landlords page renders', async ({ adminPage }) => { await adminPage.goto('/admin/landlords'); - await expect(adminPage.locator('h1')).toContainText('Landlord Management'); + await expect(adminPage.locator('h1')).toContainText('Landlords'); await adminPage.waitForLoadState('networkidle'); await expect(adminPage.locator('h1')).toBeVisible(); }); test('managers page renders', async ({ adminPage }) => { await adminPage.goto('/admin/managers'); - await expect(adminPage.locator('h1')).toContainText('Property Manager Management'); + await expect(adminPage.locator('h1')).toContainText('Property managers'); await adminPage.waitForLoadState('networkidle'); await expect(adminPage.locator('h1')).toBeVisible(); }); test('verification page renders', async ({ adminPage }) => { await adminPage.goto('/admin/verify'); - await expect(adminPage.locator('h1')).toContainText('Verification Queue'); + await expect(adminPage.locator('h1')).toContainText('Verification'); await adminPage.waitForLoadState('networkidle'); await expect(adminPage.locator('h1')).toBeVisible(); }); test('disputes page renders', async ({ adminPage }) => { await adminPage.goto('/admin/disputes'); - await expect(adminPage.locator('h1')).toContainText('Dispute Queue'); + await expect(adminPage.locator('h1')).toContainText('Disputes'); await adminPage.waitForLoadState('networkidle'); // Filter buttons: Pending, Resolved, All const pendingBtn = adminPage.locator('button').filter({ hasText: 'Pending' }); @@ -103,7 +103,7 @@ test.describe('Admin Pages Render', () => { test('audit page renders', async ({ adminPage }) => { await adminPage.goto('/admin/audit'); - await expect(adminPage.locator('h1')).toContainText('Audit Log'); + await expect(adminPage.locator('h1')).toContainText('Audit log'); await adminPage.waitForLoadState('networkidle'); // Either audit log table thead is visible or "No audit logs found" message appears const hasTable = await adminPage.locator('table thead').count(); @@ -116,8 +116,8 @@ test.describe('Admin Access Control', () => { test('non-admin user is redirected from admin pages', async ({ authedPage }) => { // SSR redirect — use waitUntil: 'commit' so Playwright resolves when the 302 is sent await authedPage.goto('/admin', { waitUntil: 'commit' }); - // Dashboard Overview heading must NOT be visible — user was redirected - await expect(authedPage.locator('h1').filter({ hasText: 'Dashboard Overview' })).not.toBeVisible(); + // Dashboard overview heading must NOT be visible — user was redirected + await expect(authedPage.locator('h1').filter({ hasText: 'Dashboard overview' })).not.toBeVisible(); }); test('unauthenticated user is redirected to signin', async ({ page }) => { @@ -127,7 +127,7 @@ test.describe('Admin Access Control', () => { const isOnAdmin = page.url().includes('/admin') && !page.url().includes('/auth'); if (isOnAdmin) { // Verify no admin dashboard content is accessible - await expect(page.locator('h1').filter({ hasText: 'Dashboard Overview' })).not.toBeVisible(); + await expect(page.locator('h1').filter({ hasText: 'Dashboard overview' })).not.toBeVisible(); } else { await expect(page).toHaveURL(/auth\/signin/); } diff --git a/e2e/auth.spec.ts b/e2e/auth.spec.ts index f07e47a..e6868b5 100644 --- a/e2e/auth.spec.ts +++ b/e2e/auth.spec.ts @@ -1,13 +1,5 @@ -import { execSync } from 'child_process'; -import path from 'path'; -import { fileURLToPath } from 'url'; import { test, expect } from './fixtures'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -// Project root for wrangler CLI calls (e2e/ is one level below root) -const PROJECT_ROOT = path.resolve(__dirname, '..'); +import { executeLocalD1 } from './test-harness'; // Seed user credentials (created in Phase 5) const SEED_EMAIL = 'user@test.ratemyplace.local'; @@ -134,15 +126,11 @@ test.describe('Password Reset', () => { await expect(page.locator('#success-message')).toBeVisible(); // Step 2: Read token from local D1 via wrangler CLI - const wranglerCommand = `npx wrangler d1 execute ratemyplace-db --local --command "SELECT pr.token FROM password_reset_tokens pr JOIN users u ON pr.user_id = u.id WHERE u.email = '${resetEmail}' ORDER BY pr.expires_at DESC LIMIT 1"`; + const tokenQuery = `SELECT pr.token FROM password_reset_tokens pr JOIN users u ON pr.user_id = u.id WHERE u.email = '${resetEmail}' ORDER BY pr.expires_at DESC LIMIT 1`; let token: string; try { - const rawOutput = execSync(wranglerCommand, { - cwd: PROJECT_ROOT, - timeout: 30000, - encoding: 'utf8', - }); + const rawOutput = executeLocalD1(tokenQuery); // Wrangler outputs JSON. Try structured parse first, then regex fallback. let parsed: unknown; diff --git a/e2e/critical-flows.spec.ts b/e2e/critical-flows.spec.ts index 9a682ed..14abc00 100644 --- a/e2e/critical-flows.spec.ts +++ b/e2e/critical-flows.spec.ts @@ -1,12 +1,11 @@ import { test, expect } from './fixtures'; -import path from 'path'; -import { fileURLToPath } from 'url'; -import { execSync } from 'child_process'; +import { + executeLocalD1, + resolveLocalE2EBaseURL, + TURNSTILE_TEST_TOKEN, +} from './test-harness'; -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); -const PROJECT_ROOT = path.resolve(__dirname, '..'); -const BASE_URL = process.env.BASE_URL || 'http://localhost:8788'; +const BASE_URL = resolveLocalE2EBaseURL(); // ─── Phase 20 reservations ────────────────────────────────────────────────── // Test-only building: building-e2e-01 (slug test-cross-view-consistency, addr "999 E2E Test Way"). @@ -25,14 +24,10 @@ const TEST_BUILDING_SLUG = 'test-cross-view-consistency'; function cleanupPhase20Reviews(): void { // Find any reviews for the test building and delete their audit_logs first, // then the reviews themselves. Uses subquery to avoid needing IDs upfront. - execSync( - `npx wrangler d1 execute ratemyplace-db --local --command "DELETE FROM audit_logs WHERE entity_id IN (SELECT id FROM reviews WHERE building_id = 'building-e2e-01')"`, - { cwd: PROJECT_ROOT, stdio: 'pipe' } - ); - execSync( - `npx wrangler d1 execute ratemyplace-db --local --command "DELETE FROM reviews WHERE building_id = 'building-e2e-01'"`, - { cwd: PROJECT_ROOT, stdio: 'pipe' } + executeLocalD1( + "DELETE FROM audit_logs WHERE entity_id IN (SELECT id FROM reviews WHERE building_id = 'building-e2e-01')" ); + executeLocalD1("DELETE FROM reviews WHERE building_id = 'building-e2e-01'"); } /** @@ -42,10 +37,7 @@ function cleanupPhase20Reviews(): void { */ function countAuditLogEntries(reviewId: string, actionType: string): number { const sql = `SELECT COUNT(*) as c FROM audit_logs WHERE entity_id = '${reviewId}' AND action_type = '${actionType}'`; - const raw = execSync( - `npx wrangler d1 execute ratemyplace-db --local --command "${sql}" --json`, - { cwd: PROJECT_ROOT, encoding: 'utf8', stdio: 'pipe' } - ); + const raw = executeLocalD1(sql); const parsed = JSON.parse(raw); return parsed[0].results[0].c as number; } @@ -54,7 +46,7 @@ function countAuditLogEntries(reviewId: string, actionType: string): number { * Submit a review via POST /api/reviews using the authed user's session. * Returns the generated reviewId from the response body. * Posts minimal-but-valid form data: required building_id, all 27 score fields - * set to 4, and the dummy Turnstile token (verify fails open in local dev). + * set to 4, and Cloudflare's documented always-pass Turnstile test token. */ async function submitReviewAsAuthedUser( authedPage: import('@playwright/test').Page, @@ -75,7 +67,7 @@ async function submitReviewAsAuthedUser( 'landlord_fee_transparency', 'landlord_safety_response', ]; const formFields: Record = { - 'cf-turnstile-response': 'XXXX.DUMMY.TOKEN.XXXX', + 'cf-turnstile-response': TURNSTILE_TEST_TOKEN, building_id: buildingId, bedrooms: '1', bathrooms: '1', @@ -128,16 +120,12 @@ test.describe('Phase 20: Critical Flows', () => { await adminPage.goto('/admin/reviews?status=pending'); await adminPage.waitForLoadState('networkidle'); - // Scope to the outer card container (bg-white rounded-xl) which contains both - // the header (cursor-pointer) and the expanded details panel with the Approve button. - // Use .first() for strict mode safety if multiple test reviews exist (e.g., from - // a previous run's afterEach failure). The beforeEach cleanup handles stale reviews, - // but .first() prevents strict-mode errors if a race leaves extras. - const reviewCard = adminPage.locator('.bg-white.rounded-xl', { hasText: TEST_BUILDING_ADDRESS }).first(); - await expect(reviewCard).toBeVisible({ timeout: 10000 }); + // Select the review's semantic header, then scope actions to its parent card. + const reviewHeader = adminPage.locator('.cursor-pointer', { hasText: TEST_BUILDING_ADDRESS }).first(); + await expect(reviewHeader).toBeVisible({ timeout: 10000 }); + const reviewCard = reviewHeader.locator('..'); - // Click the cursor-pointer header to expand the card and load full review details. - const reviewHeader = reviewCard.locator('.cursor-pointer').first(); + // Expand the card and load full review details. await reviewHeader.click(); // Wait for the Approve button to be visible inside the expanded card before clicking. @@ -198,10 +186,9 @@ test.describe('Phase 20: Critical Flows', () => { await adminPage.goto('/admin/reviews?status=pending'); await adminPage.waitForLoadState('networkidle'); - const reviewCard = adminPage.locator('.bg-white.rounded-xl', { hasText: TEST_BUILDING_ADDRESS }).first(); - await expect(reviewCard).toBeVisible({ timeout: 10000 }); - - const reviewHeader = reviewCard.locator('.cursor-pointer').first(); + const reviewHeader = adminPage.locator('.cursor-pointer', { hasText: TEST_BUILDING_ADDRESS }).first(); + await expect(reviewHeader).toBeVisible({ timeout: 10000 }); + const reviewCard = reviewHeader.locator('..'); await reviewHeader.click(); const approveButton = reviewCard.locator('button', { hasText: 'Approve' }).first(); @@ -242,8 +229,11 @@ test.describe('Phase 20: Critical Flows', () => { // the path for building-e2e-01 (no pre-seeded building_scores row). await authedPage.goto(`/building/${TEST_BUILDING_SLUG}`); await authedPage.waitForLoadState('networkidle'); - const detailScoreText = await authedPage - .locator('.text-4xl.font-bold.text-teal-600') + const detailReviewCount = authedPage.getByText(/\d+\s+reviews?/).first(); + await expect(detailReviewCount).toBeVisible({ timeout: 10000 }); + const detailScoreText = await detailReviewCount + .locator('..') + .locator(':scope > div') .first() .textContent(); expect(detailScoreText, 'Detail page must render score').toBeTruthy(); diff --git a/e2e/fixtures.ts b/e2e/fixtures.ts index d11bc69..d4bc782 100644 --- a/e2e/fixtures.ts +++ b/e2e/fixtures.ts @@ -1,7 +1,7 @@ import { test as base, expect } from '@playwright/test'; import path from 'path'; import { fileURLToPath } from 'url'; -import { execSync } from 'child_process'; +import { executeLocalD1, installTurnstileStub } from './test-harness'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -15,11 +15,16 @@ type CustomFixtures = { }; export const test = base.extend({ + page: async ({ page }, use) => { + await installTurnstileStub(page); + await use(page); + }, authedPage: async ({ browser }, use) => { const context = await browser.newContext({ storageState: USER_AUTH_FILE, }); const page = await context.newPage(); + await installTurnstileStub(page); await use(page); await context.close(); }, @@ -28,6 +33,7 @@ export const test = base.extend({ storageState: ADMIN_AUTH_FILE, }); const page = await context.newPage(); + await installTurnstileStub(page); await use(page); await context.close(); }, @@ -43,8 +49,5 @@ export { expect }; * Always operates on --local (no params); remote support is YAGNI. */ export function clearRateLimits(): void { - execSync( - 'npx wrangler d1 execute ratemyplace-db --local --command "DELETE FROM rate_limits"', - { cwd: path.resolve(__dirname, '..'), stdio: 'pipe' } - ); + executeLocalD1('DELETE FROM rate_limits'); } diff --git a/e2e/global.setup.ts b/e2e/global.setup.ts index 90f22d4..ca48d65 100644 --- a/e2e/global.setup.ts +++ b/e2e/global.setup.ts @@ -1,4 +1,4 @@ -import { test as setup } from '@playwright/test'; +import { test as setup } from './fixtures'; import { mkdir } from 'fs/promises'; import path from 'path'; import { fileURLToPath } from 'url'; diff --git a/e2e/pages.spec.ts b/e2e/pages.spec.ts index e411fc6..7102c33 100644 --- a/e2e/pages.spec.ts +++ b/e2e/pages.spec.ts @@ -11,7 +11,7 @@ test.describe('Homepage', () => { test('has How It Works section', async ({ page }) => { await page.goto('/'); await expect(page.locator('text=How It Works')).toBeVisible(); - await expect(page.locator('text=Evidence-Based Scoring')).toBeVisible(); + await expect(page.getByRole('heading', { name: 'Evidence-based scoring' })).toBeVisible(); }); }); diff --git a/e2e/preflight.ts b/e2e/preflight.ts new file mode 100644 index 0000000..758e644 --- /dev/null +++ b/e2e/preflight.ts @@ -0,0 +1,5 @@ +import { validateLocalE2EEnvironment } from './test-harness'; + +const baseURL = validateLocalE2EEnvironment(); + +console.log(`[E2E safety] Local preflight passed for ${baseURL}.`); diff --git a/e2e/review.spec.ts b/e2e/review.spec.ts index 95f05ed..4e526ba 100644 --- a/e2e/review.spec.ts +++ b/e2e/review.spec.ts @@ -1,6 +1,7 @@ import { fileURLToPath } from 'url'; import path from 'path'; import { test, expect } from './fixtures'; +import { installTurnstileStub } from './test-harness'; // Derive Page type from the fixture to avoid importing from @playwright/test directly type Page = Parameters[1]>[0]['authedPage']; @@ -246,6 +247,10 @@ test.describe('Concurrent Submissions', () => { ]); const page1 = await ctx1.newPage(); const page2 = await ctx2.newPage(); + await Promise.all([ + installTurnstileStub(page1), + installTurnstileStub(page2), + ]); // Helper to navigate through all review steps up to (but not including) the Submit click async function fillReviewToSubmit(page: Page) { diff --git a/e2e/security.spec.ts b/e2e/security.spec.ts index fca9aaf..9d71d61 100644 --- a/e2e/security.spec.ts +++ b/e2e/security.spec.ts @@ -1,22 +1,18 @@ import { test, expect, clearRateLimits } from './fixtures'; -import path from 'path'; -import { fileURLToPath } from 'url'; -import { execSync } from 'child_process'; +import { + executeLocalD1, + resolveLocalE2EBaseURL, + TURNSTILE_TEST_TOKEN, +} from './test-harness'; -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); -const PROJECT_ROOT = path.resolve(__dirname, '..'); -const BASE_URL = process.env.BASE_URL || 'http://localhost:8788'; +const BASE_URL = resolveLocalE2EBaseURL(); // Remove any disputes created by previous security test runs for the reserved review IDs. // This makes injection/XSS tests re-runnable without a full db:setup. function clearSecurityTestDisputes() { const reviewIds = ['review-030', 'review-040', 'review-060', 'review-070']; const idList = reviewIds.map((id) => `'${id}'`).join(', '); - execSync( - `npx wrangler d1 execute ratemyplace-db --local --command "DELETE FROM disputes WHERE review_id IN (${idList})"`, - { cwd: PROJECT_ROOT, stdio: 'pipe' } - ); + executeLocalD1(`DELETE FROM disputes WHERE review_id IN (${idList})`); } // Dispute payload helper — each test uses a different reviewId to avoid UNIQUE constraint. @@ -27,25 +23,26 @@ function makeDisputePayload(reviewId: string, explanation: string) { landlordName: 'Test Landlord', landlordEmail: `sec-test-${reviewId}@test.local`, landlordPhone: '555-0000', - disputeReasons: ['inaccurate_info'], + disputeReasons: ['Factually incorrect information'], disputeExplanation: explanation, + turnstileToken: TURNSTILE_TEST_TOKEN, }; } // Expand the dispute card matching a given landlord email and return whether it was found async function expandDisputeByEmail(adminPage: import('@playwright/test').Page, email: string): Promise { - const allCards = adminPage.locator('.bg-white.rounded-xl'); - const count = await allCards.count(); + const disputeHeaders = adminPage.locator('.cursor-pointer'); + const count = await disputeHeaders.count(); for (let i = 0; i < count; i++) { - const card = allCards.nth(i); - await card.click(); + const header = disputeHeaders.nth(i); + await header.click(); await adminPage.waitForTimeout(400); const emailVisible = await adminPage.locator(`text=${email}`).isVisible().catch(() => false); if (emailVisible) { return true; } // Collapse this card before trying the next - await card.click(); + await header.click(); await adminPage.waitForTimeout(200); } return false; @@ -116,12 +113,12 @@ test.describe('Rate Limiting (SEC-06)', () => { const wrongPassword = 'wrongpassword'; for (let i = 0; i < 5; i++) { await request.post('/api/auth/signin', { - form: { email, password: wrongPassword }, + form: { email, password: wrongPassword, 'cf-turnstile-response': TURNSTILE_TEST_TOKEN }, headers: { Origin: ORIGIN }, }); } const blocked = await request.post('/api/auth/signin', { - form: { email, password: wrongPassword }, + form: { email, password: wrongPassword, 'cf-turnstile-response': TURNSTILE_TEST_TOKEN }, headers: { Origin: ORIGIN }, }); expect(blocked.status()).toBe(429); @@ -137,6 +134,7 @@ test.describe('Rate Limiting (SEC-06)', () => { email: `ratelimit-signup-${i}-${ts}@fake.local`, password: 'TestPassword123!', confirmPassword: 'TestPassword123!', + 'cf-turnstile-response': TURNSTILE_TEST_TOKEN, }, headers: { Origin: ORIGIN }, }); @@ -146,6 +144,7 @@ test.describe('Rate Limiting (SEC-06)', () => { email: `ratelimit-signup-3-${ts}@fake.local`, password: 'TestPassword123!', confirmPassword: 'TestPassword123!', + 'cf-turnstile-response': TURNSTILE_TEST_TOKEN, }, headers: { Origin: ORIGIN }, }); @@ -275,7 +274,7 @@ test.describe('Phase 17: Public Endpoint Security', () => { for (let i = 0; i < 5; i++) { const res = await request.post('/api/bug-reports', { multipart: { - 'cf-turnstile-response': 'XXXX.DUMMY.TOKEN.XXXX', + 'cf-turnstile-response': TURNSTILE_TEST_TOKEN, description: `bug report number ${i} with enough characters to pass length check`, category: 'bug', }, @@ -287,7 +286,7 @@ test.describe('Phase 17: Public Endpoint Security', () => { // 6th attempt — must be 429 const sixth = await request.post('/api/bug-reports', { multipart: { - 'cf-turnstile-response': 'XXXX.DUMMY.TOKEN.XXXX', + 'cf-turnstile-response': TURNSTILE_TEST_TOKEN, description: 'sixth attempt should be rate-limited', category: 'bug', }, @@ -422,7 +421,7 @@ test.describe('Phase 21: Rate Limit Headers', () => { email: 'test@example.com', category: 'general', message: 'Phase 21 header test message', - 'cf-turnstile-response': 'XXXX.DUMMY.TOKEN.XXXX', + 'cf-turnstile-response': TURNSTILE_TEST_TOKEN, }, headers: { Origin: BASE_URL }, }); @@ -434,7 +433,7 @@ test.describe('Phase 21: Rate Limit Headers', () => { email: 'test@example.com', category: 'general', message: 'Phase 21 header test message fourth', - 'cf-turnstile-response': 'XXXX.DUMMY.TOKEN.XXXX', + 'cf-turnstile-response': TURNSTILE_TEST_TOKEN, }, headers: { Origin: BASE_URL }, }); @@ -461,7 +460,7 @@ test.describe('Phase 21: Rate Limit Headers', () => { test('SEC-08: POST /api/bug-reports under limit returns x-ratelimit-limit=5 and x-ratelimit-remaining on success', async ({ request }) => { const res = await request.post('/api/bug-reports', { multipart: { - 'cf-turnstile-response': 'XXXX.DUMMY.TOKEN.XXXX', + 'cf-turnstile-response': TURNSTILE_TEST_TOKEN, description: 'Phase 21 header test bug report with enough characters to pass length check', category: 'bug', }, diff --git a/e2e/test-harness.spec.ts b/e2e/test-harness.spec.ts new file mode 100644 index 0000000..9c1ab7d --- /dev/null +++ b/e2e/test-harness.spec.ts @@ -0,0 +1,137 @@ +import { test, expect } from '@playwright/test'; +import { spawnSync } from 'node:child_process'; +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import * as testHarness from './test-harness'; + +type BaseURLResolver = (configuredBaseURL?: string) => string; +type E2EEnvironment = Record; +type EnvironmentValidator = (environment?: E2EEnvironment) => string; + +const packageJson = JSON.parse( + readFileSync(new URL('../package.json', import.meta.url), 'utf8') +) as { scripts?: Record }; +const projectRoot = fileURLToPath(new URL('../', import.meta.url)); +const childEnvironmentKeys = [ + 'APPDATA', + 'COMSPEC', + 'HOME', + 'LOCALAPPDATA', + 'PATH', + 'Path', + 'PATHEXT', + 'SYSTEMROOT', + 'SystemRoot', + 'TEMP', + 'TMP', + 'TMPDIR', + 'USERPROFILE', +] as const; + +function buildPreflightEnvironment( + unsafeFlag: 'D1_REMOTE' | 'SEED_REVIEWS_ONLY' +): NodeJS.ProcessEnv { + const environment: NodeJS.ProcessEnv = { + BASE_URL: 'http://localhost:8788', + [unsafeFlag]: '1', + }; + + for (const key of childEnvironmentKeys) { + if (process.env[key] !== undefined) { + environment[key] = process.env[key]; + } + } + + return environment; +} + +function getNpmInvocation(): { executable: string; arguments: string[] } { + if (process.platform !== 'win32') { + return { executable: 'npm', arguments: ['run', 'e2e:preflight'] }; + } + + const npmCliPath = process.env.npm_execpath; + if (!npmCliPath) { + throw new Error('npm_execpath is required to run the package preflight contract on Windows.'); + } + + return { + executable: process.execPath, + arguments: [npmCliPath, 'run', 'e2e:preflight'], + }; +} + +function getBaseURLResolver(): BaseURLResolver { + const resolver = Reflect.get(testHarness, 'resolveLocalE2EBaseURL'); + expect(typeof resolver).toBe('function'); + return resolver as BaseURLResolver; +} + +function getEnvironmentValidator(): EnvironmentValidator { + const validator = Reflect.get(testHarness, 'validateLocalE2EEnvironment'); + expect(typeof validator).toBe('function'); + return validator as EnvironmentValidator; +} + +test.describe('local E2E target guard', () => { + test('defaults to and normalizes the approved local origin', () => { + const resolveLocalE2EBaseURL = getBaseURLResolver(); + + expect(resolveLocalE2EBaseURL()).toBe('http://localhost:8788'); + expect(resolveLocalE2EBaseURL('http://localhost:8788/')).toBe('http://localhost:8788'); + }); + + test('rejects any target other than the exact local HTTP origin', () => { + const resolveLocalE2EBaseURL = getBaseURLResolver(); + const rejectedTargets = [ + 'https://ratemyplace.org', + 'https://localhost:8788', + 'http://127.0.0.1:8788', + 'http://localhost:8789', + 'http://localhost:8788/admin', + 'http://localhost:8788?unsafe=true', + 'not-a-url', + ]; + + for (const target of rejectedTargets) { + expect(() => resolveLocalE2EBaseURL(target)).toThrow(/local E2E target/i); + } + }); + + test('runs the safety preflight before any database setup', () => { + expect(packageJson.scripts?.e2e).toMatch( + /^npm run e2e:preflight && npm run db:setup &&/ + ); + expect(packageJson.scripts?.['e2e:headed']).toMatch( + /^npm run e2e:preflight && npm run db:setup &&/ + ); + }); + + test('rejects inherited flags that can target or bypass local database seeding', () => { + const validateLocalE2EEnvironment = getEnvironmentValidator(); + + expect(() => validateLocalE2EEnvironment({ D1_REMOTE: '1' })).toThrow(/D1_REMOTE/); + expect(() => + validateLocalE2EEnvironment({ SEED_REVIEWS_ONLY: '1' }) + ).toThrow(/SEED_REVIEWS_ONLY/); + }); + + test('package preflight entrypoint rejects unsafe database seed flags', () => { + const npmInvocation = getNpmInvocation(); + + for (const unsafeFlag of ['D1_REMOTE', 'SEED_REVIEWS_ONLY'] as const) { + const result = spawnSync(npmInvocation.executable, npmInvocation.arguments, { + cwd: projectRoot, + env: buildPreflightEnvironment(unsafeFlag), + encoding: 'utf8', + shell: false, + }); + const output = `${result.stdout ?? ''}\n${result.stderr ?? ''}`; + + expect(result.error).toBeUndefined(); + expect(result.status).not.toBe(0); + expect(output).toContain('[E2E safety]'); + expect(output).toContain(unsafeFlag); + } + }); +}); diff --git a/e2e/test-harness.ts b/e2e/test-harness.ts new file mode 100644 index 0000000..b2be9d9 --- /dev/null +++ b/e2e/test-harness.ts @@ -0,0 +1,170 @@ +import type { Page } from '@playwright/test'; +import { execFileSync } from 'node:child_process'; +import { mkdtempSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const E2E_DIR = path.dirname(fileURLToPath(import.meta.url)); +const PROJECT_ROOT = path.resolve(E2E_DIR, '..'); +const WRANGLER_ENTRY = path.join(PROJECT_ROOT, 'node_modules', 'wrangler', 'bin', 'wrangler.js'); +const WRANGLER_CONFIG = path.join(PROJECT_ROOT, 'wrangler.jsonc'); +const WRANGLER_PERSISTENCE = path.join(PROJECT_ROOT, '.wrangler', 'state'); + +const TURNSTILE_SCRIPT = /^https:\/\/challenges\.cloudflare\.com\/turnstile\/v0\/api\.js(?:\?.*)?$/; +export const TURNSTILE_TEST_TOKEN = 'XXXX.DUMMY.TOKEN.XXXX'; +const LOCAL_E2E_ORIGIN = 'http://localhost:8788'; + +export interface LocalE2EEnvironment { + BASE_URL?: string; + D1_REMOTE?: string; + SEED_REVIEWS_ONLY?: string; +} + +export function resolveLocalE2EBaseURL(configuredBaseURL = process.env.BASE_URL): string { + const candidate = configuredBaseURL ?? LOCAL_E2E_ORIGIN; + let parsed: URL; + + try { + parsed = new URL(candidate); + } catch { + throw new Error( + `[E2E safety] Invalid local E2E target. BASE_URL must be ${LOCAL_E2E_ORIGIN}.` + ); + } + + const isOriginOnly = + parsed.username === '' && + parsed.password === '' && + parsed.pathname === '/' && + parsed.search === '' && + parsed.hash === ''; + + if (parsed.origin !== LOCAL_E2E_ORIGIN || !isOriginOnly) { + throw new Error( + `[E2E safety] Refusing non-local E2E target ${parsed.origin}. BASE_URL must be ${LOCAL_E2E_ORIGIN}.` + ); + } + + return LOCAL_E2E_ORIGIN; +} + +export function validateLocalE2EEnvironment( + environment: LocalE2EEnvironment = process.env +): string { + const baseURL = resolveLocalE2EBaseURL(environment.BASE_URL); + const unsafeFlags = ['D1_REMOTE', 'SEED_REVIEWS_ONLY'] as const; + + for (const flag of unsafeFlags) { + if (environment[flag] !== undefined) { + throw new Error( + `[E2E safety] Refusing to run with ${flag} set. Unset it before running local E2E tests.` + ); + } + } + + return baseURL; +} + +// Cloudflare documents this token for automated tests. The matching public +// always-pass secret is bound only to the local Wrangler process in +// playwright.config.ts; production keeps its real widget and fail-closed path. +const TURNSTILE_STUB = ` +(() => { + const token = '${TURNSTILE_TEST_TOKEN}'; + + const addToken = (container) => { + if (!container || container.querySelector('input[name="cf-turnstile-response"]')) return; + const input = document.createElement('input'); + input.type = 'hidden'; + input.name = 'cf-turnstile-response'; + input.value = token; + container.appendChild(input); + }; + + const mountImplicitWidgets = () => { + document.querySelectorAll('.cf-turnstile').forEach(addToken); + }; + + let widgetSequence = 0; + window.turnstile = { + render(container, options = {}) { + const element = typeof container === 'string' + ? document.querySelector(container) + : container; + addToken(element); + queueMicrotask(() => options.callback?.(token)); + widgetSequence += 1; + return 'e2e-turnstile-' + widgetSequence; + }, + reset() {}, + remove() {}, + }; + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', mountImplicitWidgets, { once: true }); + } else { + mountImplicitWidgets(); + } +})(); +`; + +export async function installTurnstileStub(page: Page): Promise { + await page.route(TURNSTILE_SCRIPT, async (route) => { + await route.fulfill({ + status: 200, + contentType: 'application/javascript', + body: TURNSTILE_STUB, + }); + }); +} + +export function executeLocalD1(sql: string): string { + const isolatedCwd = mkdtempSync(path.join(tmpdir(), 'ratemyplace-e2e-wrangler-')); + + try { + return execFileSync( + process.execPath, + [ + WRANGLER_ENTRY, + 'd1', + 'execute', + 'ratemyplace-db', + '--local', + '--config', + WRANGLER_CONFIG, + '--persist-to', + WRANGLER_PERSISTENCE, + '--command', + sql, + '--json', + ], + { + cwd: isolatedCwd, + timeout: 30_000, + encoding: 'utf8', + } + ); + } finally { + rmSync(isolatedCwd, { recursive: true, force: true }); + } +} + +function quoteShellArgument(value: string): string { + return `"${value.replaceAll('"', '\\"')}"`; +} + +export function buildLocalPagesCommand(): string { + return [ + quoteShellArgument(process.execPath), + quoteShellArgument(WRANGLER_ENTRY), + 'pages', + 'dev', + quoteShellArgument(path.join(PROJECT_ROOT, 'dist')), + '--port', + '8788', + '--persist-to', + quoteShellArgument(WRANGLER_PERSISTENCE), + '--binding=TURNSTILE_SECRET_KEY=1x0000000000000000000000000000000AA', + ].join(' '); +} diff --git a/package-lock.json b/package-lock.json index e225a24..bbb9723 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,55 +8,57 @@ "name": "ratemyplace", "version": "0.0.1", "dependencies": { - "@astrojs/check": "^0.9.6", "@astrojs/cloudflare": "^12.6.12", "@astrojs/react": "3.6.3", "@lucia-auth/adapter-sqlite": "^3.0.2", "@oslojs/crypto": "^1.0.1", "@oslojs/encoding": "^1.1.0", - "@tailwindcss/vite": "^4.1.18", - "@types/react": "^18.3.0", - "@types/react-dom": "^18.3.0", - "astro": "^5.16.11", + "astro": "^5.18.2", "lucia": "^3.2.2", "react": "^18.3.1", "react-dom": "^18.3.1", - "resend": "^6.9.2", - "tailwindcss": "^4.1.18", - "typescript": "^5.9.3" + "resend": "^6.25.0" }, "devDependencies": { + "@astrojs/check": "^0.9.10", "@cloudflare/workers-types": "^4.20260117.0", "@playwright/test": "^1.58.2", + "@tailwindcss/vite": "^4.1.18", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", - "happy-dom": "^20.5.1", + "@types/react": "^18.3.0", + "@types/react-dom": "^18.3.0", + "happy-dom": "^20.11.13", + "tailwindcss": "^4.1.18", "tsx": "^4.21.0", - "vitest": "^4.0.18" + "typescript": "^5.9.3", + "vitest": "^4.1.11" } }, "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.10", + "resolved": "https://registry.npmjs.org/@astrojs/check/-/check-0.9.10.tgz", + "integrity": "sha512-zgx/UQMozdjOa3bOxjgeCFdtpE3c9rRX6xHwa+2QXvy8z8Akifu2AtubHyv/zzC2znO8dl8fFWL4K+Ba9kS8HQ==", + "dev": true, "license": "MIT", "dependencies": { - "@astrojs/language-server": "^2.16.1", - "chokidar": "^4.0.1", + "@astrojs/language-server": "^2.16.7", + "chokidar": "^4.0.3", "kleur": "^4.1.5", - "yargs": "^17.7.2" + "yargs": "^18.0.0" }, "bin": { "astro-check": "bin/astro-check.js" }, "peerDependencies": { - "typescript": "^5.0.0" + "typescript": "^5.0.0 || ^6.0.0" } }, "node_modules/@astrojs/check/node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, "license": "MIT", "dependencies": { "readdirp": "^4.0.1" @@ -72,6 +74,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -81,6 +84,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 14.18.0" @@ -107,12 +111,6 @@ "astro": "^5.7.0" } }, - "node_modules/@astrojs/cloudflare/node_modules/@astrojs/internal-helpers": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.7.6.tgz", - "integrity": "sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q==", - "license": "MIT" - }, "node_modules/@astrojs/compiler": { "version": "2.13.1", "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.13.1.tgz", @@ -120,31 +118,34 @@ "license": "MIT" }, "node_modules/@astrojs/internal-helpers": { - "version": "0.7.5", + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.7.6.tgz", + "integrity": "sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q==", "license": "MIT" }, "node_modules/@astrojs/language-server": { - "version": "2.16.6", - "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-2.16.6.tgz", - "integrity": "sha512-N990lu+HSFiG57owR0XBkr02BYMgiLCshLf+4QG4v6jjSWkBeQGnzqi+E1L08xFPPJ7eEeXnxPXGLaVv5pa4Ug==", + "version": "2.16.15", + "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-2.16.15.tgz", + "integrity": "sha512-hy7nMT1YGDAaRi9Q/SgywovZ8ThBgaRniMUaIT2/lBkFlJyolLjVxDGkhn3qT+zFUQ7GC/yrEBjsb7Xnj+yeaA==", + "dev": true, "license": "MIT", "dependencies": { "@astrojs/compiler": "^2.13.1", - "@astrojs/yaml2ts": "^0.2.3", + "@astrojs/yaml2ts": "^0.2.4", "@jridgewell/sourcemap-codec": "^1.5.5", "@volar/kit": "~2.4.28", "@volar/language-core": "~2.4.28", "@volar/language-server": "~2.4.28", "@volar/language-service": "~2.4.28", "muggle-string": "^0.4.1", - "tinyglobby": "^0.2.15", - "volar-service-css": "0.0.70", - "volar-service-emmet": "0.0.70", - "volar-service-html": "0.0.70", - "volar-service-prettier": "0.0.70", - "volar-service-typescript": "0.0.70", - "volar-service-typescript-twoslash-queries": "0.0.70", - "volar-service-yaml": "0.0.70", + "tinyglobby": "^0.2.16", + "volar-service-css": "0.0.71", + "volar-service-emmet": "0.0.71", + "volar-service-html": "0.0.71", + "volar-service-prettier": "0.0.71", + "volar-service-typescript": "0.0.71", + "volar-service-typescript-twoslash-queries": "0.0.71", + "volar-service-yaml": "0.0.71", "vscode-html-languageservice": "^5.6.2", "vscode-uri": "^3.1.0" }, @@ -165,10 +166,12 @@ } }, "node_modules/@astrojs/markdown-remark": { - "version": "6.3.10", + "version": "6.3.11", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.3.11.tgz", + "integrity": "sha512-hcaxX/5aC6lQgHeGh1i+aauvSwIT6cfyFjKWvExYSxUhZZBBdvCliOtu06gbQyhbe0pGJNoNmqNlQZ5zYUuIyQ==", "license": "MIT", "dependencies": { - "@astrojs/internal-helpers": "0.7.5", + "@astrojs/internal-helpers": "0.7.6", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", @@ -182,8 +185,8 @@ "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": "^3.21.0", + "smol-toml": "^1.6.0", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", @@ -193,6 +196,8 @@ }, "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==", "license": "MIT", "dependencies": { "prismjs": "^1.30.0" @@ -707,19 +712,22 @@ "license": "MIT" }, "node_modules/@astrojs/yaml2ts": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@astrojs/yaml2ts/-/yaml2ts-0.2.3.tgz", - "integrity": "sha512-PJzRmgQzUxI2uwpdX2lXSHtP4G8ocp24/t+bZyf5Fy0SZLSF9f9KXZoMlFM/XCGue+B0nH/2IZ7FpBYQATBsCg==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@astrojs/yaml2ts/-/yaml2ts-0.2.4.tgz", + "integrity": "sha512-8oddpOae35pJsXPQXhTkM0ypfKPskVsh2bCxRtbf7e+/Epw2nReakFYpLKjZMEr75CsoF203PMnCocpfz0s69A==", + "dev": true, "license": "MIT", "dependencies": { - "yaml": "^2.8.2" + "yaml": "^2.8.3" } }, "node_modules/@babel/code-frame": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -728,26 +736,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "license": "MIT", "peer": true, "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -771,11 +783,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.6", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -786,6 +800,8 @@ }, "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -793,11 +809,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -808,6 +826,8 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -815,36 +835,44 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -861,42 +889,52 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "license": "MIT", "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.6", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", "license": "MIT", "dependencies": { - "@babel/types": "^7.28.6" + "@babel/types": "^7.29.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -942,27 +980,31 @@ } }, "node_modules/@babel/template": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.28.6", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.6", - "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", "debug": "^4.3.1" }, "engines": { @@ -970,11 +1012,13 @@ } }, "node_modules/@babel/types": { - "version": "7.28.6", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1115,6 +1159,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.3.3.tgz", "integrity": "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==", + "dev": true, "license": "MIT", "dependencies": { "@emmetio/scanner": "^1.0.4" @@ -1124,6 +1169,7 @@ "version": "2.1.8", "resolved": "https://registry.npmjs.org/@emmetio/css-abbreviation/-/css-abbreviation-2.1.8.tgz", "integrity": "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==", + "dev": true, "license": "MIT", "dependencies": { "@emmetio/scanner": "^1.0.4" @@ -1133,6 +1179,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/@emmetio/css-parser/-/css-parser-0.4.1.tgz", "integrity": "sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ==", + "dev": true, "license": "MIT", "dependencies": { "@emmetio/stream-reader": "^2.2.0", @@ -1143,6 +1190,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/@emmetio/html-matcher/-/html-matcher-1.3.0.tgz", "integrity": "sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==", + "dev": true, "license": "ISC", "dependencies": { "@emmetio/scanner": "^1.0.0" @@ -1152,18 +1200,21 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/@emmetio/scanner/-/scanner-1.0.4.tgz", "integrity": "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==", + "dev": true, "license": "MIT" }, "node_modules/@emmetio/stream-reader": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@emmetio/stream-reader/-/stream-reader-2.2.0.tgz", "integrity": "sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==", + "dev": true, "license": "MIT" }, "node_modules/@emmetio/stream-reader-utils": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@emmetio/stream-reader-utils/-/stream-reader-utils-0.1.0.tgz", "integrity": "sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==", + "dev": true, "license": "MIT" }, "node_modules/@emnapi/runtime": { @@ -2547,48 +2598,60 @@ ] }, "node_modules/@shikijs/core": { - "version": "3.21.0", + "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.21.0", + "@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/@shikijs/engine-javascript": { - "version": "3.21.0", + "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.21.0", + "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "node_modules/@shikijs/engine-oniguruma": { - "version": "3.21.0", + "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.21.0", + "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "node_modules/@shikijs/langs": { - "version": "3.21.0", + "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.21.0" + "@shikijs/types": "3.23.0" } }, "node_modules/@shikijs/themes": { - "version": "3.21.0", + "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.21.0" + "@shikijs/types": "3.23.0" } }, "node_modules/@shikijs/types": { - "version": "3.21.0", + "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", @@ -2597,6 +2660,8 @@ }, "node_modules/@shikijs/vscode-textmate": { "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", "license": "MIT" }, "node_modules/@sindresorhus/is": { @@ -2632,6 +2697,7 @@ }, "node_modules/@tailwindcss/node": { "version": "4.1.18", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.4", @@ -2645,6 +2711,7 @@ }, "node_modules/@tailwindcss/oxide": { "version": "4.1.18", + "dev": true, "license": "MIT", "engines": { "node": ">= 10" @@ -2671,6 +2738,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2687,6 +2755,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2703,6 +2772,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2719,6 +2789,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2735,6 +2806,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2751,6 +2823,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2767,6 +2840,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2783,6 +2857,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2799,6 +2874,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2823,6 +2899,7 @@ "cpu": [ "wasm32" ], + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -2837,6 +2914,66 @@ "node": ">=14.0.0" } }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.7.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.7.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.1", + "dev": true, + "inBundle": true, + "license": "0BSD", + "optional": true + }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { "version": "4.1.18", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz", @@ -2844,6 +2981,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2858,6 +2996,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2869,6 +3008,7 @@ }, "node_modules/@tailwindcss/vite": { "version": "4.1.18", + "dev": true, "license": "MIT", "dependencies": { "@tailwindcss/node": "4.1.18", @@ -3004,7 +3144,9 @@ } }, "node_modules/@types/debug": { - "version": "4.1.12", + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", "license": "MIT", "dependencies": { "@types/ms": "*" @@ -3037,10 +3179,14 @@ }, "node_modules/@types/ms": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "license": "MIT" }, "node_modules/@types/nlcst": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", "license": "MIT", "dependencies": { "@types/unist": "*" @@ -3128,31 +3274,31 @@ } }, "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.11", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", "dev": true, "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", - "tinyrainbow": "^3.0.3" + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "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.11", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.0.18", + "@vitest/spy": "4.1.11", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -3161,7 +3307,7 @@ }, "peerDependencies": { "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0-0" + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "msw": { @@ -3173,26 +3319,26 @@ } }, "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.11", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", "dev": true, "license": "MIT", "dependencies": { - "tinyrainbow": "^3.0.3" + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "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.11", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.0.18", + "@vitest/utils": "4.1.11", "pathe": "^2.0.3" }, "funding": { @@ -3200,13 +3346,14 @@ } }, "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.11", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.18", + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -3215,9 +3362,9 @@ } }, "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.11", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", "dev": true, "license": "MIT", "funding": { @@ -3225,14 +3372,15 @@ } }, "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.11", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.18", - "tinyrainbow": "^3.0.3" + "@vitest/pretty-format": "4.1.11", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" @@ -3242,6 +3390,7 @@ "version": "2.4.28", "resolved": "https://registry.npmjs.org/@volar/kit/-/kit-2.4.28.tgz", "integrity": "sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg==", + "dev": true, "license": "MIT", "dependencies": { "@volar/language-service": "2.4.28", @@ -3258,6 +3407,7 @@ "version": "2.4.28", "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", + "dev": true, "license": "MIT", "dependencies": { "@volar/source-map": "2.4.28" @@ -3267,6 +3417,7 @@ "version": "2.4.28", "resolved": "https://registry.npmjs.org/@volar/language-server/-/language-server-2.4.28.tgz", "integrity": "sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw==", + "dev": true, "license": "MIT", "dependencies": { "@volar/language-core": "2.4.28", @@ -3284,6 +3435,7 @@ "version": "2.4.28", "resolved": "https://registry.npmjs.org/@volar/language-service/-/language-service-2.4.28.tgz", "integrity": "sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw==", + "dev": true, "license": "MIT", "dependencies": { "@volar/language-core": "2.4.28", @@ -3296,12 +3448,14 @@ "version": "2.4.28", "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", + "dev": true, "license": "MIT" }, "node_modules/@volar/typescript": { "version": "2.4.28", "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", + "dev": true, "license": "MIT", "dependencies": { "@volar/language-core": "2.4.28", @@ -3313,6 +3467,7 @@ "version": "2.11.0", "resolved": "https://registry.npmjs.org/@vscode/emmet-helper/-/emmet-helper-2.11.0.tgz", "integrity": "sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw==", + "dev": true, "license": "MIT", "dependencies": { "emmet": "^2.4.3", @@ -3326,6 +3481,7 @@ "version": "0.0.18", "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.18.tgz", "integrity": "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==", + "dev": true, "license": "MIT" }, "node_modules/acorn": { @@ -3339,9 +3495,10 @@ } }, "node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -3359,6 +3516,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "dev": true, "license": "MIT", "peerDependencies": { "ajv": "^8.5.0" @@ -3369,6 +3527,16 @@ } } }, + "node_modules/ajv-i18n": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ajv-i18n/-/ajv-i18n-4.2.0.tgz", + "integrity": "sha512-v/ei2UkCEeuKNXh8RToiFsUclmU+G57LO1Oo22OagNMENIw+Yb8eMwvHu7Vn9fmkjJyv6XclhJ8TbuigSglPkg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^8.0.0-beta.0" + } + }, "node_modules/ansi-align": { "version": "3.0.1", "license": "ISC", @@ -3441,7 +3609,9 @@ } }, "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -3452,6 +3622,8 @@ }, "node_modules/argparse": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "license": "Python-2.0" }, "node_modules/aria-query": { @@ -3463,6 +3635,8 @@ }, "node_modules/array-iterate": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", + "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", "license": "MIT", "funding": { "type": "github", @@ -3480,13 +3654,15 @@ } }, "node_modules/astro": { - "version": "5.16.11", + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/astro/-/astro-5.18.2.tgz", + "integrity": "sha512-TnFwLnAXty5MXKPDGuKXqK4AMBXG+FH6RUdK7Oyc3gyfNoFIthT+4eRbzOK43bdRlLaZuxgciDSjgtggZ3OtGQ==", "license": "MIT", "peer": true, "dependencies": { "@astrojs/compiler": "^2.13.0", - "@astrojs/internal-helpers": "0.7.5", - "@astrojs/markdown-remark": "6.3.10", + "@astrojs/internal-helpers": "0.7.6", + "@astrojs/markdown-remark": "6.3.11", "@astrojs/telemetry": "3.3.0", "@capsizecss/unpack": "^4.0.0", "@oslojs/encoding": "^1.1.0", @@ -3507,7 +3683,7 @@ "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.7.0", - "esbuild": "^0.25.0", + "esbuild": "^0.27.3", "estree-walker": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.4.0", @@ -3528,16 +3704,16 @@ "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.3", - "shiki": "^3.20.0", + "shiki": "^3.21.0", "smol-toml": "^1.6.0", "svgo": "^4.0.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", - "unifont": "~0.7.1", + "unifont": "~0.7.3", "unist-util-visit": "^5.0.0", - "unstorage": "^1.17.3", + "unstorage": "^1.17.4", "vfile": "^6.0.3", "vite": "^6.4.1", "vitefu": "^1.1.1", @@ -3564,6 +3740,463 @@ "sharp": "^0.34.0" } }, + "node_modules/astro/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, "node_modules/axobject-query": { "version": "4.1.0", "license": "Apache-2.0", @@ -3584,10 +4217,15 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.9.15", + "version": "2.11.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz", + "integrity": "sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==", "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/blake3-wasm": { @@ -3598,6 +4236,8 @@ }, "node_modules/boolbase": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "license": "ISC" }, "node_modules/boxen": { @@ -3621,7 +4261,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.1", + "version": "4.28.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", + "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", "funding": [ { "type": "opencollective", @@ -3639,17 +4281,30 @@ "license": "MIT", "peer": true, "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" + "baseline-browser-mapping": "^2.11.12", + "caniuse-lite": "^1.0.30001809", + "electron-to-chromium": "^1.5.402", + "node-releases": "^2.0.53", + "update-browserslist-db": "^1.3.0" }, "bin": { "browserslist": "cli.js" }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-image-size": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/buffer-image-size/-/buffer-image-size-0.6.4.tgz", + "integrity": "sha512-nEh+kZOPY1w+gcCMobZ6ETUp9WfibndnosbpwB1iJk/8Gt5ZF2bhS6+B6bPYz424KtwsR6Rflc3tCz1/ghX2dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + }, + "engines": { + "node": ">=4.0" } }, "node_modules/camelcase": { @@ -3663,7 +4318,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001764", + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", "funding": [ { "type": "opencollective", @@ -3710,6 +4367,8 @@ }, "node_modules/character-entities": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", "license": "MIT", "funding": { "type": "github", @@ -3769,90 +4428,18 @@ } }, "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, "license": "ISC", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=20" } }, "node_modules/clsx": { @@ -3862,20 +4449,6 @@ "node": ">=6" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "license": "MIT" - }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "license": "MIT", @@ -3922,14 +4495,16 @@ } }, "node_modules/css-select": { - "version": "5.2.2", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz", + "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==", "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" + "css-what": "^7.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "nth-check": "^2.1.1" }, "funding": { "url": "https://github.com/sponsors/fb55" @@ -3947,7 +4522,9 @@ } }, "node_modules/css-what": { - "version": "6.2.2", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", + "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", "license": "BSD-2-Clause", "engines": { "node": ">= 6" @@ -4013,7 +4590,9 @@ } }, "node_modules/decode-named-character-reference": { - "version": "1.2.0", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", "license": "MIT", "dependencies": { "character-entities": "^2.0.0" @@ -4024,7 +4603,9 @@ } }, "node_modules/defu": { - "version": "6.1.4", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", "license": "MIT" }, "node_modules/dequal": { @@ -4056,9 +4637,9 @@ } }, "node_modules/devalue": { - "version": "5.6.4", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.4.tgz", - "integrity": "sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==", + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.9.2.tgz", + "integrity": "sha512-po4PAY5c53tw5XMocSnf8A/5OHhbbUftpr93aEN6BBoAdntUmK7vu7wOATqvt7cXO7m1Cl4gMVn6p7n6n4mj0w==", "license": "MIT" }, "node_modules/devlop": { @@ -4092,6 +4673,8 @@ }, "node_modules/dom-serializer": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", @@ -4104,6 +4687,8 @@ }, "node_modules/dom-serializer/node_modules/entities": { "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -4114,6 +4699,8 @@ }, "node_modules/domelementtype": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "funding": [ { "type": "github", @@ -4124,6 +4711,8 @@ }, "node_modules/domhandler": { "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" @@ -4137,6 +4726,8 @@ }, "node_modules/domutils": { "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", @@ -4155,13 +4746,16 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.267", + "version": "1.5.416", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.416.tgz", + "integrity": "sha512-K6bvB2BjnNrugtIih6ewlbBI9DXa976jIdiIlRLHhBoEI9a4JaQjjHyF+A1IQI543aQYR4LnmOrT/K5fZj0aPA==", "license": "ISC" }, "node_modules/emmet": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/emmet/-/emmet-2.4.11.tgz", "integrity": "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==", + "dev": true, "license": "MIT", "workspaces": [ "./packages/scanner", @@ -4180,6 +4774,7 @@ }, "node_modules/enhanced-resolve": { "version": "5.18.4", + "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -4260,6 +4855,8 @@ }, "node_modules/escape-string-regexp": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "license": "MIT", "engines": { "node": ">=12" @@ -4297,6 +4894,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, "license": "MIT" }, "node_modules/fast-sha256": { @@ -4306,9 +4904,10 @@ "license": "Unlicense" }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.6.tgz", + "integrity": "sha512-7Ical1vFEMr0onbVzEDIreM22I4khW+fzyQPwvAFWBp1iwdshSZRsL4jjRvPG9JP1uiqMHRto+YU6R2/CzDz5Q==", + "dev": true, "funding": [ { "type": "github", @@ -4385,13 +4984,16 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-east-asian-width": { - "version": "1.4.0", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", "license": "MIT", "engines": { "node": ">=18" @@ -4415,10 +5017,13 @@ }, "node_modules/github-slugger": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", "license": "ISC" }, "node_modules/graceful-fs": { "version": "4.2.11", + "dev": true, "license": "ISC" }, "node_modules/h3": { @@ -4439,27 +5044,28 @@ } }, "node_modules/happy-dom": { - "version": "20.5.1", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.5.1.tgz", - "integrity": "sha512-G/O6YsGjzNZVJtW3z5vzVtxgPVDuos8ZFlYz40Zz6F3p8a2jfPCMTFaRKTz9ltMHlZ2asEGKX97DwFEC+NkCFg==", + "version": "20.12.0", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.12.0.tgz", + "integrity": "sha512-7uMYJu2SEwwL8vVcKp0C0lnt6d2LSGGe+T+oY79PiCJNNSgFpbxW8n5KuzpDQvrU4mt+fYiK1+Jy7Z2v39YR6g==", "dev": true, "license": "MIT", "dependencies": { "@types/node": ">=20.0.0", "@types/whatwg-mimetype": "^3.0.2", "@types/ws": "^8.18.1", - "entities": "^4.5.0", + "buffer-image-size": "^0.6.4", + "entities": "^7.0.1", "whatwg-mimetype": "^3.0.0", - "ws": "^8.18.3" + "ws": "^8.21.0" }, "engines": { "node": ">=20.0.0" } }, "node_modules/happy-dom/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -4470,9 +5076,9 @@ } }, "node_modules/happy-dom/node_modules/ws": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", "dev": true, "license": "MIT", "engines": { @@ -4527,6 +5133,8 @@ }, "node_modules/hast-util-is-element": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" @@ -4549,6 +5157,8 @@ }, "node_modules/hast-util-raw": { "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -4593,6 +5203,8 @@ }, "node_modules/hast-util-to-parse5": { "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz", + "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -4610,6 +5222,8 @@ }, "node_modules/hast-util-to-text": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -4666,6 +5280,8 @@ }, "node_modules/import-meta-resolve": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", "license": "MIT", "funding": { "type": "github", @@ -4740,6 +5356,7 @@ }, "node_modules/jiti": { "version": "2.6.1", + "devOptional": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -4750,7 +5367,19 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.1", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -4761,6 +5390,8 @@ }, "node_modules/jsesc": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -4773,6 +5404,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, "license": "MIT" }, "node_modules/json5": { @@ -4789,6 +5421,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.1.tgz", "integrity": "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==", + "dev": true, "license": "MIT" }, "node_modules/kleur": { @@ -4800,6 +5433,7 @@ }, "node_modules/lightningcss": { "version": "1.30.2", + "devOptional": true, "license": "MPL-2.0", "peer": true, "dependencies": { @@ -5046,6 +5680,8 @@ }, "node_modules/longest-streak": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", "license": "MIT", "funding": { "type": "github", @@ -5108,6 +5744,8 @@ }, "node_modules/markdown-table": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", "license": "MIT", "funding": { "type": "github", @@ -5116,6 +5754,8 @@ }, "node_modules/mdast-util-definitions": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz", + "integrity": "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -5129,6 +5769,8 @@ }, "node_modules/mdast-util-find-and-replace": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -5142,7 +5784,9 @@ } }, "node_modules/mdast-util-from-markdown": { - "version": "2.0.2", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -5165,6 +5809,8 @@ }, "node_modules/mdast-util-gfm": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", "license": "MIT", "dependencies": { "mdast-util-from-markdown": "^2.0.0", @@ -5182,6 +5828,8 @@ }, "node_modules/mdast-util-gfm-autolink-literal": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -5197,6 +5845,8 @@ }, "node_modules/mdast-util-gfm-footnote": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -5212,6 +5862,8 @@ }, "node_modules/mdast-util-gfm-strikethrough": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -5225,6 +5877,8 @@ }, "node_modules/mdast-util-gfm-table": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -5240,6 +5894,8 @@ }, "node_modules/mdast-util-gfm-task-list-item": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -5254,6 +5910,8 @@ }, "node_modules/mdast-util-phrasing": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -5285,6 +5943,8 @@ }, "node_modules/mdast-util-to-markdown": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -5304,6 +5964,8 @@ }, "node_modules/mdast-util-to-string": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0" @@ -5319,6 +5981,8 @@ }, "node_modules/micromark": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", "funding": [ { "type": "GitHub Sponsors", @@ -5352,6 +6016,8 @@ }, "node_modules/micromark-core-commonmark": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", "funding": [ { "type": "GitHub Sponsors", @@ -5384,6 +6050,8 @@ }, "node_modules/micromark-extension-gfm": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", "license": "MIT", "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", @@ -5402,6 +6070,8 @@ }, "node_modules/micromark-extension-gfm-autolink-literal": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", @@ -5416,6 +6086,8 @@ }, "node_modules/micromark-extension-gfm-footnote": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -5434,6 +6106,8 @@ }, "node_modules/micromark-extension-gfm-strikethrough": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -5450,6 +6124,8 @@ }, "node_modules/micromark-extension-gfm-table": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -5465,6 +6141,8 @@ }, "node_modules/micromark-extension-gfm-tagfilter": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", "license": "MIT", "dependencies": { "micromark-util-types": "^2.0.0" @@ -5476,6 +6154,8 @@ }, "node_modules/micromark-extension-gfm-task-list-item": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -5491,6 +6171,8 @@ }, "node_modules/micromark-factory-destination": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", "funding": [ { "type": "GitHub Sponsors", @@ -5510,6 +6192,8 @@ }, "node_modules/micromark-factory-label": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", "funding": [ { "type": "GitHub Sponsors", @@ -5530,6 +6214,8 @@ }, "node_modules/micromark-factory-space": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { "type": "GitHub Sponsors", @@ -5548,6 +6234,8 @@ }, "node_modules/micromark-factory-title": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", "funding": [ { "type": "GitHub Sponsors", @@ -5568,6 +6256,8 @@ }, "node_modules/micromark-factory-whitespace": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", "funding": [ { "type": "GitHub Sponsors", @@ -5606,6 +6296,8 @@ }, "node_modules/micromark-util-chunked": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", "funding": [ { "type": "GitHub Sponsors", @@ -5623,6 +6315,8 @@ }, "node_modules/micromark-util-classify-character": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", "funding": [ { "type": "GitHub Sponsors", @@ -5642,6 +6336,8 @@ }, "node_modules/micromark-util-combine-extensions": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", "funding": [ { "type": "GitHub Sponsors", @@ -5660,6 +6356,8 @@ }, "node_modules/micromark-util-decode-numeric-character-reference": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", "funding": [ { "type": "GitHub Sponsors", @@ -5677,6 +6375,8 @@ }, "node_modules/micromark-util-decode-string": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", "funding": [ { "type": "GitHub Sponsors", @@ -5711,6 +6411,8 @@ }, "node_modules/micromark-util-html-tag-name": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", "funding": [ { "type": "GitHub Sponsors", @@ -5725,6 +6427,8 @@ }, "node_modules/micromark-util-normalize-identifier": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", "funding": [ { "type": "GitHub Sponsors", @@ -5742,6 +6446,8 @@ }, "node_modules/micromark-util-resolve-all": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", "funding": [ { "type": "GitHub Sponsors", @@ -5778,6 +6484,8 @@ }, "node_modules/micromark-util-subtokenize": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", "funding": [ { "type": "GitHub Sponsors", @@ -5860,10 +6568,13 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.11", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "funding": [ { "type": "github", @@ -5887,6 +6598,8 @@ }, "node_modules/nlcst-to-string": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", "license": "MIT", "dependencies": { "@types/nlcst": "^2.0.0" @@ -5905,8 +6618,13 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.27", - "license": "MIT" + "version": "2.0.54", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", + "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/normalize-path": { "version": "3.0.0", @@ -5917,6 +6635,8 @@ }, "node_modules/nth-check": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" @@ -5950,15 +6670,19 @@ "license": "MIT" }, "node_modules/oniguruma-parser": { - "version": "0.12.1", + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", + "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", "license": "MIT" }, "node_modules/oniguruma-to-es": { - "version": "4.3.4", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", + "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", "license": "MIT", "dependencies": { - "oniguruma-parser": "^0.12.1", - "regex": "^6.0.1", + "oniguruma-parser": "^0.12.2", + "regex": "^6.1.0", "regex-recursion": "^6.0.2" } }, @@ -6005,6 +6729,8 @@ }, "node_modules/parse-latin": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", + "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", "license": "MIT", "dependencies": { "@types/nlcst": "^2.0.0", @@ -6033,6 +6759,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, "license": "MIT" }, "node_modules/path-to-regexp": { @@ -6054,7 +6781,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "license": "MIT", "engines": { "node": ">=12" @@ -6111,13 +6840,15 @@ } }, "node_modules/postal-mime": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/postal-mime/-/postal-mime-2.7.3.tgz", - "integrity": "sha512-MjhXadAJaWgYzevi46+3kLak8y6gbg0ku14O1gO/LNOuay8dO+1PtcSGvAdgDR0DoIsSaiIA8y/Ddw6MnrO0Tw==", + "version": "2.7.5", + "resolved": "https://registry.npmjs.org/postal-mime/-/postal-mime-2.7.5.tgz", + "integrity": "sha512-GNEXKvWFQnbgO5NlrGzVa0FmWzBZ24PersAWErttSg1Hjpf0ATxTwS5DOMGaOpTG6bUh5cTr7xi0jAD942wCJA==", "license": "MIT-0" }, "node_modules/postcss": { - "version": "8.5.6", + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", "funding": [ { "type": "opencollective", @@ -6134,7 +6865,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -6143,9 +6874,10 @@ } }, "node_modules/prettier": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", + "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", + "dev": true, "license": "MIT", "peer": true, "bin": { @@ -6198,6 +6930,8 @@ }, "node_modules/prismjs": { "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", "license": "MIT", "engines": { "node": ">=6" @@ -6280,6 +7014,8 @@ }, "node_modules/regex": { "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", "license": "MIT", "dependencies": { "regex-utilities": "^2.3.0" @@ -6287,6 +7023,8 @@ }, "node_modules/regex-recursion": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", "license": "MIT", "dependencies": { "regex-utilities": "^2.3.0" @@ -6294,6 +7032,8 @@ }, "node_modules/regex-utilities": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", "license": "MIT" }, "node_modules/rehype": { @@ -6325,6 +7065,8 @@ }, "node_modules/rehype-raw": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -6351,6 +7093,8 @@ }, "node_modules/remark-gfm": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -6367,6 +7111,8 @@ }, "node_modules/remark-parse": { "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -6381,6 +7127,8 @@ }, "node_modules/remark-rehype": { "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -6395,7 +7143,9 @@ } }, "node_modules/remark-smartypants": { - "version": "3.0.2", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.3.tgz", + "integrity": "sha512-gCaK+ndZ0hYezlqFegHFCVh2CQemsi0Npdh1qVM9bxlUFknjkbP6VmojWhddOCrbK0PbbacmYLWfTULRiT1eWA==", "license": "MIT", "dependencies": { "retext": "^9.0.0", @@ -6409,6 +7159,8 @@ }, "node_modules/remark-stringify": { "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -6424,34 +7176,27 @@ "version": "0.7.0", "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.7.0.tgz", "integrity": "sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==", + "dev": true, "license": "MIT" }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/resend": { - "version": "6.9.2", - "resolved": "https://registry.npmjs.org/resend/-/resend-6.9.2.tgz", - "integrity": "sha512-uIM6CQ08tS+hTCRuKBFbOBvHIGaEhqZe8s4FOgqsVXSbQLAhmNWpmUhG3UAtRnmcwTWFUqnHa/+Vux8YGPyDBA==", + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/resend/-/resend-6.25.0.tgz", + "integrity": "sha512-iptUEycs+6Hu+W8mExK708LrDiMYOuGgnCP+wTD5L4Zrqqd2B86h1oyAmNe0khZWQw0ccI7jz8OgAaplEsyaIA==", "license": "MIT", "dependencies": { - "postal-mime": "2.7.3", - "svix": "1.84.1" + "postal-mime": "2.7.5", + "standardwebhooks": "1.0.0" }, "engines": { "node": ">=20" @@ -6477,6 +7222,8 @@ }, "node_modules/retext": { "version": "9.0.0", + "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", + "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==", "license": "MIT", "dependencies": { "@types/nlcst": "^2.0.0", @@ -6491,6 +7238,8 @@ }, "node_modules/retext-latin": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz", + "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==", "license": "MIT", "dependencies": { "@types/nlcst": "^2.0.0", @@ -6504,6 +7253,8 @@ }, "node_modules/retext-smartypants": { "version": "6.2.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz", + "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", "license": "MIT", "dependencies": { "@types/nlcst": "^2.0.0", @@ -6517,6 +7268,8 @@ }, "node_modules/retext-stringify": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz", + "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==", "license": "MIT", "dependencies": { "@types/nlcst": "^2.0.0", @@ -6573,9 +7326,9 @@ } }, "node_modules/sax": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", - "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", "license": "BlueOak-1.0.0", "engines": { "node": ">=11.0.0" @@ -6643,15 +7396,17 @@ } }, "node_modules/shiki": { - "version": "3.21.0", + "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.21.0", - "@shikijs/engine-javascript": "3.21.0", - "@shikijs/engine-oniguruma": "3.21.0", - "@shikijs/langs": "3.21.0", - "@shikijs/themes": "3.21.0", - "@shikijs/types": "3.21.0", + "@shikijs/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" } @@ -6668,7 +7423,9 @@ "license": "MIT" }, "node_modules/smol-toml": { - "version": "1.6.0", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.8.0.tgz", + "integrity": "sha512-kCZr2V3ch9i00x8zXRhjUNVcjG9ijES5dDudkXvUVCT5QlJNQWElSJdZqyPemffHoLNUYwOcou0Fy+ojN0uHSQ==", "license": "BSD-3-Clause", "engines": { "node": ">= 18" @@ -6710,9 +7467,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.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", "dev": true, "license": "MIT" }, @@ -6769,18 +7526,18 @@ } }, "node_modules/svgo": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz", - "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.1.0.tgz", + "integrity": "sha512-bkxnTg1kSU0guhIBmibA6UUhrQmPVA1XsQLN+ylCd+UWzbnLkySOcXpyk1mrl05f+pcaCx2eHb+sp6BgMZWX+Q==", "license": "MIT", "dependencies": { "commander": "^11.1.0", - "css-select": "^5.1.0", + "css-select": "^6.0.0", "css-tree": "^3.0.1", - "css-what": "^6.1.0", + "css-what": "^7.0.0", "csso": "^5.0.5", "picocolors": "^1.1.1", - "sax": "^1.5.0" + "sax": "1.6.1" }, "bin": { "svgo": "bin/svgo.js" @@ -6793,22 +7550,14 @@ "url": "https://opencollective.com/svgo" } }, - "node_modules/svix": { - "version": "1.84.1", - "resolved": "https://registry.npmjs.org/svix/-/svix-1.84.1.tgz", - "integrity": "sha512-K8DPPSZaW/XqXiz1kEyzSHYgmGLnhB43nQCMeKjWGCUpLIpAMMM8kx3rVVOSm6Bo6EHyK1RQLPT4R06skM/MlQ==", - "license": "MIT", - "dependencies": { - "standardwebhooks": "1.0.0", - "uuid": "^10.0.0" - } - }, "node_modules/tailwindcss": { "version": "4.1.18", + "dev": true, "license": "MIT" }, "node_modules/tapable": { "version": "2.3.0", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -6837,11 +7586,13 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -6851,9 +7602,9 @@ } }, "node_modules/tinyrainbow": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", "dev": true, "license": "MIT", "engines": { @@ -7391,6 +8142,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/typesafe-path/-/typesafe-path-0.2.2.tgz", "integrity": "sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==", + "dev": true, "license": "MIT" }, "node_modules/typescript": { @@ -7411,6 +8163,7 @@ "version": "0.3.6", "resolved": "https://registry.npmjs.org/typescript-auto-import-cache/-/typescript-auto-import-cache-0.3.6.tgz", "integrity": "sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==", + "dev": true, "license": "MIT", "dependencies": { "semver": "^7.3.8" @@ -7482,6 +8235,8 @@ }, "node_modules/unist-util-find-after": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -7505,6 +8260,8 @@ }, "node_modules/unist-util-modify-children": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-4.0.0.tgz", + "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -7528,6 +8285,8 @@ }, "node_modules/unist-util-remove-position": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -7564,6 +8323,8 @@ }, "node_modules/unist-util-visit-children": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-3.0.0.tgz", + "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -7680,7 +8441,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.2.3", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", + "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", "funding": [ { "type": "opencollective", @@ -7707,19 +8470,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/vfile": { "version": "6.0.3", "license": "MIT", @@ -7757,7 +8507,9 @@ } }, "node_modules/vite": { - "version": "6.4.1", + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", + "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", "license": "MIT", "peer": true, "dependencies": { @@ -7847,31 +8599,31 @@ } }, "node_modules/vitest": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", - "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", "dev": true, "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", + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", + "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", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "bin": { @@ -7887,12 +8639,15 @@ "@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.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", "happy-dom": "*", - "jsdom": "*" + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@edge-runtime/vm": { @@ -7913,6 +8668,12 @@ "@vitest/browser-webdriverio": { "optional": true }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, "@vitest/ui": { "optional": true }, @@ -7921,13 +8682,24 @@ }, "jsdom": { "optional": true + }, + "vite": { + "optional": false } } }, + "node_modules/vitest/node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "dev": true, + "license": "MIT" + }, "node_modules/volar-service-css": { - "version": "0.0.70", - "resolved": "https://registry.npmjs.org/volar-service-css/-/volar-service-css-0.0.70.tgz", - "integrity": "sha512-K1qyOvBpE3rzdAv3e4/6Rv5yizrYPy5R/ne3IWCAzLBuMO4qBMV3kSqWzj6KUVe6S0AnN6wxF7cRkiaKfYMYJw==", + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-css/-/volar-service-css-0.0.71.tgz", + "integrity": "sha512-wRRFt9BpjMKCazcgOh67MSjUjiWUCAh99DyYSDIOTuxaRjEtDC7PpB0k1Y1wbJIW/pVtMUSVbpPo3UGSm0Byxw==", + "dev": true, "license": "MIT", "dependencies": { "vscode-css-languageservice": "^6.3.0", @@ -7944,9 +8716,10 @@ } }, "node_modules/volar-service-emmet": { - "version": "0.0.70", - "resolved": "https://registry.npmjs.org/volar-service-emmet/-/volar-service-emmet-0.0.70.tgz", - "integrity": "sha512-xi5bC4m/VyE3zy/n2CXspKeDZs3qA41tHLTw275/7dNWM/RqE2z3BnDICQybHIVp/6G1iOQj5c1qXMgQC08TNg==", + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-emmet/-/volar-service-emmet-0.0.71.tgz", + "integrity": "sha512-zqjzt6bN95e3CUstBm0PBFAJnrfz0ZAARka87fart46/gNCLLuP3Vujy8V/J8HEziTFLnfkgIASLFYPUhonJcA==", + "dev": true, "license": "MIT", "dependencies": { "@emmetio/css-parser": "^0.4.1", @@ -7964,9 +8737,10 @@ } }, "node_modules/volar-service-html": { - "version": "0.0.70", - "resolved": "https://registry.npmjs.org/volar-service-html/-/volar-service-html-0.0.70.tgz", - "integrity": "sha512-eR6vCgMdmYAo4n+gcT7DSyBQbwB8S3HZZvSagTf0sxNaD4WppMCFfpqWnkrlGStPKMZvMiejRRVmqsX9dYcTvQ==", + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-html/-/volar-service-html-0.0.71.tgz", + "integrity": "sha512-e8tHPhgQ7ooLfudAEIku+kgd9pWkq3SSz8RbnQDI1+Eb8wbenkLGHqoirLqz5ORLV6wIMr2Iv08RWBG5eOcgpw==", + "dev": true, "license": "MIT", "dependencies": { "vscode-html-languageservice": "^5.3.0", @@ -7983,9 +8757,10 @@ } }, "node_modules/volar-service-prettier": { - "version": "0.0.70", - "resolved": "https://registry.npmjs.org/volar-service-prettier/-/volar-service-prettier-0.0.70.tgz", - "integrity": "sha512-Z6BCFSpGVCd8BPAsZ785Kce1BGlWd5ODqmqZGVuB14MJvrR4+CYz6cDy4F+igmE1gMifqfvMhdgT8Aud4M5ngg==", + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-prettier/-/volar-service-prettier-0.0.71.tgz", + "integrity": "sha512-Rz7JVH3qD108UCdmIEiZvOBNljMt2nLFdbN8AXcDfn7xD9F5I2aCIsDVqBbXw21PsnxG0b7MfwtNF+zPS/NKUg==", + "dev": true, "license": "MIT", "dependencies": { "vscode-uri": "^3.0.8" @@ -8004,9 +8779,10 @@ } }, "node_modules/volar-service-typescript": { - "version": "0.0.70", - "resolved": "https://registry.npmjs.org/volar-service-typescript/-/volar-service-typescript-0.0.70.tgz", - "integrity": "sha512-l46Bx4cokkUedTd74ojO5H/zqHZJ8SUuyZ0IB8JN4jfRqUM3bQFBHoOwlZCyZmOeO0A3RQNkMnFclxO4c++gsg==", + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-typescript/-/volar-service-typescript-0.0.71.tgz", + "integrity": "sha512-yTtM/BVT6hoyEYnDtaCyAtNhdNeS/mhTTABlBOdw3NNiRBUin3IznFJpgfjer4c6RYopiPjjQjc9VFhxVl1mLw==", + "dev": true, "license": "MIT", "dependencies": { "path-browserify": "^1.0.1", @@ -8026,9 +8802,10 @@ } }, "node_modules/volar-service-typescript-twoslash-queries": { - "version": "0.0.70", - "resolved": "https://registry.npmjs.org/volar-service-typescript-twoslash-queries/-/volar-service-typescript-twoslash-queries-0.0.70.tgz", - "integrity": "sha512-IdD13Z9N2Bu8EM6CM0fDV1E69olEYGHDU25X51YXmq8Y0CmJ2LNj6gOiBJgpS5JGUqFzECVhMNBW7R0sPdRTMQ==", + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-typescript-twoslash-queries/-/volar-service-typescript-twoslash-queries-0.0.71.tgz", + "integrity": "sha512-9K2k72s4n7rV9s4bX0MyjbX9iBribvKZbBJKuEmTCZfeWJXs6Yh7bGpY4eoc7UufAjvpheBqwyZCOIPBvxCv0A==", + "dev": true, "license": "MIT", "dependencies": { "vscode-uri": "^3.0.8" @@ -8043,13 +8820,14 @@ } }, "node_modules/volar-service-yaml": { - "version": "0.0.70", - "resolved": "https://registry.npmjs.org/volar-service-yaml/-/volar-service-yaml-0.0.70.tgz", - "integrity": "sha512-0c8bXDBeoATF9F6iPIlOuYTuZAC4c+yi0siQo920u7eiBJk8oQmUmg9cDUbR4+Gl++bvGP4plj3fErbJuPqdcQ==", + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-yaml/-/volar-service-yaml-0.0.71.tgz", + "integrity": "sha512-qYGWGuVpUTnZGu5P/CR4KLK4aIR8RrcVnmfZ2eRcj9q/I8VZCoC5yy9FtEvfNvnDp4MU17yhdJcvpQPIqhJS2Q==", + "dev": true, "license": "MIT", "dependencies": { "vscode-uri": "^3.0.8", - "yaml-language-server": "~1.20.0" + "yaml-language-server": "~1.23.0" }, "peerDependencies": { "@volar/language-service": "~2.4.0" @@ -8064,6 +8842,7 @@ "version": "6.3.10", "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-6.3.10.tgz", "integrity": "sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA==", + "dev": true, "license": "MIT", "dependencies": { "@vscode/l10n": "^0.0.18", @@ -8072,10 +8851,18 @@ "vscode-uri": "^3.1.0" } }, + "node_modules/vscode-css-languageservice/node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "dev": true, + "license": "MIT" + }, "node_modules/vscode-html-languageservice": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-5.6.2.tgz", "integrity": "sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg==", + "dev": true, "license": "MIT", "dependencies": { "@vscode/l10n": "^0.0.18", @@ -8088,6 +8875,7 @@ "version": "4.1.8", "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.1.8.tgz", "integrity": "sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==", + "dev": true, "license": "MIT", "dependencies": { "jsonc-parser": "^3.0.0", @@ -8104,12 +8892,14 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, "license": "MIT" }, "node_modules/vscode-jsonrpc": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", - "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-9.0.2.tgz", + "integrity": "sha512-SbQSV9yRemARxeXw6LU5sS6Zq0e9/DgCCX5yelH263ZQWukbTk8EF8fjTrr1dziasf4GwlJbvTwFnTrnQFWZXQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" @@ -8119,6 +8909,7 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "dev": true, "license": "MIT", "dependencies": { "vscode-languageserver-protocol": "3.17.5" @@ -8128,37 +8919,70 @@ } }, "node_modules/vscode-languageserver-protocol": { + "version": "3.18.3", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.18.3.tgz", + "integrity": "sha512-DF49+WeV5py4zO5hhobp60jjsDSK0lAqA0OuKBLBvp423HPWQcCbhZz3JgyfIewsEz2f8U+X75xNIFHdiXZm2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "9.0.2", + "vscode-languageserver-types": "3.18.3" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.14.tgz", + "integrity": "sha512-EQyqJMi552E4ZTf46izQ4Fj6XquqxCySR3J5ZSD1SisMf6RfpeOWHxGBE8Gr6V0/3GHIGdAzDn8F8+1nTGCnoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.18.3", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.18.3.tgz", + "integrity": "sha512-XIlzJ7Qp/jzSI1ds7/FwPAWrPeTZA7pAtlW4hdJ1J6xXWJL6dR9QYnDhJOdLzdKhUQ5Mm6mvUMw+3DcOQQasPw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-languageserver/node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver/node_modules/vscode-languageserver-protocol": { "version": "3.17.5", "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "dev": true, "license": "MIT", "dependencies": { "vscode-jsonrpc": "8.2.0", "vscode-languageserver-types": "3.17.5" } }, - "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", - "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", - "license": "MIT" - }, - "node_modules/vscode-languageserver-types": { + "node_modules/vscode-languageserver/node_modules/vscode-languageserver-types": { "version": "3.17.5", "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "dev": true, "license": "MIT" }, "node_modules/vscode-nls": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==", + "dev": true, "license": "MIT" }, "node_modules/vscode-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", - "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.2.0.tgz", + "integrity": "sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg==", + "dev": true, "license": "MIT" }, "node_modules/web-namespaces": { @@ -8222,6 +9046,7 @@ "integrity": "sha512-kTJ+jNdIllOzWuVA3NRQRvywP0T135zdCjAE2dAUY1BFbxM6fmMZV8BbskEoQ4hAODVQUfZQmyGctcwvVCKxFA==", "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "bin": { "workerd": "bin/workerd" }, @@ -8771,6 +9596,7 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -8778,12 +9604,15 @@ }, "node_modules/yallist": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "devOptional": true, "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -8796,22 +9625,24 @@ } }, "node_modules/yaml-language-server": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/yaml-language-server/-/yaml-language-server-1.20.0.tgz", - "integrity": "sha512-qhjK/bzSRZ6HtTvgeFvjNPJGWdZ0+x5NREV/9XZWFjIGezew2b4r5JPy66IfOhd5OA7KeFwk1JfmEbnTvev0cA==", + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/yaml-language-server/-/yaml-language-server-1.23.0.tgz", + "integrity": "sha512-3qVyCOexLCWw06PQa5kRPwvMWMZ/eZeCRWUvgD6a0OkqL/4iCnxy2WumbWifa937Uo5xhyWJ0uxlU39ljhNh7A==", + "dev": true, "license": "MIT", "dependencies": { "@vscode/l10n": "^0.0.18", "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", - "prettier": "^3.5.0", + "ajv-i18n": "^4.2.0", + "prettier": "^3.8.1", "request-light": "^0.5.7", "vscode-json-languageservice": "4.1.8", "vscode-languageserver": "^9.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.16.0", "vscode-uri": "^3.0.2", - "yaml": "2.7.1" + "yaml": "2.8.3" }, "bin": { "yaml-language-server": "bin/yaml-language-server" @@ -8821,36 +9652,41 @@ "version": "0.5.8", "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.5.8.tgz", "integrity": "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==", + "dev": true, "license": "MIT" }, "node_modules/yaml-language-server/node_modules/yaml": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", - "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { - "node": ">= 14" + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.1.0.tgz", + "integrity": "sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg==", + "dev": true, "license": "MIT", "dependencies": { - "cliui": "^8.0.1", + "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", + "string-width": "^8.2.1", "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "yargs-parser": "^22.0.0" }, "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/yargs-parser": { @@ -8860,45 +9696,31 @@ "node": ">=12" } }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", + "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==", + "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" }, "engines": { - "node": ">=8" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "node_modules/yargs/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==", + "dev": true, + "license": "ISC", "engines": { - "node": ">=8" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/yocto-queue": { diff --git a/package.json b/package.json index 3f658a4..fa260fa 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,9 @@ "test": "vitest run", "test:watch": "vitest", "smoke": "npx tsx scripts/smoke-test.ts", - "e2e": "npm run db:setup && npm run build && npx playwright test", - "e2e:headed": "npm run db:setup && npm run build && npx playwright test --headed", + "e2e:preflight": "tsx e2e/preflight.ts", + "e2e": "npm run e2e:preflight && npm run db:setup && npm run build && npx playwright test", + "e2e:headed": "npm run e2e:preflight && npm run db:setup && npm run build && npx playwright test --headed", "db:reset": "npx tsx scripts/db-reset.ts", "db:migrate:local": "npx tsx scripts/db-migrate.ts", "db:fresh": "npx tsx scripts/db-fresh.ts", @@ -21,30 +22,30 @@ "ops:metrics": "tsx scripts/ops-metrics.ts" }, "dependencies": { - "@astrojs/check": "^0.9.6", "@astrojs/cloudflare": "^12.6.12", "@astrojs/react": "3.6.3", "@lucia-auth/adapter-sqlite": "^3.0.2", "@oslojs/crypto": "^1.0.1", "@oslojs/encoding": "^1.1.0", - "@tailwindcss/vite": "^4.1.18", - "@types/react": "^18.3.0", - "@types/react-dom": "^18.3.0", - "astro": "^5.16.11", + "astro": "^5.18.2", "lucia": "^3.2.2", "react": "^18.3.1", "react-dom": "^18.3.1", - "resend": "^6.9.2", - "tailwindcss": "^4.1.18", - "typescript": "^5.9.3" + "resend": "^6.25.0" }, "devDependencies": { + "@astrojs/check": "^0.9.10", "@cloudflare/workers-types": "^4.20260117.0", "@playwright/test": "^1.58.2", + "@tailwindcss/vite": "^4.1.18", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", - "happy-dom": "^20.5.1", + "@types/react": "^18.3.0", + "@types/react-dom": "^18.3.0", + "happy-dom": "^20.11.13", + "tailwindcss": "^4.1.18", "tsx": "^4.21.0", - "vitest": "^4.0.18" + "typescript": "^5.9.3", + "vitest": "^4.1.11" } } diff --git a/playwright.config.ts b/playwright.config.ts index 1641db0..128e184 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,4 +1,7 @@ import { defineConfig } from '@playwright/test'; +import { buildLocalPagesCommand, validateLocalE2EEnvironment } from './e2e/test-harness'; + +const baseURL = validateLocalE2EEnvironment(); export default defineConfig({ testDir: './e2e', @@ -6,15 +9,15 @@ export default defineConfig({ retries: 0, workers: 1, use: { - baseURL: process.env.BASE_URL || 'http://localhost:8788', + baseURL, screenshot: 'only-on-failure', trace: 'on-first-retry', }, webServer: { - command: 'npx wrangler pages dev ./dist --port 8788', - url: 'http://localhost:8788', + command: buildLocalPagesCommand(), + url: baseURL, timeout: 120_000, - reuseExistingServer: true, + reuseExistingServer: false, }, projects: [ { diff --git a/src/lib/__tests__/workflowContracts.test.ts b/src/lib/__tests__/workflowContracts.test.ts index 0d7a69f..a062509 100644 --- a/src/lib/__tests__/workflowContracts.test.ts +++ b/src/lib/__tests__/workflowContracts.test.ts @@ -4,6 +4,145 @@ import { describe, expect, it } from 'vitest'; const workflowPath = (...parts: string[]) => resolve(process.cwd(), '.github', 'workflows', ...parts); const readWorkflow = (name: string) => readFileSync(workflowPath(name), 'utf8').replace(/\r\n/g, '\n'); +const readRepositoryFile = (...parts: string[]) => readFileSync(resolve(process.cwd(), ...parts), 'utf8') + .replace(/\r\n/g, '\n'); + +const stripYamlComment = (line: string) => { + let quote: '"' | "'" | undefined; + + for (let index = 0; index < line.length; index++) { + const character = line[index]; + if (quote === '"' && character === '\\') { + index++; + continue; + } + if (quote === "'" && character === "'" && line[index + 1] === "'") { + index++; + continue; + } + if (character === '"' || character === "'") { + quote = quote === character ? undefined : quote ?? character; + continue; + } + if (character === '#' && quote === undefined) return line.slice(0, index); + } + + return line; +}; + +const yamlScalar = (value: string) => { + const normalized = stripYamlComment(value).trim(); + const quote = normalized[0]; + return (quote === '"' || quote === "'") && normalized.at(-1) === quote + ? normalized.slice(1, -1) + : normalized; +}; + +interface YamlMapping { + indent: number; + key: string; + value: string; +} + +const parseYamlMapping = (line: string): YamlMapping | undefined => { + const activeLine = stripYamlComment(line).replace(/\s+$/, ''); + if (!activeLine.trim()) return undefined; + + const indent = activeLine.match(/^ */)?.[0].length ?? 0; + const mapping = activeLine.slice(indent).replace(/^-\s+/, '').match(/^(?:"([^"]+)"|'([^']+)'|([^:#][^:]*?))\s*:\s*(.*)$/); + if (!mapping) return undefined; + + return { + indent, + key: (mapping[1] ?? mapping[2] ?? mapping[3]).trim(), + value: mapping[4], + }; +}; + +const getActiveYamlLines = (lines: string[]) => { + const activeLines: string[] = []; + let blockScalarIndent: number | undefined; + + for (const line of lines) { + const withoutComment = stripYamlComment(line).replace(/\s+$/, ''); + const indent = withoutComment.match(/^ */)?.[0].length ?? 0; + + if (blockScalarIndent !== undefined) { + if (!withoutComment.trim() || indent > blockScalarIndent) continue; + blockScalarIndent = undefined; + } + if (!withoutComment.trim()) continue; + + activeLines.push(withoutComment); + const mapping = parseYamlMapping(withoutComment); + if (mapping && /^(?:\||>)[+-]?$/.test(mapping.value.trim())) { + blockScalarIndent = mapping.indent; + } + } + + return activeLines; +}; + +const getYamlBlock = (lines: string[], key: string, indent: number) => { + const activeLines = getActiveYamlLines(lines); + const start = activeLines.findIndex((line) => { + const mapping = parseYamlMapping(line); + return mapping?.indent === indent && mapping.key === key && mapping.value === ''; + }); + expect(start).toBeGreaterThanOrEqual(0); + + const block: string[] = []; + for (let index = start + 1; index < activeLines.length; index++) { + const line = activeLines[index]; + const lineIndent = line.match(/^ */)?.[0].length ?? 0; + if (lineIndent <= indent) break; + block.push(line); + } + return block; +}; + +const getYamlScalar = (lines: string[], key: string, indent: number) => { + const mapping = getActiveYamlLines(lines) + .map(parseYamlMapping) + .find((candidate) => candidate?.indent === indent && candidate.key === key); + return mapping === undefined ? undefined : yamlScalar(mapping.value); +}; + +interface DependabotGroup { + name: string; + appliesTo?: string; + patterns: string[]; +} + +const getDependabotGroups = (entry: string[]) => { + const groupsBlock = getYamlBlock(entry, 'groups', 4); + const groups: DependabotGroup[] = []; + + for (let index = 0; index < groupsBlock.length; index++) { + const match = groupsBlock[index].match(/^ {6}([^\s:#][^:#]*):\s*(?:#.*)?$/); + if (!match) continue; + + const groupLines: string[] = []; + for (let child = index + 1; child < groupsBlock.length; child++) { + const line = groupsBlock[child]; + const indent = line.match(/^ */)?.[0].length ?? 0; + if (indent <= 6) break; + groupLines.push(line); + } + + const patternsBlock = getYamlBlock(groupLines, 'patterns', 8); + groups.push({ + name: yamlScalar(match[1]), + appliesTo: getYamlScalar(groupLines, 'applies-to', 8), + patterns: patternsBlock + .map((line) => line.match(/^ {10}-\s+(.+)$/)?.[1]) + .filter((value): value is string => value !== undefined) + .map(yamlScalar), + }); + } + + return groups; +}; const getWorkflowJob = (workflow: string, name: string) => { const jobsStart = workflow.indexOf('jobs:\n'); @@ -15,6 +154,92 @@ const getWorkflowJob = (workflow: string, name: string) => { return nextJob === -1 ? afterJob : afterJob.slice(0, nextJob); }; +const getWorkflowRunCommands = (workflow: string, jobName: string) => { + const lines = getWorkflowJob(workflow, jobName).split('\n'); + const commands: string[] = []; + + for (let index = 0; index < lines.length; index++) { + const mapping = parseYamlMapping(lines[index]); + if (mapping?.indent !== 8 || mapping.key !== 'run') continue; + + const value = yamlScalar(mapping.value); + if (!/^(?:\||>)[+-]?$/.test(value)) { + commands.push(value); + continue; + } + + for (let child = index + 1; child < lines.length; child++) { + const line = lines[child]; + const indent = line.match(/^ */)?.[0].length ?? 0; + if (line.trim() && indent <= mapping.indent) break; + const command = line.trim(); + if (command && !command.startsWith('#')) commands.push(command); + } + } + + return commands; +}; + +const assertCiAuditGate = (ci: string) => { + const auditCommand = 'npm audit --audit-level=critical'; + const runCommands = getWorkflowRunCommands(ci, 'quality'); + expect(runCommands.filter((command) => command.includes(auditCommand))).toEqual([auditCommand]); + + const commandPositions = [ + 'npm ci', + auditCommand, + 'npm run check', + 'npm test', + 'npm run build', + ].map((command) => runCommands.indexOf(command)); + expect(commandPositions.every((position) => position >= 0)).toBe(true); + expect(commandPositions).toEqual([...commandPositions].sort((a, b) => a - b)); +}; + +const assertDependabotPolicy = (dependabot: string) => { + const lines = dependabot.split('\n'); + + expect(getYamlScalar(lines, 'version', 0)).toBe('2'); + + const updates = getYamlBlock(lines, 'updates', 0); + const entries: string[][] = []; + for (let index = 0; index < updates.length; index++) { + if (!/^ {2}-\s+/.test(updates[index])) continue; + const entry = [updates[index].replace(/^ {2}-\s+/, ' ')]; + for (let child = index + 1; child < updates.length; child++) { + if (/^ {2}-\s+/.test(updates[child])) break; + entry.push(updates[child]); + } + entries.push(entry); + } + + const npmEntries = entries.filter((entry) => getYamlScalar(entry, 'package-ecosystem', 4) === 'npm'); + expect(npmEntries).toHaveLength(1); + const [npmEntry] = npmEntries; + expect(getYamlScalar(npmEntry, 'directory', 4)).toBe('/'); + expect(getYamlScalar(getYamlBlock(npmEntry, 'schedule', 4), 'interval', 6)).toBe('monthly'); + const pullRequestLimit = getYamlScalar(npmEntry, 'open-pull-requests-limit', 4); + if (pullRequestLimit !== undefined) { + const numericLimit = Number(pullRequestLimit); + expect(Number.isFinite(numericLimit)).toBe(true); + expect(numericLimit).toBeGreaterThan(0); + } + + const groups = getDependabotGroups(npmEntry); + const versionGroup = groups.find((group) => group.appliesTo === 'version-updates'); + const securityGroup = groups.find((group) => group.appliesTo === 'security-updates'); + expect(versionGroup?.patterns).toContain('*'); + expect(securityGroup?.patterns).toContain('*'); + expect(versionGroup?.name).not.toBe(securityGroup?.name); + + const activeMappings = getActiveYamlLines(lines) + .map(parseYamlMapping) + .filter((mapping): mapping is YamlMapping => mapping !== undefined); + const forbiddenKeys = new Set(['registries', 'secret', 'secrets', 'automerge', 'auto-merge', 'auto_merge']); + expect(activeMappings.some((mapping) => forbiddenKeys.has(mapping.key.toLowerCase()))).toBe(false); + expect(activeMappings.some((mapping) => /\bsecrets?\s*\./i.test(yamlScalar(mapping.value)))).toBe(false); +}; + interface PermissionsDeclaration { indent: number; line: number; @@ -103,10 +328,76 @@ describe('release workflow contracts', () => { expect(ci).toMatch(/uses: actions\/checkout@v6\n with:\n persist-credentials: false/); expect(ci).toMatch(/uses: actions\/setup-node@v7\n with:\n node-version-file: \.node-version\n cache: npm/); - const commandPositions = ['npm ci', 'npm run check', 'npm test', 'npm run build'] - .map((command) => ci.indexOf(command)); - expect(commandPositions.every((position) => position >= 0)).toBe(true); - expect(commandPositions).toEqual([...commandPositions].sort((a, b) => a - b)); + assertCiAuditGate(ci); + }); + + it('keeps npm version and security updates separately grouped without elevated authority', () => { + assertDependabotPolicy(readRepositoryFile('.github', 'dependabot.yml')); + }); + + it.each(['00', '0x0', '+0', '0.0'])( + 'rejects open-pull-requests-limit numeric zero form %s', + (zero) => { + const dangerousDependabot = readRepositoryFile('.github', 'dependabot.yml').replace( + ' directory: /\n', + ` directory: /\n open-pull-requests-limit: ${zero}\n`, + ); + + expect(() => assertDependabotPolicy(dangerousDependabot)).toThrow(); + }, + ); + + it('rejects a quoted active registries key', () => { + const dangerousDependabot = readRepositoryFile('.github', 'dependabot.yml').replace( + ' directory: /\n', + ' directory: /\n "registries":\n - private\n', + ); + + expect(() => assertDependabotPolicy(dangerousDependabot)).toThrow(); + }); + + it('rejects a quoted active registries key as the first list-item mapping', () => { + const dangerousDependabot = readRepositoryFile('.github', 'dependabot.yml').replace( + ' - package-ecosystem: npm\n', + ' - "registries":\n - private\n package-ecosystem: npm\n', + ); + + expect(() => assertDependabotPolicy(dangerousDependabot)).toThrow(); + }); + + it('allows harmless YAML comments mentioning secrets or auto-merge', () => { + const harmlessDependabot = [ + '# secrets: are not configured here', + '# auto-merge remains disabled', + readRepositoryFile('.github', 'dependabot.yml'), + ].join('\n'); + + expect(() => assertDependabotPolicy(harmlessDependabot)).not.toThrow(); + }); + + it('rejects audit text left only in a YAML comment', () => { + const ciWithoutAudit = readWorkflow('ci.yml').replace( + ' - name: Audit critical vulnerabilities\n run: npm audit --audit-level=critical\n', + ' # run: npm audit --audit-level=critical\n', + ); + + expect(() => assertCiAuditGate(ciWithoutAudit)).toThrow(); + }); + + it('rejects audit text left only in a non-executable block scalar', () => { + const ciWithoutAudit = readWorkflow('ci.yml').replace( + ' - name: Audit critical vulnerabilities\n run: npm audit --audit-level=critical\n', + [ + ' - name: Preserve audit command as data', + ' env:', + ' NOTE: |', + ' run: npm audit --audit-level=critical', + ' run: echo "$NOTE"', + '', + ].join('\n'), + ); + + expect(() => assertCiAuditGate(ciWithoutAudit)).toThrow(); }); it('keeps every qualifying main completion visible while only successful releases smoke', () => {