diff --git a/README.md b/README.md index fc2eef4..f241cbe 100644 --- a/README.md +++ b/README.md @@ -82,8 +82,8 @@ iMeeting 是一个基于 AI 技术的智能会议记录与内容管理平台,通 ### 环境要求 -- Node.js 16+ -- Python 3.9+ +- Node.js 22.12+ +- Python 3.12+ - MySQL 5.7+ - Redis 5.0+ - Docker (可选) @@ -95,7 +95,7 @@ iMeeting 是一个基于 AI 技术的智能会议记录与内容管理平台,通 ```bash cd backend pip install -r requirements.txt -python main.py +python app/main.py ``` 默认运行在 `http://localhost:8000` @@ -110,6 +110,17 @@ npm run dev 默认运行在 `http://localhost:5173` +#### 使用 Conda 一键启动前后端 + +项目根目录提供了 Conda 启动脚本,会分别创建并使用独立环境启动前后端: + +- 后端环境: `imetting_backend` (Python 3.12) +- 前端环境: `imetting_frontend` (Node.js 22) + +```bash +./start-conda.sh +``` + ### 配置说明 详细的配置文档请参考: diff --git a/backend/app/api/endpoints/admin_settings.py b/backend/app/api/endpoints/admin_settings.py index 013c69a..ac1548f 100644 --- a/backend/app/api/endpoints/admin_settings.py +++ b/backend/app/api/endpoints/admin_settings.py @@ -9,6 +9,7 @@ from app.core.database import get_db_connection from app.core.response import create_api_response from app.services.async_transcription_service import AsyncTranscriptionService from app.services.llm_service import LLMService +from app.services.system_config_service import SystemConfigService router = APIRouter() llm_service = LLMService() @@ -800,6 +801,18 @@ async def test_audio_model_config(request: AudioModelTestRequest, current_user=D return create_api_response(code="500", message=f"音频模型测试失败: {str(e)}") +@router.get("/system-config/public") +async def get_public_system_config(): + try: + return create_api_response( + code="200", + message="获取公开配置成功", + data=SystemConfigService.get_branding_config() + ) + except Exception as e: + return create_api_response(code="500", message=f"获取公开配置失败: {str(e)}") + + @router.get("/admin/system-config") async def get_system_config_compat(current_user=Depends(get_current_admin_user)): """兼容旧前端的系统配置接口,数据来源为 sys_system_parameters。""" diff --git a/backend/app/api/endpoints/meetings.py b/backend/app/api/endpoints/meetings.py index a9daf84..bf07671 100644 --- a/backend/app/api/endpoints/meetings.py +++ b/backend/app/api/endpoints/meetings.py @@ -53,6 +53,19 @@ def _process_tags(cursor, tag_string: Optional[str], creator_id: Optional[int] = tags_data = cursor.fetchall() return [Tag(**tag) for tag in tags_data] +def _sync_attendees(cursor, meeting_id: int, attendee_ids: Optional[List[int]]) -> None: + attendee_id_list = [] + if attendee_ids: + attendee_id_list = list(dict.fromkeys(int(user_id) for user_id in attendee_ids if user_id is not None)) + + cursor.execute("DELETE FROM attendees WHERE meeting_id = %s", (meeting_id,)) + + if attendee_id_list: + cursor.executemany( + 'INSERT IGNORE INTO attendees (meeting_id, user_id) VALUES (%s, %s)', + [(meeting_id, user_id) for user_id in attendee_id_list] + ) + def _get_meeting_overall_status(meeting_id: int) -> dict: """ 获取会议的整体进度状态(包含转译和LLM两个阶段) @@ -248,7 +261,7 @@ def get_meetings( meeting_list.append(Meeting( meeting_id=meeting['meeting_id'], title=meeting['title'], meeting_time=meeting['meeting_time'], summary=meeting['summary'], created_at=meeting['created_at'], audio_file_path=meeting['audio_file_path'], - attendees=attendees, creator_id=meeting['creator_id'], creator_username=meeting['creator_username'], tags=tags_list, + attendees=attendees, attendee_ids=[row['user_id'] for row in attendees_data], creator_id=meeting['creator_id'], creator_username=meeting['creator_username'], tags=tags_list, access_password=meeting.get('access_password'), overall_status=progress_info.get('overall_status'), overall_progress=progress_info.get('overall_progress'), @@ -319,7 +332,7 @@ def get_meeting_details(meeting_id: int, current_user: dict = Depends(get_curren cursor = connection.cursor(dictionary=True) query = ''' SELECT m.meeting_id, m.title, m.meeting_time, m.summary, m.created_at, m.tags, - m.user_id as creator_id, u.caption as creator_username, + m.user_id as creator_id, u.caption as creator_username, m.prompt_id, af.file_path as audio_file_path, af.duration as audio_duration, p.name as prompt_name, m.access_password FROM meetings m @@ -341,7 +354,9 @@ def get_meeting_details(meeting_id: int, current_user: dict = Depends(get_curren meeting_data = Meeting( meeting_id=meeting['meeting_id'], title=meeting['title'], meeting_time=meeting['meeting_time'], summary=meeting['summary'], created_at=meeting['created_at'], attendees=attendees, + attendee_ids=[row['user_id'] for row in attendees_data], creator_id=meeting['creator_id'], creator_username=meeting['creator_username'], tags=tags, + prompt_id=meeting.get('prompt_id'), prompt_name=meeting.get('prompt_name'), access_password=meeting.get('access_password') ) @@ -355,6 +370,12 @@ def get_meeting_details(meeting_id: int, current_user: dict = Depends(get_curren meeting_data.transcription_status = TranscriptionTaskStatus(**transcription_status_data) except Exception as e: print(f"Warning: Failed to get transcription status for meeting {meeting_id}: {e}") + try: + llm_status_data = async_meeting_service.get_meeting_llm_status(meeting_id) + if llm_status_data: + meeting_data.llm_status = TranscriptionTaskStatus(**llm_status_data) + except Exception as e: + print(f"Warning: Failed to get llm status for meeting {meeting_id}: {e}") return create_api_response(code="200", message="获取会议详情成功", data=meeting_data) @router.get("/meetings/{meeting_id}/transcript") @@ -385,17 +406,24 @@ def create_meeting(meeting_request: CreateMeetingRequest, current_user: dict = D # 使用 _process_tags 来处理标签创建 if meeting_request.tags: _process_tags(cursor, meeting_request.tags, current_user['user_id']) - meeting_query = 'INSERT INTO meetings (user_id, title, meeting_time, summary, tags, created_at) VALUES (%s, %s, %s, %s, %s, %s)' - cursor.execute(meeting_query, (meeting_request.user_id, meeting_request.title, meeting_request.meeting_time, None, meeting_request.tags, datetime.now().isoformat())) + meeting_query = ''' + INSERT INTO meetings (user_id, title, meeting_time, summary, tags, prompt_id, created_at) + VALUES (%s, %s, %s, %s, %s, %s, %s) + ''' + cursor.execute( + meeting_query, + ( + current_user['user_id'], + meeting_request.title, + meeting_request.meeting_time, + None, + meeting_request.tags, + meeting_request.prompt_id or 0, + datetime.now().isoformat(), + ), + ) meeting_id = cursor.lastrowid - # 根据 caption 查找用户ID并插入参会人 - if meeting_request.attendees: - captions = [c.strip() for c in meeting_request.attendees.split(',') if c.strip()] - if captions: - placeholders = ','.join(['%s'] * len(captions)) - cursor.execute(f'SELECT user_id FROM sys_users WHERE caption IN ({placeholders})', captions) - for row in cursor.fetchall(): - cursor.execute('INSERT IGNORE INTO attendees (meeting_id, user_id) VALUES (%s, %s)', (meeting_id, row['user_id'])) + _sync_attendees(cursor, meeting_id, meeting_request.attendee_ids) connection.commit() return create_api_response(code="200", message="Meeting created successfully", data={"meeting_id": meeting_id}) @@ -403,7 +431,7 @@ def create_meeting(meeting_request: CreateMeetingRequest, current_user: dict = D def update_meeting(meeting_id: int, meeting_request: UpdateMeetingRequest, current_user: dict = Depends(get_current_user)): with get_db_connection() as connection: cursor = connection.cursor(dictionary=True) - cursor.execute("SELECT user_id FROM meetings WHERE meeting_id = %s", (meeting_id,)) + cursor.execute("SELECT user_id, prompt_id FROM meetings WHERE meeting_id = %s", (meeting_id,)) meeting = cursor.fetchone() if not meeting: return create_api_response(code="404", message="Meeting not found") @@ -412,17 +440,20 @@ def update_meeting(meeting_id: int, meeting_request: UpdateMeetingRequest, curre # 使用 _process_tags 来处理标签创建 if meeting_request.tags: _process_tags(cursor, meeting_request.tags, current_user['user_id']) - update_query = 'UPDATE meetings SET title = %s, meeting_time = %s, summary = %s, tags = %s WHERE meeting_id = %s' - cursor.execute(update_query, (meeting_request.title, meeting_request.meeting_time, meeting_request.summary, meeting_request.tags, meeting_id)) - cursor.execute("DELETE FROM attendees WHERE meeting_id = %s", (meeting_id,)) - # 根据 caption 查找用户ID并插入参会人 - if meeting_request.attendees: - captions = [c.strip() for c in meeting_request.attendees.split(',') if c.strip()] - if captions: - placeholders = ','.join(['%s'] * len(captions)) - cursor.execute(f'SELECT user_id FROM sys_users WHERE caption IN ({placeholders})', captions) - for row in cursor.fetchall(): - cursor.execute('INSERT INTO attendees (meeting_id, user_id) VALUES (%s, %s)', (meeting_id, row['user_id'])) + update_query = 'UPDATE meetings SET title = %s, meeting_time = %s, summary = %s, tags = %s, prompt_id = %s WHERE meeting_id = %s' + cursor.execute( + update_query, + ( + meeting_request.title, + meeting_request.meeting_time, + meeting_request.summary, + meeting_request.tags, + meeting_request.prompt_id if meeting_request.prompt_id is not None else meeting['prompt_id'], + meeting_id, + ), + ) + if meeting_request.attendee_ids is not None: + _sync_attendees(cursor, meeting_id, meeting_request.attendee_ids) connection.commit() # 同步导出总结MD文件 if meeting_request.summary: @@ -453,7 +484,7 @@ def get_meeting_for_edit(meeting_id: int, current_user: dict = Depends(get_curre cursor = connection.cursor(dictionary=True) query = ''' SELECT m.meeting_id, m.title, m.meeting_time, m.summary, m.created_at, m.tags, - m.user_id as creator_id, u.caption as creator_username, af.file_path as audio_file_path, + m.user_id as creator_id, u.caption as creator_username, m.prompt_id, af.file_path as audio_file_path, m.access_password FROM meetings m JOIN sys_users u ON m.user_id = u.user_id LEFT JOIN audio_files af ON m.meeting_id = af.meeting_id WHERE m.meeting_id = %s @@ -471,7 +502,9 @@ def get_meeting_for_edit(meeting_id: int, current_user: dict = Depends(get_curre meeting_data = Meeting( meeting_id=meeting['meeting_id'], title=meeting['title'], meeting_time=meeting['meeting_time'], summary=meeting['summary'], created_at=meeting['created_at'], attendees=attendees, + attendee_ids=[row['user_id'] for row in attendees_data], creator_id=meeting['creator_id'], creator_username=meeting['creator_username'], tags=tags, + prompt_id=meeting.get('prompt_id'), access_password=meeting.get('access_password') ) if meeting.get('audio_file_path'): @@ -490,6 +523,7 @@ async def upload_audio( meeting_id: int = Form(...), auto_summarize: str = Form("true"), prompt_id: Optional[int] = Form(None), # 可选的提示词模版ID + model_code: Optional[str] = Form(None), # 可选的总结模型编码 background_tasks: BackgroundTasks = None, current_user: dict = Depends(get_current_user) ): @@ -503,6 +537,7 @@ async def upload_audio( meeting_id: 会议ID auto_summarize: 是否自动生成总结("true"/"false",默认"true") prompt_id: 提示词模版ID(可选,如果不指定则使用默认模版) + model_code: 总结模型编码(可选,如果不指定则使用默认模型) background_tasks: FastAPI后台任务 current_user: 当前登录用户 @@ -512,14 +547,23 @@ async def upload_audio( """ auto_summarize_bool = auto_summarize.lower() in ("true", "1", "yes") - # 0. 如果没有传入 prompt_id,尝试获取默认模版ID + model_code = model_code.strip() if model_code else None + + # 0. 如果没有传入 prompt_id,优先使用会议已配置模版,否则回退默认模版 if prompt_id is None: with get_db_connection() as connection: - cursor = connection.cursor() - cursor.execute( - "SELECT id FROM prompts WHERE task_type = 'MEETING_TASK' AND is_default = TRUE AND is_active = TRUE LIMIT 1" - ) - prompt_id = cursor.fetchone()[0] + cursor = connection.cursor(dictionary=True) + cursor.execute("SELECT prompt_id FROM meetings WHERE meeting_id = %s", (meeting_id,)) + meeting_row = cursor.fetchone() + if meeting_row and meeting_row.get('prompt_id') and int(meeting_row['prompt_id']) > 0: + prompt_id = int(meeting_row['prompt_id']) + else: + cursor = connection.cursor() + cursor.execute( + "SELECT id FROM prompts WHERE task_type = 'MEETING_TASK' AND is_default = TRUE AND is_active = TRUE LIMIT 1" + ) + prompt_row = cursor.fetchone() + prompt_id = prompt_row[0] if prompt_row else None # 1. 文件类型验证 file_extension = os.path.splitext(audio_file.filename)[1].lower() @@ -572,6 +616,7 @@ async def upload_audio( auto_summarize=auto_summarize_bool, background_tasks=background_tasks, prompt_id=prompt_id, + model_code=model_code, duration=audio_duration # 传递时长参数 ) @@ -605,6 +650,7 @@ async def upload_audio( "task_id": transcription_task_id, "transcription_started": transcription_task_id is not None, "auto_summarize": auto_summarize_bool, + "model_code": model_code, "replaced_existing": result["replaced_existing"], "previous_transcription_cleared": result["replaced_existing"] and result["has_transcription"] } @@ -746,12 +792,17 @@ def get_meeting_transcription_status(meeting_id: int, current_user: dict = Depen return create_api_response(code="500", message=f"Failed to get meeting transcription status: {str(e)}") @router.post("/meetings/{meeting_id}/transcription/start") -def start_meeting_transcription(meeting_id: int, current_user: dict = Depends(get_current_user)): +def start_meeting_transcription( + meeting_id: int, + background_tasks: BackgroundTasks, + current_user: dict = Depends(get_current_user) +): try: with get_db_connection() as connection: cursor = connection.cursor(dictionary=True) - cursor.execute("SELECT meeting_id FROM meetings WHERE meeting_id = %s", (meeting_id,)) - if not cursor.fetchone(): + cursor.execute("SELECT meeting_id, prompt_id FROM meetings WHERE meeting_id = %s", (meeting_id,)) + meeting = cursor.fetchone() + if not meeting: return create_api_response(code="404", message="Meeting not found") cursor.execute("SELECT file_path FROM audio_files WHERE meeting_id = %s LIMIT 1", (meeting_id,)) audio_file = cursor.fetchone() @@ -763,6 +814,13 @@ def start_meeting_transcription(meeting_id: int, current_user: dict = Depends(ge "task_id": existing_status['task_id'], "status": existing_status['status'] }) task_id = transcription_service.start_transcription(meeting_id, audio_file['file_path']) + background_tasks.add_task( + async_meeting_service.monitor_and_auto_summarize, + meeting_id, + task_id, + meeting.get('prompt_id') if meeting.get('prompt_id') not in (None, 0) else None, + None + ) return create_api_response(code="200", message="Transcription task started successfully", data={ "task_id": task_id, "meeting_id": meeting_id }) @@ -881,6 +939,12 @@ def generate_meeting_summary_async(meeting_id: int, request: GenerateSummaryRequ cursor.execute("SELECT meeting_id FROM meetings WHERE meeting_id = %s", (meeting_id,)) if not cursor.fetchone(): return create_api_response(code="404", message="Meeting not found") + transcription_status = transcription_service.get_meeting_transcription_status(meeting_id) + if transcription_status and transcription_status.get('status') in ['pending', 'processing']: + return create_api_response(code="409", message="转录进行中,暂不允许重新总结", data={ + "task_id": transcription_status.get('task_id'), + "status": transcription_status.get('status') + }) # 传递 prompt_id 和 model_code 参数给服务层 task_id = async_meeting_service.start_summary_generation(meeting_id, request.user_prompt, request.prompt_id, request.model_code) background_tasks.add_task(async_meeting_service._process_task, task_id) @@ -915,7 +979,7 @@ def list_active_llm_models(current_user: dict = Depends(get_current_user)): "SELECT model_code, model_name, provider, is_default FROM llm_model_config WHERE is_active = 1 ORDER BY is_default DESC, model_code ASC" ) models = cursor.fetchall() - return create_api_response(code="200", message="获取模型列表成功", data={"models": models}) + return create_api_response(code="200", message="获取模型列表成功", data=models) except Exception as e: return create_api_response(code="500", message=f"获取模型列表失败: {str(e)}") @router.get("/meetings/{meeting_id}/navigation") @@ -1023,7 +1087,7 @@ def get_meeting_navigation( return create_api_response(code="500", message=f"获取导航信息失败: {str(e)}") @router.get("/meetings/{meeting_id}/preview-data") -def get_meeting_preview_data(meeting_id: int): +def get_meeting_preview_data(meeting_id: int, password: Optional[str] = None): """ 获取会议预览数据(无需登录认证) 用于二维码扫描后的预览页面 @@ -1041,7 +1105,7 @@ def get_meeting_preview_data(meeting_id: int): # 检查会议是否存在,并获取基本信息 query = ''' - SELECT m.meeting_id, m.title, m.meeting_time, m.summary, m.updated_at, m.prompt_id, + SELECT m.meeting_id, m.title, m.meeting_time, m.summary, m.updated_at, m.prompt_id, m.tags, m.user_id as creator_id, u.caption as creator_username, p.name as prompt_name, m.access_password FROM meetings m @@ -1055,6 +1119,32 @@ def get_meeting_preview_data(meeting_id: int): if not meeting: return create_api_response(code="404", message="会议不存在") + stored_password = (meeting.get('access_password') or '').strip() + provided_password = (password or '').strip() + + if stored_password: + if not provided_password: + return create_api_response( + code="401", + message="此会议受密码保护", + data={ + "meeting_id": meeting_id, + "title": meeting['title'], + "requires_password": True + } + ) + + if provided_password != stored_password: + return create_api_response( + code="401", + message="密码错误", + data={ + "meeting_id": meeting_id, + "title": meeting['title'], + "requires_password": True + } + ) + # 获取整体进度状态(两阶段) progress_info = _get_meeting_overall_status(meeting_id) overall_status = progress_info["overall_status"] @@ -1116,6 +1206,17 @@ def get_meeting_preview_data(meeting_id: int): cursor.execute(attendees_query, (meeting_id,)) attendees_data = cursor.fetchall() attendees = [{'user_id': row['user_id'], 'caption': row['caption']} for row in attendees_data] + cursor.execute( + ''' + SELECT COUNT(DISTINCT speaker_id) AS participant_count + FROM transcript_segments + WHERE meeting_id = %s AND speaker_id IS NOT NULL + ''', + (meeting_id,) + ) + speaker_count_row = cursor.fetchone() or {} + participant_count = speaker_count_row.get('participant_count') or len(attendees) + tags = _process_tags(cursor, meeting.get('tags')) # 组装返回数据 preview_data = { @@ -1127,7 +1228,8 @@ def get_meeting_preview_data(meeting_id: int): "prompt_id": meeting['prompt_id'], "prompt_name": meeting['prompt_name'], "attendees": attendees, - "attendees_count": len(attendees), + "attendees_count": participant_count, + "tags": tags, "has_password": bool(meeting.get('access_password')), "processing_status": progress_info # 附带进度信息供调试 } diff --git a/backend/app/api/endpoints/users.py b/backend/app/api/endpoints/users.py index d9f9507..12902d2 100644 --- a/backend/app/api/endpoints/users.py +++ b/backend/app/api/endpoints/users.py @@ -96,7 +96,7 @@ def create_user(request: CreateUserRequest, current_user: dict = Depends(get_cur if current_user['role_id'] != 1: # 1 is admin return create_api_response(code="403", message="仅管理员有权限创建用户") - if not validate_email(request.email): + if request.email and not validate_email(request.email): return create_api_response(code="400", message="邮箱格式不正确") with get_db_connection() as connection: diff --git a/backend/app/core/database.py b/backend/app/core/database.py index cfbab7c..f11d079 100644 --- a/backend/app/core/database.py +++ b/backend/app/core/database.py @@ -10,14 +10,14 @@ def get_db_connection(): connection = None try: connection = mysql.connector.connect(**DATABASE_CONFIG) - yield connection except Error as e: print(f"数据库连接错误: {e}") raise HTTPException(status_code=500, detail="数据库连接失败") + try: + yield connection finally: if connection and connection.is_connected(): try: - # 确保清理任何未读结果 if connection.unread_result: connection.consume_results() connection.close() diff --git a/backend/app/models/models.py b/backend/app/models/models.py index e7587eb..1938628 100644 --- a/backend/app/models/models.py +++ b/backend/app/models/models.py @@ -34,9 +34,11 @@ class CreateUserRequest(BaseModel): password: Optional[str] = None caption: str email: Optional[str] = None + avatar_url: Optional[str] = None role_id: int = 2 class UpdateUserRequest(BaseModel): + username: Optional[str] = None caption: Optional[str] = None email: Optional[str] = None role_id: Optional[int] = None @@ -76,16 +78,19 @@ class Meeting(BaseModel): creator_username: str created_at: datetime.datetime attendees: List[AttendeeInfo] + attendee_ids: Optional[List[int]] = None tags: List[Tag] audio_file_path: Optional[str] = None audio_duration: Optional[float] = None summary: Optional[str] = None transcription_status: Optional[TranscriptionTaskStatus] = None + llm_status: Optional[TranscriptionTaskStatus] = None prompt_id: Optional[int] = None prompt_name: Optional[str] = None overall_status: Optional[str] = None overall_progress: Optional[int] = None current_stage: Optional[str] = None + access_password: Optional[str] = None class TranscriptSegment(BaseModel): segment_id: int @@ -98,7 +103,7 @@ class TranscriptSegment(BaseModel): class CreateMeetingRequest(BaseModel): title: str meeting_time: datetime.datetime - attendees: str # 逗号分隔的姓名 + attendee_ids: List[int] description: Optional[str] = None tags: Optional[str] = None # 逗号分隔 prompt_id: Optional[int] = None @@ -106,7 +111,7 @@ class CreateMeetingRequest(BaseModel): class UpdateMeetingRequest(BaseModel): title: Optional[str] = None meeting_time: Optional[datetime.datetime] = None - attendees: Optional[str] = None + attendee_ids: Optional[List[int]] = None description: Optional[str] = None tags: Optional[str] = None summary: Optional[str] = None @@ -121,7 +126,7 @@ class BatchSpeakerTagUpdateRequest(BaseModel): class TranscriptUpdateRequest(BaseModel): segment_id: int - new_text: str + text_content: str class BatchTranscriptUpdateRequest(BaseModel): updates: List[TranscriptUpdateRequest] diff --git a/backend/app/services/async_meeting_service.py b/backend/app/services/async_meeting_service.py index 98d7971..297c239 100644 --- a/backend/app/services/async_meeting_service.py +++ b/backend/app/services/async_meeting_service.py @@ -127,7 +127,13 @@ class AsyncMeetingService: self._update_task_in_db(task_id, 'failed', 0, error_message=error_msg) self._update_task_status_in_redis(task_id, 'failed', 0, error_message=error_msg) - def monitor_and_auto_summarize(self, meeting_id: int, transcription_task_id: str, prompt_id: Optional[int] = None): + def monitor_and_auto_summarize( + self, + meeting_id: int, + transcription_task_id: str, + prompt_id: Optional[int] = None, + model_code: Optional[str] = None + ): """ 监控转录任务,完成后自动生成总结 此方法设计为由BackgroundTasks调用,在后台运行 @@ -136,13 +142,14 @@ class AsyncMeetingService: meeting_id: 会议ID transcription_task_id: 转录任务ID prompt_id: 提示词模版ID(可选,如果不指定则使用默认模版) + model_code: 总结模型编码(可选,如果不指定则使用默认模型) 流程: 1. 循环轮询转录任务状态 2. 转录成功后自动启动总结任务 3. 转录失败或超时则停止轮询并记录日志 """ - print(f"[Monitor] Started monitoring transcription task {transcription_task_id} for meeting {meeting_id}, prompt_id: {prompt_id}") + print(f"[Monitor] Started monitoring transcription task {transcription_task_id} for meeting {meeting_id}, prompt_id: {prompt_id}, model_code: {model_code}") # 获取配置参数 poll_interval = TRANSCRIPTION_POLL_CONFIG['poll_interval'] @@ -178,7 +185,12 @@ class AsyncMeetingService: else: # 启动总结任务 try: - summary_task_id = self.start_summary_generation(meeting_id, user_prompt="", prompt_id=prompt_id) + summary_task_id = self.start_summary_generation( + meeting_id, + user_prompt="", + prompt_id=prompt_id, + model_code=model_code + ) print(f"[Monitor] Summary task {summary_task_id} started for meeting {meeting_id}") # 在后台执行总结任务 @@ -395,6 +407,7 @@ class AsyncMeetingService: 'meeting_id': int(task_data.get('meeting_id', 0)), 'created_at': task_data.get('created_at'), 'updated_at': task_data.get('updated_at'), + 'message': task_data.get('message'), 'result': task_data.get('result'), 'error_message': task_data.get('error_message') } diff --git a/backend/app/services/audio_service.py b/backend/app/services/audio_service.py index 778c338..ea39ca6 100644 --- a/backend/app/services/audio_service.py +++ b/backend/app/services/audio_service.py @@ -25,6 +25,7 @@ def handle_audio_upload( auto_summarize: bool = True, background_tasks: BackgroundTasks = None, prompt_id: int = None, + model_code: str = None, duration: int = 0 ) -> dict: """ @@ -46,6 +47,7 @@ def handle_audio_upload( auto_summarize: 是否自动生成总结(默认True) background_tasks: FastAPI 后台任务对象 prompt_id: 提示词模版ID(可选,如果不指定则使用默认模版) + model_code: 总结模型编码(可选,如果不指定则使用默认模型) duration: 音频时长(秒) Returns: @@ -58,7 +60,7 @@ def handle_audio_upload( "has_transcription": bool # 原来是否有转录记录 (成功时) } """ - print(f"[Audio Service] handle_audio_upload called - Meeting ID: {meeting_id}, Auto-summarize: {auto_summarize}, Received prompt_id: {prompt_id}, Type: {type(prompt_id)}") + print(f"[Audio Service] handle_audio_upload called - Meeting ID: {meeting_id}, Auto-summarize: {auto_summarize}, Received prompt_id: {prompt_id}, model_code: {model_code}") # 1. 权限和已有文件检查 try: @@ -145,9 +147,10 @@ def handle_audio_upload( async_meeting_service.monitor_and_auto_summarize, meeting_id, transcription_task_id, - prompt_id # 传递 prompt_id 给自动总结监控任务 + prompt_id, + model_code ) - print(f"[audio_service] Auto-summarize enabled, monitor task added for meeting {meeting_id}, prompt_id: {prompt_id}") + print(f"[audio_service] Auto-summarize enabled, monitor task added for meeting {meeting_id}, prompt_id: {prompt_id}, model_code: {model_code}") except Exception as e: print(f"Failed to start transcription: {e}") diff --git a/backend/app/services/system_config_service.py b/backend/app/services/system_config_service.py index 52a075f..b576cee 100644 --- a/backend/app/services/system_config_service.py +++ b/backend/app/services/system_config_service.py @@ -15,6 +15,15 @@ class SystemConfigService: DEFAULT_RESET_PASSWORD = 'default_reset_password' MAX_AUDIO_SIZE = 'max_audio_size' + # 品牌配置 + BRANDING_APP_NAME = 'branding_app_name' + BRANDING_HOME_HEADLINE = 'branding_home_headline' + BRANDING_HOME_TAGLINE = 'branding_home_tagline' + BRANDING_CONSOLE_SUBTITLE = 'branding_console_subtitle' + BRANDING_PREVIEW_TITLE = 'branding_preview_title' + BRANDING_LOGIN_WELCOME = 'branding_login_welcome' + BRANDING_FOOTER_TEXT = 'branding_footer_text' + # 声纹配置 VOICEPRINT_TEMPLATE_TEXT = 'voiceprint_template_text' VOICEPRINT_MAX_SIZE = 'voiceprint_max_size' @@ -603,6 +612,18 @@ class SystemConfigService: except (ValueError, TypeError): return default + @classmethod + def get_branding_config(cls) -> Dict[str, str]: + return { + "app_name": str(cls.get_config(cls.BRANDING_APP_NAME, "智听云平台") or "智听云平台"), + "home_headline": str(cls.get_config(cls.BRANDING_HOME_HEADLINE, "智听云平台") or "智听云平台"), + "home_tagline": str(cls.get_config(cls.BRANDING_HOME_TAGLINE, "让每一次谈话都产生价值。") or "让每一次谈话都产生价值。"), + "console_subtitle": str(cls.get_config(cls.BRANDING_CONSOLE_SUBTITLE, "智能会议控制台") or "智能会议控制台"), + "preview_title": str(cls.get_config(cls.BRANDING_PREVIEW_TITLE, "会议预览") or "会议预览"), + "login_welcome": str(cls.get_config(cls.BRANDING_LOGIN_WELCOME, "欢迎回来,请输入您的登录凭证。") or "欢迎回来,请输入您的登录凭证。"), + "footer_text": str(cls.get_config(cls.BRANDING_FOOTER_TEXT, "©2026 智听云平台") or "©2026 智听云平台"), + } + # LLM模型配置获取方法(直接使用通用方法) @classmethod def get_llm_model_name(cls, default: str = "qwen-plus") -> str: diff --git a/frontend/nginx.conf b/frontend/nginx.conf index 5abc93e..2a1bd61 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -33,6 +33,42 @@ server { proxy_send_timeout 300s; } + location = /docs { + proxy_pass http://backend:8000/docs; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location = /redoc { + proxy_pass http://backend:8000/redoc; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location = /openapi.json { + proxy_pass http://backend:8000/openapi.json; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location = /docs/oauth2-redirect { + proxy_pass http://backend:8000/docs/oauth2-redirect; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + # 上传文件代理 (使用 ^~ 提高优先级,避免被静态文件正则匹配拦截) location ^~ /uploads/ { proxy_pass http://backend:8000; @@ -57,4 +93,4 @@ server { location = /50x.html { root /usr/share/nginx/html; } -} \ No newline at end of file +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 61bce18..f22f145 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,13 +8,17 @@ "name": "frontend", "version": "1.1.0", "dependencies": { + "@ant-design/v5-patch-for-react-19": "^1.0.3", + "@codemirror/lang-markdown": "^6.5.0", + "@codemirror/state": "^6.5.2", + "@codemirror/view": "^6.38.6", + "@uiw/react-codemirror": "^4.25.3", "@uiw/react-md-editor": "^4.0.8", "antd": "^5.27.3", "axios": "^1.6.2", "canvg": "^4.0.3", "html2canvas": "^1.4.1", - "jspdf": "^3.0.2", - "lucide-react": "^0.294.0", + "jspdf": "^4.2.1", "markmap-common": "^0.18.9", "markmap-lib": "^0.18.12", "markmap-view": "^0.18.12", @@ -150,6 +154,20 @@ "react": ">=16.9.0" } }, + "node_modules/@ant-design/v5-patch-for-react-19": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@ant-design/v5-patch-for-react-19/-/v5-patch-for-react-19-1.0.3.tgz", + "integrity": "sha512-iWfZuSUl5kuhqLUw7jJXUQFMMkM7XpW7apmKzQBQHU0cpifYW4A79xIBt9YVO5IBajKpPG5UKP87Ft7Yrw1p/w==", + "license": "MIT", + "engines": { + "node": ">=12.x" + }, + "peerDependencies": { + "antd": ">=5.22.6", + "react": ">=19.0.0", + "react-dom": ">=19.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -385,9 +403,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.4", - "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.28.4.tgz", - "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -441,6 +459,159 @@ "node": ">=6.9.0" } }, + "node_modules/@codemirror/autocomplete": { + "version": "6.20.1", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.1.tgz", + "integrity": "sha512-1cvg3Vz1dSSToCNlJfRA2WSI4ht3K+WplO0UMOgmUYPivCyy2oueZY6Lx7M9wThm7SDUBViRmuT+OG/i8+ON9A==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.3.tgz", + "integrity": "sha512-JFRiqhKu+bvSkDLI+rUhJwSxQxYb759W5GBezE8Uc8mHLqC9aV/9aTC7yJSqCtB3F00pylrLCwnyS91Ap5ej4Q==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.6.0", + "@codemirror/view": "^6.27.0", + "@lezer/common": "^1.1.0" + } + }, + "node_modules/@codemirror/lang-css": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz", + "integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/css": "^1.1.7" + } + }, + "node_modules/@codemirror/lang-html": { + "version": "6.4.11", + "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz", + "integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/language": "^6.4.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/css": "^1.1.0", + "@lezer/html": "^1.3.12" + } + }, + "node_modules/@codemirror/lang-javascript": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.5.tgz", + "integrity": "sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/javascript": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-markdown": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.5.0.tgz", + "integrity": "sha512-0K40bZ35jpHya6FriukbgaleaqzBLZfOh7HuzqbMxBXkbYMJDxfF39c23xOgxFezR+3G+tR2/Mup+Xk865OMvw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.7.1", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.3.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.2.1", + "@lezer/markdown": "^1.0.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.3.tgz", + "integrity": "sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.5.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.9.5", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.5.tgz", + "integrity": "sha512-GElsbU9G7QT9xXhpUg1zWGmftA/7jamh+7+ydKRuT0ORpWS3wOSP0yT1FOlIZa7mIJjpVPipErsyvVqB9cfTFA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.35.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/search": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.6.0.tgz", + "integrity": "sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.37.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.6.0.tgz", + "integrity": "sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ==", + "license": "MIT", + "dependencies": { + "@marijn/find-cluster-break": "^1.0.0" + } + }, + "node_modules/@codemirror/theme-one-dark": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz", + "integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.40.0", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.40.0.tgz", + "integrity": "sha512-WA0zdU7xfF10+5I3HhUUq3kqOx3KjqmtQ9lqZjfK7jtYk4G72YW9rezcSywpaUMCWOMlq+6E0pO1IWg1TNIhtg==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.6.0", + "crelt": "^1.0.6", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, "node_modules/@emotion/hash": { "version": "0.8.0", "resolved": "https://registry.npmmirror.com/@emotion/hash/-/hash-0.8.0.tgz", @@ -453,10 +624,78 @@ "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", "license": "MIT" }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", + "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", + "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", + "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", + "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz", - "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", + "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", "cpu": [ "arm64" ], @@ -470,6 +709,363 @@ "node": ">=18" } }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", + "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", + "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", + "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", + "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", + "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", + "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", + "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", + "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", + "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", + "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", + "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", + "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", + "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", + "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", + "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", + "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", + "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", + "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", + "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", + "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", + "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.7.0", "resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", @@ -738,6 +1334,79 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lezer/common": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.1.tgz", + "integrity": "sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw==", + "license": "MIT" + }, + "node_modules/@lezer/css": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.3.tgz", + "integrity": "sha512-RzBo8r+/6QJeow7aPHIpGVIH59xTcJXp399820gZoMo9noQDRVpJLheIBUicYwKcsbOYoBRoLZlf2720dG/4Tg==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/highlight": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", + "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.3.0" + } + }, + "node_modules/@lezer/html": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.13.tgz", + "integrity": "sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/javascript": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz", + "integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.1.3", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.8.tgz", + "integrity": "sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/markdown": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.6.3.tgz", + "integrity": "sha512-jpGm5Ps+XErS+xA4urw7ogEGkeZOahVQF21Z6oECF0sj+2liwZopd2+I8uH5I/vZsRuuze3OxBREIANLf6KKUw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.5.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@marijn/find-cluster-break": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", + "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", + "license": "MIT" + }, "node_modules/@rc-component/async-validator": { "version": "5.0.4", "resolved": "https://registry.npmmirror.com/@rc-component/async-validator/-/async-validator-5.0.4.tgz", @@ -894,10 +1563,38 @@ "dev": true, "license": "MIT" }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.0.tgz", + "integrity": "sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.0.tgz", + "integrity": "sha512-u6JHLll5QKRvjciE78bQXDmqRqNs5M/3GVqZeMwvmjaNODJih/WIrJlFVEihvV0MiYFmd+ZyPr9wxOVbPAG2Iw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.46.1", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.1.tgz", - "integrity": "sha512-EFYNNGij2WllnzljQDQnlFTXzSJw87cpAs4TVBAWLdkvic5Uh5tISrIL6NRcxoh/b2EFBG/TK8hgRrGx94zD4A==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.0.tgz", + "integrity": "sha512-qEF7CsKKzSRc20Ciu2Zw1wRrBz4g56F7r/vRwY430UPp/nt1x21Q/fpJ9N5l47WWvJlkNCPJz3QRVw008fi7yA==", "cpu": [ "arm64" ], @@ -908,6 +1605,314 @@ "darwin" ] }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.0.tgz", + "integrity": "sha512-WADYozJ4QCnXCH4wPB+3FuGmDPoFseVCUrANmA5LWwGmC6FL14BWC7pcq+FstOZv3baGX65tZ378uT6WG8ynTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.0.tgz", + "integrity": "sha512-6b8wGHJlDrGeSE3aH5mGNHBjA0TTkxdoNHik5EkvPHCt351XnigA4pS7Wsj/Eo9Y8RBU6f35cjN9SYmCFBtzxw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.0.tgz", + "integrity": "sha512-h25Ga0t4jaylMB8M/JKAyrvvfxGRjnPQIR8lnCayyzEjEOx2EJIlIiMbhpWxDRKGKF8jbNH01NnN663dH638mA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.0.tgz", + "integrity": "sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.0.tgz", + "integrity": "sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.0.tgz", + "integrity": "sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.0.tgz", + "integrity": "sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.0.tgz", + "integrity": "sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.0.tgz", + "integrity": "sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.0.tgz", + "integrity": "sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.0.tgz", + "integrity": "sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.0.tgz", + "integrity": "sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.0.tgz", + "integrity": "sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.0.tgz", + "integrity": "sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.0.tgz", + "integrity": "sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.0.tgz", + "integrity": "sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.0.tgz", + "integrity": "sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.0.tgz", + "integrity": "sha512-pESDkos/PDzYwtyzB5p/UoNU/8fJo68vcXM9ZW2V0kjYayj1KaaUfi1NmTUTUpMn4UhU4gTuK8gIaFO4UGuMbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.0.tgz", + "integrity": "sha512-hj1wFStD7B1YBeYmvY+lWXZ7ey73YGPcViMShYikqKT1GtstIKQAtfUI6yrzPjAy/O7pO0VLXGmUVWXQMaYgTQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.0.tgz", + "integrity": "sha512-SyaIPFoxmUPlNDq5EHkTbiKzmSEmq/gOYFI/3HHJ8iS/v1mbugVa7dXUzcJGQfoytp9DJFLhHH4U3/eTy2Bq4w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.0.tgz", + "integrity": "sha512-RdcryEfzZr+lAr5kRm2ucN9aVlCCa2QNq4hXelZxb8GG0NJSazq44Z3PCCc8wISRuCVnGs0lQJVX5Vp6fKA+IA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.0.tgz", + "integrity": "sha512-PrsWNQ8BuE00O3Xsx3ALh2Df8fAj9+cvvX9AIA6o4KpATR98c9mud4XtDWVvsEuyia5U4tVSTKygawyJkjm60w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmmirror.com/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1030,7 +2035,6 @@ "version": "19.1.8", "resolved": "https://registry.npmmirror.com/@types/react/-/react-19.1.8.tgz", "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==", - "dev": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -1059,6 +2063,33 @@ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, + "node_modules/@uiw/codemirror-extensions-basic-setup": { + "version": "4.25.9", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.25.9.tgz", + "integrity": "sha512-QFAqr+pu6lDmNpAlecODcF49TlsrZ0bj15zPzfhiqSDl+Um3EsDLFLppixC7kFLn+rdDM2LTvVjn5CPvefpRgw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@codemirror/autocomplete": ">=6.0.0", + "@codemirror/commands": ">=6.0.0", + "@codemirror/language": ">=6.0.0", + "@codemirror/lint": ">=6.0.0", + "@codemirror/search": ">=6.0.0", + "@codemirror/state": ">=6.0.0", + "@codemirror/view": ">=6.0.0" + } + }, "node_modules/@uiw/copy-to-clipboard": { "version": "1.0.17", "resolved": "https://registry.npmmirror.com/@uiw/copy-to-clipboard/-/copy-to-clipboard-1.0.17.tgz", @@ -1068,6 +2099,32 @@ "url": "https://jaywcjlove.github.io/#/sponsor" } }, + "node_modules/@uiw/react-codemirror": { + "version": "4.25.9", + "resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.25.9.tgz", + "integrity": "sha512-HftqCBUYShAOH0pGi1CHP8vfm5L8fQ3+0j0VI6lQD6QpK+UBu3J7nxfEN5O/BXMilMNf9ZyFJRvRcuMMOLHMng==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.6", + "@codemirror/commands": "^6.1.0", + "@codemirror/state": "^6.1.1", + "@codemirror/theme-one-dark": "^6.0.0", + "@uiw/codemirror-extensions-basic-setup": "4.25.9", + "codemirror": "^6.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.11.0", + "@codemirror/state": ">=6.0.0", + "@codemirror/theme-one-dark": ">=6.0.0", + "@codemirror/view": ">=6.0.0", + "codemirror": ">=6.0.0", + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, "node_modules/@uiw/react-markdown-preview": { "version": "5.1.5", "resolved": "https://registry.npmmirror.com/@uiw/react-markdown-preview/-/react-markdown-preview-5.1.5.tgz", @@ -1096,15 +2153,6 @@ "react-dom": ">=16.8.0" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/@babel/runtime": { - "version": "7.28.2", - "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.28.2.tgz", - "integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@uiw/react-markdown-preview/node_modules/react-markdown": { "version": "9.0.3", "resolved": "https://registry.npmmirror.com/react-markdown/-/react-markdown-9.0.3.tgz", @@ -1164,15 +2212,6 @@ "react-dom": ">=16.8.0" } }, - "node_modules/@uiw/react-md-editor/node_modules/@babel/runtime": { - "version": "7.28.2", - "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.28.2.tgz", - "integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", "resolved": "https://registry.npmmirror.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", @@ -1233,9 +2272,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -1338,18 +2377,18 @@ }, "node_modules/asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, "node_modules/axios": { - "version": "1.11.0", - "resolved": "https://registry.npmmirror.com/axios/-/axios-1.11.0.tgz", - "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", + "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, @@ -1441,7 +2480,7 @@ }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { @@ -1614,6 +2653,21 @@ "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", "license": "MIT" }, + "node_modules/codemirror": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz", + "integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", @@ -1636,7 +2690,7 @@ }, "node_modules/combined-stream": { "version": "1.0.8", - "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "license": "MIT", "dependencies": { @@ -1686,12 +2740,16 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", "license": "MIT", "engines": { "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/copy-to-clipboard": { @@ -1715,6 +2773,12 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -2253,7 +3317,7 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "license": "MIT", "engines": { @@ -2337,9 +3401,9 @@ } }, "node_modules/dompurify": { - "version": "3.2.6", - "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.2.6.tgz", - "integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz", + "integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==", "license": "(MPL-2.0 OR Apache-2.0)", "optional": true, "optionalDependencies": { @@ -2362,7 +3426,7 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "dependencies": { @@ -2408,7 +3472,7 @@ }, "node_modules/es-define-property": { "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "engines": { @@ -2417,7 +3481,7 @@ }, "node_modules/es-errors": { "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "license": "MIT", "engines": { @@ -2426,7 +3490,7 @@ }, "node_modules/es-object-atoms": { "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "dependencies": { @@ -2438,7 +3502,7 @@ }, "node_modules/es-set-tostringtag": { "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "license": "MIT", "dependencies": { @@ -2452,9 +3516,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.8", - "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.8.tgz", - "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", + "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2465,32 +3529,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.8", - "@esbuild/android-arm": "0.25.8", - "@esbuild/android-arm64": "0.25.8", - "@esbuild/android-x64": "0.25.8", - "@esbuild/darwin-arm64": "0.25.8", - "@esbuild/darwin-x64": "0.25.8", - "@esbuild/freebsd-arm64": "0.25.8", - "@esbuild/freebsd-x64": "0.25.8", - "@esbuild/linux-arm": "0.25.8", - "@esbuild/linux-arm64": "0.25.8", - "@esbuild/linux-ia32": "0.25.8", - "@esbuild/linux-loong64": "0.25.8", - "@esbuild/linux-mips64el": "0.25.8", - "@esbuild/linux-ppc64": "0.25.8", - "@esbuild/linux-riscv64": "0.25.8", - "@esbuild/linux-s390x": "0.25.8", - "@esbuild/linux-x64": "0.25.8", - "@esbuild/netbsd-arm64": "0.25.8", - "@esbuild/netbsd-x64": "0.25.8", - "@esbuild/openbsd-arm64": "0.25.8", - "@esbuild/openbsd-x64": "0.25.8", - "@esbuild/openharmony-arm64": "0.25.8", - "@esbuild/sunos-x64": "0.25.8", - "@esbuild/win32-arm64": "0.25.8", - "@esbuild/win32-ia32": "0.25.8", - "@esbuild/win32-x64": "0.25.8" + "@esbuild/aix-ppc64": "0.27.4", + "@esbuild/android-arm": "0.27.4", + "@esbuild/android-arm64": "0.27.4", + "@esbuild/android-x64": "0.27.4", + "@esbuild/darwin-arm64": "0.27.4", + "@esbuild/darwin-x64": "0.27.4", + "@esbuild/freebsd-arm64": "0.27.4", + "@esbuild/freebsd-x64": "0.27.4", + "@esbuild/linux-arm": "0.27.4", + "@esbuild/linux-arm64": "0.27.4", + "@esbuild/linux-ia32": "0.27.4", + "@esbuild/linux-loong64": "0.27.4", + "@esbuild/linux-mips64el": "0.27.4", + "@esbuild/linux-ppc64": "0.27.4", + "@esbuild/linux-riscv64": "0.27.4", + "@esbuild/linux-s390x": "0.27.4", + "@esbuild/linux-x64": "0.27.4", + "@esbuild/netbsd-arm64": "0.27.4", + "@esbuild/netbsd-x64": "0.27.4", + "@esbuild/openbsd-arm64": "0.27.4", + "@esbuild/openbsd-x64": "0.27.4", + "@esbuild/openharmony-arm64": "0.27.4", + "@esbuild/sunos-x64": "0.27.4", + "@esbuild/win32-arm64": "0.27.4", + "@esbuild/win32-ia32": "0.27.4", + "@esbuild/win32-x64": "0.27.4" } }, "node_modules/escalade": { @@ -2743,11 +3807,14 @@ } }, "node_modules/fdir": { - "version": "6.4.6", - "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.4.6.tgz", - "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, "peerDependencies": { "picomatch": "^3 || ^4" }, @@ -2808,16 +3875,16 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmmirror.com/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "funding": [ { "type": "individual", @@ -2835,9 +3902,9 @@ } }, "node_modules/form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -2866,7 +3933,7 @@ }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", "funding": { @@ -2885,7 +3952,7 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { @@ -2909,7 +3976,7 @@ }, "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { @@ -2954,7 +4021,7 @@ }, "node_modules/gopd": { "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", "engines": { @@ -2976,7 +4043,7 @@ }, "node_modules/has-symbols": { "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { @@ -2988,7 +4055,7 @@ }, "node_modules/has-tostringtag": { "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "license": "MIT", "dependencies": { @@ -3003,7 +4070,7 @@ }, "node_modules/hasown": { "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", "dependencies": { @@ -3587,9 +4654,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -3656,31 +4723,22 @@ } }, "node_modules/jspdf": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/jspdf/-/jspdf-3.0.2.tgz", - "integrity": "sha512-G0fQDJ5fAm6UW78HG6lNXyq09l0PrA1rpNY5i+ly17Zb1fMMFSmS+3lw4cnrAPGyouv2Y0ylujbY2Ieq3DSlKA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-4.2.1.tgz", + "integrity": "sha512-YyAXyvnmjTbR4bHQRLzex3CuINCDlQnBqoSYyjJwTP2x9jDLuKDzy7aKUl0hgx3uhcl7xzg32agn5vlie6HIlQ==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.26.9", + "@babel/runtime": "^7.28.6", "fast-png": "^6.2.0", "fflate": "^0.8.1" }, "optionalDependencies": { "canvg": "^3.0.11", "core-js": "^3.6.0", - "dompurify": "^3.2.4", + "dompurify": "^3.3.1", "html2canvas": "^1.0.0-rc.5" } }, - "node_modules/jspdf/node_modules/@babel/runtime": { - "version": "7.28.3", - "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.28.3.tgz", - "integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/jspdf/node_modules/canvg": { "version": "3.0.11", "resolved": "https://registry.npmmirror.com/canvg/-/canvg-3.0.11.tgz", @@ -3793,19 +4851,10 @@ "yallist": "^3.0.2" } }, - "node_modules/lucide-react": { - "version": "0.294.0", - "resolved": "https://registry.npmmirror.com/lucide-react/-/lucide-react-0.294.0.tgz", - "integrity": "sha512-V7o0/VECSGbLHn3/1O67FUgBwWB+hmzshrgDVRJQhMh8uj5D3HBuIvhuAmQTtlupILSplwIZg5FTc4tTKMA2SA==", - "license": "ISC", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/markdown-it": { - "version": "14.1.0", - "resolved": "https://registry.npmmirror.com/markdown-it/-/markdown-it-14.1.0.tgz", - "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", "license": "MIT", "dependencies": { "argparse": "^2.0.1", @@ -3916,7 +4965,7 @@ }, "node_modules/math-intrinsics": { "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", "engines": { @@ -4151,9 +5200,9 @@ } }, "node_modules/mdast-util-to-hast": { - "version": "13.2.0", - "resolved": "https://registry.npmmirror.com/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", - "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -4776,7 +5825,7 @@ }, "node_modules/mime-db": { "version": "1.52.0", - "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", "engines": { @@ -4785,7 +5834,7 @@ }, "node_modules/mime-types": { "version": "2.1.35", - "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", "dependencies": { @@ -4796,9 +5845,9 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -5048,9 +6097,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -5832,9 +6881,9 @@ } }, "node_modules/react-router": { - "version": "7.7.1", - "resolved": "https://registry.npmmirror.com/react-router/-/react-router-7.7.1.tgz", - "integrity": "sha512-jVKHXoWRIsD/qS6lvGveckwb862EekvapdHJN/cGmzw40KnJH5gg53ujOJ4qX6EKIK9LSBfFed/xiQ5yeXNrUA==", + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.2.tgz", + "integrity": "sha512-tX1Aee+ArlKQP+NIUd7SE6Li+CiGKwQtbS+FfRxPX6Pe4vHOo6nr9d++u5cwg+Z8K/x8tP+7qLmujDtfrAoUJA==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -5854,12 +6903,12 @@ } }, "node_modules/react-router-dom": { - "version": "7.7.1", - "resolved": "https://registry.npmmirror.com/react-router-dom/-/react-router-dom-7.7.1.tgz", - "integrity": "sha512-bavdk2BA5r3MYalGKZ01u8PGuDBloQmzpBZVhDLrOOv1N943Wq6dcM9GhB3x8b7AbqPMEezauv4PeGkAJfy7FQ==", + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.2.tgz", + "integrity": "sha512-aR7SUORwTqAW0JDeiWF07e9SBE9qGpByR9I8kJT5h/FrBKxPMS6TiC7rmVO+gC0q52Bx7JnjWe8Z1sR9faN4YA==", "license": "MIT", "dependencies": { - "react-router": "7.7.1" + "react-router": "7.13.2" }, "engines": { "node": ">=20.0.0" @@ -6194,9 +7243,9 @@ "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.46.1", - "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.46.1.tgz", - "integrity": "sha512-33xGNBsDJAkzt0PvninskHlWnTIPgDtTwhg0U38CUoNP/7H6wI2Cz6dUeoNPbjdTdsYTGuiFFASuUOWovH0SyQ==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.0.tgz", + "integrity": "sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6210,26 +7259,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.46.1", - "@rollup/rollup-android-arm64": "4.46.1", - "@rollup/rollup-darwin-arm64": "4.46.1", - "@rollup/rollup-darwin-x64": "4.46.1", - "@rollup/rollup-freebsd-arm64": "4.46.1", - "@rollup/rollup-freebsd-x64": "4.46.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.46.1", - "@rollup/rollup-linux-arm-musleabihf": "4.46.1", - "@rollup/rollup-linux-arm64-gnu": "4.46.1", - "@rollup/rollup-linux-arm64-musl": "4.46.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.46.1", - "@rollup/rollup-linux-ppc64-gnu": "4.46.1", - "@rollup/rollup-linux-riscv64-gnu": "4.46.1", - "@rollup/rollup-linux-riscv64-musl": "4.46.1", - "@rollup/rollup-linux-s390x-gnu": "4.46.1", - "@rollup/rollup-linux-x64-gnu": "4.46.1", - "@rollup/rollup-linux-x64-musl": "4.46.1", - "@rollup/rollup-win32-arm64-msvc": "4.46.1", - "@rollup/rollup-win32-ia32-msvc": "4.46.1", - "@rollup/rollup-win32-x64-msvc": "4.46.1", + "@rollup/rollup-android-arm-eabi": "4.60.0", + "@rollup/rollup-android-arm64": "4.60.0", + "@rollup/rollup-darwin-arm64": "4.60.0", + "@rollup/rollup-darwin-x64": "4.60.0", + "@rollup/rollup-freebsd-arm64": "4.60.0", + "@rollup/rollup-freebsd-x64": "4.60.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.0", + "@rollup/rollup-linux-arm-musleabihf": "4.60.0", + "@rollup/rollup-linux-arm64-gnu": "4.60.0", + "@rollup/rollup-linux-arm64-musl": "4.60.0", + "@rollup/rollup-linux-loong64-gnu": "4.60.0", + "@rollup/rollup-linux-loong64-musl": "4.60.0", + "@rollup/rollup-linux-ppc64-gnu": "4.60.0", + "@rollup/rollup-linux-ppc64-musl": "4.60.0", + "@rollup/rollup-linux-riscv64-gnu": "4.60.0", + "@rollup/rollup-linux-riscv64-musl": "4.60.0", + "@rollup/rollup-linux-s390x-gnu": "4.60.0", + "@rollup/rollup-linux-x64-gnu": "4.60.0", + "@rollup/rollup-linux-x64-musl": "4.60.0", + "@rollup/rollup-openbsd-x64": "4.60.0", + "@rollup/rollup-openharmony-arm64": "4.60.0", + "@rollup/rollup-win32-arm64-msvc": "4.60.0", + "@rollup/rollup-win32-ia32-msvc": "4.60.0", + "@rollup/rollup-win32-x64-gnu": "4.60.0", + "@rollup/rollup-win32-x64-msvc": "4.60.0", "fsevents": "~2.3.2" } }, @@ -6271,9 +7325,9 @@ } }, "node_modules/set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmmirror.com/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", "license": "MIT" }, "node_modules/shebang-command": { @@ -6361,6 +7415,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-mod": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", + "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==", + "license": "MIT" + }, "node_modules/style-to-js": { "version": "1.1.17", "resolved": "https://registry.npmmirror.com/style-to-js/-/style-to-js-1.1.17.tgz", @@ -6426,14 +7486,14 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.14", - "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.14.tgz", - "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, "license": "MIT", "dependencies": { - "fdir": "^6.4.4", - "picomatch": "^4.0.2" + "fdir": "^6.5.0", + "picomatch": "^4.0.3" }, "engines": { "node": ">=12.0.0" @@ -6488,9 +7548,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "6.21.3", - "resolved": "https://registry.npmmirror.com/undici/-/undici-6.21.3.tgz", - "integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==", + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", + "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", "license": "MIT", "engines": { "node": ">=18.17" @@ -6687,18 +7747,18 @@ } }, "node_modules/vite": { - "version": "7.0.6", - "resolved": "https://registry.npmmirror.com/vite/-/vite-7.0.6.tgz", - "integrity": "sha512-MHFiOENNBd+Bd9uvc8GEsIzdkn1JxMmEeYX35tI3fv0sJBUTfW5tQsoaOwuY4KhBI09A3dUJ/DXf2yxPVPUceg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.6", + "esbuild": "^0.27.0", + "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", - "rollup": "^4.40.0", - "tinyglobby": "^0.2.14" + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" @@ -6761,6 +7821,12 @@ } } }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + }, "node_modules/web-namespaces": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/web-namespaces/-/web-namespaces-2.0.1.tgz", @@ -6826,15 +7892,18 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yocto-queue": { diff --git a/frontend/package.json b/frontend/package.json index 44967f7..e686dd9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "@ant-design/v5-patch-for-react-19": "^1.0.3", "@codemirror/lang-markdown": "^6.5.0", "@codemirror/state": "^6.5.2", "@codemirror/view": "^6.38.6", @@ -19,7 +20,7 @@ "axios": "^1.6.2", "canvg": "^4.0.3", "html2canvas": "^1.4.1", - "jspdf": "^3.0.2", + "jspdf": "^4.2.1", "markmap-common": "^0.18.9", "markmap-lib": "^0.18.12", "markmap-view": "^0.18.12", diff --git a/frontend/src/components/ContentViewer.jsx b/frontend/src/components/ContentViewer.jsx index d7e4723..36d7f2a 100644 --- a/frontend/src/components/ContentViewer.jsx +++ b/frontend/src/components/ContentViewer.jsx @@ -23,7 +23,7 @@ const ContentViewer = ({ if (!content) { return ( - + ); @@ -59,7 +59,7 @@ const ContentViewer = ({ ]; return ( - + { const [drawerOpen, setDrawerOpen] = useState(false); const [openKeys, setOpenKeys] = useState([]); const [activeMenuKey, setActiveMenuKey] = useState(null); + const [branding, setBranding] = useState(DEFAULT_BRANDING_CONFIG); const navigate = useNavigate(); const location = useLocation(); const screens = useBreakpoint(); @@ -40,6 +42,10 @@ const MainLayout = ({ children, user, onLogout }) => { fetchMenus(); }, []); + useEffect(() => { + configService.getBrandingConfig().then(setBranding).catch(() => {}); + }, []); + useEffect(() => { if (isMobile) { setCollapsed(false); @@ -267,8 +273,8 @@ const MainLayout = ({ children, user, onLogout }) => { {!collapsed && (
-
iMeeting
-
智能会议控制台
+
{branding.app_name}
+
{branding.console_subtitle}
)} {!isMobile && ( diff --git a/frontend/src/components/MarkdownEditor.jsx b/frontend/src/components/MarkdownEditor.jsx index 41a424e..ca2cbfb 100644 --- a/frontend/src/components/MarkdownEditor.jsx +++ b/frontend/src/components/MarkdownEditor.jsx @@ -92,8 +92,8 @@ const MarkdownEditor = ({
} size={4}> @@ -132,7 +132,7 @@ const MarkdownEditor = ({ {showPreview ? ( - + ) : ( diff --git a/frontend/src/components/MeetingFormDrawer.jsx b/frontend/src/components/MeetingFormDrawer.jsx index 632fd92..e303fa1 100644 --- a/frontend/src/components/MeetingFormDrawer.jsx +++ b/frontend/src/components/MeetingFormDrawer.jsx @@ -7,7 +7,7 @@ import { buildApiUrl, API_ENDPOINTS } from '../config/api'; const { TextArea } = Input; -const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null, user }) => { +const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null }) => { const { message } = App.useApp(); const [form] = Form.useForm(); const [loading, setLoading] = useState(false); @@ -47,7 +47,7 @@ const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null, user }) form.setFieldsValue({ title: meeting.title, meeting_time: dayjs(meeting.meeting_time), - attendees: meeting.attendees?.map((a) => (typeof a === 'string' ? a : a.caption)) || [], + attendee_ids: meeting.attendee_ids || meeting.attendees?.map((a) => a.user_id).filter(Boolean) || [], prompt_id: meeting.prompt_id, tags: meeting.tags?.map((t) => t.name) || [], description: meeting.description, @@ -66,7 +66,7 @@ const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null, user }) const payload = { ...values, meeting_time: values.meeting_time.format('YYYY-MM-DD HH:mm:ss'), - attendees: values.attendees?.join(',') || '', + attendee_ids: values.attendee_ids || [], tags: values.tags?.join(',') || '', }; @@ -74,7 +74,6 @@ const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null, user }) await apiClient.put(buildApiUrl(API_ENDPOINTS.MEETINGS.UPDATE(meetingId)), payload); message.success('会议更新成功'); } else { - payload.creator_id = user.user_id; const res = await apiClient.post(buildApiUrl(API_ENDPOINTS.MEETINGS.CREATE), payload); if (res.code === '200') { message.success('会议创建成功'); @@ -87,7 +86,7 @@ const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null, user }) onClose(); } catch (error) { if (!error?.errorFields) { - message.error(error?.response?.data?.message || '操作失败'); + message.error(error?.response?.data?.message || error?.response?.data?.detail || '操作失败'); } } finally { setLoading(false); @@ -127,10 +126,10 @@ const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null, user }) - + diff --git a/frontend/src/components/QRCodeModal.jsx b/frontend/src/components/QRCodeModal.jsx index eb747a3..aa9cb55 100644 --- a/frontend/src/components/QRCodeModal.jsx +++ b/frontend/src/components/QRCodeModal.jsx @@ -5,7 +5,7 @@ import { QRCodeSVG } from 'qrcode.react'; const { Text, Paragraph } = Typography; -const QRCodeModal = ({ open, onClose, url, title = "扫描二维码分享" }) => { +const QRCodeModal = ({ open, onClose, url, title = "扫描二维码分享", children }) => { const { message } = App.useApp(); const handleCopy = () => { @@ -43,6 +43,11 @@ const QRCodeModal = ({ open, onClose, url, title = "扫描二维码分享" }) =>
{url}
+ {children ? ( +
+ {children} +
+ ) : null}
); diff --git a/frontend/src/config/api.js b/frontend/src/config/api.js index e0cb4e3..51d6ddd 100644 --- a/frontend/src/config/api.js +++ b/frontend/src/config/api.js @@ -36,6 +36,8 @@ const API_CONFIG = { UPLOAD_IMAGE: (meetingId) => `/api/meetings/${meetingId}/upload-image`, REGENERATE_SUMMARY: (meetingId) => `/api/meetings/${meetingId}/regenerate-summary`, NAVIGATION: (meetingId) => `/api/meetings/${meetingId}/navigation`, + ACCESS_PASSWORD: (meetingId) => `/api/meetings/${meetingId}/access-password`, + PREVIEW_DATA: (meetingId) => `/api/meetings/${meetingId}/preview-data`, LLM_MODELS: '/api/llm-models/active' }, ADMIN: { @@ -63,6 +65,9 @@ const API_CONFIG = { ITEM_DETAIL: (id) => `/api/admin/hot-word-items/${id}`, } }, + PUBLIC: { + SYSTEM_CONFIG: '/api/system-config/public', + }, TAGS: { LIST: '/api/tags' }, diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx index 81a054e..e99eecf 100644 --- a/frontend/src/main.jsx +++ b/frontend/src/main.jsx @@ -1,3 +1,4 @@ +import '@ant-design/v5-patch-for-react-19'; import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import { StyleProvider } from '@ant-design/cssinjs'; @@ -13,4 +14,4 @@ createRoot(document.getElementById('root')).render( , -); \ No newline at end of file +); diff --git a/frontend/src/pages/AdminDashboard.jsx b/frontend/src/pages/AdminDashboard.jsx index 3ad0e3c..ec7a5d6 100644 --- a/frontend/src/pages/AdminDashboard.jsx +++ b/frontend/src/pages/AdminDashboard.jsx @@ -341,7 +341,7 @@ const AdminDashboard = () => { - +
用户统计
@@ -356,7 +356,7 @@ const AdminDashboard = () => { - +
会议统计
@@ -371,7 +371,7 @@ const AdminDashboard = () => { - +
存储统计
@@ -386,7 +386,7 @@ const AdminDashboard = () => { - +
服务器资源
diff --git a/frontend/src/pages/ClientDownloadPage.jsx b/frontend/src/pages/ClientDownloadPage.jsx index aa70d21..67953ab 100644 --- a/frontend/src/pages/ClientDownloadPage.jsx +++ b/frontend/src/pages/ClientDownloadPage.jsx @@ -9,7 +9,7 @@ const { Title, Paragraph } = Typography; const ClientDownloadPage = () => { return (
- +
随时随地,开启智能会议 diff --git a/frontend/src/pages/CreateMeeting.jsx b/frontend/src/pages/CreateMeeting.jsx index dc33bfd..60dd3b5 100644 --- a/frontend/src/pages/CreateMeeting.jsx +++ b/frontend/src/pages/CreateMeeting.jsx @@ -17,7 +17,7 @@ import { buildApiUrl, API_ENDPOINTS } from '../config/api'; const { Title, Text } = Typography; const { TextArea } = Input; -const CreateMeeting = ({ user }) => { +const CreateMeeting = () => { const navigate = useNavigate(); const { message } = App.useApp(); const [form] = Form.useForm(); @@ -50,8 +50,7 @@ const CreateMeeting = ({ user }) => { const payload = { ...values, meeting_time: values.meeting_time.format('YYYY-MM-DD HH:mm:ss'), - attendees: values.attendees.join(','), - creator_id: user.user_id + attendee_ids: values.attendee_ids }; const res = await apiClient.post(buildApiUrl(API_ENDPOINTS.MEETINGS.CREATE), payload); if (res.code === '200') { @@ -59,7 +58,7 @@ const CreateMeeting = ({ user }) => { navigate(`/meetings/${res.data.meeting_id}`); } } catch (error) { - message.error(error.response?.data?.message || '创建失败'); + message.error(error.response?.data?.message || error.response?.data?.detail || '创建失败'); } finally { setLoading(false); } @@ -67,7 +66,7 @@ const CreateMeeting = ({ user }) => { return (
- +
diff --git a/frontend/src/pages/MeetingCenterPage.jsx b/frontend/src/pages/MeetingCenterPage.jsx index e24c786..5e06c5f 100644 --- a/frontend/src/pages/MeetingCenterPage.jsx +++ b/frontend/src/pages/MeetingCenterPage.jsx @@ -173,13 +173,13 @@ const MeetingCenterPage = ({ user }) => { }} >
@@ -252,7 +252,7 @@ const MeetingCenterPage = ({ user }) => { return ( navigate(`/meetings/${meeting.meeting_id}`)} style={{ @@ -263,7 +263,7 @@ const MeetingCenterPage = ({ user }) => { position: 'relative', overflow: 'hidden', }} - bodyStyle={{ padding: 0 }} + styles={{ body: { padding: 0 } }} >
{ const [summaryTaskProgress, setSummaryTaskProgress] = useState(0); const [summaryTaskMessage, setSummaryTaskMessage] = useState(''); const [summaryPollInterval, setSummaryPollInterval] = useState(null); + const [activeSummaryTaskId, setActiveSummaryTaskId] = useState(null); const [llmModels, setLlmModels] = useState([]); const [selectedModelCode, setSelectedModelCode] = useState(null); @@ -75,6 +76,9 @@ const MeetingDetails = ({ user }) => { const [showQRModal, setShowQRModal] = useState(false); const [isUploading, setIsUploading] = useState(false); const [playbackRate, setPlaybackRate] = useState(1); + const [accessPasswordEnabled, setAccessPasswordEnabled] = useState(false); + const [accessPasswordDraft, setAccessPasswordDraft] = useState(''); + const [savingAccessPassword, setSavingAccessPassword] = useState(false); // 转录编辑 Drawer const [showTranscriptEditDrawer, setShowTranscriptEditDrawer] = useState(false); @@ -84,9 +88,26 @@ const MeetingDetails = ({ user }) => { // 总结内容编辑(同窗口) const [isEditingSummary, setIsEditingSummary] = useState(false); const [editingSummaryContent, setEditingSummaryContent] = useState(''); + const [inlineSpeakerEdit, setInlineSpeakerEdit] = useState(null); + const [inlineSpeakerEditSegmentId, setInlineSpeakerEditSegmentId] = useState(null); + const [inlineSpeakerValue, setInlineSpeakerValue] = useState(''); + const [inlineSegmentEditId, setInlineSegmentEditId] = useState(null); + const [inlineSegmentValue, setInlineSegmentValue] = useState(''); + const [savingInlineEdit, setSavingInlineEdit] = useState(false); const audioRef = useRef(null); const transcriptRefs = useRef([]); + const isMeetingOwner = user?.user_id === meeting?.creator_id; + const hasUploadedAudio = Boolean(audioUrl); + const isTranscriptionRunning = ['pending', 'processing'].includes(transcriptionStatus?.status); + const summaryDisabledReason = isUploading + ? '音频上传中,暂不允许重新总结' + : !hasUploadedAudio + ? '请先上传音频后再总结' + : isTranscriptionRunning + ? '转录进行中,完成后会自动总结' + : ''; + const isSummaryActionDisabled = isUploading || !hasUploadedAudio || isTranscriptionRunning || summaryLoading; /* ══════════════════ 数据获取 ══════════════════ */ @@ -105,6 +126,11 @@ const MeetingDetails = ({ user }) => { setLoading(true); const response = await apiClient.get(buildApiUrl(API_ENDPOINTS.MEETINGS.DETAIL(meeting_id))); setMeeting(response.data); + if (response.data.prompt_id) { + setSelectedPromptId(response.data.prompt_id); + } + setAccessPasswordEnabled(Boolean(response.data.access_password)); + setAccessPasswordDraft(response.data.access_password || ''); if (response.data.transcription_status) { const ts = response.data.transcription_status; @@ -113,6 +139,17 @@ const MeetingDetails = ({ user }) => { if (['pending', 'processing'].includes(ts.status)) { startStatusPolling(ts.task_id); } + } else { + setTranscriptionStatus(null); + setTranscriptionProgress(0); + } + + if (response.data.llm_status) { + setSummaryTaskProgress(response.data.llm_status.progress || 0); + setSummaryTaskMessage(response.data.llm_status.message || ''); + if (['pending', 'processing'].includes(response.data.llm_status.status)) { + startSummaryPolling(response.data.llm_status.task_id); + } } try { @@ -121,6 +158,7 @@ const MeetingDetails = ({ user }) => { } catch { setAudioUrl(null); } fetchTranscript(); + fetchSummaryHistory(); } catch { message.error('加载会议详情失败'); } finally { @@ -154,7 +192,13 @@ const MeetingDetails = ({ user }) => { setTranscriptionProgress(status.progress || 0); if (['completed', 'failed', 'error', 'cancelled'].includes(status.status)) { clearInterval(interval); - if (status.status === 'completed') fetchTranscript(); + if (status.status === 'completed') { + fetchTranscript(); + fetchMeetingDetails(); + setTimeout(() => { + fetchSummaryHistory(); + }, 1000); + } } } catch { clearInterval(interval); } }, 3000); @@ -173,17 +217,73 @@ const MeetingDetails = ({ user }) => { const fetchLlmModels = async () => { try { const res = await apiClient.get(buildApiUrl(API_ENDPOINTS.MEETINGS.LLM_MODELS)); - const models = res.data.models || []; + const models = Array.isArray(res.data) ? res.data : (res.data?.models || []); setLlmModels(models); const def = models.find(m => m.is_default); if (def) setSelectedModelCode(def.model_code); } catch {} }; + const startSummaryPolling = (taskId, options = {}) => { + const { closeDrawerOnComplete = false } = options; + if (!taskId) return; + if (summaryPollInterval && activeSummaryTaskId === taskId) return; + if (summaryPollInterval) clearInterval(summaryPollInterval); + + setActiveSummaryTaskId(taskId); + setSummaryLoading(true); + + const poll = async () => { + try { + const statusRes = await apiClient.get(buildApiUrl(API_ENDPOINTS.TASKS.SUMMARY_STATUS(taskId))); + const status = statusRes.data; + setSummaryTaskProgress(status.progress || 0); + setSummaryTaskMessage(status.message || ''); + + if (status.status === 'completed') { + clearInterval(interval); + setSummaryPollInterval(null); + setActiveSummaryTaskId(null); + setSummaryLoading(false); + if (closeDrawerOnComplete) { + setShowSummaryDrawer(false); + } + fetchSummaryHistory(); + fetchMeetingDetails(); + } else if (status.status === 'failed') { + clearInterval(interval); + setSummaryPollInterval(null); + setActiveSummaryTaskId(null); + setSummaryLoading(false); + message.error(status.error_message || '生成总结失败'); + } + } catch (error) { + clearInterval(interval); + setSummaryPollInterval(null); + setActiveSummaryTaskId(null); + setSummaryLoading(false); + message.error(error?.response?.data?.message || '获取总结状态失败'); + } + }; + + const interval = setInterval(poll, 3000); + setSummaryPollInterval(interval); + poll(); + }; + const fetchSummaryHistory = async () => { try { const res = await apiClient.get(buildApiUrl(`/api/meetings/${meeting_id}/llm-tasks`)); - setSummaryHistory(res.data.tasks?.filter(t => t.status === 'completed') || []); + const tasks = res.data.tasks || []; + setSummaryHistory(tasks.filter(t => t.status === 'completed')); + const latestRunningTask = tasks.find(t => ['pending', 'processing'].includes(t.status)); + if (latestRunningTask) { + startSummaryPolling(latestRunningTask.task_id); + } else if (!activeSummaryTaskId) { + setSummaryLoading(false); + setSummaryTaskProgress(0); + setSummaryTaskMessage(''); + } } catch {} }; @@ -211,6 +311,12 @@ const MeetingDetails = ({ user }) => { formData.append('audio_file', file); formData.append('meeting_id', meeting_id); formData.append('force_replace', 'true'); + if (meeting?.prompt_id) { + formData.append('prompt_id', String(meeting.prompt_id)); + } + if (selectedModelCode) { + formData.append('model_code', selectedModelCode); + } setIsUploading(true); try { await apiClient.post(buildApiUrl(API_ENDPOINTS.MEETINGS.UPLOAD_AUDIO), formData); @@ -220,10 +326,119 @@ const MeetingDetails = ({ user }) => { finally { setIsUploading(false); } }; + const saveAccessPassword = async () => { + const nextPassword = accessPasswordEnabled ? accessPasswordDraft.trim() : null; + if (accessPasswordEnabled && !nextPassword) { + message.warning('开启访问密码后,请先输入密码'); + return; + } + + setSavingAccessPassword(true); + try { + const res = await apiClient.put( + buildApiUrl(API_ENDPOINTS.MEETINGS.ACCESS_PASSWORD(meeting_id)), + { password: nextPassword } + ); + const savedPassword = res.data?.password || null; + setMeeting((prev) => (prev ? { ...prev, access_password: savedPassword } : prev)); + setAccessPasswordEnabled(Boolean(savedPassword)); + setAccessPasswordDraft(savedPassword || ''); + message.success(res.message || '访问密码已更新'); + } catch (error) { + message.error(error?.response?.data?.message || '访问密码更新失败'); + } finally { + setSavingAccessPassword(false); + } + }; + + const copyAccessPassword = async () => { + if (!accessPasswordDraft) { + message.warning('当前没有可复制的访问密码'); + return; + } + await navigator.clipboard.writeText(accessPasswordDraft); + message.success('访问密码已复制'); + }; + const openAudioUploadPicker = () => { document.getElementById('audio-upload-input')?.click(); }; + const startInlineSpeakerEdit = (speakerId, currentTag, segmentId) => { + setInlineSpeakerEdit(speakerId); + setInlineSpeakerEditSegmentId(`speaker-${speakerId}-${segmentId}`); + setInlineSpeakerValue(currentTag || `发言人 ${speakerId}`); + }; + + const cancelInlineSpeakerEdit = () => { + setInlineSpeakerEdit(null); + setInlineSpeakerEditSegmentId(null); + setInlineSpeakerValue(''); + }; + + const saveInlineSpeakerEdit = async () => { + if (inlineSpeakerEdit == null) return; + const nextTag = inlineSpeakerValue.trim(); + if (!nextTag) { + message.warning('发言人名称不能为空'); + return; + } + setSavingInlineEdit(true); + try { + await apiClient.put(buildApiUrl(`/api/meetings/${meeting_id}/speaker-tags/batch`), { + updates: [{ speaker_id: inlineSpeakerEdit, new_tag: nextTag }] + }); + setTranscript(prev => prev.map(item => ( + item.speaker_id === inlineSpeakerEdit + ? { ...item, speaker_tag: nextTag } + : item + ))); + setSpeakerList(prev => prev.map(item => ( + item.speaker_id === inlineSpeakerEdit + ? { ...item, speaker_tag: nextTag } + : item + ))); + setEditingSpeakers(prev => ({ ...prev, [inlineSpeakerEdit]: nextTag })); + message.success('发言人名称已更新'); + cancelInlineSpeakerEdit(); + } catch (error) { + message.error(error?.response?.data?.message || '更新发言人名称失败'); + } finally { + setSavingInlineEdit(false); + } + }; + + const startInlineSegmentEdit = (segment) => { + setInlineSegmentEditId(segment.segment_id); + setInlineSegmentValue(segment.text_content || ''); + }; + + const cancelInlineSegmentEdit = () => { + setInlineSegmentEditId(null); + setInlineSegmentValue(''); + }; + + const saveInlineSegmentEdit = async () => { + if (inlineSegmentEditId == null) return; + setSavingInlineEdit(true); + try { + await apiClient.put(buildApiUrl(`/api/meetings/${meeting_id}/transcript/batch`), { + updates: [{ segment_id: inlineSegmentEditId, text_content: inlineSegmentValue }] + }); + setTranscript(prev => prev.map(item => ( + item.segment_id === inlineSegmentEditId + ? { ...item, text_content: inlineSegmentValue } + : item + ))); + message.success('转录内容已更新'); + cancelInlineSegmentEdit(); + } catch (error) { + message.error(error?.response?.data?.message || '更新转录内容失败'); + } finally { + setSavingInlineEdit(false); + } + }; + const changePlaybackRate = (nextRate) => { setPlaybackRate(nextRate); if (audioRef.current) { @@ -258,6 +473,18 @@ const MeetingDetails = ({ user }) => { }; const generateSummary = async () => { + if (isUploading) { + message.warning('音频上传中,暂不允许重新总结'); + return; + } + if (!hasUploadedAudio) { + message.warning('请先上传音频后再总结'); + return; + } + if (isTranscriptionRunning) { + message.warning('转录进行中,暂不允许重新总结'); + return; + } setSummaryLoading(true); setSummaryTaskProgress(0); try { @@ -266,29 +493,26 @@ const MeetingDetails = ({ user }) => { prompt_id: selectedPromptId, model_code: selectedModelCode }); - const taskId = res.data.task_id; - const interval = setInterval(async () => { - const statusRes = await apiClient.get(buildApiUrl(API_ENDPOINTS.TASKS.SUMMARY_STATUS(taskId))); - const s = statusRes.data; - setSummaryTaskProgress(s.progress || 0); - setSummaryTaskMessage(s.message); - if (s.status === 'completed') { - clearInterval(interval); - setSummaryLoading(false); - setShowSummaryDrawer(false); - fetchSummaryHistory(); - fetchMeetingDetails(); - } else if (s.status === 'failed') { - clearInterval(interval); - setSummaryLoading(false); - message.error('生成总结失败'); - } - }, 3000); - setSummaryPollInterval(interval); - } catch { setSummaryLoading(false); } + startSummaryPolling(res.data.task_id, { closeDrawerOnComplete: true }); + } catch (error) { + message.error(error?.response?.data?.message || '生成总结失败'); + setSummaryLoading(false); + } }; const openSummaryDrawer = () => { + if (isUploading) { + message.warning('音频上传中,暂不允许重新总结'); + return; + } + if (!hasUploadedAudio) { + message.warning('请先上传音频后再总结'); + return; + } + if (isTranscriptionRunning) { + message.warning('转录进行中,完成后会自动总结'); + return; + } setShowSummaryDrawer(true); fetchSummaryHistory(); }; @@ -374,7 +598,7 @@ const MeetingDetails = ({ user }) => {
{/* ── 标题 Header ── */} {
- + + + + +
- {item.text_content} + {inlineSegmentEditId === item.segment_id ? ( +
e.stopPropagation()}> + setInlineSegmentValue(e.target.value)} + onPressEnter={(e) => { + if (e.ctrlKey || e.metaKey) { + saveInlineSegmentEdit(); + } + }} + /> + + + + +
+ ) : ( + { + e.stopPropagation(); + startInlineSegmentEdit(item); + }} + > + {item.text_content} + + )}
), }; @@ -559,7 +851,7 @@ const MeetingDetails = ({ user }) => { {/* 右列: AI 总结 / 思维导图 */} { {/* 总结生成中进度条 */} {summaryLoading && (
- +
{summaryTaskMessage || 'AI 正在思考中...'} {summaryTaskProgress}% @@ -735,7 +1027,7 @@ const MeetingDetails = ({ user }) => { {/* 生成进度 */} {summaryLoading && ( - +
{summaryTaskMessage || 'AI 正在思考中...'} {summaryTaskProgress}% @@ -864,7 +1156,48 @@ const MeetingDetails = ({ user }) => { )} - setShowQRModal(false)} url={`${window.location.origin}/meetings/preview/${meeting_id}`} /> + setShowQRModal(false)} url={`${window.location.origin}/meetings/preview/${meeting_id}`}> + {isMeetingOwner ? ( + <> + +
+ 访问密码保护 + +
+ {accessPasswordEnabled ? ( + + setAccessPasswordDraft(e.target.value)} + placeholder="请输入访问密码" + /> + + 开启后,访客打开分享链接时需要输入这个密码 + + + + + + + ) : ( + + 关闭后,任何拿到链接的人都可以直接查看预览页 + + + )} + + ) : meeting?.access_password ? ( + <> + + 该分享链接已启用访问密码,密码由会议创建人管理。 + + ) : null} +
setEditDrawerOpen(false)} diff --git a/frontend/src/pages/MeetingPreview.jsx b/frontend/src/pages/MeetingPreview.jsx index 516d315..9cc7a3b 100644 --- a/frontend/src/pages/MeetingPreview.jsx +++ b/frontend/src/pages/MeetingPreview.jsx @@ -1,56 +1,135 @@ -import React, { useState, useEffect } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { useParams, Link } from 'react-router-dom'; -import { - Layout, Card, Typography, Space, Button, - Result, Spin, App, Tag, Divider, Empty, Input -} from 'antd'; -import { - LockOutlined, EyeOutlined, EyeInvisibleOutlined, - CopyOutlined, CheckCircleOutlined, ShareAltOutlined, - PlayCircleFilled, PauseCircleFilled, - HomeOutlined, CalendarOutlined, LoginOutlined -} from '@ant-design/icons'; +import { Layout, Space, Button, App, Tag, Empty, Input, Tabs } from 'antd'; +import { LockOutlined, EyeOutlined, CopyOutlined, ShareAltOutlined, HomeOutlined, UserOutlined, FileTextOutlined, PartitionOutlined, AudioOutlined } from '@ant-design/icons'; import apiClient from '../utils/apiClient'; import { buildApiUrl, API_ENDPOINTS } from '../config/api'; import MarkdownRenderer from '../components/MarkdownRenderer'; -import BrandLogo from '../components/BrandLogo'; +import MindMap from '../components/MindMap'; import tools from '../utils/tools'; +import configService, { DEFAULT_BRANDING_CONFIG } from '../utils/configService'; +import './MeetingPreview.css'; -const { Header, Content } = Layout; -const { Title, Text, Paragraph } = Typography; +const { Content } = Layout; const MeetingPreview = () => { const { meeting_id } = useParams(); const { message } = App.useApp(); + const audioRef = useRef(null); const [meeting, setMeeting] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [password, setPassword] = useState(''); + const [passwordError, setPasswordError] = useState(''); + const [passwordRequired, setPasswordRequired] = useState(false); const [isAuthorized, setIsAuthorized] = useState(false); + const [branding, setBranding] = useState(DEFAULT_BRANDING_CONFIG); + const [transcript, setTranscript] = useState([]); + const [audioUrl, setAudioUrl] = useState(''); + const [activeSegmentIndex, setActiveSegmentIndex] = useState(-1); useEffect(() => { + configService.getBrandingConfig().then(setBranding).catch(() => {}); + }, []); + + useEffect(() => { + setMeeting(null); + setTranscript([]); + setAudioUrl(''); + setActiveSegmentIndex(-1); + setError(null); + setPassword(''); + setPasswordError(''); + setPasswordRequired(false); + setIsAuthorized(false); fetchPreview(); }, [meeting_id]); - const fetchPreview = async (pwd = null) => { + const fetchTranscriptAndAudio = async () => { + const [transcriptRes, audioRes] = await Promise.allSettled([ + apiClient.get(buildApiUrl(API_ENDPOINTS.MEETINGS.TRANSCRIPT(meeting_id))), + apiClient.get(buildApiUrl(API_ENDPOINTS.MEETINGS.AUDIO(meeting_id))), + ]); + + if (transcriptRes.status === 'fulfilled') { + setTranscript(Array.isArray(transcriptRes.value.data) ? transcriptRes.value.data : []); + } else { + setTranscript([]); + } + + if (audioRes.status === 'fulfilled') { + setAudioUrl(buildApiUrl(`${API_ENDPOINTS.MEETINGS.AUDIO(meeting_id)}/stream`)); + } else { + setAudioUrl(''); + } + }; + + const fetchPreview = async (pwd = '') => { setLoading(true); try { - const url = buildApiUrl(`/api/meetings/preview/${meeting_id}${pwd ? `?password=${pwd}` : ''}`); + const endpoint = API_ENDPOINTS.MEETINGS.PREVIEW_DATA(meeting_id); + const url = buildApiUrl(`${endpoint}${pwd ? `?password=${encodeURIComponent(pwd)}` : ''}`); const res = await apiClient.get(url); setMeeting(res.data); setIsAuthorized(true); + setPasswordRequired(false); + setPasswordError(''); setError(null); + await fetchTranscriptAndAudio(); } catch (err) { - if (err.response?.status === 401) { + const responseCode = String(err?.response?.data?.code || ''); + if (responseCode === '401') { + setMeeting(null); setIsAuthorized(false); + setPasswordRequired(true); + setPasswordError(err?.response?.data?.message || ''); + setError(null); } else { - setError('无法加载会议预览'); + setMeeting(null); + setIsAuthorized(false); + setPasswordRequired(false); + setPasswordError(''); + setError(err?.response?.data?.message || '无法加载会议预览'); } } finally { setLoading(false); } }; + const handleCopyLink = async () => { + await navigator.clipboard.writeText(window.location.href); + message.success('分享链接已复制'); + }; + + const handleShare = async () => { + if (navigator.share) { + try { + await navigator.share({ title: meeting?.title || branding.preview_title, url: window.location.href }); + return; + } catch {} + } + await handleCopyLink(); + }; + + const handleTimeUpdate = () => { + if (!audioRef.current || !transcript.length) { + return; + } + const currentMs = audioRef.current.currentTime * 1000; + const index = transcript.findIndex( + (item) => currentMs >= item.start_time_ms && currentMs <= item.end_time_ms, + ); + setActiveSegmentIndex(index); + }; + + const jumpToSegment = (segment) => { + if (!audioRef.current || !segment) { + return; + } + audioRef.current.currentTime = (segment.start_time_ms || 0) / 1000; + audioRef.current.play().catch(() => {}); + }; + const handleVerify = () => { if (!password) { message.warning('请输入访问密码'); @@ -59,62 +138,191 @@ const MeetingPreview = () => { fetchPreview(password); }; - if (loading && !meeting) return
; - - if (!isAuthorized) { + if (loading && !meeting) { return ( -
- - - 此会议受密码保护 - 请输入访问密码以查看会议纪要 - - setPassword(e.target.value)} - onPressEnter={handleVerify} - /> - - -
- -
-
+
+
+
+

正在加载会议预览...

+
); } - if (error) return } />; + if (error) { + return ( +
+
+
⚠️
+

加载失败

+

{error}

+ +
+
+ ); + } + + if (passwordRequired && !isAuthorized) { + return ( +
+
+
+
+ +
+

此会议受密码保护

+

请输入访问密码以查看会议纪要

+
+ { + setPassword(e.target.value); + if (passwordError) { + setPasswordError(''); + } + }} + onPressEnter={handleVerify} + /> +
+ {passwordError ?
{passwordError}
: null} + +
+ +
+
+
+
+ ); + } return ( - -
- - - - -
- - - - {meeting.title} - - {meeting.tags?.map(t => {t.name})} - {tools.formatDateTime(meeting.meeting_time)} - - - - -
- {meeting.summary ? ( - - ) : ( - - )} + + +
+

{meeting.title}

+ +
+

会议信息

+
创建人:{meeting.creator_username || '未知'}
+
会议时间:{tools.formatDateTime(meeting.meeting_time)}
+
参会人员:{meeting.attendees?.length ? meeting.attendees.map((item) => item.caption).join('、') : '未设置'}
+
计算人数:{meeting.attendees_count || meeting.attendees?.length || 0}人
+
总结模板:{meeting.prompt_name || '默认模板'}
+ {meeting.tags?.length ? ( +
+ 标签: + + {meeting.tags.map((tag) => {tag.name})} + +
+ ) : null}
- + +
+ + +
+ +
+ + + 会议总结 + + ), + children: ( +
+ {meeting.summary ? : } +
+ ), + }, + { + key: 'transcript', + label: ( + + + 会议转录 + + ), + children: ( +
+ {audioUrl ? ( +
+
+ ) : null} + {transcript.length ? ( +
+ {transcript.map((segment, index) => ( +
jumpToSegment(segment)} + > +
+ + + {segment.speaker_tag || `发言人 ${segment.speaker_id}`} + + {tools.formatDuration((segment.start_time_ms || 0) / 1000)} +
+
{segment.text_content}
+
+ ))} +
+ ) : ( +
暂无转录内容
+ )} +
+ ), + }, + { + key: 'mindmap', + label: ( + + + 思维导图 + + ), + children: ( +
+ +
+ ), + }, + ]} + /> +
+ +
+ {branding.footer_text} +
+
); diff --git a/frontend/src/pages/PromptConfigPage.jsx b/frontend/src/pages/PromptConfigPage.jsx index ffc11bd..68fe726 100644 --- a/frontend/src/pages/PromptConfigPage.jsx +++ b/frontend/src/pages/PromptConfigPage.jsx @@ -109,7 +109,7 @@ const PromptConfigPage = ({ user }) => { return (
- +
提示词配置 @@ -117,7 +117,7 @@ const PromptConfigPage = ({ user }) => {
- + { items={[ { key: 'config', - label: '提示词配置', + label: '系统提示词配置', children: (
@@ -142,7 +142,7 @@ const PromptConfigPage = ({ user }) => {
- + {availablePrompts.length ? availablePrompts.map((item) => { const isSystem = Number(item.is_system) === 1; @@ -188,7 +188,7 @@ const PromptConfigPage = ({ user }) => { - + {selectedPromptCards.length ? selectedPromptCards.map((item, index) => ( diff --git a/frontend/src/pages/PromptManagementPage.jsx b/frontend/src/pages/PromptManagementPage.jsx index 62f7301..8cbb746 100644 --- a/frontend/src/pages/PromptManagementPage.jsx +++ b/frontend/src/pages/PromptManagementPage.jsx @@ -13,6 +13,7 @@ import { Segmented, Select, Space, + Switch, Tag, Tooltip, Typography, @@ -240,7 +241,7 @@ const PromptManagementPage = ({ user, mode = 'default', embedded = false }) => { return (
{!embedded ? ( - +
{pageTitle} @@ -333,7 +334,7 @@ const PromptManagementPage = ({ user, mode = 'default', embedded = false }) => { )}
) : ( - + {prompts.length ? ( <> diff --git a/frontend/src/pages/admin/DictManagement.jsx b/frontend/src/pages/admin/DictManagement.jsx index d201d2d..9ee4c12 100644 --- a/frontend/src/pages/admin/DictManagement.jsx +++ b/frontend/src/pages/admin/DictManagement.jsx @@ -236,7 +236,7 @@ const DictManagement = () => { 新增 } - bordered={false} + variant="borderless" >
- - ) : ( - - )} + + ) : ( + + )} + diff --git a/frontend/src/pages/admin/ModelManagement.jsx b/frontend/src/pages/admin/ModelManagement.jsx index 2abf685..b1b3175 100644 --- a/frontend/src/pages/admin/ModelManagement.jsx +++ b/frontend/src/pages/admin/ModelManagement.jsx @@ -15,6 +15,7 @@ import { Space, Switch, Table, + Tag, Tabs, } from 'antd'; import { DeleteOutlined, EditOutlined, ExperimentOutlined, PlusOutlined, ReloadOutlined, RobotOutlined, SaveOutlined } from '@ant-design/icons'; diff --git a/frontend/src/pages/admin/PermissionManagement.jsx b/frontend/src/pages/admin/PermissionManagement.jsx index cb08595..24e0900 100644 --- a/frontend/src/pages/admin/PermissionManagement.jsx +++ b/frontend/src/pages/admin/PermissionManagement.jsx @@ -675,7 +675,7 @@ const PermissionManagement = () => { const roleManagementView = ( - +
角色列表 @@ -730,7 +730,7 @@ const PermissionManagement = () => { - + {!selectedRoleId ? ( ) : ( @@ -763,7 +763,7 @@ const PermissionManagement = () => {
- + { {selectedMenuRows.length ? selectedMenuRows.map((menu) => (
@@ -864,7 +864,7 @@ const PermissionManagement = () => { const menuManagementView = ( - + { =6.0.0": + version "6.40.0" + resolved "https://registry.npmjs.org/@codemirror/view/-/view-6.40.0.tgz" + integrity sha512-WA0zdU7xfF10+5I3HhUUq3kqOx3KjqmtQ9lqZjfK7jtYk4G72YW9rezcSywpaUMCWOMlq+6E0pO1IWg1TNIhtg== dependencies: - "@codemirror/state" "^6.5.0" + "@codemirror/state" "^6.6.0" crelt "^1.0.6" style-mod "^4.1.0" w3c-keyname "^2.2.4" @@ -385,135 +380,10 @@ resolved "https://registry.npmmirror.com/@emotion/unitless/-/unitless-0.7.5.tgz" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== -"@esbuild/aix-ppc64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz#a1414903bb38027382f85f03dda6065056757727" - integrity sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA== - -"@esbuild/android-arm64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz#c859994089e9767224269884061f89dae6fb51c6" - integrity sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w== - -"@esbuild/android-arm@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.25.8.tgz#96a8f2ca91c6cd29ea90b1af79d83761c8ba0059" - integrity sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw== - -"@esbuild/android-x64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.25.8.tgz#a3a626c4fec4a024a9fa8c7679c39996e92916f0" - integrity sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA== - -"@esbuild/darwin-arm64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz" - integrity sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw== - -"@esbuild/darwin-x64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz#5271b0df2bb12ce8df886704bfdd1c7cc01385d2" - integrity sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg== - -"@esbuild/freebsd-arm64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz#d0a0e7fdf19733b8bb1566b81df1aa0bb7e46ada" - integrity sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA== - -"@esbuild/freebsd-x64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz#2de8b2e0899d08f1cb1ef3128e159616e7e85343" - integrity sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw== - -"@esbuild/linux-arm64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz#a4209efadc0c2975716458484a4e90c237c48ae9" - integrity sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w== - -"@esbuild/linux-arm@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz#ccd9e291c24cd8d9142d819d463e2e7200d25b19" - integrity sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg== - -"@esbuild/linux-ia32@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz#006ad1536d0c2b28fb3a1cf0b53bcb85aaf92c4d" - integrity sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg== - -"@esbuild/linux-loong64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz#127b3fbfb2c2e08b1397e985932f718f09a8f5c4" - integrity sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ== - -"@esbuild/linux-mips64el@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz#837d1449517791e3fa7d82675a2d06d9f56cb340" - integrity sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw== - -"@esbuild/linux-ppc64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz#aa2e3bd93ab8df084212f1895ca4b03c42d9e0fe" - integrity sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ== - -"@esbuild/linux-riscv64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz#a340620e31093fef72767dd28ab04214b3442083" - integrity sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg== - -"@esbuild/linux-s390x@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz#ddfed266c8c13f5efb3105a0cd47f6dcd0e79e71" - integrity sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg== - -"@esbuild/linux-x64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz#9a4f78c75c051e8c060183ebb39a269ba936a2ac" - integrity sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ== - -"@esbuild/netbsd-arm64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz#902c80e1d678047926387230bc037e63e00697d0" - integrity sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw== - -"@esbuild/netbsd-x64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz#2d9eb4692add2681ff05a14ce99de54fbed7079c" - integrity sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg== - -"@esbuild/openbsd-arm64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz#89c3b998c6de739db38ab7fb71a8a76b3fa84a45" - integrity sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ== - -"@esbuild/openbsd-x64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz#2f01615cf472b0e48c077045cfd96b5c149365cc" - integrity sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ== - -"@esbuild/openharmony-arm64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz#a201f720cd2c3ebf9a6033fcc3feb069a54b509a" - integrity sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg== - -"@esbuild/sunos-x64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz#07046c977985a3334667f19e6ab3a01a80862afb" - integrity sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w== - -"@esbuild/win32-arm64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz#4a5470caf0d16127c05d4833d4934213c69392d1" - integrity sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ== - -"@esbuild/win32-ia32@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz#3de3e8470b7b328d99dbc3e9ec1eace207e5bbc4" - integrity sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg== - -"@esbuild/win32-x64@0.25.8": - version "0.25.8" - resolved "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz#610d7ea539d2fcdbe39237b5cc175eb2c4451f9c" - integrity sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw== +"@esbuild/linux-x64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz" + integrity sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA== "@eslint-community/eslint-utils@^4.2.0": version "4.7.0" @@ -563,7 +433,7 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@9.32.0", "@eslint/js@^9.30.1": +"@eslint/js@^9.30.1", "@eslint/js@9.32.0": version "9.32.0" resolved "https://registry.npmmirror.com/@eslint/js/-/js-9.32.0.tgz" integrity sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg== @@ -642,15 +512,15 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@lezer/common@^1.0.0", "@lezer/common@^1.0.2", "@lezer/common@^1.1.0", "@lezer/common@^1.2.0", "@lezer/common@^1.2.1", "@lezer/common@^1.3.0": - version "1.3.0" - resolved "https://registry.npmmirror.com/@lezer/common/-/common-1.3.0.tgz#123427ec4c53c2c8367415b4441e555b4f85c696" - integrity sha512-L9X8uHCYU310o99L3/MpJKYxPzXPOS7S0NmBaM7UO/x2Kb2WbmMLSkfvdr1KxRIFYOpbY0Jhn7CfLSUDzL8arQ== +"@lezer/common@^1.0.0", "@lezer/common@^1.0.2", "@lezer/common@^1.1.0", "@lezer/common@^1.2.0", "@lezer/common@^1.2.1", "@lezer/common@^1.3.0", "@lezer/common@^1.5.0": + version "1.5.1" + resolved "https://registry.npmjs.org/@lezer/common/-/common-1.5.1.tgz" + integrity sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw== "@lezer/css@^1.1.0", "@lezer/css@^1.1.7": - version "1.3.0" - resolved "https://registry.npmmirror.com/@lezer/css/-/css-1.3.0.tgz#296f298814782c2fad42a936f3510042cdcd2034" - integrity sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw== + version "1.3.3" + resolved "https://registry.npmjs.org/@lezer/css/-/css-1.3.3.tgz" + integrity sha512-RzBo8r+/6QJeow7aPHIpGVIH59xTcJXp399820gZoMo9noQDRVpJLheIBUicYwKcsbOYoBRoLZlf2720dG/4Tg== dependencies: "@lezer/common" "^1.2.0" "@lezer/highlight" "^1.0.0" @@ -658,15 +528,15 @@ "@lezer/highlight@^1.0.0", "@lezer/highlight@^1.1.3": version "1.2.3" - resolved "https://registry.npmmirror.com/@lezer/highlight/-/highlight-1.2.3.tgz#a20f324b71148a2ea9ba6ff42e58bbfaec702857" + resolved "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz" integrity sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g== dependencies: "@lezer/common" "^1.3.0" "@lezer/html@^1.3.12": - version "1.3.12" - resolved "https://registry.npmmirror.com/@lezer/html/-/html-1.3.12.tgz#a438e2d04f4c863d49cad27efe714cde8cf3ff1b" - integrity sha512-RJ7eRWdaJe3bsiiLLHjCFT1JMk8m1YP9kaUbvu2rMLEoOnke9mcTVDyfOslsln0LtujdWespjJ39w6zo+RsQYw== + version "1.3.13" + resolved "https://registry.npmjs.org/@lezer/html/-/html-1.3.13.tgz" + integrity sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg== dependencies: "@lezer/common" "^1.2.0" "@lezer/highlight" "^1.0.0" @@ -674,7 +544,7 @@ "@lezer/javascript@^1.0.0": version "1.5.4" - resolved "https://registry.npmmirror.com/@lezer/javascript/-/javascript-1.5.4.tgz#11746955f957d33c0933f17d7594db54a8b4beea" + resolved "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz" integrity sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA== dependencies: "@lezer/common" "^1.2.0" @@ -682,23 +552,23 @@ "@lezer/lr" "^1.3.0" "@lezer/lr@^1.0.0", "@lezer/lr@^1.3.0": - version "1.4.3" - resolved "https://registry.npmmirror.com/@lezer/lr/-/lr-1.4.3.tgz#51b252ff8ff9fea863819de7f4b6501ccf69d403" - integrity sha512-yenN5SqAxAPv/qMnpWW0AT7l+SxVrgG+u0tNsRQWqbrz66HIl8DnEbBObvy21J5K7+I1v7gsAnlE2VQ5yYVSeA== + version "1.4.8" + resolved "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.8.tgz" + integrity sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA== dependencies: "@lezer/common" "^1.0.0" "@lezer/markdown@^1.0.0": - version "1.6.0" - resolved "https://registry.npmmirror.com/@lezer/markdown/-/markdown-1.6.0.tgz#9db3356d52955391b021cc3ead9c79f87186840f" - integrity sha512-AXb98u3M6BEzTnreBnGtQaF7xFTiMA92Dsy5tqEjpacbjRxDSFdN4bKJo9uvU4cEEOS7D2B9MT7kvDgOEIzJSw== + version "1.6.3" + resolved "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.6.3.tgz" + integrity sha512-jpGm5Ps+XErS+xA4urw7ogEGkeZOahVQF21Z6oECF0sj+2liwZopd2+I8uH5I/vZsRuuze3OxBREIANLf6KKUw== dependencies: - "@lezer/common" "^1.0.0" + "@lezer/common" "^1.5.0" "@lezer/highlight" "^1.0.0" "@marijn/find-cluster-break@^1.0.0": version "1.0.2" - resolved "https://registry.npmmirror.com/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz#775374306116d51c0c500b8c4face0f9a04752d8" + resolved "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz" integrity sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g== "@rc-component/async-validator@^5.0.3": @@ -788,105 +658,15 @@ resolved "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz" integrity sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA== -"@rollup/rollup-android-arm-eabi@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.1.tgz#c659481d5b15054d4636b3dd0c2f50ab3083d839" - integrity sha512-oENme6QxtLCqjChRUUo3S6X8hjCXnWmJWnedD7VbGML5GUtaOtAyx+fEEXnBXVf0CBZApMQU0Idwi0FmyxzQhw== +"@rollup/rollup-linux-x64-gnu@4.60.0": + version "4.60.0" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.0.tgz" + integrity sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg== -"@rollup/rollup-android-arm64@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.1.tgz#7e05c3c0bf6a79ee6b40ab5e778679742f06815d" - integrity sha512-OikvNT3qYTl9+4qQ9Bpn6+XHM+ogtFadRLuT2EXiFQMiNkXFLQfNVppi5o28wvYdHL2s3fM0D/MZJ8UkNFZWsw== - -"@rollup/rollup-darwin-arm64@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.1.tgz" - integrity sha512-EFYNNGij2WllnzljQDQnlFTXzSJw87cpAs4TVBAWLdkvic5Uh5tISrIL6NRcxoh/b2EFBG/TK8hgRrGx94zD4A== - -"@rollup/rollup-darwin-x64@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.1.tgz#a4df7fa06ac318b66a6aa66d6f1e0a58fef58cd3" - integrity sha512-ZaNH06O1KeTug9WI2+GRBE5Ujt9kZw4a1+OIwnBHal92I8PxSsl5KpsrPvthRynkhMck4XPdvY0z26Cym/b7oA== - -"@rollup/rollup-freebsd-arm64@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.1.tgz#6634478a78a0c17dcf55adb621fa66faa58a017b" - integrity sha512-n4SLVebZP8uUlJ2r04+g2U/xFeiQlw09Me5UFqny8HGbARl503LNH5CqFTb5U5jNxTouhRjai6qPT0CR5c/Iig== - -"@rollup/rollup-freebsd-x64@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.1.tgz#db42c46c0263b2562e2ba5c2e00e318646f2b24c" - integrity sha512-8vu9c02F16heTqpvo3yeiu7Vi1REDEC/yES/dIfq3tSXe6mLndiwvYr3AAvd1tMNUqE9yeGYa5w7PRbI5QUV+w== - -"@rollup/rollup-linux-arm-gnueabihf@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.1.tgz#88ca443ad42c70555978b000c6d1dd925fb3203b" - integrity sha512-K4ncpWl7sQuyp6rWiGUvb6Q18ba8mzM0rjWJ5JgYKlIXAau1db7hZnR0ldJvqKWWJDxqzSLwGUhA4jp+KqgDtQ== - -"@rollup/rollup-linux-arm-musleabihf@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.1.tgz#36106fe103d32c2a97583ebadcfb28dc63988bda" - integrity sha512-YykPnXsjUjmXE6j6k2QBBGAn1YsJUix7pYaPLK3RVE0bQL2jfdbfykPxfF8AgBlqtYbfEnYHmLXNa6QETjdOjQ== - -"@rollup/rollup-linux-arm64-gnu@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.1.tgz#00c28bc9210dcfbb5e7fa8e52fd827fb570afe26" - integrity sha512-kKvqBGbZ8i9pCGW3a1FH3HNIVg49dXXTsChGFsHGXQaVJPLA4f/O+XmTxfklhccxdF5FefUn2hvkoGJH0ScWOA== - -"@rollup/rollup-linux-arm64-musl@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.1.tgz#45a13486b5523235eb87b349e7ca5a0bb85a5b0e" - integrity sha512-zzX5nTw1N1plmqC9RGC9vZHFuiM7ZP7oSWQGqpbmfjK7p947D518cVK1/MQudsBdcD84t6k70WNczJOct6+hdg== - -"@rollup/rollup-linux-loongarch64-gnu@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.1.tgz#b8edd99f072cd652acbbddc1c539b1ac4254381d" - integrity sha512-O8CwgSBo6ewPpktFfSDgB6SJN9XDcPSvuwxfejiddbIC/hn9Tg6Ai0f0eYDf3XvB/+PIWzOQL+7+TZoB8p9Yuw== - -"@rollup/rollup-linux-ppc64-gnu@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.1.tgz#0ec72a4f8b7a86b13c0f6b7666ed1d3b6e8e67cc" - integrity sha512-JnCfFVEKeq6G3h3z8e60kAp8Rd7QVnWCtPm7cxx+5OtP80g/3nmPtfdCXbVl063e3KsRnGSKDHUQMydmzc/wBA== - -"@rollup/rollup-linux-riscv64-gnu@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.1.tgz#99f06928528fb58addd12e50827e1a0269c1cca8" - integrity sha512-dVxuDqS237eQXkbYzQQfdf/njgeNw6LZuVyEdUaWwRpKHhsLI+y4H/NJV8xJGU19vnOJCVwaBFgr936FHOnJsQ== - -"@rollup/rollup-linux-riscv64-musl@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.1.tgz#3c14aba63b4170fe3d9d0b6ad98361366170590e" - integrity sha512-CvvgNl2hrZrTR9jXK1ye0Go0HQRT6ohQdDfWR47/KFKiLd5oN5T14jRdUVGF4tnsN8y9oSfMOqH6RuHh+ck8+w== - -"@rollup/rollup-linux-s390x-gnu@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.1.tgz#34c647a823dcdca0f749a2bdcbde4fb131f37a4c" - integrity sha512-x7ANt2VOg2565oGHJ6rIuuAon+A8sfe1IeUx25IKqi49OjSr/K3awoNqr9gCwGEJo9OuXlOn+H2p1VJKx1psxA== - -"@rollup/rollup-linux-x64-gnu@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.1.tgz#3991010418c005e8791c415e7c2072b247157710" - integrity sha512-9OADZYryz/7E8/qt0vnaHQgmia2Y0wrjSSn1V/uL+zw/i7NUhxbX4cHXdEQ7dnJgzYDS81d8+tf6nbIdRFZQoQ== - -"@rollup/rollup-linux-x64-musl@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.1.tgz#f3943e5f284f40ffbcf4a14da9ee2e43d303b462" - integrity sha512-NuvSCbXEKY+NGWHyivzbjSVJi68Xfq1VnIvGmsuXs6TCtveeoDRKutI5vf2ntmNnVq64Q4zInet0UDQ+yMB6tA== - -"@rollup/rollup-win32-arm64-msvc@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.1.tgz#45b5a1d3f0af63f85044913c371d7b0519c913ad" - integrity sha512-mWz+6FSRb82xuUMMV1X3NGiaPFqbLN9aIueHleTZCc46cJvwTlvIh7reQLk4p97dv0nddyewBhwzryBHH7wtPw== - -"@rollup/rollup-win32-ia32-msvc@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.1.tgz#900ef7211d2929e9809f3a044c4e2fd3aa685a0c" - integrity sha512-7Thzy9TMXDw9AU4f4vsLNBxh7/VOKuXi73VH3d/kHGr0tZ3x/ewgL9uC7ojUKmH1/zvmZe2tLapYcZllk3SO8Q== - -"@rollup/rollup-win32-x64-msvc@4.46.1": - version "4.46.1" - resolved "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.1.tgz#932d8696dfef673bee1a1e291a5531d25a6903be" - integrity sha512-7GVB4luhFmGUNXXJhH2jJwZCFB3pIOixv2E3s17GQHBFUOQaISlt7aGcQgqvCaDSxTZJUzlK/QJ1FN8S94MrzQ== +"@rollup/rollup-linux-x64-musl@4.60.0": + version "4.60.0" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.0.tgz" + integrity sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw== "@types/babel__core@^7.20.5": version "7.20.5" @@ -935,7 +715,7 @@ dependencies: "@types/estree" "*" -"@types/estree@*", "@types/estree@1.0.8", "@types/estree@^1.0.0", "@types/estree@^1.0.6": +"@types/estree@*", "@types/estree@^1.0.0", "@types/estree@^1.0.6", "@types/estree@1.0.8": version "1.0.8" resolved "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz" integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== @@ -991,7 +771,7 @@ resolved "https://registry.npmmirror.com/@types/react-dom/-/react-dom-19.1.6.tgz" integrity sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw== -"@types/react@^19.1.8": +"@types/react@^19.0.0", "@types/react@^19.1.8", "@types/react@>=18": version "19.1.8" resolved "https://registry.npmmirror.com/@types/react/-/react-19.1.8.tgz" integrity sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g== @@ -1008,15 +788,20 @@ resolved "https://registry.npmmirror.com/@types/unist/-/unist-3.0.3.tgz" integrity sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q== -"@types/unist@^2", "@types/unist@^2.0.0": +"@types/unist@^2": version "2.0.11" resolved "https://registry.npmmirror.com/@types/unist/-/unist-2.0.11.tgz" integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA== -"@uiw/codemirror-extensions-basic-setup@4.25.3": - version "4.25.3" - resolved "https://registry.npmmirror.com/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.25.3.tgz#6fb28745e7012bfcad0dc5103119487e40a744bc" - integrity sha512-F1doRyD50CWScwGHG2bBUtUpwnOv/zqSnzkZqJcX5YAHQx6Z1CuX8jdnFMH6qktRrPU1tfpNYftTWu3QIoHiMA== +"@types/unist@^2.0.0": + version "2.0.11" + resolved "https://registry.npmmirror.com/@types/unist/-/unist-2.0.11.tgz" + integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA== + +"@uiw/codemirror-extensions-basic-setup@4.25.9": + version "4.25.9" + resolved "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.25.9.tgz" + integrity sha512-QFAqr+pu6lDmNpAlecODcF49TlsrZ0bj15zPzfhiqSDl+Um3EsDLFLppixC7kFLn+rdDM2LTvVjn5CPvefpRgw== dependencies: "@codemirror/autocomplete" "^6.0.0" "@codemirror/commands" "^6.0.0" @@ -1032,15 +817,15 @@ integrity sha512-O2GUHV90Iw2VrSLVLK0OmNIMdZ5fgEg4NhvtwINsX+eZ/Wf6DWD0TdsK9xwV7dNRnK/UI2mQtl0a2/kRgm1m1A== "@uiw/react-codemirror@^4.25.3": - version "4.25.3" - resolved "https://registry.npmmirror.com/@uiw/react-codemirror/-/react-codemirror-4.25.3.tgz#dd61549051d4398068f087858b39f3fc988c7537" - integrity sha512-1wtBZTXPIp8u6F/xjHvsUAYlEeF5Dic4xZBnqJyLzv7o7GjGYEUfSz9Z7bo9aK9GAx2uojG/AuBMfhA4uhvIVQ== + version "4.25.9" + resolved "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.25.9.tgz" + integrity sha512-HftqCBUYShAOH0pGi1CHP8vfm5L8fQ3+0j0VI6lQD6QpK+UBu3J7nxfEN5O/BXMilMNf9ZyFJRvRcuMMOLHMng== dependencies: "@babel/runtime" "^7.18.6" "@codemirror/commands" "^6.1.0" "@codemirror/state" "^6.1.1" "@codemirror/theme-one-dark" "^6.0.0" - "@uiw/codemirror-extensions-basic-setup" "4.25.3" + "@uiw/codemirror-extensions-basic-setup" "4.25.9" codemirror "^6.0.0" "@uiw/react-markdown-preview@^5.0.6": @@ -1101,15 +886,15 @@ acorn-jsx@^5.3.2: resolved "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.15.0: +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.15.0: version "8.15.0" resolved "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz" integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + version "6.14.0" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz" + integrity sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" @@ -1123,7 +908,7 @@ ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -antd@^5.27.3: +antd@^5.27.3, antd@>=5.22.6: version "5.27.3" resolved "https://registry.npmmirror.com/antd/-/antd-5.27.3.tgz" integrity sha512-Jewp1ek1iyqoAyjWyPgzc2kioZ+7S3jh39a+tld/j4ucnuf/cBk4omfyIdhLz49pVNsaEcRp5LtJOSQPFwPgpA== @@ -1185,16 +970,16 @@ argparse@^2.0.1: asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== axios@^1.6.2: - version "1.11.0" - resolved "https://registry.npmmirror.com/axios/-/axios-1.11.0.tgz" - integrity sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA== + version "1.13.6" + resolved "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz" + integrity sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ== dependencies: - follow-redirects "^1.15.6" - form-data "^4.0.4" + follow-redirects "^1.15.11" + form-data "^4.0.5" proxy-from-env "^1.1.0" bail@^2.0.0: @@ -1230,7 +1015,7 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -browserslist@^4.24.0: +browserslist@^4.24.0, "browserslist@>= 4.21.0": version "4.25.1" resolved "https://registry.npmmirror.com/browserslist/-/browserslist-4.25.1.tgz" integrity sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw== @@ -1242,7 +1027,7 @@ browserslist@^4.24.0: call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: version "1.0.2" - resolved "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz" + resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz" integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== dependencies: es-errors "^1.3.0" @@ -1345,14 +1130,14 @@ cheerio@1.0.0: undici "^6.19.5" whatwg-mimetype "^4.0.0" -classnames@2.x, classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1, classnames@^2.3.2, classnames@^2.5.1: +classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1, classnames@^2.3.2, classnames@^2.5.1, classnames@2.x: version "2.5.1" resolved "https://registry.npmmirror.com/classnames/-/classnames-2.5.1.tgz" integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== codemirror@^6.0.0: version "6.0.2" - resolved "https://registry.npmmirror.com/codemirror/-/codemirror-6.0.2.tgz#4d3fea1ad60b6753f97ca835f2f48c6936a8946e" + resolved "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz" integrity sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw== dependencies: "@codemirror/autocomplete" "^6.0.0" @@ -1377,7 +1162,7 @@ color-name@~1.1.4: combined-stream@^1.0.8: version "1.0.8" - resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" @@ -1387,16 +1172,16 @@ comma-separated-tokens@^2.0.0: resolved "https://registry.npmmirror.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz" integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg== -commander@7: - version "7.2.0" - resolved "https://registry.npmmirror.com/commander/-/commander-7.2.0.tgz" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - commander@^8.3.0: version "8.3.0" resolved "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== +commander@7: + version "7.2.0" + resolved "https://registry.npmmirror.com/commander/-/commander-7.2.0.tgz" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + compute-scroll-into-view@^3.0.2: version "3.1.1" resolved "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz" @@ -1413,9 +1198,9 @@ convert-source-map@^2.0.0: integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== cookie@^1.0.1: - version "1.0.2" - resolved "https://registry.npmmirror.com/cookie/-/cookie-1.0.2.tgz" - integrity sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA== + version "1.1.1" + resolved "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz" + integrity sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ== copy-to-clipboard@^3.3.3: version "3.3.3" @@ -1431,7 +1216,7 @@ core-js@^3.6.0, core-js@^3.8.3: crelt@^1.0.5, crelt@^1.0.6: version "1.0.6" - resolved "https://registry.npmmirror.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72" + resolved "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz" integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g== cross-spawn@^7.0.6: @@ -1476,7 +1261,7 @@ csstype@^3.0.2, csstype@^3.1.3: resolved "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== -"d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3, d3-array@^3.2.0: +d3-array@^3.2.0, "d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3: version "3.2.4" resolved "https://registry.npmmirror.com/d3-array/-/d3-array-3.2.4.tgz" integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg== @@ -1592,7 +1377,7 @@ d3-hierarchy@3: dependencies: d3-color "1 - 3" -"d3-path@1 - 3", d3-path@3, d3-path@^3.1.0: +d3-path@^3.1.0, "d3-path@1 - 3", d3-path@3: version "3.1.0" resolved "https://registry.npmmirror.com/d3-path/-/d3-path-3.1.0.tgz" integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ== @@ -1720,7 +1505,7 @@ d3@^7.8.5: d3-transition "3" d3-zoom "3" -dayjs@^1.11.11: +dayjs@^1.11.11, "dayjs@>= 1.x": version "1.11.18" resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.18.tgz" integrity sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA== @@ -1753,7 +1538,7 @@ delaunator@5: delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== dequal@^2.0.0: @@ -1794,10 +1579,10 @@ domhandler@^5.0.2, domhandler@^5.0.3: dependencies: domelementtype "^2.3.0" -dompurify@^3.2.4: - version "3.2.6" - resolved "https://registry.npmmirror.com/dompurify/-/dompurify-3.2.6.tgz" - integrity sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ== +dompurify@^3.3.1: + version "3.3.3" + resolved "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz" + integrity sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA== optionalDependencies: "@types/trusted-types" "^2.0.7" @@ -1812,7 +1597,7 @@ domutils@^3.0.1, domutils@^3.1.0: dunder-proto@^1.0.1: version "1.0.1" - resolved "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz" + resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz" integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== dependencies: call-bind-apply-helpers "^1.0.1" @@ -1844,24 +1629,24 @@ entities@^6.0.0: es-define-property@^1.0.1: version "1.0.1" - resolved "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz" + resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz" integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== es-errors@^1.3.0: version "1.3.0" - resolved "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz" + resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: version "1.1.1" - resolved "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz" + resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz" integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== dependencies: es-errors "^1.3.0" es-set-tostringtag@^2.1.0: version "2.1.0" - resolved "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz" + resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz" integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== dependencies: es-errors "^1.3.0" @@ -1869,37 +1654,37 @@ es-set-tostringtag@^2.1.0: has-tostringtag "^1.0.2" hasown "^2.0.2" -esbuild@^0.25.0: - version "0.25.8" - resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.8.tgz" - integrity sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q== +esbuild@^0.27.0: + version "0.27.4" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz" + integrity sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ== optionalDependencies: - "@esbuild/aix-ppc64" "0.25.8" - "@esbuild/android-arm" "0.25.8" - "@esbuild/android-arm64" "0.25.8" - "@esbuild/android-x64" "0.25.8" - "@esbuild/darwin-arm64" "0.25.8" - "@esbuild/darwin-x64" "0.25.8" - "@esbuild/freebsd-arm64" "0.25.8" - "@esbuild/freebsd-x64" "0.25.8" - "@esbuild/linux-arm" "0.25.8" - "@esbuild/linux-arm64" "0.25.8" - "@esbuild/linux-ia32" "0.25.8" - "@esbuild/linux-loong64" "0.25.8" - "@esbuild/linux-mips64el" "0.25.8" - "@esbuild/linux-ppc64" "0.25.8" - "@esbuild/linux-riscv64" "0.25.8" - "@esbuild/linux-s390x" "0.25.8" - "@esbuild/linux-x64" "0.25.8" - "@esbuild/netbsd-arm64" "0.25.8" - "@esbuild/netbsd-x64" "0.25.8" - "@esbuild/openbsd-arm64" "0.25.8" - "@esbuild/openbsd-x64" "0.25.8" - "@esbuild/openharmony-arm64" "0.25.8" - "@esbuild/sunos-x64" "0.25.8" - "@esbuild/win32-arm64" "0.25.8" - "@esbuild/win32-ia32" "0.25.8" - "@esbuild/win32-x64" "0.25.8" + "@esbuild/aix-ppc64" "0.27.4" + "@esbuild/android-arm" "0.27.4" + "@esbuild/android-arm64" "0.27.4" + "@esbuild/android-x64" "0.27.4" + "@esbuild/darwin-arm64" "0.27.4" + "@esbuild/darwin-x64" "0.27.4" + "@esbuild/freebsd-arm64" "0.27.4" + "@esbuild/freebsd-x64" "0.27.4" + "@esbuild/linux-arm" "0.27.4" + "@esbuild/linux-arm64" "0.27.4" + "@esbuild/linux-ia32" "0.27.4" + "@esbuild/linux-loong64" "0.27.4" + "@esbuild/linux-mips64el" "0.27.4" + "@esbuild/linux-ppc64" "0.27.4" + "@esbuild/linux-riscv64" "0.27.4" + "@esbuild/linux-s390x" "0.27.4" + "@esbuild/linux-x64" "0.27.4" + "@esbuild/netbsd-arm64" "0.27.4" + "@esbuild/netbsd-x64" "0.27.4" + "@esbuild/openbsd-arm64" "0.27.4" + "@esbuild/openbsd-x64" "0.27.4" + "@esbuild/openharmony-arm64" "0.27.4" + "@esbuild/sunos-x64" "0.27.4" + "@esbuild/win32-arm64" "0.27.4" + "@esbuild/win32-ia32" "0.27.4" + "@esbuild/win32-x64" "0.27.4" escalade@^3.2.0: version "3.2.0" @@ -1944,7 +1729,7 @@ eslint-visitor-keys@^4.2.1: resolved "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz" integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== -eslint@^9.30.1: +"eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", eslint@^9.30.1, eslint@>=8.40: version "9.32.0" resolved "https://registry.npmmirror.com/eslint/-/eslint-9.32.0.tgz" integrity sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg== @@ -2052,10 +1837,10 @@ fast-png@^6.2.0: iobuffer "^5.3.2" pako "^2.1.0" -fdir@^6.4.4, fdir@^6.4.6: - version "6.4.6" - resolved "https://registry.npmmirror.com/fdir/-/fdir-6.4.6.tgz" - integrity sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w== +fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== fflate@^0.8.1: version "0.8.2" @@ -2086,19 +1871,19 @@ flat-cache@^4.0.0: keyv "^4.5.4" flatted@^3.2.9: - version "3.3.3" - resolved "https://registry.npmmirror.com/flatted/-/flatted-3.3.3.tgz" - integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== + version "3.4.2" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz" + integrity sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA== -follow-redirects@^1.15.6: - version "1.15.9" - resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz" - integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== +follow-redirects@^1.15.11: + version "1.15.11" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz" + integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ== -form-data@^4.0.4: - version "4.0.4" - resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.4.tgz" - integrity sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow== +form-data@^4.0.5: + version "4.0.5" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz" + integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" @@ -2106,14 +1891,9 @@ form-data@^4.0.4: hasown "^2.0.2" mime-types "^2.1.12" -fsevents@~2.3.2, fsevents@~2.3.3: - version "2.3.3" - resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - function-bind@^1.1.2: version "1.1.2" - resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== gensync@^1.0.0-beta.2: @@ -2123,7 +1903,7 @@ gensync@^1.0.0-beta.2: get-intrinsic@^1.2.6: version "1.3.0" - resolved "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz" integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== dependencies: call-bind-apply-helpers "^1.0.2" @@ -2139,7 +1919,7 @@ get-intrinsic@^1.2.6: get-proto@^1.0.1: version "1.0.1" - resolved "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz" + resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz" integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== dependencies: dunder-proto "^1.0.1" @@ -2169,7 +1949,7 @@ globals@^16.3.0: gopd@^1.2.0: version "1.2.0" - resolved "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz" integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== has-flag@^4.0.0: @@ -2179,19 +1959,19 @@ has-flag@^4.0.0: has-symbols@^1.0.3, has-symbols@^1.1.0: version "1.1.0" - resolved "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz" integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== has-tostringtag@^1.0.2: version "1.0.2" - resolved "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz" integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: has-symbols "^1.0.3" hasown@^2.0.2: version "2.0.2" - resolved "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" @@ -2426,7 +2206,7 @@ htmlparser2@^9.1.0: domutils "^3.1.0" entities "^4.5.0" -iconv-lite@0.6, iconv-lite@0.6.3, iconv-lite@^0.6.3: +iconv-lite@^0.6.3, iconv-lite@0.6, iconv-lite@0.6.3: version "0.6.3" resolved "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== @@ -2517,9 +2297,9 @@ js-tokens@^4.0.0: integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + version "4.1.1" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== dependencies: argparse "^2.0.1" @@ -2555,18 +2335,18 @@ json5@^2.2.3: resolved "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jspdf@^3.0.2: - version "3.0.2" - resolved "https://registry.npmmirror.com/jspdf/-/jspdf-3.0.2.tgz" - integrity sha512-G0fQDJ5fAm6UW78HG6lNXyq09l0PrA1rpNY5i+ly17Zb1fMMFSmS+3lw4cnrAPGyouv2Y0ylujbY2Ieq3DSlKA== +jspdf@^4.2.1: + version "4.2.1" + resolved "https://registry.npmjs.org/jspdf/-/jspdf-4.2.1.tgz" + integrity sha512-YyAXyvnmjTbR4bHQRLzex3CuINCDlQnBqoSYyjJwTP2x9jDLuKDzy7aKUl0hgx3uhcl7xzg32agn5vlie6HIlQ== dependencies: - "@babel/runtime" "^7.26.9" + "@babel/runtime" "^7.28.6" fast-png "^6.2.0" fflate "^0.8.1" optionalDependencies: canvg "^3.0.11" core-js "^3.6.0" - dompurify "^3.2.4" + dompurify "^3.3.1" html2canvas "^1.0.0-rc.5" katex@^0.16.4, katex@^0.16.8: @@ -2622,11 +2402,6 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lucide-react@^0.294.0: - version "0.294.0" - resolved "https://registry.npmmirror.com/lucide-react/-/lucide-react-0.294.0.tgz" - integrity sha512-V7o0/VECSGbLHn3/1O67FUgBwWB+hmzshrgDVRJQhMh8uj5D3HBuIvhuAmQTtlupILSplwIZg5FTc4tTKMA2SA== - markdown-it-ins@^4.0.0: version "4.0.0" resolved "https://registry.npmmirror.com/markdown-it-ins/-/markdown-it-ins-4.0.0.tgz" @@ -2648,9 +2423,9 @@ markdown-it-sup@^2.0.0: integrity sha512-5VgmdKlkBd8sgXuoDoxMpiU+BiEt3I49GItBzzw7Mxq9CxvnhE/k09HFli09zgfFDRixDQDfDxi0mgBCXtaTvA== markdown-it@^14.1.0: - version "14.1.0" - resolved "https://registry.npmmirror.com/markdown-it/-/markdown-it-14.1.0.tgz" - integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg== + version "14.1.1" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz" + integrity sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA== dependencies: argparse "^2.0.1" entities "^4.4.0" @@ -2664,7 +2439,7 @@ markdown-table@^3.0.0: resolved "https://registry.npmmirror.com/markdown-table/-/markdown-table-3.0.4.tgz" integrity sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw== -markmap-common@^0.18.9: +markmap-common@*, markmap-common@^0.18.9: version "0.18.9" resolved "https://registry.npmmirror.com/markmap-common/-/markmap-common-0.18.9.tgz" integrity sha512-MV2HQO7IGIm3jWEJXSG8vmdpqf4WIDXcEyAEN52lrWR1qD53Zg5l81JwjXoZ2l0rY5mofKYqUFlmdM2fqTGMVg== @@ -2700,7 +2475,7 @@ markmap-lib@^0.18.12: prismjs "^1.29.0" yaml "^2.5.1" -markmap-view@0.18.12, markmap-view@^0.18.12: +markmap-view@^0.18.12, markmap-view@0.18.12: version "0.18.12" resolved "https://registry.npmmirror.com/markmap-view/-/markmap-view-0.18.12.tgz" integrity sha512-D8bzT1YwIC/8rkbwm6WzigVUrpOAGv7ioEGTi1Lj+Oo8gO5sAm6hhli27jvTgUcZ9TwBeIWZ+dSUP+AupYUGlQ== @@ -2710,7 +2485,7 @@ markmap-view@0.18.12, markmap-view@^0.18.12: math-intrinsics@^1.1.0: version "1.1.0" - resolved "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz" + resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz" integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== mdast-util-find-and-replace@^3.0.0: @@ -2857,9 +2632,9 @@ mdast-util-phrasing@^4.0.0: unist-util-is "^6.0.0" mdast-util-to-hast@^13.0.0: - version "13.2.0" - resolved "https://registry.npmmirror.com/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz" - integrity sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA== + version "13.2.1" + resolved "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz" + integrity sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA== dependencies: "@types/hast" "^3.0.0" "@types/mdast" "^4.0.0" @@ -3173,20 +2948,20 @@ micromark@^4.0.0: mime-db@1.52.0: version "1.52.0" - resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== mime-types@^2.1.12: version "2.1.35" - resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + version "3.1.5" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz" + integrity sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w== dependencies: brace-expansion "^1.1.7" @@ -3320,10 +3095,10 @@ picocolors@^1.1.1: resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@^4.0.2, picomatch@^4.0.3: - version "4.0.3" - resolved "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz" - integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== +"picomatch@^3 || ^4", picomatch@^4.0.3: + version "4.0.4" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz" + integrity sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A== postcss@^8.5.6: version "8.5.6" @@ -3732,7 +3507,7 @@ rc-virtual-list@^3.14.2, rc-virtual-list@^3.5.1, rc-virtual-list@^3.5.2: rc-resize-observer "^1.0.0" rc-util "^5.36.0" -react-dom@^19.1.0: +react-dom@*, react-dom@^19.1.0, react-dom@>=16.0.0, react-dom@>=16.11.0, react-dom@>=16.8.0, react-dom@>=16.9.0, react-dom@>=17.0.0, react-dom@>=18, react-dom@>=19.0.0: version "19.1.1" resolved "https://registry.npmmirror.com/react-dom/-/react-dom-19.1.1.tgz" integrity sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw== @@ -3783,21 +3558,21 @@ react-refresh@^0.17.0: integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ== react-router-dom@^7.7.1: - version "7.7.1" - resolved "https://registry.npmmirror.com/react-router-dom/-/react-router-dom-7.7.1.tgz" - integrity sha512-bavdk2BA5r3MYalGKZ01u8PGuDBloQmzpBZVhDLrOOv1N943Wq6dcM9GhB3x8b7AbqPMEezauv4PeGkAJfy7FQ== + version "7.13.2" + resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.2.tgz" + integrity sha512-aR7SUORwTqAW0JDeiWF07e9SBE9qGpByR9I8kJT5h/FrBKxPMS6TiC7rmVO+gC0q52Bx7JnjWe8Z1sR9faN4YA== dependencies: - react-router "7.7.1" + react-router "7.13.2" -react-router@7.7.1: - version "7.7.1" - resolved "https://registry.npmmirror.com/react-router/-/react-router-7.7.1.tgz" - integrity sha512-jVKHXoWRIsD/qS6lvGveckwb862EekvapdHJN/cGmzw40KnJH5gg53ujOJ4qX6EKIK9LSBfFed/xiQ5yeXNrUA== +react-router@7.13.2: + version "7.13.2" + resolved "https://registry.npmjs.org/react-router/-/react-router-7.13.2.tgz" + integrity sha512-tX1Aee+ArlKQP+NIUd7SE6Li+CiGKwQtbS+FfRxPX6Pe4vHOo6nr9d++u5cwg+Z8K/x8tP+7qLmujDtfrAoUJA== dependencies: cookie "^1.0.1" set-cookie-parser "^2.6.0" -react@^19.1.0: +react@*, "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", react@^19.1.0, react@^19.1.1, react@>=16.0.0, react@>=16.11.0, react@>=16.8.0, react@>=16.9.0, react@>=17.0.0, react@>=18, react@>=19.0.0: version "19.1.1" resolved "https://registry.npmmirror.com/react/-/react-19.1.1.tgz" integrity sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ== @@ -3855,10 +3630,10 @@ rehype-parse@^9.0.0: hast-util-from-html "^2.0.0" unified "^11.0.0" -rehype-prism-plus@2.0.0: - version "2.0.0" - resolved "https://registry.npmmirror.com/rehype-prism-plus/-/rehype-prism-plus-2.0.0.tgz" - integrity sha512-FeM/9V2N7EvDZVdR2dqhAzlw5YI49m9Tgn7ZrYJeYHIahM6gcXpH0K1y2gNnKanZCydOMluJvX2cB9z3lhY8XQ== +rehype-prism-plus@~2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/rehype-prism-plus/-/rehype-prism-plus-2.0.1.tgz" + integrity sha512-Wglct0OW12tksTUseAPyWPo3srjBOY7xKlql/DPKi7HbsdZTyaLCAoO58QBKSczFQxElTsQlOY3JDOFzB/K++Q== dependencies: hast-util-to-string "^3.0.0" parse-numeric-range "^1.3.0" @@ -3867,10 +3642,10 @@ rehype-prism-plus@2.0.0: unist-util-filter "^5.0.0" unist-util-visit "^5.0.0" -rehype-prism-plus@~2.0.0: - version "2.0.1" - resolved "https://registry.npmmirror.com/rehype-prism-plus/-/rehype-prism-plus-2.0.1.tgz" - integrity sha512-Wglct0OW12tksTUseAPyWPo3srjBOY7xKlql/DPKi7HbsdZTyaLCAoO58QBKSczFQxElTsQlOY3JDOFzB/K++Q== +rehype-prism-plus@2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/rehype-prism-plus/-/rehype-prism-plus-2.0.0.tgz" + integrity sha512-FeM/9V2N7EvDZVdR2dqhAzlw5YI49m9Tgn7ZrYJeYHIahM6gcXpH0K1y2gNnKanZCydOMluJvX2cB9z3lhY8XQ== dependencies: hast-util-to-string "^3.0.0" parse-numeric-range "^1.3.0" @@ -4004,33 +3779,38 @@ robust-predicates@^3.0.2: resolved "https://registry.npmmirror.com/robust-predicates/-/robust-predicates-3.0.2.tgz" integrity sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg== -rollup@^4.40.0: - version "4.46.1" - resolved "https://registry.npmmirror.com/rollup/-/rollup-4.46.1.tgz" - integrity sha512-33xGNBsDJAkzt0PvninskHlWnTIPgDtTwhg0U38CUoNP/7H6wI2Cz6dUeoNPbjdTdsYTGuiFFASuUOWovH0SyQ== +rollup@^4.43.0: + version "4.60.0" + resolved "https://registry.npmjs.org/rollup/-/rollup-4.60.0.tgz" + integrity sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ== dependencies: "@types/estree" "1.0.8" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.46.1" - "@rollup/rollup-android-arm64" "4.46.1" - "@rollup/rollup-darwin-arm64" "4.46.1" - "@rollup/rollup-darwin-x64" "4.46.1" - "@rollup/rollup-freebsd-arm64" "4.46.1" - "@rollup/rollup-freebsd-x64" "4.46.1" - "@rollup/rollup-linux-arm-gnueabihf" "4.46.1" - "@rollup/rollup-linux-arm-musleabihf" "4.46.1" - "@rollup/rollup-linux-arm64-gnu" "4.46.1" - "@rollup/rollup-linux-arm64-musl" "4.46.1" - "@rollup/rollup-linux-loongarch64-gnu" "4.46.1" - "@rollup/rollup-linux-ppc64-gnu" "4.46.1" - "@rollup/rollup-linux-riscv64-gnu" "4.46.1" - "@rollup/rollup-linux-riscv64-musl" "4.46.1" - "@rollup/rollup-linux-s390x-gnu" "4.46.1" - "@rollup/rollup-linux-x64-gnu" "4.46.1" - "@rollup/rollup-linux-x64-musl" "4.46.1" - "@rollup/rollup-win32-arm64-msvc" "4.46.1" - "@rollup/rollup-win32-ia32-msvc" "4.46.1" - "@rollup/rollup-win32-x64-msvc" "4.46.1" + "@rollup/rollup-android-arm-eabi" "4.60.0" + "@rollup/rollup-android-arm64" "4.60.0" + "@rollup/rollup-darwin-arm64" "4.60.0" + "@rollup/rollup-darwin-x64" "4.60.0" + "@rollup/rollup-freebsd-arm64" "4.60.0" + "@rollup/rollup-freebsd-x64" "4.60.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.60.0" + "@rollup/rollup-linux-arm-musleabihf" "4.60.0" + "@rollup/rollup-linux-arm64-gnu" "4.60.0" + "@rollup/rollup-linux-arm64-musl" "4.60.0" + "@rollup/rollup-linux-loong64-gnu" "4.60.0" + "@rollup/rollup-linux-loong64-musl" "4.60.0" + "@rollup/rollup-linux-ppc64-gnu" "4.60.0" + "@rollup/rollup-linux-ppc64-musl" "4.60.0" + "@rollup/rollup-linux-riscv64-gnu" "4.60.0" + "@rollup/rollup-linux-riscv64-musl" "4.60.0" + "@rollup/rollup-linux-s390x-gnu" "4.60.0" + "@rollup/rollup-linux-x64-gnu" "4.60.0" + "@rollup/rollup-linux-x64-musl" "4.60.0" + "@rollup/rollup-openbsd-x64" "4.60.0" + "@rollup/rollup-openharmony-arm64" "4.60.0" + "@rollup/rollup-win32-arm64-msvc" "4.60.0" + "@rollup/rollup-win32-ia32-msvc" "4.60.0" + "@rollup/rollup-win32-x64-gnu" "4.60.0" + "@rollup/rollup-win32-x64-msvc" "4.60.0" fsevents "~2.3.2" rw@1: @@ -4061,9 +3841,9 @@ semver@^6.3.1: integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== set-cookie-parser@^2.6.0: - version "2.7.1" - resolved "https://registry.npmmirror.com/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz" - integrity sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ== + version "2.7.2" + resolved "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz" + integrity sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw== shebang-command@^2.0.0: version "2.0.0" @@ -4112,7 +3892,7 @@ strip-json-comments@^3.1.1: style-mod@^4.0.0, style-mod@^4.1.0: version "4.1.3" - resolved "https://registry.npmmirror.com/style-mod/-/style-mod-4.1.3.tgz#6e9012255bb799bdac37e288f7671b5d71bf9f73" + resolved "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz" integrity sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ== style-to-js@^1.0.0: @@ -4158,13 +3938,13 @@ throttle-debounce@^5.0.0, throttle-debounce@^5.0.2: resolved "https://registry.npmmirror.com/throttle-debounce/-/throttle-debounce-5.0.2.tgz" integrity sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A== -tinyglobby@^0.2.14: - version "0.2.14" - resolved "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.14.tgz" - integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ== +tinyglobby@^0.2.15: + version "0.2.15" + resolved "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz" + integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== dependencies: - fdir "^6.4.4" - picomatch "^4.0.2" + fdir "^6.5.0" + picomatch "^4.0.3" toggle-selection@^1.0.6: version "1.0.6" @@ -4194,9 +3974,9 @@ uc.micro@^2.0.0, uc.micro@^2.1.0: integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A== undici@^6.19.5: - version "6.21.3" - resolved "https://registry.npmmirror.com/undici/-/undici-6.21.3.tgz" - integrity sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw== + version "6.24.1" + resolved "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz" + integrity sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA== unified@^11.0.0, unified@^11.0.3, unified@~11.0.0: version "11.0.5" @@ -4304,23 +4084,23 @@ vfile@^6.0.0: "@types/unist" "^3.0.0" vfile-message "^4.0.0" -vite@^7.0.4: - version "7.0.6" - resolved "https://registry.npmmirror.com/vite/-/vite-7.0.6.tgz" - integrity sha512-MHFiOENNBd+Bd9uvc8GEsIzdkn1JxMmEeYX35tI3fv0sJBUTfW5tQsoaOwuY4KhBI09A3dUJ/DXf2yxPVPUceg== +"vite@^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", vite@^7.0.4: + version "7.3.1" + resolved "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz" + integrity sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA== dependencies: - esbuild "^0.25.0" - fdir "^6.4.6" + esbuild "^0.27.0" + fdir "^6.5.0" picomatch "^4.0.3" postcss "^8.5.6" - rollup "^4.40.0" - tinyglobby "^0.2.14" + rollup "^4.43.0" + tinyglobby "^0.2.15" optionalDependencies: fsevents "~2.3.3" w3c-keyname@^2.2.4: version "2.2.8" - resolved "https://registry.npmmirror.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5" + resolved "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz" integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ== web-namespaces@^2.0.0: @@ -4357,10 +4137,10 @@ yallist@^3.0.2: resolved "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yaml@^2.5.1: - version "2.8.1" - resolved "https://registry.npmmirror.com/yaml/-/yaml-2.8.1.tgz" - integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw== +yaml@^2.4.2, yaml@^2.5.1: + version "2.8.3" + resolved "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz" + integrity sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg== yocto-queue@^0.1.0: version "0.1.0" diff --git a/start-conda.sh b/start-conda.sh new file mode 100755 index 0000000..3b52083 --- /dev/null +++ b/start-conda.sh @@ -0,0 +1,139 @@ +#!/bin/bash + +# Exit on error +set -e + +# Project Root Directory +PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BACKEND_DIR="$PROJECT_ROOT/backend" +FRONTEND_DIR="$PROJECT_ROOT/frontend" + +# Define environment names +BACKEND_ENV="imetting_backend" +FRONTEND_ENV="imetting_frontend" +PYTHON_VERSION="3.12" +NODE_VERSION="22" + +echo "========================================" +echo "Starting iMeeting with Conda" +echo "========================================" + +# Try to find conda if not in PATH +if ! command -v conda &> /dev/null; then + echo "Conda not found in PATH, trying common locations..." + + # Check common installation paths + CONDA_PATHS=( + "$HOME/miniconda3/bin" + "$HOME/anaconda3/bin" + "/opt/conda/bin" + "$HOME/miniconda/bin" + "$HOME/anaconda/bin" + "/usr/local/miniconda3/bin" + "/usr/local/anaconda3/bin" + ) + + for bin_path in "${CONDA_PATHS[@]}"; do + if [ -x "$bin_path/conda" ]; then + export PATH="$bin_path:$PATH" + echo "Found conda at: $bin_path/conda" + break + fi + done +fi + +if ! command -v conda &> /dev/null; then + echo "Error: Conda is still not found." + echo "Please ensure Miniconda or Anaconda is installed and accessible." + exit 1 +fi + +# Initialize conda for bash script +eval "$(conda shell.bash hook)" +conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/main >/dev/null 2>&1 || true +conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/r >/dev/null 2>&1 || true + +version_gte() { + [ "$(printf '%s\n' "$1" "$2" | sort -V | head -n 1)" = "$2" ] +} + +node_version_supported_for_vite() { + local version="$1" + version="${version#v}" + if version_gte "$version" "22.12.0"; then + return 0 + fi + if version_gte "$version" "20.19.0" && ! version_gte "$version" "21.0.0"; then + return 0 + fi + return 1 +} + +BACKEND_PYTHON_VERSION="" +if conda info --envs | awk '{print $1}' | grep -qx "$BACKEND_ENV"; then + BACKEND_PYTHON_VERSION="$(conda run -n "$BACKEND_ENV" python -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null | tail -n 1 | tr -d '[:space:]')" + if [ "$BACKEND_PYTHON_VERSION" != "$PYTHON_VERSION" ]; then + echo "Backend environment '$BACKEND_ENV' is using Python $BACKEND_PYTHON_VERSION, recreating with Python $PYTHON_VERSION..." + conda remove -y -n "$BACKEND_ENV" --all + else + echo "Backend environment '$BACKEND_ENV' already exists with Python $PYTHON_VERSION." + fi +fi + +if ! conda info --envs | awk '{print $1}' | grep -qx "$BACKEND_ENV"; then + echo "Creating Conda environment '$BACKEND_ENV' with Python $PYTHON_VERSION..." + conda create -y -n "$BACKEND_ENV" python=$PYTHON_VERSION -c conda-forge --override-channels +fi + +FRONTEND_NODE_VERSION="" +if conda info --envs | awk '{print $1}' | grep -qx "$FRONTEND_ENV"; then + FRONTEND_NODE_VERSION="$(conda run -n "$FRONTEND_ENV" node -p 'process.versions.node' 2>/dev/null | tail -n 1 | tr -d '[:space:]')" + if node_version_supported_for_vite "$FRONTEND_NODE_VERSION"; then + echo "Frontend environment '$FRONTEND_ENV' already exists with Node.js $FRONTEND_NODE_VERSION." + else + echo "Frontend environment '$FRONTEND_ENV' is using Node.js $FRONTEND_NODE_VERSION, recreating with Node.js $NODE_VERSION..." + conda remove -y -n "$FRONTEND_ENV" --all + fi +fi + +if ! conda info --envs | awk '{print $1}' | grep -qx "$FRONTEND_ENV"; then + echo "Creating Conda environment '$FRONTEND_ENV' with Node.js $NODE_VERSION..." + conda create -y -n "$FRONTEND_ENV" nodejs=$NODE_VERSION -c conda-forge --override-channels +fi + +# Start Backend in a subshell +echo "Starting backend..." +( + eval "$(conda shell.bash hook)" + conda activate "$BACKEND_ENV" + cd "$BACKEND_DIR" + pip install -r requirements.txt + python app/main.py +) & +BACKEND_PID=$! + +# Start Frontend in a subshell +echo "Starting frontend..." +( + eval "$(conda shell.bash hook)" + conda activate "$FRONTEND_ENV" + cd "$FRONTEND_DIR" + npm install + npm run dev +) & +FRONTEND_PID=$! + +echo "========================================" +echo "iMeeting is starting!" +echo "Backend Env: $BACKEND_ENV (PID: $BACKEND_PID)" +echo "Frontend Env: $FRONTEND_ENV (PID: $FRONTEND_PID)" +echo "Backend URL: http://localhost:8000" +echo "Frontend URL: http://localhost:5173" +echo "Press Ctrl+C to stop both services." +echo "========================================" + +# Trap Ctrl+C (SIGINT) and kill both processes +trap "echo -e '\nStopping services...'; kill $BACKEND_PID $FRONTEND_PID 2>/dev/null; exit 0" SIGINT SIGTERM + +# Wait for background processes to keep the script running +wait $BACKEND_PID $FRONTEND_PID diff --git a/start-external.sh b/start-external.sh new file mode 100755 index 0000000..31a015f --- /dev/null +++ b/start-external.sh @@ -0,0 +1,217 @@ +#!/bin/bash + +set -e + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +print_banner() { + echo -e "${BLUE}" + cat << "EOF" + _ __ __ _ _ + (_) \/ | ___ ___| |_(_)_ __ __ _ + | | |\/| |/ _ \/ _ \ __| | '_ \ / _` | + | | | | | __/ __/ |_| | | | | (_| | + |_|_| |_|\___|\___|\__|_|_| |_|\__, | + |___/ + External Middleware Deployment +EOF + echo -e "${NC}" +} + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +check_dependencies() { + print_info "检查系统依赖..." + + if ! command -v docker &> /dev/null; then + print_error "未安装 Docker,请先安装 Docker" + exit 1 + fi + + if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then + print_error "未安装 Docker Compose,请先安装 Docker Compose" + exit 1 + fi + + print_success "系统依赖检查通过" +} + +init_compose_cmd() { + if docker compose version &> /dev/null; then + COMPOSE_CMD="docker compose" + else + COMPOSE_CMD="docker-compose" + fi +} + +check_env_files() { + print_info "检查环境变量配置..." + + if [ ! -f .env ]; then + print_warning ".env 文件不存在,从模板创建..." + cp .env.example .env + print_warning "请编辑 .env 文件,配置访问端口、BASE_URL、QWEN_API_KEY 等参数" + print_warning "按任意键继续,或 Ctrl+C 退出..." + read -n 1 -s + fi + + if [ ! -f backend/.env ]; then + print_warning "backend/.env 文件不存在,从模板创建..." + cp backend/.env.example backend/.env + print_warning "请编辑 backend/.env 文件,配置外部数据库和 Redis 参数" + print_warning "按任意键继续,或 Ctrl+C 退出..." + read -n 1 -s + fi + + print_success "环境变量文件检查完成" +} + +load_external_env() { + print_info "加载外部数据库与 Redis 配置..." + + set -a + source backend/.env + set +a + + DB_PORT="${DB_PORT:-3306}" + REDIS_PORT="${REDIS_PORT:-6379}" + REDIS_DB="${REDIS_DB:-0}" + REDIS_PASSWORD="${REDIS_PASSWORD:-}" + + local required_vars=(DB_HOST DB_USER DB_PASSWORD DB_NAME REDIS_HOST) + for var_name in "${required_vars[@]}"; do + if [ -z "${!var_name}" ]; then + print_error "backend/.env 缺少必填配置: ${var_name}" + exit 1 + fi + done + + print_success "外部中间件配置已加载" +} + +create_directories() { + print_info "创建必要的目录..." + + mkdir -p data/uploads + mkdir -p data/logs/backend + mkdir -p data/logs/frontend + mkdir -p backups + + print_success "目录创建完成" +} + +create_override_file() { + OVERRIDE_FILE="$(mktemp /tmp/imeeting-external-compose.XXXXXX.yml)" + trap 'rm -f "$OVERRIDE_FILE"' EXIT + + cat > "$OVERRIDE_FILE" </dev/null | grep -c '"Health":"healthy"' || echo "0") + + if [ "$healthy_count" -eq 2 ]; then + print_success "前后端服务已就绪" + return 0 + fi + + echo -ne "\r等待中... (${waited}s/${max_wait}s) 健康: ${healthy_count}/2" + sleep 5 + waited=$((waited + 5)) + done + + echo "" + print_warning "服务启动超时,请手动检查状态" + return 1 +} + +show_status() { + print_info "服务状态:" + $COMPOSE_CMD ps backend frontend +} + +show_access_info() { + echo "" + print_success "===================================" + print_success " iMeeting 外部中间件模式部署完成!" + print_success "===================================" + echo "" + echo -e "${GREEN}访问地址:${NC}" + echo -e " HTTP访问: ${BLUE}http://localhost${NC}" + echo -e " API文档: ${BLUE}http://localhost/docs${NC}" + echo "" + echo -e "${YELLOW}当前模式:${NC}" + echo -e " 仅启动: ${BLUE}backend + frontend${NC}" + echo -e " 外部依赖: ${BLUE}backend/.env 中配置的 MySQL / Redis${NC}" + echo "" + echo -e "${YELLOW}常用命令:${NC}" + echo -e " 查看日志: ${BLUE}$COMPOSE_CMD logs -f backend frontend${NC}" + echo -e " 停止服务: ${BLUE}./stop-external.sh${NC}" + echo -e " 查看状态: ${BLUE}$COMPOSE_CMD ps backend frontend${NC}" + echo "" +} + +main() { + print_banner + check_dependencies + init_compose_cmd + check_env_files + load_external_env + create_directories + create_override_file + start_services + echo "" + wait_for_health + echo "" + show_status + show_access_info +} + +main "$@" diff --git a/stop-external.sh b/stop-external.sh new file mode 100755 index 0000000..d80d4e8 --- /dev/null +++ b/stop-external.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +set -e + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +if docker compose version &> /dev/null; then + COMPOSE_CMD="docker compose" +else + COMPOSE_CMD="docker-compose" +fi + +print_info "当前应用服务状态:" +$COMPOSE_CMD ps backend frontend + +echo "" +echo -e "${YELLOW}是否保留应用容器?${NC}" +echo "1) 仅停止 backend/frontend(保留容器)" +echo "2) 停止并删除 backend/frontend 容器" +read -p "请选择 (1/2): " choice + +case $choice in + 1) + print_info "停止应用服务..." + $COMPOSE_CMD stop backend frontend + print_success "应用服务已停止,外部数据库和 Redis 未受影响" + ;; + 2) + print_info "停止并删除应用容器..." + $COMPOSE_CMD stop backend frontend + $COMPOSE_CMD rm -f backend frontend + print_success "应用容器已删除,外部数据库和 Redis 未受影响" + ;; + *) + print_warning "无效选择,仅停止应用服务" + $COMPOSE_CMD stop backend frontend + ;; +esac