├── src ├── vite-env.d.ts ├── lib │ └── supabase.ts ├── main.tsx ├── index.css ├── store │ ├── retryStore.ts │ ├── authStore.ts │ └── novelStore.ts ├── types.ts ├── components │ ├── BackToTop.tsx │ ├── StyleCard.tsx │ ├── ChoiceList.tsx │ ├── ThemeSwitcher.tsx │ ├── HistoryDrawer.tsx │ ├── LoadingIndicator.tsx │ ├── Navigation.tsx │ ├── AuthModal.tsx │ ├── StyleSelectionScreen.tsx │ └── NovelReadingScreen.tsx ├── data │ └── novelStyles.ts ├── App.tsx └── services │ └── aiService.ts ├── .bolt ├── config.json └── prompt ├── dist.zip ├── postcss.config.js ├── tsconfig.json ├── vite.config.ts ├── supabase_update.sql ├── index.html ├── tsconfig.node.json ├── tailwind.config.js ├── tsconfig.app.json ├── .gitignore ├── .gitignore.example ├── eslint.config.js ├── .env.example ├── package.json ├── README.md ├── README.en.md ├── LICENSE └── pnpm-lock.yaml /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /.bolt/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "template": "bolt-vite-react-ts" 3 | } 4 | -------------------------------------------------------------------------------- /dist.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TangQi001/novel_by_you/HEAD/dist.zip -------------------------------------------------------------------------------- /src/lib/supabase.ts: -------------------------------------------------------------------------------- 1 | // Supabase client removed as authentication and database features are disabled. -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | optimizeDeps: { 8 | exclude: ['lucide-react'], 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | import App from './App.tsx'; 4 | import './index.css'; 5 | 6 | createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @keyframes slide-in-right { 6 | from { 7 | transform: translateX(100%); 8 | } 9 | to { 10 | transform: translateX(0); 11 | } 12 | } 13 | 14 | .animate-slide-in-right { 15 | animation: slide-in-right 0.3s ease-out; 16 | } -------------------------------------------------------------------------------- /.bolt/prompt: -------------------------------------------------------------------------------- 1 | For all designs I ask you to make, have them be beautiful, not cookie cutter. Make webpages that are fully featured and worthy for production. 2 | 3 | By default, this template supports JSX syntax with Tailwind CSS classes, React hooks, and Lucide React for icons. Do not install other packages for UI themes, icons, etc unless absolutely necessary or I request them. 4 | 5 | Use icons from lucide-react for logos. 6 | -------------------------------------------------------------------------------- /supabase_update.sql: -------------------------------------------------------------------------------- 1 | -- SQL 语句以更新 Supabase 数据库结构 2 | -- 在 Supabase 控制台的 SQL 编辑器中执行以下语句: 3 | 4 | -- 向 reading_histories 表添加 structure_outline 列 5 | ALTER TABLE reading_histories 6 | ADD COLUMN structure_outline TEXT DEFAULT NULL; 7 | 8 | -- 更新现有记录的 structure_outline 字段(可选操作) 9 | -- UPDATE reading_histories 10 | -- SET structure_outline = '这是一个默认的故事结构大纲。'; 11 | 12 | -- 重建索引(如果需要) 13 | -- REINDEX TABLE reading_histories; -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | AI Novel Generator Application 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "lib": ["ES2023"], 5 | "module": "ESNext", 6 | "skipLibCheck": true, 7 | 8 | /* Bundler mode */ 9 | "moduleResolution": "bundler", 10 | "allowImportingTsExtensions": true, 11 | "isolatedModules": true, 12 | "moduleDetection": "force", 13 | "noEmit": true, 14 | 15 | /* Linting */ 16 | "strict": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "noFallthroughCasesInSwitch": true 20 | }, 21 | "include": ["vite.config.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], 4 | darkMode: 'class', 5 | theme: { 6 | extend: { 7 | colors: { 8 | primary: { 9 | 50: '#f5f3ff', 10 | 100: '#ede9fe', 11 | 200: '#ddd6fe', 12 | 300: '#c4b5fd', 13 | 400: '#a78bfa', 14 | 500: '#8b5cf6', 15 | 600: '#7c3aed', 16 | 700: '#6d28d9', 17 | 800: '#5b21b6', 18 | 900: '#4c1d95', 19 | 950: '#2e1065', 20 | }, 21 | }, 22 | }, 23 | }, 24 | plugins: [], 25 | }; -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"] 24 | } 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | # Dependencies 11 | node_modules 12 | dist 13 | dist-ssr 14 | *.local 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | 27 | # Environment variables 28 | .env 29 | .env.* 30 | !.env.example 31 | 32 | # Supabase 33 | supabase/ 34 | 35 | # Build output 36 | dist/ 37 | build/ 38 | 39 | # Cache 40 | .cache/ 41 | .eslintcache 42 | .stylelintcache 43 | 44 | # Testing 45 | coverage/ 46 | 47 | # Misc 48 | *.pem 49 | .DS_Store 50 | Thumbs.db -------------------------------------------------------------------------------- /.gitignore.example: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | # Dependencies 11 | node_modules 12 | dist 13 | dist-ssr 14 | *.local 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | 27 | # Environment variables 28 | .env 29 | .env.* 30 | !.env.example 31 | 32 | # Supabase 33 | supabase/ 34 | 35 | # Build output 36 | dist/ 37 | build/ 38 | 39 | # Cache 40 | .cache/ 41 | .eslintcache 42 | .stylelintcache 43 | 44 | # Testing 45 | coverage/ 46 | 47 | # Misc 48 | *.pem 49 | .DS_Store 50 | Thumbs.db -------------------------------------------------------------------------------- /src/store/retryStore.ts: -------------------------------------------------------------------------------- 1 | import { create } from 'zustand'; 2 | 3 | interface RetryState { 4 | isRetrying: boolean; 5 | retryCount: number; 6 | maxRetries: number; 7 | startRetrying: (maxRetries: number) => void; 8 | updateRetry: (count: number) => void; 9 | stopRetrying: () => void; 10 | } 11 | 12 | export const useRetryStore = create((set) => ({ 13 | isRetrying: false, 14 | retryCount: 0, 15 | maxRetries: 5, 16 | startRetrying: (maxRetries: number) => set({ 17 | isRetrying: true, 18 | retryCount: 1, 19 | maxRetries 20 | }), 21 | updateRetry: (count: number) => set({ 22 | retryCount: count 23 | }), 24 | stopRetrying: () => set({ 25 | isRetrying: false, 26 | retryCount: 0 27 | }) 28 | })); -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js'; 2 | import globals from 'globals'; 3 | import reactHooks from 'eslint-plugin-react-hooks'; 4 | import reactRefresh from 'eslint-plugin-react-refresh'; 5 | import tseslint from 'typescript-eslint'; 6 | 7 | export default tseslint.config( 8 | { ignores: ['dist'] }, 9 | { 10 | extends: [js.configs.recommended, ...tseslint.configs.recommended], 11 | files: ['**/*.{ts,tsx}'], 12 | languageOptions: { 13 | ecmaVersion: 2020, 14 | globals: globals.browser, 15 | }, 16 | plugins: { 17 | 'react-hooks': reactHooks, 18 | 'react-refresh': reactRefresh, 19 | }, 20 | rules: { 21 | ...reactHooks.configs.recommended.rules, 22 | 'react-refresh/only-export-components': [ 23 | 'warn', 24 | { allowConstantExport: true }, 25 | ], 26 | }, 27 | } 28 | ); 29 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # --- AI Service Configuration --- 2 | # Your AI service API Key (e.g., OpenAI, Groq, Gemini, etc.) 3 | VITE_AI_API_KEY="YOUR_AI_API_KEY_HERE" 4 | 5 | # Model configuration for the "Creative" style 6 | VITE_AI_CREATIVE_MODEL_NAME="YOUR_CREATIVE_MODEL_NAME_HERE" # e.g., gemini-1.5-flash-latest 7 | VITE_AI_CREATIVE_MODEL_ENDPOINT="YOUR_CREATIVE_MODEL_ENDPOINT_HERE" # e.g., https://api.example.com/v1/chat/completions 8 | 9 | # Model configuration for the "Precise" style 10 | VITE_AI_PRECISE_MODEL_NAME="YOUR_PRECISE_MODEL_NAME_HERE" 11 | VITE_AI_PRECISE_MODEL_ENDPOINT="YOUR_PRECISE_MODEL_ENDPOINT_HERE" 12 | 13 | # Model configuration for the "Balanced" style 14 | VITE_AI_BALANCED_MODEL_NAME="YOUR_BALANCED_MODEL_NAME_HERE" 15 | VITE_AI_BALANCED_MODEL_ENDPOINT="YOUR_BALANCED_MODEL_ENDPOINT_HERE" 16 | 17 | # --- Optional Configuration --- 18 | # Threshold for triggering structure thinking and preference analysis (default is 5) 19 | # VITE_STRUCTURE_THINKING_THRESHOLD=5 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-react-typescript-starter", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@radix-ui/react-dialog": "^1.0.5", 14 | "lucide-react": "^0.344.0", 15 | "react": "^18.3.1", 16 | "react-dom": "^18.3.1", 17 | "zustand": "^4.5.2" 18 | }, 19 | "devDependencies": { 20 | "@eslint/js": "^9.9.1", 21 | "@types/react": "^18.3.5", 22 | "@types/react-dom": "^18.3.0", 23 | "@vitejs/plugin-react": "^4.3.1", 24 | "autoprefixer": "^10.4.18", 25 | "eslint": "^9.9.1", 26 | "eslint-plugin-react-hooks": "^5.1.0-rc.0", 27 | "eslint-plugin-react-refresh": "^0.4.11", 28 | "globals": "^15.9.0", 29 | "postcss": "^8.4.35", 30 | "tailwindcss": "^3.4.1", 31 | "typescript": "^5.5.3", 32 | "typescript-eslint": "^8.3.0", 33 | "vite": "^5.4.2" 34 | } 35 | } -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export interface NovelStyle { 2 | id: string; 3 | name: string; 4 | description: string; 5 | prompt: string; 6 | sampleText: string; 7 | imageUrl: string; 8 | } 9 | 10 | export interface StoryChoice { 11 | id: string; 12 | text: string; 13 | } 14 | 15 | export interface HistoryItem { 16 | role: 'user' | 'assistant'; 17 | content: string; 18 | } 19 | 20 | export interface ThinkingHistoryItem { 21 | position: number; 22 | content: string; 23 | } 24 | 25 | export interface NovelHistory { 26 | id: string; 27 | style: NovelStyle; 28 | lastUpdated: number; 29 | content: string; 30 | choices: StoryChoice[]; 31 | history: HistoryItem[]; 32 | structureOutline?: string | null; 33 | structureThinkingHistory?: ThinkingHistoryItem[]; 34 | preferenceThinkingHistory?: ThinkingHistoryItem[]; 35 | } 36 | 37 | export interface EnhancedContinuationResponse { 38 | storyContinuation: string; 39 | choices: StoryChoice[]; 40 | structureThinking?: string; 41 | preferenceThinking?: string; 42 | } -------------------------------------------------------------------------------- /src/store/authStore.ts: -------------------------------------------------------------------------------- 1 | import { create } from 'zustand'; 2 | // Removed persist and supabase import 3 | 4 | // Keep Profile interface for structure, but it won't be fetched 5 | interface Profile { 6 | id: string; 7 | username: string; 8 | // Remove timestamps or keep if needed for local logic 9 | // created_at: string; 10 | // updated_at: string; 11 | } 12 | 13 | // Simplified AuthState 14 | interface AuthState { 15 | user: Profile | null; // Keep the structure, but initialize differently 16 | // Remove setUser, signUp, signIn, signOut methods 17 | } 18 | 19 | // Create a mock user profile 20 | const mockUser: Profile = { 21 | id: 'local-user', // Static ID for the local session user 22 | username: 'Local User', 23 | }; 24 | 25 | // Create the store without persistence and Supabase interactions 26 | export const useAuthStore = create()(() => ({ 27 | // Initialize user as the mock user, effectively skipping login 28 | user: mockUser, 29 | // Remove setUser, signUp, signIn, signOut implementations 30 | })); -------------------------------------------------------------------------------- /src/components/BackToTop.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ArrowUp } from 'lucide-react'; 3 | import { useThemeStore } from './ThemeSwitcher'; 4 | 5 | interface BackToTopProps { 6 | contentRef: React.RefObject; 7 | } 8 | 9 | const BackToTop: React.FC = ({ contentRef }) => { 10 | const theme = useThemeStore((state) => state.theme); 11 | 12 | const scrollToTop = () => { 13 | if (contentRef.current) { 14 | contentRef.current.scrollTo({ 15 | top: 0, 16 | behavior: 'smooth' 17 | }); 18 | } 19 | }; 20 | 21 | return ( 22 | 33 | ); 34 | }; 35 | 36 | export default BackToTop; -------------------------------------------------------------------------------- /src/components/StyleCard.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { NovelStyle } from '../types'; 3 | import { useThemeStore } from './ThemeSwitcher'; 4 | 5 | interface StyleCardProps { 6 | style: NovelStyle; 7 | onSelect: () => void; 8 | } 9 | 10 | const StyleCard: React.FC = ({ style, onSelect }) => { 11 | const theme = useThemeStore((state) => state.theme); 12 | 13 | return ( 14 |
22 |
23 | {style.name} 28 |
29 |

{style.name}

30 |
31 |
32 |
33 |

{style.description}

34 |
35 |
36 | ); 37 | }; 38 | 39 | export default StyleCard; -------------------------------------------------------------------------------- /src/components/ChoiceList.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StoryChoice } from '../types'; 3 | import { useThemeStore } from './ThemeSwitcher'; 4 | 5 | interface ChoiceListProps { 6 | choices: StoryChoice[]; 7 | onChoiceSelected: (choice: StoryChoice) => void; 8 | } 9 | 10 | const ChoiceList: React.FC = ({ choices, onChoiceSelected }) => { 11 | const theme = useThemeStore((state) => state.theme); 12 | 13 | return ( 14 |
15 | {choices.map((choice) => ( 16 | 30 | ))} 31 |
32 | ); 33 | }; 34 | 35 | export default ChoiceList; -------------------------------------------------------------------------------- /src/components/ThemeSwitcher.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Sun, Moon } from 'lucide-react'; 3 | import { create } from 'zustand'; 4 | import { persist } from 'zustand/middleware'; 5 | 6 | interface ThemeStore { 7 | theme: 'light' | 'dark'; 8 | toggleTheme: () => void; 9 | } 10 | 11 | export const useThemeStore = create()( 12 | persist( 13 | (set) => ({ 14 | theme: 'dark', 15 | toggleTheme: () => set((state) => ({ 16 | theme: state.theme === 'dark' ? 'light' : 'dark' 17 | })), 18 | }), 19 | { 20 | name: 'theme-storage', 21 | } 22 | ) 23 | ); 24 | 25 | const ThemeSwitcher: React.FC = () => { 26 | const { theme, toggleTheme } = useThemeStore(); 27 | 28 | React.useEffect(() => { 29 | if (theme === 'dark') { 30 | document.documentElement.classList.add('dark'); 31 | } else { 32 | document.documentElement.classList.remove('dark'); 33 | } 34 | }, [theme]); 35 | 36 | return ( 37 | 53 | ); 54 | }; 55 | 56 | export default ThemeSwitcher; -------------------------------------------------------------------------------- /src/store/novelStore.ts: -------------------------------------------------------------------------------- 1 | import { create } from 'zustand'; 2 | import { NovelHistory } from '../types'; // Keep type definition 3 | 4 | // Simplified store interface without Supabase sync/persistence 5 | interface NovelStore { 6 | histories: NovelHistory[]; 7 | addHistory: (history: NovelHistory) => void; // Simplified signature 8 | updateHistory: (id: string, updates: Partial) => void; // Simplified signature 9 | clearHistories: () => void; // Simplified signature 10 | // Removed: pendingWrites, syncWithSupabase, processPendingWrites, scheduleSyncWithSupabase 11 | } 12 | 13 | export const useNovelStore = create((set) => ({ 14 | histories: [], // Initialize as empty 15 | 16 | addHistory: (history) => { 17 | // Ensure history has a unique ID if needed locally 18 | const historyWithId = { ...history, id: history.id || crypto.randomUUID() }; 19 | console.log(`[${new Date().toISOString()}] addHistory called (session only).`, historyWithId); 20 | set(state => ({ 21 | // Add to the beginning and keep only the last 10 (or adjust as needed) 22 | histories: [historyWithId, ...state.histories].slice(0, 10), 23 | })); 24 | }, 25 | 26 | updateHistory: (id, updates) => { 27 | const timestamp = Date.now(); // Keep timestamp for potential local use 28 | console.log(`[${new Date().toISOString()}] updateHistory called for ID: ${id} (session only).`, updates); 29 | set(state => ({ 30 | histories: state.histories.map((h) => 31 | h.id === id ? { ...h, ...updates, lastUpdated: timestamp } : h 32 | ), 33 | })); 34 | }, 35 | 36 | clearHistories: () => { 37 | console.log(`[${new Date().toISOString()}] clearHistories called (session only).`); 38 | set({ histories: [] }); // Simply clear the local array 39 | }, 40 | 41 | // Removed syncWithSupabase and related logic 42 | })); -------------------------------------------------------------------------------- /src/components/HistoryDrawer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import * as Dialog from '@radix-ui/react-dialog'; 3 | import { X, Clock } from 'lucide-react'; 4 | import { useNovelStore } from '../store/novelStore'; 5 | 6 | interface HistoryDrawerProps { 7 | onSelectHistory: (historyId: string) => void; 8 | } 9 | 10 | const HistoryDrawer: React.FC = ({ onSelectHistory }) => { 11 | const histories = useNovelStore((state) => state.histories); 12 | 13 | return ( 14 | 15 | 16 | 22 | 23 | 24 | 25 | 26 |
27 | 阅读历史 28 | 29 | 32 | 33 |
34 | 35 |
36 | {histories.length === 0 ? ( 37 |

暂无阅读历史

38 | ) : ( 39 | histories.map((history) => ( 40 | 53 | )) 54 | )} 55 |
56 |
57 |
58 |
59 | ); 60 | }; 61 | 62 | export default HistoryDrawer; -------------------------------------------------------------------------------- /src/components/LoadingIndicator.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | interface LoadingIndicatorProps { 4 | text: string; 5 | } 6 | 7 | const PixelDino = () => { 8 | return ( 9 |
10 | 78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | ); 86 | }; 87 | 88 | const LoadingIndicator: React.FC = ({ text }) => { 89 | return ( 90 |
91 | 92 |

{text}

93 |
94 | {[0, 1, 2].map(i => ( 95 |
102 | ))} 103 |
104 | 112 |
113 | ); 114 | }; 115 | 116 | export default LoadingIndicator; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 我个人实测: gemini 2.0 flash模型是最好的, 其他模型比如2.5 flash或者deepseekv3会导致返回格式错误 2 | 如今存在的bug: 3 | 1. 由于模型能力, 导致小说生成质量低 4 | 2. 由于模型能力, 导致返回格式错误, 此时需要进行重复选择直到功能有效 5 | 6 | # 执笔马良 - AI 交互式小说生成器 7 | 8 | 一个基于 AI 的交互式小说生成器,允许用户选择不同的风格,然后通过选择剧情分支来决定故事的走向。 9 | ![image](https://github.com/user-attachments/assets/b05b0078-a4a2-4a24-acea-9fa4dcbb4fac) 10 | ![image](https://github.com/user-attachments/assets/6d1badf7-3559-447b-a969-1097fe3ab47e) 11 | ![image](https://github.com/user-attachments/assets/f744a09e-a7ae-4b81-8ee3-f53e1fef7e50) 12 | 13 | ## 项目特点 14 | 15 | - 多种小说风格:武侠江湖、科幻探索、奇幻魔法、悬疑推理等 16 | - 丰富的交互选择:用户可以在故事中作出选择,影响故事发展方向 17 | - 流畅的用户体验:美观的界面,无缝的故事过渡 18 | - 历史记录:在当前会话中保存用户的阅读历史,可以随时回顾或继续 19 | 20 | ## 新增功能 21 | 22 | ### 1. 基于关键词的 AI 响应解析 23 | 24 | - 修改了 AI 交互逻辑,不再依赖严格的 JSON 格式 25 | - 使用关键词(`novelstory:`, `options:`, `structure_thinking:`, `preference_thinking:`)和特定分隔符(`.`)从 AI 响应中提取内容 26 | - 实现了健壮的解析逻辑,可以处理各种可能的 AI 输出格式 27 | 28 | ### 2. 小说结构思考 29 | 30 | - 用户选择风格后,系统会生成一个初始的小说结构大纲 31 | - 当用户选择次数达到阈值(默认为 5 次)后,AI 会分析当前剧情并对后续结构进行调整 32 | - 结构大纲在当前会话中保留,并在每次故事继续时提供给 AI 参考 33 | 34 | ### 3. 用户偏好分析 35 | 36 | - 系统会记录用户在当前会话中的所有选择,并在达到阈值后分析用户的偏好 37 | - AI 可以根据分析结果调整后续剧情和选项,使故事更符合用户喜好 38 | - 偏好分析结果目前会记录在控制台中(仅用于调试) 39 | 40 | ## 技术栈 41 | 42 | - 前端:React, TailwindCSS, Zustand 43 | - AI:可配置的 AI 服务 (只支持OpenAI格式) 44 | 45 | ## 安装与运行 46 | 47 | 1. **克隆项目** 48 | ```bash 49 | git clone https://github.com/TangQi001/novel_by_you.git 50 | cd novel_by_you 51 | ``` 52 | 53 | 2. **安装依赖** 54 | 推荐使用 `pnpm`: 55 | ```bash 56 | pnpm install 57 | ``` 58 | 或者使用 `npm` 或 `yarn`: 59 | ```bash 60 | npm install 61 | # 或 62 | yarn install 63 | ``` 64 | 65 | 3. **配置环境变量** 66 | * 复制环境变量模板文件: 67 | ```bash 68 | cp .env.example .env.local 69 | ``` 70 | * 编辑 `.env.local` 文件,填入**所有必需的** AI 服务配置信息。请参考文件内的注释说明: 71 | * `VITE_AI_API_KEY`: 你的 AI 服务 API 密钥。 72 | * `VITE_AI_CREATIVE_MODEL_NAME` / `VITE_AI_CREATIVE_MODEL_ENDPOINT`: "Creative" 模式使用的模型名称及完整接口地址。 73 | * `VITE_AI_PRECISE_MODEL_NAME` / `VITE_AI_PRECISE_MODEL_ENDPOINT`: "Precise" 模式使用的模型名称及完整接口地址。 74 | * `VITE_AI_BALANCED_MODEL_NAME` / `VITE_AI_BALANCED_MODEL_ENDPOINT`: "Balanced" 模式使用的模型名称及完整接口地址。 75 | * `VITE_STRUCTURE_THINKING_THRESHOLD` (可选): 控制触发结构思考的阈值,默认为 5。 76 | 77 | `*_ENDPOINT` 字段必须包含完整的 `chat/completions` 路径(例如 `https://api.openai.com/v1/chat/completions`)。 78 | 79 | 如需增加更多风格,可在 `src/data/novelStyles.ts` 中新增定义。 80 | 81 | 4. **运行开发服务器** 82 | ```bash 83 | pnpm dev 84 | # 或 85 | npm run dev 86 | # 或 87 | yarn dev 88 | ``` 89 | 应用将在本地启动,通常是 `http://localhost:5173`。 90 | 91 | ## 功能特点 92 | 93 | - 🎭 多种小说风格:武侠、科幻、奇幻、悬疑等多种风格可选 94 | - 🔄 交互式剧情:每个选择都会影响故事的发展方向 95 | - 💾 会话历史记录:自动保存在当前浏览器会话中的阅读历史 96 | - 🌓 深色/浅色主题:支持主题切换,提供舒适的阅读体验 97 | - 📱 响应式设计:完美支持各种设备尺寸 98 | 99 | ## 技术栈 (详细) 100 | 101 | - **前端框架**: React 18 102 | - **构建工具**: Vite 103 | - **样式方案**: Tailwind CSS 104 | - **状态管理**: Zustand 105 | - **UI 组件**: Radix UI (可能用于底层组件) 106 | - **图标**: Lucide React 107 | - **类型检查**: TypeScript 108 | 109 | ## 项目结构 110 | 111 | ``` 112 | src/ 113 | ├── components/ # React 组件 114 | ├── data/ # 静态数据 (如小说风格定义) 115 | ├── lib/ # 工具库 (已移除 Supabase 客户端) 116 | ├── services/ # 服务层 (如 AI 交互逻辑) 117 | ├── store/ # 状态管理 (Zustand stores) 118 | ├── types/ # TypeScript 类型定义 119 | └── App.tsx # 应用入口组件 120 | └── main.tsx # 应用渲染入口 121 | └── index.css # 全局 CSS 122 | ``` 123 | 124 | ## 部署 125 | 126 | 项目可以使用 Vercel, Netlify 或其他支持 Vite 应用的平台进行部署。 127 | 128 | **构建命令**: `npm run build` (或 `pnpm build`, `yarn build`) 129 | **输出目录**: `dist` 130 | 131 | 确保在部署平台正确配置了所有必需的环境变量 (主要是 AI 服务相关的变量)。 132 | 133 | ## 贡献指南 134 | 135 | 1. Fork 项目 136 | 2. 创建特性分支 (`git checkout -b feature/amazing-feature`) 137 | 3. 提交更改 (`git commit -m 'Add amazing feature'`) 138 | 4. 推送到分支 (`git push origin feature/amazing-feature`) 139 | 5. 开启 Pull Request 140 | 141 | ## 许可证 142 | 143 | [Apache License 2.0](LICENSE) 144 | -------------------------------------------------------------------------------- /src/components/Navigation.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Home, Clock } from 'lucide-react'; 3 | import * as Dialog from '@radix-ui/react-dialog'; 4 | import { X } from 'lucide-react'; 5 | import { useNovelStore } from '../store/novelStore'; 6 | import ThemeSwitcher from './ThemeSwitcher'; 7 | import { useThemeStore } from './ThemeSwitcher'; 8 | 9 | interface NavigationProps { 10 | onHome: () => void; 11 | onSelectHistory: (historyId: string) => void; 12 | } 13 | 14 | const Navigation: React.FC = ({ onHome, onSelectHistory }) => { 15 | const histories = useNovelStore((state) => state.histories); 16 | const theme = useThemeStore((state) => state.theme); 17 | 18 | return ( 19 |
20 | 28 | 29 |
30 | 31 | 32 | 39 | 40 | 41 | 42 | 43 |
44 | 阅读历史 45 | 46 | 49 | 50 |
51 | 52 |
53 | {histories.length === 0 ? ( 54 |

暂无阅读历史

55 | ) : ( 56 | histories.map((history) => ( 57 | 76 | )) 77 | )} 78 |
79 |
80 |
81 |
82 | 83 |
84 |
85 | ); 86 | }; 87 | 88 | export default Navigation; -------------------------------------------------------------------------------- /src/data/novelStyles.ts: -------------------------------------------------------------------------------- 1 | import { NovelStyle } from '../types'; 2 | 3 | export const novelStyles: NovelStyle[] = [ 4 | { 5 | id: 'wuxia', 6 | name: '武侠江湖', 7 | description: '刀光剑影,恩怨情仇,一段传奇武侠故事等待你的选择', 8 | prompt: '创作一个武侠故事的开篇。聚焦于一位身负秘密或血海深仇的主角,他/她正处于一个关键的抉择点或危险的境地,周遭暗流涌动,门派与江湖势力若隐若现。', 9 | sampleText: '三更鼓响,冷雨敲窗。\n\n黑衣人影如鬼魅般掠过"镇远镖局"的高墙,手中紧握的不是别的,正是总镖头昨夜失窃的令牌。墙内隐约传来压抑的哭喊声和刀刃出鞘的轻响。他知道,一旦暴露,身后便是万丈深渊。\n\n腰间的伤口还在渗血,但他无暇顾及。必须在天亮前,将这枚能调动西北十三路的令牌送到城外接应人手中。可镖局之内,似乎已布下天罗地网,一股若有若无的杀气,如同实质般弥漫在雨夜里。', 10 | imageUrl: 'https://images.pexels.com/photos/4275885/pexels-photo-4275885.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2' 11 | }, 12 | { 13 | id: 'scifi', 14 | name: '科幻探索', 15 | description: '穿越星际,探索未知,体验震撼人心的科幻冒险', 16 | prompt: '创作一个科幻故事的开篇。将主角置于一个远离地球的未知环境(如陌生星球、深空探测器、异常空间),遭遇无法用现有知识解释的现象或智慧信号,迫使其做出关乎生存或探索的艰难决定。', 17 | sampleText: '"警告:生命维持系统效能降至17%。"合成语音毫无波澜地在舰桥回荡,冰冷的红光将艾拉苍白的脸映得如同鬼魅。\n\n舷窗外,那片无垠的紫色星云正以肉眼可见的速度吞噬着"远航者号"。它并非任何已知的天体现象,更像是一种……活物。舰船的能量正被其不可思议地汲取。\n\n通讯系统早已失灵,跃迁引擎也无法启动。艾拉是舰上唯一从紧急休眠中醒来的人,肩负着全船数百名沉睡者的命运。她面前的操作台上,只有一个选项在闪烁:启动"方舟"协议——将载有胚胎库和人类基因图谱的逃生舱射入星云深处,赌一个未知的未来。', 18 | imageUrl: 'https://images.pexels.com/photos/2008465/pexels-photo-2008465.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2' 19 | }, 20 | { 21 | id: 'fantasy', 22 | name: '奇幻魔法', 23 | description: '魔法、神秘生物与史诗冒险的奇幻世界', 24 | prompt: '创作一个奇幻故事的开篇。主角应意外卷入一场涉及古老魔法、预言或神秘生物的危机中。他/她可能身怀异能而不自知,或持有一件看似平凡却蕴藏力量的物品。故事需营造出浓厚的神秘氛围和潜在的危险。', 25 | sampleText: '当艾里昂触摸到森林深处那块低语古石时,指尖传来并非冰冷石头的触感,而是一种奇异的温热,仿佛握住了一颗跳动的心脏。\n\n石面上那些从未见过的符文瞬间亮起幽蓝的光芒,如同活了过来,在他脑海中汇成一句低沉的警告:"平衡已被打破,暗影即将重临。"\n\n他只是村里一个普通的猎人,唯一的不同寻常,或许就是手腕上那个伴随他出生的月牙形胎记。此刻,那胎记竟也随着古石的光芒一同灼热起来。远方传来狼嚎,却又不像他听过的任何一种狼。艾里昂感到一股寒意沿着脊柱爬升——这片他自以为熟悉的森林,隐藏着他无法想象的秘密。', 26 | imageUrl: 'https://images.pexels.com/photos/90597/pexels-photo-90597.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2' 27 | }, 28 | { 29 | id: 'mystery', 30 | name: '悬疑推理', 31 | description: '谜团丛生,真相扑朔迷离,一场智慧与勇气的考验', 32 | prompt: '创作一个悬疑推理故事的开篇。设置一个看似平静却暗藏玄机的场景,引入一个令人不安的反常细节或一个无法解释的事件。主角(如侦探、记者或普通人)需要被这个谜团吸引或卷入其中,故事需营造出紧张、诡异或压抑的氛围。', 33 | sampleText: '午夜时分,老侦探陈默被电话铃声惊醒。电话那头,只有断断续续的电流声和一个反复低语的词:"衣柜……衣柜……"\n\n他追踪信号来源,竟指向城中早已废弃多年的"百乐门"舞厅。当他推开那扇尘封的旋转门时,一股混合着霉味和劣质香水的气息扑面而来。舞池中央,聚光灯竟然亮着,下方空无一人,只有一支孤零零的红色高跟鞋,鞋跟断裂,旁边散落着几片黑色的羽毛。\n\n更让他脊背发凉的是,舞厅角落里那个巨大的老式衣柜,柜门虚掩着,里面似乎有什么东西,正随着从破损窗户灌入的夜风,轻微地……摇晃着。', 34 | imageUrl: 'https://images.pexels.com/photos/923681/pexels-photo-923681.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2' 35 | }, 36 | { 37 | id: 'xianxia', 38 | name: '玄幻修仙', 39 | description: '逆天修行,破碎虚空,追寻长生大道的东方幻想', 40 | prompt: '创作一个玄幻修仙故事的开篇。主角可以是一个资质平庸但意志坚韧的少年/少女,或是一个遭遇变故的天才。他/她需意外获得一部残缺功法、一件上古法宝,或卷入修真门派的纷争,从而踏上坎坷的修行之路。突出修真世界的残酷法则和主角的不屈意志。', 41 | sampleText: '"废灵根,三段气感,此生筑基无望。"测灵石旁,执事冷漠的声音如同冰锥,刺穿了少年林凡最后的希望。\n\n周围传来毫不掩饰的嘲笑声。作为曾经被誉为"青阳镇第一天才"的他,一夜之间从云端跌落泥潭,成了宗门里人人可欺的外门杂役。\n\n无人看见,在他紧握的拳心中,那枚从地摊上淘来的、毫不起眼的黑色戒指,此刻正微微发烫,一丝若有若无的古老气息悄然渗入他的经脉。脑海深处,一个苍老的声音似乎在叹息:"痴儿,天弃汝,吾予汝逆天改命之机……"\n\n林凡抬起头,眼中没有绝望,只有燃起的火焰。他不信命,只信自己手中的剑,和那不为人知的秘密。', 42 | imageUrl: 'https://images.pexels.com/photos/2110951/pexels-photo-2110951.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2' 43 | }, 44 | { 45 | id: 'ceo_romance', 46 | name: '霸道总裁', 47 | description: '都市霓虹,豪门恩怨,一场权力与爱情的极限拉扯', 48 | prompt: '创作一个都市霸道总裁风格的故事开篇。设定一个家境普通却坚韧独立的女主角,因某种契机(如债务、误会、工作)与一位外表冷酷、内心复杂、掌控欲强的集团总裁产生交集。着重描绘两人初遇时的戏剧性冲突、身份差异带来的张力以及一丝若有若无的情愫。', 49 | sampleText: '"签了它,你母亲的医药费,我全包了。"冰冷的声线不带一丝温度,男人将一份合约推到苏晚面前。\n\n巨大的落地窗外是璀璨的城市夜景,而窗内,顶级奢侈品牌打造的办公室内,气压低得让人窒息。眼前这个男人,厉氏集团的总裁厉寒霆,是这座城市金字塔尖的存在,传说他跺跺脚,整个商界都要抖三抖。\n\n苏晚看着合约上"契约情人"四个刺眼的字,手指攥得发白。她只是个刚毕业的实习生,为了母亲的病,不得不放下尊严。\n\n"为什么是我?"她鼓起勇气抬头,直视那双深不见底的黑眸。\n\n厉寒霆嘴角勾起一抹嘲讽的弧度,伸手捏住她的下巴,迫使她靠近:"因为,你的眼睛,让我想起了一个……故人。"', 50 | imageUrl: 'https://images.pexels.com/photos/3760810/pexels-photo-3760810.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2' 51 | }, 52 | { 53 | id: 'solo_leveling', 54 | name: '我独自升级', 55 | description: '系统降临,末日怪物,从最弱者开始的逆袭之路', 56 | prompt: '创作一个类似"我独自升级"风格的故事开篇。背景可以是现代都市突现裂隙与怪物,或是异世界与系统融合。主角必须是公认的"最弱者"或底层人物,在一次濒死危机中意外觉醒了独一无二的"系统"或特殊能力(如升级、加点、任务面板等)。开篇需展现世界的危险性、主角的绝望处境以及"系统"带来的转机。', 57 | sampleText: '【警告:生命体征低于临界值,系统强制启动……绑定成功。】\n\n冰冷的机械音在濒死的李浩脑海中响起时,他正被一只低阶哥布林的爪子贯穿腹部,腥臭的口水滴落在他脸上。作为E级猎人中最垫底的存在,队友早已弃他而去,这次进入最低级的F级裂隙,他依然成了炮灰。\n\n【任务发布:生存。任务奖励:???失败惩罚:死亡。】\n\n眼前突然弹出一个只有他能看到的透明蓝色面板,上面清晰地显示着他的状态:【HP:3/100】。\n\n"这是……什么?"李浩用尽最后一丝力气,意识模糊间,仿佛看到面板上出现了一个新的按钮【新手礼包:开启】。\n\n是幻觉吗?还是……唯一的生机?他颤抖着,用意念"点"向了那个按钮。', 58 | imageUrl: 'https://images.pexels.com/photos/1111304/pexels-photo-1111304.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2' 59 | }, 60 | { 61 | id: 'regent_prince', 62 | name: '霸道王爷', 63 | description: '深宫权谋,禁忌之恋,体验古风背景下的强制爱与宿命纠缠', 64 | prompt: '创作一个古风霸道王爷的故事开篇。设定一位身份卑微(或来自敌对势力、或有特殊使命)的女主角,因命运捉弄或政治安排,被迫进入一位权倾朝野、性格冷傲孤高、令人畏惧的王爷的生活。着重描绘两人初次(或早期)交锋的紧张氛围、王爷不容置疑的权威以及女主角的坚韧(或隐藏的计谋)。', 65 | sampleText: '冰冷的雨水顺着琉璃瓦滴落,汇入汉白玉阶前的积水中,映出沈清薇苍白而倔强的脸庞。\n\n她已在这座名为"靖王府"的华丽牢笼里跪了整整一个时辰。寒气透过单薄的衣衫侵入骨髓,但她不能倒下。只因她不慎打碎了书房里的一只玉瓶——据说是那位权倾朝野的靖王爷最心爱之物。\n\n沉重的殿门"吱呀"一声被推开,身着墨色蟒袍的男人逆光走出,身形颀长,面容俊美却如同覆着一层寒霜。他便是靖王萧玦,那个传说中杀伐决断、从无败绩的"冷面阎罗"。\n\n"抬起头来。"他的声音低沉,带着不容抗拒的威压。\n\n沈清薇缓缓抬头,迎上那双深邃冷冽的眸子,心知今日若无转圜,她这条小命,恐怕就要交代在这里了。', 66 | imageUrl: 'https://images.pexels.com/photos/164583/pexels-photo-164583.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2' 67 | } 68 | ]; -------------------------------------------------------------------------------- /src/components/AuthModal.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import * as Dialog from '@radix-ui/react-dialog'; 3 | import { X } from 'lucide-react'; 4 | import { useAuthStore } from '../store/authStore'; 5 | import { useThemeStore } from './ThemeSwitcher'; 6 | 7 | interface AuthModalProps { 8 | isOpen: boolean; 9 | onClose: () => void; 10 | } 11 | 12 | const AuthModal: React.FC = ({ isOpen, onClose }) => { 13 | const [isSignUp, setIsSignUp] = useState(false); 14 | const [email, setEmail] = useState(''); 15 | const [password, setPassword] = useState(''); 16 | const [error, setError] = useState(null); 17 | const [isLoading, setIsLoading] = useState(false); 18 | 19 | const { signIn, signUp } = useAuthStore(); 20 | const theme = useThemeStore((state) => state.theme); 21 | 22 | const handleSubmit = async (e: React.FormEvent) => { 23 | e.preventDefault(); 24 | setError(null); 25 | setIsLoading(true); 26 | 27 | try { 28 | if (isSignUp) { 29 | await signUp(email, password); 30 | } else { 31 | await signIn(email, password); 32 | } 33 | onClose(); 34 | } catch (err) { 35 | setError((err as Error).message); 36 | } finally { 37 | setIsLoading(false); 38 | } 39 | }; 40 | 41 | return ( 42 | 43 | 44 | 45 | 48 |
49 | 52 | {isSignUp ? '注册账号' : '登录账号'} 53 | 54 | 55 | 60 | 61 |
62 | 63 |
64 |
65 | 70 | setEmail(e.target.value)} 75 | className={`mt-1 block w-full rounded-md ${ 76 | theme === 'dark' 77 | ? 'bg-gray-800 border-gray-700 text-gray-200' 78 | : 'bg-white border-gray-300 text-gray-900' 79 | } shadow-sm focus:border-purple-500 focus:ring-purple-500`} 80 | required 81 | /> 82 |
83 | 84 |
85 | 90 | setPassword(e.target.value)} 95 | className={`mt-1 block w-full rounded-md ${ 96 | theme === 'dark' 97 | ? 'bg-gray-800 border-gray-700 text-gray-200' 98 | : 'bg-white border-gray-300 text-gray-900' 99 | } shadow-sm focus:border-purple-500 focus:ring-purple-500`} 100 | required 101 | /> 102 |
103 | 104 | {error && ( 105 |
106 | {error} 107 |
108 | )} 109 | 110 | 121 | 122 |
123 | 132 |
133 |
134 |
135 |
136 |
137 | ); 138 | }; 139 | 140 | export default AuthModal; -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | # Novel By You - AI Interactive Novel Generator 2 | 3 | An AI-based interactive novel generator that allows users to choose different styles and then decide the story's direction by selecting plot branches. 4 | 5 | ## Project Features 6 | 7 | - Multiple Novel Styles: Wuxia, Sci-Fi Exploration, Fantasy Magic, Mystery Thriller, etc. 8 | - Rich Interactive Choices: Users can make choices within the story, influencing its development. 9 | - Smooth User Experience: Beautiful interface, seamless story transitions. 10 | - History Tracking: Saves the user's reading history within the current session for easy review or continuation. 11 | 12 | ## New Features 13 | 14 | ### 1. Keyword-Based AI Response Parsing 15 | 16 | - Modified AI interaction logic, no longer relying on strict JSON format. 17 | - Uses keywords (`novelstory:`, `options:`, `structure_thinking:`, `preference_thinking:`) and specific delimiters (`.`) to extract content from AI responses. 18 | - Implemented robust parsing logic capable of handling various potential AI output formats. 19 | 20 | ### 2. Novel Structure Thinking 21 | 22 | - After the user selects a style, the system generates an initial novel structure outline. 23 | - When the user's choice count reaches a threshold (default is 5), the AI analyzes the current plot and adjusts the subsequent structure. 24 | - The structure outline is kept within the current session and provided to the AI for reference during story continuation. 25 | 26 | ### 3. User Preference Analysis 27 | 28 | - The system records all user choices within the current session and analyzes user preferences after reaching the threshold. 29 | - The AI can adjust subsequent plots and options based on the analysis results to better align the story with user preferences. 30 | - Preference analysis results are currently logged to the console (for debugging purposes only). 31 | 32 | ## Tech Stack 33 | 34 | - Frontend: React, TailwindCSS, Zustand 35 | - AI: Configurable AI Service (e.g., Gemini, OpenAI, Groq, etc.) 36 | 37 | ## Installation and Setup 38 | 39 | 1. **Clone the Project** 40 | ```bash 41 | git clone https://github.com/TangQi001/novel_by_you.git 42 | cd novel_by_you 43 | ``` 44 | 45 | 2. **Install Dependencies** 46 | Using `pnpm` is recommended: 47 | ```bash 48 | pnpm install 49 | ``` 50 | Alternatively, use `npm` or `yarn`: 51 | ```bash 52 | npm install 53 | # or 54 | yarn install 55 | ``` 56 | 57 | 3. **Configure Environment Variables** 58 | * Copy the environment variable template file: 59 | ```bash 60 | cp .env.example .env.local 61 | ``` 62 | * Edit the `.env.local` file and fill in **all required** AI service configuration details. Refer to the comments within the file for guidance: 63 | * `VITE_AI_API_KEY`: Your AI service API key. 64 | * `VITE_AI_CREATIVE_MODEL_NAME` / `VITE_AI_CREATIVE_MODEL_ENDPOINT`: Model name and full endpoint for the "Creative" mode. 65 | * `VITE_AI_PRECISE_MODEL_NAME` / `VITE_AI_PRECISE_MODEL_ENDPOINT`: Model name and full endpoint for the "Precise" mode. 66 | * `VITE_AI_BALANCED_MODEL_NAME` / `VITE_AI_BALANCED_MODEL_ENDPOINT`: Model name and full endpoint for the "Balanced" mode. 67 | * `VITE_STRUCTURE_THINKING_THRESHOLD` (Optional): Threshold for triggering structure thinking, defaults to 5. 68 | 69 | The `*_ENDPOINT` value must include the complete `chat/completions` path (e.g. `https://api.openai.com/v1/chat/completions`). 70 | 71 | To add more styles, edit `src/data/novelStyles.ts`. 72 | 73 | 4. **Run the Development Server** 74 | ```bash 75 | pnpm dev 76 | # or 77 | npm run dev 78 | # or 79 | yarn dev 80 | ``` 81 | The application will start locally, typically at `http://localhost:5173`. 82 | 83 | ## Core Features 84 | 85 | - 🎭 Multiple Novel Styles: Choose from various genres like Wuxia, Sci-Fi, Fantasy, Mystery, etc. 86 | - 🔄 Interactive Storytelling: Every choice impacts the story's direction. 87 | - 💾 Session History: Automatically saves reading history within the current browser session. 88 | - 🌓 Dark/Light Theme: Switch themes for a comfortable reading experience. 89 | - 📱 Responsive Design: Works perfectly on various device sizes. 90 | 91 | ## Tech Stack (Detailed) 92 | 93 | - **Frontend Framework**: React 18 94 | - **Build Tool**: Vite 95 | - **Styling**: Tailwind CSS 96 | - **State Management**: Zustand 97 | - **UI Components**: Radix UI (Potentially used for primitives) 98 | - **Icons**: Lucide React 99 | - **Type Checking**: TypeScript 100 | 101 | ## Project Structure 102 | 103 | ``` 104 | src/ 105 | ├── components/ # React components 106 | ├── data/ # Static data (e.g., novel style definitions) 107 | ├── lib/ # Utility libraries (Supabase client removed) 108 | ├── services/ # Service layer (e.g., AI interaction logic) 109 | ├── store/ # State management (Zustand stores) 110 | ├── types/ # TypeScript type definitions 111 | └── App.tsx # Main application component 112 | └── main.tsx # Application render entry point 113 | └── index.css # Global CSS 114 | ``` 115 | 116 | ## Deployment 117 | 118 | The project can be deployed using Vercel, Netlify, or other platforms supporting Vite applications. 119 | 120 | **Build Command**: `npm run build` (or `pnpm build`, `yarn build`) 121 | **Output Directory**: `dist` 122 | 123 | Ensure all required environment variables (mainly AI service related) are correctly configured on the deployment platform. 124 | 125 | ## Contribution Guide 126 | 127 | 1. Fork the project 128 | 2. Create a feature branch (`git checkout -b feature/amazing-feature`) 129 | 3. Commit your changes (`git commit -m 'Add amazing feature'`) 130 | 4. Push to the branch (`git push origin feature/amazing-feature`) 131 | 5. Open a Pull Request 132 | 133 | ## License 134 | 135 | [Apache License 2.0](LICENSE) 136 | -------------------------------------------------------------------------------- /src/components/StyleSelectionScreen.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; // Keep React import 2 | import { NovelStyle } from '../types'; 3 | import StyleCard from './StyleCard'; 4 | import LoadingIndicator from './LoadingIndicator'; 5 | import * as Dialog from '@radix-ui/react-dialog'; 6 | import { Clock, X } from 'lucide-react'; // Removed LogIn import 7 | import { useNovelStore } from '../store/novelStore'; 8 | import { useThemeStore } from './ThemeSwitcher'; 9 | // Removed useAuthStore import 10 | import ThemeSwitcher from './ThemeSwitcher'; 11 | // Removed AuthModal import 12 | 13 | interface StyleSelectionScreenProps { 14 | styles: NovelStyle[]; 15 | onSelectStyle: (style: NovelStyle) => void; // Keep onSelectStyle, but it won't call AuthModal 16 | isLoading: boolean; 17 | error: string | null; 18 | } 19 | 20 | const StyleSelectionScreen: React.FC = ({ 21 | styles, 22 | onSelectStyle, 23 | isLoading, 24 | error 25 | }) => { 26 | const histories = useNovelStore((state) => state.histories); 27 | const theme = useThemeStore((state) => state.theme); 28 | // Removed user from useAuthStore 29 | // Removed showAuthModal state 30 | 31 | // Simplified onSelectStyle call in history mapping (line 80) - no need to check user 32 | const handleHistorySelect = (style: NovelStyle) => { 33 | onSelectStyle(style); // Directly call onSelectStyle 34 | }; 35 | 36 | 37 | return ( 38 |
39 |
40 |
41 | {/* History Dialog - Always visible now */} 42 | 43 | 44 | 55 | 56 | 57 | 58 | 61 |
62 | 阅读历史 65 | 66 | 73 | 74 |
75 | 76 |
77 | {histories.length === 0 ? ( 78 |

暂无阅读历史

81 | ) : ( 82 | histories.map((history) => ( 83 | 103 | )) 104 | )} 105 |
106 |
107 |
108 |
109 | {/* Removed conditional rendering for login button */} 110 | 111 |
112 | 113 |

执笔马良

116 |

119 | 选择一种小说风格,开始你的交互式阅读之旅。每个选择都将引领故事走向不同的方向。 120 |

121 |
122 | 123 | {error && ( 124 |
125 | {error} 126 |
127 | )} 128 | 129 | {isLoading ? ( 130 |
131 | 132 |
133 | ) : ( 134 |
135 | {styles.map((style) => ( 136 | onSelectStyle(style)} // Direct call, no auth check needed 140 | /> 141 | ))} 142 |
143 | )} 144 | 145 | {/* Removed AuthModal rendering */} 146 |
147 | ); 148 | }; 149 | 150 | export default StyleSelectionScreen; -------------------------------------------------------------------------------- /src/components/NovelReadingScreen.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef, useState } from 'react'; 2 | import { HistoryItem, StoryChoice, ThinkingHistoryItem } from '../types'; 3 | import LoadingIndicator from './LoadingIndicator'; 4 | import ChoiceList from './ChoiceList'; 5 | import BackToTop from './BackToTop'; 6 | import { continueStoryAndGenerateChoices, handleAiError } from '../services/aiService'; 7 | import { useThemeStore } from './ThemeSwitcher'; 8 | 9 | interface NovelReadingScreenProps { 10 | storyContent: string; 11 | currentChoices: StoryChoice[]; 12 | setStoryContent: React.Dispatch>; 13 | setCurrentChoices: React.Dispatch>; 14 | history: HistoryItem[]; 15 | setHistory: React.Dispatch>; 16 | structureOutline: string | null; 17 | isLoading: boolean; 18 | setIsLoading: React.Dispatch>; 19 | onUpdate: ( 20 | content: string, 21 | choices: StoryChoice[], 22 | history: HistoryItem[], 23 | newStructureOutline?: string, 24 | structureThinkingHistory?: ThinkingHistoryItem[], 25 | preferenceThinkingHistory?: ThinkingHistoryItem[] 26 | ) => void; 27 | structureThinkingHistory?: ThinkingHistoryItem[]; 28 | preferenceThinkingHistory?: ThinkingHistoryItem[]; 29 | } 30 | 31 | const NovelReadingScreen: React.FC = ({ 32 | storyContent, 33 | currentChoices, 34 | setStoryContent, 35 | setCurrentChoices, 36 | history, 37 | setHistory, 38 | structureOutline, 39 | isLoading, 40 | setIsLoading, 41 | onUpdate, 42 | structureThinkingHistory = [], 43 | preferenceThinkingHistory = [] 44 | }) => { 45 | const contentRef = useRef(null); 46 | const choicesRef = useRef(null); 47 | const [showBackToTop, setShowBackToTop] = useState(false); 48 | const [error, setError] = useState(null); 49 | const theme = useThemeStore((state) => state.theme); 50 | 51 | useEffect(() => { 52 | if (!isLoading && choicesRef.current) { 53 | choicesRef.current.scrollIntoView({ behavior: 'smooth', block: 'center' }); 54 | } 55 | }, [storyContent, isLoading]); 56 | 57 | const handleScroll = () => { 58 | if (contentRef.current) { 59 | setShowBackToTop(contentRef.current.scrollTop > 300); 60 | } 61 | }; 62 | 63 | const handleChoiceSelected = async (choice: StoryChoice) => { 64 | if (isLoading) return; 65 | 66 | setIsLoading(true); 67 | setError(null); 68 | 69 | const userChoice = `> 你选择了:${choice.text}`; 70 | const updatedHistory: HistoryItem[] = [ 71 | ...history, 72 | { role: 'user', content: userChoice } 73 | ]; 74 | setHistory(updatedHistory); 75 | 76 | const updatedContent = `${storyContent}\n\n${userChoice}\n\n`; 77 | setStoryContent(updatedContent); 78 | 79 | try { 80 | // 计算用户选择次数 81 | const choiceCount = history.filter(item => item.role === 'user').length; 82 | 83 | const response = await continueStoryAndGenerateChoices( 84 | updatedHistory, 85 | 'creative', 86 | structureOutline, 87 | choiceCount, 88 | structureThinkingHistory, 89 | preferenceThinkingHistory 90 | ); 91 | 92 | const { storyContinuation, choices, structureThinking, preferenceThinking } = response; 93 | 94 | const finalContent = updatedContent + storyContinuation; 95 | const finalHistory: HistoryItem[] = [...updatedHistory, { role: 'assistant', content: storyContinuation }]; 96 | 97 | setStoryContent(finalContent); 98 | setHistory(finalHistory); 99 | setCurrentChoices(choices); 100 | 101 | // 更新思考历史 102 | const updatedStructureThinkingHistory = [...structureThinkingHistory]; 103 | const updatedPreferenceThinkingHistory = [...preferenceThinkingHistory]; 104 | 105 | // 如果有结构思考,添加到历史 106 | if (structureThinking) { 107 | updatedStructureThinkingHistory.push({ 108 | position: choiceCount, 109 | content: structureThinking 110 | }); 111 | } 112 | 113 | // 如果有用户偏好分析,添加到历史 114 | if (preferenceThinking) { 115 | updatedPreferenceThinkingHistory.push({ 116 | position: choiceCount, 117 | content: preferenceThinking 118 | }); 119 | } 120 | 121 | // 将更新后的内容、选项和思考历史传递回 App 组件 122 | onUpdate( 123 | finalContent, 124 | choices, 125 | finalHistory, 126 | structureThinking && structureOutline ? structureOutline : undefined, 127 | updatedStructureThinkingHistory, 128 | updatedPreferenceThinkingHistory 129 | ); 130 | 131 | // 如果返回了用户偏好分析,可以在控制台记录用于调试 132 | if (preferenceThinking) { 133 | console.log('用户偏好分析:', preferenceThinking); 134 | } 135 | } catch (err) { 136 | const errorMessage = handleAiError(err as Error); 137 | setError(errorMessage); 138 | setCurrentChoices(currentChoices); 139 | } finally { 140 | setIsLoading(false); 141 | } 142 | }; 143 | 144 | return ( 145 |
152 |
153 | {storyContent.split('\n\n').map((paragraph, index) => ( 154 |

') 156 | ? theme === 'dark' ? 'text-green-400' : 'text-green-600' 157 | : '' 158 | } ${theme === 'dark' ? 'text-gray-200' : 'text-gray-800'}`}> 159 | {paragraph} 160 |

161 | ))} 162 |
163 | 164 |
165 | {error && ( 166 |
167 | {error} 168 |
169 | )} 170 | 171 | {isLoading ? ( 172 | 173 | ) : ( 174 | <> 175 |
176 |

你会怎么做?

179 | 180 | 181 | )} 182 |
183 | 184 | {showBackToTop && } 185 |
186 | ); 187 | }; 188 | 189 | export default NovelReadingScreen; -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import StyleSelectionScreen from './components/StyleSelectionScreen'; 3 | import NovelReadingScreen from './components/NovelReadingScreen'; 4 | import Navigation from './components/Navigation'; 5 | // Removed AuthModal import 6 | import { NovelStyle, ThinkingHistoryItem } from './types'; 7 | import { novelStyles } from './data/novelStyles'; 8 | import { generateInitialStoryAndChoices, generateInitialStructure, handleAiError } from './services/aiService'; 9 | import { useNovelStore } from './store/novelStore'; 10 | import { useThemeStore } from './components/ThemeSwitcher'; 11 | // Removed useAuthStore import (or keep if user info is still displayed, but remove setUser) 12 | // Removed supabase import 13 | 14 | function App() { 15 | const [currentScreen, setCurrentScreen] = useState<'style' | 'novel'>('style'); 16 | const [selectedStyle, setSelectedStyle] = useState(null); 17 | const [storyContent, setStoryContent] = useState(''); 18 | const [currentChoices, setCurrentChoices] = useState>([]); 19 | const [history, setHistory] = useState>([]); 20 | const [structureOutline, setStructureOutline] = useState(null); 21 | const [structureThinkingHistory, setStructureThinkingHistory] = useState([]); 22 | const [preferenceThinkingHistory, setPreferenceThinkingHistory] = useState([]); 23 | const [isLoading, setIsLoading] = useState(false); 24 | const [error, setError] = useState(null); 25 | // Removed showAuthModal state 26 | 27 | // Removed syncWithSupabase from destructuring 28 | const { histories, addHistory, updateHistory } = useNovelStore(); 29 | // Removed user and setUser from useAuthStore 30 | const theme = useThemeStore((state) => state.theme); 31 | 32 | // Removed Supabase useEffect hook (lines 31-68 from original) 33 | 34 | const handleStyleSelect = async (style: NovelStyle) => { 35 | // Removed user check and setShowAuthModal call 36 | 37 | setSelectedStyle(style); 38 | setIsLoading(true); 39 | setError(null); 40 | 41 | try { 42 | // Generate initial story and structure (logic remains the same) 43 | const { story, choices } = await generateInitialStoryAndChoices( 44 | style.prompt, 45 | 'creative' 46 | ); 47 | const initialOutline = await generateInitialStructure(style.prompt, 'balanced'); 48 | setStructureOutline(initialOutline); 49 | 50 | // Reset thinking history 51 | setStructureThinkingHistory([]); 52 | setPreferenceThinkingHistory([]); 53 | 54 | // Create new history entry (logic remains the same, uses local ID generation) 55 | const newHistory = { 56 | id: crypto.randomUUID(), // Use local ID 57 | style, 58 | lastUpdated: Date.now(), 59 | content: story, 60 | choices, 61 | history: [{ role: 'assistant' as const, content: story }], 62 | structureOutline: initialOutline, 63 | structureThinkingHistory: [], 64 | preferenceThinkingHistory: [] 65 | }; 66 | 67 | // Add history to the local store 68 | addHistory(newHistory); // No longer async or interacting with Supabase 69 | 70 | setStoryContent(story); 71 | setCurrentChoices(choices); 72 | setHistory([{ role: 'assistant', content: story }]); 73 | setCurrentScreen('novel'); 74 | } catch (err) { 75 | const errorMessage = handleAiError(err as Error); 76 | setError(errorMessage); 77 | } finally { 78 | setIsLoading(false); 79 | } 80 | }; 81 | 82 | const handleSelectHistory = (historyId: string) => { 83 | const selectedHistory = histories.find(h => h.id === historyId); 84 | if (selectedHistory) { 85 | setSelectedStyle(selectedHistory.style); 86 | setStoryContent(selectedHistory.content); 87 | setCurrentChoices(selectedHistory.choices); 88 | setHistory(selectedHistory.history); 89 | setStructureOutline(selectedHistory.structureOutline || null); 90 | setStructureThinkingHistory(selectedHistory.structureThinkingHistory || []); 91 | setPreferenceThinkingHistory(selectedHistory.preferenceThinkingHistory || []); 92 | setCurrentScreen('novel'); 93 | } 94 | }; 95 | 96 | // handleStoryUpdate remains largely the same, but updateHistory is now synchronous 97 | const handleStoryUpdate = ( // Removed async keyword 98 | content: string, 99 | choices: Array<{id: string, text: string}>, 100 | historyItems: Array<{role: 'user' | 'assistant', content: string}>, 101 | newStructureOutline?: string, 102 | updatedStructureThinkingHistory?: ThinkingHistoryItem[], 103 | updatedPreferenceThinkingHistory?: ThinkingHistoryItem[] 104 | ) => { 105 | if (selectedStyle && histories.length > 0) { 106 | if (newStructureOutline) { 107 | setStructureOutline(newStructureOutline); 108 | } 109 | if (updatedStructureThinkingHistory) { 110 | setStructureThinkingHistory(updatedStructureThinkingHistory); 111 | } 112 | if (updatedPreferenceThinkingHistory) { 113 | setPreferenceThinkingHistory(updatedPreferenceThinkingHistory); 114 | } 115 | 116 | // Update history in the local store 117 | updateHistory(histories[0].id, { // No longer async 118 | content, 119 | choices, 120 | history: historyItems, 121 | structureOutline: newStructureOutline || structureOutline, 122 | structureThinkingHistory: updatedStructureThinkingHistory || structureThinkingHistory, 123 | preferenceThinkingHistory: updatedPreferenceThinkingHistory || preferenceThinkingHistory 124 | }); 125 | } 126 | }; 127 | 128 | return ( 129 |
130 | {currentScreen === 'style' ? ( 131 | 138 | ) : ( 139 | <> 140 | 154 | setCurrentScreen('style')} 156 | onSelectHistory={handleSelectHistory} 157 | // Removed user prop if it existed 158 | /> 159 | 160 | )} 161 | {/* Removed AuthModal rendering */} 162 |
163 | ); 164 | } 165 | 166 | export default App; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /src/services/aiService.ts: -------------------------------------------------------------------------------- 1 | import { HistoryItem, StoryChoice, EnhancedContinuationResponse, ThinkingHistoryItem } from '../types'; 2 | 3 | // Model configurations 4 | interface ModelConfig { 5 | name: string; 6 | endpoint: string; 7 | temperature: number; 8 | maxTokens?: number; 9 | topP?: number; 10 | frequencyPenalty?: number; 11 | presencePenalty?: number; 12 | thinking?: { 13 | enabled: boolean; 14 | steps: number; 15 | depth: number; 16 | }; 17 | } 18 | 19 | const models: Record = { 20 | creative: { 21 | name: import.meta.env.VITE_AI_CREATIVE_MODEL_NAME, 22 | endpoint: import.meta.env.VITE_AI_CREATIVE_MODEL_ENDPOINT , 23 | temperature: 0.8, 24 | maxTokens: 2000, 25 | topP: 0.9, 26 | frequencyPenalty: 0.3, 27 | presencePenalty: 0.3, 28 | thinking: { 29 | enabled: false, 30 | steps: 3, 31 | depth: 2 32 | } 33 | }, 34 | precise: { 35 | name: import.meta.env.VITE_AI_PRECISE_MODEL_NAME, 36 | endpoint: import.meta.env.VITE_AI_PRECISE_MODEL_ENDPOINT , 37 | temperature: 0.3, 38 | maxTokens: 2000, 39 | topP: 0.8, 40 | frequencyPenalty: 0.1, 41 | presencePenalty: 0.1, 42 | thinking: { 43 | enabled: false, 44 | steps: 4, 45 | depth: 3 46 | } 47 | }, 48 | balanced: { 49 | name: import.meta.env.VITE_AI_BALANCED_MODEL_NAME, 50 | endpoint: import.meta.env.VITE_AI_BALANCED_MODEL_ENDPOINT , 51 | temperature: 0.5, 52 | maxTokens: 2000, 53 | topP: 0.85, 54 | frequencyPenalty: 0.2, 55 | presencePenalty: 0.2, 56 | thinking: { 57 | enabled: false, 58 | steps: 3, 59 | depth: 2 60 | } 61 | } 62 | }; 63 | 64 | const defaultModel: ModelConfig = models.creative; 65 | const API_KEY = import.meta.env.VITE_AI_API_KEY; 66 | 67 | if (!API_KEY) { 68 | throw new Error('AI API key not found in environment variables'); 69 | } 70 | 71 | const generateThinkingSteps = (prompt: string, config: ModelConfig['thinking']) => { 72 | if (!config?.enabled) return prompt; 73 | 74 | const steps = Array(config.steps).fill(0).map((_, i) => { 75 | const depth = Array(config.depth).fill(0).map((_, j) => { 76 | return `思考层级 ${j + 1}: 分析当前情节发展的可能性和影响`; 77 | }).join('\n'); 78 | return `步骤 ${i + 1}:\n${depth}`; 79 | }).join('\n\n'); 80 | 81 | return `${steps}\n\n${prompt}`; 82 | }; 83 | 84 | interface StoryResponse { 85 | story: string; 86 | choices: StoryChoice[]; 87 | } 88 | 89 | const safeJsonParse = (text: string) => { 90 | let cleaned = text.trim(); 91 | 92 | // Remove Markdown code fences like ```json ... ``` 93 | cleaned = cleaned 94 | .replace(/^```(?:json)?\s*/i, '') 95 | .replace(/\s*```$/i, '') 96 | .trim(); 97 | 98 | // Normalize curly quotes that occasionally appear in AI output 99 | cleaned = cleaned.replace(/[“”]/g, '"'); 100 | 101 | // Extract the first JSON object if extra text surrounds it 102 | const firstBrace = cleaned.indexOf('{'); 103 | const lastBrace = cleaned.lastIndexOf('}'); 104 | if (firstBrace !== -1 && lastBrace !== -1) { 105 | const jsonSubstring = cleaned.substring(firstBrace, lastBrace + 1); 106 | try { 107 | return JSON.parse(jsonSubstring); 108 | } catch (_) { 109 | // fall through to try full cleaned string below 110 | } 111 | } 112 | 113 | try { 114 | return JSON.parse(cleaned); 115 | } catch (error) { 116 | console.error('JSON Parse Error:', error); 117 | console.error('Raw Response:', text); 118 | throw new Error(`Invalid JSON response from AI service: ${(error as Error).message}`); 119 | } 120 | }; 121 | 122 | // 新增:生成初始结构大纲 123 | export const generateInitialStructure = async ( 124 | stylePrompt: string, 125 | modelType: keyof typeof models = 'balanced' 126 | ): Promise => { 127 | try { 128 | const modelConfig = models[modelType] || defaultModel; 129 | const basePrompt = ` 130 | **!!!绝对强制输出格式!!!** 131 | 你的唯一输出**必须**是单个、完整且语法绝对正确的 JSON 对象。**禁止**在 JSON 对象之外添加任何字符、解释、注释、代码标记(如 \`\`\`json)或任何形式的元评论。任何偏离此格式的输出都将被视为完全失败。 132 | 133 | **JSON 结构(必须严格遵守)**: 134 | { 135 | "outline": "大纲内容。段落之间必须使用且仅使用 \\n\\n 分隔。" 136 | } 137 | 138 | **JSON 格式细节(强制)**: 139 | 1. **引号**:所有 JSON 键和字符串值**必须**使用双引号 ("). 140 | 2. **转义**:字符串值内部的所有特殊字符(如 "、换行符等)**必须**正确转义(例如:\\", \\n)。 141 | 3. **完整性**:确保 JSON 对象完整,无截断、无语法错误(如多余逗号)。 142 | 4. **无额外包装(关键点)**:最终的输出必须是纯粹的、原始的 JSON 字符串本身,绝对不能包含 Markdown 的代码块标记或其他任何解释性文本。响应应直接以 { 开始,并以 } 结束。 143 | 144 | **任务**: 根据以下风格提示,生成一个简洁的小说初始结构大纲。 145 | **风格提示**: ${stylePrompt} 146 | **要求**: 147 | 1. 大纲应包含主要章节、关键转折点或大致的结局方向。 148 | 2. 输出**必须**是纯文本格式的大纲内容,**不要包含任何** 嵌套JSON、Markdown 标记或其他元注释。 149 | 3. 大纲内容应控制在 200-300 字左右。 150 | 4. 将你创作的大纲填充到上述 JSON 结构的 "outline" 字段中。 151 | 152 | **输出示例内容(仅供参考,你需要创建原创内容并放入JSON结构中)**: 153 | 第一章:主角的平凡生活与隐藏的危机。 154 | 第二章:危机爆发,主角被迫踏上旅程。 155 | 第三章:遭遇关键盟友或导师,获得初步成长。 156 | 第四章:面临重大挑战与第一个转折点。 157 | 第五章:深入险境,揭露部分真相。 158 | 第六章:最终决战与结局(开放式/封闭式)。 159 | `; 160 | 161 | return await retryWithBackoff(async () => { 162 | // --- Start Logging --- 163 | const requestBody = { 164 | model: modelConfig.name, 165 | messages: [ 166 | { 167 | role: 'system', 168 | content: '你的唯一输出必须是单个、完整且语法绝对正确的 JSON 对象。禁止在 JSON 对象之外添加任何其他内容。' 169 | }, 170 | { role: 'user', content: basePrompt } 171 | ], 172 | temperature: modelConfig.temperature, 173 | max_tokens: 500, 174 | response_format: { type: "json_object" } 175 | }; 176 | const requestHeaders = { 177 | 'Content-Type': 'application/json', 178 | 'Authorization': `Bearer ${API_KEY ? '***MASKED***' : 'MISSING'}` // Mask API Key 179 | }; 180 | console.log(`[${new Date().toISOString()}] AI Request (generateInitialStructure):`); 181 | console.log(` URL: ${modelConfig.endpoint}`); 182 | console.log(` Method: POST`); 183 | console.log(` Headers: ${JSON.stringify(requestHeaders)}`); 184 | console.log(` Body: ${JSON.stringify(requestBody)}`); 185 | // --- End Logging --- 186 | 187 | const response = await fetch(modelConfig.endpoint, { 188 | method: 'POST', 189 | headers: { // Use original headers for the actual request 190 | 'Content-Type': 'application/json', 191 | 'Authorization': `Bearer ${API_KEY}` 192 | }, 193 | body: JSON.stringify(requestBody) 194 | }); 195 | 196 | if (!response.ok) { 197 | // Log error response body if possible 198 | try { 199 | const errorBody = await response.text(); 200 | console.error(`[${new Date().toISOString()}] AI Request Failed (generateInitialStructure). Status: ${response.status}. Body: ${errorBody}`); 201 | } catch (e) { 202 | console.error(`[${new Date().toISOString()}] AI Request Failed (generateInitialStructure). Status: ${response.status}. Could not read error body:`, e); // Fix: Use 'e' 203 | } 204 | throw new Error(`API error: ${response.status} ${response.statusText}`); 205 | } 206 | 207 | const data = await response.json(); 208 | console.log('Raw AI Response Data (Initial Structure):', data); 209 | 210 | if (!data.choices?.[0]?.message?.content) { 211 | console.error('Raw AI Response Data (Initial Structure) missing content:', data); 212 | throw new Error('AI response structure unexpected or content missing'); 213 | } 214 | 215 | console.log('AI Output Content (Initial Structure):', data.choices[0].message.content); 216 | 217 | const result = safeJsonParse(data.choices[0].message.content); 218 | 219 | if (!result.outline) { 220 | throw new Error('AI response missing outline field'); 221 | } 222 | 223 | return result.outline.trim(); 224 | }); 225 | } catch (error) { 226 | console.error('Error generating initial structure:', error); 227 | throw error; 228 | } 229 | }; 230 | 231 | // Add retry mechanism with exponential backoff 232 | const retryWithBackoff = async ( 233 | operation: () => Promise, 234 | maxRetries: number = 3, 235 | baseDelay: number = 1000 236 | ): Promise => { 237 | let lastError: Error | null = null; 238 | 239 | for (let attempt = 0; attempt < maxRetries; attempt++) { 240 | try { 241 | // Log attempt number 242 | console.log(`[${new Date().toISOString()}] Retry Attempt ${attempt + 1}/${maxRetries}...`); 243 | return await operation(); 244 | } catch (error: unknown) { 245 | lastError = error as Error; 246 | console.error(`[${new Date().toISOString()}] Retry Attempt ${attempt + 1} failed:`, lastError); 247 | 248 | // Only retry on 503 errors or potentially other transient server errors (e.g., 500, 502, 504) 249 | const statusCodeMatch = lastError.message.match(/API error: (5\d{2})/); 250 | const shouldRetry = statusCodeMatch && ['500', '502', '503', '504'].includes(statusCodeMatch[1]); 251 | 252 | if (!shouldRetry) { 253 | console.log(`[${new Date().toISOString()}] Error is not retryable (${lastError.message}). Throwing.`); 254 | throw lastError; 255 | } 256 | 257 | if (attempt === maxRetries - 1) { 258 | console.log(`[${new Date().toISOString()}] Max retries reached. Throwing last error.`); 259 | throw lastError; 260 | } 261 | 262 | const delay = baseDelay * Math.pow(2, attempt); 263 | console.log(`[${new Date().toISOString()}] Retrying after ${delay}ms delay...`); 264 | await new Promise(resolve => setTimeout(resolve, delay)); 265 | } 266 | } 267 | 268 | // This should theoretically not be reached due to the throw in the loop, but needed for TS 269 | throw lastError || new Error("Retry mechanism failed unexpectedly"); 270 | }; 271 | 272 | export const generateInitialStoryAndChoices = async ( 273 | stylePrompt: string, 274 | modelType: keyof typeof models = 'creative' 275 | ): Promise => { 276 | try { 277 | const modelConfig = models[modelType] || defaultModel; 278 | const basePrompt = ` 279 | **内容生成任务**: 280 | 根据以下「风格提示」和「内容与风格要求」,生成故事开篇和选项,并填充到 JSON 结构的对应字段中, 请注意生成的内容不要有\`\`\`json这种表示markdown的格式表示, 直接返回对象即可。 281 | 282 | **风格提示**:${stylePrompt} 283 | 284 | **内容与风格要求**: 285 | 1. **引人入胜的开篇**: 286 | * **制造悬念与冲突**:开篇需迅速建立悬念、引入核心冲突或提出一个引人好奇的问题,抓住读者注意力。 287 | * **鲜活的感官描写**:运用具体的视觉、听觉、嗅觉、触觉等细节,营造氛围,让读者身临其境("展示,而非告知")。 288 | * **确立基调**:故事开篇的语言风格、节奏和情感色彩必须与「风格提示」高度一致。 289 | * **避免陈词滥调**:在情节构思、人物设定和语言表达上力求新颖,避开常见的套路和俗语。 290 | 2. **故事长度**:开篇故事长度控制在 400 至 500 字之间。 291 | 3. **后续选项**: 292 | * 提供**三个**清晰、具体且有区分度的后续发展选项。 293 | * 每个选项应能将故事引向不同的方向,激发读者的选择欲。 294 | * 选项文本应简洁明了,准确描述选择后的可能发展。 295 | 296 | **!!!绝对强制输出格式!!!** 297 | 你的唯一输出**必须**是单个、完整且语法绝对正确的 JSON 对象。**禁止**在 JSON 对象之外添加任何字符、解释、注释、代码标记(如 \`\`\`json)或任何形式的元评论。任何偏离此格式的输出都将被视为完全失败。 298 | 299 | **JSON 结构(必须严格遵守)**: 300 | { 301 | "story": "故事开篇内容。段落之间必须使用且仅使用 \\n\\n 分隔。", 302 | "choices": [ 303 | { "id": "choice1", "text": "第一个选项描述" }, 304 | { "id": "choice2", "text": "第二个选项描述" }, 305 | { "id": "choice3", "text": "第三个选项描述" } 306 | ] 307 | } 308 | 309 | **JSON 格式细节(强制)**: 310 | 1. **引号**:所有 JSON 键和字符串值**必须**使用双引号 ("). 311 | 2. **转义**:字符串值内部的所有特殊字符(如 "、换行符等)**必须**正确转义(例如:\\", \\n)。 312 | 3. **完整性**:确保 JSON 对象完整,无截断、无语法错误(如多余逗号)。 313 | 4. **无额外包装(关键点)**:最终的输出必须是纯粹的、原始的 JSON 字符串本身,绝对不能包含 Markdown 的代码块标记或其他任何解释性文本。响应应直接以 { 开始,并以 } 结束。 314 | `; 315 | 316 | const prompt = generateThinkingSteps(basePrompt, modelConfig.thinking); 317 | 318 | return await retryWithBackoff(async () => { 319 | // --- Start Logging --- 320 | const requestBody = { 321 | model: modelConfig.name, 322 | messages: [ 323 | { 324 | role: 'system', 325 | content: '你的唯一输出必须是单个、完整且语法绝对正确的 JSON 对象。禁止在 JSON 对象之外添加任何其他内容。' 326 | }, 327 | { role: 'user', content: prompt } 328 | ], 329 | temperature: modelConfig.temperature, 330 | max_tokens: modelConfig.maxTokens, 331 | top_p: modelConfig.topP, 332 | frequency_penalty: modelConfig.frequencyPenalty, 333 | presence_penalty: modelConfig.presencePenalty, 334 | response_format: { type: "json_object" } 335 | }; 336 | const requestHeaders = { 337 | 'Content-Type': 'application/json', 338 | 'Authorization': `Bearer ${API_KEY ? '***MASKED***' : 'MISSING'}` // Mask API Key 339 | }; 340 | console.log(`[${new Date().toISOString()}] AI Request (generateInitialStoryAndChoices):`); 341 | console.log(` URL: ${modelConfig.endpoint}`); 342 | console.log(` Method: POST`); 343 | console.log(` Headers: ${JSON.stringify(requestHeaders)}`); 344 | console.log(` Body: ${JSON.stringify(requestBody)}`); 345 | // --- End Logging --- 346 | 347 | const response = await fetch(modelConfig.endpoint, { 348 | method: 'POST', 349 | headers: { // Use original headers for the actual request 350 | 'Content-Type': 'application/json', 351 | 'Authorization': `Bearer ${API_KEY}` 352 | }, 353 | body: JSON.stringify(requestBody) 354 | }); 355 | 356 | if (!response.ok) { 357 | // Log error response body if possible 358 | try { 359 | const errorBody = await response.text(); 360 | console.error(`[${new Date().toISOString()}] AI Request Failed (generateInitialStoryAndChoices). Status: ${response.status}. Body: ${errorBody}`); 361 | } catch (e) { 362 | console.error(`[${new Date().toISOString()}] AI Request Failed (generateInitialStoryAndChoices). Status: ${response.status}. Could not read error body:`, e); // Fix: Use 'e' 363 | } 364 | throw new Error(`API error: ${response.status} ${response.statusText}`); 365 | } 366 | 367 | const data = await response.json(); 368 | console.log('Raw AI Response Data (Initial Story):', data); 369 | if (!data.choices?.[0]?.message?.content) { 370 | console.error('Raw AI Response Data (Initial Story) missing content:', data); 371 | throw new Error('AI response structure unexpected or content missing'); 372 | } 373 | console.log('AI Output Content (Initial Story):', data.choices[0].message.content); 374 | 375 | const result = safeJsonParse(data.choices[0].message.content) as StoryResponse; 376 | 377 | if (!result.story || !Array.isArray(result.choices) || result.choices.length !== 3) { 378 | throw new Error('AI response missing required fields or has incorrect format'); 379 | } 380 | 381 | return result; 382 | }); 383 | } catch (error) { 384 | console.error('Error generating initial story:', error); 385 | throw error; 386 | } 387 | }; 388 | 389 | export const continueStoryAndGenerateChoices = async ( 390 | history: HistoryItem[], 391 | modelType: keyof typeof models = 'creative', 392 | currentStructureOutline: string | null = null, 393 | choiceCount: number = 0, 394 | structureThinkingHistory: ThinkingHistoryItem[] = [], 395 | preferenceThinkingHistory: ThinkingHistoryItem[] = [] 396 | ): Promise => { 397 | try { 398 | const modelConfig = models[modelType] || defaultModel; 399 | // 从环境变量读取结构思考的阈值,如未设置则默认为 5 400 | const thresholdN = Number(import.meta.env.VITE_STRUCTURE_THINKING_THRESHOLD) || 5; 401 | const needStructureThinking = choiceCount > 0 && choiceCount % thresholdN === 0; 402 | 403 | let basePrompt = ` 404 | **!!!绝对强制输出格式!!!** 405 | 你的唯一输出**必须**是单个、完整且语法绝对正确的 JSON 对象。**禁止**在 JSON 对象之外添加任何字符、解释、注释、代码标记(如 \`\`\`json)或任何形式的元评论。任何偏离此格式的输出都将被视为完全失败。 406 | 407 | **JSON 结构(必须严格遵守)**:`; 408 | 409 | // 根据是否需要结构思考确定JSON结构 410 | if (needStructureThinking) { 411 | basePrompt += ` 412 | { 413 | "storyContinuation": "续写的故事内容。段落之间必须使用且仅使用 \\n\\n 分隔。", 414 | "choices": [ 415 | { "id": "choice1", "text": "第一个选项描述" }, 416 | { "id": "choice2", "text": "第二个选项描述" }, 417 | { "id": "choice3", "text": "第三个选项描述" } 418 | ], 419 | "structureThinking": "对后续小说结构的思考和规划,包括如何根据用户的选择调整当前故事结构", 420 | "preferenceThinking": "对用户偏好的分析和推断,根据历史选择推测用户喜好并规划如何利用这些偏好来设计后续情节或选项" 421 | }`; 422 | } else { 423 | basePrompt += ` 424 | { 425 | "storyContinuation": "续写的故事内容。段落之间必须使用且仅使用 \\n\\n 分隔。", 426 | "choices": [ 427 | { "id": "choice1", "text": "第一个选项描述" }, 428 | { "id": "choice2", "text": "第二个选项描述" }, 429 | { "id": "choice3", "text": "第三个选项描述" } 430 | ] 431 | }`; 432 | } 433 | 434 | basePrompt += ` 435 | 436 | **JSON 格式细节(强制)**: 437 | 1. **引号**:所有 JSON 键和字符串值**必须**使用双引号 ("). 438 | 2. **转义**:字符串值内部的所有特殊字符(如 "、换行符等)**必须**正确转义(例如:\\", \\n)。 439 | 3. **完整性**:确保 JSON 对象完整,无截断、无语法错误(如多余逗号)。 440 | 4. **无额外包装(关键点)**:最终的输出必须是纯粹的、原始的 JSON 字符串本身,绝对不能包含 Markdown 的代码块标记或其他任何解释性文本。响应应直接以 { 开始,并以 } 结束。 441 | 442 | **内容生成任务**: 443 | 根据用户提供的对话历史(包含之前的故事片段和用户的最新选择)和以下「故事续写要求」,创作故事续写和选项,并填充到上述 JSON 结构的对应字段中。 444 | `; 445 | 446 | // 如果有结构大纲,添加到 prompt 中 447 | if (currentStructureOutline) { 448 | basePrompt += `\n**当前故事结构大纲 (${needStructureThinking ? '供参考与更新' : '供参考'})**: 449 | ${currentStructureOutline}\n\n`; 450 | } 451 | 452 | // 如果有结构思考历史,添加到 prompt 中 453 | if (structureThinkingHistory && structureThinkingHistory.length > 0) { 454 | basePrompt += `\n**历史结构思考 (仅供参考)**:\n`; 455 | structureThinkingHistory.forEach(item => { 456 | basePrompt += `[选择${item.position}次后] ${item.content}\n\n`; 457 | }); 458 | } 459 | 460 | // 如果有用户偏好分析历史,添加到 prompt 中 461 | if (preferenceThinkingHistory && preferenceThinkingHistory.length > 0) { 462 | basePrompt += `\n**历史用户偏好分析 (仅供参考)**:\n`; 463 | preferenceThinkingHistory.forEach(item => { 464 | basePrompt += `[选择${item.position}次后] ${item.content}\n\n`; 465 | }); 466 | } 467 | 468 | basePrompt += ` 469 | **故事续写要求**: 470 | 1. **高度连贯性**:续写内容**必须**紧密衔接之前的故事情节和用户做出的最新选择。保持人物性格、动机、故事背景和整体基调的一致性。**允许在叙事需要时进行合理的场景切换或时间跳跃,但必须过渡自然,服务于故事整体逻辑,** 绝不允许出现逻辑断裂或与前文矛盾之处。 471 | 2. **服务故事主线**:续写部分**必须**有效地推动核心情节发展,或深化人物形象,或揭示重要信息。避免无关的旁枝末节或仅仅为了填充字数的无效描写(牢记"故事优先"原则)。 472 | 3. **保持吸引力 ("好看")**: 473 | * 在连贯的基础上,继续营造悬念、加剧冲突或探索新的情节可能性,维持读者的阅读兴趣。 474 | * 运用生动具体的描写(视觉、听觉等感官细节),保持故事的画面感和真实感。 475 | * 语言风格应与故事已有部分保持一致,力求精准、流畅。 476 | 4. **后续选项质量与多样性**: 477 | * 提出的**三个**选项必须是基于当前故事点的合理延伸,**可以包含直接情节推进、角色具体行动或决定、探索不同地点/视角、或引入新的变数**。 478 | * 选项之间应有明显区分,各自导向不同的、有意义的情节发展方向。 479 | * **至少包含一个**提供显著变化、转折或探索不同可能性的选项,以增加故事的丰富度和不可预测性。 480 | * **所有选项必须**与当前故事背景和人物状态保持逻辑关联,**不得完全脱离故事**,并具有潜在的叙事价值。 481 | * 选项描述需简洁、清晰,能准确预示选择后的故事走向。 482 | 5. **字数控制**:续写的故事内容长度严格控制在 300 至 500 字之间。 483 | `; 484 | 485 | // 如果是第5、10、15...次选择,添加额外思考要求 486 | if (needStructureThinking) { 487 | basePrompt += ` 488 | **额外思考要求(因为这是第${choiceCount}次选择)**: 489 | 1. **结构思考**:分析故事当前的发展状态,对后续结构进行深入思考。考虑当前情节如何发展,需要注意哪些主题和矛盾,如何推动故事向高潮迈进。 490 | 2. **用户偏好分析**:基于用户之前的${choiceCount}次选择,推断用户的偏好和兴趣点。考虑用户是更偏向冒险、对话、情感描写还是其他方面,并思考如何在后续选项和内容中融入这些偏好。 491 | `; 492 | } 493 | 494 | const systemPrompt = generateThinkingSteps(basePrompt, modelConfig.thinking); 495 | 496 | return await retryWithBackoff(async () => { 497 | // --- Start Logging --- 498 | const requestBody = { 499 | model: modelConfig.name, 500 | messages: [ 501 | { 502 | role: 'system', 503 | content: '你的唯一输出必须是单个、完整且语法绝对正确的 JSON 对象。禁止在 JSON 对象之外添加任何其他内容。请注意生成的内容不要有```json这种表示markdown的格式表示, 直接返回对象即可.' 504 | }, 505 | ...history, 506 | { role: 'user', content: systemPrompt } 507 | ], 508 | temperature: modelConfig.temperature, 509 | max_tokens: modelConfig.maxTokens, 510 | top_p: modelConfig.topP, 511 | frequency_penalty: modelConfig.frequencyPenalty, 512 | presence_penalty: modelConfig.presencePenalty, 513 | response_format: { type: "json_object" } 514 | }; 515 | const requestHeaders = { 516 | 'Content-Type': 'application/json', 517 | 'Authorization': `Bearer ${API_KEY ? '***MASKED***' : 'MISSING'}` // Mask API Key 518 | }; 519 | console.log(`[${new Date().toISOString()}] AI Request (continueStoryAndGenerateChoices):`); 520 | console.log(` URL: ${modelConfig.endpoint}`); 521 | console.log(` Method: POST`); 522 | console.log(` Headers: ${JSON.stringify(requestHeaders)}`); 523 | console.log(` Body: ${JSON.stringify(requestBody)}`); 524 | // --- End Logging --- 525 | 526 | const response = await fetch(modelConfig.endpoint, { 527 | method: 'POST', 528 | headers: { // Use original headers for the actual request 529 | 'Content-Type': 'application/json', 530 | 'Authorization': `Bearer ${API_KEY}` 531 | }, 532 | body: JSON.stringify(requestBody) 533 | }); 534 | 535 | if (!response.ok) { 536 | // Log error response body if possible 537 | try { 538 | const errorBody = await response.text(); 539 | console.error(`[${new Date().toISOString()}] AI Request Failed (continueStoryAndGenerateChoices). Status: ${response.status}. Body: ${errorBody}`); 540 | } catch (e) { 541 | console.error(`[${new Date().toISOString()}] AI Request Failed (continueStoryAndGenerateChoices). Status: ${response.status}. Could not read error body:`, e); // Fix: Use 'e' 542 | } 543 | throw new Error(`API error: ${response.status} ${response.statusText}`); 544 | } 545 | 546 | const data = await response.json(); 547 | console.log('Raw AI Response Data (Continuation):', data); 548 | if (!data.choices?.[0]?.message?.content) { 549 | console.error('Raw AI Response Data (Continuation) missing content:', data); 550 | throw new Error('AI response structure unexpected or content missing'); 551 | } 552 | console.log('AI Output Content (Continuation):', data.choices[0].message.content); 553 | 554 | const result = safeJsonParse(data.choices[0].message.content); 555 | 556 | if (!result.storyContinuation || !Array.isArray(result.choices) || result.choices.length !== 3) { 557 | throw new Error('AI response missing required fields or has incorrect format'); 558 | } 559 | 560 | return { 561 | storyContinuation: result.storyContinuation, 562 | choices: result.choices, 563 | structureThinking: result.structureThinking, 564 | preferenceThinking: result.preferenceThinking 565 | }; 566 | }); 567 | } catch (error) { 568 | console.error('Error continuing story:', error); 569 | throw error; 570 | } 571 | }; 572 | 573 | export const handleAiError = (error: Error, defaultMessage: string = 'AI服务暂时不可用,请稍后再试'): string => { 574 | console.error('AI Service Error:', error); 575 | 576 | if (error.message.includes('API error: 429')) { 577 | return '请求次数过多,请稍后再试'; 578 | } else if (error.message.includes('API error: 503')) { 579 | return 'AI服务暂时不可用,系统正在尝试重新连接,请稍候...'; 580 | } else if (error.message.includes('API error: 5')) { // Catch 5xx errors 581 | return 'AI服务器暂时不可用,请稍后再试'; 582 | } else if (error.message.includes('Invalid JSON response')) { 583 | return 'AI返回的格式有误,请重试'; 584 | } else if (error.message.includes('解析错误:')) { // Assuming this is a custom error message prefix 585 | return `${error.message},请重试`; 586 | } else if (error.message.includes('API error: 403')) { 587 | return 'AI服务授权失败,请检查API密钥是否正确'; 588 | } else if (error.message.includes('API error: 400')) { // Add specific message for 400 589 | return '请求参数错误,请检查输入或联系开发者'; 590 | } else if (error.message.includes('missing required fields')) { 591 | return 'AI返回的内容格式不完整,请重试'; 592 | } 593 | 594 | return defaultMessage; 595 | }; -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | '@radix-ui/react-dialog': 12 | specifier: ^1.0.5 13 | version: 1.1.11(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 14 | lucide-react: 15 | specifier: ^0.344.0 16 | version: 0.344.0(react@18.3.1) 17 | react: 18 | specifier: ^18.3.1 19 | version: 18.3.1 20 | react-dom: 21 | specifier: ^18.3.1 22 | version: 18.3.1(react@18.3.1) 23 | zustand: 24 | specifier: ^4.5.2 25 | version: 4.5.6(@types/react@18.3.20)(react@18.3.1) 26 | devDependencies: 27 | '@eslint/js': 28 | specifier: ^9.9.1 29 | version: 9.25.1 30 | '@types/react': 31 | specifier: ^18.3.5 32 | version: 18.3.20 33 | '@types/react-dom': 34 | specifier: ^18.3.0 35 | version: 18.3.6(@types/react@18.3.20) 36 | '@vitejs/plugin-react': 37 | specifier: ^4.3.1 38 | version: 4.4.1(vite@5.4.18(@types/node@22.15.3)) 39 | autoprefixer: 40 | specifier: ^10.4.18 41 | version: 10.4.21(postcss@8.5.3) 42 | eslint: 43 | specifier: ^9.9.1 44 | version: 9.25.1(jiti@1.21.7) 45 | eslint-plugin-react-hooks: 46 | specifier: ^5.1.0-rc.0 47 | version: 5.2.0(eslint@9.25.1(jiti@1.21.7)) 48 | eslint-plugin-react-refresh: 49 | specifier: ^0.4.11 50 | version: 0.4.20(eslint@9.25.1(jiti@1.21.7)) 51 | globals: 52 | specifier: ^15.9.0 53 | version: 15.15.0 54 | postcss: 55 | specifier: ^8.4.35 56 | version: 8.5.3 57 | tailwindcss: 58 | specifier: ^3.4.1 59 | version: 3.4.17 60 | typescript: 61 | specifier: ^5.5.3 62 | version: 5.8.3 63 | typescript-eslint: 64 | specifier: ^8.3.0 65 | version: 8.31.0(eslint@9.25.1(jiti@1.21.7))(typescript@5.8.3) 66 | vite: 67 | specifier: ^5.4.2 68 | version: 5.4.18(@types/node@22.15.3) 69 | 70 | packages: 71 | 72 | '@alloc/quick-lru@5.2.0': 73 | resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} 74 | engines: {node: '>=10'} 75 | 76 | '@ampproject/remapping@2.3.0': 77 | resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} 78 | engines: {node: '>=6.0.0'} 79 | 80 | '@babel/code-frame@7.26.2': 81 | resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} 82 | engines: {node: '>=6.9.0'} 83 | 84 | '@babel/compat-data@7.26.8': 85 | resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==} 86 | engines: {node: '>=6.9.0'} 87 | 88 | '@babel/core@7.26.10': 89 | resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==} 90 | engines: {node: '>=6.9.0'} 91 | 92 | '@babel/generator@7.27.0': 93 | resolution: {integrity: sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==} 94 | engines: {node: '>=6.9.0'} 95 | 96 | '@babel/helper-compilation-targets@7.27.0': 97 | resolution: {integrity: sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==} 98 | engines: {node: '>=6.9.0'} 99 | 100 | '@babel/helper-module-imports@7.25.9': 101 | resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} 102 | engines: {node: '>=6.9.0'} 103 | 104 | '@babel/helper-module-transforms@7.26.0': 105 | resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} 106 | engines: {node: '>=6.9.0'} 107 | peerDependencies: 108 | '@babel/core': ^7.0.0 109 | 110 | '@babel/helper-plugin-utils@7.26.5': 111 | resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==} 112 | engines: {node: '>=6.9.0'} 113 | 114 | '@babel/helper-string-parser@7.25.9': 115 | resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} 116 | engines: {node: '>=6.9.0'} 117 | 118 | '@babel/helper-validator-identifier@7.25.9': 119 | resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} 120 | engines: {node: '>=6.9.0'} 121 | 122 | '@babel/helper-validator-option@7.25.9': 123 | resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} 124 | engines: {node: '>=6.9.0'} 125 | 126 | '@babel/helpers@7.27.0': 127 | resolution: {integrity: sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==} 128 | engines: {node: '>=6.9.0'} 129 | 130 | '@babel/parser@7.27.0': 131 | resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==} 132 | engines: {node: '>=6.0.0'} 133 | hasBin: true 134 | 135 | '@babel/plugin-transform-react-jsx-self@7.25.9': 136 | resolution: {integrity: sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==} 137 | engines: {node: '>=6.9.0'} 138 | peerDependencies: 139 | '@babel/core': ^7.0.0-0 140 | 141 | '@babel/plugin-transform-react-jsx-source@7.25.9': 142 | resolution: {integrity: sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==} 143 | engines: {node: '>=6.9.0'} 144 | peerDependencies: 145 | '@babel/core': ^7.0.0-0 146 | 147 | '@babel/template@7.27.0': 148 | resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==} 149 | engines: {node: '>=6.9.0'} 150 | 151 | '@babel/traverse@7.27.0': 152 | resolution: {integrity: sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==} 153 | engines: {node: '>=6.9.0'} 154 | 155 | '@babel/types@7.27.0': 156 | resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==} 157 | engines: {node: '>=6.9.0'} 158 | 159 | '@esbuild/aix-ppc64@0.21.5': 160 | resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} 161 | engines: {node: '>=12'} 162 | cpu: [ppc64] 163 | os: [aix] 164 | 165 | '@esbuild/android-arm64@0.21.5': 166 | resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} 167 | engines: {node: '>=12'} 168 | cpu: [arm64] 169 | os: [android] 170 | 171 | '@esbuild/android-arm@0.21.5': 172 | resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} 173 | engines: {node: '>=12'} 174 | cpu: [arm] 175 | os: [android] 176 | 177 | '@esbuild/android-x64@0.21.5': 178 | resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} 179 | engines: {node: '>=12'} 180 | cpu: [x64] 181 | os: [android] 182 | 183 | '@esbuild/darwin-arm64@0.21.5': 184 | resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} 185 | engines: {node: '>=12'} 186 | cpu: [arm64] 187 | os: [darwin] 188 | 189 | '@esbuild/darwin-x64@0.21.5': 190 | resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} 191 | engines: {node: '>=12'} 192 | cpu: [x64] 193 | os: [darwin] 194 | 195 | '@esbuild/freebsd-arm64@0.21.5': 196 | resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} 197 | engines: {node: '>=12'} 198 | cpu: [arm64] 199 | os: [freebsd] 200 | 201 | '@esbuild/freebsd-x64@0.21.5': 202 | resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} 203 | engines: {node: '>=12'} 204 | cpu: [x64] 205 | os: [freebsd] 206 | 207 | '@esbuild/linux-arm64@0.21.5': 208 | resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} 209 | engines: {node: '>=12'} 210 | cpu: [arm64] 211 | os: [linux] 212 | 213 | '@esbuild/linux-arm@0.21.5': 214 | resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} 215 | engines: {node: '>=12'} 216 | cpu: [arm] 217 | os: [linux] 218 | 219 | '@esbuild/linux-ia32@0.21.5': 220 | resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} 221 | engines: {node: '>=12'} 222 | cpu: [ia32] 223 | os: [linux] 224 | 225 | '@esbuild/linux-loong64@0.21.5': 226 | resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} 227 | engines: {node: '>=12'} 228 | cpu: [loong64] 229 | os: [linux] 230 | 231 | '@esbuild/linux-mips64el@0.21.5': 232 | resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} 233 | engines: {node: '>=12'} 234 | cpu: [mips64el] 235 | os: [linux] 236 | 237 | '@esbuild/linux-ppc64@0.21.5': 238 | resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} 239 | engines: {node: '>=12'} 240 | cpu: [ppc64] 241 | os: [linux] 242 | 243 | '@esbuild/linux-riscv64@0.21.5': 244 | resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} 245 | engines: {node: '>=12'} 246 | cpu: [riscv64] 247 | os: [linux] 248 | 249 | '@esbuild/linux-s390x@0.21.5': 250 | resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} 251 | engines: {node: '>=12'} 252 | cpu: [s390x] 253 | os: [linux] 254 | 255 | '@esbuild/linux-x64@0.21.5': 256 | resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} 257 | engines: {node: '>=12'} 258 | cpu: [x64] 259 | os: [linux] 260 | 261 | '@esbuild/netbsd-x64@0.21.5': 262 | resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} 263 | engines: {node: '>=12'} 264 | cpu: [x64] 265 | os: [netbsd] 266 | 267 | '@esbuild/openbsd-x64@0.21.5': 268 | resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} 269 | engines: {node: '>=12'} 270 | cpu: [x64] 271 | os: [openbsd] 272 | 273 | '@esbuild/sunos-x64@0.21.5': 274 | resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} 275 | engines: {node: '>=12'} 276 | cpu: [x64] 277 | os: [sunos] 278 | 279 | '@esbuild/win32-arm64@0.21.5': 280 | resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} 281 | engines: {node: '>=12'} 282 | cpu: [arm64] 283 | os: [win32] 284 | 285 | '@esbuild/win32-ia32@0.21.5': 286 | resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} 287 | engines: {node: '>=12'} 288 | cpu: [ia32] 289 | os: [win32] 290 | 291 | '@esbuild/win32-x64@0.21.5': 292 | resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} 293 | engines: {node: '>=12'} 294 | cpu: [x64] 295 | os: [win32] 296 | 297 | '@eslint-community/eslint-utils@4.6.1': 298 | resolution: {integrity: sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==} 299 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 300 | peerDependencies: 301 | eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 302 | 303 | '@eslint-community/regexpp@4.12.1': 304 | resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} 305 | engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} 306 | 307 | '@eslint/config-array@0.20.0': 308 | resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==} 309 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 310 | 311 | '@eslint/config-helpers@0.2.1': 312 | resolution: {integrity: sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==} 313 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 314 | 315 | '@eslint/core@0.13.0': 316 | resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} 317 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 318 | 319 | '@eslint/eslintrc@3.3.1': 320 | resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} 321 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 322 | 323 | '@eslint/js@9.25.1': 324 | resolution: {integrity: sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==} 325 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 326 | 327 | '@eslint/object-schema@2.1.6': 328 | resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} 329 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 330 | 331 | '@eslint/plugin-kit@0.2.8': 332 | resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} 333 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 334 | 335 | '@humanfs/core@0.19.1': 336 | resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} 337 | engines: {node: '>=18.18.0'} 338 | 339 | '@humanfs/node@0.16.6': 340 | resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} 341 | engines: {node: '>=18.18.0'} 342 | 343 | '@humanwhocodes/module-importer@1.0.1': 344 | resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} 345 | engines: {node: '>=12.22'} 346 | 347 | '@humanwhocodes/retry@0.3.1': 348 | resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} 349 | engines: {node: '>=18.18'} 350 | 351 | '@humanwhocodes/retry@0.4.2': 352 | resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} 353 | engines: {node: '>=18.18'} 354 | 355 | '@isaacs/cliui@8.0.2': 356 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 357 | engines: {node: '>=12'} 358 | 359 | '@jridgewell/gen-mapping@0.3.8': 360 | resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} 361 | engines: {node: '>=6.0.0'} 362 | 363 | '@jridgewell/resolve-uri@3.1.2': 364 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 365 | engines: {node: '>=6.0.0'} 366 | 367 | '@jridgewell/set-array@1.2.1': 368 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 369 | engines: {node: '>=6.0.0'} 370 | 371 | '@jridgewell/sourcemap-codec@1.5.0': 372 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 373 | 374 | '@jridgewell/trace-mapping@0.3.25': 375 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 376 | 377 | '@nodelib/fs.scandir@2.1.5': 378 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 379 | engines: {node: '>= 8'} 380 | 381 | '@nodelib/fs.stat@2.0.5': 382 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 383 | engines: {node: '>= 8'} 384 | 385 | '@nodelib/fs.walk@1.2.8': 386 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 387 | engines: {node: '>= 8'} 388 | 389 | '@pkgjs/parseargs@0.11.0': 390 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} 391 | engines: {node: '>=14'} 392 | 393 | '@radix-ui/primitive@1.1.2': 394 | resolution: {integrity: sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==} 395 | 396 | '@radix-ui/react-compose-refs@1.1.2': 397 | resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} 398 | peerDependencies: 399 | '@types/react': '*' 400 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 401 | peerDependenciesMeta: 402 | '@types/react': 403 | optional: true 404 | 405 | '@radix-ui/react-context@1.1.2': 406 | resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} 407 | peerDependencies: 408 | '@types/react': '*' 409 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 410 | peerDependenciesMeta: 411 | '@types/react': 412 | optional: true 413 | 414 | '@radix-ui/react-dialog@1.1.11': 415 | resolution: {integrity: sha512-yI7S1ipkP5/+99qhSI6nthfo/tR6bL6Zgxi/+1UO6qPa6UeM6nlafWcQ65vB4rU2XjgjMfMhI3k9Y5MztA62VQ==} 416 | peerDependencies: 417 | '@types/react': '*' 418 | '@types/react-dom': '*' 419 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 420 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 421 | peerDependenciesMeta: 422 | '@types/react': 423 | optional: true 424 | '@types/react-dom': 425 | optional: true 426 | 427 | '@radix-ui/react-dismissable-layer@1.1.7': 428 | resolution: {integrity: sha512-j5+WBUdhccJsmH5/H0K6RncjDtoALSEr6jbkaZu+bjw6hOPOhHycr6vEUujl+HBK8kjUfWcoCJXxP6e4lUlMZw==} 429 | peerDependencies: 430 | '@types/react': '*' 431 | '@types/react-dom': '*' 432 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 433 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 434 | peerDependenciesMeta: 435 | '@types/react': 436 | optional: true 437 | '@types/react-dom': 438 | optional: true 439 | 440 | '@radix-ui/react-focus-guards@1.1.2': 441 | resolution: {integrity: sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==} 442 | peerDependencies: 443 | '@types/react': '*' 444 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 445 | peerDependenciesMeta: 446 | '@types/react': 447 | optional: true 448 | 449 | '@radix-ui/react-focus-scope@1.1.4': 450 | resolution: {integrity: sha512-r2annK27lIW5w9Ho5NyQgqs0MmgZSTIKXWpVCJaLC1q2kZrZkcqnmHkCHMEmv8XLvsLlurKMPT+kbKkRkm/xVA==} 451 | peerDependencies: 452 | '@types/react': '*' 453 | '@types/react-dom': '*' 454 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 455 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 456 | peerDependenciesMeta: 457 | '@types/react': 458 | optional: true 459 | '@types/react-dom': 460 | optional: true 461 | 462 | '@radix-ui/react-id@1.1.1': 463 | resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} 464 | peerDependencies: 465 | '@types/react': '*' 466 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 467 | peerDependenciesMeta: 468 | '@types/react': 469 | optional: true 470 | 471 | '@radix-ui/react-portal@1.1.6': 472 | resolution: {integrity: sha512-XmsIl2z1n/TsYFLIdYam2rmFwf9OC/Sh2avkbmVMDuBZIe7hSpM0cYnWPAo7nHOVx8zTuwDZGByfcqLdnzp3Vw==} 473 | peerDependencies: 474 | '@types/react': '*' 475 | '@types/react-dom': '*' 476 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 477 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 478 | peerDependenciesMeta: 479 | '@types/react': 480 | optional: true 481 | '@types/react-dom': 482 | optional: true 483 | 484 | '@radix-ui/react-presence@1.1.4': 485 | resolution: {integrity: sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==} 486 | peerDependencies: 487 | '@types/react': '*' 488 | '@types/react-dom': '*' 489 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 490 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 491 | peerDependenciesMeta: 492 | '@types/react': 493 | optional: true 494 | '@types/react-dom': 495 | optional: true 496 | 497 | '@radix-ui/react-primitive@2.1.0': 498 | resolution: {integrity: sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw==} 499 | peerDependencies: 500 | '@types/react': '*' 501 | '@types/react-dom': '*' 502 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 503 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 504 | peerDependenciesMeta: 505 | '@types/react': 506 | optional: true 507 | '@types/react-dom': 508 | optional: true 509 | 510 | '@radix-ui/react-slot@1.2.0': 511 | resolution: {integrity: sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==} 512 | peerDependencies: 513 | '@types/react': '*' 514 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 515 | peerDependenciesMeta: 516 | '@types/react': 517 | optional: true 518 | 519 | '@radix-ui/react-use-callback-ref@1.1.1': 520 | resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} 521 | peerDependencies: 522 | '@types/react': '*' 523 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 524 | peerDependenciesMeta: 525 | '@types/react': 526 | optional: true 527 | 528 | '@radix-ui/react-use-controllable-state@1.2.2': 529 | resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} 530 | peerDependencies: 531 | '@types/react': '*' 532 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 533 | peerDependenciesMeta: 534 | '@types/react': 535 | optional: true 536 | 537 | '@radix-ui/react-use-effect-event@0.0.2': 538 | resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} 539 | peerDependencies: 540 | '@types/react': '*' 541 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 542 | peerDependenciesMeta: 543 | '@types/react': 544 | optional: true 545 | 546 | '@radix-ui/react-use-escape-keydown@1.1.1': 547 | resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} 548 | peerDependencies: 549 | '@types/react': '*' 550 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 551 | peerDependenciesMeta: 552 | '@types/react': 553 | optional: true 554 | 555 | '@radix-ui/react-use-layout-effect@1.1.1': 556 | resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} 557 | peerDependencies: 558 | '@types/react': '*' 559 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 560 | peerDependenciesMeta: 561 | '@types/react': 562 | optional: true 563 | 564 | '@rollup/rollup-android-arm-eabi@4.40.1': 565 | resolution: {integrity: sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw==} 566 | cpu: [arm] 567 | os: [android] 568 | 569 | '@rollup/rollup-android-arm64@4.40.1': 570 | resolution: {integrity: sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw==} 571 | cpu: [arm64] 572 | os: [android] 573 | 574 | '@rollup/rollup-darwin-arm64@4.40.1': 575 | resolution: {integrity: sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA==} 576 | cpu: [arm64] 577 | os: [darwin] 578 | 579 | '@rollup/rollup-darwin-x64@4.40.1': 580 | resolution: {integrity: sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw==} 581 | cpu: [x64] 582 | os: [darwin] 583 | 584 | '@rollup/rollup-freebsd-arm64@4.40.1': 585 | resolution: {integrity: sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw==} 586 | cpu: [arm64] 587 | os: [freebsd] 588 | 589 | '@rollup/rollup-freebsd-x64@4.40.1': 590 | resolution: {integrity: sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q==} 591 | cpu: [x64] 592 | os: [freebsd] 593 | 594 | '@rollup/rollup-linux-arm-gnueabihf@4.40.1': 595 | resolution: {integrity: sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg==} 596 | cpu: [arm] 597 | os: [linux] 598 | libc: [glibc] 599 | 600 | '@rollup/rollup-linux-arm-musleabihf@4.40.1': 601 | resolution: {integrity: sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg==} 602 | cpu: [arm] 603 | os: [linux] 604 | libc: [musl] 605 | 606 | '@rollup/rollup-linux-arm64-gnu@4.40.1': 607 | resolution: {integrity: sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg==} 608 | cpu: [arm64] 609 | os: [linux] 610 | libc: [glibc] 611 | 612 | '@rollup/rollup-linux-arm64-musl@4.40.1': 613 | resolution: {integrity: sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ==} 614 | cpu: [arm64] 615 | os: [linux] 616 | libc: [musl] 617 | 618 | '@rollup/rollup-linux-loongarch64-gnu@4.40.1': 619 | resolution: {integrity: sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ==} 620 | cpu: [loong64] 621 | os: [linux] 622 | libc: [glibc] 623 | 624 | '@rollup/rollup-linux-powerpc64le-gnu@4.40.1': 625 | resolution: {integrity: sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg==} 626 | cpu: [ppc64] 627 | os: [linux] 628 | libc: [glibc] 629 | 630 | '@rollup/rollup-linux-riscv64-gnu@4.40.1': 631 | resolution: {integrity: sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ==} 632 | cpu: [riscv64] 633 | os: [linux] 634 | libc: [glibc] 635 | 636 | '@rollup/rollup-linux-riscv64-musl@4.40.1': 637 | resolution: {integrity: sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA==} 638 | cpu: [riscv64] 639 | os: [linux] 640 | libc: [musl] 641 | 642 | '@rollup/rollup-linux-s390x-gnu@4.40.1': 643 | resolution: {integrity: sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg==} 644 | cpu: [s390x] 645 | os: [linux] 646 | libc: [glibc] 647 | 648 | '@rollup/rollup-linux-x64-gnu@4.40.1': 649 | resolution: {integrity: sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==} 650 | cpu: [x64] 651 | os: [linux] 652 | libc: [glibc] 653 | 654 | '@rollup/rollup-linux-x64-musl@4.40.1': 655 | resolution: {integrity: sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==} 656 | cpu: [x64] 657 | os: [linux] 658 | libc: [musl] 659 | 660 | '@rollup/rollup-win32-arm64-msvc@4.40.1': 661 | resolution: {integrity: sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==} 662 | cpu: [arm64] 663 | os: [win32] 664 | 665 | '@rollup/rollup-win32-ia32-msvc@4.40.1': 666 | resolution: {integrity: sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA==} 667 | cpu: [ia32] 668 | os: [win32] 669 | 670 | '@rollup/rollup-win32-x64-msvc@4.40.1': 671 | resolution: {integrity: sha512-ECyOuDeH3C1I8jH2MK1RtBJW+YPMvSfT0a5NN0nHfQYnDSJ6tUiZH3gzwVP5/Kfh/+Tt7tpWVF9LXNTnhTJ3kA==} 672 | cpu: [x64] 673 | os: [win32] 674 | 675 | '@types/babel__core@7.20.5': 676 | resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} 677 | 678 | '@types/babel__generator@7.27.0': 679 | resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} 680 | 681 | '@types/babel__template@7.4.4': 682 | resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} 683 | 684 | '@types/babel__traverse@7.20.7': 685 | resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} 686 | 687 | '@types/estree@1.0.7': 688 | resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} 689 | 690 | '@types/json-schema@7.0.15': 691 | resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} 692 | 693 | '@types/node@22.15.3': 694 | resolution: {integrity: sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==} 695 | 696 | '@types/prop-types@15.7.14': 697 | resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==} 698 | 699 | '@types/react-dom@18.3.6': 700 | resolution: {integrity: sha512-nf22//wEbKXusP6E9pfOCDwFdHAX4u172eaJI4YkDRQEZiorm6KfYnSC2SWLDMVWUOWPERmJnN0ujeAfTBLvrw==} 701 | peerDependencies: 702 | '@types/react': ^18.0.0 703 | 704 | '@types/react@18.3.20': 705 | resolution: {integrity: sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==} 706 | 707 | '@typescript-eslint/eslint-plugin@8.31.0': 708 | resolution: {integrity: sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ==} 709 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 710 | peerDependencies: 711 | '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 712 | eslint: ^8.57.0 || ^9.0.0 713 | typescript: '>=4.8.4 <5.9.0' 714 | 715 | '@typescript-eslint/parser@8.31.0': 716 | resolution: {integrity: sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw==} 717 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 718 | peerDependencies: 719 | eslint: ^8.57.0 || ^9.0.0 720 | typescript: '>=4.8.4 <5.9.0' 721 | 722 | '@typescript-eslint/scope-manager@8.31.0': 723 | resolution: {integrity: sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw==} 724 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 725 | 726 | '@typescript-eslint/type-utils@8.31.0': 727 | resolution: {integrity: sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg==} 728 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 729 | peerDependencies: 730 | eslint: ^8.57.0 || ^9.0.0 731 | typescript: '>=4.8.4 <5.9.0' 732 | 733 | '@typescript-eslint/types@8.31.0': 734 | resolution: {integrity: sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ==} 735 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 736 | 737 | '@typescript-eslint/typescript-estree@8.31.0': 738 | resolution: {integrity: sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ==} 739 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 740 | peerDependencies: 741 | typescript: '>=4.8.4 <5.9.0' 742 | 743 | '@typescript-eslint/utils@8.31.0': 744 | resolution: {integrity: sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww==} 745 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 746 | peerDependencies: 747 | eslint: ^8.57.0 || ^9.0.0 748 | typescript: '>=4.8.4 <5.9.0' 749 | 750 | '@typescript-eslint/visitor-keys@8.31.0': 751 | resolution: {integrity: sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ==} 752 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 753 | 754 | '@vitejs/plugin-react@4.4.1': 755 | resolution: {integrity: sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w==} 756 | engines: {node: ^14.18.0 || >=16.0.0} 757 | peerDependencies: 758 | vite: ^4.2.0 || ^5.0.0 || ^6.0.0 759 | 760 | acorn-jsx@5.3.2: 761 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 762 | peerDependencies: 763 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 764 | 765 | acorn@8.14.1: 766 | resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} 767 | engines: {node: '>=0.4.0'} 768 | hasBin: true 769 | 770 | ajv@6.12.6: 771 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 772 | 773 | ansi-regex@5.0.1: 774 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 775 | engines: {node: '>=8'} 776 | 777 | ansi-regex@6.1.0: 778 | resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} 779 | engines: {node: '>=12'} 780 | 781 | ansi-styles@4.3.0: 782 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 783 | engines: {node: '>=8'} 784 | 785 | ansi-styles@6.2.1: 786 | resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} 787 | engines: {node: '>=12'} 788 | 789 | any-promise@1.3.0: 790 | resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} 791 | 792 | anymatch@3.1.3: 793 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 794 | engines: {node: '>= 8'} 795 | 796 | arg@5.0.2: 797 | resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} 798 | 799 | argparse@2.0.1: 800 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 801 | 802 | aria-hidden@1.2.4: 803 | resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} 804 | engines: {node: '>=10'} 805 | 806 | autoprefixer@10.4.21: 807 | resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} 808 | engines: {node: ^10 || ^12 || >=14} 809 | hasBin: true 810 | peerDependencies: 811 | postcss: ^8.1.0 812 | 813 | balanced-match@1.0.2: 814 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 815 | 816 | binary-extensions@2.3.0: 817 | resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} 818 | engines: {node: '>=8'} 819 | 820 | brace-expansion@1.1.11: 821 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 822 | 823 | brace-expansion@2.0.1: 824 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 825 | 826 | braces@3.0.3: 827 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 828 | engines: {node: '>=8'} 829 | 830 | browserslist@4.24.4: 831 | resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} 832 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 833 | hasBin: true 834 | 835 | callsites@3.1.0: 836 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 837 | engines: {node: '>=6'} 838 | 839 | camelcase-css@2.0.1: 840 | resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} 841 | engines: {node: '>= 6'} 842 | 843 | caniuse-lite@1.0.30001715: 844 | resolution: {integrity: sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==} 845 | 846 | chalk@4.1.2: 847 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 848 | engines: {node: '>=10'} 849 | 850 | chokidar@3.6.0: 851 | resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} 852 | engines: {node: '>= 8.10.0'} 853 | 854 | color-convert@2.0.1: 855 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 856 | engines: {node: '>=7.0.0'} 857 | 858 | color-name@1.1.4: 859 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 860 | 861 | commander@4.1.1: 862 | resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} 863 | engines: {node: '>= 6'} 864 | 865 | concat-map@0.0.1: 866 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 867 | 868 | convert-source-map@2.0.0: 869 | resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} 870 | 871 | cross-spawn@7.0.6: 872 | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 873 | engines: {node: '>= 8'} 874 | 875 | cssesc@3.0.0: 876 | resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} 877 | engines: {node: '>=4'} 878 | hasBin: true 879 | 880 | csstype@3.1.3: 881 | resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} 882 | 883 | debug@4.4.0: 884 | resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} 885 | engines: {node: '>=6.0'} 886 | peerDependencies: 887 | supports-color: '*' 888 | peerDependenciesMeta: 889 | supports-color: 890 | optional: true 891 | 892 | deep-is@0.1.4: 893 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 894 | 895 | detect-node-es@1.1.0: 896 | resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} 897 | 898 | didyoumean@1.2.2: 899 | resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} 900 | 901 | dlv@1.1.3: 902 | resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} 903 | 904 | eastasianwidth@0.2.0: 905 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 906 | 907 | electron-to-chromium@1.5.143: 908 | resolution: {integrity: sha512-QqklJMOFBMqe46k8iIOwA9l2hz57V2OKMmP5eSWcUvwx+mASAsbU+wkF1pHjn9ZVSBPrsYWr4/W/95y5SwYg2g==} 909 | 910 | emoji-regex@8.0.0: 911 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 912 | 913 | emoji-regex@9.2.2: 914 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 915 | 916 | esbuild@0.21.5: 917 | resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} 918 | engines: {node: '>=12'} 919 | hasBin: true 920 | 921 | escalade@3.2.0: 922 | resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} 923 | engines: {node: '>=6'} 924 | 925 | escape-string-regexp@4.0.0: 926 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 927 | engines: {node: '>=10'} 928 | 929 | eslint-plugin-react-hooks@5.2.0: 930 | resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} 931 | engines: {node: '>=10'} 932 | peerDependencies: 933 | eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 934 | 935 | eslint-plugin-react-refresh@0.4.20: 936 | resolution: {integrity: sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==} 937 | peerDependencies: 938 | eslint: '>=8.40' 939 | 940 | eslint-scope@8.3.0: 941 | resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} 942 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 943 | 944 | eslint-visitor-keys@3.4.3: 945 | resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} 946 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 947 | 948 | eslint-visitor-keys@4.2.0: 949 | resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} 950 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 951 | 952 | eslint@9.25.1: 953 | resolution: {integrity: sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==} 954 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 955 | hasBin: true 956 | peerDependencies: 957 | jiti: '*' 958 | peerDependenciesMeta: 959 | jiti: 960 | optional: true 961 | 962 | espree@10.3.0: 963 | resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} 964 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 965 | 966 | esquery@1.6.0: 967 | resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} 968 | engines: {node: '>=0.10'} 969 | 970 | esrecurse@4.3.0: 971 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 972 | engines: {node: '>=4.0'} 973 | 974 | estraverse@5.3.0: 975 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 976 | engines: {node: '>=4.0'} 977 | 978 | esutils@2.0.3: 979 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 980 | engines: {node: '>=0.10.0'} 981 | 982 | fast-deep-equal@3.1.3: 983 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 984 | 985 | fast-glob@3.3.3: 986 | resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} 987 | engines: {node: '>=8.6.0'} 988 | 989 | fast-json-stable-stringify@2.1.0: 990 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 991 | 992 | fast-levenshtein@2.0.6: 993 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 994 | 995 | fastq@1.19.1: 996 | resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} 997 | 998 | file-entry-cache@8.0.0: 999 | resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} 1000 | engines: {node: '>=16.0.0'} 1001 | 1002 | fill-range@7.1.1: 1003 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 1004 | engines: {node: '>=8'} 1005 | 1006 | find-up@5.0.0: 1007 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} 1008 | engines: {node: '>=10'} 1009 | 1010 | flat-cache@4.0.1: 1011 | resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} 1012 | engines: {node: '>=16'} 1013 | 1014 | flatted@3.3.3: 1015 | resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} 1016 | 1017 | foreground-child@3.3.1: 1018 | resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} 1019 | engines: {node: '>=14'} 1020 | 1021 | fraction.js@4.3.7: 1022 | resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} 1023 | 1024 | fsevents@2.3.3: 1025 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 1026 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 1027 | os: [darwin] 1028 | 1029 | function-bind@1.1.2: 1030 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 1031 | 1032 | gensync@1.0.0-beta.2: 1033 | resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} 1034 | engines: {node: '>=6.9.0'} 1035 | 1036 | get-nonce@1.0.1: 1037 | resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} 1038 | engines: {node: '>=6'} 1039 | 1040 | glob-parent@5.1.2: 1041 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 1042 | engines: {node: '>= 6'} 1043 | 1044 | glob-parent@6.0.2: 1045 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 1046 | engines: {node: '>=10.13.0'} 1047 | 1048 | glob@10.4.5: 1049 | resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} 1050 | hasBin: true 1051 | 1052 | globals@11.12.0: 1053 | resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} 1054 | engines: {node: '>=4'} 1055 | 1056 | globals@14.0.0: 1057 | resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} 1058 | engines: {node: '>=18'} 1059 | 1060 | globals@15.15.0: 1061 | resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} 1062 | engines: {node: '>=18'} 1063 | 1064 | graphemer@1.4.0: 1065 | resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} 1066 | 1067 | has-flag@4.0.0: 1068 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 1069 | engines: {node: '>=8'} 1070 | 1071 | hasown@2.0.2: 1072 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 1073 | engines: {node: '>= 0.4'} 1074 | 1075 | ignore@5.3.2: 1076 | resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} 1077 | engines: {node: '>= 4'} 1078 | 1079 | import-fresh@3.3.1: 1080 | resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} 1081 | engines: {node: '>=6'} 1082 | 1083 | imurmurhash@0.1.4: 1084 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 1085 | engines: {node: '>=0.8.19'} 1086 | 1087 | is-binary-path@2.1.0: 1088 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 1089 | engines: {node: '>=8'} 1090 | 1091 | is-core-module@2.16.1: 1092 | resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} 1093 | engines: {node: '>= 0.4'} 1094 | 1095 | is-extglob@2.1.1: 1096 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 1097 | engines: {node: '>=0.10.0'} 1098 | 1099 | is-fullwidth-code-point@3.0.0: 1100 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 1101 | engines: {node: '>=8'} 1102 | 1103 | is-glob@4.0.3: 1104 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 1105 | engines: {node: '>=0.10.0'} 1106 | 1107 | is-number@7.0.0: 1108 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 1109 | engines: {node: '>=0.12.0'} 1110 | 1111 | isexe@2.0.0: 1112 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 1113 | 1114 | jackspeak@3.4.3: 1115 | resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} 1116 | 1117 | jiti@1.21.7: 1118 | resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} 1119 | hasBin: true 1120 | 1121 | js-tokens@4.0.0: 1122 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 1123 | 1124 | js-yaml@4.1.0: 1125 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 1126 | hasBin: true 1127 | 1128 | jsesc@3.1.0: 1129 | resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} 1130 | engines: {node: '>=6'} 1131 | hasBin: true 1132 | 1133 | json-buffer@3.0.1: 1134 | resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} 1135 | 1136 | json-schema-traverse@0.4.1: 1137 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 1138 | 1139 | json-stable-stringify-without-jsonify@1.0.1: 1140 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 1141 | 1142 | json5@2.2.3: 1143 | resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} 1144 | engines: {node: '>=6'} 1145 | hasBin: true 1146 | 1147 | keyv@4.5.4: 1148 | resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} 1149 | 1150 | levn@0.4.1: 1151 | resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 1152 | engines: {node: '>= 0.8.0'} 1153 | 1154 | lilconfig@3.1.3: 1155 | resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} 1156 | engines: {node: '>=14'} 1157 | 1158 | lines-and-columns@1.2.4: 1159 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 1160 | 1161 | locate-path@6.0.0: 1162 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} 1163 | engines: {node: '>=10'} 1164 | 1165 | lodash.merge@4.6.2: 1166 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 1167 | 1168 | loose-envify@1.4.0: 1169 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} 1170 | hasBin: true 1171 | 1172 | lru-cache@10.4.3: 1173 | resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} 1174 | 1175 | lru-cache@5.1.1: 1176 | resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} 1177 | 1178 | lucide-react@0.344.0: 1179 | resolution: {integrity: sha512-6YyBnn91GB45VuVT96bYCOKElbJzUHqp65vX8cDcu55MQL9T969v4dhGClpljamuI/+KMO9P6w9Acq1CVQGvIQ==} 1180 | peerDependencies: 1181 | react: ^16.5.1 || ^17.0.0 || ^18.0.0 1182 | 1183 | merge2@1.4.1: 1184 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 1185 | engines: {node: '>= 8'} 1186 | 1187 | micromatch@4.0.8: 1188 | resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} 1189 | engines: {node: '>=8.6'} 1190 | 1191 | minimatch@3.1.2: 1192 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 1193 | 1194 | minimatch@9.0.5: 1195 | resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} 1196 | engines: {node: '>=16 || 14 >=14.17'} 1197 | 1198 | minipass@7.1.2: 1199 | resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} 1200 | engines: {node: '>=16 || 14 >=14.17'} 1201 | 1202 | ms@2.1.3: 1203 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 1204 | 1205 | mz@2.7.0: 1206 | resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} 1207 | 1208 | nanoid@3.3.11: 1209 | resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} 1210 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1211 | hasBin: true 1212 | 1213 | natural-compare@1.4.0: 1214 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 1215 | 1216 | node-releases@2.0.19: 1217 | resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} 1218 | 1219 | normalize-path@3.0.0: 1220 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 1221 | engines: {node: '>=0.10.0'} 1222 | 1223 | normalize-range@0.1.2: 1224 | resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} 1225 | engines: {node: '>=0.10.0'} 1226 | 1227 | object-assign@4.1.1: 1228 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 1229 | engines: {node: '>=0.10.0'} 1230 | 1231 | object-hash@3.0.0: 1232 | resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} 1233 | engines: {node: '>= 6'} 1234 | 1235 | optionator@0.9.4: 1236 | resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} 1237 | engines: {node: '>= 0.8.0'} 1238 | 1239 | p-limit@3.1.0: 1240 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 1241 | engines: {node: '>=10'} 1242 | 1243 | p-locate@5.0.0: 1244 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 1245 | engines: {node: '>=10'} 1246 | 1247 | package-json-from-dist@1.0.1: 1248 | resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} 1249 | 1250 | parent-module@1.0.1: 1251 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 1252 | engines: {node: '>=6'} 1253 | 1254 | path-exists@4.0.0: 1255 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 1256 | engines: {node: '>=8'} 1257 | 1258 | path-key@3.1.1: 1259 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1260 | engines: {node: '>=8'} 1261 | 1262 | path-parse@1.0.7: 1263 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 1264 | 1265 | path-scurry@1.11.1: 1266 | resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} 1267 | engines: {node: '>=16 || 14 >=14.18'} 1268 | 1269 | picocolors@1.1.1: 1270 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 1271 | 1272 | picomatch@2.3.1: 1273 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 1274 | engines: {node: '>=8.6'} 1275 | 1276 | pify@2.3.0: 1277 | resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} 1278 | engines: {node: '>=0.10.0'} 1279 | 1280 | pirates@4.0.7: 1281 | resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} 1282 | engines: {node: '>= 6'} 1283 | 1284 | postcss-import@15.1.0: 1285 | resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} 1286 | engines: {node: '>=14.0.0'} 1287 | peerDependencies: 1288 | postcss: ^8.0.0 1289 | 1290 | postcss-js@4.0.1: 1291 | resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} 1292 | engines: {node: ^12 || ^14 || >= 16} 1293 | peerDependencies: 1294 | postcss: ^8.4.21 1295 | 1296 | postcss-load-config@4.0.2: 1297 | resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} 1298 | engines: {node: '>= 14'} 1299 | peerDependencies: 1300 | postcss: '>=8.0.9' 1301 | ts-node: '>=9.0.0' 1302 | peerDependenciesMeta: 1303 | postcss: 1304 | optional: true 1305 | ts-node: 1306 | optional: true 1307 | 1308 | postcss-nested@6.2.0: 1309 | resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} 1310 | engines: {node: '>=12.0'} 1311 | peerDependencies: 1312 | postcss: ^8.2.14 1313 | 1314 | postcss-selector-parser@6.1.2: 1315 | resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} 1316 | engines: {node: '>=4'} 1317 | 1318 | postcss-value-parser@4.2.0: 1319 | resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} 1320 | 1321 | postcss@8.5.3: 1322 | resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} 1323 | engines: {node: ^10 || ^12 || >=14} 1324 | 1325 | prelude-ls@1.2.1: 1326 | resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} 1327 | engines: {node: '>= 0.8.0'} 1328 | 1329 | punycode@2.3.1: 1330 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 1331 | engines: {node: '>=6'} 1332 | 1333 | queue-microtask@1.2.3: 1334 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 1335 | 1336 | react-dom@18.3.1: 1337 | resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} 1338 | peerDependencies: 1339 | react: ^18.3.1 1340 | 1341 | react-refresh@0.17.0: 1342 | resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} 1343 | engines: {node: '>=0.10.0'} 1344 | 1345 | react-remove-scroll-bar@2.3.8: 1346 | resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} 1347 | engines: {node: '>=10'} 1348 | peerDependencies: 1349 | '@types/react': '*' 1350 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 1351 | peerDependenciesMeta: 1352 | '@types/react': 1353 | optional: true 1354 | 1355 | react-remove-scroll@2.6.3: 1356 | resolution: {integrity: sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==} 1357 | engines: {node: '>=10'} 1358 | peerDependencies: 1359 | '@types/react': '*' 1360 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc 1361 | peerDependenciesMeta: 1362 | '@types/react': 1363 | optional: true 1364 | 1365 | react-style-singleton@2.2.3: 1366 | resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} 1367 | engines: {node: '>=10'} 1368 | peerDependencies: 1369 | '@types/react': '*' 1370 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc 1371 | peerDependenciesMeta: 1372 | '@types/react': 1373 | optional: true 1374 | 1375 | react@18.3.1: 1376 | resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} 1377 | engines: {node: '>=0.10.0'} 1378 | 1379 | read-cache@1.0.0: 1380 | resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} 1381 | 1382 | readdirp@3.6.0: 1383 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 1384 | engines: {node: '>=8.10.0'} 1385 | 1386 | resolve-from@4.0.0: 1387 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 1388 | engines: {node: '>=4'} 1389 | 1390 | resolve@1.22.10: 1391 | resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} 1392 | engines: {node: '>= 0.4'} 1393 | hasBin: true 1394 | 1395 | reusify@1.1.0: 1396 | resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} 1397 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 1398 | 1399 | rollup@4.40.1: 1400 | resolution: {integrity: sha512-C5VvvgCCyfyotVITIAv+4efVytl5F7wt+/I2i9q9GZcEXW9BP52YYOXC58igUi+LFZVHukErIIqQSWwv/M3WRw==} 1401 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 1402 | hasBin: true 1403 | 1404 | run-parallel@1.2.0: 1405 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 1406 | 1407 | scheduler@0.23.2: 1408 | resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} 1409 | 1410 | semver@6.3.1: 1411 | resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} 1412 | hasBin: true 1413 | 1414 | semver@7.7.1: 1415 | resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} 1416 | engines: {node: '>=10'} 1417 | hasBin: true 1418 | 1419 | shebang-command@2.0.0: 1420 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1421 | engines: {node: '>=8'} 1422 | 1423 | shebang-regex@3.0.0: 1424 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1425 | engines: {node: '>=8'} 1426 | 1427 | signal-exit@4.1.0: 1428 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 1429 | engines: {node: '>=14'} 1430 | 1431 | source-map-js@1.2.1: 1432 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 1433 | engines: {node: '>=0.10.0'} 1434 | 1435 | string-width@4.2.3: 1436 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1437 | engines: {node: '>=8'} 1438 | 1439 | string-width@5.1.2: 1440 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 1441 | engines: {node: '>=12'} 1442 | 1443 | strip-ansi@6.0.1: 1444 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1445 | engines: {node: '>=8'} 1446 | 1447 | strip-ansi@7.1.0: 1448 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} 1449 | engines: {node: '>=12'} 1450 | 1451 | strip-json-comments@3.1.1: 1452 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 1453 | engines: {node: '>=8'} 1454 | 1455 | sucrase@3.35.0: 1456 | resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} 1457 | engines: {node: '>=16 || 14 >=14.17'} 1458 | hasBin: true 1459 | 1460 | supports-color@7.2.0: 1461 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 1462 | engines: {node: '>=8'} 1463 | 1464 | supports-preserve-symlinks-flag@1.0.0: 1465 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 1466 | engines: {node: '>= 0.4'} 1467 | 1468 | tailwindcss@3.4.17: 1469 | resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} 1470 | engines: {node: '>=14.0.0'} 1471 | hasBin: true 1472 | 1473 | thenify-all@1.6.0: 1474 | resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} 1475 | engines: {node: '>=0.8'} 1476 | 1477 | thenify@3.3.1: 1478 | resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} 1479 | 1480 | to-regex-range@5.0.1: 1481 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1482 | engines: {node: '>=8.0'} 1483 | 1484 | ts-api-utils@2.1.0: 1485 | resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} 1486 | engines: {node: '>=18.12'} 1487 | peerDependencies: 1488 | typescript: '>=4.8.4' 1489 | 1490 | ts-interface-checker@0.1.13: 1491 | resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} 1492 | 1493 | tslib@2.8.1: 1494 | resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 1495 | 1496 | type-check@0.4.0: 1497 | resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 1498 | engines: {node: '>= 0.8.0'} 1499 | 1500 | typescript-eslint@8.31.0: 1501 | resolution: {integrity: sha512-u+93F0sB0An8WEAPtwxVhFby573E8ckdjwUUQUj9QA4v8JAvgtoDdIyYR3XFwFHq2W1KJ1AurwJCO+w+Y1ixyQ==} 1502 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1503 | peerDependencies: 1504 | eslint: ^8.57.0 || ^9.0.0 1505 | typescript: '>=4.8.4 <5.9.0' 1506 | 1507 | typescript@5.8.3: 1508 | resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} 1509 | engines: {node: '>=14.17'} 1510 | hasBin: true 1511 | 1512 | undici-types@6.21.0: 1513 | resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} 1514 | 1515 | update-browserslist-db@1.1.3: 1516 | resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} 1517 | hasBin: true 1518 | peerDependencies: 1519 | browserslist: '>= 4.21.0' 1520 | 1521 | uri-js@4.4.1: 1522 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 1523 | 1524 | use-callback-ref@1.3.3: 1525 | resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} 1526 | engines: {node: '>=10'} 1527 | peerDependencies: 1528 | '@types/react': '*' 1529 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc 1530 | peerDependenciesMeta: 1531 | '@types/react': 1532 | optional: true 1533 | 1534 | use-sidecar@1.1.3: 1535 | resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} 1536 | engines: {node: '>=10'} 1537 | peerDependencies: 1538 | '@types/react': '*' 1539 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc 1540 | peerDependenciesMeta: 1541 | '@types/react': 1542 | optional: true 1543 | 1544 | use-sync-external-store@1.5.0: 1545 | resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} 1546 | peerDependencies: 1547 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 1548 | 1549 | util-deprecate@1.0.2: 1550 | resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 1551 | 1552 | vite@5.4.18: 1553 | resolution: {integrity: sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA==} 1554 | engines: {node: ^18.0.0 || >=20.0.0} 1555 | hasBin: true 1556 | peerDependencies: 1557 | '@types/node': ^18.0.0 || >=20.0.0 1558 | less: '*' 1559 | lightningcss: ^1.21.0 1560 | sass: '*' 1561 | sass-embedded: '*' 1562 | stylus: '*' 1563 | sugarss: '*' 1564 | terser: ^5.4.0 1565 | peerDependenciesMeta: 1566 | '@types/node': 1567 | optional: true 1568 | less: 1569 | optional: true 1570 | lightningcss: 1571 | optional: true 1572 | sass: 1573 | optional: true 1574 | sass-embedded: 1575 | optional: true 1576 | stylus: 1577 | optional: true 1578 | sugarss: 1579 | optional: true 1580 | terser: 1581 | optional: true 1582 | 1583 | which@2.0.2: 1584 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1585 | engines: {node: '>= 8'} 1586 | hasBin: true 1587 | 1588 | word-wrap@1.2.5: 1589 | resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} 1590 | engines: {node: '>=0.10.0'} 1591 | 1592 | wrap-ansi@7.0.0: 1593 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1594 | engines: {node: '>=10'} 1595 | 1596 | wrap-ansi@8.1.0: 1597 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 1598 | engines: {node: '>=12'} 1599 | 1600 | yallist@3.1.1: 1601 | resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} 1602 | 1603 | yaml@2.7.1: 1604 | resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==} 1605 | engines: {node: '>= 14'} 1606 | hasBin: true 1607 | 1608 | yocto-queue@0.1.0: 1609 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 1610 | engines: {node: '>=10'} 1611 | 1612 | zustand@4.5.6: 1613 | resolution: {integrity: sha512-ibr/n1hBzLLj5Y+yUcU7dYw8p6WnIVzdJbnX+1YpaScvZVF2ziugqHs+LAmHw4lWO9c/zRj+K1ncgWDQuthEdQ==} 1614 | engines: {node: '>=12.7.0'} 1615 | peerDependencies: 1616 | '@types/react': '>=16.8' 1617 | immer: '>=9.0.6' 1618 | react: '>=16.8' 1619 | peerDependenciesMeta: 1620 | '@types/react': 1621 | optional: true 1622 | immer: 1623 | optional: true 1624 | react: 1625 | optional: true 1626 | 1627 | snapshots: 1628 | 1629 | '@alloc/quick-lru@5.2.0': {} 1630 | 1631 | '@ampproject/remapping@2.3.0': 1632 | dependencies: 1633 | '@jridgewell/gen-mapping': 0.3.8 1634 | '@jridgewell/trace-mapping': 0.3.25 1635 | 1636 | '@babel/code-frame@7.26.2': 1637 | dependencies: 1638 | '@babel/helper-validator-identifier': 7.25.9 1639 | js-tokens: 4.0.0 1640 | picocolors: 1.1.1 1641 | 1642 | '@babel/compat-data@7.26.8': {} 1643 | 1644 | '@babel/core@7.26.10': 1645 | dependencies: 1646 | '@ampproject/remapping': 2.3.0 1647 | '@babel/code-frame': 7.26.2 1648 | '@babel/generator': 7.27.0 1649 | '@babel/helper-compilation-targets': 7.27.0 1650 | '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10) 1651 | '@babel/helpers': 7.27.0 1652 | '@babel/parser': 7.27.0 1653 | '@babel/template': 7.27.0 1654 | '@babel/traverse': 7.27.0 1655 | '@babel/types': 7.27.0 1656 | convert-source-map: 2.0.0 1657 | debug: 4.4.0 1658 | gensync: 1.0.0-beta.2 1659 | json5: 2.2.3 1660 | semver: 6.3.1 1661 | transitivePeerDependencies: 1662 | - supports-color 1663 | 1664 | '@babel/generator@7.27.0': 1665 | dependencies: 1666 | '@babel/parser': 7.27.0 1667 | '@babel/types': 7.27.0 1668 | '@jridgewell/gen-mapping': 0.3.8 1669 | '@jridgewell/trace-mapping': 0.3.25 1670 | jsesc: 3.1.0 1671 | 1672 | '@babel/helper-compilation-targets@7.27.0': 1673 | dependencies: 1674 | '@babel/compat-data': 7.26.8 1675 | '@babel/helper-validator-option': 7.25.9 1676 | browserslist: 4.24.4 1677 | lru-cache: 5.1.1 1678 | semver: 6.3.1 1679 | 1680 | '@babel/helper-module-imports@7.25.9': 1681 | dependencies: 1682 | '@babel/traverse': 7.27.0 1683 | '@babel/types': 7.27.0 1684 | transitivePeerDependencies: 1685 | - supports-color 1686 | 1687 | '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.10)': 1688 | dependencies: 1689 | '@babel/core': 7.26.10 1690 | '@babel/helper-module-imports': 7.25.9 1691 | '@babel/helper-validator-identifier': 7.25.9 1692 | '@babel/traverse': 7.27.0 1693 | transitivePeerDependencies: 1694 | - supports-color 1695 | 1696 | '@babel/helper-plugin-utils@7.26.5': {} 1697 | 1698 | '@babel/helper-string-parser@7.25.9': {} 1699 | 1700 | '@babel/helper-validator-identifier@7.25.9': {} 1701 | 1702 | '@babel/helper-validator-option@7.25.9': {} 1703 | 1704 | '@babel/helpers@7.27.0': 1705 | dependencies: 1706 | '@babel/template': 7.27.0 1707 | '@babel/types': 7.27.0 1708 | 1709 | '@babel/parser@7.27.0': 1710 | dependencies: 1711 | '@babel/types': 7.27.0 1712 | 1713 | '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.10)': 1714 | dependencies: 1715 | '@babel/core': 7.26.10 1716 | '@babel/helper-plugin-utils': 7.26.5 1717 | 1718 | '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.10)': 1719 | dependencies: 1720 | '@babel/core': 7.26.10 1721 | '@babel/helper-plugin-utils': 7.26.5 1722 | 1723 | '@babel/template@7.27.0': 1724 | dependencies: 1725 | '@babel/code-frame': 7.26.2 1726 | '@babel/parser': 7.27.0 1727 | '@babel/types': 7.27.0 1728 | 1729 | '@babel/traverse@7.27.0': 1730 | dependencies: 1731 | '@babel/code-frame': 7.26.2 1732 | '@babel/generator': 7.27.0 1733 | '@babel/parser': 7.27.0 1734 | '@babel/template': 7.27.0 1735 | '@babel/types': 7.27.0 1736 | debug: 4.4.0 1737 | globals: 11.12.0 1738 | transitivePeerDependencies: 1739 | - supports-color 1740 | 1741 | '@babel/types@7.27.0': 1742 | dependencies: 1743 | '@babel/helper-string-parser': 7.25.9 1744 | '@babel/helper-validator-identifier': 7.25.9 1745 | 1746 | '@esbuild/aix-ppc64@0.21.5': 1747 | optional: true 1748 | 1749 | '@esbuild/android-arm64@0.21.5': 1750 | optional: true 1751 | 1752 | '@esbuild/android-arm@0.21.5': 1753 | optional: true 1754 | 1755 | '@esbuild/android-x64@0.21.5': 1756 | optional: true 1757 | 1758 | '@esbuild/darwin-arm64@0.21.5': 1759 | optional: true 1760 | 1761 | '@esbuild/darwin-x64@0.21.5': 1762 | optional: true 1763 | 1764 | '@esbuild/freebsd-arm64@0.21.5': 1765 | optional: true 1766 | 1767 | '@esbuild/freebsd-x64@0.21.5': 1768 | optional: true 1769 | 1770 | '@esbuild/linux-arm64@0.21.5': 1771 | optional: true 1772 | 1773 | '@esbuild/linux-arm@0.21.5': 1774 | optional: true 1775 | 1776 | '@esbuild/linux-ia32@0.21.5': 1777 | optional: true 1778 | 1779 | '@esbuild/linux-loong64@0.21.5': 1780 | optional: true 1781 | 1782 | '@esbuild/linux-mips64el@0.21.5': 1783 | optional: true 1784 | 1785 | '@esbuild/linux-ppc64@0.21.5': 1786 | optional: true 1787 | 1788 | '@esbuild/linux-riscv64@0.21.5': 1789 | optional: true 1790 | 1791 | '@esbuild/linux-s390x@0.21.5': 1792 | optional: true 1793 | 1794 | '@esbuild/linux-x64@0.21.5': 1795 | optional: true 1796 | 1797 | '@esbuild/netbsd-x64@0.21.5': 1798 | optional: true 1799 | 1800 | '@esbuild/openbsd-x64@0.21.5': 1801 | optional: true 1802 | 1803 | '@esbuild/sunos-x64@0.21.5': 1804 | optional: true 1805 | 1806 | '@esbuild/win32-arm64@0.21.5': 1807 | optional: true 1808 | 1809 | '@esbuild/win32-ia32@0.21.5': 1810 | optional: true 1811 | 1812 | '@esbuild/win32-x64@0.21.5': 1813 | optional: true 1814 | 1815 | '@eslint-community/eslint-utils@4.6.1(eslint@9.25.1(jiti@1.21.7))': 1816 | dependencies: 1817 | eslint: 9.25.1(jiti@1.21.7) 1818 | eslint-visitor-keys: 3.4.3 1819 | 1820 | '@eslint-community/regexpp@4.12.1': {} 1821 | 1822 | '@eslint/config-array@0.20.0': 1823 | dependencies: 1824 | '@eslint/object-schema': 2.1.6 1825 | debug: 4.4.0 1826 | minimatch: 3.1.2 1827 | transitivePeerDependencies: 1828 | - supports-color 1829 | 1830 | '@eslint/config-helpers@0.2.1': {} 1831 | 1832 | '@eslint/core@0.13.0': 1833 | dependencies: 1834 | '@types/json-schema': 7.0.15 1835 | 1836 | '@eslint/eslintrc@3.3.1': 1837 | dependencies: 1838 | ajv: 6.12.6 1839 | debug: 4.4.0 1840 | espree: 10.3.0 1841 | globals: 14.0.0 1842 | ignore: 5.3.2 1843 | import-fresh: 3.3.1 1844 | js-yaml: 4.1.0 1845 | minimatch: 3.1.2 1846 | strip-json-comments: 3.1.1 1847 | transitivePeerDependencies: 1848 | - supports-color 1849 | 1850 | '@eslint/js@9.25.1': {} 1851 | 1852 | '@eslint/object-schema@2.1.6': {} 1853 | 1854 | '@eslint/plugin-kit@0.2.8': 1855 | dependencies: 1856 | '@eslint/core': 0.13.0 1857 | levn: 0.4.1 1858 | 1859 | '@humanfs/core@0.19.1': {} 1860 | 1861 | '@humanfs/node@0.16.6': 1862 | dependencies: 1863 | '@humanfs/core': 0.19.1 1864 | '@humanwhocodes/retry': 0.3.1 1865 | 1866 | '@humanwhocodes/module-importer@1.0.1': {} 1867 | 1868 | '@humanwhocodes/retry@0.3.1': {} 1869 | 1870 | '@humanwhocodes/retry@0.4.2': {} 1871 | 1872 | '@isaacs/cliui@8.0.2': 1873 | dependencies: 1874 | string-width: 5.1.2 1875 | string-width-cjs: string-width@4.2.3 1876 | strip-ansi: 7.1.0 1877 | strip-ansi-cjs: strip-ansi@6.0.1 1878 | wrap-ansi: 8.1.0 1879 | wrap-ansi-cjs: wrap-ansi@7.0.0 1880 | 1881 | '@jridgewell/gen-mapping@0.3.8': 1882 | dependencies: 1883 | '@jridgewell/set-array': 1.2.1 1884 | '@jridgewell/sourcemap-codec': 1.5.0 1885 | '@jridgewell/trace-mapping': 0.3.25 1886 | 1887 | '@jridgewell/resolve-uri@3.1.2': {} 1888 | 1889 | '@jridgewell/set-array@1.2.1': {} 1890 | 1891 | '@jridgewell/sourcemap-codec@1.5.0': {} 1892 | 1893 | '@jridgewell/trace-mapping@0.3.25': 1894 | dependencies: 1895 | '@jridgewell/resolve-uri': 3.1.2 1896 | '@jridgewell/sourcemap-codec': 1.5.0 1897 | 1898 | '@nodelib/fs.scandir@2.1.5': 1899 | dependencies: 1900 | '@nodelib/fs.stat': 2.0.5 1901 | run-parallel: 1.2.0 1902 | 1903 | '@nodelib/fs.stat@2.0.5': {} 1904 | 1905 | '@nodelib/fs.walk@1.2.8': 1906 | dependencies: 1907 | '@nodelib/fs.scandir': 2.1.5 1908 | fastq: 1.19.1 1909 | 1910 | '@pkgjs/parseargs@0.11.0': 1911 | optional: true 1912 | 1913 | '@radix-ui/primitive@1.1.2': {} 1914 | 1915 | '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.20)(react@18.3.1)': 1916 | dependencies: 1917 | react: 18.3.1 1918 | optionalDependencies: 1919 | '@types/react': 18.3.20 1920 | 1921 | '@radix-ui/react-context@1.1.2(@types/react@18.3.20)(react@18.3.1)': 1922 | dependencies: 1923 | react: 18.3.1 1924 | optionalDependencies: 1925 | '@types/react': 18.3.20 1926 | 1927 | '@radix-ui/react-dialog@1.1.11(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': 1928 | dependencies: 1929 | '@radix-ui/primitive': 1.1.2 1930 | '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.20)(react@18.3.1) 1931 | '@radix-ui/react-context': 1.1.2(@types/react@18.3.20)(react@18.3.1) 1932 | '@radix-ui/react-dismissable-layer': 1.1.7(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 1933 | '@radix-ui/react-focus-guards': 1.1.2(@types/react@18.3.20)(react@18.3.1) 1934 | '@radix-ui/react-focus-scope': 1.1.4(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 1935 | '@radix-ui/react-id': 1.1.1(@types/react@18.3.20)(react@18.3.1) 1936 | '@radix-ui/react-portal': 1.1.6(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 1937 | '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 1938 | '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 1939 | '@radix-ui/react-slot': 1.2.0(@types/react@18.3.20)(react@18.3.1) 1940 | '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.20)(react@18.3.1) 1941 | aria-hidden: 1.2.4 1942 | react: 18.3.1 1943 | react-dom: 18.3.1(react@18.3.1) 1944 | react-remove-scroll: 2.6.3(@types/react@18.3.20)(react@18.3.1) 1945 | optionalDependencies: 1946 | '@types/react': 18.3.20 1947 | '@types/react-dom': 18.3.6(@types/react@18.3.20) 1948 | 1949 | '@radix-ui/react-dismissable-layer@1.1.7(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': 1950 | dependencies: 1951 | '@radix-ui/primitive': 1.1.2 1952 | '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.20)(react@18.3.1) 1953 | '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 1954 | '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.20)(react@18.3.1) 1955 | '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.20)(react@18.3.1) 1956 | react: 18.3.1 1957 | react-dom: 18.3.1(react@18.3.1) 1958 | optionalDependencies: 1959 | '@types/react': 18.3.20 1960 | '@types/react-dom': 18.3.6(@types/react@18.3.20) 1961 | 1962 | '@radix-ui/react-focus-guards@1.1.2(@types/react@18.3.20)(react@18.3.1)': 1963 | dependencies: 1964 | react: 18.3.1 1965 | optionalDependencies: 1966 | '@types/react': 18.3.20 1967 | 1968 | '@radix-ui/react-focus-scope@1.1.4(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': 1969 | dependencies: 1970 | '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.20)(react@18.3.1) 1971 | '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 1972 | '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.20)(react@18.3.1) 1973 | react: 18.3.1 1974 | react-dom: 18.3.1(react@18.3.1) 1975 | optionalDependencies: 1976 | '@types/react': 18.3.20 1977 | '@types/react-dom': 18.3.6(@types/react@18.3.20) 1978 | 1979 | '@radix-ui/react-id@1.1.1(@types/react@18.3.20)(react@18.3.1)': 1980 | dependencies: 1981 | '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.20)(react@18.3.1) 1982 | react: 18.3.1 1983 | optionalDependencies: 1984 | '@types/react': 18.3.20 1985 | 1986 | '@radix-ui/react-portal@1.1.6(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': 1987 | dependencies: 1988 | '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 1989 | '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.20)(react@18.3.1) 1990 | react: 18.3.1 1991 | react-dom: 18.3.1(react@18.3.1) 1992 | optionalDependencies: 1993 | '@types/react': 18.3.20 1994 | '@types/react-dom': 18.3.6(@types/react@18.3.20) 1995 | 1996 | '@radix-ui/react-presence@1.1.4(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': 1997 | dependencies: 1998 | '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.20)(react@18.3.1) 1999 | '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.20)(react@18.3.1) 2000 | react: 18.3.1 2001 | react-dom: 18.3.1(react@18.3.1) 2002 | optionalDependencies: 2003 | '@types/react': 18.3.20 2004 | '@types/react-dom': 18.3.6(@types/react@18.3.20) 2005 | 2006 | '@radix-ui/react-primitive@2.1.0(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': 2007 | dependencies: 2008 | '@radix-ui/react-slot': 1.2.0(@types/react@18.3.20)(react@18.3.1) 2009 | react: 18.3.1 2010 | react-dom: 18.3.1(react@18.3.1) 2011 | optionalDependencies: 2012 | '@types/react': 18.3.20 2013 | '@types/react-dom': 18.3.6(@types/react@18.3.20) 2014 | 2015 | '@radix-ui/react-slot@1.2.0(@types/react@18.3.20)(react@18.3.1)': 2016 | dependencies: 2017 | '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.20)(react@18.3.1) 2018 | react: 18.3.1 2019 | optionalDependencies: 2020 | '@types/react': 18.3.20 2021 | 2022 | '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.20)(react@18.3.1)': 2023 | dependencies: 2024 | react: 18.3.1 2025 | optionalDependencies: 2026 | '@types/react': 18.3.20 2027 | 2028 | '@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.3.20)(react@18.3.1)': 2029 | dependencies: 2030 | '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.3.20)(react@18.3.1) 2031 | '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.20)(react@18.3.1) 2032 | react: 18.3.1 2033 | optionalDependencies: 2034 | '@types/react': 18.3.20 2035 | 2036 | '@radix-ui/react-use-effect-event@0.0.2(@types/react@18.3.20)(react@18.3.1)': 2037 | dependencies: 2038 | '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.20)(react@18.3.1) 2039 | react: 18.3.1 2040 | optionalDependencies: 2041 | '@types/react': 18.3.20 2042 | 2043 | '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@18.3.20)(react@18.3.1)': 2044 | dependencies: 2045 | '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.20)(react@18.3.1) 2046 | react: 18.3.1 2047 | optionalDependencies: 2048 | '@types/react': 18.3.20 2049 | 2050 | '@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.3.20)(react@18.3.1)': 2051 | dependencies: 2052 | react: 18.3.1 2053 | optionalDependencies: 2054 | '@types/react': 18.3.20 2055 | 2056 | '@rollup/rollup-android-arm-eabi@4.40.1': 2057 | optional: true 2058 | 2059 | '@rollup/rollup-android-arm64@4.40.1': 2060 | optional: true 2061 | 2062 | '@rollup/rollup-darwin-arm64@4.40.1': 2063 | optional: true 2064 | 2065 | '@rollup/rollup-darwin-x64@4.40.1': 2066 | optional: true 2067 | 2068 | '@rollup/rollup-freebsd-arm64@4.40.1': 2069 | optional: true 2070 | 2071 | '@rollup/rollup-freebsd-x64@4.40.1': 2072 | optional: true 2073 | 2074 | '@rollup/rollup-linux-arm-gnueabihf@4.40.1': 2075 | optional: true 2076 | 2077 | '@rollup/rollup-linux-arm-musleabihf@4.40.1': 2078 | optional: true 2079 | 2080 | '@rollup/rollup-linux-arm64-gnu@4.40.1': 2081 | optional: true 2082 | 2083 | '@rollup/rollup-linux-arm64-musl@4.40.1': 2084 | optional: true 2085 | 2086 | '@rollup/rollup-linux-loongarch64-gnu@4.40.1': 2087 | optional: true 2088 | 2089 | '@rollup/rollup-linux-powerpc64le-gnu@4.40.1': 2090 | optional: true 2091 | 2092 | '@rollup/rollup-linux-riscv64-gnu@4.40.1': 2093 | optional: true 2094 | 2095 | '@rollup/rollup-linux-riscv64-musl@4.40.1': 2096 | optional: true 2097 | 2098 | '@rollup/rollup-linux-s390x-gnu@4.40.1': 2099 | optional: true 2100 | 2101 | '@rollup/rollup-linux-x64-gnu@4.40.1': 2102 | optional: true 2103 | 2104 | '@rollup/rollup-linux-x64-musl@4.40.1': 2105 | optional: true 2106 | 2107 | '@rollup/rollup-win32-arm64-msvc@4.40.1': 2108 | optional: true 2109 | 2110 | '@rollup/rollup-win32-ia32-msvc@4.40.1': 2111 | optional: true 2112 | 2113 | '@rollup/rollup-win32-x64-msvc@4.40.1': 2114 | optional: true 2115 | 2116 | '@types/babel__core@7.20.5': 2117 | dependencies: 2118 | '@babel/parser': 7.27.0 2119 | '@babel/types': 7.27.0 2120 | '@types/babel__generator': 7.27.0 2121 | '@types/babel__template': 7.4.4 2122 | '@types/babel__traverse': 7.20.7 2123 | 2124 | '@types/babel__generator@7.27.0': 2125 | dependencies: 2126 | '@babel/types': 7.27.0 2127 | 2128 | '@types/babel__template@7.4.4': 2129 | dependencies: 2130 | '@babel/parser': 7.27.0 2131 | '@babel/types': 7.27.0 2132 | 2133 | '@types/babel__traverse@7.20.7': 2134 | dependencies: 2135 | '@babel/types': 7.27.0 2136 | 2137 | '@types/estree@1.0.7': {} 2138 | 2139 | '@types/json-schema@7.0.15': {} 2140 | 2141 | '@types/node@22.15.3': 2142 | dependencies: 2143 | undici-types: 6.21.0 2144 | optional: true 2145 | 2146 | '@types/prop-types@15.7.14': {} 2147 | 2148 | '@types/react-dom@18.3.6(@types/react@18.3.20)': 2149 | dependencies: 2150 | '@types/react': 18.3.20 2151 | 2152 | '@types/react@18.3.20': 2153 | dependencies: 2154 | '@types/prop-types': 15.7.14 2155 | csstype: 3.1.3 2156 | 2157 | '@typescript-eslint/eslint-plugin@8.31.0(@typescript-eslint/parser@8.31.0(eslint@9.25.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.25.1(jiti@1.21.7))(typescript@5.8.3)': 2158 | dependencies: 2159 | '@eslint-community/regexpp': 4.12.1 2160 | '@typescript-eslint/parser': 8.31.0(eslint@9.25.1(jiti@1.21.7))(typescript@5.8.3) 2161 | '@typescript-eslint/scope-manager': 8.31.0 2162 | '@typescript-eslint/type-utils': 8.31.0(eslint@9.25.1(jiti@1.21.7))(typescript@5.8.3) 2163 | '@typescript-eslint/utils': 8.31.0(eslint@9.25.1(jiti@1.21.7))(typescript@5.8.3) 2164 | '@typescript-eslint/visitor-keys': 8.31.0 2165 | eslint: 9.25.1(jiti@1.21.7) 2166 | graphemer: 1.4.0 2167 | ignore: 5.3.2 2168 | natural-compare: 1.4.0 2169 | ts-api-utils: 2.1.0(typescript@5.8.3) 2170 | typescript: 5.8.3 2171 | transitivePeerDependencies: 2172 | - supports-color 2173 | 2174 | '@typescript-eslint/parser@8.31.0(eslint@9.25.1(jiti@1.21.7))(typescript@5.8.3)': 2175 | dependencies: 2176 | '@typescript-eslint/scope-manager': 8.31.0 2177 | '@typescript-eslint/types': 8.31.0 2178 | '@typescript-eslint/typescript-estree': 8.31.0(typescript@5.8.3) 2179 | '@typescript-eslint/visitor-keys': 8.31.0 2180 | debug: 4.4.0 2181 | eslint: 9.25.1(jiti@1.21.7) 2182 | typescript: 5.8.3 2183 | transitivePeerDependencies: 2184 | - supports-color 2185 | 2186 | '@typescript-eslint/scope-manager@8.31.0': 2187 | dependencies: 2188 | '@typescript-eslint/types': 8.31.0 2189 | '@typescript-eslint/visitor-keys': 8.31.0 2190 | 2191 | '@typescript-eslint/type-utils@8.31.0(eslint@9.25.1(jiti@1.21.7))(typescript@5.8.3)': 2192 | dependencies: 2193 | '@typescript-eslint/typescript-estree': 8.31.0(typescript@5.8.3) 2194 | '@typescript-eslint/utils': 8.31.0(eslint@9.25.1(jiti@1.21.7))(typescript@5.8.3) 2195 | debug: 4.4.0 2196 | eslint: 9.25.1(jiti@1.21.7) 2197 | ts-api-utils: 2.1.0(typescript@5.8.3) 2198 | typescript: 5.8.3 2199 | transitivePeerDependencies: 2200 | - supports-color 2201 | 2202 | '@typescript-eslint/types@8.31.0': {} 2203 | 2204 | '@typescript-eslint/typescript-estree@8.31.0(typescript@5.8.3)': 2205 | dependencies: 2206 | '@typescript-eslint/types': 8.31.0 2207 | '@typescript-eslint/visitor-keys': 8.31.0 2208 | debug: 4.4.0 2209 | fast-glob: 3.3.3 2210 | is-glob: 4.0.3 2211 | minimatch: 9.0.5 2212 | semver: 7.7.1 2213 | ts-api-utils: 2.1.0(typescript@5.8.3) 2214 | typescript: 5.8.3 2215 | transitivePeerDependencies: 2216 | - supports-color 2217 | 2218 | '@typescript-eslint/utils@8.31.0(eslint@9.25.1(jiti@1.21.7))(typescript@5.8.3)': 2219 | dependencies: 2220 | '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.1(jiti@1.21.7)) 2221 | '@typescript-eslint/scope-manager': 8.31.0 2222 | '@typescript-eslint/types': 8.31.0 2223 | '@typescript-eslint/typescript-estree': 8.31.0(typescript@5.8.3) 2224 | eslint: 9.25.1(jiti@1.21.7) 2225 | typescript: 5.8.3 2226 | transitivePeerDependencies: 2227 | - supports-color 2228 | 2229 | '@typescript-eslint/visitor-keys@8.31.0': 2230 | dependencies: 2231 | '@typescript-eslint/types': 8.31.0 2232 | eslint-visitor-keys: 4.2.0 2233 | 2234 | '@vitejs/plugin-react@4.4.1(vite@5.4.18(@types/node@22.15.3))': 2235 | dependencies: 2236 | '@babel/core': 7.26.10 2237 | '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.10) 2238 | '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.10) 2239 | '@types/babel__core': 7.20.5 2240 | react-refresh: 0.17.0 2241 | vite: 5.4.18(@types/node@22.15.3) 2242 | transitivePeerDependencies: 2243 | - supports-color 2244 | 2245 | acorn-jsx@5.3.2(acorn@8.14.1): 2246 | dependencies: 2247 | acorn: 8.14.1 2248 | 2249 | acorn@8.14.1: {} 2250 | 2251 | ajv@6.12.6: 2252 | dependencies: 2253 | fast-deep-equal: 3.1.3 2254 | fast-json-stable-stringify: 2.1.0 2255 | json-schema-traverse: 0.4.1 2256 | uri-js: 4.4.1 2257 | 2258 | ansi-regex@5.0.1: {} 2259 | 2260 | ansi-regex@6.1.0: {} 2261 | 2262 | ansi-styles@4.3.0: 2263 | dependencies: 2264 | color-convert: 2.0.1 2265 | 2266 | ansi-styles@6.2.1: {} 2267 | 2268 | any-promise@1.3.0: {} 2269 | 2270 | anymatch@3.1.3: 2271 | dependencies: 2272 | normalize-path: 3.0.0 2273 | picomatch: 2.3.1 2274 | 2275 | arg@5.0.2: {} 2276 | 2277 | argparse@2.0.1: {} 2278 | 2279 | aria-hidden@1.2.4: 2280 | dependencies: 2281 | tslib: 2.8.1 2282 | 2283 | autoprefixer@10.4.21(postcss@8.5.3): 2284 | dependencies: 2285 | browserslist: 4.24.4 2286 | caniuse-lite: 1.0.30001715 2287 | fraction.js: 4.3.7 2288 | normalize-range: 0.1.2 2289 | picocolors: 1.1.1 2290 | postcss: 8.5.3 2291 | postcss-value-parser: 4.2.0 2292 | 2293 | balanced-match@1.0.2: {} 2294 | 2295 | binary-extensions@2.3.0: {} 2296 | 2297 | brace-expansion@1.1.11: 2298 | dependencies: 2299 | balanced-match: 1.0.2 2300 | concat-map: 0.0.1 2301 | 2302 | brace-expansion@2.0.1: 2303 | dependencies: 2304 | balanced-match: 1.0.2 2305 | 2306 | braces@3.0.3: 2307 | dependencies: 2308 | fill-range: 7.1.1 2309 | 2310 | browserslist@4.24.4: 2311 | dependencies: 2312 | caniuse-lite: 1.0.30001715 2313 | electron-to-chromium: 1.5.143 2314 | node-releases: 2.0.19 2315 | update-browserslist-db: 1.1.3(browserslist@4.24.4) 2316 | 2317 | callsites@3.1.0: {} 2318 | 2319 | camelcase-css@2.0.1: {} 2320 | 2321 | caniuse-lite@1.0.30001715: {} 2322 | 2323 | chalk@4.1.2: 2324 | dependencies: 2325 | ansi-styles: 4.3.0 2326 | supports-color: 7.2.0 2327 | 2328 | chokidar@3.6.0: 2329 | dependencies: 2330 | anymatch: 3.1.3 2331 | braces: 3.0.3 2332 | glob-parent: 5.1.2 2333 | is-binary-path: 2.1.0 2334 | is-glob: 4.0.3 2335 | normalize-path: 3.0.0 2336 | readdirp: 3.6.0 2337 | optionalDependencies: 2338 | fsevents: 2.3.3 2339 | 2340 | color-convert@2.0.1: 2341 | dependencies: 2342 | color-name: 1.1.4 2343 | 2344 | color-name@1.1.4: {} 2345 | 2346 | commander@4.1.1: {} 2347 | 2348 | concat-map@0.0.1: {} 2349 | 2350 | convert-source-map@2.0.0: {} 2351 | 2352 | cross-spawn@7.0.6: 2353 | dependencies: 2354 | path-key: 3.1.1 2355 | shebang-command: 2.0.0 2356 | which: 2.0.2 2357 | 2358 | cssesc@3.0.0: {} 2359 | 2360 | csstype@3.1.3: {} 2361 | 2362 | debug@4.4.0: 2363 | dependencies: 2364 | ms: 2.1.3 2365 | 2366 | deep-is@0.1.4: {} 2367 | 2368 | detect-node-es@1.1.0: {} 2369 | 2370 | didyoumean@1.2.2: {} 2371 | 2372 | dlv@1.1.3: {} 2373 | 2374 | eastasianwidth@0.2.0: {} 2375 | 2376 | electron-to-chromium@1.5.143: {} 2377 | 2378 | emoji-regex@8.0.0: {} 2379 | 2380 | emoji-regex@9.2.2: {} 2381 | 2382 | esbuild@0.21.5: 2383 | optionalDependencies: 2384 | '@esbuild/aix-ppc64': 0.21.5 2385 | '@esbuild/android-arm': 0.21.5 2386 | '@esbuild/android-arm64': 0.21.5 2387 | '@esbuild/android-x64': 0.21.5 2388 | '@esbuild/darwin-arm64': 0.21.5 2389 | '@esbuild/darwin-x64': 0.21.5 2390 | '@esbuild/freebsd-arm64': 0.21.5 2391 | '@esbuild/freebsd-x64': 0.21.5 2392 | '@esbuild/linux-arm': 0.21.5 2393 | '@esbuild/linux-arm64': 0.21.5 2394 | '@esbuild/linux-ia32': 0.21.5 2395 | '@esbuild/linux-loong64': 0.21.5 2396 | '@esbuild/linux-mips64el': 0.21.5 2397 | '@esbuild/linux-ppc64': 0.21.5 2398 | '@esbuild/linux-riscv64': 0.21.5 2399 | '@esbuild/linux-s390x': 0.21.5 2400 | '@esbuild/linux-x64': 0.21.5 2401 | '@esbuild/netbsd-x64': 0.21.5 2402 | '@esbuild/openbsd-x64': 0.21.5 2403 | '@esbuild/sunos-x64': 0.21.5 2404 | '@esbuild/win32-arm64': 0.21.5 2405 | '@esbuild/win32-ia32': 0.21.5 2406 | '@esbuild/win32-x64': 0.21.5 2407 | 2408 | escalade@3.2.0: {} 2409 | 2410 | escape-string-regexp@4.0.0: {} 2411 | 2412 | eslint-plugin-react-hooks@5.2.0(eslint@9.25.1(jiti@1.21.7)): 2413 | dependencies: 2414 | eslint: 9.25.1(jiti@1.21.7) 2415 | 2416 | eslint-plugin-react-refresh@0.4.20(eslint@9.25.1(jiti@1.21.7)): 2417 | dependencies: 2418 | eslint: 9.25.1(jiti@1.21.7) 2419 | 2420 | eslint-scope@8.3.0: 2421 | dependencies: 2422 | esrecurse: 4.3.0 2423 | estraverse: 5.3.0 2424 | 2425 | eslint-visitor-keys@3.4.3: {} 2426 | 2427 | eslint-visitor-keys@4.2.0: {} 2428 | 2429 | eslint@9.25.1(jiti@1.21.7): 2430 | dependencies: 2431 | '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.1(jiti@1.21.7)) 2432 | '@eslint-community/regexpp': 4.12.1 2433 | '@eslint/config-array': 0.20.0 2434 | '@eslint/config-helpers': 0.2.1 2435 | '@eslint/core': 0.13.0 2436 | '@eslint/eslintrc': 3.3.1 2437 | '@eslint/js': 9.25.1 2438 | '@eslint/plugin-kit': 0.2.8 2439 | '@humanfs/node': 0.16.6 2440 | '@humanwhocodes/module-importer': 1.0.1 2441 | '@humanwhocodes/retry': 0.4.2 2442 | '@types/estree': 1.0.7 2443 | '@types/json-schema': 7.0.15 2444 | ajv: 6.12.6 2445 | chalk: 4.1.2 2446 | cross-spawn: 7.0.6 2447 | debug: 4.4.0 2448 | escape-string-regexp: 4.0.0 2449 | eslint-scope: 8.3.0 2450 | eslint-visitor-keys: 4.2.0 2451 | espree: 10.3.0 2452 | esquery: 1.6.0 2453 | esutils: 2.0.3 2454 | fast-deep-equal: 3.1.3 2455 | file-entry-cache: 8.0.0 2456 | find-up: 5.0.0 2457 | glob-parent: 6.0.2 2458 | ignore: 5.3.2 2459 | imurmurhash: 0.1.4 2460 | is-glob: 4.0.3 2461 | json-stable-stringify-without-jsonify: 1.0.1 2462 | lodash.merge: 4.6.2 2463 | minimatch: 3.1.2 2464 | natural-compare: 1.4.0 2465 | optionator: 0.9.4 2466 | optionalDependencies: 2467 | jiti: 1.21.7 2468 | transitivePeerDependencies: 2469 | - supports-color 2470 | 2471 | espree@10.3.0: 2472 | dependencies: 2473 | acorn: 8.14.1 2474 | acorn-jsx: 5.3.2(acorn@8.14.1) 2475 | eslint-visitor-keys: 4.2.0 2476 | 2477 | esquery@1.6.0: 2478 | dependencies: 2479 | estraverse: 5.3.0 2480 | 2481 | esrecurse@4.3.0: 2482 | dependencies: 2483 | estraverse: 5.3.0 2484 | 2485 | estraverse@5.3.0: {} 2486 | 2487 | esutils@2.0.3: {} 2488 | 2489 | fast-deep-equal@3.1.3: {} 2490 | 2491 | fast-glob@3.3.3: 2492 | dependencies: 2493 | '@nodelib/fs.stat': 2.0.5 2494 | '@nodelib/fs.walk': 1.2.8 2495 | glob-parent: 5.1.2 2496 | merge2: 1.4.1 2497 | micromatch: 4.0.8 2498 | 2499 | fast-json-stable-stringify@2.1.0: {} 2500 | 2501 | fast-levenshtein@2.0.6: {} 2502 | 2503 | fastq@1.19.1: 2504 | dependencies: 2505 | reusify: 1.1.0 2506 | 2507 | file-entry-cache@8.0.0: 2508 | dependencies: 2509 | flat-cache: 4.0.1 2510 | 2511 | fill-range@7.1.1: 2512 | dependencies: 2513 | to-regex-range: 5.0.1 2514 | 2515 | find-up@5.0.0: 2516 | dependencies: 2517 | locate-path: 6.0.0 2518 | path-exists: 4.0.0 2519 | 2520 | flat-cache@4.0.1: 2521 | dependencies: 2522 | flatted: 3.3.3 2523 | keyv: 4.5.4 2524 | 2525 | flatted@3.3.3: {} 2526 | 2527 | foreground-child@3.3.1: 2528 | dependencies: 2529 | cross-spawn: 7.0.6 2530 | signal-exit: 4.1.0 2531 | 2532 | fraction.js@4.3.7: {} 2533 | 2534 | fsevents@2.3.3: 2535 | optional: true 2536 | 2537 | function-bind@1.1.2: {} 2538 | 2539 | gensync@1.0.0-beta.2: {} 2540 | 2541 | get-nonce@1.0.1: {} 2542 | 2543 | glob-parent@5.1.2: 2544 | dependencies: 2545 | is-glob: 4.0.3 2546 | 2547 | glob-parent@6.0.2: 2548 | dependencies: 2549 | is-glob: 4.0.3 2550 | 2551 | glob@10.4.5: 2552 | dependencies: 2553 | foreground-child: 3.3.1 2554 | jackspeak: 3.4.3 2555 | minimatch: 9.0.5 2556 | minipass: 7.1.2 2557 | package-json-from-dist: 1.0.1 2558 | path-scurry: 1.11.1 2559 | 2560 | globals@11.12.0: {} 2561 | 2562 | globals@14.0.0: {} 2563 | 2564 | globals@15.15.0: {} 2565 | 2566 | graphemer@1.4.0: {} 2567 | 2568 | has-flag@4.0.0: {} 2569 | 2570 | hasown@2.0.2: 2571 | dependencies: 2572 | function-bind: 1.1.2 2573 | 2574 | ignore@5.3.2: {} 2575 | 2576 | import-fresh@3.3.1: 2577 | dependencies: 2578 | parent-module: 1.0.1 2579 | resolve-from: 4.0.0 2580 | 2581 | imurmurhash@0.1.4: {} 2582 | 2583 | is-binary-path@2.1.0: 2584 | dependencies: 2585 | binary-extensions: 2.3.0 2586 | 2587 | is-core-module@2.16.1: 2588 | dependencies: 2589 | hasown: 2.0.2 2590 | 2591 | is-extglob@2.1.1: {} 2592 | 2593 | is-fullwidth-code-point@3.0.0: {} 2594 | 2595 | is-glob@4.0.3: 2596 | dependencies: 2597 | is-extglob: 2.1.1 2598 | 2599 | is-number@7.0.0: {} 2600 | 2601 | isexe@2.0.0: {} 2602 | 2603 | jackspeak@3.4.3: 2604 | dependencies: 2605 | '@isaacs/cliui': 8.0.2 2606 | optionalDependencies: 2607 | '@pkgjs/parseargs': 0.11.0 2608 | 2609 | jiti@1.21.7: {} 2610 | 2611 | js-tokens@4.0.0: {} 2612 | 2613 | js-yaml@4.1.0: 2614 | dependencies: 2615 | argparse: 2.0.1 2616 | 2617 | jsesc@3.1.0: {} 2618 | 2619 | json-buffer@3.0.1: {} 2620 | 2621 | json-schema-traverse@0.4.1: {} 2622 | 2623 | json-stable-stringify-without-jsonify@1.0.1: {} 2624 | 2625 | json5@2.2.3: {} 2626 | 2627 | keyv@4.5.4: 2628 | dependencies: 2629 | json-buffer: 3.0.1 2630 | 2631 | levn@0.4.1: 2632 | dependencies: 2633 | prelude-ls: 1.2.1 2634 | type-check: 0.4.0 2635 | 2636 | lilconfig@3.1.3: {} 2637 | 2638 | lines-and-columns@1.2.4: {} 2639 | 2640 | locate-path@6.0.0: 2641 | dependencies: 2642 | p-locate: 5.0.0 2643 | 2644 | lodash.merge@4.6.2: {} 2645 | 2646 | loose-envify@1.4.0: 2647 | dependencies: 2648 | js-tokens: 4.0.0 2649 | 2650 | lru-cache@10.4.3: {} 2651 | 2652 | lru-cache@5.1.1: 2653 | dependencies: 2654 | yallist: 3.1.1 2655 | 2656 | lucide-react@0.344.0(react@18.3.1): 2657 | dependencies: 2658 | react: 18.3.1 2659 | 2660 | merge2@1.4.1: {} 2661 | 2662 | micromatch@4.0.8: 2663 | dependencies: 2664 | braces: 3.0.3 2665 | picomatch: 2.3.1 2666 | 2667 | minimatch@3.1.2: 2668 | dependencies: 2669 | brace-expansion: 1.1.11 2670 | 2671 | minimatch@9.0.5: 2672 | dependencies: 2673 | brace-expansion: 2.0.1 2674 | 2675 | minipass@7.1.2: {} 2676 | 2677 | ms@2.1.3: {} 2678 | 2679 | mz@2.7.0: 2680 | dependencies: 2681 | any-promise: 1.3.0 2682 | object-assign: 4.1.1 2683 | thenify-all: 1.6.0 2684 | 2685 | nanoid@3.3.11: {} 2686 | 2687 | natural-compare@1.4.0: {} 2688 | 2689 | node-releases@2.0.19: {} 2690 | 2691 | normalize-path@3.0.0: {} 2692 | 2693 | normalize-range@0.1.2: {} 2694 | 2695 | object-assign@4.1.1: {} 2696 | 2697 | object-hash@3.0.0: {} 2698 | 2699 | optionator@0.9.4: 2700 | dependencies: 2701 | deep-is: 0.1.4 2702 | fast-levenshtein: 2.0.6 2703 | levn: 0.4.1 2704 | prelude-ls: 1.2.1 2705 | type-check: 0.4.0 2706 | word-wrap: 1.2.5 2707 | 2708 | p-limit@3.1.0: 2709 | dependencies: 2710 | yocto-queue: 0.1.0 2711 | 2712 | p-locate@5.0.0: 2713 | dependencies: 2714 | p-limit: 3.1.0 2715 | 2716 | package-json-from-dist@1.0.1: {} 2717 | 2718 | parent-module@1.0.1: 2719 | dependencies: 2720 | callsites: 3.1.0 2721 | 2722 | path-exists@4.0.0: {} 2723 | 2724 | path-key@3.1.1: {} 2725 | 2726 | path-parse@1.0.7: {} 2727 | 2728 | path-scurry@1.11.1: 2729 | dependencies: 2730 | lru-cache: 10.4.3 2731 | minipass: 7.1.2 2732 | 2733 | picocolors@1.1.1: {} 2734 | 2735 | picomatch@2.3.1: {} 2736 | 2737 | pify@2.3.0: {} 2738 | 2739 | pirates@4.0.7: {} 2740 | 2741 | postcss-import@15.1.0(postcss@8.5.3): 2742 | dependencies: 2743 | postcss: 8.5.3 2744 | postcss-value-parser: 4.2.0 2745 | read-cache: 1.0.0 2746 | resolve: 1.22.10 2747 | 2748 | postcss-js@4.0.1(postcss@8.5.3): 2749 | dependencies: 2750 | camelcase-css: 2.0.1 2751 | postcss: 8.5.3 2752 | 2753 | postcss-load-config@4.0.2(postcss@8.5.3): 2754 | dependencies: 2755 | lilconfig: 3.1.3 2756 | yaml: 2.7.1 2757 | optionalDependencies: 2758 | postcss: 8.5.3 2759 | 2760 | postcss-nested@6.2.0(postcss@8.5.3): 2761 | dependencies: 2762 | postcss: 8.5.3 2763 | postcss-selector-parser: 6.1.2 2764 | 2765 | postcss-selector-parser@6.1.2: 2766 | dependencies: 2767 | cssesc: 3.0.0 2768 | util-deprecate: 1.0.2 2769 | 2770 | postcss-value-parser@4.2.0: {} 2771 | 2772 | postcss@8.5.3: 2773 | dependencies: 2774 | nanoid: 3.3.11 2775 | picocolors: 1.1.1 2776 | source-map-js: 1.2.1 2777 | 2778 | prelude-ls@1.2.1: {} 2779 | 2780 | punycode@2.3.1: {} 2781 | 2782 | queue-microtask@1.2.3: {} 2783 | 2784 | react-dom@18.3.1(react@18.3.1): 2785 | dependencies: 2786 | loose-envify: 1.4.0 2787 | react: 18.3.1 2788 | scheduler: 0.23.2 2789 | 2790 | react-refresh@0.17.0: {} 2791 | 2792 | react-remove-scroll-bar@2.3.8(@types/react@18.3.20)(react@18.3.1): 2793 | dependencies: 2794 | react: 18.3.1 2795 | react-style-singleton: 2.2.3(@types/react@18.3.20)(react@18.3.1) 2796 | tslib: 2.8.1 2797 | optionalDependencies: 2798 | '@types/react': 18.3.20 2799 | 2800 | react-remove-scroll@2.6.3(@types/react@18.3.20)(react@18.3.1): 2801 | dependencies: 2802 | react: 18.3.1 2803 | react-remove-scroll-bar: 2.3.8(@types/react@18.3.20)(react@18.3.1) 2804 | react-style-singleton: 2.2.3(@types/react@18.3.20)(react@18.3.1) 2805 | tslib: 2.8.1 2806 | use-callback-ref: 1.3.3(@types/react@18.3.20)(react@18.3.1) 2807 | use-sidecar: 1.1.3(@types/react@18.3.20)(react@18.3.1) 2808 | optionalDependencies: 2809 | '@types/react': 18.3.20 2810 | 2811 | react-style-singleton@2.2.3(@types/react@18.3.20)(react@18.3.1): 2812 | dependencies: 2813 | get-nonce: 1.0.1 2814 | react: 18.3.1 2815 | tslib: 2.8.1 2816 | optionalDependencies: 2817 | '@types/react': 18.3.20 2818 | 2819 | react@18.3.1: 2820 | dependencies: 2821 | loose-envify: 1.4.0 2822 | 2823 | read-cache@1.0.0: 2824 | dependencies: 2825 | pify: 2.3.0 2826 | 2827 | readdirp@3.6.0: 2828 | dependencies: 2829 | picomatch: 2.3.1 2830 | 2831 | resolve-from@4.0.0: {} 2832 | 2833 | resolve@1.22.10: 2834 | dependencies: 2835 | is-core-module: 2.16.1 2836 | path-parse: 1.0.7 2837 | supports-preserve-symlinks-flag: 1.0.0 2838 | 2839 | reusify@1.1.0: {} 2840 | 2841 | rollup@4.40.1: 2842 | dependencies: 2843 | '@types/estree': 1.0.7 2844 | optionalDependencies: 2845 | '@rollup/rollup-android-arm-eabi': 4.40.1 2846 | '@rollup/rollup-android-arm64': 4.40.1 2847 | '@rollup/rollup-darwin-arm64': 4.40.1 2848 | '@rollup/rollup-darwin-x64': 4.40.1 2849 | '@rollup/rollup-freebsd-arm64': 4.40.1 2850 | '@rollup/rollup-freebsd-x64': 4.40.1 2851 | '@rollup/rollup-linux-arm-gnueabihf': 4.40.1 2852 | '@rollup/rollup-linux-arm-musleabihf': 4.40.1 2853 | '@rollup/rollup-linux-arm64-gnu': 4.40.1 2854 | '@rollup/rollup-linux-arm64-musl': 4.40.1 2855 | '@rollup/rollup-linux-loongarch64-gnu': 4.40.1 2856 | '@rollup/rollup-linux-powerpc64le-gnu': 4.40.1 2857 | '@rollup/rollup-linux-riscv64-gnu': 4.40.1 2858 | '@rollup/rollup-linux-riscv64-musl': 4.40.1 2859 | '@rollup/rollup-linux-s390x-gnu': 4.40.1 2860 | '@rollup/rollup-linux-x64-gnu': 4.40.1 2861 | '@rollup/rollup-linux-x64-musl': 4.40.1 2862 | '@rollup/rollup-win32-arm64-msvc': 4.40.1 2863 | '@rollup/rollup-win32-ia32-msvc': 4.40.1 2864 | '@rollup/rollup-win32-x64-msvc': 4.40.1 2865 | fsevents: 2.3.3 2866 | 2867 | run-parallel@1.2.0: 2868 | dependencies: 2869 | queue-microtask: 1.2.3 2870 | 2871 | scheduler@0.23.2: 2872 | dependencies: 2873 | loose-envify: 1.4.0 2874 | 2875 | semver@6.3.1: {} 2876 | 2877 | semver@7.7.1: {} 2878 | 2879 | shebang-command@2.0.0: 2880 | dependencies: 2881 | shebang-regex: 3.0.0 2882 | 2883 | shebang-regex@3.0.0: {} 2884 | 2885 | signal-exit@4.1.0: {} 2886 | 2887 | source-map-js@1.2.1: {} 2888 | 2889 | string-width@4.2.3: 2890 | dependencies: 2891 | emoji-regex: 8.0.0 2892 | is-fullwidth-code-point: 3.0.0 2893 | strip-ansi: 6.0.1 2894 | 2895 | string-width@5.1.2: 2896 | dependencies: 2897 | eastasianwidth: 0.2.0 2898 | emoji-regex: 9.2.2 2899 | strip-ansi: 7.1.0 2900 | 2901 | strip-ansi@6.0.1: 2902 | dependencies: 2903 | ansi-regex: 5.0.1 2904 | 2905 | strip-ansi@7.1.0: 2906 | dependencies: 2907 | ansi-regex: 6.1.0 2908 | 2909 | strip-json-comments@3.1.1: {} 2910 | 2911 | sucrase@3.35.0: 2912 | dependencies: 2913 | '@jridgewell/gen-mapping': 0.3.8 2914 | commander: 4.1.1 2915 | glob: 10.4.5 2916 | lines-and-columns: 1.2.4 2917 | mz: 2.7.0 2918 | pirates: 4.0.7 2919 | ts-interface-checker: 0.1.13 2920 | 2921 | supports-color@7.2.0: 2922 | dependencies: 2923 | has-flag: 4.0.0 2924 | 2925 | supports-preserve-symlinks-flag@1.0.0: {} 2926 | 2927 | tailwindcss@3.4.17: 2928 | dependencies: 2929 | '@alloc/quick-lru': 5.2.0 2930 | arg: 5.0.2 2931 | chokidar: 3.6.0 2932 | didyoumean: 1.2.2 2933 | dlv: 1.1.3 2934 | fast-glob: 3.3.3 2935 | glob-parent: 6.0.2 2936 | is-glob: 4.0.3 2937 | jiti: 1.21.7 2938 | lilconfig: 3.1.3 2939 | micromatch: 4.0.8 2940 | normalize-path: 3.0.0 2941 | object-hash: 3.0.0 2942 | picocolors: 1.1.1 2943 | postcss: 8.5.3 2944 | postcss-import: 15.1.0(postcss@8.5.3) 2945 | postcss-js: 4.0.1(postcss@8.5.3) 2946 | postcss-load-config: 4.0.2(postcss@8.5.3) 2947 | postcss-nested: 6.2.0(postcss@8.5.3) 2948 | postcss-selector-parser: 6.1.2 2949 | resolve: 1.22.10 2950 | sucrase: 3.35.0 2951 | transitivePeerDependencies: 2952 | - ts-node 2953 | 2954 | thenify-all@1.6.0: 2955 | dependencies: 2956 | thenify: 3.3.1 2957 | 2958 | thenify@3.3.1: 2959 | dependencies: 2960 | any-promise: 1.3.0 2961 | 2962 | to-regex-range@5.0.1: 2963 | dependencies: 2964 | is-number: 7.0.0 2965 | 2966 | ts-api-utils@2.1.0(typescript@5.8.3): 2967 | dependencies: 2968 | typescript: 5.8.3 2969 | 2970 | ts-interface-checker@0.1.13: {} 2971 | 2972 | tslib@2.8.1: {} 2973 | 2974 | type-check@0.4.0: 2975 | dependencies: 2976 | prelude-ls: 1.2.1 2977 | 2978 | typescript-eslint@8.31.0(eslint@9.25.1(jiti@1.21.7))(typescript@5.8.3): 2979 | dependencies: 2980 | '@typescript-eslint/eslint-plugin': 8.31.0(@typescript-eslint/parser@8.31.0(eslint@9.25.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.25.1(jiti@1.21.7))(typescript@5.8.3) 2981 | '@typescript-eslint/parser': 8.31.0(eslint@9.25.1(jiti@1.21.7))(typescript@5.8.3) 2982 | '@typescript-eslint/utils': 8.31.0(eslint@9.25.1(jiti@1.21.7))(typescript@5.8.3) 2983 | eslint: 9.25.1(jiti@1.21.7) 2984 | typescript: 5.8.3 2985 | transitivePeerDependencies: 2986 | - supports-color 2987 | 2988 | typescript@5.8.3: {} 2989 | 2990 | undici-types@6.21.0: 2991 | optional: true 2992 | 2993 | update-browserslist-db@1.1.3(browserslist@4.24.4): 2994 | dependencies: 2995 | browserslist: 4.24.4 2996 | escalade: 3.2.0 2997 | picocolors: 1.1.1 2998 | 2999 | uri-js@4.4.1: 3000 | dependencies: 3001 | punycode: 2.3.1 3002 | 3003 | use-callback-ref@1.3.3(@types/react@18.3.20)(react@18.3.1): 3004 | dependencies: 3005 | react: 18.3.1 3006 | tslib: 2.8.1 3007 | optionalDependencies: 3008 | '@types/react': 18.3.20 3009 | 3010 | use-sidecar@1.1.3(@types/react@18.3.20)(react@18.3.1): 3011 | dependencies: 3012 | detect-node-es: 1.1.0 3013 | react: 18.3.1 3014 | tslib: 2.8.1 3015 | optionalDependencies: 3016 | '@types/react': 18.3.20 3017 | 3018 | use-sync-external-store@1.5.0(react@18.3.1): 3019 | dependencies: 3020 | react: 18.3.1 3021 | 3022 | util-deprecate@1.0.2: {} 3023 | 3024 | vite@5.4.18(@types/node@22.15.3): 3025 | dependencies: 3026 | esbuild: 0.21.5 3027 | postcss: 8.5.3 3028 | rollup: 4.40.1 3029 | optionalDependencies: 3030 | '@types/node': 22.15.3 3031 | fsevents: 2.3.3 3032 | 3033 | which@2.0.2: 3034 | dependencies: 3035 | isexe: 2.0.0 3036 | 3037 | word-wrap@1.2.5: {} 3038 | 3039 | wrap-ansi@7.0.0: 3040 | dependencies: 3041 | ansi-styles: 4.3.0 3042 | string-width: 4.2.3 3043 | strip-ansi: 6.0.1 3044 | 3045 | wrap-ansi@8.1.0: 3046 | dependencies: 3047 | ansi-styles: 6.2.1 3048 | string-width: 5.1.2 3049 | strip-ansi: 7.1.0 3050 | 3051 | yallist@3.1.1: {} 3052 | 3053 | yaml@2.7.1: {} 3054 | 3055 | yocto-queue@0.1.0: {} 3056 | 3057 | zustand@4.5.6(@types/react@18.3.20)(react@18.3.1): 3058 | dependencies: 3059 | use-sync-external-store: 1.5.0(react@18.3.1) 3060 | optionalDependencies: 3061 | '@types/react': 18.3.20 3062 | react: 18.3.1 3063 | --------------------------------------------------------------------------------