diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..6ef4f80 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,135 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Common Development Commands + +### Installation and Setup + +```bash +# Install dependencies using pnpm (recommended) +pnpm install + +# Or using npm +npm install +``` + +### Development + +```bash +# Start development server on http://localhost:3000 +pnpm dev + +# Build the project +pnpm build + +# Start production server +pnpm start + +# Process MDX files (runs automatically after install) +pnpm postinstall +``` + +### Code Quality + +```bash +# Run linting +pnpm lint + +# Run type checking +pnpm typecheck + +# Check image compliance with project rules +pnpm lint:images + +# Migrate images to proper directory structure +pnpm migrate:images +``` + +### Git Commits + +- The project uses Husky for git hooks and lint-staged for pre-commit formatting +- Prettier will automatically format files on commit +- On Windows + VSCode/Cursor, use command line (`git commit`) instead of GUI to avoid Husky bugs + +## Project Architecture + +### Tech Stack + +- **Framework**: Next.js 15 with App Router +- **Documentation**: Fumadocs MDX (文档系统) +- **Styling**: Tailwind CSS v4 +- **UI Components**: Fumadocs UI + custom components +- **Authentication**: NextAuth (beta) +- **AI Integration**: Vercel AI SDK with Assistant UI +- **Database**: Prisma with Neon (PostgreSQL) + +### Directory Structure + +``` +app/ +├── api/ # API routes (auth, chat, docs-tree) +├── components/ # React components +│ ├── assistant-ui/ # AI assistant components +│ └── ui/ # Reusable UI components +├── docs/ # MDX documentation content +│ ├── ai/ # AI-related documentation +│ ├── computer-science/ # CS topics +│ ├── frontend/ # Frontend development +│ └── [...slug]/ # Dynamic routing for docs +├── hooks/ # Custom React hooks +└── layout.tsx # Root layout with providers +``` + +### Documentation Structure + +- Uses "Folder as a Book" pattern - each folder can have an `index.mdx` for overview +- URLs are auto-generated from file structure (e.g., `docs/ai/llm-basics/index.mdx` → `/ai/llm-basics`) +- File naming: use `kebab-case` and numeric prefixes for ordering (e.g., `01-intro.mdx`) +- Numeric prefixes are stripped from final URLs + +### Image Management + +- Images should be placed in `./.assets/` directory alongside the MDX file +- Example: `foo.mdx` → images go in `./foo.assets/` +- Auto-migration scripts handle image placement during commits +- Site-wide images: `/images/site/*` +- Component demos: `/images/components//*` + +### MDX Frontmatter + +Required fields: + +```yaml +--- +title: Document Title +--- +``` + +Optional fields: + +```yaml +--- +description: Brief description +date: "2025-01-01" +tags: + - tag1 + - tag2 +--- +``` + +### Key Features + +1. **AI Assistant**: Integrated chat interface with support for multiple AI providers +2. **Internationalization**: Using next-intl for multi-language support +3. **Search**: Orama search integration for documentation +4. **Comments**: Giscus integration for discussion +5. **Math Support**: KaTeX for mathematical expressions +6. **Authentication**: GitHub OAuth integration + +### Development Considerations + +- The project uses Fumadocs for documentation, refer to [Fumadocs docs](https://fumadocs.dev/docs) for UI components +- Math expressions use remark-math and rehype-katex plugins +- Authentication is handled via NextAuth with Neon database adapter +- The project includes pre-configured GitHub Actions for automated deployment diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 72126f0..a4f01f6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -101,6 +101,7 @@ git push origin doc_raven ``` --- + ## Q&A > Windows + VSCode(Cursor) 用户:如遇 Husky 在 VSCode 内置终端阻止提交,请使用外部命令行执行 `git commit`。 @@ -154,6 +155,7 @@ pnpm lint:images # 检查图片是否符合规范 pnpm migrate:images # 自动迁移图片到对应 assets 目录 pnpm postinstall # 同步必要的 Husky/Fumadocs 配置 ``` + --- ## 📚 文档规范 diff --git a/app/api/chat/route.test.ts b/app/api/chat/route.test.ts new file mode 100644 index 0000000..e04b40b --- /dev/null +++ b/app/api/chat/route.test.ts @@ -0,0 +1,213 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { POST } from "./route"; +import { streamText } from "ai"; +import { getModel } from "@/lib/ai/models"; + +// Mock the dependencies +vi.mock("@/lib/ai/models", () => ({ + getModel: vi.fn(), + requiresApiKey: vi.fn((provider) => provider !== "intern"), +})); + +vi.mock("@/lib/ai/prompt", () => ({ + buildSystemMessage: vi.fn((system) => { + return system || "You are a helpful AI assistant."; + }), +})); + +vi.mock("ai", () => ({ + streamText: vi.fn(), + convertToModelMessages: vi.fn((messages) => messages), + UIMessage: {}, +})); + +describe("chat API route", () => { + const mockStreamText = vi.mocked(streamText); + const mockGetModel = vi.mocked(getModel); + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("should return error when API key is missing for openai", async () => { + const request = new Request("http://localhost:3000/api/chat", { + method: "POST", + body: JSON.stringify({ + messages: [{ role: "user", content: "Hello" }], + provider: "openai", + }), + }); + + const response = await POST(request); + const data = await response.json(); + + expect(response.status).toBe(400); + expect(data.error).toContain("API key is required"); + }); + + it("should return error when API key is empty string for gemini", async () => { + const request = new Request("http://localhost:3000/api/chat", { + method: "POST", + body: JSON.stringify({ + messages: [{ role: "user", content: "Hello" }], + provider: "gemini", + apiKey: "", + }), + }); + + const response = await POST(request); + const data = await response.json(); + + expect(response.status).toBe(400); + expect(data.error).toContain("API key is required"); + }); + + it("should use intern provider by default", async () => { + const mockModel = { id: "intern-model" } as any; + mockGetModel.mockReturnValue(mockModel); + + const mockStreamResponse = { + toUIMessageStreamResponse: vi.fn(() => new Response()), + } as any; + mockStreamText.mockReturnValue(mockStreamResponse); + + const request = new Request("http://localhost:3000/api/chat", { + method: "POST", + body: JSON.stringify({ + messages: [{ role: "user", content: "Hello" }], + }), + }); + + await POST(request); + + expect(mockGetModel).toHaveBeenCalledWith("intern", undefined); + expect(mockStreamText).toHaveBeenCalledWith({ + model: mockModel, + system: expect.stringContaining("You are a helpful AI assistant"), + messages: [{ role: "user", content: "Hello" }], + }); + }); + + it("should use OpenAI provider when specified", async () => { + const mockModel = { id: "openai-model" } as any; + mockGetModel.mockReturnValue(mockModel); + + const mockStreamResponse = { + toUIMessageStreamResponse: vi.fn(() => new Response()), + } as any; + mockStreamText.mockReturnValue(mockStreamResponse); + + const request = new Request("http://localhost:3000/api/chat", { + method: "POST", + body: JSON.stringify({ + messages: [{ role: "user", content: "Hello" }], + provider: "openai", + apiKey: "test-api-key", + }), + }); + + await POST(request); + + expect(mockGetModel).toHaveBeenCalledWith("openai", "test-api-key"); + }); + + it("should include page context in system message", async () => { + const mockModel = { id: "test-model" } as any; + mockGetModel.mockReturnValue(mockModel); + + const mockStreamResponse = { + toUIMessageStreamResponse: vi.fn(() => new Response()), + } as any; + mockStreamText.mockReturnValue(mockStreamResponse); + + const pageContext = { + title: "Test Page", + description: "A test page", + content: "Page content here", + slug: "test-page", + }; + + const request = new Request("http://localhost:3000/api/chat", { + method: "POST", + body: JSON.stringify({ + messages: [{ role: "user", content: "Hello" }], + pageContext, + }), + }); + + await POST(request); + + const { buildSystemMessage } = await import("@/lib/ai/prompt"); + expect(buildSystemMessage).toHaveBeenCalledWith(undefined, pageContext); + }); + + it("should use custom system message when provided", async () => { + const mockModel = { id: "test-model" } as any; + mockGetModel.mockReturnValue(mockModel); + + const mockStreamResponse = { + toUIMessageStreamResponse: vi.fn(() => new Response()), + } as any; + mockStreamText.mockReturnValue(mockStreamResponse); + + const customSystem = "You are a specialized AI assistant."; + + const request = new Request("http://localhost:3000/api/chat", { + method: "POST", + body: JSON.stringify({ + messages: [{ role: "user", content: "Hello" }], + system: customSystem, + }), + }); + + await POST(request); + + const { buildSystemMessage } = await import("@/lib/ai/prompt"); + expect(buildSystemMessage).toHaveBeenCalledWith(customSystem, undefined); + }); + + it("should handle API errors gracefully", async () => { + const mockModel = { id: "test-model" } as any; + mockGetModel.mockReturnValue(mockModel); + + mockStreamText.mockImplementation(() => { + throw new Error("Stream failed"); + }); + + const request = new Request("http://localhost:3000/api/chat", { + method: "POST", + body: JSON.stringify({ + messages: [{ role: "user", content: "Hello" }], + }), + }); + + const response = await POST(request); + const data = await response.json(); + + expect(response.status).toBe(500); + expect(data).toEqual({ error: "Failed to process chat request" }); + }); + + it("should handle getModel API key errors", async () => { + mockGetModel.mockImplementation(() => { + throw new Error("OpenAI API key is required"); + }); + + const request = new Request("http://localhost:3000/api/chat", { + method: "POST", + body: JSON.stringify({ + messages: [{ role: "user", content: "Hello" }], + provider: "openai", + }), + }); + + const response = await POST(request); + const data = await response.json(); + + expect(response.status).toBe(400); + expect(data.error).toBe( + "API key is required. Please configure your API key in the settings.", + ); + }); +}); diff --git a/app/api/docs-tree/route.test.ts b/app/api/docs-tree/route.test.ts new file mode 100644 index 0000000..430197c --- /dev/null +++ b/app/api/docs-tree/route.test.ts @@ -0,0 +1,281 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { describe, it, expect, vi, beforeEach } from "vitest"; +import * as fs from "node:fs"; +import * as path from "node:path"; + +// Mock node modules before importing the route +vi.mock("node:fs"); +vi.mock("node:path"); + +// Import the route after mocking +import { GET } from "./route"; + +describe("docs-tree API route", () => { + const mockFs = vi.mocked(fs); + const mockPath = vi.mocked(path); + + beforeEach(() => { + vi.clearAllMocks(); + // Reset process.cwd mock + vi.spyOn(process, "cwd").mockReturnValue("/test/project"); + // Setup default path mocks + mockPath.resolve.mockImplementation((...args) => args.join("/")); + mockPath.join.mockImplementation((...args) => args.join("/")); + }); + + it("should return error when fs is not available", async () => { + // Save original functions + const originalReaddirSync = mockFs.readdirSync; + const originalExistsSync = mockFs.existsSync; + + // Mock fs functions to be undefined + (mockFs as any).readdirSync = undefined; + (mockFs as any).existsSync = undefined; + + const response = await GET(); + const data = await response.json(); + + // Restore original functions + mockFs.readdirSync = originalReaddirSync; + mockFs.existsSync = originalExistsSync; + + expect(response.status).toBe(500); + expect(data.ok).toBe(false); + expect(data.reason).toBe("fs-unavailable"); + expect(data.diag.hasFs).toBe(false); + }); + + it("should return error when docs root is not found", async () => { + mockFs.readdirSync.mockImplementation((() => []) as any); + mockFs.existsSync.mockReturnValue(false); + + const response = await GET(); + const data = await response.json(); + + expect(response.status).toBe(500); + expect(data.ok).toBe(false); + expect(data.reason).toBe("docs-root-not-found"); + }); + + it("should build correct tree structure", async () => { + const mockDirents = [ + { name: "ai", isDirectory: () => true }, + { name: "frontend", isDirectory: () => true }, + { name: "index.mdx", isDirectory: () => false }, + ]; + + const mockAiSubdirs = [ + { name: "llm-basics", isDirectory: () => true }, + { name: "multimodal", isDirectory: () => true }, + { name: "index.mdx", isDirectory: () => false }, + ]; + + mockFs.existsSync.mockReturnValue(true); + mockFs.readdirSync.mockImplementation(((dir: any, options: any) => { + if ( + options && + typeof options === "object" && + "withFileTypes" in options && + options.withFileTypes + ) { + // Return dirent objects for directories + if (dir === "/test/project/app/docs") return mockDirents; + if (dir === "/test/project/app/docs/ai") return mockAiSubdirs; + if (dir === "/test/project/app/docs/frontend") return []; + return []; + } + // Otherwise return string array + return []; + }) as any); + + const response = await GET(); + const data = await response.json(); + + expect(response.status).toBe(200); + expect(data.ok).toBe(true); + expect(data.docsRoot).toBe("/test/project/app/docs"); + expect(data.tree).toEqual([ + { + name: "ai", + path: "ai", + children: [ + { name: "llm-basics", path: "ai/llm-basics" }, + { name: "multimodal", path: "ai/multimodal" }, + ], + }, + { + name: "frontend", + path: "frontend", + children: [], + }, + ]); + }); + + it("should handle missing docs directory gracefully", async () => { + mockFs.existsSync.mockReturnValue(true); + mockFs.readdirSync.mockImplementation((() => { + throw new Error("Permission denied"); + }) as any); + + const response = await GET(); + const data = await response.json(); + + expect(response.status).toBe(500); + expect(data.ok).toBe(false); + expect(data.error).toContain("Permission denied"); + }); + + it("should handle empty docs directory", async () => { + mockFs.existsSync.mockReturnValue(true); + mockFs.readdirSync.mockImplementation((() => { + return []; + }) as any); + + const response = await GET(); + const data = await response.json(); + + expect(response.status).toBe(200); + expect(data.ok).toBe(true); + expect(data.tree).toEqual([]); + }); + + it("should filter out files and only include directories", async () => { + const mockDirents = [ + { name: "folder1", isDirectory: () => true }, + { name: "file1.mdx", isDirectory: () => false }, + { name: "folder2", isDirectory: () => true }, + { name: "README.md", isDirectory: () => false }, + ]; + + mockFs.existsSync.mockReturnValue(true); + mockFs.readdirSync.mockImplementation(((dir: any, options: any) => { + if ( + options && + typeof options === "object" && + "withFileTypes" in options && + options.withFileTypes + ) { + return mockDirents; + } + return []; + }) as any); + + const response = await GET(); + const data = await response.json(); + + expect(response.status).toBe(200); + expect(data.tree).toHaveLength(2); + expect(data.tree.map((item: any) => item.name)).toEqual([ + "folder1", + "folder2", + ]); + }); + + it("should handle nested directory structure", async () => { + mockFs.existsSync.mockReturnValue(true); + mockFs.readdirSync.mockImplementation(((dir: any, options: any) => { + if ( + options && + typeof options === "object" && + "withFileTypes" in options && + options.withFileTypes + ) { + if (dir === "/test/project/app/docs") { + return [{ name: "parent", isDirectory: () => true }]; + } + if (dir === "/test/project/app/docs/parent") { + return [{ name: "child", isDirectory: () => true }]; + } + if (dir === "/test/project/app/docs/parent/child") { + return [{ name: "grandchild", isDirectory: () => true }]; + } + } + return []; + }) as any); + + const response = await GET(); + const data = await response.json(); + + expect(response.status).toBe(200); + expect(data.tree[0]).toEqual({ + name: "parent", + path: "parent", + children: [ + { + name: "child", + path: "parent/child", + }, + ], + }); + }); + + it("should handle process.cwd errors", async () => { + vi.spyOn(process, "cwd").mockImplementation(() => { + throw new Error("Cannot determine cwd"); + }); + + await expect(GET()).rejects.toThrow("Cannot determine cwd"); + }); + + it("should handle different OS path separators", async () => { + // Setup for Windows-style paths + vi.spyOn(process, "cwd").mockReturnValue("C:\\test\\project"); + mockPath.resolve.mockImplementation((...args) => args.join("\\")); + mockPath.join.mockImplementation((...args) => args.join("\\")); + + mockFs.existsSync.mockReturnValue(true); + mockFs.readdirSync.mockImplementation(((dir: any, options: any) => { + if ( + options && + typeof options === "object" && + "withFileTypes" in options && + options.withFileTypes + ) { + return [{ name: "test-folder", isDirectory: () => true }]; + } + return []; + }) as any); + + const response = await GET(); + const data = await response.json(); + + expect(response.status).toBe(200); + expect(data.ok).toBe(true); + }); + + it("should limit recursion depth", async () => { + // This test ensures we don't have infinite recursion + mockFs.existsSync.mockReturnValue(true); + mockFs.readdirSync.mockImplementation(((dir: any, options: any) => { + if ( + options && + typeof options === "object" && + "withFileTypes" in options && + options.withFileTypes + ) { + // Create a structure that's deeper than maxDepth + if (dir === "/test/project/app/docs") { + return [{ name: "level1", isDirectory: () => true }]; + } + if (dir === "/test/project/app/docs/level1") { + return [{ name: "level2", isDirectory: () => true }]; + } + if (dir === "/test/project/app/docs/level1/level2") { + // This should not have children due to maxDepth=2 + return [{ name: "level3", isDirectory: () => true }]; + } + } + return []; + }) as any); + + const response = await GET(); + const data = await response.json(); + + expect(response.status).toBe(200); + // Verify that level3 is not included due to maxDepth=2 + expect(data.tree[0].children[0]).toEqual({ + name: "level2", + path: "level1/level2", + }); + }); +}); diff --git a/app/docs/CommunityShare/Geek/git101.mdx b/app/docs/CommunityShare/Geek/git101.mdx index f63ee20..9c826b6 100644 --- a/app/docs/CommunityShare/Geek/git101.mdx +++ b/app/docs/CommunityShare/Geek/git101.mdx @@ -41,4 +41,5 @@ docId: tksz80mfqqyzwzzer5p3uxtg | `git diff --cached` → 暂存区 vs 最近提交 | `git log --graph --decorate` → 图形化历史 | ## 模拟演练 + 推荐一个git的模拟演练沙盒网站,帮助初学者快速上手git操作:https://learngitbranching.js.org/ diff --git a/app/docs/CommunityShare/Geek/raspberry-guide.md b/app/docs/CommunityShare/Geek/raspberry-guide.md index 9c03728..05b4a8b 100644 --- a/app/docs/CommunityShare/Geek/raspberry-guide.md +++ b/app/docs/CommunityShare/Geek/raspberry-guide.md @@ -301,7 +301,7 @@ $ tmux ls | :- | :- | | 类型 | A | | 名称(必需) | rasp | -| IPv4 地址(必需) | | +| IPv4 地址(必需) | <VPS公网IP> | | 代理状态 | 仅DNS | 就可以通过你的域名登录了 diff --git a/app/docs/ai/MoE/moe-update.md b/app/docs/ai/MoE/moe-update.md index 90297d9..463a677 100644 --- a/app/docs/ai/MoE/moe-update.md +++ b/app/docs/ai/MoE/moe-update.md @@ -70,8 +70,8 @@ $$ > **目标**:在第 $t$ 轮,专家 $m_t$ 要拟合任务数据集 $(X_t, y_t)$ > $$ \min\_{w}\ \|X_t^\top w - y_t\|\_2^2 $$ > -> **问题**:过参数化 ($s_t < d$) 时解不唯一,直接算最小二乘解会丢掉历史信息。 -> 所以论文改成 **约束优化**: +> **问题**:过参数化 ($s_t < d$) 时解不唯一,直接算最小二乘解会丢掉历史信息。 +> > 所以论文改成 **约束优化**: > > $$ > \min_w \ \|w - w_{t-1}^{(m_t)}\|_2^2 \quad @@ -203,23 +203,24 @@ $$ - 在前章节使用的方法 - 保证同一专家在相邻任务上的参数差异不要太大。 - -- **表示相似性 (Representation Locality)** - - 可以直接对专家输出的表示(hidden states)施加约束。 +- **表示相似性 (Representation Locality)** - 可以直接对专家输出的表示(hidden states)施加约束。 - 比如: + $$ L^{loc}_{repr} = \sum_{m \in [M]} \pi_m(X_t,\Theta_t)\,\|f_m(X_t) - f_m(X_{t-1})\|_2 $$ + - 让相似输入在同一专家上输出保持稳定。 -- **路由概率连续性 (Routing Locality)** - - 约束 router 的分配概率不要随任务跳跃太大。 +- **路由概率连续性 (Routing Locality)** - 约束 router 的分配概率不要随任务跳跃太大。 - 形式类似: + $$ L^{loc}_{route} = \sum_{m \in [M]} \|\pi_m(X_t,\Theta_t) - \pi_m(X_{t-1},\Theta_{t-1})\|_2 $$ + - **语义/任务嵌入的相似性 (Task Embedding Locality)** - 如果能为任务构建一个 task embedding(比如通过元学习或对比学习),可以定义: - 相似任务 → 路由到同一专家 diff --git a/app/docs/computer-science/cpp_backend/easy_compile/2_base_gcc.md b/app/docs/computer-science/cpp_backend/easy_compile/2_base_gcc.md index a97f44f..4aa6c30 100644 --- a/app/docs/computer-science/cpp_backend/easy_compile/2_base_gcc.md +++ b/app/docs/computer-science/cpp_backend/easy_compile/2_base_gcc.md @@ -50,7 +50,7 @@ sudo dnf groupinstall "Development Tools" -y 将这几个头文件放入MinGW的include下。 -1. 代码中引入头文件将include 改为include (这个点在上述仓库中的ReadMe里有写) +1. 代码中引入头文件将include 改为include <mingw.thread.h> (这个点在上述仓库中的ReadMe里有写) 2. 如果是命令行编译,加上-D_WIN32_WINNT=0x0501这个参数,让编译器知道你正在针对 **Windows XP**(或更高版本)进行编译。(不知道是不是我的版本是win32的原因,也许mingw-win64版本不需要) 这是我踩坑的版本 diff --git a/app/hooks/useAssistantSettings.test.tsx b/app/hooks/useAssistantSettings.test.tsx new file mode 100644 index 0000000..edd5349 --- /dev/null +++ b/app/hooks/useAssistantSettings.test.tsx @@ -0,0 +1,237 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { renderHook, act } from "@testing-library/react"; +import { + AssistantSettingsProvider, + useAssistantSettings, +} from "./useAssistantSettings"; + +describe("useAssistantSettings", () => { + beforeEach(() => { + vi.mocked(localStorage.getItem).mockReturnValue(null); + vi.mocked(localStorage.setItem).mockClear(); + }); + + const wrapper = ({ children }: { children: React.ReactNode }) => ( + {children} + ); + + it("should throw error when used outside provider", () => { + // Suppress console.error for this test + const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {}); + + expect(() => { + renderHook(() => useAssistantSettings()); + }).toThrow( + "useAssistantSettings must be used within an AssistantSettingsProvider", + ); + + consoleSpy.mockRestore(); + }); + + it("should initialize with default settings", () => { + const { result } = renderHook(() => useAssistantSettings(), { wrapper }); + + expect(result.current.provider).toBe("openai"); + expect(result.current.openaiApiKey).toBe(""); + expect(result.current.geminiApiKey).toBe(""); + }); + + it("should load settings from localStorage", () => { + const savedSettings = { + provider: "gemini", + openaiApiKey: "test-openai-key", + geminiApiKey: "test-gemini-key", + }; + vi.mocked(localStorage.getItem).mockReturnValue( + JSON.stringify(savedSettings), + ); + + const { result } = renderHook(() => useAssistantSettings(), { wrapper }); + + expect(result.current.provider).toBe("gemini"); + expect(result.current.openaiApiKey).toBe("test-openai-key"); + expect(result.current.geminiApiKey).toBe("test-gemini-key"); + }); + + it("should handle invalid localStorage data gracefully", () => { + vi.mocked(localStorage.getItem).mockReturnValue("invalid json"); + const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {}); + + const { result } = renderHook(() => useAssistantSettings(), { wrapper }); + + expect(result.current.provider).toBe("openai"); + expect(result.current.openaiApiKey).toBe(""); + expect(result.current.geminiApiKey).toBe(""); + expect(consoleSpy).toHaveBeenCalledWith( + "Failed to parse assistant settings from localStorage", + expect.any(SyntaxError), + ); + + consoleSpy.mockRestore(); + }); + + it("should update provider and save to localStorage", () => { + const { result } = renderHook(() => useAssistantSettings(), { wrapper }); + + act(() => { + result.current.setProvider("gemini"); + }); + + expect(result.current.provider).toBe("gemini"); + expect(vi.mocked(localStorage.setItem)).toHaveBeenCalledWith( + "assistant-settings-storage", + expect.stringContaining('"provider":"gemini"'), + ); + }); + + it("should update openaiApiKey and save to localStorage", () => { + const { result } = renderHook(() => useAssistantSettings(), { wrapper }); + + act(() => { + result.current.setOpenaiApiKey("new-openai-key"); + }); + + expect(result.current.openaiApiKey).toBe("new-openai-key"); + expect(vi.mocked(localStorage.setItem)).toHaveBeenCalledWith( + "assistant-settings-storage", + expect.stringContaining('"openaiApiKey":"new-openai-key"'), + ); + }); + + it("should update geminiApiKey and save to localStorage", () => { + const { result } = renderHook(() => useAssistantSettings(), { wrapper }); + + act(() => { + result.current.setGeminiApiKey("new-gemini-key"); + }); + + expect(result.current.geminiApiKey).toBe("new-gemini-key"); + expect(vi.mocked(localStorage.setItem)).toHaveBeenCalledWith( + "assistant-settings-storage", + expect.stringContaining('"geminiApiKey":"new-gemini-key"'), + ); + }); + + it("should handle localStorage save errors gracefully", () => { + const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {}); + vi.mocked(localStorage.setItem).mockImplementation(() => { + throw new Error("Storage error"); + }); + + const { result } = renderHook(() => useAssistantSettings(), { wrapper }); + + act(() => { + result.current.setProvider("gemini"); + }); + + expect(consoleSpy).toHaveBeenCalledWith( + "Failed to save assistant settings to localStorage", + expect.any(Error), + ); + + consoleSpy.mockRestore(); + }); + + it("should refresh settings from storage", () => { + const { result } = renderHook(() => useAssistantSettings(), { wrapper }); + + // Change settings + act(() => { + result.current.setProvider("gemini"); + }); + + // Mock new data in localStorage + const newSettings = { + provider: "openai", + openaiApiKey: "refreshed-key", + geminiApiKey: "", + }; + vi.mocked(localStorage.getItem).mockReturnValue( + JSON.stringify(newSettings), + ); + + // Refresh from storage + act(() => { + result.current.refreshFromStorage(); + }); + + expect(result.current.provider).toBe("openai"); + expect(result.current.openaiApiKey).toBe("refreshed-key"); + }); + + it("should handle storage events from other tabs", () => { + const { result } = renderHook(() => useAssistantSettings(), { wrapper }); + + const newSettings = { + provider: "gemini", + openaiApiKey: "", + geminiApiKey: "external-change", + }; + + // Simulate storage event from another tab + act(() => { + const storageEvent = new StorageEvent("storage", { + key: "assistant-settings-storage", + newValue: JSON.stringify(newSettings), + oldValue: null, + storageArea: window.localStorage, + url: window.location.href, + }); + window.dispatchEvent(storageEvent); + }); + + expect(result.current.provider).toBe("gemini"); + expect(result.current.geminiApiKey).toBe("external-change"); + }); + + it("should ignore storage events for other keys", () => { + const { result } = renderHook(() => useAssistantSettings(), { wrapper }); + const initialProvider = result.current.provider; + + // Simulate storage event for different key + act(() => { + const storageEvent = new StorageEvent("storage", { + key: "other-key", + newValue: "some value", + oldValue: null, + storageArea: window.localStorage, + url: window.location.href, + }); + window.dispatchEvent(storageEvent); + }); + + expect(result.current.provider).toBe(initialProvider); + }); + + it("should validate provider values from localStorage", () => { + const invalidSettings = { + provider: "invalid-provider", + openaiApiKey: "key", + geminiApiKey: "", + }; + vi.mocked(localStorage.getItem).mockReturnValue( + JSON.stringify(invalidSettings), + ); + + const { result } = renderHook(() => useAssistantSettings(), { wrapper }); + + // Should default to 'openai' for invalid provider + expect(result.current.provider).toBe("openai"); + }); + + it("should handle missing fields in localStorage gracefully", () => { + const partialSettings = { + provider: "gemini", + // Missing API keys + }; + vi.mocked(localStorage.getItem).mockReturnValue( + JSON.stringify(partialSettings), + ); + + const { result } = renderHook(() => useAssistantSettings(), { wrapper }); + + expect(result.current.provider).toBe("gemini"); + expect(result.current.openaiApiKey).toBe(""); + expect(result.current.geminiApiKey).toBe(""); + }); +}); diff --git a/architecture-diagram.md b/architecture-diagram.md new file mode 100644 index 0000000..6bd4b93 --- /dev/null +++ b/architecture-diagram.md @@ -0,0 +1,210 @@ +# InvolutionHell Architecture Diagram + +```mermaid +graph TB + subgraph "Client Layer" + Browser[Web Browser] + Mobile[Mobile Browser] + end + + subgraph "Frontend Application" + subgraph "Next.js App Router" + HomePage[Home Page
app/page.tsx] + DocsPages[Documentation Pages
app/docs/[...slug]/page.tsx] + + subgraph "UI Components" + Header[Header Component] + Hero[Hero Section] + Features[Features Section] + Community[Community Section] + Footer[Footer Component] + DocsAssistant[AI Assistant Modal] + GiscusComments[Comments System] + end + + subgraph "Layouts" + RootLayout[Root Layout
- Theme Provider
- Root Provider
- Global Styles] + DocsLayout[Docs Layout
- Sidebar Navigation
- Page Tree] + end + end + + subgraph "Client Features" + ThemeToggle[Theme Toggle
Dark/Light Mode] + UserMenu[User Menu
Sign In/Out] + Search[Search
Orama Integration] + AIChat[AI Chat Interface
Assistant UI] + end + end + + subgraph "API Layer" + subgraph "API Routes" + AuthAPI[/api/auth/[...nextauth]
NextAuth Handler] + ChatAPI[/api/chat
AI Chat Endpoint] + DocsTreeAPI[/api/docs-tree
Documentation Structure] + end + end + + subgraph "Backend Services" + subgraph "Authentication" + NextAuth[NextAuth.js
- GitHub OAuth
- Session Management] + AuthConfig[Auth Configuration
- JWT/Database Strategy] + end + + subgraph "AI Integration" + OpenAI[OpenAI SDK
GPT Models] + Gemini[Google Gemini
Generative AI] + AISDKCore[Vercel AI SDK
Stream Processing] + end + + subgraph "Content Management" + Fumadocs[Fumadocs MDX
- MDX Processing
- Page Tree Generation] + ContentSources[Content Sources
app/docs/**/*.mdx] + end + end + + subgraph "Data Layer" + subgraph "Database" + Neon[(Neon PostgreSQL
- User Data
- Sessions
- Auth Tokens)] + Prisma[Prisma ORM
Schema Management] + end + + subgraph "Static Content" + MDXFiles[MDX Files
Documentation Content] + Assets[Assets
Images & Resources] + end + end + + subgraph "External Services" + GitHub[GitHub
- OAuth Provider
- Version Control] + Giscus[Giscus
Comments via GitHub Discussions] + Vercel[Vercel
- Deployment
- Analytics] + end + + subgraph "Build & Development" + NextBuild[Next.js Build
- Static Generation
- API Routes] + Scripts[Scripts
- Image Migration
- Content Validation] + Husky[Husky & Lint-staged
Pre-commit Hooks] + end + + %% Client connections + Browser --> HomePage + Browser --> DocsPages + Mobile --> HomePage + Mobile --> DocsPages + + %% Page connections + HomePage --> Header + HomePage --> Hero + HomePage --> Features + HomePage --> Community + HomePage --> Footer + + DocsPages --> DocsLayout + DocsPages --> DocsAssistant + DocsPages --> GiscusComments + + %% Layout connections + RootLayout --> ThemeToggle + DocsLayout --> Search + DocsLayout --> UserMenu + + %% API connections + UserMenu --> AuthAPI + DocsAssistant --> ChatAPI + DocsLayout --> DocsTreeAPI + AIChat --> ChatAPI + + %% Backend connections + AuthAPI --> NextAuth + NextAuth --> AuthConfig + NextAuth --> Neon + AuthConfig --> GitHub + + ChatAPI --> OpenAI + ChatAPI --> Gemini + ChatAPI --> AISDKCore + + DocsTreeAPI --> Fumadocs + Fumadocs --> ContentSources + Fumadocs --> MDXFiles + + %% Database connections + NextAuth --> Prisma + Prisma --> Neon + + %% External connections + GiscusComments --> Giscus + NextBuild --> Vercel + + %% Build connections + MDXFiles --> NextBuild + Assets --> Scripts + Scripts --> Husky + + classDef frontend fill:#e1f5fe,stroke:#01579b,stroke-width:2px + classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px + classDef backend fill:#f3e5f5,stroke:#4a148c,stroke-width:2px + classDef data fill:#e8f5e9,stroke:#1b5e20,stroke-width:2px + classDef external fill:#fce4ec,stroke:#880e4f,stroke-width:2px + classDef build fill:#f5f5f5,stroke:#424242,stroke-width:2px + + class Browser,Mobile,HomePage,DocsPages,Header,Hero,Features,Community,Footer,DocsAssistant,GiscusComments,RootLayout,DocsLayout,ThemeToggle,UserMenu,Search,AIChat frontend + class AuthAPI,ChatAPI,DocsTreeAPI api + class NextAuth,AuthConfig,OpenAI,Gemini,AISDKCore,Fumadocs,ContentSources backend + class Neon,Prisma,MDXFiles,Assets data + class GitHub,Giscus,Vercel external + class NextBuild,Scripts,Husky build +``` + +## Architecture Overview + +### 1. **Client Layer** + +- Web and mobile browsers access the application + +### 2. **Frontend Application (Next.js 15)** + +- **App Router**: Modern Next.js routing with server components +- **Home Page**: Landing page with Hero, Features, Community sections +- **Documentation Pages**: Dynamic MDX-based documentation with [...slug] routing +- **UI Components**: Reusable components built with Fumadocs UI and custom components +- **Client Features**: Theme switching, user authentication, search, and AI chat + +### 3. **API Layer** + +- **Authentication**: NextAuth.js endpoints for OAuth flow +- **Chat API**: AI-powered chat endpoint supporting OpenAI and Gemini +- **Docs Tree API**: Provides documentation structure for navigation + +### 4. **Backend Services** + +- **Authentication**: NextAuth with GitHub OAuth, supports both JWT and database sessions +- **AI Integration**: Multiple AI providers (OpenAI, Google Gemini) via Vercel AI SDK +- **Content Management**: Fumadocs MDX for processing documentation + +### 5. **Data Layer** + +- **Database**: Neon PostgreSQL for user data, managed via Prisma ORM +- **Static Content**: MDX files and assets stored in the repository + +### 6. **External Services** + +- **GitHub**: OAuth provider and version control +- **Giscus**: Comment system using GitHub Discussions +- **Vercel**: Deployment platform with analytics + +### 7. **Build & Development** + +- **Next.js Build**: Static site generation and API route compilation +- **Scripts**: Custom scripts for image management and content validation +- **Git Hooks**: Husky with lint-staged for code quality + +## Key Features + +1. **Multi-language Support**: Internationalization with next-intl +2. **AI Assistant**: Context-aware documentation assistant +3. **Theme Support**: Dark/light mode with system preference detection +4. **Search**: Fast client-side search with Orama +5. **Math Support**: KaTeX for mathematical expressions +6. **Image Optimization**: Automatic image migration and organization +7. **Comments**: GitHub-based discussion system diff --git a/lib/github.test.ts b/lib/github.test.ts new file mode 100644 index 0000000..b9388e3 --- /dev/null +++ b/lib/github.test.ts @@ -0,0 +1,117 @@ +import { describe, it, expect } from "vitest"; +import { + buildDocsEditUrl, + buildDocsNewUrl, + normalizeDocsPath, + githubConstants, +} from "./github"; + +describe("github utilities", () => { + describe("buildDocsEditUrl", () => { + it("should build correct edit URL for simple path", () => { + const result = buildDocsEditUrl("ai/llm-basics/index.mdx"); + expect(result).toBe( + "https://github.com/InvolutionHell/involutionhell.github.io/edit/main/app/docs/ai/llm-basics/index.mdx", + ); + }); + + it("should handle paths with Chinese characters", () => { + const result = buildDocsEditUrl("ai/基础知识/入门.mdx"); + expect(result).toBe( + "https://github.com/InvolutionHell/involutionhell.github.io/edit/main/app/docs/ai/%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/%E5%85%A5%E9%97%A8.mdx", + ); + }); + + it("should handle paths with spaces", () => { + const result = buildDocsEditUrl("ai/machine learning/deep learning.mdx"); + expect(result).toBe( + "https://github.com/InvolutionHell/involutionhell.github.io/edit/main/app/docs/ai/machine%20learning/deep%20learning.mdx", + ); + }); + + it("should handle empty path", () => { + const result = buildDocsEditUrl(""); + expect(result).toBe( + "https://github.com/InvolutionHell/involutionhell.github.io/edit/main/app/docs", + ); + }); + + it("should clean up multiple slashes", () => { + const result = buildDocsEditUrl("ai//llm-basics///index.mdx"); + expect(result).toBe( + "https://github.com/InvolutionHell/involutionhell.github.io/edit/main/app/docs/ai/llm-basics/index.mdx", + ); + }); + + it("should remove leading and trailing slashes", () => { + const result = buildDocsEditUrl("/ai/llm-basics/index.mdx/"); + expect(result).toBe( + "https://github.com/InvolutionHell/involutionhell.github.io/edit/main/app/docs/ai/llm-basics/index.mdx", + ); + }); + }); + + describe("buildDocsNewUrl", () => { + it("should build correct new file URL with params", () => { + const params = new URLSearchParams({ + filename: "new-doc.mdx", + value: "---\ntitle: New Doc\n---\n\nContent", + }); + const result = buildDocsNewUrl("ai/llm-basics", params); + expect(result).toBe( + "https://github.com/InvolutionHell/involutionhell.github.io/new/main/app/docs/ai/llm-basics?filename=new-doc.mdx&value=---%0Atitle%3A+New+Doc%0A---%0A%0AContent", + ); + }); + + it("should handle empty params", () => { + const params = new URLSearchParams(); + const result = buildDocsNewUrl("ai/llm-basics", params); + expect(result).toBe( + "https://github.com/InvolutionHell/involutionhell.github.io/new/main/app/docs/ai/llm-basics", + ); + }); + + it("should encode directory path with special characters", () => { + const params = new URLSearchParams({ filename: "test.mdx" }); + const result = buildDocsNewUrl("ai/机器学习", params); + expect(result).toBe( + "https://github.com/InvolutionHell/involutionhell.github.io/new/main/app/docs/ai/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0?filename=test.mdx", + ); + }); + }); + + describe("normalizeDocsPath", () => { + it("should normalize simple path", () => { + const result = normalizeDocsPath("ai/llm-basics/index.mdx"); + expect(result).toBe("app/docs/ai/llm-basics/index.mdx"); + }); + + it("should handle empty path", () => { + const result = normalizeDocsPath(""); + expect(result).toBe("app/docs"); + }); + + it("should clean up multiple slashes", () => { + const result = normalizeDocsPath("ai//llm-basics///index.mdx"); + expect(result).toBe("app/docs/ai/llm-basics/index.mdx"); + }); + + it("should not encode special characters", () => { + const result = normalizeDocsPath("ai/基础知识/入门.mdx"); + expect(result).toBe("app/docs/ai/基础知识/入门.mdx"); + }); + }); + + describe("githubConstants", () => { + it("should export correct constants", () => { + expect(githubConstants).toEqual({ + owner: "InvolutionHell", + repo: "involutionhell.github.io", + defaultBranch: "main", + docsBase: "app/docs", + repoBaseUrl: + "https://github.com/InvolutionHell/involutionhell.github.io", + }); + }); + }); +}); diff --git a/lib/utils.test.ts b/lib/utils.test.ts new file mode 100644 index 0000000..8055e7e --- /dev/null +++ b/lib/utils.test.ts @@ -0,0 +1,112 @@ +import { describe, it, expect } from "vitest"; +import { cn } from "./utils"; + +describe("cn utility", () => { + it("should merge single class string", () => { + expect(cn("foo")).toBe("foo"); + }); + + it("should merge multiple class strings", () => { + expect(cn("foo", "bar")).toBe("foo bar"); + }); + + it("should handle conditional classes", () => { + expect(cn("foo", false && "bar", "baz")).toBe("foo baz"); + expect(cn("foo", true && "bar", "baz")).toBe("foo bar baz"); + }); + + it("should handle undefined and null values", () => { + expect(cn("foo", undefined, "bar", null, "baz")).toBe("foo bar baz"); + }); + + it("should handle object syntax", () => { + expect(cn({ foo: true, bar: false, baz: true })).toBe("foo baz"); + }); + + it("should handle array syntax", () => { + expect(cn(["foo", "bar"], "baz")).toBe("foo bar baz"); + }); + + it("should handle empty inputs", () => { + expect(cn()).toBe(""); + expect(cn("")).toBe(""); + }); + + it("should merge tailwind classes correctly", () => { + // twMerge should handle conflicting classes + expect(cn("p-4", "p-2")).toBe("p-2"); + expect(cn("text-red-500", "text-blue-500")).toBe("text-blue-500"); + }); + + it("should preserve non-conflicting tailwind classes", () => { + expect(cn("p-4 text-red-500", "mx-2")).toBe("p-4 text-red-500 mx-2"); + }); + + it("should handle complex tailwind modifiers", () => { + expect(cn("hover:bg-red-500", "hover:bg-blue-500")).toBe( + "hover:bg-blue-500", + ); + expect(cn("sm:p-4", "lg:p-8")).toBe("sm:p-4 lg:p-8"); + }); + + it("should handle mixed inputs", () => { + expect( + cn( + "base-class", + { active: true, disabled: false }, + ["array-class-1", "array-class-2"], + undefined, + "final-class", + ), + ).toBe("base-class active array-class-1 array-class-2 final-class"); + }); + + it("should handle complex conditional rendering patterns", () => { + const isActive = true; + const isDisabled = false; + const size: "lg" | "sm" | undefined = "lg"; + + expect( + cn( + "btn", + isActive && "btn-active", + isDisabled && "btn-disabled", + size === "lg" && "btn-lg", + ), + ).toBe("btn btn-active btn-lg"); + }); + + it("should handle duplicate classes", () => { + // Note: cn doesn't deduplicate classes by default - that's expected behavior + expect(cn("foo foo bar", "bar baz")).toBe("foo foo bar bar baz"); + }); + + it("should handle numeric values", () => { + // clsx converts numbers to strings + expect(cn("gap-", 4 as unknown as string)).toBe("gap- 4"); + }); + + it("should handle Tailwind arbitrary values", () => { + expect(cn("w-[100px]", "w-[200px]")).toBe("w-[200px]"); + expect(cn("text-[#123456]", "text-[#789abc]")).toBe("text-[#789abc]"); + }); + + it("should handle important modifiers", () => { + // twMerge preserves order - important modifier comes first + expect(cn("!p-4", "p-8")).toBe("!p-4 p-8"); + }); + + it("should handle responsive breakpoints correctly", () => { + expect(cn("text-sm md:text-base lg:text-lg", "md:text-xl")).toBe( + "text-sm lg:text-lg md:text-xl", + ); + }); + + it("should handle deeply nested arrays", () => { + expect(cn(["foo", ["bar", ["baz"]]])).toBe("foo bar baz"); + }); + + it("should return empty string for all falsy inputs", () => { + expect(cn(false, null, undefined, "", 0 as unknown as string)).toBe(""); + }); +}); diff --git a/mdx-components.tsx b/mdx-components.tsx index b2e9a62..5a89ce2 100644 --- a/mdx-components.tsx +++ b/mdx-components.tsx @@ -11,34 +11,34 @@ import type { MDXComponents } from "mdx/types"; // }; // function MdxImage({ src, alt = "", width, height, ...rest }: MdxImageProps) { - // if (!src) { - // return ( - // {alt} - // ); - // } - // const numericWidth = typeof width === "string" ? Number(width) : width; - // const numericHeight = typeof height === "string" ? Number(height) : height; +// if (!src) { +// return ( +// {alt} +// ); +// } +// const numericWidth = typeof width === "string" ? Number(width) : width; +// const numericHeight = typeof height === "string" ? Number(height) : height; - // if (!Number.isFinite(numericWidth) || !Number.isFinite(numericHeight)) { - // // fallback: 当 width/height 不是可解析数值时,直接使用原生 - // return {alt; - // } +// if (!Number.isFinite(numericWidth) || !Number.isFinite(numericHeight)) { +// // fallback: 当 width/height 不是可解析数值时,直接使用原生 +// return {alt; +// } - // return ( - // {alt - // ); +// return ( +// {alt +// ); // return ( // =18" } peerDependencies: @@ -241,10 +265,10 @@ packages: peerDependencies: zod: ^3.25.76 || ^4 - "@ai-sdk/provider-utils@3.0.10": + "@ai-sdk/provider-utils@3.0.12": resolution: { - integrity: sha512-T1gZ76gEIwffep6MWI0QNy9jgoybUHE7TRaHB5k54K8mF91ciGFlbtCGxDYhMH3nCRergKwYFIDeFF0hJSIQHQ==, + integrity: sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg==, } engines: { node: ">=18" } peerDependencies: @@ -286,6 +310,13 @@ packages: } engines: { node: ">=10" } + "@ampproject/remapping@2.3.0": + resolution: + { + integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==, + } + engines: { node: ">=6.0.0" } + "@ant-design/colors@7.2.1": resolution: { @@ -420,6 +451,125 @@ packages: integrity: sha512-KuwialF1LrM5AZOzGurw6OUfeO/sW1ZAQirceYuxzpiVPvUJCeOPHQro0vcvD29JmdpWh5XegnEbRHXtVXROPg==, } + "@babel/code-frame@7.27.1": + resolution: + { + integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==, + } + engines: { node: ">=6.9.0" } + + "@babel/compat-data@7.28.4": + resolution: + { + integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==, + } + engines: { node: ">=6.9.0" } + + "@babel/core@7.28.4": + resolution: + { + integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==, + } + engines: { node: ">=6.9.0" } + + "@babel/generator@7.28.3": + resolution: + { + integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-compilation-targets@7.27.2": + resolution: + { + integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-globals@7.28.0": + resolution: + { + integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-module-imports@7.27.1": + resolution: + { + integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-module-transforms@7.28.3": + resolution: + { + integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/helper-plugin-utils@7.27.1": + resolution: + { + integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-string-parser@7.27.1": + resolution: + { + integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-validator-identifier@7.27.1": + resolution: + { + integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-validator-option@7.27.1": + resolution: + { + integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==, + } + engines: { node: ">=6.9.0" } + + "@babel/helpers@7.28.4": + resolution: + { + integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==, + } + engines: { node: ">=6.9.0" } + + "@babel/parser@7.28.4": + resolution: + { + integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==, + } + engines: { node: ">=6.0.0" } + hasBin: true + + "@babel/plugin-transform-react-jsx-self@7.27.1": + resolution: + { + integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-react-jsx-source@7.27.1": + resolution: + { + integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + "@babel/runtime@7.28.4": resolution: { @@ -427,6 +577,33 @@ packages: } engines: { node: ">=6.9.0" } + "@babel/template@7.27.2": + resolution: + { + integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==, + } + engines: { node: ">=6.9.0" } + + "@babel/traverse@7.28.4": + resolution: + { + integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==, + } + engines: { node: ">=6.9.0" } + + "@babel/types@7.28.4": + resolution: + { + integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==, + } + engines: { node: ">=6.9.0" } + + "@bcoe/v8-coverage@0.2.3": + resolution: + { + integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==, + } + "@cspotcode/source-map-support@0.8.1": resolution: { @@ -499,6 +676,15 @@ packages: integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==, } + "@esbuild/aix-ppc64@0.21.5": + resolution: + { + integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==, + } + engines: { node: ">=12" } + cpu: [ppc64] + os: [aix] + "@esbuild/aix-ppc64@0.25.10": resolution: { @@ -508,6 +694,15 @@ packages: cpu: [ppc64] os: [aix] + "@esbuild/android-arm64@0.21.5": + resolution: + { + integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==, + } + engines: { node: ">=12" } + cpu: [arm64] + os: [android] + "@esbuild/android-arm64@0.25.10": resolution: { @@ -517,6 +712,15 @@ packages: cpu: [arm64] os: [android] + "@esbuild/android-arm@0.21.5": + resolution: + { + integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==, + } + engines: { node: ">=12" } + cpu: [arm] + os: [android] + "@esbuild/android-arm@0.25.10": resolution: { @@ -526,6 +730,15 @@ packages: cpu: [arm] os: [android] + "@esbuild/android-x64@0.21.5": + resolution: + { + integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [android] + "@esbuild/android-x64@0.25.10": resolution: { @@ -535,6 +748,15 @@ packages: cpu: [x64] os: [android] + "@esbuild/darwin-arm64@0.21.5": + resolution: + { + integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==, + } + engines: { node: ">=12" } + cpu: [arm64] + os: [darwin] + "@esbuild/darwin-arm64@0.25.10": resolution: { @@ -544,6 +766,15 @@ packages: cpu: [arm64] os: [darwin] + "@esbuild/darwin-x64@0.21.5": + resolution: + { + integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [darwin] + "@esbuild/darwin-x64@0.25.10": resolution: { @@ -553,6 +784,15 @@ packages: cpu: [x64] os: [darwin] + "@esbuild/freebsd-arm64@0.21.5": + resolution: + { + integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==, + } + engines: { node: ">=12" } + cpu: [arm64] + os: [freebsd] + "@esbuild/freebsd-arm64@0.25.10": resolution: { @@ -562,6 +802,15 @@ packages: cpu: [arm64] os: [freebsd] + "@esbuild/freebsd-x64@0.21.5": + resolution: + { + integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [freebsd] + "@esbuild/freebsd-x64@0.25.10": resolution: { @@ -571,6 +820,15 @@ packages: cpu: [x64] os: [freebsd] + "@esbuild/linux-arm64@0.21.5": + resolution: + { + integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==, + } + engines: { node: ">=12" } + cpu: [arm64] + os: [linux] + "@esbuild/linux-arm64@0.25.10": resolution: { @@ -580,6 +838,15 @@ packages: cpu: [arm64] os: [linux] + "@esbuild/linux-arm@0.21.5": + resolution: + { + integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==, + } + engines: { node: ">=12" } + cpu: [arm] + os: [linux] + "@esbuild/linux-arm@0.25.10": resolution: { @@ -589,6 +856,15 @@ packages: cpu: [arm] os: [linux] + "@esbuild/linux-ia32@0.21.5": + resolution: + { + integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==, + } + engines: { node: ">=12" } + cpu: [ia32] + os: [linux] + "@esbuild/linux-ia32@0.25.10": resolution: { @@ -598,6 +874,15 @@ packages: cpu: [ia32] os: [linux] + "@esbuild/linux-loong64@0.21.5": + resolution: + { + integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==, + } + engines: { node: ">=12" } + cpu: [loong64] + os: [linux] + "@esbuild/linux-loong64@0.25.10": resolution: { @@ -607,6 +892,15 @@ packages: cpu: [loong64] os: [linux] + "@esbuild/linux-mips64el@0.21.5": + resolution: + { + integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==, + } + engines: { node: ">=12" } + cpu: [mips64el] + os: [linux] + "@esbuild/linux-mips64el@0.25.10": resolution: { @@ -616,6 +910,15 @@ packages: cpu: [mips64el] os: [linux] + "@esbuild/linux-ppc64@0.21.5": + resolution: + { + integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==, + } + engines: { node: ">=12" } + cpu: [ppc64] + os: [linux] + "@esbuild/linux-ppc64@0.25.10": resolution: { @@ -625,6 +928,15 @@ packages: cpu: [ppc64] os: [linux] + "@esbuild/linux-riscv64@0.21.5": + resolution: + { + integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==, + } + engines: { node: ">=12" } + cpu: [riscv64] + os: [linux] + "@esbuild/linux-riscv64@0.25.10": resolution: { @@ -634,6 +946,15 @@ packages: cpu: [riscv64] os: [linux] + "@esbuild/linux-s390x@0.21.5": + resolution: + { + integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==, + } + engines: { node: ">=12" } + cpu: [s390x] + os: [linux] + "@esbuild/linux-s390x@0.25.10": resolution: { @@ -643,6 +964,15 @@ packages: cpu: [s390x] os: [linux] + "@esbuild/linux-x64@0.21.5": + resolution: + { + integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [linux] + "@esbuild/linux-x64@0.25.10": resolution: { @@ -661,6 +991,15 @@ packages: cpu: [arm64] os: [netbsd] + "@esbuild/netbsd-x64@0.21.5": + resolution: + { + integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [netbsd] + "@esbuild/netbsd-x64@0.25.10": resolution: { @@ -679,6 +1018,15 @@ packages: cpu: [arm64] os: [openbsd] + "@esbuild/openbsd-x64@0.21.5": + resolution: + { + integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [openbsd] + "@esbuild/openbsd-x64@0.25.10": resolution: { @@ -697,6 +1045,15 @@ packages: cpu: [arm64] os: [openharmony] + "@esbuild/sunos-x64@0.21.5": + resolution: + { + integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [sunos] + "@esbuild/sunos-x64@0.25.10": resolution: { @@ -706,6 +1063,15 @@ packages: cpu: [x64] os: [sunos] + "@esbuild/win32-arm64@0.21.5": + resolution: + { + integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==, + } + engines: { node: ">=12" } + cpu: [arm64] + os: [win32] + "@esbuild/win32-arm64@0.25.10": resolution: { @@ -715,6 +1081,15 @@ packages: cpu: [arm64] os: [win32] + "@esbuild/win32-ia32@0.21.5": + resolution: + { + integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==, + } + engines: { node: ">=12" } + cpu: [ia32] + os: [win32] + "@esbuild/win32-ia32@0.25.10": resolution: { @@ -724,6 +1099,15 @@ packages: cpu: [ia32] os: [win32] + "@esbuild/win32-x64@0.21.5": + resolution: + { + integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [win32] + "@esbuild/win32-x64@0.25.10": resolution: { @@ -1114,6 +1498,13 @@ packages: } engines: { node: ">=18.0.0" } + "@istanbuljs/schema@0.1.3": + resolution: + { + integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==, + } + engines: { node: ">=8" } + "@jridgewell/gen-mapping@0.3.13": resolution: { @@ -1280,12 +1671,12 @@ packages: cpu: [x64] os: [win32] - "@noble/hashes@1.8.0": + "@noble/hashes@2.0.1": resolution: { - integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==, + integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==, } - engines: { node: ^14.21.3 || >=16 } + engines: { node: ">= 20.19.0" } "@nodelib/fs.scandir@2.1.5": resolution: @@ -1342,11 +1733,13 @@ packages: integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==, } - "@paralleldrive/cuid2@2.2.2": + "@paralleldrive/cuid2@2.3.0": resolution: { - integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==, + integrity: sha512-dnBUdZHawCgqpp8bJhzFDAdkzci00nCN47EiW6TxD9OVfP+gh4qVnstXRRnBKW3hm9vpa+P7cod6jiBJdf7V+g==, } + deprecated: this version is deprecated because it should have been a major bump + hasBin: true "@pkgjs/parseargs@0.11.0": resolution: @@ -1355,6 +1748,12 @@ packages: } engines: { node: ">=14" } + "@polka/url@1.0.0-next.29": + resolution: + { + integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==, + } + "@prisma/client@6.16.2": resolution: { @@ -1992,47 +2391,229 @@ packages: react: ">=16.9.0" react-dom: ">=16.9.0" - "@rc-component/qrcode@1.0.1": + "@rc-component/qrcode@1.0.1": + resolution: + { + integrity: sha512-g8eeeaMyFXVlq8cZUeaxCDhfIYjpao0l9cvm5gFwKXy/Vm1yDWV7h2sjH5jHYzdFedlVKBpATFB1VKMrHzwaWQ==, + } + engines: { node: ">=8.x" } + peerDependencies: + react: ">=16.9.0" + react-dom: ">=16.9.0" + + "@rc-component/tour@1.15.1": + resolution: + { + integrity: sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==, + } + engines: { node: ">=8.x" } + peerDependencies: + react: ">=16.9.0" + react-dom: ">=16.9.0" + + "@rc-component/trigger@2.3.0": + resolution: + { + integrity: sha512-iwaxZyzOuK0D7lS+0AQEtW52zUWxoGqTGkke3dRyb8pYiShmRpCjB/8TzPI4R6YySCH7Vm9BZj/31VPiiQTLBg==, + } + engines: { node: ">=8.x" } + peerDependencies: + react: ">=16.9.0" + react-dom: ">=16.9.0" + + "@rolldown/pluginutils@1.0.0-beta.27": + resolution: + { + integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==, + } + + "@rollup/pluginutils@5.3.0": + resolution: + { + integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==, + } + engines: { node: ">=14.0.0" } + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + "@rollup/rollup-android-arm-eabi@4.52.5": + resolution: + { + integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==, + } + cpu: [arm] + os: [android] + + "@rollup/rollup-android-arm64@4.52.5": + resolution: + { + integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==, + } + cpu: [arm64] + os: [android] + + "@rollup/rollup-darwin-arm64@4.52.5": + resolution: + { + integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==, + } + cpu: [arm64] + os: [darwin] + + "@rollup/rollup-darwin-x64@4.52.5": + resolution: + { + integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==, + } + cpu: [x64] + os: [darwin] + + "@rollup/rollup-freebsd-arm64@4.52.5": + resolution: + { + integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==, + } + cpu: [arm64] + os: [freebsd] + + "@rollup/rollup-freebsd-x64@4.52.5": + resolution: + { + integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==, + } + cpu: [x64] + os: [freebsd] + + "@rollup/rollup-linux-arm-gnueabihf@4.52.5": + resolution: + { + integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==, + } + cpu: [arm] + os: [linux] + + "@rollup/rollup-linux-arm-musleabihf@4.52.5": + resolution: + { + integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==, + } + cpu: [arm] + os: [linux] + + "@rollup/rollup-linux-arm64-gnu@4.52.5": + resolution: + { + integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==, + } + cpu: [arm64] + os: [linux] + + "@rollup/rollup-linux-arm64-musl@4.52.5": + resolution: + { + integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==, + } + cpu: [arm64] + os: [linux] + + "@rollup/rollup-linux-loong64-gnu@4.52.5": + resolution: + { + integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==, + } + cpu: [loong64] + os: [linux] + + "@rollup/rollup-linux-ppc64-gnu@4.52.5": + resolution: + { + integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==, + } + cpu: [ppc64] + os: [linux] + + "@rollup/rollup-linux-riscv64-gnu@4.52.5": + resolution: + { + integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==, + } + cpu: [riscv64] + os: [linux] + + "@rollup/rollup-linux-riscv64-musl@4.52.5": + resolution: + { + integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==, + } + cpu: [riscv64] + os: [linux] + + "@rollup/rollup-linux-s390x-gnu@4.52.5": + resolution: + { + integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==, + } + cpu: [s390x] + os: [linux] + + "@rollup/rollup-linux-x64-gnu@4.52.5": + resolution: + { + integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==, + } + cpu: [x64] + os: [linux] + + "@rollup/rollup-linux-x64-musl@4.52.5": + resolution: + { + integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==, + } + cpu: [x64] + os: [linux] + + "@rollup/rollup-openharmony-arm64@4.52.5": + resolution: + { + integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==, + } + cpu: [arm64] + os: [openharmony] + + "@rollup/rollup-win32-arm64-msvc@4.52.5": resolution: { - integrity: sha512-g8eeeaMyFXVlq8cZUeaxCDhfIYjpao0l9cvm5gFwKXy/Vm1yDWV7h2sjH5jHYzdFedlVKBpATFB1VKMrHzwaWQ==, + integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==, } - engines: { node: ">=8.x" } - peerDependencies: - react: ">=16.9.0" - react-dom: ">=16.9.0" + cpu: [arm64] + os: [win32] - "@rc-component/tour@1.15.1": + "@rollup/rollup-win32-ia32-msvc@4.52.5": resolution: { - integrity: sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==, + integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==, } - engines: { node: ">=8.x" } - peerDependencies: - react: ">=16.9.0" - react-dom: ">=16.9.0" + cpu: [ia32] + os: [win32] - "@rc-component/trigger@2.3.0": + "@rollup/rollup-win32-x64-gnu@4.52.5": resolution: { - integrity: sha512-iwaxZyzOuK0D7lS+0AQEtW52zUWxoGqTGkke3dRyb8pYiShmRpCjB/8TzPI4R6YySCH7Vm9BZj/31VPiiQTLBg==, + integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==, } - engines: { node: ">=8.x" } - peerDependencies: - react: ">=16.9.0" - react-dom: ">=16.9.0" + cpu: [x64] + os: [win32] - "@rollup/pluginutils@5.3.0": + "@rollup/rollup-win32-x64-msvc@4.52.5": resolution: { - integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==, + integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==, } - engines: { node: ">=14.0.0" } - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true + cpu: [x64] + os: [win32] "@rtsao/scc@1.1.0": resolution: @@ -2257,6 +2838,59 @@ packages: integrity: sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==, } + "@testing-library/dom@10.4.1": + resolution: + { + integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==, + } + engines: { node: ">=18" } + + "@testing-library/react-hooks@8.0.1": + resolution: + { + integrity: sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g==, + } + engines: { node: ">=12" } + peerDependencies: + "@types/react": ^16.9.0 || ^17.0.0 + react: ^16.9.0 || ^17.0.0 + react-dom: ^16.9.0 || ^17.0.0 + react-test-renderer: ^16.9.0 || ^17.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + react-dom: + optional: true + react-test-renderer: + optional: true + + "@testing-library/react@16.3.0": + resolution: + { + integrity: sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==, + } + engines: { node: ">=18" } + peerDependencies: + "@testing-library/dom": ^10.0.0 + "@types/react": ^18.0.0 || ^19.0.0 + "@types/react-dom": ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@testing-library/user-event@14.6.1": + resolution: + { + integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==, + } + engines: { node: ">=12", npm: ">=6" } + peerDependencies: + "@testing-library/dom": ">=7.21.4" + "@tootallnate/once@2.0.0": resolution: { @@ -2300,6 +2934,36 @@ packages: integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==, } + "@types/aria-query@5.0.4": + resolution: + { + integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==, + } + + "@types/babel__core@7.20.5": + resolution: + { + integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==, + } + + "@types/babel__generator@7.27.0": + resolution: + { + integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==, + } + + "@types/babel__template@7.4.4": + resolution: + { + integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==, + } + + "@types/babel__traverse@7.28.0": + resolution: + { + integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==, + } + "@types/debug@4.1.12": resolution: { @@ -2825,6 +3489,85 @@ packages: integrity: sha512-2d+TXr6K30w86a+WbMbGm2W91O0UzO5VeemZYBBUJbCjk/5FLLGIi8aV6RS2+WmaRvtcqNTn2pUA7nCOK3bGcQ==, } + "@vitejs/plugin-react@4.7.0": + resolution: + { + integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==, + } + engines: { node: ^14.18.0 || >=16.0.0 } + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + + "@vitest/coverage-v8@2.1.9": + resolution: + { + integrity: sha512-Z2cOr0ksM00MpEfyVE8KXIYPEcBFxdbLSs56L8PO0QQMxt/6bDj45uQfxoc96v05KW3clk7vvgP0qfDit9DmfQ==, + } + peerDependencies: + "@vitest/browser": 2.1.9 + vitest: 2.1.9 + peerDependenciesMeta: + "@vitest/browser": + optional: true + + "@vitest/expect@2.1.9": + resolution: + { + integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==, + } + + "@vitest/mocker@2.1.9": + resolution: + { + integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==, + } + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + "@vitest/pretty-format@2.1.9": + resolution: + { + integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==, + } + + "@vitest/runner@2.1.9": + resolution: + { + integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==, + } + + "@vitest/snapshot@2.1.9": + resolution: + { + integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==, + } + + "@vitest/spy@2.1.9": + resolution: + { + integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==, + } + + "@vitest/ui@2.1.9": + resolution: + { + integrity: sha512-izzd2zmnk8Nl5ECYkW27328RbQ1nKvkm6Bb5DAaz1Gk59EbLkiCMa6OLT0NoaAYTjOFS6N+SMYW1nh4/9ljPiw==, + } + peerDependencies: + vitest: 2.1.9 + + "@vitest/utils@2.1.9": + resolution: + { + integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==, + } + abbrev@3.0.1: resolution: { @@ -2919,6 +3662,13 @@ packages: } engines: { node: ">=8" } + ansi-styles@5.2.0: + resolution: + { + integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==, + } + engines: { node: ">=10" } + ansi-styles@6.2.3: resolution: { @@ -2972,6 +3722,12 @@ packages: } engines: { node: ">=10" } + aria-query@5.3.0: + resolution: + { + integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==, + } + aria-query@5.3.2: resolution: { @@ -3035,6 +3791,13 @@ packages: } engines: { node: ">= 0.4" } + assertion-error@2.0.1: + resolution: + { + integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==, + } + engines: { node: ">=12" } + assistant-cloud@0.1.1: resolution: { @@ -3206,6 +3969,13 @@ packages: magicast: optional: true + cac@6.7.14: + resolution: + { + integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==, + } + engines: { node: ">=8" } + call-bind-apply-helpers@1.0.2: resolution: { @@ -3246,6 +4016,13 @@ packages: integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==, } + chai@5.3.3: + resolution: + { + integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==, + } + engines: { node: ">=18" } + chalk@4.1.2: resolution: { @@ -3284,6 +4061,13 @@ packages: integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==, } + check-error@2.1.1: + resolution: + { + integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==, + } + engines: { node: ">= 16" } + chokidar@4.0.0: resolution: { @@ -3462,6 +4246,12 @@ packages: } engines: { node: ">=8" } + convert-source-map@2.0.0: + resolution: + { + integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==, + } + copy-to-clipboard@3.3.3: resolution: { @@ -3575,6 +4365,13 @@ packages: integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==, } + deep-eql@5.0.2: + resolution: + { + integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==, + } + engines: { node: ">=6" } + deep-is@0.1.4: resolution: { @@ -3661,6 +4458,12 @@ packages: } engines: { node: ">=0.10.0" } + dom-accessibility-api@0.5.16: + resolution: + { + integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==, + } + dotenv@16.6.1: resolution: { @@ -3746,6 +4549,13 @@ packages: } engines: { node: ">=10.13.0" } + entities@4.5.0: + resolution: + { + integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==, + } + engines: { node: ">=0.12" } + entities@6.0.1: resolution: { @@ -3760,6 +4570,12 @@ packages: } engines: { node: ">=18" } + error-causes@3.0.2: + resolution: + { + integrity: sha512-i0B8zq1dHL6mM85FGoxaJnVtx6LD5nL2v0hlpGdntg5FOSyzQ46c9lmz5qx0xRS2+PWHGOHcYxGIBC5Le2dRMw==, + } + es-abstract@1.24.0: resolution: { @@ -3794,6 +4610,12 @@ packages: integrity: sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==, } + es-module-lexer@1.7.0: + resolution: + { + integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==, + } + es-object-atoms@1.1.1: resolution: { @@ -4022,6 +4844,14 @@ packages: engines: { node: ">=12" } hasBin: true + esbuild@0.21.5: + resolution: + { + integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==, + } + engines: { node: ">=12" } + hasBin: true + esbuild@0.25.10: resolution: { @@ -4306,6 +5136,13 @@ packages: } engines: { node: ">=18.0.0" } + expect-type@1.2.2: + resolution: + { + integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==, + } + engines: { node: ">=12.0.0" } + exsolve@1.0.7: resolution: { @@ -4388,6 +5225,12 @@ packages: picomatch: optional: true + fflate@0.8.2: + resolution: + { + integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==, + } + file-entry-cache@8.0.0: resolution: { @@ -4479,6 +5322,14 @@ packages: } engines: { node: ">= 8" } + fsevents@2.3.3: + resolution: + { + integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, + } + engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } + os: [darwin] + fumadocs-core@15.7.13: resolution: { @@ -4584,6 +5435,13 @@ packages: } engines: { node: ">= 4" } + gensync@1.0.0-beta.2: + resolution: + { + integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, + } + engines: { node: ">=6.9.0" } + get-east-asian-width@1.4.0: resolution: { @@ -4705,6 +5563,13 @@ packages: } engines: { node: ">=6.0" } + happy-dom@15.11.7: + resolution: + { + integrity: sha512-KyrFvnl+J9US63TEzwoiJOQzZBJY7KgBushJA8X61DMbNsH+2ONkDuLDnCnwUiPTF42tLoEmrPyoqbenVA5zrg==, + } + engines: { node: ">=18.0.0" } + has-bigints@1.1.0: resolution: { @@ -4837,6 +5702,12 @@ packages: integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==, } + html-escaper@2.0.2: + resolution: + { + integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==, + } + html-url-attributes@3.0.1: resolution: { @@ -5198,23 +6069,51 @@ packages: } engines: { node: ">= 0.4" } - isarray@0.0.1: + isarray@0.0.1: + resolution: + { + integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==, + } + + isarray@2.0.5: + resolution: + { + integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==, + } + + isexe@2.0.0: + resolution: + { + integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + } + + istanbul-lib-coverage@3.2.2: + resolution: + { + integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==, + } + engines: { node: ">=8" } + + istanbul-lib-report@3.0.1: resolution: { - integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==, + integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==, } + engines: { node: ">=10" } - isarray@2.0.5: + istanbul-lib-source-maps@5.0.6: resolution: { - integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==, + integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==, } + engines: { node: ">=10" } - isexe@2.0.0: + istanbul-reports@3.2.0: resolution: { - integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==, } + engines: { node: ">=8" } iterator.prototype@1.1.5: resolution: @@ -5268,6 +6167,14 @@ packages: } hasBin: true + jsesc@3.1.0: + resolution: + { + integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==, + } + engines: { node: ">=6" } + hasBin: true + json-buffer@3.0.1: resolution: { @@ -5317,6 +6224,14 @@ packages: } hasBin: true + json5@2.2.3: + resolution: + { + integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==, + } + engines: { node: ">=6" } + hasBin: true + jsonfile@6.2.0: resolution: { @@ -5540,6 +6455,12 @@ packages: } hasBin: true + loupe@3.2.1: + resolution: + { + integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==, + } + lru-cache@10.4.3: resolution: { @@ -5553,6 +6474,12 @@ packages: } engines: { node: 20 || >=22 } + lru-cache@5.1.1: + resolution: + { + integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, + } + lru-cache@6.0.0: resolution: { @@ -5568,12 +6495,32 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + lz-string@1.5.0: + resolution: + { + integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==, + } + hasBin: true + magic-string@0.30.19: resolution: { integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==, } + magicast@0.3.5: + resolution: + { + integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==, + } + + make-dir@4.0.0: + resolution: + { + integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==, + } + engines: { node: ">=10" } + make-error@1.3.6: resolution: { @@ -6067,6 +7014,13 @@ packages: } engines: { node: ">=4" } + mrmime@2.0.1: + resolution: + { + integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==, + } + engines: { node: ">=10" } + ms@2.1.1: resolution: { @@ -6503,12 +7457,25 @@ packages: integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==, } + pathe@1.1.2: + resolution: + { + integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==, + } + pathe@2.0.3: resolution: { integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==, } + pathval@2.0.1: + resolution: + { + integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==, + } + engines: { node: ">= 14.16" } + pend@1.2.0: resolution: { @@ -6720,6 +7687,13 @@ packages: engines: { node: ">=14" } hasBin: true + pretty-format@27.5.1: + resolution: + { + integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==, + } + engines: { node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0 } + pretty-ms@7.0.1: resolution: { @@ -7128,12 +8102,27 @@ packages: peerDependencies: react: ^19.1.1 + react-error-boundary@3.1.4: + resolution: + { + integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==, + } + engines: { node: ">=10", npm: ">=6" } + peerDependencies: + react: ">=16.13.1" + react-is@16.13.1: resolution: { integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==, } + react-is@17.0.2: + resolution: + { + integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==, + } + react-is@18.3.1: resolution: { @@ -7158,6 +8147,13 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-refresh@0.17.0: + resolution: + { + integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==, + } + engines: { node: ">=0.10.0" } + react-remove-scroll-bar@2.3.8: resolution: { @@ -7419,6 +8415,14 @@ packages: integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==, } + rollup@4.52.5: + resolution: + { + integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==, + } + engines: { node: ">=18.0.0", npm: ">=8.0.0" } + hasBin: true + run-parallel@1.2.0: resolution: { @@ -7582,6 +8586,12 @@ packages: } engines: { node: ">= 0.4" } + siginfo@2.0.0: + resolution: + { + integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==, + } + signal-exit@4.0.2: resolution: { @@ -7596,6 +8606,13 @@ packages: } engines: { node: ">=14" } + sirv@3.0.2: + resolution: + { + integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==, + } + engines: { node: ">=18" } + slice-ansi@7.1.2: resolution: { @@ -7635,6 +8652,12 @@ packages: integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==, } + stackback@0.0.2: + resolution: + { + integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==, + } + stat-mode@0.3.0: resolution: { @@ -7648,6 +8671,12 @@ packages: } engines: { node: ">= 0.6" } + std-env@3.10.0: + resolution: + { + integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==, + } + stop-iteration-iterator@1.1.0: resolution: { @@ -7879,6 +8908,13 @@ packages: } engines: { node: ">=18" } + test-exclude@7.0.1: + resolution: + { + integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==, + } + engines: { node: ">=18" } + throttle-debounce@5.0.2: resolution: { @@ -7900,6 +8936,12 @@ packages: } engines: { node: ">=10" } + tinybench@2.9.0: + resolution: + { + integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==, + } + tinyexec@0.3.2: resolution: { @@ -7919,6 +8961,27 @@ packages: } engines: { node: ">=12.0.0" } + tinypool@1.1.1: + resolution: + { + integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==, + } + engines: { node: ^18.0.0 || >=20.0.0 } + + tinyrainbow@1.2.0: + resolution: + { + integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==, + } + engines: { node: ">=14.0.0" } + + tinyspy@3.0.2: + resolution: + { + integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==, + } + engines: { node: ">=14.0.0" } + to-regex-range@5.0.1: resolution: { @@ -7939,6 +9002,13 @@ packages: } engines: { node: ">=0.6" } + totalist@3.0.1: + resolution: + { + integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==, + } + engines: { node: ">=6" } + tr46@0.0.3: resolution: { @@ -8315,6 +9385,76 @@ packages: integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==, } + vite-node@2.1.9: + resolution: + { + integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==, + } + engines: { node: ^18.0.0 || >=20.0.0 } + hasBin: true + + vite@5.4.21: + resolution: + { + integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==, + } + engines: { node: ^18.0.0 || >=20.0.0 } + hasBin: true + peerDependencies: + "@types/node": ^18.0.0 || >=20.0.0 + less: "*" + lightningcss: ^1.21.0 + sass: "*" + sass-embedded: "*" + stylus: "*" + sugarss: "*" + terser: ^5.4.0 + peerDependenciesMeta: + "@types/node": + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitest@2.1.9: + resolution: + { + integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==, + } + engines: { node: ^18.0.0 || >=20.0.0 } + hasBin: true + peerDependencies: + "@edge-runtime/vm": "*" + "@types/node": ^18.0.0 || >=20.0.0 + "@vitest/browser": 2.1.9 + "@vitest/ui": 2.1.9 + happy-dom: "*" + jsdom: "*" + peerDependenciesMeta: + "@edge-runtime/vm": + optional: true + "@types/node": + optional: true + "@vitest/browser": + optional: true + "@vitest/ui": + optional: true + happy-dom: + optional: true + jsdom: + optional: true + web-namespaces@2.0.1: resolution: { @@ -8333,6 +9473,20 @@ packages: integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==, } + webidl-conversions@7.0.0: + resolution: + { + integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==, + } + engines: { node: ">=12" } + + whatwg-mimetype@3.0.0: + resolution: + { + integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==, + } + engines: { node: ">=12" } + whatwg-url@5.0.0: resolution: { @@ -8375,6 +9529,14 @@ packages: engines: { node: ">= 8" } hasBin: true + why-is-node-running@2.3.0: + resolution: + { + integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==, + } + engines: { node: ">=8" } + hasBin: true + word-wrap@1.2.5: resolution: { @@ -8430,6 +9592,12 @@ packages: } engines: { node: ">=0.4" } + yallist@3.1.1: + resolution: + { + integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==, + } + yallist@4.0.0: resolution: { @@ -8531,10 +9699,10 @@ snapshots: "@ai-sdk/provider-utils": 3.0.9(zod@4.1.11) zod: 4.1.11 - "@ai-sdk/openai-compatible@1.0.19(zod@4.1.11)": + "@ai-sdk/openai-compatible@1.0.22(zod@4.1.11)": dependencies: "@ai-sdk/provider": 2.0.0 - "@ai-sdk/provider-utils": 3.0.10(zod@4.1.11) + "@ai-sdk/provider-utils": 3.0.12(zod@4.1.11) zod: 4.1.11 "@ai-sdk/openai@2.0.32(zod@4.1.11)": @@ -8543,7 +9711,7 @@ snapshots: "@ai-sdk/provider-utils": 3.0.9(zod@4.1.11) zod: 4.1.11 - "@ai-sdk/provider-utils@3.0.10(zod@4.1.11)": + "@ai-sdk/provider-utils@3.0.12(zod@4.1.11)": dependencies: "@ai-sdk/provider": 2.0.0 "@standard-schema/spec": 1.0.0 @@ -8573,6 +9741,11 @@ snapshots: "@alloc/quick-lru@5.2.0": {} + "@ampproject/remapping@2.3.0": + dependencies: + "@jridgewell/gen-mapping": 0.3.13 + "@jridgewell/trace-mapping": 0.3.31 + "@ant-design/colors@7.2.1": dependencies: "@ant-design/fast-color": 2.0.6 @@ -8707,8 +9880,122 @@ snapshots: - "@simplewebauthn/server" - nodemailer + "@babel/code-frame@7.27.1": + dependencies: + "@babel/helper-validator-identifier": 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + "@babel/compat-data@7.28.4": {} + + "@babel/core@7.28.4": + dependencies: + "@babel/code-frame": 7.27.1 + "@babel/generator": 7.28.3 + "@babel/helper-compilation-targets": 7.27.2 + "@babel/helper-module-transforms": 7.28.3(@babel/core@7.28.4) + "@babel/helpers": 7.28.4 + "@babel/parser": 7.28.4 + "@babel/template": 7.27.2 + "@babel/traverse": 7.28.4 + "@babel/types": 7.28.4 + "@jridgewell/remapping": 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + "@babel/generator@7.28.3": + dependencies: + "@babel/parser": 7.28.4 + "@babel/types": 7.28.4 + "@jridgewell/gen-mapping": 0.3.13 + "@jridgewell/trace-mapping": 0.3.31 + jsesc: 3.1.0 + + "@babel/helper-compilation-targets@7.27.2": + dependencies: + "@babel/compat-data": 7.28.4 + "@babel/helper-validator-option": 7.27.1 + browserslist: 4.26.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + "@babel/helper-globals@7.28.0": {} + + "@babel/helper-module-imports@7.27.1": + dependencies: + "@babel/traverse": 7.28.4 + "@babel/types": 7.28.4 + transitivePeerDependencies: + - supports-color + + "@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)": + dependencies: + "@babel/core": 7.28.4 + "@babel/helper-module-imports": 7.27.1 + "@babel/helper-validator-identifier": 7.27.1 + "@babel/traverse": 7.28.4 + transitivePeerDependencies: + - supports-color + + "@babel/helper-plugin-utils@7.27.1": {} + + "@babel/helper-string-parser@7.27.1": {} + + "@babel/helper-validator-identifier@7.27.1": {} + + "@babel/helper-validator-option@7.27.1": {} + + "@babel/helpers@7.28.4": + dependencies: + "@babel/template": 7.27.2 + "@babel/types": 7.28.4 + + "@babel/parser@7.28.4": + dependencies: + "@babel/types": 7.28.4 + + "@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4)": + dependencies: + "@babel/core": 7.28.4 + "@babel/helper-plugin-utils": 7.27.1 + + "@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.4)": + dependencies: + "@babel/core": 7.28.4 + "@babel/helper-plugin-utils": 7.27.1 + "@babel/runtime@7.28.4": {} + "@babel/template@7.27.2": + dependencies: + "@babel/code-frame": 7.27.1 + "@babel/parser": 7.28.4 + "@babel/types": 7.28.4 + + "@babel/traverse@7.28.4": + dependencies: + "@babel/code-frame": 7.27.1 + "@babel/generator": 7.28.3 + "@babel/helper-globals": 7.28.0 + "@babel/parser": 7.28.4 + "@babel/template": 7.27.2 + "@babel/types": 7.28.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + "@babel/types@7.28.4": + dependencies: + "@babel/helper-string-parser": 7.27.1 + "@babel/helper-validator-identifier": 7.27.1 + + "@bcoe/v8-coverage@0.2.3": {} + "@cspotcode/source-map-support@0.8.1": dependencies: "@jridgewell/trace-mapping": 0.3.9 @@ -8745,81 +10032,150 @@ snapshots: "@emotion/unitless@0.7.5": {} + "@esbuild/aix-ppc64@0.21.5": + optional: true + "@esbuild/aix-ppc64@0.25.10": optional: true + "@esbuild/android-arm64@0.21.5": + optional: true + "@esbuild/android-arm64@0.25.10": optional: true + "@esbuild/android-arm@0.21.5": + optional: true + "@esbuild/android-arm@0.25.10": optional: true + "@esbuild/android-x64@0.21.5": + optional: true + "@esbuild/android-x64@0.25.10": optional: true + "@esbuild/darwin-arm64@0.21.5": + optional: true + "@esbuild/darwin-arm64@0.25.10": optional: true + "@esbuild/darwin-x64@0.21.5": + optional: true + "@esbuild/darwin-x64@0.25.10": optional: true + "@esbuild/freebsd-arm64@0.21.5": + optional: true + "@esbuild/freebsd-arm64@0.25.10": optional: true + "@esbuild/freebsd-x64@0.21.5": + optional: true + "@esbuild/freebsd-x64@0.25.10": optional: true - "@esbuild/linux-arm64@0.25.10": + "@esbuild/linux-arm64@0.21.5": + optional: true + + "@esbuild/linux-arm64@0.25.10": + optional: true + + "@esbuild/linux-arm@0.21.5": optional: true "@esbuild/linux-arm@0.25.10": optional: true + "@esbuild/linux-ia32@0.21.5": + optional: true + "@esbuild/linux-ia32@0.25.10": optional: true + "@esbuild/linux-loong64@0.21.5": + optional: true + "@esbuild/linux-loong64@0.25.10": optional: true + "@esbuild/linux-mips64el@0.21.5": + optional: true + "@esbuild/linux-mips64el@0.25.10": optional: true + "@esbuild/linux-ppc64@0.21.5": + optional: true + "@esbuild/linux-ppc64@0.25.10": optional: true + "@esbuild/linux-riscv64@0.21.5": + optional: true + "@esbuild/linux-riscv64@0.25.10": optional: true + "@esbuild/linux-s390x@0.21.5": + optional: true + "@esbuild/linux-s390x@0.25.10": optional: true + "@esbuild/linux-x64@0.21.5": + optional: true + "@esbuild/linux-x64@0.25.10": optional: true "@esbuild/netbsd-arm64@0.25.10": optional: true + "@esbuild/netbsd-x64@0.21.5": + optional: true + "@esbuild/netbsd-x64@0.25.10": optional: true "@esbuild/openbsd-arm64@0.25.10": optional: true + "@esbuild/openbsd-x64@0.21.5": + optional: true + "@esbuild/openbsd-x64@0.25.10": optional: true "@esbuild/openharmony-arm64@0.25.10": optional: true + "@esbuild/sunos-x64@0.21.5": + optional: true + "@esbuild/sunos-x64@0.25.10": optional: true + "@esbuild/win32-arm64@0.21.5": + optional: true + "@esbuild/win32-arm64@0.25.10": optional: true + "@esbuild/win32-ia32@0.21.5": + optional: true + "@esbuild/win32-ia32@0.25.10": optional: true + "@esbuild/win32-x64@0.21.5": + optional: true + "@esbuild/win32-x64@0.25.10": optional: true @@ -9035,6 +10391,8 @@ snapshots: dependencies: minipass: 7.1.2 + "@istanbuljs/schema@0.1.3": {} + "@jridgewell/gen-mapping@0.3.13": dependencies: "@jridgewell/sourcemap-codec": 1.5.5 @@ -9154,7 +10512,7 @@ snapshots: "@next/swc-win32-x64-msvc@15.5.3": optional: true - "@noble/hashes@1.8.0": {} + "@noble/hashes@2.0.1": {} "@nodelib/fs.scandir@2.1.5": dependencies: @@ -9180,21 +10538,24 @@ snapshots: "@panva/hkdf@1.2.1": {} - "@paralleldrive/cuid2@2.2.2": + "@paralleldrive/cuid2@2.3.0": dependencies: - "@noble/hashes": 1.8.0 + "@noble/hashes": 2.0.1 + error-causes: 3.0.2 "@pkgjs/parseargs@0.11.0": optional: true - "@prisma/client@6.16.2(prisma@6.16.2(typescript@5.9.2))(typescript@5.9.2)": + "@polka/url@1.0.0-next.29": {} + + "@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2)": optionalDependencies: - prisma: 6.16.2(typescript@5.9.2) + prisma: 6.16.2(magicast@0.3.5)(typescript@5.9.2) typescript: 5.9.2 - "@prisma/config@6.16.2": + "@prisma/config@6.16.2(magicast@0.3.5)": dependencies: - c12: 3.1.0 + c12: 3.1.0(magicast@0.3.5) deepmerge-ts: 7.1.5 effect: 3.16.12 empathic: 2.0.0 @@ -9707,11 +11068,81 @@ snapshots: react: 19.1.1 react-dom: 19.1.1(react@19.1.1) - "@rollup/pluginutils@5.3.0": + "@rolldown/pluginutils@1.0.0-beta.27": {} + + "@rollup/pluginutils@5.3.0(rollup@4.52.5)": dependencies: "@types/estree": 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 + optionalDependencies: + rollup: 4.52.5 + + "@rollup/rollup-android-arm-eabi@4.52.5": + optional: true + + "@rollup/rollup-android-arm64@4.52.5": + optional: true + + "@rollup/rollup-darwin-arm64@4.52.5": + optional: true + + "@rollup/rollup-darwin-x64@4.52.5": + optional: true + + "@rollup/rollup-freebsd-arm64@4.52.5": + optional: true + + "@rollup/rollup-freebsd-x64@4.52.5": + optional: true + + "@rollup/rollup-linux-arm-gnueabihf@4.52.5": + optional: true + + "@rollup/rollup-linux-arm-musleabihf@4.52.5": + optional: true + + "@rollup/rollup-linux-arm64-gnu@4.52.5": + optional: true + + "@rollup/rollup-linux-arm64-musl@4.52.5": + optional: true + + "@rollup/rollup-linux-loong64-gnu@4.52.5": + optional: true + + "@rollup/rollup-linux-ppc64-gnu@4.52.5": + optional: true + + "@rollup/rollup-linux-riscv64-gnu@4.52.5": + optional: true + + "@rollup/rollup-linux-riscv64-musl@4.52.5": + optional: true + + "@rollup/rollup-linux-s390x-gnu@4.52.5": + optional: true + + "@rollup/rollup-linux-x64-gnu@4.52.5": + optional: true + + "@rollup/rollup-linux-x64-musl@4.52.5": + optional: true + + "@rollup/rollup-openharmony-arm64@4.52.5": + optional: true + + "@rollup/rollup-win32-arm64-msvc@4.52.5": + optional: true + + "@rollup/rollup-win32-ia32-msvc@4.52.5": + optional: true + + "@rollup/rollup-win32-x64-gnu@4.52.5": + optional: true + + "@rollup/rollup-win32-x64-msvc@4.52.5": + optional: true "@rtsao/scc@1.1.0": {} @@ -9846,6 +11277,40 @@ snapshots: postcss: 8.5.6 tailwindcss: 4.1.13 + "@testing-library/dom@10.4.1": + dependencies: + "@babel/code-frame": 7.27.1 + "@babel/runtime": 7.28.4 + "@types/aria-query": 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + "@testing-library/react-hooks@8.0.1(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)": + dependencies: + "@babel/runtime": 7.28.4 + react: 19.1.1 + react-error-boundary: 3.1.4(react@19.1.1) + optionalDependencies: + "@types/react": 19.1.13 + react-dom: 19.1.1(react@19.1.1) + + "@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)": + dependencies: + "@babel/runtime": 7.28.4 + "@testing-library/dom": 10.4.1 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + "@types/react": 19.1.13 + "@types/react-dom": 19.1.9(@types/react@19.1.13) + + "@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)": + dependencies: + "@testing-library/dom": 10.4.1 + "@tootallnate/once@2.0.0": {} "@ts-morph/common@0.11.1": @@ -9868,6 +11333,29 @@ snapshots: tslib: 2.8.1 optional: true + "@types/aria-query@5.0.4": {} + + "@types/babel__core@7.20.5": + dependencies: + "@babel/parser": 7.28.4 + "@babel/types": 7.28.4 + "@types/babel__generator": 7.27.0 + "@types/babel__template": 7.4.4 + "@types/babel__traverse": 7.28.0 + + "@types/babel__generator@7.27.0": + dependencies: + "@babel/types": 7.28.4 + + "@types/babel__template@7.4.4": + dependencies: + "@babel/parser": 7.28.4 + "@babel/types": 7.28.4 + + "@types/babel__traverse@7.28.0": + dependencies: + "@babel/types": 7.28.4 + "@types/debug@4.1.12": dependencies: "@types/ms": 2.1.0 @@ -10100,9 +11588,9 @@ snapshots: "@vercel/error-utils@2.0.3": {} - "@vercel/express@0.0.17": + "@vercel/express@0.0.17(rollup@4.52.5)": dependencies: - "@vercel/node": 5.3.23 + "@vercel/node": 5.3.23(rollup@4.52.5) "@vercel/static-config": 3.1.2 ts-morph: 12.0.0 transitivePeerDependencies: @@ -10150,9 +11638,9 @@ snapshots: "@vercel/go@3.2.3": {} - "@vercel/h3@0.1.1": + "@vercel/h3@0.1.1(rollup@4.52.5)": dependencies: - "@vercel/node": 5.3.23 + "@vercel/node": 5.3.23(rollup@4.52.5) "@vercel/static-config": 3.1.2 transitivePeerDependencies: - "@swc/core" @@ -10161,9 +11649,9 @@ snapshots: - rollup - supports-color - "@vercel/hono@0.1.1": + "@vercel/hono@0.1.1(rollup@4.52.5)": dependencies: - "@vercel/node": 5.3.23 + "@vercel/node": 5.3.23(rollup@4.52.5) "@vercel/static-config": 3.1.2 ts-morph: 12.0.0 transitivePeerDependencies: @@ -10178,18 +11666,18 @@ snapshots: "@vercel/static-config": 3.1.2 ts-morph: 12.0.0 - "@vercel/next@4.12.6": + "@vercel/next@4.12.6(rollup@4.52.5)": dependencies: - "@vercel/nft": 0.30.1 + "@vercel/nft": 0.30.1(rollup@4.52.5) transitivePeerDependencies: - encoding - rollup - supports-color - "@vercel/nft@0.30.1": + "@vercel/nft@0.30.1(rollup@4.52.5)": dependencies: "@mapbox/node-pre-gyp": 2.0.0 - "@rollup/pluginutils": 5.3.0 + "@rollup/pluginutils": 5.3.0(rollup@4.52.5) acorn: 8.15.0 acorn-import-attributes: 1.9.5(acorn@8.15.0) async-sema: 3.1.1 @@ -10205,7 +11693,7 @@ snapshots: - rollup - supports-color - "@vercel/node@5.3.23": + "@vercel/node@5.3.23(rollup@4.52.5)": dependencies: "@edge-runtime/node-utils": 2.3.0 "@edge-runtime/primitives": 4.1.0 @@ -10213,7 +11701,7 @@ snapshots: "@types/node": 16.18.11 "@vercel/build-utils": 12.1.0 "@vercel/error-utils": 2.0.3 - "@vercel/nft": 0.30.1 + "@vercel/nft": 0.30.1(rollup@4.52.5) "@vercel/static-config": 3.1.2 async-listen: 3.0.0 cjs-module-lexer: 1.2.3 @@ -10238,9 +11726,9 @@ snapshots: "@vercel/python@5.0.5": {} - "@vercel/redwood@2.3.6": + "@vercel/redwood@2.3.6(rollup@4.52.5)": dependencies: - "@vercel/nft": 0.30.1 + "@vercel/nft": 0.30.1(rollup@4.52.5) "@vercel/static-config": 3.1.2 semver: 6.3.1 ts-morph: 12.0.0 @@ -10249,10 +11737,10 @@ snapshots: - rollup - supports-color - "@vercel/remix-builder@5.4.12": + "@vercel/remix-builder@5.4.12(rollup@4.52.5)": dependencies: "@vercel/error-utils": 2.0.3 - "@vercel/nft": 0.30.1 + "@vercel/nft": 0.30.1(rollup@4.52.5) "@vercel/static-config": 3.1.2 path-to-regexp: 6.1.0 path-to-regexp-updated: path-to-regexp@6.3.0 @@ -10264,9 +11752,9 @@ snapshots: "@vercel/ruby@2.2.1": {} - "@vercel/speed-insights@1.2.0(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)": + "@vercel/speed-insights@1.2.0(next@15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)": optionalDependencies: - next: 15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + next: 15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react: 19.1.1 "@vercel/static-build@2.7.23": @@ -10282,6 +11770,87 @@ snapshots: json-schema-to-ts: 1.6.4 ts-morph: 12.0.0 + "@vitejs/plugin-react@4.7.0(vite@5.4.21(@types/node@24.5.2)(lightningcss@1.30.1))": + dependencies: + "@babel/core": 7.28.4 + "@babel/plugin-transform-react-jsx-self": 7.27.1(@babel/core@7.28.4) + "@babel/plugin-transform-react-jsx-source": 7.27.1(@babel/core@7.28.4) + "@rolldown/pluginutils": 1.0.0-beta.27 + "@types/babel__core": 7.20.5 + react-refresh: 0.17.0 + vite: 5.4.21(@types/node@24.5.2)(lightningcss@1.30.1) + transitivePeerDependencies: + - supports-color + + "@vitest/coverage-v8@2.1.9(vitest@2.1.9)": + dependencies: + "@ampproject/remapping": 2.3.0 + "@bcoe/v8-coverage": 0.2.3 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + magic-string: 0.30.19 + magicast: 0.3.5 + std-env: 3.10.0 + test-exclude: 7.0.1 + tinyrainbow: 1.2.0 + vitest: 2.1.9(@edge-runtime/vm@3.2.0)(@types/node@24.5.2)(@vitest/ui@2.1.9)(happy-dom@15.11.7)(lightningcss@1.30.1) + transitivePeerDependencies: + - supports-color + + "@vitest/expect@2.1.9": + dependencies: + "@vitest/spy": 2.1.9 + "@vitest/utils": 2.1.9 + chai: 5.3.3 + tinyrainbow: 1.2.0 + + "@vitest/mocker@2.1.9(vite@5.4.21(@types/node@24.5.2)(lightningcss@1.30.1))": + dependencies: + "@vitest/spy": 2.1.9 + estree-walker: 3.0.3 + magic-string: 0.30.19 + optionalDependencies: + vite: 5.4.21(@types/node@24.5.2)(lightningcss@1.30.1) + + "@vitest/pretty-format@2.1.9": + dependencies: + tinyrainbow: 1.2.0 + + "@vitest/runner@2.1.9": + dependencies: + "@vitest/utils": 2.1.9 + pathe: 1.1.2 + + "@vitest/snapshot@2.1.9": + dependencies: + "@vitest/pretty-format": 2.1.9 + magic-string: 0.30.19 + pathe: 1.1.2 + + "@vitest/spy@2.1.9": + dependencies: + tinyspy: 3.0.2 + + "@vitest/ui@2.1.9(vitest@2.1.9)": + dependencies: + "@vitest/utils": 2.1.9 + fflate: 0.8.2 + flatted: 3.3.3 + pathe: 1.1.2 + sirv: 3.0.2 + tinyglobby: 0.2.15 + tinyrainbow: 1.2.0 + vitest: 2.1.9(@edge-runtime/vm@3.2.0)(@types/node@24.5.2)(@vitest/ui@2.1.9)(happy-dom@15.11.7)(lightningcss@1.30.1) + + "@vitest/utils@2.1.9": + dependencies: + "@vitest/pretty-format": 2.1.9 + loupe: 3.2.1 + tinyrainbow: 1.2.0 + abbrev@3.0.1: {} acorn-import-attributes@1.9.5(acorn@8.15.0): @@ -10334,6 +11903,8 @@ snapshots: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi-styles@6.2.3: {} antd@5.27.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1): @@ -10410,6 +11981,10 @@ snapshots: dependencies: tslib: 2.8.1 + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + aria-query@5.3.2: {} array-buffer-byte-length@1.0.2: @@ -10479,6 +12054,8 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 + assertion-error@2.0.1: {} + assistant-cloud@0.1.1: dependencies: assistant-stream: 0.2.28 @@ -10560,7 +12137,7 @@ snapshots: bytes@3.1.0: {} - c12@3.1.0: + c12@3.1.0(magicast@0.3.5): dependencies: chokidar: 4.0.3 confbox: 0.2.2 @@ -10574,6 +12151,10 @@ snapshots: perfect-debounce: 1.0.0 pkg-types: 2.3.0 rc9: 2.1.2 + optionalDependencies: + magicast: 0.3.5 + + cac@6.7.14: {} call-bind-apply-helpers@1.0.2: dependencies: @@ -10598,6 +12179,14 @@ snapshots: ccount@2.0.1: {} + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -10613,6 +12202,8 @@ snapshots: character-reference-invalid@2.0.1: {} + check-error@2.1.1: {} + chokidar@4.0.0: dependencies: readdirp: 4.1.2 @@ -10692,6 +12283,8 @@ snapshots: convert-hrtime@3.0.0: {} + convert-source-map@2.0.0: {} + copy-to-clipboard@3.3.3: dependencies: toggle-selection: 1.0.6 @@ -10748,6 +12341,8 @@ snapshots: dependencies: character-entities: 2.0.2 + deep-eql@5.0.2: {} + deep-is@0.1.4: {} deepmerge-ts@7.1.5: {} @@ -10786,6 +12381,8 @@ snapshots: dependencies: esutils: 2.0.3 + dom-accessibility-api@0.5.16: {} + dotenv@16.6.1: {} dotenv@17.2.3: {} @@ -10834,10 +12431,14 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.2.3 + entities@4.5.0: {} + entities@6.0.1: {} environment@1.1.0: {} + error-causes@3.0.2: {} + es-abstract@1.24.0: dependencies: array-buffer-byte-length: 1.0.2 @@ -10920,6 +12521,8 @@ snapshots: es-module-lexer@1.4.1: {} + es-module-lexer@1.7.0: {} + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -11038,6 +12641,32 @@ snapshots: esbuild-windows-64: 0.14.47 esbuild-windows-arm64: 0.14.47 + esbuild@0.21.5: + optionalDependencies: + "@esbuild/aix-ppc64": 0.21.5 + "@esbuild/android-arm": 0.21.5 + "@esbuild/android-arm64": 0.21.5 + "@esbuild/android-x64": 0.21.5 + "@esbuild/darwin-arm64": 0.21.5 + "@esbuild/darwin-x64": 0.21.5 + "@esbuild/freebsd-arm64": 0.21.5 + "@esbuild/freebsd-x64": 0.21.5 + "@esbuild/linux-arm": 0.21.5 + "@esbuild/linux-arm64": 0.21.5 + "@esbuild/linux-ia32": 0.21.5 + "@esbuild/linux-loong64": 0.21.5 + "@esbuild/linux-mips64el": 0.21.5 + "@esbuild/linux-ppc64": 0.21.5 + "@esbuild/linux-riscv64": 0.21.5 + "@esbuild/linux-s390x": 0.21.5 + "@esbuild/linux-x64": 0.21.5 + "@esbuild/netbsd-x64": 0.21.5 + "@esbuild/openbsd-x64": 0.21.5 + "@esbuild/sunos-x64": 0.21.5 + "@esbuild/win32-arm64": 0.21.5 + "@esbuild/win32-ia32": 0.21.5 + "@esbuild/win32-x64": 0.21.5 + esbuild@0.25.10: optionalDependencies: "@esbuild/aix-ppc64": 0.25.10 @@ -11319,6 +12948,8 @@ snapshots: eventsource-parser@3.0.6: {} + expect-type@1.2.2: {} + exsolve@1.0.7: {} extend-shallow@2.0.1: @@ -11365,6 +12996,8 @@ snapshots: optionalDependencies: picomatch: 4.0.3 + fflate@0.8.2: {} + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -11417,7 +13050,10 @@ snapshots: dependencies: minipass: 3.3.6 - fumadocs-core@15.7.13(@types/react@19.1.13)(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + fsevents@2.3.3: + optional: true + + fumadocs-core@15.7.13(@types/react@19.1.13)(next@15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: "@formatjs/intl-localematcher": 0.6.1 "@orama/orama": 3.1.14 @@ -11438,20 +13074,20 @@ snapshots: unist-util-visit: 5.0.0 optionalDependencies: "@types/react": 19.1.13 - next: 15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + next: 15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react: 19.1.1 react-dom: 19.1.1(react@19.1.1) transitivePeerDependencies: - supports-color - fumadocs-mdx@11.10.1(fumadocs-core@15.7.13(@types/react@19.1.13)(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1): + fumadocs-mdx@11.10.1(fumadocs-core@15.7.13(@types/react@19.1.13)(next@15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(next@15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(vite@5.4.21(@types/node@24.5.2)(lightningcss@1.30.1)): dependencies: "@mdx-js/mdx": 3.1.1 "@standard-schema/spec": 1.0.0 chokidar: 4.0.3 esbuild: 0.25.10 estree-util-value-to-estree: 3.4.0 - fumadocs-core: 15.7.13(@types/react@19.1.13)(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + fumadocs-core: 15.7.13(@types/react@19.1.13)(next@15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1) js-yaml: 4.1.0 lru-cache: 11.2.1 picocolors: 1.1.1 @@ -11463,12 +13099,13 @@ snapshots: unist-util-visit: 5.0.0 zod: 4.1.11 optionalDependencies: - next: 15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + next: 15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react: 19.1.1 + vite: 5.4.21(@types/node@24.5.2)(lightningcss@1.30.1) transitivePeerDependencies: - supports-color - fumadocs-ui@15.7.13(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(tailwindcss@4.1.13): + fumadocs-ui@15.7.13(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(next@15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(tailwindcss@4.1.13): dependencies: "@radix-ui/react-accordion": 1.2.12(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) "@radix-ui/react-collapsible": 1.1.12(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -11481,7 +13118,7 @@ snapshots: "@radix-ui/react-slot": 1.2.3(@types/react@19.1.13)(react@19.1.1) "@radix-ui/react-tabs": 1.1.13(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) class-variance-authority: 0.7.1 - fumadocs-core: 15.7.13(@types/react@19.1.13)(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + fumadocs-core: 15.7.13(@types/react@19.1.13)(next@15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1) lodash.merge: 4.6.2 next-themes: 0.4.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1) postcss-selector-parser: 7.1.0 @@ -11492,7 +13129,7 @@ snapshots: tailwind-merge: 3.3.1 optionalDependencies: "@types/react": 19.1.13 - next: 15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + next: 15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) tailwindcss: 4.1.13 transitivePeerDependencies: - "@mixedbread/sdk" @@ -11519,6 +13156,8 @@ snapshots: generic-pool@3.4.2: {} + gensync@1.0.0-beta.2: {} + get-east-asian-width@1.4.0: {} get-intrinsic@1.3.0: @@ -11603,6 +13242,12 @@ snapshots: section-matter: 1.0.0 strip-bom-string: 1.0.0 + happy-dom@15.11.7: + dependencies: + entities: 4.5.0 + webidl-conversions: 7.0.0 + whatwg-mimetype: 3.0.0 + has-bigints@1.1.0: {} has-flag@4.0.0: {} @@ -11748,6 +13393,8 @@ snapshots: property-information: 7.1.0 space-separated-tokens: 2.0.2 + html-escaper@2.0.2: {} + html-url-attributes@3.0.1: {} html-void-elements@3.0.0: {} @@ -11952,6 +13599,27 @@ snapshots: isexe@2.0.0: {} + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + "@jridgewell/trace-mapping": 0.3.31 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + iterator.prototype@1.1.5: dependencies: define-data-property: 1.1.4 @@ -11984,6 +13652,8 @@ snapshots: dependencies: argparse: 2.0.1 + jsesc@3.1.0: {} + json-buffer@3.0.1: {} json-schema-to-ts@1.6.4: @@ -12007,6 +13677,8 @@ snapshots: dependencies: minimist: 1.2.8 + json5@2.2.3: {} + jsonfile@6.2.0: dependencies: universalify: 2.0.1 @@ -12148,10 +13820,16 @@ snapshots: dependencies: js-tokens: 4.0.0 + loupe@3.2.1: {} + lru-cache@10.4.3: {} lru-cache@11.2.1: {} + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + lru-cache@6.0.0: dependencies: yallist: 4.0.0 @@ -12160,10 +13838,22 @@ snapshots: dependencies: react: 19.1.1 + lz-string@1.5.0: {} + magic-string@0.30.19: dependencies: "@jridgewell/sourcemap-codec": 1.5.5 + magicast@0.3.5: + dependencies: + "@babel/parser": 7.28.4 + "@babel/types": 7.28.4 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.7.2 + make-error@1.3.6: {} markdown-extensions@2.0.0: {} @@ -12689,6 +14379,8 @@ snapshots: mri@1.2.0: {} + mrmime@2.0.1: {} + ms@2.1.1: {} ms@2.1.2: {} @@ -12707,17 +14399,17 @@ snapshots: negotiator@1.0.0: {} - next-auth@5.0.0-beta.29(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1): + next-auth@5.0.0-beta.29(next@15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1): dependencies: "@auth/core": 0.40.0 - next: 15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + next: 15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react: 19.1.1 - next-intl@4.3.9(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(typescript@5.9.2): + next-intl@4.3.9(next@15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(typescript@5.9.2): dependencies: "@formatjs/intl-localematcher": 0.5.10 negotiator: 1.0.0 - next: 15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + next: 15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react: 19.1.1 use-intl: 4.3.9(react@19.1.1) optionalDependencies: @@ -12728,7 +14420,7 @@ snapshots: react: 19.1.1 react-dom: 19.1.1(react@19.1.1) - next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + next@15.5.3(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: "@next/env": 15.5.3 "@swc/helpers": 0.5.15 @@ -12736,7 +14428,7 @@ snapshots: postcss: 8.4.31 react: 19.1.1 react-dom: 19.1.1(react@19.1.1) - styled-jsx: 5.1.6(react@19.1.1) + styled-jsx: 5.1.6(@babel/core@7.28.4)(react@19.1.1) optionalDependencies: "@next/swc-darwin-arm64": 15.5.3 "@next/swc-darwin-x64": 15.5.3 @@ -12923,8 +14615,12 @@ snapshots: path-to-regexp@6.3.0: {} + pathe@1.1.2: {} + pathe@2.0.3: {} + pathval@2.0.1: {} + pend@1.2.0: {} perfect-debounce@1.0.0: {} @@ -13022,13 +14718,19 @@ snapshots: prettier@3.6.2: {} + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + pretty-ms@7.0.1: dependencies: parse-ms: 2.1.0 - prisma@6.16.2(typescript@5.9.2): + prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2): dependencies: - "@prisma/config": 6.16.2 + "@prisma/config": 6.16.2(magicast@0.3.5) "@prisma/engines": 6.16.2 optionalDependencies: typescript: 5.9.2 @@ -13387,8 +15089,15 @@ snapshots: react: 19.1.1 scheduler: 0.26.0 + react-error-boundary@3.1.4(react@19.1.1): + dependencies: + "@babel/runtime": 7.28.4 + react: 19.1.1 + react-is@16.13.1: {} + react-is@17.0.2: {} + react-is@18.3.1: {} react-markdown@10.1.0(@types/react@19.1.13)(react@19.1.1): @@ -13414,6 +15123,8 @@ snapshots: react: 19.1.1 react-dom: 19.1.1(react@19.1.1) + react-refresh@0.17.0: {} + react-remove-scroll-bar@2.3.8(@types/react@19.1.13)(react@19.1.1): dependencies: react: 19.1.1 @@ -13640,6 +15351,34 @@ snapshots: rfdc@1.4.1: {} + rollup@4.52.5: + dependencies: + "@types/estree": 1.0.8 + optionalDependencies: + "@rollup/rollup-android-arm-eabi": 4.52.5 + "@rollup/rollup-android-arm64": 4.52.5 + "@rollup/rollup-darwin-arm64": 4.52.5 + "@rollup/rollup-darwin-x64": 4.52.5 + "@rollup/rollup-freebsd-arm64": 4.52.5 + "@rollup/rollup-freebsd-x64": 4.52.5 + "@rollup/rollup-linux-arm-gnueabihf": 4.52.5 + "@rollup/rollup-linux-arm-musleabihf": 4.52.5 + "@rollup/rollup-linux-arm64-gnu": 4.52.5 + "@rollup/rollup-linux-arm64-musl": 4.52.5 + "@rollup/rollup-linux-loong64-gnu": 4.52.5 + "@rollup/rollup-linux-ppc64-gnu": 4.52.5 + "@rollup/rollup-linux-riscv64-gnu": 4.52.5 + "@rollup/rollup-linux-riscv64-musl": 4.52.5 + "@rollup/rollup-linux-s390x-gnu": 4.52.5 + "@rollup/rollup-linux-x64-gnu": 4.52.5 + "@rollup/rollup-linux-x64-musl": 4.52.5 + "@rollup/rollup-openharmony-arm64": 4.52.5 + "@rollup/rollup-win32-arm64-msvc": 4.52.5 + "@rollup/rollup-win32-ia32-msvc": 4.52.5 + "@rollup/rollup-win32-x64-gnu": 4.52.5 + "@rollup/rollup-win32-x64-msvc": 4.52.5 + fsevents: 2.3.3 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -13785,10 +15524,18 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 + siginfo@2.0.0: {} + signal-exit@4.0.2: {} signal-exit@4.1.0: {} + sirv@3.0.2: + dependencies: + "@polka/url": 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + slice-ansi@7.1.2: dependencies: ansi-styles: 6.2.3 @@ -13804,10 +15551,14 @@ snapshots: stable-hash@0.0.5: {} + stackback@0.0.2: {} + stat-mode@0.3.0: {} statuses@1.5.0: {} + std-env@3.10.0: {} + stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 @@ -13927,10 +15678,12 @@ snapshots: dependencies: inline-style-parser: 0.2.4 - styled-jsx@5.1.6(react@19.1.1): + styled-jsx@5.1.6(@babel/core@7.28.4)(react@19.1.1): dependencies: client-only: 0.0.1 react: 19.1.1 + optionalDependencies: + "@babel/core": 7.28.4 stylis@4.3.6: {} @@ -13970,6 +15723,12 @@ snapshots: mkdirp: 3.0.1 yallist: 5.0.0 + test-exclude@7.0.1: + dependencies: + "@istanbuljs/schema": 0.1.3 + glob: 10.4.5 + minimatch: 9.0.5 + throttle-debounce@5.0.2: {} throttleit@2.1.0: {} @@ -13978,6 +15737,8 @@ snapshots: dependencies: convert-hrtime: 3.0.0 + tinybench@2.9.0: {} + tinyexec@0.3.2: {} tinyexec@1.0.1: {} @@ -13987,6 +15748,12 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 + tinypool@1.1.1: {} + + tinyrainbow@1.2.0: {} + + tinyspy@3.0.2: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -13995,6 +15762,8 @@ snapshots: toidentifier@1.0.0: {} + totalist@3.0.1: {} + tr46@0.0.3: {} tree-kill@1.2.2: {} @@ -14239,22 +16008,22 @@ snapshots: v8-compile-cache-lib@3.0.1: {} - vercel@48.1.0: + vercel@48.1.0(rollup@4.52.5): dependencies: "@vercel/blob": 1.0.2 "@vercel/build-utils": 12.1.0 "@vercel/detect-agent": 0.2.0 - "@vercel/express": 0.0.17 + "@vercel/express": 0.0.17(rollup@4.52.5) "@vercel/fun": 1.1.6 "@vercel/go": 3.2.3 - "@vercel/h3": 0.1.1 - "@vercel/hono": 0.1.1 + "@vercel/h3": 0.1.1(rollup@4.52.5) + "@vercel/hono": 0.1.1(rollup@4.52.5) "@vercel/hydrogen": 1.2.4 - "@vercel/next": 4.12.6 - "@vercel/node": 5.3.23 + "@vercel/next": 4.12.6(rollup@4.52.5) + "@vercel/node": 5.3.23(rollup@4.52.5) "@vercel/python": 5.0.5 - "@vercel/redwood": 2.3.6 - "@vercel/remix-builder": 5.4.12 + "@vercel/redwood": 2.3.6(rollup@4.52.5) + "@vercel/remix-builder": 5.4.12(rollup@4.52.5) "@vercel/ruby": 2.2.1 "@vercel/static-build": 2.7.23 chokidar: 4.0.0 @@ -14281,12 +16050,82 @@ snapshots: "@types/unist": 3.0.3 vfile-message: 4.0.3 + vite-node@2.1.9(@types/node@24.5.2)(lightningcss@1.30.1): + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 1.1.2 + vite: 5.4.21(@types/node@24.5.2)(lightningcss@1.30.1) + transitivePeerDependencies: + - "@types/node" + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite@5.4.21(@types/node@24.5.2)(lightningcss@1.30.1): + dependencies: + esbuild: 0.21.5 + postcss: 8.5.6 + rollup: 4.52.5 + optionalDependencies: + "@types/node": 24.5.2 + fsevents: 2.3.3 + lightningcss: 1.30.1 + + vitest@2.1.9(@edge-runtime/vm@3.2.0)(@types/node@24.5.2)(@vitest/ui@2.1.9)(happy-dom@15.11.7)(lightningcss@1.30.1): + dependencies: + "@vitest/expect": 2.1.9 + "@vitest/mocker": 2.1.9(vite@5.4.21(@types/node@24.5.2)(lightningcss@1.30.1)) + "@vitest/pretty-format": 2.1.9 + "@vitest/runner": 2.1.9 + "@vitest/snapshot": 2.1.9 + "@vitest/spy": 2.1.9 + "@vitest/utils": 2.1.9 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.2.2 + magic-string: 0.30.19 + pathe: 1.1.2 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.1.1 + tinyrainbow: 1.2.0 + vite: 5.4.21(@types/node@24.5.2)(lightningcss@1.30.1) + vite-node: 2.1.9(@types/node@24.5.2)(lightningcss@1.30.1) + why-is-node-running: 2.3.0 + optionalDependencies: + "@edge-runtime/vm": 3.2.0 + "@types/node": 24.5.2 + "@vitest/ui": 2.1.9(vitest@2.1.9) + happy-dom: 15.11.7 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + web-namespaces@2.0.1: {} web-vitals@0.2.4: {} webidl-conversions@3.0.1: {} + webidl-conversions@7.0.0: {} + + whatwg-mimetype@3.0.0: {} + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -14337,6 +16176,11 @@ snapshots: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + word-wrap@1.2.5: {} wrap-ansi@7.0.0: @@ -14369,6 +16213,8 @@ snapshots: xtend@4.0.2: {} + yallist@3.1.1: {} + yallist@4.0.0: {} yallist@5.0.0: {} diff --git a/test/setup.ts b/test/setup.ts new file mode 100644 index 0000000..d5058ce --- /dev/null +++ b/test/setup.ts @@ -0,0 +1,45 @@ +import { vi, afterEach } from "vitest"; + +// Mock next/navigation +vi.mock("next/navigation", () => ({ + useRouter: () => ({ + push: vi.fn(), + replace: vi.fn(), + prefetch: vi.fn(), + back: vi.fn(), + }), + useSearchParams: () => ({ + get: vi.fn(), + }), + usePathname: () => "/", +})); + +// Mock next/headers +vi.mock("next/headers", () => ({ + headers: () => new Headers(), + cookies: () => ({ + get: vi.fn(), + set: vi.fn(), + }), +})); + +// Setup global fetch mock +global.fetch = vi.fn(); + +// Setup localStorage mock +const localStorageMock = { + getItem: vi.fn(), + setItem: vi.fn(), + removeItem: vi.fn(), + clear: vi.fn(), + length: 0, + key: vi.fn(), +}; +global.localStorage = localStorageMock as any; + +// Clean up after each test +afterEach(() => { + vi.clearAllMocks(); + localStorageMock.getItem.mockClear(); + localStorageMock.setItem.mockClear(); +}); diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..af1f9d4 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,30 @@ +import { defineConfig } from "vitest/config"; +import react from "@vitejs/plugin-react"; +import { resolve } from "path"; + +export default defineConfig({ + plugins: [react()], + test: { + environment: "happy-dom", + setupFiles: "./test/setup.ts", + coverage: { + reporter: ["text", "json", "html"], + exclude: [ + "node_modules/", + "test/", + "**/*.d.ts", + "**/*.config.*", + "**/mockData.ts", + ".next/", + "generated/", + ], + }, + globals: true, + }, + resolve: { + alias: { + "@": resolve(__dirname, "./"), + "@/.source": resolve(__dirname, "./.source"), + }, + }, +});