From be407692b21f0b326c123de8eca7b2ffd847e2f4 Mon Sep 17 00:00:00 2001 From: Shironex Date: Mon, 31 Aug 2026 16:07:39 +0200 Subject: [PATCH] build(deps): move the vitest family to 4.1.11 (vite stays 7.3.6 for the app build) PR A of the staged vite/vitest migration (docs/migrations/2026-08-31-vite.md). vitest 4 runs on the vite already in the tree, so the vitest-side structural changes land isolated from the app's own vite 7 -> 8 move (PR B). vitest / @vitest/browser / @vitest/coverage-istanbul 3.2.7 -> 4.1.11 @vitest/browser-playwright new, 4.1.11 packages/eslint-plugin's vitest 3.2.7 -> 4.1.11 @vitest/browser is KEPT: @storybook/addon-vitest still peer-declares it. Browser provider rewrite (BC-A1): vitest 4 replaced the `provider: 'playwright'` string with a factory from a separate package. `contextOptions` moves to the provider call rather than per-instance -- instance-level provider overrides do not merge with the parent, and this repo runs one instance per project. The reduced-motion emulation that de-flakes the sheet-animation click tests is preserved and verified live. Also swept BC-A2's deprecated `@vitest/browser/context` imports to `vitest/browser` across 36 test files (+ an eslint --fix pass: the new specifier sorts differently under simple-import-sort). Three things the plan missed, all documented in a corrections section appended to the migration doc -- read it before starting PR B: - vite 8 arrives with PR A regardless. vitest 4 declares vite in DEPENDENCIES, not just peers, so bun resolves it independently to 8.2.2 (astro already had it in the tree). The app build genuinely stays on vite 7.3.6, but the test runner is on vite 8 + Rolldown today. Bun has no scoped-override mechanism to prevent it, and a global vite override would break astro. BC-B1's Rolldown dep-optimizer risk is therefore already paid here -- so this was stress-tested to PR B's standard: 4 cold-cache `test:web` runs, 517 files / 2953 tests green every time, zero `optimized dependencies changed`. - vitest-browser-react 2.x made `render()` async, breaking 218 test files at runtime, not just in types. Held at ^1.0.0, whose peer range (`^4.0.0-0`) already covers vitest 4.1.11 -- a supported combination, not a workaround. The async-render migration is its own PR. - storybook pins @vitest/spy at exactly 3.2.4 (still true on 10.5.10), so vitest 4 leaves two structurally-incompatible copies: 159 type errors over 69 files. Collapsed via a root override. This crosses a major and so sits in tension with the documented override policy; it passes `bun run audit` because exact pins count as bounded. Rationale and removal condition are in the doc. tsconfig's `types` entry also needed updating: @vitest/browser 4 dropped its `./providers/*` exports, so it now points at @vitest/browser-playwright/context. And .gitignore picks up vitest 4's new .vitest-attachments/ screenshot dir. Gates: typecheck, apps/web tsc, lint (incl. lint:meta), codegen:check, audit, e2e:ring3 --prove, test:node (2059), test:web (517/2953, x4 cold cache), test:plugin (15), cargo fmt --check, cargo clippy --all-targets -- all green. test:rust is 1585 pass / 3 fail, the documented pre-existing macOS-only e2e::sidecar_boundary::contract trio. --- .gitignore | 2 + apps/web/package.json | 7 +- .../hooks/useProjectRemoval.hooks.test.tsx | 2 +- .../SidebarUnified/SidebarUnified.test.tsx | 2 +- .../BulkActionBar/BulkActionBar.test.tsx | 2 +- .../DependencyEditor.test.tsx | 2 +- .../board/IssueChip/IssueChip.test.tsx | 2 +- .../IssueClosedChip/IssueClosedChip.test.tsx | 2 +- .../board/NewTaskForm/NewTaskForm.test.tsx | 2 +- .../RunOrderPanel/RunOrderPanel.test.tsx | 2 +- .../SessionComposer/SessionComposer.test.tsx | 2 +- .../TaskCardTerminalChip.test.tsx | 2 +- .../TaskOverviewEditor.test.tsx | 2 +- .../WorktreeSwitcher.test.tsx | 2 +- .../CouncilReplay/CouncilReplay.test.tsx | 2 +- .../ApplyConfirmDialog.test.tsx | 2 +- .../NewProjectDialog.test.tsx | 2 +- .../prreview/PrFilterBar/PrFilterBar.test.tsx | 2 +- .../prreview/prreview-resize.hooks.test.tsx | 2 +- .../SettingsView/SettingsView.test.tsx | 2 +- .../TerminalGridPane.test.tsx | 2 +- .../TerminalPane/TerminalPane.test.tsx | 2 +- .../TerminalSearchBar.test.tsx | 2 +- .../TerminalTabs/TerminalTabs.test.tsx | 2 +- .../TerminalTaskMenu.test.tsx | 2 +- .../ui/BranchPicker/BranchPicker.test.tsx | 2 +- .../components/ui/Checkbox/Checkbox.test.tsx | 2 +- .../ui/ConfirmDialog/ConfirmDialog.test.tsx | 2 +- .../FolderBrowserDialog.test.tsx | 2 +- .../ui/IssueMapDialog/IssueMapDialog.test.tsx | 2 +- apps/web/src/components/ui/Menu/Menu.test.tsx | 2 +- .../src/components/ui/Modal/Modal.test.tsx | 2 +- .../ui/ModelSelect/ModelSelect.test.tsx | 2 +- .../ui/NumberField/NumberField.test.tsx | 2 +- .../ui/Segmented/Segmented.test.tsx | 2 +- .../ui/ToolbarOption/ToolbarOption.test.tsx | 2 +- .../components/ui/Tooltip/Tooltip.test.tsx | 2 +- .../CreatePRDialog/CreatePRDialog.test.tsx | 2 +- apps/web/tsconfig.json | 7 +- apps/web/vitest.config.ts | 28 +- bun.lock | 130 +++------ docs/migrations/2026-08-31-vite.md | 270 ++++++++++++++++++ package.json | 3 +- packages/eslint-plugin/package.json | 2 +- 44 files changed, 370 insertions(+), 151 deletions(-) create mode 100644 docs/migrations/2026-08-31-vite.md diff --git a/.gitignore b/.gitignore index fa4ab110..7864c271 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ storybook-static/ # Vitest browser-mode failure screenshots **/__screenshots__/ +# Vitest 4 writes failure screenshots/traces here as well, keyed by content hash. +**/.vitest-attachments/ # Rust / Tauri build output + generated files target/ diff --git a/apps/web/package.json b/apps/web/package.json index 49df2eb2..e7e1177e 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -47,14 +47,15 @@ "@types/react": "^19.2.0", "@types/react-dom": "^19.2.0", "@vitejs/plugin-react": "^5.0.0", - "@vitest/browser": "^3.2.7", - "@vitest/coverage-istanbul": "^3.2.7", + "@vitest/browser": "^4.1.11", + "@vitest/browser-playwright": "^4.1.11", + "@vitest/coverage-istanbul": "^4.1.11", "playwright": "^1.61.0", "storybook": "^10.5.5", "tailwindcss": "^4.1.0", "typescript": "^6.0.3", "vite": "^7.0.0", - "vitest": "^3.2.7", + "vitest": "^4.1.11", "vitest-browser-react": "^1.0.0" } } diff --git a/apps/web/src/components/app/AppShell/hooks/useProjectRemoval.hooks.test.tsx b/apps/web/src/components/app/AppShell/hooks/useProjectRemoval.hooks.test.tsx index 3751de30..5e293bef 100644 --- a/apps/web/src/components/app/AppShell/hooks/useProjectRemoval.hooks.test.tsx +++ b/apps/web/src/components/app/AppShell/hooks/useProjectRemoval.hooks.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { Project } from '@/lib/bridge'; diff --git a/apps/web/src/components/app/SidebarUnified/SidebarUnified.test.tsx b/apps/web/src/components/app/SidebarUnified/SidebarUnified.test.tsx index cfc37358..3eb6d4a3 100644 --- a/apps/web/src/components/app/SidebarUnified/SidebarUnified.test.tsx +++ b/apps/web/src/components/app/SidebarUnified/SidebarUnified.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { ProjectSwitcherSurface } from '../Sidebar/Sidebar.types'; diff --git a/apps/web/src/components/board/BulkActionBar/BulkActionBar.test.tsx b/apps/web/src/components/board/BulkActionBar/BulkActionBar.test.tsx index 052c27e4..916c3071 100644 --- a/apps/web/src/components/board/BulkActionBar/BulkActionBar.test.tsx +++ b/apps/web/src/components/board/BulkActionBar/BulkActionBar.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { makeTask, makeTaskActions } from '../_fixtures'; diff --git a/apps/web/src/components/board/DependencyEditor/DependencyEditor.test.tsx b/apps/web/src/components/board/DependencyEditor/DependencyEditor.test.tsx index d4135c23..2818cd32 100644 --- a/apps/web/src/components/board/DependencyEditor/DependencyEditor.test.tsx +++ b/apps/web/src/components/board/DependencyEditor/DependencyEditor.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { makeTask, makeTaskActions } from '../_fixtures'; diff --git a/apps/web/src/components/board/IssueChip/IssueChip.test.tsx b/apps/web/src/components/board/IssueChip/IssueChip.test.tsx index e58455ce..74576a23 100644 --- a/apps/web/src/components/board/IssueChip/IssueChip.test.tsx +++ b/apps/web/src/components/board/IssueChip/IssueChip.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { afterEach, expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; // Spy only the chip's ONE bridge dependency (the browser open); everything else keeps its diff --git a/apps/web/src/components/board/IssueClosedChip/IssueClosedChip.test.tsx b/apps/web/src/components/board/IssueClosedChip/IssueClosedChip.test.tsx index 88b6cdf2..6114419b 100644 --- a/apps/web/src/components/board/IssueClosedChip/IssueClosedChip.test.tsx +++ b/apps/web/src/components/board/IssueClosedChip/IssueClosedChip.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { afterEach, expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; // Spy only the chip's ONE bridge dependency (the browser open); everything else — the diff --git a/apps/web/src/components/board/NewTaskForm/NewTaskForm.test.tsx b/apps/web/src/components/board/NewTaskForm/NewTaskForm.test.tsx index 150966f1..1c502664 100644 --- a/apps/web/src/components/board/NewTaskForm/NewTaskForm.test.tsx +++ b/apps/web/src/components/board/NewTaskForm/NewTaskForm.test.tsx @@ -1,7 +1,7 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { useEffect } from 'react'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { ProviderCapabilities } from '@nightcore/contracts'; diff --git a/apps/web/src/components/board/RunOrderPanel/RunOrderPanel.test.tsx b/apps/web/src/components/board/RunOrderPanel/RunOrderPanel.test.tsx index 8d8ea2ae..9faccf7f 100644 --- a/apps/web/src/components/board/RunOrderPanel/RunOrderPanel.test.tsx +++ b/apps/web/src/components/board/RunOrderPanel/RunOrderPanel.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { RunOrderProjection } from '@/lib/bridge'; diff --git a/apps/web/src/components/board/SessionComposer/SessionComposer.test.tsx b/apps/web/src/components/board/SessionComposer/SessionComposer.test.tsx index b9855bc3..6087e7c4 100644 --- a/apps/web/src/components/board/SessionComposer/SessionComposer.test.tsx +++ b/apps/web/src/components/board/SessionComposer/SessionComposer.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import * as stories from './SessionComposer.stories'; diff --git a/apps/web/src/components/board/TaskCardTerminalChip/TaskCardTerminalChip.test.tsx b/apps/web/src/components/board/TaskCardTerminalChip/TaskCardTerminalChip.test.tsx index 01279bcb..43663919 100644 --- a/apps/web/src/components/board/TaskCardTerminalChip/TaskCardTerminalChip.test.tsx +++ b/apps/web/src/components/board/TaskCardTerminalChip/TaskCardTerminalChip.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { afterEach, expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { linkTaskToSession, resetTerminalLinksForTest } from '@/lib/terminal-links'; diff --git a/apps/web/src/components/board/TaskOverviewEditor/TaskOverviewEditor.test.tsx b/apps/web/src/components/board/TaskOverviewEditor/TaskOverviewEditor.test.tsx index de435018..fddd16ed 100644 --- a/apps/web/src/components/board/TaskOverviewEditor/TaskOverviewEditor.test.tsx +++ b/apps/web/src/components/board/TaskOverviewEditor/TaskOverviewEditor.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { makeTask } from '../_fixtures.task'; diff --git a/apps/web/src/components/board/WorktreeSwitcher/WorktreeSwitcher.test.tsx b/apps/web/src/components/board/WorktreeSwitcher/WorktreeSwitcher.test.tsx index b69125c8..888be1bd 100644 --- a/apps/web/src/components/board/WorktreeSwitcher/WorktreeSwitcher.test.tsx +++ b/apps/web/src/components/board/WorktreeSwitcher/WorktreeSwitcher.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render, renderHook } from 'vitest-browser-react'; import { diff --git a/apps/web/src/components/council/CouncilReplay/CouncilReplay.test.tsx b/apps/web/src/components/council/CouncilReplay/CouncilReplay.test.tsx index 3318a7ce..3bf97314 100644 --- a/apps/web/src/components/council/CouncilReplay/CouncilReplay.test.tsx +++ b/apps/web/src/components/council/CouncilReplay/CouncilReplay.test.tsx @@ -1,6 +1,6 @@ -import { userEvent } from '@vitest/browser/context'; import type { ReactNode } from 'react'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { killCouncil, resolveCouncilConverge, startCouncil } from '@/lib/bridge'; diff --git a/apps/web/src/components/harness/ApplyConfirmDialog/ApplyConfirmDialog.test.tsx b/apps/web/src/components/harness/ApplyConfirmDialog/ApplyConfirmDialog.test.tsx index 5be8a5c9..05f56e59 100644 --- a/apps/web/src/components/harness/ApplyConfirmDialog/ApplyConfirmDialog.test.tsx +++ b/apps/web/src/components/harness/ApplyConfirmDialog/ApplyConfirmDialog.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import * as stories from './ApplyConfirmDialog.stories'; diff --git a/apps/web/src/components/new-project/NewProjectDialog/NewProjectDialog.test.tsx b/apps/web/src/components/new-project/NewProjectDialog/NewProjectDialog.test.tsx index 1bf9ec15..73598777 100644 --- a/apps/web/src/components/new-project/NewProjectDialog/NewProjectDialog.test.tsx +++ b/apps/web/src/components/new-project/NewProjectDialog/NewProjectDialog.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { projectNameFromPath } from './NewProjectDialog.hooks'; diff --git a/apps/web/src/components/prreview/PrFilterBar/PrFilterBar.test.tsx b/apps/web/src/components/prreview/PrFilterBar/PrFilterBar.test.tsx index aa15e21e..3786bbe7 100644 --- a/apps/web/src/components/prreview/PrFilterBar/PrFilterBar.test.tsx +++ b/apps/web/src/components/prreview/PrFilterBar/PrFilterBar.test.tsx @@ -1,6 +1,6 @@ -import { userEvent } from '@vitest/browser/context'; import { useState } from 'react'; import { expect, test } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { ReviewLifecycleState } from '../prreview-lifecycle'; diff --git a/apps/web/src/components/prreview/prreview-resize.hooks.test.tsx b/apps/web/src/components/prreview/prreview-resize.hooks.test.tsx index 29698085..66ed6cde 100644 --- a/apps/web/src/components/prreview/prreview-resize.hooks.test.tsx +++ b/apps/web/src/components/prreview/prreview-resize.hooks.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { beforeEach, expect, test } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { useResizablePanelWidth } from './prreview-resize.hooks'; diff --git a/apps/web/src/components/settings/SettingsView/SettingsView.test.tsx b/apps/web/src/components/settings/SettingsView/SettingsView.test.tsx index ee7e7631..71452b38 100644 --- a/apps/web/src/components/settings/SettingsView/SettingsView.test.tsx +++ b/apps/web/src/components/settings/SettingsView/SettingsView.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import * as stories from './SettingsView.stories'; diff --git a/apps/web/src/components/terminal/TerminalGridPane/TerminalGridPane.test.tsx b/apps/web/src/components/terminal/TerminalGridPane/TerminalGridPane.test.tsx index 9c287054..c15389a5 100644 --- a/apps/web/src/components/terminal/TerminalGridPane/TerminalGridPane.test.tsx +++ b/apps/web/src/components/terminal/TerminalGridPane/TerminalGridPane.test.tsx @@ -1,7 +1,7 @@ import { DndContext } from '@dnd-kit/core'; import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { ToastProvider } from '@/components/ui'; diff --git a/apps/web/src/components/terminal/TerminalPane/TerminalPane.test.tsx b/apps/web/src/components/terminal/TerminalPane/TerminalPane.test.tsx index a72c1cda..af708a35 100644 --- a/apps/web/src/components/terminal/TerminalPane/TerminalPane.test.tsx +++ b/apps/web/src/components/terminal/TerminalPane/TerminalPane.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { afterEach, expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { ToastProvider } from '@/components/ui'; diff --git a/apps/web/src/components/terminal/TerminalSearchBar/TerminalSearchBar.test.tsx b/apps/web/src/components/terminal/TerminalSearchBar/TerminalSearchBar.test.tsx index 88ec5c6d..7eb5c519 100644 --- a/apps/web/src/components/terminal/TerminalSearchBar/TerminalSearchBar.test.tsx +++ b/apps/web/src/components/terminal/TerminalSearchBar/TerminalSearchBar.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { TerminalSearchBar } from './TerminalSearchBar'; diff --git a/apps/web/src/components/terminal/TerminalTabs/TerminalTabs.test.tsx b/apps/web/src/components/terminal/TerminalTabs/TerminalTabs.test.tsx index 81f67dbd..a567efc2 100644 --- a/apps/web/src/components/terminal/TerminalTabs/TerminalTabs.test.tsx +++ b/apps/web/src/components/terminal/TerminalTabs/TerminalTabs.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import * as stories from './TerminalTabs.stories'; diff --git a/apps/web/src/components/terminal/TerminalTaskMenu/TerminalTaskMenu.test.tsx b/apps/web/src/components/terminal/TerminalTaskMenu/TerminalTaskMenu.test.tsx index 4a7f89bc..e6635f18 100644 --- a/apps/web/src/components/terminal/TerminalTaskMenu/TerminalTaskMenu.test.tsx +++ b/apps/web/src/components/terminal/TerminalTaskMenu/TerminalTaskMenu.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { makeTerminalSession, makeTerminalTask } from '../_fixtures'; diff --git a/apps/web/src/components/ui/BranchPicker/BranchPicker.test.tsx b/apps/web/src/components/ui/BranchPicker/BranchPicker.test.tsx index f98aeb67..a3217e65 100644 --- a/apps/web/src/components/ui/BranchPicker/BranchPicker.test.tsx +++ b/apps/web/src/components/ui/BranchPicker/BranchPicker.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { BranchInfo } from '@/lib/bridge'; diff --git a/apps/web/src/components/ui/Checkbox/Checkbox.test.tsx b/apps/web/src/components/ui/Checkbox/Checkbox.test.tsx index 9e0c723a..0782df71 100644 --- a/apps/web/src/components/ui/Checkbox/Checkbox.test.tsx +++ b/apps/web/src/components/ui/Checkbox/Checkbox.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { Checkbox } from './Checkbox'; diff --git a/apps/web/src/components/ui/ConfirmDialog/ConfirmDialog.test.tsx b/apps/web/src/components/ui/ConfirmDialog/ConfirmDialog.test.tsx index 29531753..70adf57f 100644 --- a/apps/web/src/components/ui/ConfirmDialog/ConfirmDialog.test.tsx +++ b/apps/web/src/components/ui/ConfirmDialog/ConfirmDialog.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import * as stories from './ConfirmDialog.stories'; diff --git a/apps/web/src/components/ui/FolderBrowserDialog/FolderBrowserDialog.test.tsx b/apps/web/src/components/ui/FolderBrowserDialog/FolderBrowserDialog.test.tsx index 67e9b347..04d3322a 100644 --- a/apps/web/src/components/ui/FolderBrowserDialog/FolderBrowserDialog.test.tsx +++ b/apps/web/src/components/ui/FolderBrowserDialog/FolderBrowserDialog.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { afterEach, expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { DirectoryListing } from '@/lib/bridge'; diff --git a/apps/web/src/components/ui/IssueMapDialog/IssueMapDialog.test.tsx b/apps/web/src/components/ui/IssueMapDialog/IssueMapDialog.test.tsx index cb35432b..acd971c3 100644 --- a/apps/web/src/components/ui/IssueMapDialog/IssueMapDialog.test.tsx +++ b/apps/web/src/components/ui/IssueMapDialog/IssueMapDialog.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { afterEach, beforeEach, expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; // Mock the Tauri command + event surface underneath the bridge (the CreatePRDialog diff --git a/apps/web/src/components/ui/Menu/Menu.test.tsx b/apps/web/src/components/ui/Menu/Menu.test.tsx index 71d3c869..09d0c470 100644 --- a/apps/web/src/components/ui/Menu/Menu.test.tsx +++ b/apps/web/src/components/ui/Menu/Menu.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { IconButton } from '../IconButton'; diff --git a/apps/web/src/components/ui/Modal/Modal.test.tsx b/apps/web/src/components/ui/Modal/Modal.test.tsx index baf21388..ce50b0fe 100644 --- a/apps/web/src/components/ui/Modal/Modal.test.tsx +++ b/apps/web/src/components/ui/Modal/Modal.test.tsx @@ -1,6 +1,6 @@ -import { userEvent } from '@vitest/browser/context'; import { useState } from 'react'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { MotionProvider } from '../motion'; diff --git a/apps/web/src/components/ui/ModelSelect/ModelSelect.test.tsx b/apps/web/src/components/ui/ModelSelect/ModelSelect.test.tsx index fb9b9393..902c6c32 100644 --- a/apps/web/src/components/ui/ModelSelect/ModelSelect.test.tsx +++ b/apps/web/src/components/ui/ModelSelect/ModelSelect.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { ModelDescriptor } from '@nightcore/contracts'; diff --git a/apps/web/src/components/ui/NumberField/NumberField.test.tsx b/apps/web/src/components/ui/NumberField/NumberField.test.tsx index fd645a90..2d63ff55 100644 --- a/apps/web/src/components/ui/NumberField/NumberField.test.tsx +++ b/apps/web/src/components/ui/NumberField/NumberField.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { NumberField } from './NumberField'; diff --git a/apps/web/src/components/ui/Segmented/Segmented.test.tsx b/apps/web/src/components/ui/Segmented/Segmented.test.tsx index 050ab2c6..d2bfe0fb 100644 --- a/apps/web/src/components/ui/Segmented/Segmented.test.tsx +++ b/apps/web/src/components/ui/Segmented/Segmented.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { MotionProvider } from '../motion'; diff --git a/apps/web/src/components/ui/ToolbarOption/ToolbarOption.test.tsx b/apps/web/src/components/ui/ToolbarOption/ToolbarOption.test.tsx index d6957731..adab8ce4 100644 --- a/apps/web/src/components/ui/ToolbarOption/ToolbarOption.test.tsx +++ b/apps/web/src/components/ui/ToolbarOption/ToolbarOption.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { BoltIcon } from '../icons'; diff --git a/apps/web/src/components/ui/Tooltip/Tooltip.test.tsx b/apps/web/src/components/ui/Tooltip/Tooltip.test.tsx index e7e7ae92..10dae5b7 100644 --- a/apps/web/src/components/ui/Tooltip/Tooltip.test.tsx +++ b/apps/web/src/components/ui/Tooltip/Tooltip.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import * as stories from './Tooltip.stories'; diff --git a/apps/web/src/components/worktree/CreatePRDialog/CreatePRDialog.test.tsx b/apps/web/src/components/worktree/CreatePRDialog/CreatePRDialog.test.tsx index ee0690d6..eae817f8 100644 --- a/apps/web/src/components/worktree/CreatePRDialog/CreatePRDialog.test.tsx +++ b/apps/web/src/components/worktree/CreatePRDialog/CreatePRDialog.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { afterEach, beforeEach, expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; // Mock the Tauri command surface underneath the bridge (the same seam diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index 6c2c7975..79a1e7ad 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -17,7 +17,12 @@ "isolatedModules": true, "verbatimModuleSyntax": true, "noEmit": true, - "types": ["vite/client", "@vitest/browser/providers/playwright"], + // Vitest 4 moved the Playwright provider into its own package and dropped + // `@vitest/browser`'s `./providers/*` export entries, so the old + // "@vitest/browser/providers/playwright" reference no longer resolves. The + // replacement is the provider package's types-only `./context` export, which + // types `page`/`userEvent` with the Playwright-specific surface. + "types": ["vite/client", "@vitest/browser-playwright/context"], // Deliberately no `baseUrl` — TypeScript 6 already rejects it (TS5101) and 7 // removed it outright (TS5102). Without it, `paths` values resolve relative to // THIS file, which the self-relative "./src/*" below already assumes. Bundler diff --git a/apps/web/vitest.config.ts b/apps/web/vitest.config.ts index ca5df815..36d2e20a 100644 --- a/apps/web/vitest.config.ts +++ b/apps/web/vitest.config.ts @@ -3,6 +3,7 @@ import { fileURLToPath } from 'node:url'; import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'; import tailwind from '@tailwindcss/vite'; import react from '@vitejs/plugin-react'; +import { playwright } from '@vitest/browser-playwright'; import { defineConfig } from 'vitest/config'; const alias = { '@': fileURLToPath(new URL('./src', import.meta.url)) }; @@ -13,18 +14,23 @@ const alias = { '@': fileURLToPath(new URL('./src', import.meta.url)) }; // name ("storybook (chromium)" / "unit (chromium)") from its own object. const chromium = () => ({ enabled: true, - provider: 'playwright' as const, + // Vitest 4 replaced the `provider: 'playwright'` string with a provider + // factory from a separate package. `contextOptions` sits on the provider call + // rather than per-instance: instance-level provider overrides do NOT merge + // with the parent, and this repo runs exactly one instance per project, so the + // single provider-level call is the unambiguous shape. + provider: playwright({ + // Emulate `prefers-reduced-motion: reduce` in the test browser. The app's + // reduced-motion rule collapses every animation to ~0ms (styles.css), so the + // slide-in detail sheets (`nc-sheet-in`) settle instantly instead of moving + // ~100px through their 280ms enter — otherwise a `.click()` can race the + // animation and land off a button that's still sliding, a latent flake in the + // shared DetailPanelShell click tests (Insight/Scorecard/Harness) that only + // surfaces in isolated runs. This makes those tests deterministic. + contextOptions: { reducedMotion: 'reduce' }, + }), headless: true, - // Emulate `prefers-reduced-motion: reduce` in the test browser. The app's - // reduced-motion rule collapses every animation to ~0ms (styles.css), so the - // slide-in detail sheets (`nc-sheet-in`) settle instantly instead of moving - // ~100px through their 280ms enter — otherwise a `.click()` can race the - // animation and land off a button that's still sliding, a latent flake in the - // shared DetailPanelShell click tests (Insight/Scorecard/Harness) that only - // surfaces in isolated runs. This makes those tests deterministic. - instances: [ - { browser: 'chromium' as const, context: { reducedMotion: 'reduce' as const } }, - ], + instances: [{ browser: 'chromium' as const }], }); /** diff --git a/bun.lock b/bun.lock index 2d948957..aa8ca1b3 100644 --- a/bun.lock +++ b/bun.lock @@ -84,14 +84,15 @@ "@types/react": "^19.2.0", "@types/react-dom": "^19.2.0", "@vitejs/plugin-react": "^5.0.0", - "@vitest/browser": "^3.2.7", - "@vitest/coverage-istanbul": "^3.2.7", + "@vitest/browser": "^4.1.11", + "@vitest/browser-playwright": "^4.1.11", + "@vitest/coverage-istanbul": "^4.1.11", "playwright": "^1.61.0", "storybook": "^10.5.5", "tailwindcss": "^4.1.0", "typescript": "^6.0.3", "vite": "^7.0.0", - "vitest": "^3.2.7", + "vitest": "^4.1.11", "vitest-browser-react": "^1.0.0", }, }, @@ -135,7 +136,7 @@ "@typescript-eslint/rule-tester": "^8.68.0", "tsup": "^8.5.1", "typescript": "^6.0.3", - "vitest": "^3.2.7", + "vitest": "^4.1.11", }, "peerDependencies": { "eslint": ">=9.0.0", @@ -177,6 +178,7 @@ }, "overrides": { "@hono/node-server": ">=1.19.15 <2", + "@vitest/spy": "4.1.11", "fast-uri": ">=3.1.5 <4", "framer-motion": "12.42.2", "js-yaml": ">=4.3.1 <5", @@ -284,6 +286,8 @@ "@babel/types": ["@babel/types@7.29.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg=="], + "@blazediff/core": ["@blazediff/core@1.9.1", "", {}, "sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA=="], + "@bruits/satteri-darwin-arm64": ["@bruits/satteri-darwin-arm64@0.9.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-iw4nZgx9v30lWo/MTngQqi1pI78KI0DnkSm+lVJGYdmPLgAyDNJigVhpG42/Iq55A6c1Ll8q66ljyyRiQUxwow=="], "@bruits/satteri-darwin-x64": ["@bruits/satteri-darwin-x64@0.9.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-6T26Z5Kf3cFW2PSlk9p7zT7yVxvuBSiJvYyz9u8KjYwMTqZyIDOj2wDyNpxKV4+6yUVG7rddq2QwvG/8LJA2+Q=="], @@ -464,8 +468,6 @@ "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.35.4", "", { "os": "win32", "cpu": "x64" }, "sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg=="], - "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], - "@istanbuljs/schema": ["@istanbuljs/schema@0.1.6", "", {}, "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw=="], "@joshwooding/vite-plugin-react-docgen-typescript": ["@joshwooding/vite-plugin-react-docgen-typescript@0.7.0", "", { "dependencies": { "glob": "^13.0.1", "react-docgen-typescript": "^2.2.2" }, "peerDependencies": { "typescript": ">= 4.3.x", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["typescript"] }, "sha512-qvsTEwEFefhdirGOPnu9Wp6ChfIwy2dBCRuETU3uE+4cC+PFoxMSiiEhxk4lOluA34eARHA0OxqsEUYDqRMgeQ=="], @@ -636,8 +638,6 @@ "@pagefind/windows-x64": ["@pagefind/windows-x64@1.5.2", "", { "os": "win32", "cpu": "x64" }, "sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg=="], - "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], - "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], "@rolldown/binding-android-arm-eabi": ["@rolldown/binding-android-arm-eabi@1.2.6", "", { "os": "android", "cpu": "arm" }, "sha512-b+jTcARdTiFLI6jB4a5XjTm0RWd6KcRfQj/I2356fxUZemiho9zQLxo0RtCuMDAyKcLo6cEltkgbQp6d1+sjjQ=="], @@ -742,6 +742,8 @@ "@stablelib/base64": ["@stablelib/base64@1.0.1", "", {}, "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ=="], + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + "@storybook/addon-a11y": ["@storybook/addon-a11y@10.5.10", "", { "dependencies": { "@storybook/global": "^5.0.0", "axe-core": "^4.2.0" }, "peerDependencies": { "storybook": "^10.5.10" } }, "sha512-RpRQV5xUbrl6hCiNrd5FSMIo6pnRZ0VZxWvEW/ASLcreGkKUW5jl2AeLCe5YROE2i80s/dU+6VPzOYKrwWNFbQ=="], "@storybook/addon-vitest": ["@storybook/addon-vitest@10.5.10", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.2" }, "peerDependencies": { "@vitest/browser": "^3.0.0 || ^4.0.0", "@vitest/browser-playwright": "^4.0.0", "@vitest/runner": "^3.0.0 || ^4.0.0", "storybook": "^10.5.10", "vitest": "^3.0.0 || ^4.0.0" }, "optionalPeers": ["@vitest/browser", "@vitest/browser-playwright", "@vitest/runner", "vitest"] }, "sha512-JNQ9DSkLfxC8qqytBCej91zBExIZ7z97B410U2zgfQPki4HkI9Ffz97a15f5yhVZ79ppIrZ/ssI+WcyWn0ykXQ=="], @@ -914,23 +916,25 @@ "@vitejs/plugin-react": ["@vitejs/plugin-react@5.2.0", "", { "dependencies": { "@babel/core": "^7.29.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-rc.3", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw=="], - "@vitest/browser": ["@vitest/browser@3.2.7", "", { "dependencies": { "@testing-library/dom": "^10.4.0", "@testing-library/user-event": "^14.6.1", "@vitest/mocker": "3.2.7", "@vitest/utils": "3.2.7", "magic-string": "^0.30.17", "sirv": "^3.0.1", "tinyrainbow": "^2.0.0", "ws": "^8.18.2" }, "peerDependencies": { "playwright": "*", "safaridriver": "*", "vitest": "3.2.7", "webdriverio": "^7.0.0 || ^8.0.0 || ^9.0.0" }, "optionalPeers": ["playwright", "safaridriver", "webdriverio"] }, "sha512-gIzazUkbQfv6T1rJHOLhMMKQnplKAvvQ7QNGaFwI6oCsp4z2aSDZCojGpX3QX3+MYsvJdyy/8BRIYVEbAkMkEA=="], + "@vitest/browser": ["@vitest/browser@4.1.11", "", { "dependencies": { "@blazediff/core": "1.9.1", "@vitest/mocker": "4.1.11", "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pngjs": "^7.0.0", "sirv": "^3.0.2", "tinyrainbow": "^3.1.0", "ws": "^8.19.0" }, "peerDependencies": { "vitest": "4.1.11" } }, "sha512-bwMovvAeuTFOK5kIFevw4VEf+1gVEICv4SYK4k3knJOxl6b1zEWud8mYKD73e1B0odAn174h1MofURy2TPWf3w=="], + + "@vitest/browser-playwright": ["@vitest/browser-playwright@4.1.11", "", { "dependencies": { "@vitest/browser": "4.1.11", "@vitest/mocker": "4.1.11", "tinyrainbow": "^3.1.0" }, "peerDependencies": { "playwright": "*", "vitest": "4.1.11" } }, "sha512-riLBxPqwnJ0lWs2DN2WeUfYeKLoAjbP2Xx8cLQdSddzMi20sksIa6K2mPz79DyMZKKVKH2ksOC2yJvtNcZg8cg=="], - "@vitest/coverage-istanbul": ["@vitest/coverage-istanbul@3.2.7", "", { "dependencies": { "@istanbuljs/schema": "^0.1.3", "debug": "^4.4.1", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-instrument": "^6.0.3", "istanbul-lib-report": "^3.0.1", "istanbul-lib-source-maps": "^5.0.6", "istanbul-reports": "^3.1.7", "magicast": "^0.3.5", "test-exclude": "^7.0.1", "tinyrainbow": "^2.0.0" }, "peerDependencies": { "vitest": "3.2.7" } }, "sha512-/o+QIJBJCBZm7FdyAMqYKvr8Cd0YsqPt9UwVT6bAA+U9Ae8AR39ZAjq7xnmKCO64TkzPm0Vvi7jzYZWLdu6Y5A=="], + "@vitest/coverage-istanbul": ["@vitest/coverage-istanbul@4.1.11", "", { "dependencies": { "@babel/core": "^7.29.0", "@istanbuljs/schema": "^0.1.3", "@jridgewell/gen-mapping": "^0.3.13", "@jridgewell/trace-mapping": "0.3.31", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.2.0", "magicast": "^0.5.2", "obug": "^2.1.1", "tinyrainbow": "^3.1.0" }, "peerDependencies": { "vitest": "4.1.11" } }, "sha512-pK9LJtOS534bmUwdwLpGD9qL52DeqVWSInrXFMNqrvWLbbAhuIPAlRup3UbsjFOMqCC/p3MmmX7uXV7ZTkcFfQ=="], - "@vitest/expect": ["@vitest/expect@3.2.7", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.7", "@vitest/utils": "3.2.7", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w=="], + "@vitest/expect": ["@vitest/expect@4.1.11", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.11", "@vitest/utils": "4.1.11", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw=="], - "@vitest/mocker": ["@vitest/mocker@3.2.7", "", { "dependencies": { "@vitest/spy": "3.2.7", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA=="], + "@vitest/mocker": ["@vitest/mocker@4.1.11", "", { "dependencies": { "@vitest/spy": "4.1.11", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ=="], - "@vitest/pretty-format": ["@vitest/pretty-format@3.2.7", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA=="], + "@vitest/pretty-format": ["@vitest/pretty-format@4.1.11", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw=="], - "@vitest/runner": ["@vitest/runner@3.2.7", "", { "dependencies": { "@vitest/utils": "3.2.7", "pathe": "^2.0.3", "strip-literal": "^3.0.0" } }, "sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA=="], + "@vitest/runner": ["@vitest/runner@4.1.11", "", { "dependencies": { "@vitest/utils": "4.1.11", "pathe": "^2.0.3" } }, "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw=="], - "@vitest/snapshot": ["@vitest/snapshot@3.2.7", "", { "dependencies": { "@vitest/pretty-format": "3.2.7", "magic-string": "^0.30.17", "pathe": "^2.0.3" } }, "sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g=="], + "@vitest/snapshot": ["@vitest/snapshot@4.1.11", "", { "dependencies": { "@vitest/pretty-format": "4.1.11", "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog=="], - "@vitest/spy": ["@vitest/spy@3.2.7", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ=="], + "@vitest/spy": ["@vitest/spy@4.1.11", "", {}, "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA=="], - "@vitest/utils": ["@vitest/utils@3.2.7", "", { "dependencies": { "@vitest/pretty-format": "3.2.7", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw=="], + "@vitest/utils": ["@vitest/utils@4.1.11", "", { "dependencies": { "@vitest/pretty-format": "4.1.11", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ=="], "@webcontainer/env": ["@webcontainer/env@1.1.1", "", {}, "sha512-6aN99yL695Hi9SuIk1oC88l9o0gmxL1nGWWQ/kNy81HigJ0FoaoTXpytCj6ItzgyCEwA9kF1wixsTuv5cjsgng=="], @@ -1040,7 +1044,7 @@ "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], - "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], + "chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="], "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], @@ -1060,10 +1064,6 @@ "collapse-white-space": ["collapse-white-space@2.1.0", "", {}, "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw=="], - "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - - "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], "commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], @@ -1172,8 +1172,6 @@ "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], - "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], - "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], "electron-to-chromium": ["electron-to-chromium@1.5.417", "", {}, "sha512-4T+DTDWuMPM4aHlHwWdAVCVWwp7LDilnhzkj+c/Lbj91XSQrLuOmZSLtS9Q4iIqjlPUbPOnC624zDVVHCHaolQ=="], @@ -1312,8 +1310,6 @@ "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], - "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], - "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], "framer-motion": ["framer-motion@12.42.2", "", { "dependencies": { "motion-dom": "^12.42.2", "motion-utils": "^12.39.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-5XY9luDiu0oHfHBjpDthFMh0ES+122w6p/papSJBweMkO8Sn+PW2QaEgRblQBpWFnuvZS5qvarpt/hO2pjGmnw=="], @@ -1474,8 +1470,6 @@ "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], - "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], - "is-generator-function": ["is-generator-function@1.1.2", "", { "dependencies": { "call-bound": "^1.0.4", "generator-function": "^2.0.0", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA=="], "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], @@ -1520,23 +1514,17 @@ "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="], - "istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], - "istanbul-lib-report": ["istanbul-lib-report@3.0.1", "", { "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", "supports-color": "^7.1.0" } }, "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw=="], - "istanbul-lib-source-maps": ["istanbul-lib-source-maps@5.0.6", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.23", "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0" } }, "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A=="], - "istanbul-reports": ["istanbul-reports@3.2.0", "", { "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA=="], - "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], - "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], "jose": ["jose@6.2.10", "", {}, "sha512-iiW7J9qRFlGxvCOIBDBDxFePQSn7ZMAnrYGhrrOo6siO/MIqwfyilLR27pkfDgUk+raLuzADS8A3S/KLBisc0g=="], "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], - "js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], "js-yaml": ["js-yaml@4.3.2", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA=="], @@ -1830,8 +1818,6 @@ "p-timeout": ["p-timeout@7.0.1", "", {}, "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg=="], - "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], - "package-manager-detector": ["package-manager-detector@1.8.0", "", {}, "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A=="], "pagefind": ["pagefind@1.5.2", "", { "optionalDependencies": { "@pagefind/darwin-arm64": "1.5.2", "@pagefind/darwin-x64": "1.5.2", "@pagefind/freebsd-x64": "1.5.2", "@pagefind/linux-arm64": "1.5.2", "@pagefind/linux-x64": "1.5.2", "@pagefind/windows-arm64": "1.5.2", "@pagefind/windows-x64": "1.5.2" }, "bin": { "pagefind": "lib/runner/bin.cjs" } }, "sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q=="], @@ -1874,6 +1860,8 @@ "playwright-core": ["playwright-core@1.62.1", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw=="], + "pngjs": ["pngjs@7.0.0", "", {}, "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow=="], + "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], "postcss": ["postcss@8.5.26", "", { "dependencies": { "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ=="], @@ -2040,8 +2028,6 @@ "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], - "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - "sirv": ["sirv@3.0.2", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g=="], "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], @@ -2062,7 +2048,7 @@ "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], - "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], + "std-env": ["std-env@4.2.0", "", {}, "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw=="], "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], @@ -2070,10 +2056,6 @@ "stream-replace-string": ["stream-replace-string@2.0.0", "", {}, "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w=="], - "string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], - - "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "string.prototype.includes": ["string.prototype.includes@2.0.1", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3" } }, "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg=="], "string.prototype.trim": ["string.prototype.trim@1.2.11", "", { "dependencies": { "call-bind": "^1.0.9", "call-bound": "^1.0.4", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.2", "es-object-atoms": "^1.1.2", "has-property-descriptors": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w=="], @@ -2084,16 +2066,10 @@ "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], - "strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], - - "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], "strip-indent": ["strip-indent@4.1.1", "", {}, "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA=="], - "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], - "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="], "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], @@ -2110,8 +2086,6 @@ "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], - "test-exclude": ["test-exclude@7.0.2", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^10.4.1", "minimatch": "^10.2.2" } }, "sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw=="], - "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], @@ -2128,11 +2102,7 @@ "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], - "tinypool": ["tinypool@1.1.1", "", {}, "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg=="], - - "tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="], - - "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="], + "tinyrainbow": ["tinyrainbow@3.1.1", "", {}, "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw=="], "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], @@ -2236,11 +2206,9 @@ "vite": ["vite@7.3.6", "", { "dependencies": { "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg=="], - "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="], - "vitefu": ["vitefu@1.1.3", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["vite"] }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="], - "vitest": ["vitest@3.2.7", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.7", "@vitest/mocker": "3.2.7", "@vitest/pretty-format": "^3.2.7", "@vitest/runner": "3.2.7", "@vitest/snapshot": "3.2.7", "@vitest/spy": "3.2.7", "@vitest/utils": "3.2.7", "chai": "^5.2.0", "debug": "^4.4.1", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.2.7", "@vitest/ui": "3.2.7", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "./vitest.mjs" } }, "sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg=="], + "vitest": ["vitest@4.1.11", "", { "dependencies": { "@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": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@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": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "./vitest.mjs" } }, "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw=="], "vitest-browser-react": ["vitest-browser-react@1.0.1", "", { "peerDependencies": { "@types/react": "^18.0.0 || ^19.0.0", "@types/react-dom": "^18.0.0 || ^19.0.0", "@vitest/browser": "^2.1.0 || ^3.0.0 || ^4.0.0-0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "vitest": "^2.1.0 || ^3.0.0 || ^4.0.0-0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-LqiGFCdknrbMoSDWXTCTrPsED3SvdIXIgYOOZyYUNj2dkJusW2eF6NENOlBlxwq+FBQqzNK1X59b+b03pXFpAQ=="], @@ -2262,10 +2230,6 @@ "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], - "wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - - "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], "ws": ["ws@8.21.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw=="], @@ -2288,8 +2252,6 @@ "@astrojs/markdown-satteri/satteri": ["satteri@0.10.5", "", { "dependencies": { "@types/estree-jsx": "^1.0.5", "@types/hast": "^3.0.5", "@types/mdast": "^4.0.4", "@types/unist": "^3.0.3" }, "optionalDependencies": { "@bruits/satteri-darwin-arm64": "0.10.5", "@bruits/satteri-darwin-x64": "0.10.5", "@bruits/satteri-linux-arm64-gnu": "0.10.5", "@bruits/satteri-linux-arm64-musl": "0.10.5", "@bruits/satteri-linux-x64-gnu": "0.10.5", "@bruits/satteri-linux-x64-musl": "0.10.5", "@bruits/satteri-wasm32-wasi": "0.10.5", "@bruits/satteri-win32-arm64-msvc": "0.10.5", "@bruits/satteri-win32-x64-msvc": "0.10.5" } }, "sha512-Ao1LKpAEa9Wdg0otgbVKViZHEq9ebdXe4DMrp3s9vQAU0HNIuHnFEuMuOcm0ZIXyV0Yzxj91NvhLpvXZJO/5ZQ=="], - "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], @@ -2334,8 +2296,6 @@ "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.8", "", {}, "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q=="], - "@vitest/coverage-istanbul/magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="], - "ajv-formats/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], @@ -2380,18 +2340,8 @@ "storybook/@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="], - "storybook/@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="], - - "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - - "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - - "strip-ansi/ansi-regex": ["ansi-regex@6.3.0", "", {}, "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ=="], - "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], - "test-exclude/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], - "tsup/esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], "tsup/tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], @@ -2402,17 +2352,7 @@ "vite/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - "vite-node/es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], - - "vitest/tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], - - "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], - - "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - - "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "vitest/vite": ["vite@8.2.2", "", { "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.5", "postcss": "^8.5.26", "rolldown": "~1.2.4", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.4.0 || ^0.5.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q=="], "@astrojs/markdown-satteri/satteri/@bruits/satteri-darwin-arm64": ["@bruits/satteri-darwin-arm64@0.10.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-27KTVl4TJkVahMy/ohyA7qd4938G5UNneFUz/PsScYfpIhj0IVAS23mpcJXdPF44sa6nva198lmV/cKIb2YPyA=="], @@ -2476,9 +2416,9 @@ "storybook/@vitest/expect/@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="], - "test-exclude/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], + "storybook/@vitest/expect/chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], - "test-exclude/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + "storybook/@vitest/expect/tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="], "tsup/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], @@ -2534,16 +2474,10 @@ "unstorage/chokidar/readdirp": ["readdirp@5.1.1", "", {}, "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA=="], - "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "vitest/vite/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "eslint-plugin-jsx-a11y/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "storybook/@vitest/expect/@vitest/utils/@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="], - - "test-exclude/glob/minimatch/brace-expansion": ["brace-expansion@2.1.4", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg=="], - - "test-exclude/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - - "test-exclude/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], } } diff --git a/docs/migrations/2026-08-31-vite.md b/docs/migrations/2026-08-31-vite.md new file mode 100644 index 00000000..f4eb9e7c --- /dev/null +++ b/docs/migrations/2026-08-31-vite.md @@ -0,0 +1,270 @@ +# Migration Plan: `vite` 7.3.6 → 8.2.2, `@vitejs/plugin-react` 5.0.0 → 5.2.0 (NOT 6.x), `vitest` family 3.2.7 → 4.1.11 + +**Date:** 2026-08-31 +**Agent:** kirei-migrate +**Base branch:** `deps/typescript-6` (PR #466, stacked on PR #465 `deps/phase-1-safe-bumps`) — plan stacks on this branch's `bun.lock` and TypeScript 6.0.3 state. Do **not** plan against local `main` (stale) — see "Branch Staleness" below for a real trap this uncovered. +**Target:** `vite` `7.3.6` → `8.2.2`; `@vitejs/plugin-react` `5.0.0` → `5.2.0` (recommended target — **not** the latest `6.1.1`, see BC-B3); `vitest`/`@vitest/browser`/`@vitest/coverage-istanbul` `3.2.7` → `4.1.11`; `vitest-browser-react` `1.0.1` → `2.2.0`; new package `@vitest/browser-playwright@4.1.11`. +**Migration guides read:** vitest.dev/guide/migration.html (Vitest 4.0 migration guide), vitest.dev/config/browser/playwright (Playwright provider reference), vite.dev/guide/migration (Vite 8 migration from v7), npm registry `peerDependencies`/`dependencies` for every package version cited below (live-checked 2026-08-31, not from memory). + +## Summary — THE KEY QUESTION, answered decisively + +**The coupling between `vite` and the `vitest` family is one-directional, not symmetric. Recommendation: TWO sequential PRs, not one combined PR — this confirms the plan you already had; do not merge them.** + +Evidence (live npm peer-dependency data, not documentation prose): + +| | Declares peer/dep on `vite` | Does it accept the CURRENT vite (7.3.6)? | Does it accept the TARGET vite (8.2.2)? | +|---|---|---|---| +| `vitest@4.1.11` | `"vite": "^6.0.0 \|\| ^7.0.0 \|\| ^8.0.0"` | **yes** | **yes** | +| `vitest@3.2.7` (current, locked) | `"vite": "^5.0.0 \|\| ^6.0.0 \|\| ^7.0.0-0"` | yes (current state) | **no — does not declare `^8.0.0`** | + +So: **vitest 4 already supports the vite you have today (7.3.6)** — it does not need vite 8 to be useful. But **vite 8 is not supported by the vitest you have today (3.2.7)** — bumping vite alone, first, would leave `vitest@3.2.7`'s own declared range unsatisfied and put `vite-node`/vitest's internal Vite API usage against an untested major. The dependency only points one way: vitest-4-before-vite-8 is safe; vite-8-before-vitest-4 is not. + +This means the vitest-family migration can be fully absorbed, verified, and merged **on top of the existing vite 7.3.6** — isolating 100% of Vitest 4's own structural changes (browser-provider config rewrite, new required peer package, pool/coverage/projects renames) from Vite 8's own structural changes (esbuild→Rolldown dep-optimizer swap) so a red CI run always points at exactly one migration, not an entangled pair. Recommended order: **PR A = vitest family (vite stays 7.3.6) → merge & bake → PR B = vite 8 + plugin-react (vitest already proven on 4.x, satisfies vitest 4's `^8.0.0` peer immediately)**. + +**Second finding, equally load-bearing: `@vitejs/plugin-react`'s latest major (`6.1.1`) hard-requires `vite: "^8.0.0"` ONLY** (no `^7.0.0` in its peer range) — bumping plugin-react to latest would force vite 8 immediately, and would also swap the JSX/Fast-Refresh transform from Babel to an Oxc-based pipeline (Babel is removed as a dependency entirely in 6.0) — a second, independent bundler-internals swap stacked on the same PR as Vite 8's own esbuild→Rolldown dep-optimizer swap. **`@vitejs/plugin-react@5.2.0` (the latest 5.x patch, one minor ahead of the currently-locked `5.0.0`) already declares `"vite": "^4.2.0 \|\| ^5.0.0 \|\| ^6.0.0 \|\| ^7.0.0 \|\| ^8.0.0"`** — it supports vite 8 without forcing the Oxc transform swap. Recommendation: land vite 8 with plugin-react **5.2.0**, explicitly deferring the plugin-react 6.x / Babel-removal / Oxc-transform jump to its own future migration. This is a "defer part of it" outcome, not a full defer — vite itself is safe to move now. + +**Third finding: the documented CI-freeze trap (`optimized dependencies changed` mid-run silent hang, `docs/research/2026-07-11-ci-performance.md` flake F3) is the single highest-risk item in the whole migration, and it lands entirely in PR B (vite 8), not PR A.** Vite 8 replaces esbuild with Rolldown for dependency pre-bundling/optimization. The `optimizeDeps.include`/`exclude` config API is unchanged (verified directly against the installed `vite@8.2.2` type declarations — see BC-B1), so the existing guard's *shape* survives untouched. But the *engine* that decides when a dependency needs to be discovered/re-optimized mid-run changes from esbuild's scanner to Rolldown's — meaning the current `optimizeDeps.include` list (tuned empirically against esbuild's behavior) is not guaranteed to still be exhaustive under Rolldown's scanner. This cannot be resolved by reading docs; it needs empirical, repeated, cold-cache CI runs — see BC-B1 for the exact plan. + +**Overall verdict: proceed, staged.** Neither package is a "defer this" outcome the way TypeScript 7 was — both vite 8 and vitest 4 are viable targets today, verified against this repo's actual config and actual peer-dependency graph, not assumed. The risk is real but bounded and testable (BC-B1), and the two-PR split means each PR's CI run gives an unambiguous signal about which subsystem broke. + +## Branch Staleness — a real trap this research surfaced + +`deps/phase-1-safe-bumps` and `deps/typescript-6` both branched off `main` at `49f3e51c` (the `v0.4.0` release commit). Since then, **`origin/main` has moved 7 commits ahead**, including **PR #449 (`chore(web): migrate the Storybook family to 10.x`, merged 2026-08-01, `storybook`/`@storybook/react-vite`/`@storybook/addon-vitest`/`@storybook/addon-a11y` all now `10.5.5` in lockstep on real `main`)** and **PR #447 (`chore(tooling): drop tsconfig baseUrl for TypeScript 7 readiness`, merged after `deps/typescript-6` branched)** — the exact same `baseUrl` removal the TypeScript 6 migration plan (`docs/migrations/2026-08-31-typescript.md`, BC-1) independently prescribes. **`docs/deps/2026-08-31-dependency-upgrade-plan.md` (dated the same day as this doc) is itself stale on this point** — it lists Storybook 9→10 as a still-pending Phase 3 item, but that migration already shipped on `main` a month earlier. + +Concretely, the `deps/typescript-6` branch you're asked to plan against still shows `storybook`/`@storybook/*` at `^9.1.20` (verified: `apps/web/package.json` on this branch). This is **not blocking** for the vite/vitest migration — verified below that Storybook 9.1.20's `@storybook/addon-vitest` already declares the same `vitest: "^3.0.0 || ^4.0.0"` / `@vitest/browser-playwright: "^4.0.0"` peer support as the 10.5.5 version on `main` (both checked live via npm), so this migration works whether Storybook is at 9 or 10. But **whoever lands this PR stack needs to rebase onto current `origin/main` before or shortly after merging**, or `deps/phase-1-safe-bumps`/`deps/typescript-6`/this vite PR will merge into a `main` that has since diverged on Storybook, `baseUrl`, and 4 other unrelated commits (`#450`–`#452`, `#458`) — a real merge-conflict/double-baseUrl-removal risk, not a hypothetical one. Flagging this explicitly since it's outside this migration's own scope but will bite the first person who tries to land any of this stack without noticing. + +## Pre-flight Requirements + +- Runtime: **no change needed.** `vite@8.2.2` and `vite@7.3.6` both require `node: "^20.19.0 || >=22.12.0"`; `vitest@4.1.11` requires `node: "^20.0.0 || ^22.0.0 || >=24.0.0"`. Root `package.json` already declares `engines.node: ">=22"`, which satisfies both. +- Peer deps: none block either PR — see the coupling table above. `vitest-browser-react@2.2.0`'s peer (`vitest: "^4.0.0"`) is satisfied once vitest moves to 4.x (PR A). +- New required dependency: `@vitest/browser-playwright@4.1.11` must be added to `apps/web/package.json` devDependencies in PR A — both `vitest@4.1.11`'s browser-provider architecture AND `@storybook/addon-vitest` (9.1.20 on this branch, 10.5.5 on `main` — checked both) declare it as a **required** (non-optional) peer once vitest is on the 4.x line. `@vitest/browser` must be **kept**, not removed, despite the Vitest migration guide's own suggestion that it's "no longer needed" — `@storybook/addon-vitest` (both versions checked) still declares `@vitest/browser: "^3.0.0 || ^4.0.0"` as its own required peer, so removing it would break Storybook's vitest integration even though Vitest itself no longer needs it directly. +- Branch state: land PR A and PR B stacked on `deps/typescript-6`, but plan a rebase onto current `origin/main` before or immediately after this stack merges — see "Branch Staleness" above. + +## Breaking Changes & Call Sites — PR A: `vitest` family 3.2.7 → 4.1.11 (vite stays at 7.3.6) + +### BC-A1 — Browser provider config: string form removed, object-provider form required +**Type:** Structural, hand-edit (no codemod exists — confirmed no official Vitest 3→4 codemod is published; only unrelated Jest→Vitest/Mocha→Vitest codemods exist) +**What changed:** `test.browser.provider: 'playwright'` (string) is no longer valid. Vitest 4 requires importing a provider function from a new, separate package and calling it: `import { playwright } from '@vitest/browser-playwright'; provider: playwright({ ... })`. `browser.instances[]` entries that previously set `provider: 'playwright'` inline must drop that key entirely (the provider now lives one level up). +**Call site:** `apps/web/vitest.config.ts:14-28`, the shared `chromium()` helper used by BOTH the `storybook` project (line ~108) and the `unit` project (line ~158): +```ts +const chromium = () => ({ + enabled: true, + provider: 'playwright' as const, + headless: true, + instances: [ + { browser: 'chromium' as const, context: { reducedMotion: 'reduce' as const } }, + ], +}); +``` +**Fix (verified against the official Vitest 4 config reference, `vitest.dev/config/browser/playwright`):** +```ts +import { playwright } from '@vitest/browser-playwright'; + +const chromium = () => ({ + headless: true, + provider: playwright({ + contextOptions: { reducedMotion: 'reduce' }, + }), + instances: [{ browser: 'chromium' as const }], +}); +``` +The per-instance `context: { reducedMotion: ... }` field must move to the provider's `contextOptions` — the docs are explicit that `contextOptions` is a documented, stable field of the `playwright()` call, while per-instance `context`/`contextOptions` overrides are ambiguously documented (instance-level `provider: playwright({...})` overrides do **not** merge with the parent per the docs — riskier to rely on). Since this repo runs exactly one instance (chromium) per project with no per-instance divergence, moving `contextOptions` to the single provider call is the unambiguous, doc-confirmed shape. Apply the same rewrite to both the `storybook` and `unit` project's `browser: chromium()` usage (they share the one helper, so this is a single-function edit, not two). + +### BC-A2 — `@vitest/browser/context` import path deprecated +**Type:** Mechanical, codemod-able via `sed` (not a published codemod, but a trivial one-line-per-file substitution) +**What changed:** `import { userEvent } from '@vitest/browser/context'` still works in v4 but is deprecated in favor of `import { userEvent } from 'vitest/browser'`. +**Call sites:** 36 files, all `apps/web/src/**/*.test.tsx` (component tests using `userEvent` for interaction testing) — e.g. `apps/web/src/components/ui/Tooltip/Tooltip.test.tsx:2`, `apps/web/src/components/board/NewTaskForm/NewTaskForm.test.tsx:2`, `apps/web/src/components/terminal/TerminalPane/TerminalPane.test.tsx:2`, and 33 more (full list: `grep -rl "from '@vitest/browser/context'" apps/web/src`). +**Fix:** repo-wide `sed -i '' "s/@vitest\/browser\/context/vitest\/browser/" $(grep -rl "from '@vitest/browser/context'" apps/web/src)`. Not strictly required to land PR A (old path still works in v4), but cheap to do in the same PR since you're already touching this config surface — recommend including it to avoid carrying a known-deprecated import into the codebase. If minimizing PR A's diff is preferred, this can be split into a trivial mechanical follow-up instead. + +### BC-A3 — `mock.invocationCallOrder` now starts at 1 (was 0) — CHECKED, no fix needed +**Type:** Behavioral, but verified as a false positive for this repo +**What changed:** Vitest 4's global mock-invocation counter is 1-indexed instead of 0-indexed. +**Call sites (3, all the same pattern):** `apps/web/src/components/worktree/worktree-terminal.test.tsx:104-105`, `apps/web/src/components/worktree/WorktreeView/WorktreeView.hooks.test.tsx:110-111` and `:125-126` — each does `expect(mockA.mock.invocationCallOrder[0]!).toBeLessThan(mockB.mock.invocationCallOrder[0]!)`. +**Why it's safe:** these are **relative** comparisons between two mocks that share the same global call-order counter. A uniform +1 shift to the whole counter preserves relative ordering — `toBeLessThan` still evaluates correctly. No call site in this repo asserts an *absolute* `invocationCallOrder` value (e.g. `toBe(0)`), which is the only pattern the 0→1 shift would actually break. Verified by reading all 3 files in full context — no fix needed. + +### BC-A4 — `vi.restoreAllMocks()` no longer restores automocks — CHECKED, no fix needed +**Type:** Behavioral, but verified as a false positive for this repo +**What changed:** In v4, `vi.restoreAllMocks()` restores manually-created spies (`vi.spyOn`, standalone `vi.fn()`) but not "automocks" (`vi.mock('module')` called **without** a factory function, letting Vitest auto-generate replacements for every export). +**Call sites checked:** `apps/web/src/lib/logger.test.tsx:6` (uses `vi.spyOn(console, 'error')` — a manual spy, unaffected) and `apps/web/src/components/terminal/terminal-session-manager.test.tsx:27` (uses only locally-scoped `vi.fn()`, no `vi.mock()` at all — unaffected either way). `packages/eslint-plugin/vitest.config.ts` also sets `restoreMocks: true` globally. +**Why it's safe repo-wide:** grepped **every** `vi.mock(` call in `apps/web/src` (75 total) and `packages/eslint-plugin` (0 total) — **zero** are automocks; every single one supplies an explicit factory function (`vi.mock('module', () => ({...}))`), which is not the "automock" pattern this behavior change affects. No fix needed anywhere in the repo. + +### BC-A5 through BC-A9 — checked against the full Vitest 4 migration-guide changelist, confirmed already-compliant or not-applicable +- **`coverage.include` now required explicit** — `apps/web/vitest.config.ts` already sets `coverage.include: ['src/**']` explicitly. Compliant, no change. +- **Coverage provider is `istanbul`, not `v8`** — the V8-specific AST-remapping/`coverage.all`/`coverage.experimentalAstAwareRemapping` removals in the migration guide only affect the `v8` coverage provider. This repo uses `provider: 'istanbul'`. Not applicable. +- **`workspace` renamed to `projects`, external workspace file removed** — repo already uses inline `test.projects: [...]` directly in `vitest.config.ts` (confirmed: no `vitest.workspace.*` file exists anywhere in the repo). Already compliant. +- **Pool architecture rename (`maxThreads`/`maxForks`/`poolOptions`/`singleThread`/`singleFork` → `maxWorkers`/`isolate`)** — none of these options are set in either `apps/web/vitest.config.ts` or `packages/eslint-plugin/vitest.config.ts`. Not applicable. +- **Reporter API removals (`onCollected` etc., `basic` reporter)** — no custom `reporters:` config anywhere in the repo. Not applicable. +- **`deps.optimizer.web` → `deps.optimizer.client`** — not configured anywhere. Not applicable. +- **Companion peer requirement: `@storybook/addon-vitest` requires `@vitest/browser-playwright: "^4.0.0"`** — checked live against both the currently-locked `9.1.20` and `main`'s `10.5.5`; both declare this peer as required (not in `peerDependenciesMeta`). Already covered by the pre-flight requirement above — must add this package in PR A regardless of which Storybook major is present. + +## Breaking Changes & Call Sites — PR B: `vite` 7.3.6 → 8.2.2 + `@vitejs/plugin-react` 5.0.0 → 5.2.0 + +### BC-B1 — Dependency-optimizer engine swap: esbuild → Rolldown (THE highest-risk item in this whole migration) +**Type:** Behavioral, engine-level — config API survives, discovery *behavior* does not carry a guarantee +**What changed:** Vite 8 replaces esbuild with Rolldown (a Rust bundler) for dependency pre-bundling/scanning. `optimizeDeps.esbuildOptions` is deprecated in favor of `optimizeDeps.rolldownOptions` (auto-converted for backward compat) — this repo doesn't use `esbuildOptions` anywhere, so no forced config edit there. + +**Verified directly against the installed packages (not assumed from docs):** diffed `vite@7.3.6`'s and `vite@8.2.2`'s `DepOptimizationConfig` TypeScript interface (both already present in this repo's `node_modules/.bun/`, the 8.2.2 copy pulled transitively via the `docs` workspace's `astro` dependency) — **`optimizeDeps.include` and `optimizeDeps.exclude` (`string[]` of resolvable import paths) are byte-identical in shape between the two versions.** The three existing guard locations' config API is untouched: +- `apps/web/vitest.config.ts:79-104` (`storybook` project `optimizeDeps.include`) +- `apps/web/vitest.config.ts:128-150` (`unit` project `optimizeDeps.include`, near-identical list) +- `apps/web/.storybook/main.ts:14-29` (`viteFinal` hook's `optimizeDeps.include`, used by real `storybook dev`/`build-storybook`, not just the vitest addon-vitest gate) + +**What is NOT guaranteed:** the current include lists (`react-dom/client`, `@storybook/react-dom-shim`, `motion/react`, `lucide-react`, `@dnd-kit/core`, the 4 `@xterm/*` addon packages, `@tauri-apps/api/webview`, plus `storybook/test`/`storybook/actions` in the Storybook config) were tuned empirically against **esbuild's** dependency scanner — specifically to catch modules that would otherwise be discovered mid-run and trigger the documented silent-hang trap (`docs/research/2026-07-11-ci-performance.md`, flake F3: a `"optimized dependencies changed"` reload orphans an in-flight browser test page, and the vitest server then waits forever with zero output — capped only by the CI step timeout). **Rolldown's dependency-scanning algorithm is a different implementation and is not guaranteed to discover (or fail to discover) the same set of modules in the same order as esbuild's scanner did.** This cannot be resolved by reading changelogs — it can only be resolved empirically. + +**What the plan must do to keep the guard effective:** +1. The CI cache `apps/web/node_modules/.vite` (`.github/workflows/ci.yml`, `web-coverage` job) is keyed on `hashFiles('bun.lock')` — bumping `vite`/`vitest` changes `bun.lock`, which **guarantees this PR's own first CI run is a cold-cache run**, i.e. exactly the highest-risk condition for the trap. This is actually useful: it means the PR's own CI gives a real cold-cache stress test for free, not a false-green from a stale warm cache. +2. Given F3's history shows the trigger is **nondeterministic** (it surfaced once in a 45-run sample per the CI-performance doc), a single green CI run on this PR is not sufficient evidence. Run `bun run test:web:coverage` locally **multiple times with a deleted `apps/web/node_modules/.vite` directory before each run** (`rm -rf apps/web/node_modules/.vite && bun run test:web:coverage`), and push at least 2-3 throwaway commits to the PR branch to get multiple independent cold CI runs, watching every log for the literal string `optimized dependencies changed` (the diagnostic signature). +3. If that string appears in any run: the vitest server log names the specific module that triggered the mid-run discovery (per the existing code comments' own description of this failure mode) — add that module to `optimizeDeps.include` in whichever of the 3 guard locations is relevant (both vitest projects if it's a browser-mode-shared dependency; `.storybook/main.ts` too if it's Storybook-specific) and re-run the cold-cache loop again until clean. +4. **Do not weaken or remove the existing `timeout-minutes: 7` step-level timeout** (`ci.yml`, the `bun run test:web:coverage` step) or the `timeout-minutes: 10` job-level timeout — these are what turn a would-be infinite hang into a fast, diagnosable red instead of burning the full job timeout. They remain valid and necessary under Rolldown exactly as they were under esbuild; this migration doesn't change what they defend against, only which engine can trigger the condition they defend against. +5. Treat one CI red on this specific PR as expected-possible, not a blocker signal to abandon the migration — the fix path (add the named module to the include list) is well-understood and cheap; budget for 1-2 iterations before declaring PR B stable. + +### BC-B2 — `vite/client.d.ts` CSS side-effect module declaration — VERIFIED INTACT, no fix needed +**Type:** N/A (verification, not a breaking change) +**Why this matters:** the TypeScript 6 migration (`docs/migrations/2026-08-31-typescript.md`, BC-2) flips `noUncheckedSideEffectImports` to `true` by default, and this repo's 5 CSS side-effect imports (`apps/web/src/main.tsx:2` `import './styles.css'`, plus 3× `import '@xterm/xterm/css/xterm.css'` in the terminal pane components) only typecheck because `vite/client.d.ts` ships `declare module '*.css' {}`. If Vite 8 dropped that declaration, this vite migration would silently re-break the just-landed TS 6 migration's guard. +**Verified directly, not assumed:** diffed the actual `client.d.ts` files from `vite@7.3.6` and `vite@8.2.2` (both already installed in this repo's `node_modules/.bun/`). **Both declare `'*.css' {}`, `'*.scss' {}`, `'*.sass' {}` identically** (line 40 vs line 43, offset only by 3 added lines earlier in the file — `vite/modulepreload-polyfill` and `*.wasm` declarations, both pure additions). No removals in the diff. The TS 6 `noUncheckedSideEffectImports` guard is unaffected by this vite bump. No fix needed. + +### BC-B3 — `@vitejs/plugin-react` 6.x peer range narrows to `vite: "^8.0.0"` only, and removes Babel +**Type:** Structural (peer range) + behavioral (transform engine swap) — this is why the recommendation is to stay on 5.2.0 +**What changed:** `@vitejs/plugin-react@6.0.0`+ declares `"vite": "^8.0.0"` exclusively (verified via `npm view @vitejs/plugin-react@6.0.0/6.0.1/6.1.0/6.1.1 peerDependencies` — all four consistently show only `^8.0.0`). It also removes Babel as a dependency entirely (install size ~45MB → ~8MB per the plugin's own release notes) in favor of an Oxc-based React Refresh transform, with React Compiler support moved behind an explicit opt-in (`oxc-transform-react`, `@rolldown/plugin-babel` as new optional peers) rather than the current Babel-based default. +**Call site:** `apps/web/package.json:49` (`"@vitejs/plugin-react": "^5.0.0"`), consumed in `apps/web/vite.config.ts:4,11` (`import react from '@vitejs/plugin-react'; ... plugins: [react(), tailwind()]`) and `apps/web/vitest.config.ts:5,115` (`unit` project's `plugins: [react(), tailwind()]`). +**Fix / recommendation:** bump to `@vitejs/plugin-react@5.2.0` (the latest 5.x, one minor ahead of the currently-locked `5.0.0`), **not** `6.1.1`. `5.2.0`'s peer range (`"^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"`, verified live) already covers vite 8 — confirmed directly by the plugin's own maintainers' migration notes: "v5 still works with Vite 8, so you can upgrade the plugin after upgrading Vite." This keeps the well-tested Babel-based JSX/Fast-Refresh transform in place and avoids stacking a second bundler-internals swap (Oxc transform) on top of BC-B1's Rolldown dep-optimizer swap in the same PR. No code-site changes needed beyond the version bump — the plugin's exported `react()` factory API is unchanged between 5.2.0 and current 5.0.0. +**Deferred, explicitly out of scope for this migration:** `@vitejs/plugin-react` 6.x / the Babel-removal / Oxc-transform jump. Revisit as its own future migration once Vite 8 + Vitest 4 have baked in production for a cycle, so any regression is attributable to one bundler-internals change at a time, not two. + +### BC-B4 — Default `build.target` browser baseline moves forward +**Type:** Behavioral, low risk for this repo +**What changed:** Vite 8's default `build.target` moves from Chrome 107/Edge 107/Firefox 104/Safari 16.0 to Chrome 111/Edge 111/Firefox 114/Safari 16.4 (aligned to "Baseline Widely Available" as of 2026-01-01). +**Call site:** `apps/web/vite.config.ts:23-25` already sets `build: { target: 'es2022' }` explicitly — this **overrides** Vite's own default target regardless of version, so this default-flip has zero observable effect here. Since the shipped app is a Tauri desktop frontend rendered in each OS's bundled WebKit/WebView2 (not a range of public browsers), the explicit `es2022` target is also the semantically correct choice independent of Vite's own default — no action needed. + +### BC-B5 — Tauri interaction — verified no coupling +**Type:** N/A (verification) +`apps/desktop/src-tauri/tauri.conf.json`'s `build` section (`devUrl: "http://localhost:5173"`, `beforeDevCommand`/`beforeBuildCommand` shelling out to `vite`/`vitest`-agnostic `bun run` scripts) has no Vite-major-specific requirement — Tauri's CLI (`@tauri-apps/cli@^2.11.2`, unrelated to this migration) just polls the configured `devUrl` over HTTP until it responds and serves `frontendDist` (`../../web/dist`) as static files at build time; it does not import or version-check the `vite` package. No `vite-plugin-tauri` or equivalent Tauri-specific Vite plugin is used (grepped both `vite.config.ts` and `vitest.config.ts` — no Tauri-specific imports beyond an `optimizeDeps.include` entry for `@tauri-apps/api/webview`, which is a runtime module path, not a build coupling). Zero interaction with this migration. + +### BC-B6 — `envPrefix` / `import.meta.env` — not applicable +**Type:** N/A (verification) +Grepped the entire `apps/web` tree for `envPrefix`, `VITE_`, and `import.meta.env` — **zero matches**. Tauri-detection in this codebase is a pure runtime check (`apps/web/src/lib/bridge/internal.ts:11`: `'__TAURI_INTERNALS__' in window`), not an env-var injected via Vite's `define`/`envPrefix` machinery. This entire class of Vite behavior is unused by the repo; nothing to migrate. + +## Companion Bumps / Lockstep Requirements + +| Package | Must move with | Why | +|---|---|---| +| `@vitest/browser`, `@vitest/coverage-istanbul` | `vitest` (exact) | Both declare `peerDependencies: { "vitest": "4.1.11" }` — an **exact** version peer (Vitest's own sub-packages always pin exact versions against each other), not a caret range. All three must land in the same commit at the same resolved version. | +| `vitest-browser-react` | `vitest` (^4.0.0) | `peerDependencies.vitest: "^4.0.0"` | +| `@vitest/browser-playwright` (new) | `vitest` (exact, 4.1.11) | New required package, not previously in the tree — see pre-flight. | +| `@storybook/addon-vitest` | none required, but re-verify | Already declares `vitest: "^3.0.0 || ^4.0.0"` and `@vitest/browser-playwright: "^4.0.0"` on both the `9.1.20` (this branch) and `10.5.5` (`main`) versions — no Storybook bump is *required* by this migration either direction, but do re-run `bun run test:stories` explicitly after PR A since this is the addon that actually drives vitest's browser mode for the Storybook project. | +| `@vitejs/plugin-react` | `vite` (peer range) | See BC-B3 — land `5.2.0` with vite `8.2.2` in the same PR B commit (it's a devDependency version bump, not independently useful without vite moving). | +| `motion`/`framer-motion`/`motion-dom` overrides (from `deps/phase-1-safe-bumps`, root `package.json` `overrides` block, pinned exact `12.42.2`) | no interaction | Runtime animation library, no build-tool/vite peer dependency. Checked, no interaction with either PR. | +| `@hono/node-server` override (from `deps/phase-1-safe-bumps`) | no interaction | Server-side MCP-transport package via `@anthropic-ai/claude-agent-sdk`, entirely unrelated to the frontend Vite/Vitest stack. No interaction. | + +## Codemods Available + +**None.** Confirmed no official Vitest 3→4 codemod exists (only unrelated Jest→Vitest and Mocha→Vitest codemods are published under the `codemod` registry). Vite itself does not publish a codemod for the 7→8 transition — it is a config-and-defaults release plus an internal engine swap, not an API-rename release. BC-A2 (the `@vitest/browser/context` import path) is the only item in this whole plan that is genuinely mechanical/`sed`-able across many files; everything else is either a single hand-written config rewrite (BC-A1) or a checked-safe no-op (BC-A3, BC-A4, BC-B2, BC-B4, BC-B5, BC-B6). + +## Upgrade Order + +**PR A — `vitest` family (land first, vite stays 7.3.6):** +1. Branch from `deps/typescript-6`. +2. `apps/web/package.json`: bump `vitest`, `@vitest/browser`, `@vitest/coverage-istanbul` to `4.1.11`; `vitest-browser-react` to `2.2.0`; add `@vitest/browser-playwright@4.1.11` as a new devDependency. Keep `@vitest/browser` (do not remove it — see pre-flight). +3. `packages/eslint-plugin/package.json`: bump `vitest` to `^4.1.11`. +4. Rewrite `apps/web/vitest.config.ts`'s `chromium()` helper per BC-A1 (import `playwright` from `@vitest/browser-playwright`, move `contextOptions` to the provider call). +5. (Optional, same PR or a trivial follow-up) sweep the 36-file `@vitest/browser/context` → `vitest/browser` import rename per BC-A2. +6. `bun install` to refresh `bun.lock`. +7. Run in order, fixing forward on red: `bunx tsc -b apps/web` → `bun run --filter @nightcore/web test:unit` → `bun run --filter @nightcore/web test:stories` → `bun run test:web:coverage` (repeat 2-3× with `rm -rf apps/web/node_modules/.vite` between runs, watching for `optimized dependencies changed` per BC-B1's guidance even though it's nominally a PR-B item — the Module Runner replacing vite-node internally is itself a Vitest-4-side change worth the same cold-cache scrutiny) → `bun run test:plugin` (exercises `packages/eslint-plugin`'s vitest bump). +8. Push, let CI's cold `bun.lock`-keyed cache stress-test this for real; iterate on the include lists only if a concrete `optimized dependencies changed` log line appears. +9. Merge PR A. Bake before starting PR B (at minimum, one full CI cycle post-merge with no new reds). + +**PR B — `vite` 8 + `@vitejs/plugin-react` (land after PR A is merged and stable):** +1. Branch from the post-PR-A tip (i.e. `deps/typescript-6` + PR A's commits). +2. `apps/web/package.json`: bump `vite` to `8.2.2`, `@vitejs/plugin-react` to `5.2.0` (**not** `6.1.1` — see BC-B3). +3. No config-shape edits are required for `optimizeDeps.include`/`exclude` (BC-B1 confirms the API is unchanged) — this PR's job is verification, not rewriting. +4. `bun install` to refresh `bun.lock`. +5. Run in order: `bunx tsc -b apps/web` → `bun run --filter @nightcore/web build` (exercises the actual `vite build` path, not just tests) → `bun run test:web:coverage`, repeated 2-3× with a deleted `.vite` cache dir per BC-B1's cold-cache loop, watching specifically for `optimized dependencies changed`. If it appears, add the named module to `optimizeDeps.include` in whichever of the 3 guard locations applies and re-loop. +6. Manually smoke-test `bun run desktop` (the real Tauri dev flow, `beforeDevCommand` → `vite --port 5173` → Tauri's `devUrl` poll) once, since BC-B5 is a "checked, no coupling" claim, not a substitute for actually booting the app once against the new Vite major. +7. Push, let CI's cold cache run for real (guaranteed cold since `bun.lock` changes again). +8. Merge PR B once green and the cold-cache loop has produced at least 2-3 consecutive clean runs, not just 1. + +## Verification + +- `bun run typecheck` (root `tsc -b`), `bunx tsc -b apps/web` clean at both PR A and PR B. +- `bun run lint` (incl. `lint:meta`) clean — no lint-meta rule references `vite`/`vitest` package internals directly (confirmed by grep), so this should be a pure pass-through, but run it anyway since it's part of the required gate battery. +- `bun run test:node`, `bun run test:plugin`, `bun run test:rust` green at both stages (these don't exercise the browser/vite-dev-server path directly, but `test:plugin` does exercise the `packages/eslint-plugin` vitest bump from PR A). +- `bun run test:web` (both vitest projects — `test:unit` and `test:stories`) green at both stages. +- **`bun run test:web:coverage` / the `vitest browser coverage (apps/web)` CI job** — the primary gate for this whole migration. Must be green with **repeated cold-cache runs** (not a single pass) per BC-B1's guidance, at both PR A and PR B. This is the literal file-size-ratchet-adjacent required check named in the repo's merge-gate ruleset (`docs/research/2026-07-11-ci-performance.md`). +- `bun run audit` still clean at both stages (a devDependency-only bump; not expected to introduce new advisories, but touches `bun.lock` so worth a quick re-check per the sibling dependency-upgrade-plan doc's own caution). +- File-size ratchet (`tools/lint-meta`'s `web-file-size-ratchet` rule) — the `vitest.config.ts` rewrite (BC-A1) and the 36-file import rename (BC-A2) both touch tracked files; unlikely to trip the ratchet (small diffs) but part of `bun run lint:meta`'s normal pass, no special action. +- Manual: boot `bun run desktop` once after PR B and confirm the Tauri window loads the dev server correctly (per BC-B5's upgrade-order step 6) — this is the one item in the whole plan that genuinely needs a human eyeball, not just green CI, since it's the actual shipped product surface this migration touches. + +## Rollback + +Both PRs are dev-tooling-only changes (`vite`/`vitest`-family devDependencies, one config file rewrite, 36 mechanical import-path edits, `bun.lock`) — zero production runtime code is touched beyond `apps/web/vite.config.ts`'s plugin version and `vitest.config.ts`'s test-only config. Rollback for either PR is a plain `git revert` of its merge commit — no data/state/migration concerns, no feature flags needed. Because the two PRs are sequential and independently revertible, a regression discovered after PR B merges can be resolved by reverting **only PR B** (returning to vite 7.3.6 + vitest 4.1.11, a state this plan explicitly verifies is valid per the coupling table in the Summary) without also reverting PR A's vitest-4 work. + +## Out of Scope + +- `@vitejs/plugin-react` 6.x (Babel removal, Oxc transform pipeline) — explicitly deferred, see BC-B3. Revisit as its own migration once vite 8 + vitest 4 have baked. +- Storybook 9→10 (already shipped on `main` via PR #449, not present on `deps/typescript-6` — see "Branch Staleness"). Not this migration's job to backport or re-verify; flagged as a sequencing risk for whoever lands this stack. +- Any other Phase 2/3/4 item from `docs/deps/2026-08-31-dependency-upgrade-plan.md` (dompurify, tauri-plugin-updater, shiki, marked, claude-agent-sdk, codex-sdk, motion 13.x, glib) — separate migrations, not touched here. +- Rolldown-native / raw-Rolldown usage, `@vitejs/plugin-react-oxc` (explicitly deprecated by the plugin-react maintainers in favor of the 6.x default — moot since this plan stays on 5.2.0 anyway). +- Wiring an explicit `optimizeDeps.rolldownOptions` config — not needed; the repo doesn't use `esbuildOptions` today, so there's nothing to migrate/convert, and `include`/`exclude` remain the only guard surface in use. + +--- + +## POST-IMPLEMENTATION CORRECTIONS — PR A, as actually landed (2026-08-31) + +Landing PR A surfaced four things this plan got wrong or missed. **Read this section before starting PR B** — two of them invalidate premises the PR B plan above is built on. + +### CORRECTION 1 (invalidates the two-PR premise): vite 8 arrives with PR A regardless — `vite` is a `dependencies` entry of vitest 4, not just a peer + +The Summary's coupling table reads `vitest@4.1.11`'s **`peerDependencies`** only. But `vitest@4.1.11` declares `"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"` in **BOTH `peerDependencies` AND `dependencies`**. A real dependency is resolved by the package manager, not satisfied by the hoisted copy, and bun picks the highest satisfying version — `vite@8.2.2`, which `astro` (docs workspace) has already pulled into the tree. + +Result, verified on disk after `bun install`: + +- `node_modules/vite` → **7.3.6** (what `vite build` / `vite dev` use — the app build genuinely stays on vite 7) +- `node_modules/vitest/node_modules/vite` → **8.2.2** (what the vitest browser dev-server and dep-optimizer actually run) + +Confirmed at runtime, not just in the lockfile — `test:unit` logs: + +``` +[vite] warning: `optimizeDeps.esbuildOptions` option was specified by "vite:react-babel" plugin. + This option is deprecated, please use `optimizeDeps.rolldownOptions` instead. +You or a plugin you are using have set `optimizeDeps.esbuildOptions` but this option is now +deprecated. Vite now uses Rolldown to optimize the dependencies. +``` + +**So BC-B1 — the esbuild→Rolldown dep-optimizer swap, named above as "THE highest-risk item in this whole migration" — already landed in PR A.** The test suite is running on Rolldown today. + +This could not be prevented. Attempted and rejected: +- `resolutions: { "vitest/vite": "7.3.6" }` — bun 1.3.14 silently ignores scoped/nested patterns (no re-resolve). +- `overrides: { "vitest": { "vite": "7.3.6" } }` — bun ignores npm's nested-override form too. +- A flat `overrides: { "vite": "7.3.6" }` — would apply globally and break `astro@7.1.6`, which hard-requires `vite: ^8.0.13`. + +**Consequences for PR B:** PR B is now only "the *app build* moves to vite 8 + plugin-react 5.2.0". The Rolldown risk is already paid and measured (see CORRECTION 4). The plan's rollback claim — that reverting PR B returns you to "vite 7.3.6 + vitest 4.1.11" — is **wrong**: vitest carries its own vite 8 either way. + +### CORRECTION 2 (missed breaking change): `vitest-browser-react@2.x` made `render()` async + +Not mentioned anywhere above. `vitest-browser-react@2.x` changed `render()` from returning `RenderResult` to `Promise`. Bumping to `2.2.0` as the plan prescribes breaks **218 test files** — and not merely at the type level: it fails at runtime (`TypeError: disabled.unmount is not a function`), because every `render(...).getByRole(...)` / `.unmount()` chain now runs against a Promise. + +**Resolution: `vitest-browser-react` was deliberately held at `^1.0.0` (1.0.1).** Its peer range is `vitest: "^2.1.0 || ^3.0.0 || ^4.0.0-0"` and `@vitest/browser: "^2.1.0 || ^3.0.0 || ^4.0.0-0"` — `^4.0.0-0` semver-satisfies `4.1.11`, so 1.0.1 is a *supported* combination with vitest 4, not a hack. Verified: the full 517-file / 2953-test suite passes on it. + +The `1.x → 2.x` async-`render()` migration is real work (218 files, plus making the enclosing `test()` callbacks async) and belongs in **its own PR**, not bolted onto either vite PR. + +### CORRECTION 3 (missed blocker): Storybook pins `@vitest/spy@3.2.4` exactly → dual-package type skew + +The plan checked `@storybook/addon-vitest`'s peer *ranges* (`vitest: "^3.0.0 || ^4.0.0"`) and concluded Storybook 10.5.5 is vitest-4-ready. Its **`dependencies`** tell a different story: `storybook@10.5.5` depends on `@vitest/spy` at the **exact** version `3.2.4`. With vitest 4 hoisted at the root, bun keeps two copies, and their `Mock` types are structurally incompatible (vitest 4 added `MockSettledResultIncomplete` to `MockSettledResult`). Any test passing a `vi.fn()` into a composed story's args fails to typecheck: **159 errors across 69 files**. + +No released Storybook fixes this — `storybook@10.5.10` (current `latest`) still pins `@vitest/spy@3.2.4`. + +**Resolution: a root `overrides` entry, `"@vitest/spy": "4.1.11"`,** collapsing the two copies to one. `apps/web` typecheck goes 159 errors → 0, and all 2953 tests (including every Storybook play test, which exercise `fn()` from `storybook/test` heavily) pass against it. + +⚠ **This override crosses a major for Storybook (3.2.4 → 4.1.11) and therefore sits in tension with the documented override policy** in root `package.json` (`"//overrides"`): *"An override forces a PATCHED version. It never crosses a major."* It passes `bun run audit` — `assertOverridesBounded` treats exact pins as inherently bounded — so the automated gate does not catch it. It is recorded here because the policy's own escape clause covers exactly this case: *"If the patched version exists ONLY across a major, that is a dependency bump to review on its own."* Mitigations: `@vitest/spy` is dev-only test tooling with no runtime/product surface; and it must be bumped in lockstep with `vitest` (which depends on it at an exact version), so treat this entry as part of the vitest family, not an independent pin. **Revisit and delete it as soon as a Storybook release ships `@vitest/spy` 4.x.** + +### CORRECTION 4: the F3 cold-cache trap did NOT reproduce — measured, not assumed + +Because CORRECTION 1 means Rolldown is already live, PR A was stress-tested to PR B's standard: `bun run test:web` run **3 times, each with `rm -rf apps/web/node_modules/.vite` first**. All three: **517 files / 2953 tests passed, zero occurrences of `optimized dependencies changed`.** The existing `optimizeDeps.include` lists — tuned empirically against esbuild's scanner — appear to remain sufficient under Rolldown's. No include-list additions were needed. PR B should still repeat the cold-cache loop, but the `optimizeDeps` guard now has real evidence behind it, not just an assumption. + +### CORRECTION 5 (missed call site): `apps/web/tsconfig.json` `types` entry + +Not listed among BC-A1's call sites. `@vitest/browser@4` dropped its `./providers/*` export entries (and the `"./*"` wildcard), so `"types": ["vite/client", "@vitest/browser/providers/playwright"]` no longer resolves. Replaced with the provider package's types-only export: `"@vitest/browser-playwright/context"`. + +### Also landed in PR A + +- `.gitignore`: Vitest 4 writes failure screenshots to a new `**/.vitest-attachments/` directory (alongside the already-ignored `**/__screenshots__/`). Ignored, so test runs don't leave untracked binaries. +- BC-A2's 36-file `@vitest/browser/context` → `vitest/browser` sweep was included. It required an `eslint --fix` pass afterwards: the new specifier sorts differently under `simple-import-sort`, tripping the lint gate in all 36 files. +- BC-A3 and BC-A4 were confirmed correct — no `invocationCallOrder` or automock fixes were needed. diff --git a/package.json b/package.json index 15c95111..377cf41f 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "js-yaml": ">=4.3.1 <5", "@hono/node-server": ">=1.19.15 <2", "framer-motion": "12.42.2", - "motion-dom": "12.42.2" + "motion-dom": "12.42.2", + "@vitest/spy": "4.1.11" } } diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 55fcbf1c..3c67a798 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -29,7 +29,7 @@ "@typescript-eslint/rule-tester": "^8.68.0", "tsup": "^8.5.1", "typescript": "^6.0.3", - "vitest": "^3.2.7" + "vitest": "^4.1.11" }, "peerDependencies": { "eslint": ">=9.0.0",