├── 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 |

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 |
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 | 
10 | 
11 | 
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 |
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 |
--------------------------------------------------------------------------------