From 32249d18865ba20d0d95f9b650ef86b7624a5f78 Mon Sep 17 00:00:00 2001 From: Will Miao Date: Sat, 10 Jan 2026 17:45:26 +0800 Subject: [PATCH] feat: add Vue widget demo node and development support - Add LoraManagerDemoNode to node mappings for Vue widget demonstration - Update .gitignore to exclude Vue widget development artifacts (node_modules, .vite, dist) - Implement automatic Vue widget build check in development mode with fallback handling - Maintain pytest compatibility with proper import error handling --- .gitignore | 5 + BUILD_WORKFLOW_IMPLEMENTATION.md | 397 + BUILD_WORKFLOW_SOLUTIONS.md | 267 + CLAUDE.md | 211 + QUICK_REFERENCE.md | 290 + VUE_WIDGETS_SETUP.md | 181 + __init__.py | 19 +- py/nodes/demo_vue_widget_node.py | 72 + py/vue_widget_builder.py | 241 + vue-widgets/.gitignore | 4 + vue-widgets/DEMO_INSTRUCTIONS.md | 179 + vue-widgets/README.md | 169 + vue-widgets/package-lock.json | 1694 +++ vue-widgets/package.json | 28 + vue-widgets/pre-commit.example | 37 + vue-widgets/src/components/DemoWidget.vue | 176 + vue-widgets/src/main.ts | 73 + vue-widgets/tsconfig.json | 24 + vue-widgets/tsconfig.node.json | 10 + vue-widgets/vite.config.mts | 35 + .../assets/demo-widget-RA_dFMfB.css | 56 + web/comfyui/vue-widgets/demo-widget.js | 11672 ++++++++++++++++ web/comfyui/vue-widgets/demo-widget.js.map | 1 + 23 files changed, 15840 insertions(+), 1 deletion(-) create mode 100644 BUILD_WORKFLOW_IMPLEMENTATION.md create mode 100644 BUILD_WORKFLOW_SOLUTIONS.md create mode 100644 CLAUDE.md create mode 100644 QUICK_REFERENCE.md create mode 100644 VUE_WIDGETS_SETUP.md create mode 100644 py/nodes/demo_vue_widget_node.py create mode 100644 py/vue_widget_builder.py create mode 100644 vue-widgets/.gitignore create mode 100644 vue-widgets/DEMO_INSTRUCTIONS.md create mode 100644 vue-widgets/README.md create mode 100644 vue-widgets/package-lock.json create mode 100644 vue-widgets/package.json create mode 100644 vue-widgets/pre-commit.example create mode 100644 vue-widgets/src/components/DemoWidget.vue create mode 100644 vue-widgets/src/main.ts create mode 100644 vue-widgets/tsconfig.json create mode 100644 vue-widgets/tsconfig.node.json create mode 100644 vue-widgets/vite.config.mts create mode 100644 web/comfyui/vue-widgets/assets/demo-widget-RA_dFMfB.css create mode 100644 web/comfyui/vue-widgets/demo-widget.js create mode 100644 web/comfyui/vue-widgets/demo-widget.js.map diff --git a/.gitignore b/.gitignore index bdf79ac6..e2288075 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,8 @@ node_modules/ coverage/ .coverage model_cache/ + +# Vue widgets development cache (but keep build output) +vue-widgets/node_modules/ +vue-widgets/.vite/ +vue-widgets/dist/ diff --git a/BUILD_WORKFLOW_IMPLEMENTATION.md b/BUILD_WORKFLOW_IMPLEMENTATION.md new file mode 100644 index 00000000..60e33696 --- /dev/null +++ b/BUILD_WORKFLOW_IMPLEMENTATION.md @@ -0,0 +1,397 @@ +# Vue Widget 构建流程实施方案 + +## 已实施方案:方案1 + 方案4 组合 + +我们采用了**提交构建产物 + 智能检测**的混合方案,同时满足用户便利性和开发灵活性。 + +--- + +## 🎯 方案特点 + +### 对于用户 +✅ **安装即用** - Clone仓库后无需任何构建步骤 +✅ **无需Node.js** - 构建产物已包含在仓库中 +✅ **快速启动** - ComfyUI启动时无延迟 + +### 对于开发者 +✅ **自动检测** - 源代码变更后自动检测是否需要重新构建 +✅ **自动构建** - 如果检测到需要,可自动执行构建(需要Node.js) +✅ **灵活配置** - 可选择手动或自动构建模式 + +--- + +## 📦 实施的组件 + +### 1. Git 配置调整 + +**文件**: `.gitignore` + +```diff +- # Vue widgets build output +- web/comfyui/vue-widgets/ + ++ # Vue widgets development cache (but keep build output) ++ vue-widgets/node_modules/ ++ vue-widgets/.vite/ ++ vue-widgets/dist/ +``` + +**说明**: +- ✅ 构建产物 `web/comfyui/vue-widgets/` **提交到Git** +- ✅ 开发缓存(node_modules等)被忽略 +- ✅ 仓库大小增加约 1.4MB(可接受) + +--- + +### 2. 智能构建检测模块 + +**文件**: `py/vue_widget_builder.py` + +**核心功能**: +- ✅ 检查构建产物是否存在 +- ✅ 检查源代码是否比构建新(开发模式) +- ✅ 检查Node.js/npm是否可用 +- ✅ 自动执行构建(如果需要且可行) +- ✅ 友好的错误提示和日志 + +**主要类和方法**: + +```python +class VueWidgetBuilder: + def check_build_exists() -> bool + """检查构建产物是否存在""" + + def check_build_outdated() -> bool + """检查源代码是否比构建新""" + + def check_node_available() -> bool + """检查Node.js是否可用""" + + def build_widgets(force=False) -> bool + """执行构建""" + + def ensure_built(auto_build=True, warn_only=True) -> bool + """确保构建存在,智能处理""" +``` + +**便捷函数**: +```python +check_and_build_vue_widgets(auto_build=True, warn_only=True, force=False) +``` + +--- + +### 3. 启动时自动检测 + +**文件**: `__init__.py` + +在ComfyUI加载插件时自动检测并构建: + +```python +# Check and build Vue widgets if needed (development mode) +try: + from .py.vue_widget_builder import check_and_build_vue_widgets + # Auto-build in development, warn only if fails + check_and_build_vue_widgets(auto_build=True, warn_only=True) +except Exception as e: + logging.warning(f"[LoRA Manager] Vue widget build check skipped: {e}") +``` + +**行为**: +- ✅ 如果构建产物存在且最新 → 静默通过 +- ✅ 如果构建产物缺失/过期 → 尝试自动构建(需Node.js) +- ✅ 如果构建失败 → 警告但不阻止ComfyUI启动 +- ✅ 开发模式下源代码变更后自动重建 + +--- + +### 4. 增强的构建脚本 + +**文件**: `vue-widgets/package.json` + +```json +{ + "scripts": { + "dev": "vite build --watch", + "build": "vite build", + "build:production": "vite build --mode production", + "typecheck": "vue-tsc --noEmit", + "clean": "rm -rf ../web/comfyui/vue-widgets", + "rebuild": "npm run clean && npm run build", + "prepare": "npm run build" + } +} +``` + +**新增脚本**: +- `clean` - 清理构建产物 +- `rebuild` - 完全重建 +- `build:production` - 生产模式构建 +- `prepare` - npm install后自动构建(可选) + +--- + +### 5. Pre-commit Hook 示例 + +**文件**: `vue-widgets/pre-commit.example` + +提供了Git pre-commit hook示例,确保提交前构建: + +```bash +#!/bin/sh +cd vue-widgets && npm run build && git add web/comfyui/vue-widgets/ +``` + +**使用方法**: +```bash +# 手动安装(简单方法) +cp vue-widgets/pre-commit.example .git/hooks/pre-commit +chmod +x .git/hooks/pre-commit + +# 或使用Husky(推荐用于团队) +npm install --save-dev husky +npx husky install +npx husky add .git/hooks/pre-commit "cd vue-widgets && npm run build" +``` + +--- + +## 🔄 工作流程 + +### 场景A: 用户安装 + +```bash +# 1. 用户clone仓库 +git clone +cd ComfyUI-Lora-Manager + +# 2. 启动ComfyUI(无需任何构建步骤) +# 构建产物已在仓库中,直接可用 +``` + +**结果**: ✅ 即装即用,无需Node.js + +--- + +### 场景B: 开发者修改Vue代码 + +**方式1: 手动构建** +```bash +cd vue-widgets +npm run build +# 修改会被检测到,ComfyUI重启时会看到最新版本 +``` + +**方式2: 监听模式** +```bash +cd vue-widgets +npm run dev # Watch mode,自动重建 +# 浏览器刷新即可看到变化 +``` + +**方式3: 自动检测** +```bash +# 修改Vue源代码 +vim vue-widgets/src/components/DemoWidget.vue + +# 重启ComfyUI +# __init__.py会检测到源代码比构建新,自动重建(如果有Node.js) +``` + +--- + +### 场景C: 提交代码 + +**如果安装了pre-commit hook**: +```bash +git commit -m "Update widget" +# Hook自动执行构建 +# 构建产物自动添加到commit +``` + +**如果没有hook(手动)**: +```bash +cd vue-widgets && npm run build && cd .. +git add . +git commit -m "Update widget and build output" +``` + +--- + +### 场景D: CI/CD 发布 + +```bash +# 在GitHub Actions或其他CI中 +cd vue-widgets +npm install +npm run build +# 构建产物自动包含在release中 +``` + +--- + +## 📊 测试结果 + +已测试以下场景,全部通过: + +### ✅ Test 1: 构建产物存在时 +``` +Result: True (静默通过,无日志) +``` + +### ✅ Test 2: 构建产物缺失时 +``` +自动检测 → 自动npm install → 自动build → 成功 +Result: True +Build created: web/comfyui/vue-widgets/demo-widget.js (418K) +``` + +### ✅ Test 3: 源代码变更检测 +``` +修改.vue文件 → 时间戳检测 → 自动重建 +Result: True +``` + +--- + +## 📁 Git 仓库状态 + +### 应该提交的文件: + +``` +✅ vue-widgets/src/**/*.{ts,vue} # 源代码 +✅ vue-widgets/package.json # 依赖配置 +✅ vue-widgets/package-lock.json # 锁定版本 +✅ vue-widgets/vite.config.mts # 构建配置 +✅ vue-widgets/tsconfig.json # TS配置 +✅ vue-widgets/*.md # 文档 +✅ web/comfyui/vue-widgets/**/*.js # 构建产物 ⭐ +✅ web/comfyui/vue-widgets/**/*.css # 构建CSS ⭐ +✅ web/comfyui/vue-widgets/**/*.map # Source maps ⭐ +✅ py/vue_widget_builder.py # 构建检测模块 ⭐ +``` + +### 应该忽略的文件: + +``` +❌ vue-widgets/node_modules/ # npm依赖 +❌ vue-widgets/.vite/ # Vite缓存 +❌ vue-widgets/dist/ # Vite临时目录 +``` + +--- + +## 🎓 开发者指南 + +### 首次设置 + +```bash +cd vue-widgets +npm install +npm run build +``` + +### 日常开发 + +```bash +# 开发模式(推荐) +cd vue-widgets +npm run dev +# 在另一个终端启动ComfyUI,修改后刷新浏览器 + +# 或者依赖自动检测 +# 修改代码 → 重启ComfyUI → 自动重建 +``` + +### 提交前 + +```bash +# 确保构建最新 +cd vue-widgets && npm run build && cd .. + +# 或者安装pre-commit hook自动化 +cp vue-widgets/pre-commit.example .git/hooks/pre-commit +chmod +x .git/hooks/pre-commit +``` + +--- + +## 🔧 故障排除 + +### 问题1: 构建产物不是最新的 + +**症状**: 修改了Vue代码,但ComfyUI中看不到变化 + +**解决方案**: +```bash +cd vue-widgets +npm run rebuild # 强制重建 +# 然后刷新浏览器 +``` + +### 问题2: 自动构建失败 + +**症状**: ComfyUI启动时显示构建失败警告 + +**检查**: +```bash +# 检查Node.js是否安装 +node --version +npm --version + +# 手动测试构建 +cd vue-widgets +npm install +npm run build +``` + +### 问题3: Git显示大量构建产物变更 + +**这是正常的** - 构建产物应该提交 + +**最小化变更**: +- 使用 `npm run build` 而非 `npm run dev`(watch模式) +- 确保vite配置中 `minify: false`(已配置) +- 只在需要时重新构建 + +--- + +## 📈 优势总结 + +| 方面 | 优势 | +|------|------| +| 用户体验 | ⭐⭐⭐⭐⭐ 安装即用 | +| 开发体验 | ⭐⭐⭐⭐⭐ 自动检测+构建 | +| 可靠性 | ⭐⭐⭐⭐⭐ 构建产物已验证 | +| 灵活性 | ⭐⭐⭐⭐ 支持多种工作流 | +| 维护性 | ⭐⭐⭐⭐ 清晰的构建流程 | +| Git仓库 | ⭐⭐⭐ 略大但可接受 | + +--- + +## 🚀 未来优化(可选) + +1. **添加Husky** - 自动化pre-commit hooks +2. **GitHub Actions** - CI自动构建和测试 +3. **构建缓存** - 加速CI构建 +4. **Minification** - 生产模式压缩代码(减小体积) +5. **代码分割** - 按需加载不同widget + +--- + +## 总结 + +当前实施的方案完美平衡了用户便利性和开发灵活性: + +- ✅ **用户**: Clone后即用,无需Node.js +- ✅ **开发者**: 自动检测和构建,开发流畅 +- ✅ **可靠性**: 构建产物已验证提交 +- ✅ **可维护性**: 清晰的构建流程和文档 + +用户安装时,`web/comfyui/vue-widgets/`中的JS代码**始终是由vue-widgets中的最新代码编译得到的**,因为: + +1. 开发者提交前会构建(手动或通过hook) +2. ComfyUI启动时会检测并自动重建(开发模式) +3. 构建产物已包含在Git仓库中(用户直接获得) + +这个方案已经过测试验证,可以投入生产使用。 diff --git a/BUILD_WORKFLOW_SOLUTIONS.md b/BUILD_WORKFLOW_SOLUTIONS.md new file mode 100644 index 00000000..5707b826 --- /dev/null +++ b/BUILD_WORKFLOW_SOLUTIONS.md @@ -0,0 +1,267 @@ +# Vue Widget 构建流程解决方案 + +## 问题分析 + +当前配置问题: +- ✅ Vue源代码在 `vue-widgets/src/` 中 +- ✅ 构建产物输出到 `web/comfyui/vue-widgets/` +- ❌ **构建产物被 `.gitignore` 忽略,不会提交到仓库** +- ❌ **用户安装后没有构建产物,widget无法工作** + +## 解决方案对比 + +### 方案1:提交构建产物到Git(推荐 ⭐) + +**优点:** +- ✅ 用户安装即可用,无需额外步骤 +- ✅ 最简单可靠 +- ✅ 适合大多数ComfyUI用户(不一定有Node.js环境) +- ✅ 与现有ComfyUI插件生态一致 + +**缺点:** +- ⚠️ Git仓库略大(每次构建产物变化都会commit) +- ⚠️ 需要确保开发者提交前构建 + +**实现方式:** +1. 从 `.gitignore` 移除 `web/comfyui/vue-widgets/` +2. 添加 pre-commit hook 自动构建 +3. 提交构建产物到仓库 + +**适用场景:** +- 生产环境发布 +- 用户通过ComfyUI Manager或git clone安装 + +--- + +### 方案2:用户安装时自动构建 + +**优点:** +- ✅ Git仓库小,只包含源代码 +- ✅ 始终使用最新代码构建 +- ✅ 开发者友好 + +**缺点:** +- ❌ 要求用户有Node.js环境 +- ❌ 安装时间长(需要npm install + build) +- ❌ 可能构建失败影响安装体验 +- ❌ ComfyUI Manager可能不支持 + +**实现方式:** +1. 保持 `.gitignore` 设置 +2. 添加安装脚本自动检测并构建 +3. 在Python `__init__.py` 启动时检查构建产物 + +**适用场景:** +- 开发环境 +- 技术用户 + +--- + +### 方案3:混合方案(开发 + 生产分离) + +**优点:** +- ✅ 开发时只提交源代码 +- ✅ Release时提供完整构建 +- ✅ Git仓库保持干净 +- ✅ 用户安装release版本即可用 + +**缺点:** +- ⚠️ 需要CI/CD配置 +- ⚠️ 工作流稍复杂 + +**实现方式:** +1. 开发分支:gitignore构建产物 +2. GitHub Actions:自动构建 +3. Release分支/Tag:包含构建产物 +4. 用户安装release版本 + +**适用场景:** +- 成熟项目 +- 多人协作开发 + +--- + +### 方案4:Python启动时自动构建(智能方案) + +**优点:** +- ✅ 自动检测是否需要构建 +- ✅ 开发模式自动构建 +- ✅ 生产模式使用已有构建 +- ✅ 最灵活 + +**缺点:** +- ⚠️ 需要编写构建检测逻辑 +- ⚠️ 首次启动可能较慢 + +**实现方式:** +1. 在 `__init__.py` 中检查构建产物 +2. 如果不存在或过期,尝试自动构建 +3. 如果无Node.js环境,给出明确提示 + +**适用场景:** +- 开发+生产通用 +- 技术用户为主 + +--- + +## 推荐实现:方案1 + 方案4 组合 + +### 为什么? + +1. **对普通用户**:提交构建产物,安装即用 +2. **对开发者**:pre-commit hook确保提交前构建 +3. **智能检测**:Python启动时检查,开发模式可自动重建 + +### 实现步骤 + +#### Step 1: 修改 .gitignore(提交构建产物) + +```bash +# 移除这行: +# web/comfyui/vue-widgets/ + +# 但保留源码构建缓存: +vue-widgets/node_modules/ +vue-widgets/dist/ +``` + +#### Step 2: 添加 pre-commit hook + +创建 `.husky/pre-commit` 或使用简单的git hook: +```bash +#!/bin/sh +# 在commit前自动构建Vue widgets +cd vue-widgets && npm run build && cd .. && git add web/comfyui/vue-widgets/ +``` + +#### Step 3: 在Python中添加智能检测 + +在 `__init__.py` 或专门的构建检查模块中: +```python +import os +import subprocess +from pathlib import Path + +def check_vue_widgets_build(): + """检查Vue widgets是否已构建,如果需要则自动构建""" + project_root = Path(__file__).parent + build_file = project_root / "web/comfyui/vue-widgets/demo-widget.js" + src_dir = project_root / "vue-widgets/src" + + # 如果构建产物不存在 + if not build_file.exists(): + print("[LoRA Manager] Vue widget build not found, attempting to build...") + try: + result = subprocess.run( + ["npm", "run", "build"], + cwd=project_root / "vue-widgets", + capture_output=True, + timeout=120 + ) + if result.returncode == 0: + print("[LoRA Manager] ✓ Vue widgets built successfully") + else: + print(f"[LoRA Manager] ⚠️ Build failed: {result.stderr.decode()}") + print("[LoRA Manager] Please run: cd vue-widgets && npm install && npm run build") + except FileNotFoundError: + print("[LoRA Manager] ⚠️ Node.js not found. Please install Node.js and run:") + print("[LoRA Manager] cd vue-widgets && npm install && npm run build") + except Exception as e: + print(f"[LoRA Manager] ⚠️ Build error: {e}") + + # 检查源代码是否比构建产物新(开发模式) + elif src_dir.exists(): + src_mtime = max(f.stat().st_mtime for f in src_dir.rglob("*") if f.is_file()) + build_mtime = build_file.stat().st_mtime + + if src_mtime > build_mtime: + print("[LoRA Manager] Source code newer than build, rebuilding...") + # 同样的构建逻辑 +``` + +#### Step 4: package.json 添加便捷脚本 + +```json +{ + "scripts": { + "dev": "vite build --watch", + "build": "vite build", + "build:check": "node scripts/check-build.js", + "typecheck": "vue-tsc --noEmit", + "prepare": "npm run build" + } +} +``` + +--- + +## 对于不同场景的建议 + +### 场景A:当前开发阶段(快速验证) +**使用:方案1(提交构建产物)** +```bash +# 1. 移除gitignore +# 2. 构建并提交 +cd vue-widgets && npm run build && cd .. +git add -f web/comfyui/vue-widgets/ +git commit -m "Add Vue widget build output" +``` + +### 场景B:多人协作开发 +**使用:方案1 + pre-commit hook** +- 提交构建产物保证可用性 +- Hook确保开发者不会忘记构建 + +### 场景C:成熟生产项目 +**使用:方案3(GitHub Actions)** +- main分支不含构建产物 +- CI自动构建并发布到release +- 用户安装release tag + +--- + +## 立即可用的解决方案 + +### 最简单方案(推荐现在使用): + +```bash +# 1. 修改 .gitignore,移除构建产物忽略 +sed -i '/web\/comfyui\/vue-widgets/d' .gitignore + +# 2. 添加源码缓存到gitignore +echo "vue-widgets/node_modules/" >> .gitignore +echo "vue-widgets/.vite/" >> .gitignore + +# 3. 确保已构建 +cd vue-widgets && npm run build && cd .. + +# 4. 提交所有文件 +git add . +git commit -m "feat: Add Vue + PrimeVue widget scaffold with demo" +``` + +这样用户clone后即可直接使用,同时开发者在修改Vue代码后需要手动运行 `npm run build`。 + +--- + +## 未来改进 + +可以考虑: +1. 添加 Husky + lint-staged 自动化pre-commit +2. 添加 GitHub Actions 自动构建和发布 +3. 编写安装后检查脚本 +4. 在ComfyUI Manager元数据中说明Node.js依赖(如果选择方案2) + +--- + +## 总结 + +| 方案 | 用户体验 | 开发体验 | Git仓库大小 | 实现难度 | +|------|---------|---------|------------|---------| +| 方案1 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | +| 方案2 | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | +| 方案3 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ | +| 方案4 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | + +**当前阶段推荐:方案1(提交构建产物)** +**长期推荐:方案1 + 方案4 组合(提交产物 + 智能检测)** diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..7311f88b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,211 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +ComfyUI LoRA Manager is a comprehensive LoRA management system for ComfyUI that combines a Python backend with browser-based widgets. It provides model organization, downloading from CivitAI/CivArchive, recipe management, and one-click workflow integration. + +## Development Commands + +### Backend Development +```bash +# Install dependencies +pip install -r requirements.txt + +# Install development dependencies (for testing) +pip install -r requirements-dev.txt + +# Run standalone server (port 8188 by default) +python standalone.py --port 8188 + +# Run backend tests with coverage +COVERAGE_FILE=coverage/backend/.coverage pytest \ + --cov=py \ + --cov=standalone \ + --cov-report=term-missing \ + --cov-report=html:coverage/backend/html \ + --cov-report=xml:coverage/backend/coverage.xml \ + --cov-report=json:coverage/backend/coverage.json + +# Run specific test file +pytest tests/test_recipes.py +``` + +### Frontend Development +```bash +# Install frontend dependencies +npm install + +# Run frontend tests +npm test + +# Run frontend tests in watch mode +npm run test:watch + +# Run frontend tests with coverage +npm run test:coverage +``` + +### Localization +```bash +# Sync translation keys after UI string updates +python scripts/sync_translation_keys.py +``` + +## Architecture + +### Backend Structure (Python) + +**Core Entry Points:** +- `__init__.py` - ComfyUI plugin entry point, registers nodes and routes +- `standalone.py` - Standalone server that mocks ComfyUI dependencies +- `py/lora_manager.py` - Main LoraManager class that registers HTTP routes + +**Service Layer** (`py/services/`): +- `ServiceRegistry` - Singleton service registry for dependency management +- `ModelServiceFactory` - Factory for creating model services (LoRA, Checkpoint, Embedding) +- Scanner services (`lora_scanner.py`, `checkpoint_scanner.py`, `embedding_scanner.py`) - Model file discovery and indexing +- `model_scanner.py` - Base scanner with hash-based deduplication and metadata extraction +- `persistent_model_cache.py` - SQLite-based cache for model metadata +- `metadata_sync_service.py` - Syncs metadata from CivitAI/CivArchive APIs +- `civitai_client.py` / `civarchive_client.py` - API clients for external services +- `downloader.py` / `download_manager.py` - Model download orchestration +- `recipe_scanner.py` - Recipe file management and image association +- `settings_manager.py` - Application settings with migration support +- `websocket_manager.py` - WebSocket broadcasting for real-time updates +- `use_cases/` - Business logic orchestration (auto-organize, bulk refresh, downloads) + +**Routes Layer** (`py/routes/`): +- Route registrars organize endpoints by domain (models, recipes, previews, example images, updates) +- `handlers/` - Request handlers implementing business logic +- Routes use aiohttp and integrate with ComfyUI's PromptServer + +**Recipe System** (`py/recipes/`): +- `base.py` - Base recipe metadata structure +- `enrichment.py` - Enriches recipes with model metadata +- `merger.py` - Merges recipe data from multiple sources +- `parsers/` - Parsers for different recipe formats (PNG, JSON, workflow) + +**Custom Nodes** (`py/nodes/`): +- `lora_loader.py` - LoRA loader nodes with preset support +- `save_image.py` - Enhanced save image with pattern-based filenames +- `trigger_word_toggle.py` - Toggle trigger words in prompts +- `lora_stacker.py` - Stack multiple LoRAs +- `prompt.py` - Prompt node with autocomplete +- `wanvideo_lora_select.py` - WanVideo-specific LoRA selection + +**Configuration** (`py/config.py`): +- Manages folder paths for models, checkpoints, embeddings +- Handles symlink mappings for complex directory structures +- Auto-saves paths to settings.json in ComfyUI mode + +### Frontend Structure (JavaScript) + +**ComfyUI Widgets** (`web/comfyui/`): +- Vanilla JavaScript ES modules extending ComfyUI's LiteGraph-based UI +- `loras_widget.js` - Main LoRA selection widget with preview +- `loras_widget_events.js` - Event handling for widget interactions +- `autocomplete.js` - Autocomplete for trigger words and embeddings +- `preview_tooltip.js` - Preview tooltip for model cards +- `top_menu_extension.js` - Adds "Launch LoRA Manager" menu item +- `trigger_word_highlight.js` - Syntax highlighting for trigger words +- `utils.js` - Shared utilities and API helpers + +**Widget Development:** +- Widgets use `app.registerExtension` and `getCustomWidgets` hooks +- `node.addDOMWidget(name, type, element, options)` embeds HTML in nodes +- See `docs/dom_widget_dev_guide.md` for complete DOMWidget development guide + +**Web Source** (`web-src/`): +- Modern frontend components (if migrating from static) +- `components/` - Reusable UI components +- `styles/` - CSS styling + +### Key Patterns + +**Dual Mode Operation:** +- ComfyUI plugin mode: Integrates with ComfyUI's PromptServer, uses folder_paths +- Standalone mode: Mocks ComfyUI dependencies via `standalone.py`, reads paths from settings.json +- Detection: `os.environ.get("LORA_MANAGER_STANDALONE", "0") == "1"` + +**Settings Management:** +- Settings stored in user directory (via `platformdirs`) or portable mode (in repo) +- Migration system tracks settings schema version +- Template in `settings.json.example` defines defaults + +**Model Scanning Flow:** +1. Scanner walks folder paths, computes file hashes +2. Hash-based deduplication prevents duplicate processing +3. Metadata extracted from safetensors headers +4. Persistent cache stores results in SQLite +5. Background sync fetches CivitAI/CivArchive metadata +6. WebSocket broadcasts updates to connected clients + +**Recipe System:** +- Recipes store LoRA combinations with parameters +- Supports import from workflow JSON, PNG metadata +- Images associated with recipes via sibling file detection +- Enrichment adds model metadata for display + +**Frontend-Backend Communication:** +- REST API for CRUD operations +- WebSocket for real-time progress updates (downloads, scans) +- API endpoints follow `/loras/*` pattern + +## Code Style + +**Python:** +- PEP 8 with 4-space indentation +- snake_case for files, functions, variables +- PascalCase for classes +- Type hints preferred +- English comments only (per copilot-instructions.md) +- Loggers via `logging.getLogger(__name__)` + +**JavaScript:** +- ES modules with camelCase +- Files use `*_widget.js` suffix for ComfyUI widgets +- Prefer vanilla JS, avoid framework dependencies + +## Testing + +**Backend Tests:** +- pytest with `--import-mode=importlib` +- Test files: `tests/test_*.py` +- Fixtures in `tests/conftest.py` +- Mock ComfyUI dependencies using standalone.py patterns +- Markers: `@pytest.mark.asyncio` for async tests, `@pytest.mark.no_settings_dir_isolation` for real paths + +**Frontend Tests:** +- Vitest with jsdom environment +- Test files: `tests/frontend/**/*.test.js` +- Setup in `tests/frontend/setup.js` +- Coverage via `npm run test:coverage` + +## Important Notes + +**Settings Location:** +- ComfyUI mode: Auto-saves folder paths to user settings directory +- Standalone mode: Use `settings.json` (copy from `settings.json.example`) +- Portable mode: Set `"use_portable_settings": true` in settings.json + +**API Integration:** +- CivitAI API key required for downloads (add to settings) +- CivArchive API used as fallback for deleted models +- Metadata archive database available for offline metadata + +**Symlink Handling:** +- Config scans symlinks to map virtual paths to physical locations +- Preview validation uses normalized preview root paths +- Fingerprinting prevents redundant symlink rescans + +**ComfyUI Node Development:** +- Nodes defined in `py/nodes/`, registered in `__init__.py` +- Frontend widgets in `web/comfyui/`, matched by node type +- Use `WEB_DIRECTORY = "./web/comfyui"` convention + +**Recipe Image Association:** +- Recipes scan for sibling images in same directory +- Supports repair/migration of recipe image paths +- See `py/services/recipe_scanner.py` for implementation details diff --git a/QUICK_REFERENCE.md b/QUICK_REFERENCE.md new file mode 100644 index 00000000..4d4af733 --- /dev/null +++ b/QUICK_REFERENCE.md @@ -0,0 +1,290 @@ +# Vue Widget 开发快速参考 + +## 🚀 快速开始 + +### 用户安装 +```bash +# Clone仓库后直接启动ComfyUI,无需其他步骤 +git clone +# 构建产物已包含,直接可用 +``` + +### 开发者设置 +```bash +cd vue-widgets +npm install # 首次安装依赖 +npm run build # 构建widget +``` + +--- + +## 📝 常用命令 + +### 构建命令 +```bash +cd vue-widgets + +npm run build # 单次构建 +npm run dev # 监听模式(自动重建) +npm run rebuild # 清理并重建 +npm run typecheck # TypeScript类型检查 +npm run clean # 清理构建产物 +``` + +### 开发工作流 +```bash +# 方式1: 监听模式(推荐) +cd vue-widgets && npm run dev +# 修改代码后,刷新ComfyUI浏览器页面 + +# 方式2: 手动构建 +# 修改代码 → npm run build → 刷新浏览器 + +# 方式3: 自动检测 +# 修改代码 → 重启ComfyUI(会自动重建) +``` + +--- + +## 📂 项目结构 + +``` +vue-widgets/ # Vue源代码目录 +├── src/ +│ ├── main.ts # 扩展注册入口 +│ └── components/ +│ └── DemoWidget.vue # Widget组件 +├── package.json # 依赖和脚本 +└── vite.config.mts # 构建配置 + +web/comfyui/vue-widgets/ # 构建产物(提交到Git) +├── demo-widget.js # 编译后的JS +├── demo-widget.js.map # Source map +└── assets/ # CSS等资源 + +py/nodes/ +└── demo_vue_widget_node.py # Python节点定义 + +py/ +└── vue_widget_builder.py # 构建检测模块 +``` + +--- + +## 🔧 创建新Widget + +### 1. 创建Python节点 +`py/nodes/my_widget_node.py`: +```python +class MyWidgetNode: + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "my_widget": ("MY_WIDGET", {}), + } + } + + RETURN_TYPES = ("STRING",) + FUNCTION = "process" + CATEGORY = "loramanager" + + def process(self, my_widget): + return (str(my_widget),) + +NODE_CLASS_MAPPINGS = {"MyWidgetNode": MyWidgetNode} +``` + +### 2. 创建Vue组件 +`vue-widgets/src/components/MyWidget.vue`: +```vue + + + +``` + +### 3. 注册Widget +`vue-widgets/src/main.ts`: +```typescript +import MyWidget from '@/components/MyWidget.vue' + +// 在 getCustomWidgets() 中: +MY_WIDGET(node) { + return createVueWidget(node, MyWidget, 'my-widget') +} +``` + +### 4. 注册节点 +`__init__.py`: +```python +from .py.nodes.my_widget_node import MyWidgetNode + +NODE_CLASS_MAPPINGS = { + # ... + "MyWidgetNode": MyWidgetNode +} +``` + +### 5. 构建并测试 +```bash +cd vue-widgets && npm run build +# 重启ComfyUI并测试 +``` + +--- + +## 🎯 构建流程保证 + +### 如何确保用户安装后有最新的构建产物? + +**实施的方案**: 提交构建产物 + 智能检测 + +#### ✅ 对用户 +1. 构建产物已包含在Git仓库中 +2. Clone后即可使用,无需Node.js +3. ComfyUI启动时自动检查(如果有Node.js会自动重建) + +#### ✅ 对开发者 +1. 修改Vue代码后,ComfyUI重启时自动检测并重建 +2. 可使用 `npm run dev` 监听模式自动重建 +3. 提交前运行 `npm run build`(或使用pre-commit hook) + +#### ✅ Git配置 +```bash +# .gitignore +✅ 提交: web/comfyui/vue-widgets/ # 构建产物 +❌ 忽略: vue-widgets/node_modules/ # 开发依赖 +❌ 忽略: vue-widgets/.vite/ # 构建缓存 +``` + +--- + +## 🛠️ 故障排除 + +### 问题: Widget不显示最新修改 +```bash +# 解决方案1: 强制重建 +cd vue-widgets && npm run rebuild + +# 解决方案2: 清理缓存 +rm -rf web/comfyui/vue-widgets +npm run build + +# 解决方案3: 硬刷新浏览器 +Ctrl+Shift+R (Windows/Linux) +Cmd+Shift+R (Mac) +``` + +### 问题: 自动构建失败 +```bash +# 检查Node.js +node --version # 需要 >= 18 +npm --version + +# 重新安装依赖 +cd vue-widgets +rm -rf node_modules package-lock.json +npm install +npm run build +``` + +### 问题: TypeScript错误 +```bash +cd vue-widgets +npm run typecheck # 检查类型错误 +npm run build # 构建(忽略类型错误) +``` + +--- + +## 📚 常用PrimeVue组件 + +```typescript +import Button from 'primevue/button' +import InputText from 'primevue/inputtext' +import InputNumber from 'primevue/inputnumber' +import Dropdown from 'primevue/dropdown' +import Card from 'primevue/card' +import DataTable from 'primevue/datatable' +import Column from 'primevue/column' +import Dialog from 'primevue/dialog' +import Tree from 'primevue/tree' +import Checkbox from 'primevue/checkbox' +import Slider from 'primevue/slider' +``` + +文档: https://primevue.org/ + +--- + +## 🔄 Git工作流 + +### 提交代码 +```bash +# 方式1: 手动构建 +cd vue-widgets && npm run build && cd .. +git add . +git commit -m "feat: update widget" + +# 方式2: 使用pre-commit hook +cp vue-widgets/pre-commit.example .git/hooks/pre-commit +chmod +x .git/hooks/pre-commit +git commit -m "feat: update widget" +# Hook自动构建并添加产物 +``` + +### 提交前检查清单 +- [ ] Vue源代码已修改 +- [ ] 运行 `npm run build` +- [ ] 测试widget功能正常 +- [ ] 构建产物已生成在 `web/comfyui/vue-widgets/` +- [ ] `git add` 包含构建产物 +- [ ] Commit + +--- + +## 📖 更多文档 + +- **VUE_WIDGETS_SETUP.md** - 完整架构和设置指南 +- **vue-widgets/README.md** - Widget开发详细指南 +- **vue-widgets/DEMO_INSTRUCTIONS.md** - Demo widget测试说明 +- **BUILD_WORKFLOW_SOLUTIONS.md** - 构建流程方案对比 +- **BUILD_WORKFLOW_IMPLEMENTATION.md** - 已实施方案详解 + +--- + +## 💡 提示 + +- 开发时优先使用 `npm run dev` 监听模式 +- 提交前确保运行 `npm run build` +- 构建产物约1.4MB,会提交到Git(正常) +- ComfyUI会在启动时自动检测并重建(如果需要) +- Source maps已启用,便于调试 + +--- + +## 🎓 学习资源 + +- [Vue 3 文档](https://vuejs.org/) +- [PrimeVue 文档](https://primevue.org/) +- [TypeScript 文档](https://www.typescriptlang.org/) +- [Vite 文档](https://vitejs.dev/) +- [ComfyUI 自定义节点开发](https://docs.comfy.org/) diff --git a/VUE_WIDGETS_SETUP.md b/VUE_WIDGETS_SETUP.md new file mode 100644 index 00000000..caa9541b --- /dev/null +++ b/VUE_WIDGETS_SETUP.md @@ -0,0 +1,181 @@ +# Vue + PrimeVue Widget Development Setup + +This guide explains the Vue + PrimeVue widget development scaffold for ComfyUI LoRA Manager. + +## Overview + +The project now supports developing custom ComfyUI widgets using Vue 3 + PrimeVue, providing a modern reactive framework for building rich UI components. + +## Architecture + +``` +ComfyUI-Lora-Manager/ +├── vue-widgets/ # Vue widget source code (TypeScript) +│ ├── src/ +│ │ ├── main.ts # Extension registration +│ │ └── components/ # Vue components +│ ├── package.json +│ ├── vite.config.mts # Build to web/comfyui/vue-widgets/ +│ └── tsconfig.json +│ +├── web/comfyui/ # ComfyUI web directory +│ ├── vue-widgets/ # Compiled Vue widgets (gitignored) +│ │ ├── demo-widget.js # Built JavaScript +│ │ └── assets/ # CSS and other assets +│ └── *.js # Existing vanilla JS widgets +│ +├── py/nodes/ # Python node definitions +│ ├── demo_vue_widget_node.py # Demo node +│ └── ... +│ +└── __init__.py # Node registration +``` + +## Quick Start + +### 1. Install Dependencies + +```bash +cd vue-widgets +npm install +``` + +### 2. Build the Demo Widget + +```bash +npm run build +``` + +This compiles the TypeScript/Vue code and outputs to `web/comfyui/vue-widgets/`. + +### 3. Test in ComfyUI + +1. Start/restart ComfyUI +2. Open the ComfyUI interface +3. Add the "LoRA Manager Demo (Vue)" node from the node menu +4. You should see a Vue-powered widget with PrimeVue components: + - Text input for model name + - Number input for strength (with +/- buttons) + - Apply and Reset buttons + - Result card showing current configuration + +## Development Workflow + +### Watch Mode for Development + +```bash +cd vue-widgets +npm run dev +``` + +This watches for file changes and automatically rebuilds. You'll need to refresh ComfyUI's browser page to see changes. + +### Project Structure + +**Python Side (`py/nodes/demo_vue_widget_node.py`):** +- Defines the ComfyUI node class +- Specifies input types (including the custom widget type) +- Implements the processing logic +- The widget type name must match the key in the frontend's `getCustomWidgets()` + +**Frontend Side (`vue-widgets/src/`):** +- `main.ts` - Registers the extension with ComfyUI and creates Vue apps +- `components/DemoWidget.vue` - The actual Vue component with PrimeVue UI + +### Data Flow + +1. **Widget Creation:** + - ComfyUI calls `getCustomWidgets()` when creating a node + - Creates a container DOM element + - Mounts a Vue app with the component inside the container + +2. **Widget State:** + - Component props receive `widget` and `node` objects from ComfyUI + - Use Vue's reactive state management within the component + +3. **Serialization:** + - Implement `widget.serializeValue()` in `onMounted()` + - This function is called when the workflow is saved or executed + - Return the data that should be passed to the Python node + +4. **Processing:** + - Python node receives the serialized data in its `process()` method + - Process the data and return results to the workflow + +## Creating Your Own Widget + +See the detailed guide in `vue-widgets/README.md`. + +Quick checklist: +- [ ] Create Python node in `py/nodes/` +- [ ] Create Vue component in `vue-widgets/src/components/` +- [ ] Register widget in `vue-widgets/src/main.ts` +- [ ] Register node in `__init__.py` +- [ ] Build with `npm run build` +- [ ] Test in ComfyUI + +## Key Technologies + +- **Vue 3**: Modern reactive framework with Composition API +- **PrimeVue 4**: Rich UI component library with 90+ components +- **TypeScript**: Type-safe development +- **Vite**: Fast build tool with HMR support + +## Build Configuration + +The build is configured to: +- Output ES modules to `../web/comfyui/vue-widgets/` +- Mark ComfyUI's `app.js` as external (not bundled) +- Generate source maps for debugging +- Keep code unminified for easier debugging +- Split vendor code into separate chunks + +## PrimeVue Components + +The demo widget showcases several PrimeVue components: +- `Button` - Styled buttons with icons +- `InputText` - Text input fields +- `InputNumber` - Number inputs with spinners +- `Card` - Container component + +For the full component library, see [PrimeVue Documentation](https://primevue.org/). + +## Troubleshooting + +### Build fails with module errors +- Make sure you're in the `vue-widgets` directory +- Run `npm install` to ensure all dependencies are installed +- Check that Node.js version is 18+ (`node --version`) + +### Widget doesn't appear in ComfyUI +- Verify the build completed successfully (`web/comfyui/vue-widgets/demo-widget.js` exists) +- Check that the Python node is registered in `__init__.py` +- Restart ComfyUI completely (not just refresh browser) +- Check browser console for JavaScript errors + +### Widget type mismatch error +- Ensure the widget type in Python (e.g., `"LORA_DEMO_WIDGET"`) matches the key in `getCustomWidgets()` +- Type names are case-sensitive + +### Changes not reflected after rebuild +- Hard refresh the browser (Ctrl+Shift+R / Cmd+Shift+R) +- Clear browser cache +- Restart ComfyUI server + +## Next Steps + +Now that the scaffold is set up, you can: + +1. **Extend the demo widget** - Add more PrimeVue components and functionality +2. **Create production widgets** - Build widgets for actual LoRA management features +3. **Add styling** - Customize the look with CSS/Tailwind +4. **Add i18n** - Implement vue-i18n for internationalization +5. **Add state management** - Use Pinia if you need shared state across widgets + +## References + +- [ComfyUI Custom Nodes Documentation](https://docs.comfy.org/essentials/custom_node_server) +- [PrimeVue Documentation](https://primevue.org/) +- [Vue 3 Documentation](https://vuejs.org/) +- [Vite Documentation](https://vitejs.dev/) +- Reference implementation: `/refs/ComfyUI_frontend_vue_basic` diff --git a/__init__.py b/__init__.py index 2be5df72..a0fb24fb 100644 --- a/__init__.py +++ b/__init__.py @@ -8,6 +8,7 @@ try: # pragma: no cover - import fallback for pytest collection from .py.nodes.debug_metadata import DebugMetadata from .py.nodes.wanvideo_lora_select import WanVideoLoraSelectLM from .py.nodes.wanvideo_lora_select_from_text import WanVideoLoraSelectFromText + from .py.nodes.demo_vue_widget_node import LoraManagerDemoNode from .py.metadata_collector import init as init_metadata_collector except ImportError: # pragma: no cover - allows running under pytest without package install import importlib @@ -28,6 +29,7 @@ except ImportError: # pragma: no cover - allows running under pytest without pa DebugMetadata = importlib.import_module("py.nodes.debug_metadata").DebugMetadata WanVideoLoraSelectLM = importlib.import_module("py.nodes.wanvideo_lora_select").WanVideoLoraSelectLM WanVideoLoraSelectFromText = importlib.import_module("py.nodes.wanvideo_lora_select_from_text").WanVideoLoraSelectFromText + LoraManagerDemoNode = importlib.import_module("py.nodes.demo_vue_widget_node").LoraManagerDemoNode init_metadata_collector = importlib.import_module("py.metadata_collector").init NODE_CLASS_MAPPINGS = { @@ -39,11 +41,26 @@ NODE_CLASS_MAPPINGS = { SaveImageLM.NAME: SaveImageLM, DebugMetadata.NAME: DebugMetadata, WanVideoLoraSelectLM.NAME: WanVideoLoraSelectLM, - WanVideoLoraSelectFromText.NAME: WanVideoLoraSelectFromText + WanVideoLoraSelectFromText.NAME: WanVideoLoraSelectFromText, + "LoraManagerDemoNode": LoraManagerDemoNode } WEB_DIRECTORY = "./web/comfyui" +# Check and build Vue widgets if needed (development mode) +try: + from .py.vue_widget_builder import check_and_build_vue_widgets + # Auto-build in development, warn only if fails + check_and_build_vue_widgets(auto_build=True, warn_only=True) +except ImportError: + # Fallback for pytest + import importlib + check_and_build_vue_widgets = importlib.import_module("py.vue_widget_builder").check_and_build_vue_widgets + check_and_build_vue_widgets(auto_build=True, warn_only=True) +except Exception as e: + import logging + logging.warning(f"[LoRA Manager] Vue widget build check skipped: {e}") + # Initialize metadata collector init_metadata_collector() diff --git a/py/nodes/demo_vue_widget_node.py b/py/nodes/demo_vue_widget_node.py new file mode 100644 index 00000000..7429ed25 --- /dev/null +++ b/py/nodes/demo_vue_widget_node.py @@ -0,0 +1,72 @@ +""" +Demo node to showcase Vue + PrimeVue widget integration in ComfyUI LoRA Manager. + +This node demonstrates: +- Vue 3 + PrimeVue custom widget +- Widget state serialization +- Integration with ComfyUI workflow +""" + + +class LoraManagerDemoNode: + """ + A demo node that uses a Vue + PrimeVue widget to configure LoRA parameters. + """ + + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "lora_demo_widget": ("LORA_DEMO_WIDGET", {}), + }, + "optional": { + "text": ("STRING", { + "default": "", + "multiline": True, + "placeholder": "Additional prompt text..." + }), + } + } + + RETURN_TYPES = ("STRING", "FLOAT", "STRING") + RETURN_NAMES = ("model_name", "strength", "info") + + FUNCTION = "process" + + CATEGORY = "loramanager/demo" + + def process(self, lora_demo_widget, text=""): + """ + Process the widget data and return the configuration. + + Args: + lora_demo_widget: Widget data containing model_name and strength + text: Optional text input + + Returns: + Tuple of (model_name, strength, info_string) + """ + model_name = lora_demo_widget.get("modelName", "") + strength = lora_demo_widget.get("strength", 1.0) + + info = f"Vue Widget Demo - Model: {model_name}, Strength: {strength}" + if text: + info += f"\nAdditional text: {text}" + + print(f"[LoraManagerDemoNode] {info}") + + return (model_name, strength, info) + + +# Node class mappings for ComfyUI +NODE_CLASS_MAPPINGS = { + "LoraManagerDemoNode": LoraManagerDemoNode +} + +# Display name mappings +NODE_DISPLAY_NAME_MAPPINGS = { + "LoraManagerDemoNode": "LoRA Manager Demo (Vue)" +} diff --git a/py/vue_widget_builder.py b/py/vue_widget_builder.py new file mode 100644 index 00000000..7884d322 --- /dev/null +++ b/py/vue_widget_builder.py @@ -0,0 +1,241 @@ +""" +Vue Widget Build Checker and Auto-builder + +This module checks if Vue widgets are built and attempts to build them if needed. +Useful for development mode where source code might be newer than build output. +""" + +import os +import subprocess +import logging +from pathlib import Path +from typing import Optional + +logger = logging.getLogger(__name__) + + +class VueWidgetBuilder: + """Manages Vue widget build checking and auto-building.""" + + def __init__(self, project_root: Optional[Path] = None): + """ + Initialize the builder. + + Args: + project_root: Project root directory. If None, auto-detects. + """ + if project_root is None: + # Auto-detect project root (where __init__.py is) + project_root = Path(__file__).parent.parent + + self.project_root = Path(project_root) + self.vue_widgets_dir = self.project_root / "vue-widgets" + self.build_output_dir = self.project_root / "web" / "comfyui" / "vue-widgets" + self.src_dir = self.vue_widgets_dir / "src" + + def check_build_exists(self) -> bool: + """ + Check if build output exists. + + Returns: + True if at least one built .js file exists + """ + if not self.build_output_dir.exists(): + return False + + js_files = list(self.build_output_dir.glob("*.js")) + return len(js_files) > 0 + + def check_build_outdated(self) -> bool: + """ + Check if source code is newer than build output. + + Returns: + True if source is newer, False otherwise or if can't determine + """ + if not self.src_dir.exists(): + return False + + if not self.check_build_exists(): + return True + + try: + # Get newest file in source directory + src_files = [f for f in self.src_dir.rglob("*") if f.is_file()] + if not src_files: + return False + + newest_src_time = max(f.stat().st_mtime for f in src_files) + + # Get oldest file in build directory + build_files = [f for f in self.build_output_dir.rglob("*.js") if f.is_file()] + if not build_files: + return True + + oldest_build_time = min(f.stat().st_mtime for f in build_files) + + return newest_src_time > oldest_build_time + + except Exception as e: + logger.debug(f"Error checking build timestamps: {e}") + return False + + def check_node_available(self) -> bool: + """ + Check if Node.js is available. + + Returns: + True if node/npm are available + """ + try: + result = subprocess.run( + ["npm", "--version"], + capture_output=True, + timeout=5, + check=False + ) + return result.returncode == 0 + except (FileNotFoundError, subprocess.TimeoutExpired): + return False + + def build_widgets(self, force: bool = False) -> bool: + """ + Build Vue widgets. + + Args: + force: If True, build even if not needed + + Returns: + True if build succeeded or not needed, False if failed + """ + if not force and self.check_build_exists() and not self.check_build_outdated(): + logger.debug("Vue widgets build is up to date") + return True + + if not self.vue_widgets_dir.exists(): + logger.warning(f"Vue widgets directory not found: {self.vue_widgets_dir}") + return False + + if not self.check_node_available(): + logger.warning( + "Node.js/npm not found. Cannot build Vue widgets. " + "Please install Node.js or build manually: cd vue-widgets && npm run build" + ) + return False + + logger.info("Building Vue widgets...") + + try: + # Check if node_modules exists, if not run npm install first + node_modules = self.vue_widgets_dir / "node_modules" + if not node_modules.exists(): + logger.info("Installing npm dependencies...") + install_result = subprocess.run( + ["npm", "install"], + cwd=self.vue_widgets_dir, + capture_output=True, + timeout=300, # 5 minutes for install + check=False + ) + + if install_result.returncode != 0: + logger.error(f"npm install failed: {install_result.stderr.decode()}") + return False + + # Run build + build_result = subprocess.run( + ["npm", "run", "build"], + cwd=self.vue_widgets_dir, + capture_output=True, + timeout=120, # 2 minutes for build + check=False + ) + + if build_result.returncode == 0: + logger.info("✓ Vue widgets built successfully") + return True + else: + logger.error(f"Build failed: {build_result.stderr.decode()}") + return False + + except subprocess.TimeoutExpired: + logger.error("Build timed out") + return False + except Exception as e: + logger.error(f"Build error: {e}") + return False + + def ensure_built(self, auto_build: bool = True, warn_only: bool = True) -> bool: + """ + Ensure Vue widgets are built, optionally auto-building if needed. + + Args: + auto_build: If True, attempt to build if needed + warn_only: If True, only warn on failure instead of raising + + Returns: + True if widgets are available (built or successfully auto-built) + + Raises: + RuntimeError: If warn_only=False and build is missing/failed + """ + if self.check_build_exists(): + # Build exists, check if outdated + if self.check_build_outdated(): + logger.info("Vue widget source code is newer than build") + if auto_build: + return self.build_widgets() + else: + logger.warning( + "Vue widget build is outdated. " + "Please rebuild: cd vue-widgets && npm run build" + ) + return True + + # No build exists + logger.warning("Vue widget build not found") + + if auto_build: + if self.build_widgets(): + return True + else: + msg = ( + "Failed to build Vue widgets. " + "Please build manually: cd vue-widgets && npm install && npm run build" + ) + if warn_only: + logger.warning(msg) + return False + else: + raise RuntimeError(msg) + else: + msg = "Vue widgets not built. Please run: cd vue-widgets && npm install && npm run build" + if warn_only: + logger.warning(msg) + return False + else: + raise RuntimeError(msg) + + +def check_and_build_vue_widgets( + auto_build: bool = True, + warn_only: bool = True, + force: bool = False +) -> bool: + """ + Convenience function to check and build Vue widgets. + + Args: + auto_build: If True, attempt to build if needed + warn_only: If True, only warn on failure instead of raising + force: If True, force rebuild even if up to date + + Returns: + True if widgets are available + """ + builder = VueWidgetBuilder() + + if force: + return builder.build_widgets(force=True) + + return builder.ensure_built(auto_build=auto_build, warn_only=warn_only) diff --git a/vue-widgets/.gitignore b/vue-widgets/.gitignore new file mode 100644 index 00000000..a4d699a9 --- /dev/null +++ b/vue-widgets/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +*.local +.DS_Store diff --git a/vue-widgets/DEMO_INSTRUCTIONS.md b/vue-widgets/DEMO_INSTRUCTIONS.md new file mode 100644 index 00000000..86515cbf --- /dev/null +++ b/vue-widgets/DEMO_INSTRUCTIONS.md @@ -0,0 +1,179 @@ +# Demo Widget Testing Instructions + +## What Was Created + +A complete Vue + PrimeVue development scaffold for creating custom ComfyUI widgets, including a working demo to validate the entire workflow. + +## Components + +### 1. Python Node (`py/nodes/demo_vue_widget_node.py`) +- **Node Name**: LoRA Manager Demo (Vue) +- **Category**: loramanager/demo +- **Inputs**: + - `lora_demo_widget` (custom widget) + - `text` (optional string) +- **Outputs**: + - `model_name` (STRING) + - `strength` (FLOAT) + - `info` (STRING) + +### 2. Vue Widget (`vue-widgets/src/components/DemoWidget.vue`) +Uses PrimeVue components: +- **InputText** - For model name input +- **InputNumber** - For strength value (0-2, step 0.1) with +/- buttons +- **Button** - Apply and Reset actions +- **Card** - Display current configuration + +### 3. Build System +- **Vite** - Fast build tool +- **TypeScript** - Type-safe development +- **Output**: `web/comfyui/vue-widgets/demo-widget.js` + +## How to Test + +### 1. Build the Widget (if not already built) + +```bash +cd vue-widgets +npm install # Only needed once +npm run build +``` + +### 2. Start/Restart ComfyUI + +```bash +# In your ComfyUI root directory +python main.py +``` + +### 3. Add the Demo Node + +1. Open ComfyUI in your browser (usually http://localhost:8188) +2. Right-click on the canvas → **Add Node** +3. Navigate to: **loramanager** → **demo** → **LoRA Manager Demo (Vue)** +4. The node should appear with a Vue-powered widget inside + +### 4. Test the Widget + +The widget provides an interactive demo: + +1. **Enter a model name** in the text field (e.g., "test-lora-model") +2. **Adjust the strength** using the number input or +/- buttons (0.0 - 2.0) +3. **Click "Apply"** to set the configuration +4. A card will appear showing the current configuration +5. **Click "Reset"** to clear everything + +### 5. Test Workflow Integration + +1. Add some input/output nodes to create a minimal workflow +2. Connect the demo node outputs to other nodes: + - `model_name` → Can connect to any STRING input + - `strength` → Can connect to any FLOAT input + - `info` → Informational STRING output +3. Click **Queue Prompt** to execute the workflow +4. Check the console/terminal - you should see: + ``` + [LoraManagerDemoNode] Vue Widget Demo - Model: test-lora-model, Strength: 1.5 + ``` + +### 6. Test State Persistence + +1. Configure the widget (set model name and strength, click Apply) +2. Save the workflow (Ctrl+S / Cmd+S) +3. Reload the page +4. Load the saved workflow +5. The widget should restore its state + +## Expected Behavior + +✅ **Success Indicators:** +- Widget appears inside the node with proper styling +- PrimeVue components are rendered correctly +- Buttons respond to clicks +- Input values update reactively +- Configuration card appears after clicking Apply +- Node outputs the correct data when workflow executes +- State persists when saving/loading workflows + +❌ **Common Issues:** + +**Widget doesn't appear:** +- Check browser console for JavaScript errors +- Verify `web/comfyui/vue-widgets/demo-widget.js` exists +- Restart ComfyUI completely + +**Build errors:** +- Make sure you're in the `vue-widgets` directory when running npm commands +- Check Node.js version: `node --version` (should be 18+) +- Try deleting `node_modules` and running `npm install` again + +**Widget shows but crashes:** +- Check browser console for errors +- Verify PrimeVue components are imported correctly +- Check that the widget type matches between Python and JavaScript + +## Development Workflow + +For active development: + +```bash +# Terminal 1: Watch mode for auto-rebuild +cd vue-widgets +npm run dev + +# Terminal 2: ComfyUI server +cd ../../.. # Back to ComfyUI root +python main.py +``` + +When you make changes to Vue files: +1. Vite automatically rebuilds +2. Hard refresh the browser (Ctrl+Shift+R / Cmd+Shift+R) +3. Changes should appear + +## Next Steps + +Now that the demo works, you can: + +1. **Modify the demo widget** to add more features +2. **Create new widgets** for actual LoRA Manager functionality +3. **Add more PrimeVue components** (see [PrimeVue Docs](https://primevue.org/)) +4. **Integrate with the LoRA Manager API** to fetch real data +5. **Add styling** to match ComfyUI's theme better + +## File Structure Reference + +``` +ComfyUI-Lora-Manager/ +├── vue-widgets/ # Vue source code +│ ├── src/ +│ │ ├── main.ts # Extension registration +│ │ └── components/ +│ │ └── DemoWidget.vue # Demo widget component +│ ├── package.json # Dependencies +│ ├── vite.config.mts # Build config +│ ├── tsconfig.json # TypeScript config +│ ├── README.md # Development guide +│ └── DEMO_INSTRUCTIONS.md # This file +│ +├── web/comfyui/ +│ └── vue-widgets/ # Build output (gitignored) +│ ├── demo-widget.js # Compiled JavaScript +│ └── assets/ +│ └── demo-widget-*.css # Compiled CSS +│ +├── py/nodes/ +│ └── demo_vue_widget_node.py # Python node definition +│ +├── __init__.py # Updated with demo node +├── VUE_WIDGETS_SETUP.md # Complete setup guide +└── .gitignore # Updated to ignore build output +``` + +## Support + +For issues or questions: +1. Check the browser console for errors +2. Check the ComfyUI terminal for Python errors +3. Review `VUE_WIDGETS_SETUP.md` for detailed documentation +4. Review `vue-widgets/README.md` for development guide diff --git a/vue-widgets/README.md b/vue-widgets/README.md new file mode 100644 index 00000000..d7812d08 --- /dev/null +++ b/vue-widgets/README.md @@ -0,0 +1,169 @@ +# Vue Widgets for ComfyUI LoRA Manager + +This directory contains the source code for Vue 3 + PrimeVue custom widgets for ComfyUI LoRA Manager. + +## Structure + +``` +vue-widgets/ +├── src/ # TypeScript/Vue source code +│ ├── main.ts # Main entry point that registers extensions +│ └── components/ # Vue components +│ └── DemoWidget.vue # Example demo widget +├── package.json # Dependencies and build scripts +├── vite.config.mts # Vite build configuration +├── tsconfig.json # TypeScript configuration +└── README.md # This file +``` + +## Development + +### Install Dependencies + +```bash +cd vue-widgets +npm install +``` + +### Build for Production + +```bash +npm run build +``` + +This compiles the TypeScript/Vue code and outputs to `../web/comfyui/vue-widgets/`. + +### Development Mode (Watch) + +```bash +npm run dev +``` + +This builds the widgets in watch mode, automatically rebuilding when files change. + +### Type Checking + +```bash +npm run typecheck +``` + +## Creating a New Widget + +### 1. Create the Python Node + +Create a new node file in `/py/nodes/your_node.py`: + +```python +class YourCustomNode: + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "your_widget_name": ("YOUR_WIDGET_TYPE", {}), + } + } + + RETURN_TYPES = ("STRING",) + FUNCTION = "process" + CATEGORY = "loramanager" + + def process(self, your_widget_name): + # Process widget data + return (str(your_widget_name),) + +NODE_CLASS_MAPPINGS = { + "YourCustomNode": YourCustomNode +} +``` + +### 2. Create the Vue Component + +Create a new component in `src/components/YourWidget.vue`: + +```vue + + + + + +``` + +### 3. Register the Widget + +In `src/main.ts`, add your widget registration: + +```typescript +import YourWidget from '@/components/YourWidget.vue' + +// In getCustomWidgets() +YOUR_WIDGET_TYPE(node) { + return createVueWidget(node, YourWidget, 'your-widget-name') +} + +// In nodeCreated() +if (node.constructor?.comfyClass !== 'YourCustomNode') return +``` + +### 4. Register the Node + +Add your node to `__init__.py`: + +```python +from .py.nodes.your_node import YourCustomNode + +NODE_CLASS_MAPPINGS = { + # ... + "YourCustomNode": YourCustomNode +} +``` + +### 5. Build and Test + +```bash +npm run build +``` + +Then restart ComfyUI and test your new widget! + +## Available PrimeVue Components + +This project uses PrimeVue 4.x. Popular components include: + +- `Button` - Buttons with icons and variants +- `InputText` - Text input fields +- `InputNumber` - Number input with increment/decrement +- `Dropdown` - Select dropdowns +- `Card` - Card containers +- `DataTable` - Data tables with sorting/filtering +- `Dialog` - Modal dialogs +- `Tree` - Tree view components +- And many more! See [PrimeVue Docs](https://primevue.org/) + +## Notes + +- Build output goes to `../web/comfyui/vue-widgets/` (gitignored) +- The widget type name in Python (e.g., "YOUR_WIDGET_TYPE") must match the key in `getCustomWidgets()` +- Widget data is serialized when the workflow is saved/executed via `serializeValue()` +- ComfyUI's app.js is marked as external and not bundled diff --git a/vue-widgets/package-lock.json b/vue-widgets/package-lock.json new file mode 100644 index 00000000..1cbb8cce --- /dev/null +++ b/vue-widgets/package-lock.json @@ -0,0 +1,1694 @@ +{ + "name": "comfyui-lora-manager-vue-widgets", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "comfyui-lora-manager-vue-widgets", + "version": "1.0.0", + "dependencies": { + "primevue": "^4.2.5", + "vue": "^3.5.13", + "vue-i18n": "^9.14.0" + }, + "devDependencies": { + "@comfyorg/comfyui-frontend-types": "^1.35.4", + "@types/node": "^22.10.1", + "@vitejs/plugin-vue": "^5.2.3", + "typescript": "^5.7.2", + "vite": "^6.3.5", + "vue-tsc": "^2.1.10" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@comfyorg/comfyui-frontend-types": { + "version": "1.37.8", + "resolved": "https://registry.npmjs.org/@comfyorg/comfyui-frontend-types/-/comfyui-frontend-types-1.37.8.tgz", + "integrity": "sha512-3VFPTpPJdni5FHN7is5f91mOdKumXQseNmJMP9JlEF8q0Xm2x9tyNMyJq04WjDVG2DuHJpaQI4nkbvjUAWU2QA==", + "dev": true, + "license": "GPL-3.0-only", + "peerDependencies": { + "vue": "^3.5.13", + "zod": "^3.23.8" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@intlify/core-base": { + "version": "9.14.5", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.14.5.tgz", + "integrity": "sha512-5ah5FqZG4pOoHjkvs8mjtv+gPKYU0zCISaYNjBNNqYiaITxW8ZtVih3GS/oTOqN8d9/mDLyrjD46GBApNxmlsA==", + "license": "MIT", + "dependencies": { + "@intlify/message-compiler": "9.14.5", + "@intlify/shared": "9.14.5" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/message-compiler": { + "version": "9.14.5", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.14.5.tgz", + "integrity": "sha512-IHzgEu61/YIpQV5Pc3aRWScDcnFKWvQA9kigcINcCBXN8mbW+vk9SK+lDxA6STzKQsVJxUPg9ACC52pKKo3SVQ==", + "license": "MIT", + "dependencies": { + "@intlify/shared": "9.14.5", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/shared": { + "version": "9.14.5", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.14.5.tgz", + "integrity": "sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@primeuix/styled": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@primeuix/styled/-/styled-0.7.4.tgz", + "integrity": "sha512-QSO/NpOQg8e9BONWRBx9y8VGMCMYz0J/uKfNJEya/RGEu7ARx0oYW0ugI1N3/KB1AAvyGxzKBzGImbwg0KUiOQ==", + "license": "MIT", + "dependencies": { + "@primeuix/utils": "^0.6.1" + }, + "engines": { + "node": ">=12.11.0" + } + }, + "node_modules/@primeuix/styles": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@primeuix/styles/-/styles-2.0.2.tgz", + "integrity": "sha512-LNtkJsTonNHF5ag+9s3+zQzm00+LRmffw68QRIHy6S/dam1JpdrrAnUzNYlWbaY7aE2EkZvQmx7Np7+PyHn+ow==", + "license": "MIT", + "dependencies": { + "@primeuix/styled": "^0.7.4" + } + }, + "node_modules/@primeuix/utils": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@primeuix/utils/-/utils-0.6.3.tgz", + "integrity": "sha512-/SLNQSKQ73WbBIsflKVqbpVjCfFYvQO3Sf1LMheXyxh8JqxO4M63dzP56wwm9OPGuCQ6MYOd2AHgZXz+g7PZcg==", + "license": "MIT", + "engines": { + "node": ">=12.11.0" + } + }, + "node_modules/@primevue/core": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/@primevue/core/-/core-4.5.4.tgz", + "integrity": "sha512-lYJJB3wTrDJ8MkLctzHfrPZAqXVxoatjIsswSJzupatf6ZogJHVYADUKcn1JAkLLk8dtV1FA2AxDek663fHO5Q==", + "license": "MIT", + "dependencies": { + "@primeuix/styled": "^0.7.4", + "@primeuix/utils": "^0.6.2" + }, + "engines": { + "node": ">=12.11.0" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/@primevue/icons": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/@primevue/icons/-/icons-4.5.4.tgz", + "integrity": "sha512-DxgryEc7ZmUqcEhYMcxGBRyFzdtLIoy3jLtlH1zsVSRZaG+iSAcjQ88nvfkZxGUZtZBFL7sRjF6KLq3bJZJwUw==", + "license": "MIT", + "dependencies": { + "@primeuix/utils": "^0.6.2", + "@primevue/core": "4.5.4" + }, + "engines": { + "node": ">=12.11.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", + "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", + "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", + "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", + "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", + "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", + "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", + "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", + "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", + "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", + "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", + "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", + "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", + "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", + "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", + "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", + "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", + "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz", + "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", + "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", + "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", + "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", + "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", + "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", + "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", + "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.19.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.5.tgz", + "integrity": "sha512-HfF8+mYcHPcPypui3w3mvzuIErlNOh2OAG+BCeBZCEwyiD5ls2SiCwEyT47OELtf7M3nHxBdu0FsmzdKxkN52Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.15.tgz", + "integrity": "sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.15" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.15.tgz", + "integrity": "sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.15.tgz", + "integrity": "sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.15", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.26", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.26.tgz", + "integrity": "sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@vue/shared": "3.5.26", + "entities": "^7.0.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.26", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.26.tgz", + "integrity": "sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.26", + "@vue/shared": "3.5.26" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.26", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.26.tgz", + "integrity": "sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@vue/compiler-core": "3.5.26", + "@vue/compiler-dom": "3.5.26", + "@vue/compiler-ssr": "3.5.26", + "@vue/shared": "3.5.26", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.26", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.26.tgz", + "integrity": "sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.26", + "@vue/shared": "3.5.26" + } + }, + "node_modules/@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", + "dev": true, + "license": "MIT", + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/@vue/language-core": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.12.tgz", + "integrity": "sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.15", + "@vue/compiler-dom": "^3.5.0", + "@vue/compiler-vue2": "^2.7.16", + "@vue/shared": "^3.5.0", + "alien-signals": "^1.0.3", + "minimatch": "^9.0.3", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.26", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.26.tgz", + "integrity": "sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.26" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.26", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.26.tgz", + "integrity": "sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.26", + "@vue/shared": "3.5.26" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.26", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.26.tgz", + "integrity": "sha512-XLLd/+4sPC2ZkN/6+V4O4gjJu6kSDbHAChvsyWgm1oGbdSO3efvGYnm25yCjtFm/K7rrSDvSfPDgN1pHgS4VNQ==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.26", + "@vue/runtime-core": "3.5.26", + "@vue/shared": "3.5.26", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.26", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.26.tgz", + "integrity": "sha512-TYKLXmrwWKSodyVuO1WAubucd+1XlLg4set0YoV+Hu8Lo79mp/YMwWV5mC5FgtsDxX3qo1ONrxFaTP1OQgy1uA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.26", + "@vue/shared": "3.5.26" + }, + "peerDependencies": { + "vue": "3.5.26" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.26", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.26.tgz", + "integrity": "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==", + "license": "MIT" + }, + "node_modules/alien-signals": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-1.0.13.tgz", + "integrity": "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/entities": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.0.tgz", + "integrity": "sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/fdir": { + "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" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/primevue": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/primevue/-/primevue-4.5.4.tgz", + "integrity": "sha512-nTyEohZABFJhVIpeUxgP0EJ8vKcJAhD+Z7DYj95e7ie/MNUCjRNcGjqmE1cXtXi4z54qDfTSI9h2uJ51qz2DIw==", + "license": "MIT", + "dependencies": { + "@primeuix/styled": "^0.7.4", + "@primeuix/styles": "^2.0.2", + "@primeuix/utils": "^0.6.2", + "@primevue/core": "4.5.4", + "@primevue/icons": "4.5.4" + }, + "engines": { + "node": ">=12.11.0" + } + }, + "node_modules/rollup": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", + "integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.55.1", + "@rollup/rollup-android-arm64": "4.55.1", + "@rollup/rollup-darwin-arm64": "4.55.1", + "@rollup/rollup-darwin-x64": "4.55.1", + "@rollup/rollup-freebsd-arm64": "4.55.1", + "@rollup/rollup-freebsd-x64": "4.55.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", + "@rollup/rollup-linux-arm-musleabihf": "4.55.1", + "@rollup/rollup-linux-arm64-gnu": "4.55.1", + "@rollup/rollup-linux-arm64-musl": "4.55.1", + "@rollup/rollup-linux-loong64-gnu": "4.55.1", + "@rollup/rollup-linux-loong64-musl": "4.55.1", + "@rollup/rollup-linux-ppc64-gnu": "4.55.1", + "@rollup/rollup-linux-ppc64-musl": "4.55.1", + "@rollup/rollup-linux-riscv64-gnu": "4.55.1", + "@rollup/rollup-linux-riscv64-musl": "4.55.1", + "@rollup/rollup-linux-s390x-gnu": "4.55.1", + "@rollup/rollup-linux-x64-gnu": "4.55.1", + "@rollup/rollup-linux-x64-musl": "4.55.1", + "@rollup/rollup-openbsd-x64": "4.55.1", + "@rollup/rollup-openharmony-arm64": "4.55.1", + "@rollup/rollup-win32-arm64-msvc": "4.55.1", + "@rollup/rollup-win32-ia32-msvc": "4.55.1", + "@rollup/rollup-win32-x64-gnu": "4.55.1", + "@rollup/rollup-win32-x64-msvc": "4.55.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "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.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.26", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.26.tgz", + "integrity": "sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/compiler-dom": "3.5.26", + "@vue/compiler-sfc": "3.5.26", + "@vue/runtime-dom": "3.5.26", + "@vue/server-renderer": "3.5.26", + "@vue/shared": "3.5.26" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-i18n": { + "version": "9.14.5", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.14.5.tgz", + "integrity": "sha512-0jQ9Em3ymWngyiIkj0+c/k7WgaPO+TNzjKSNq9BvBQaKJECqn9cd9fL4tkDhB5G1QBskGl9YxxbDAhgbFtpe2g==", + "deprecated": "v9 and v10 no longer supported. please migrate to v11. about maintenance status, see https://vue-i18n.intlify.dev/guide/maintenance.html", + "license": "MIT", + "dependencies": { + "@intlify/core-base": "9.14.5", + "@intlify/shared": "9.14.5", + "@vue/devtools-api": "^6.5.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/vue-tsc": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.2.12.tgz", + "integrity": "sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "2.4.15", + "@vue/language-core": "2.2.12" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/vue-widgets/package.json b/vue-widgets/package.json new file mode 100644 index 00000000..7d6175e2 --- /dev/null +++ b/vue-widgets/package.json @@ -0,0 +1,28 @@ +{ + "name": "comfyui-lora-manager-vue-widgets", + "version": "1.0.0", + "type": "module", + "description": "Vue-based custom widgets for ComfyUI LoRA Manager", + "dependencies": { + "vue": "^3.5.13", + "vue-i18n": "^9.14.0", + "primevue": "^4.2.5" + }, + "devDependencies": { + "@comfyorg/comfyui-frontend-types": "^1.35.4", + "@types/node": "^22.10.1", + "@vitejs/plugin-vue": "^5.2.3", + "typescript": "^5.7.2", + "vite": "^6.3.5", + "vue-tsc": "^2.1.10" + }, + "scripts": { + "dev": "vite build --watch", + "build": "vite build", + "build:production": "vite build --mode production", + "typecheck": "vue-tsc --noEmit", + "clean": "rm -rf ../web/comfyui/vue-widgets", + "rebuild": "npm run clean && npm run build", + "prepare": "npm run build" + } +} diff --git a/vue-widgets/pre-commit.example b/vue-widgets/pre-commit.example new file mode 100644 index 00000000..a7c8ebe3 --- /dev/null +++ b/vue-widgets/pre-commit.example @@ -0,0 +1,37 @@ +#!/bin/sh +# +# Example pre-commit hook to ensure Vue widgets are built before committing +# +# To use this hook: +# 1. Copy this file to .git/hooks/pre-commit +# 2. Make it executable: chmod +x .git/hooks/pre-commit +# +# Or use a tool like Husky for automatic hook management: +# npm install --save-dev husky +# npx husky install +# npx husky add .git/hooks/pre-commit "cd vue-widgets && npm run build" + +echo "Running pre-commit hook: Building Vue widgets..." + +# Navigate to vue-widgets directory and build +cd "$(git rev-parse --show-toplevel)/vue-widgets" || exit 1 + +# Check if node_modules exists +if [ ! -d "node_modules" ]; then + echo "node_modules not found, running npm install..." + npm install || exit 1 +fi + +# Build Vue widgets +npm run build || { + echo "❌ Vue widget build failed! Commit aborted." + echo "Please fix the build errors before committing." + exit 1 +} + +# Add built files to the commit +cd .. +git add web/comfyui/vue-widgets/ + +echo "✓ Vue widgets built and staged successfully" +exit 0 diff --git a/vue-widgets/src/components/DemoWidget.vue b/vue-widgets/src/components/DemoWidget.vue new file mode 100644 index 00000000..adf0723f --- /dev/null +++ b/vue-widgets/src/components/DemoWidget.vue @@ -0,0 +1,176 @@ + + + + + diff --git a/vue-widgets/src/main.ts b/vue-widgets/src/main.ts new file mode 100644 index 00000000..fd691c3b --- /dev/null +++ b/vue-widgets/src/main.ts @@ -0,0 +1,73 @@ +import { createApp, type App as VueApp } from 'vue' +import PrimeVue from 'primevue/config' +import DemoWidget from '@/components/DemoWidget.vue' + +// @ts-ignore - ComfyUI external module +import { app } from '../../../scripts/app.js' + +const vueApps = new Map() + +// @ts-ignore +function createVueWidget(node) { + const container = document.createElement('div') + container.id = `lora-manager-demo-widget-${node.id}` + container.style.width = '100%' + container.style.height = '100%' + container.style.minHeight = '300px' + container.style.display = 'flex' + container.style.flexDirection = 'column' + container.style.overflow = 'hidden' + + const widget = node.addDOMWidget( + 'lora_demo_widget', + 'lora-manager-demo', + container, + { + getMinHeight: () => 320, + hideOnZoom: false, + serialize: true + } + ) + + const vueApp = createApp(DemoWidget, { + widget, + node + }) + + vueApp.use(PrimeVue) + + vueApp.mount(container) + vueApps.set(node.id, vueApp) + + widget.onRemove = () => { + const vueApp = vueApps.get(node.id) + if (vueApp) { + vueApp.unmount() + vueApps.delete(node.id) + } + } + + return { widget } +} + +app.registerExtension({ + name: 'comfyui.loramanager.demo', + + getCustomWidgets() { + return { + // @ts-ignore + LORA_DEMO_WIDGET(node) { + return createVueWidget(node) + } + } + }, + + // @ts-ignore + nodeCreated(node) { + if (node.constructor?.comfyClass !== 'LoraManagerDemoNode') return + + const [oldWidth, oldHeight] = node.size + + node.setSize([Math.max(oldWidth, 350), Math.max(oldHeight, 400)]) + } +}) diff --git a/vue-widgets/tsconfig.json b/vue-widgets/tsconfig.json new file mode 100644 index 00000000..4b6a33ba --- /dev/null +++ b/vue-widgets/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/vue-widgets/tsconfig.node.json b/vue-widgets/tsconfig.node.json new file mode 100644 index 00000000..a8583534 --- /dev/null +++ b/vue-widgets/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.mts"] +} diff --git a/vue-widgets/vite.config.mts b/vue-widgets/vite.config.mts new file mode 100644 index 00000000..861b6fce --- /dev/null +++ b/vue-widgets/vite.config.mts @@ -0,0 +1,35 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import { resolve } from 'path' + +export default defineConfig({ + plugins: [vue()], + resolve: { + alias: { + '@': resolve(__dirname, './src') + } + }, + build: { + lib: { + entry: resolve(__dirname, './src/main.ts'), + formats: ['es'], + fileName: 'demo-widget' + }, + rollupOptions: { + external: [ + '../../../scripts/app.js' + ], + output: { + dir: '../web/comfyui/vue-widgets', + entryFileNames: 'demo-widget.js', + chunkFileNames: 'assets/[name]-[hash].js', + assetFileNames: 'assets/[name]-[hash][extname]' + } + }, + sourcemap: true, + minify: false + }, + define: { + 'process.env.NODE_ENV': JSON.stringify('production') + } +}) diff --git a/web/comfyui/vue-widgets/assets/demo-widget-RA_dFMfB.css b/web/comfyui/vue-widgets/assets/demo-widget-RA_dFMfB.css new file mode 100644 index 00000000..d09e5469 --- /dev/null +++ b/web/comfyui/vue-widgets/assets/demo-widget-RA_dFMfB.css @@ -0,0 +1,56 @@ + +.demo-widget-container[data-v-df0cb94d] { + padding: 12px; + box-sizing: border-box; + background: var(--comfy-menu-bg); + border-radius: 4px; + height: 100%; + display: flex; + flex-direction: column; +} +.demo-title[data-v-df0cb94d] { + margin: 0 0 12px 0; + font-size: 16px; + font-weight: 600; + color: var(--fg-color); +} +.demo-content[data-v-df0cb94d] { + display: flex; + flex-direction: column; + gap: 12px; + flex: 1; +} +.input-group[data-v-df0cb94d] { + display: flex; + flex-direction: column; + gap: 6px; +} +.input-group label[data-v-df0cb94d] { + font-size: 13px; + font-weight: 500; + color: var(--fg-color); +} +.demo-input[data-v-df0cb94d] { + width: 100%; +} +.button-group[data-v-df0cb94d] { + display: flex; + gap: 8px; + margin-top: 8px; +} +.result-card[data-v-df0cb94d] { + margin-top: 8px; + background: var(--comfy-input-bg); +} +.result-card[data-v-df0cb94d] .p-card-title { + font-size: 14px; + margin-bottom: 8px; +} +.result-card[data-v-df0cb94d] .p-card-content { + padding-top: 0; +} +.result-card p[data-v-df0cb94d] { + margin: 4px 0; + font-size: 13px; + color: var(--fg-color); +} diff --git a/web/comfyui/vue-widgets/demo-widget.js b/web/comfyui/vue-widgets/demo-widget.js new file mode 100644 index 00000000..89363eeb --- /dev/null +++ b/web/comfyui/vue-widgets/demo-widget.js @@ -0,0 +1,11672 @@ +import { app } from "../../../scripts/app.js"; +/** +* @vue/shared v3.5.26 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/ +// @__NO_SIDE_EFFECTS__ +function makeMap(str) { + const map = /* @__PURE__ */ Object.create(null); + for (const key of str.split(",")) map[key] = 1; + return (val) => val in map; +} +const EMPTY_OBJ = {}; +const EMPTY_ARR = []; +const NOOP = () => { +}; +const NO = () => false; +const isOn = (key) => key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110 && // uppercase letter +(key.charCodeAt(2) > 122 || key.charCodeAt(2) < 97); +const isModelListener = (key) => key.startsWith("onUpdate:"); +const extend = Object.assign; +const remove = (arr, el) => { + const i2 = arr.indexOf(el); + if (i2 > -1) { + arr.splice(i2, 1); + } +}; +const hasOwnProperty$1 = Object.prototype.hasOwnProperty; +const hasOwn = (val, key) => hasOwnProperty$1.call(val, key); +const isArray = Array.isArray; +const isMap = (val) => toTypeString(val) === "[object Map]"; +const isSet = (val) => toTypeString(val) === "[object Set]"; +const isFunction = (val) => typeof val === "function"; +const isString = (val) => typeof val === "string"; +const isSymbol = (val) => typeof val === "symbol"; +const isObject = (val) => val !== null && typeof val === "object"; +const isPromise = (val) => { + return (isObject(val) || isFunction(val)) && isFunction(val.then) && isFunction(val.catch); +}; +const objectToString = Object.prototype.toString; +const toTypeString = (value) => objectToString.call(value); +const toRawType = (value) => { + return toTypeString(value).slice(8, -1); +}; +const isPlainObject = (val) => toTypeString(val) === "[object Object]"; +const isIntegerKey = (key) => isString(key) && key !== "NaN" && key[0] !== "-" && "" + parseInt(key, 10) === key; +const isReservedProp = /* @__PURE__ */ makeMap( + // the leading comma is intentional so empty string "" is also included + ",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted" +); +const cacheStringFunction = (fn) => { + const cache = /* @__PURE__ */ Object.create(null); + return ((str) => { + const hit = cache[str]; + return hit || (cache[str] = fn(str)); + }); +}; +const camelizeRE = /-\w/g; +const camelize = cacheStringFunction( + (str) => { + return str.replace(camelizeRE, (c2) => c2.slice(1).toUpperCase()); + } +); +const hyphenateRE = /\B([A-Z])/g; +const hyphenate = cacheStringFunction( + (str) => str.replace(hyphenateRE, "-$1").toLowerCase() +); +const capitalize = cacheStringFunction((str) => { + return str.charAt(0).toUpperCase() + str.slice(1); +}); +const toHandlerKey = cacheStringFunction( + (str) => { + const s2 = str ? `on${capitalize(str)}` : ``; + return s2; + } +); +const hasChanged = (value, oldValue) => !Object.is(value, oldValue); +const invokeArrayFns = (fns, ...arg) => { + for (let i2 = 0; i2 < fns.length; i2++) { + fns[i2](...arg); + } +}; +const def = (obj, key, value, writable = false) => { + Object.defineProperty(obj, key, { + configurable: true, + enumerable: false, + writable, + value + }); +}; +const looseToNumber = (val) => { + const n = parseFloat(val); + return isNaN(n) ? val : n; +}; +let _globalThis; +const getGlobalThis = () => { + return _globalThis || (_globalThis = typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {}); +}; +function normalizeStyle(value) { + if (isArray(value)) { + const res = {}; + for (let i2 = 0; i2 < value.length; i2++) { + const item = value[i2]; + const normalized = isString(item) ? parseStringStyle(item) : normalizeStyle(item); + if (normalized) { + for (const key in normalized) { + res[key] = normalized[key]; + } + } + } + return res; + } else if (isString(value) || isObject(value)) { + return value; + } +} +const listDelimiterRE = /;(?![^(]*\))/g; +const propertyDelimiterRE = /:([^]+)/; +const styleCommentRE = /\/\*[^]*?\*\//g; +function parseStringStyle(cssText) { + const ret = {}; + cssText.replace(styleCommentRE, "").split(listDelimiterRE).forEach((item) => { + if (item) { + const tmp = item.split(propertyDelimiterRE); + tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim()); + } + }); + return ret; +} +function normalizeClass(value) { + let res = ""; + if (isString(value)) { + res = value; + } else if (isArray(value)) { + for (let i2 = 0; i2 < value.length; i2++) { + const normalized = normalizeClass(value[i2]); + if (normalized) { + res += normalized + " "; + } + } + } else if (isObject(value)) { + for (const name in value) { + if (value[name]) { + res += name + " "; + } + } + } + return res.trim(); +} +const specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`; +const isSpecialBooleanAttr = /* @__PURE__ */ makeMap(specialBooleanAttrs); +function includeBooleanAttr(value) { + return !!value || value === ""; +} +const isRef$1 = (val) => { + return !!(val && val["__v_isRef"] === true); +}; +const toDisplayString = (val) => { + return isString(val) ? val : val == null ? "" : isArray(val) || isObject(val) && (val.toString === objectToString || !isFunction(val.toString)) ? isRef$1(val) ? toDisplayString(val.value) : JSON.stringify(val, replacer, 2) : String(val); +}; +const replacer = (_key, val) => { + if (isRef$1(val)) { + return replacer(_key, val.value); + } else if (isMap(val)) { + return { + [`Map(${val.size})`]: [...val.entries()].reduce( + (entries, [key, val2], i2) => { + entries[stringifySymbol(key, i2) + " =>"] = val2; + return entries; + }, + {} + ) + }; + } else if (isSet(val)) { + return { + [`Set(${val.size})`]: [...val.values()].map((v2) => stringifySymbol(v2)) + }; + } else if (isSymbol(val)) { + return stringifySymbol(val); + } else if (isObject(val) && !isArray(val) && !isPlainObject(val)) { + return String(val); + } + return val; +}; +const stringifySymbol = (v2, i2 = "") => { + var _a; + return ( + // Symbol.description in es2019+ so we need to cast here to pass + // the lib: es2016 check + isSymbol(v2) ? `Symbol(${(_a = v2.description) != null ? _a : i2})` : v2 + ); +}; +/** +* @vue/reactivity v3.5.26 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/ +let activeEffectScope; +class EffectScope { + constructor(detached = false) { + this.detached = detached; + this._active = true; + this._on = 0; + this.effects = []; + this.cleanups = []; + this._isPaused = false; + this.parent = activeEffectScope; + if (!detached && activeEffectScope) { + this.index = (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push( + this + ) - 1; + } + } + get active() { + return this._active; + } + pause() { + if (this._active) { + this._isPaused = true; + let i2, l2; + if (this.scopes) { + for (i2 = 0, l2 = this.scopes.length; i2 < l2; i2++) { + this.scopes[i2].pause(); + } + } + for (i2 = 0, l2 = this.effects.length; i2 < l2; i2++) { + this.effects[i2].pause(); + } + } + } + /** + * Resumes the effect scope, including all child scopes and effects. + */ + resume() { + if (this._active) { + if (this._isPaused) { + this._isPaused = false; + let i2, l2; + if (this.scopes) { + for (i2 = 0, l2 = this.scopes.length; i2 < l2; i2++) { + this.scopes[i2].resume(); + } + } + for (i2 = 0, l2 = this.effects.length; i2 < l2; i2++) { + this.effects[i2].resume(); + } + } + } + } + run(fn) { + if (this._active) { + const currentEffectScope = activeEffectScope; + try { + activeEffectScope = this; + return fn(); + } finally { + activeEffectScope = currentEffectScope; + } + } + } + /** + * This should only be called on non-detached scopes + * @internal + */ + on() { + if (++this._on === 1) { + this.prevScope = activeEffectScope; + activeEffectScope = this; + } + } + /** + * This should only be called on non-detached scopes + * @internal + */ + off() { + if (this._on > 0 && --this._on === 0) { + activeEffectScope = this.prevScope; + this.prevScope = void 0; + } + } + stop(fromParent) { + if (this._active) { + this._active = false; + let i2, l2; + for (i2 = 0, l2 = this.effects.length; i2 < l2; i2++) { + this.effects[i2].stop(); + } + this.effects.length = 0; + for (i2 = 0, l2 = this.cleanups.length; i2 < l2; i2++) { + this.cleanups[i2](); + } + this.cleanups.length = 0; + if (this.scopes) { + for (i2 = 0, l2 = this.scopes.length; i2 < l2; i2++) { + this.scopes[i2].stop(true); + } + this.scopes.length = 0; + } + if (!this.detached && this.parent && !fromParent) { + const last = this.parent.scopes.pop(); + if (last && last !== this) { + this.parent.scopes[this.index] = last; + last.index = this.index; + } + } + this.parent = void 0; + } + } +} +function getCurrentScope() { + return activeEffectScope; +} +let activeSub; +const pausedQueueEffects = /* @__PURE__ */ new WeakSet(); +class ReactiveEffect { + constructor(fn) { + this.fn = fn; + this.deps = void 0; + this.depsTail = void 0; + this.flags = 1 | 4; + this.next = void 0; + this.cleanup = void 0; + this.scheduler = void 0; + if (activeEffectScope && activeEffectScope.active) { + activeEffectScope.effects.push(this); + } + } + pause() { + this.flags |= 64; + } + resume() { + if (this.flags & 64) { + this.flags &= -65; + if (pausedQueueEffects.has(this)) { + pausedQueueEffects.delete(this); + this.trigger(); + } + } + } + /** + * @internal + */ + notify() { + if (this.flags & 2 && !(this.flags & 32)) { + return; + } + if (!(this.flags & 8)) { + batch(this); + } + } + run() { + if (!(this.flags & 1)) { + return this.fn(); + } + this.flags |= 2; + cleanupEffect(this); + prepareDeps(this); + const prevEffect = activeSub; + const prevShouldTrack = shouldTrack; + activeSub = this; + shouldTrack = true; + try { + return this.fn(); + } finally { + cleanupDeps(this); + activeSub = prevEffect; + shouldTrack = prevShouldTrack; + this.flags &= -3; + } + } + stop() { + if (this.flags & 1) { + for (let link = this.deps; link; link = link.nextDep) { + removeSub(link); + } + this.deps = this.depsTail = void 0; + cleanupEffect(this); + this.onStop && this.onStop(); + this.flags &= -2; + } + } + trigger() { + if (this.flags & 64) { + pausedQueueEffects.add(this); + } else if (this.scheduler) { + this.scheduler(); + } else { + this.runIfDirty(); + } + } + /** + * @internal + */ + runIfDirty() { + if (isDirty(this)) { + this.run(); + } + } + get dirty() { + return isDirty(this); + } +} +let batchDepth = 0; +let batchedSub; +let batchedComputed; +function batch(sub, isComputed = false) { + sub.flags |= 8; + if (isComputed) { + sub.next = batchedComputed; + batchedComputed = sub; + return; + } + sub.next = batchedSub; + batchedSub = sub; +} +function startBatch() { + batchDepth++; +} +function endBatch() { + if (--batchDepth > 0) { + return; + } + if (batchedComputed) { + let e = batchedComputed; + batchedComputed = void 0; + while (e) { + const next = e.next; + e.next = void 0; + e.flags &= -9; + e = next; + } + } + let error; + while (batchedSub) { + let e = batchedSub; + batchedSub = void 0; + while (e) { + const next = e.next; + e.next = void 0; + e.flags &= -9; + if (e.flags & 1) { + try { + ; + e.trigger(); + } catch (err) { + if (!error) error = err; + } + } + e = next; + } + } + if (error) throw error; +} +function prepareDeps(sub) { + for (let link = sub.deps; link; link = link.nextDep) { + link.version = -1; + link.prevActiveLink = link.dep.activeLink; + link.dep.activeLink = link; + } +} +function cleanupDeps(sub) { + let head; + let tail = sub.depsTail; + let link = tail; + while (link) { + const prev = link.prevDep; + if (link.version === -1) { + if (link === tail) tail = prev; + removeSub(link); + removeDep(link); + } else { + head = link; + } + link.dep.activeLink = link.prevActiveLink; + link.prevActiveLink = void 0; + link = prev; + } + sub.deps = head; + sub.depsTail = tail; +} +function isDirty(sub) { + for (let link = sub.deps; link; link = link.nextDep) { + if (link.dep.version !== link.version || link.dep.computed && (refreshComputed(link.dep.computed) || link.dep.version !== link.version)) { + return true; + } + } + if (sub._dirty) { + return true; + } + return false; +} +function refreshComputed(computed2) { + if (computed2.flags & 4 && !(computed2.flags & 16)) { + return; + } + computed2.flags &= -17; + if (computed2.globalVersion === globalVersion) { + return; + } + computed2.globalVersion = globalVersion; + if (!computed2.isSSR && computed2.flags & 128 && (!computed2.deps && !computed2._dirty || !isDirty(computed2))) { + return; + } + computed2.flags |= 2; + const dep = computed2.dep; + const prevSub = activeSub; + const prevShouldTrack = shouldTrack; + activeSub = computed2; + shouldTrack = true; + try { + prepareDeps(computed2); + const value = computed2.fn(computed2._value); + if (dep.version === 0 || hasChanged(value, computed2._value)) { + computed2.flags |= 128; + computed2._value = value; + dep.version++; + } + } catch (err) { + dep.version++; + throw err; + } finally { + activeSub = prevSub; + shouldTrack = prevShouldTrack; + cleanupDeps(computed2); + computed2.flags &= -3; + } +} +function removeSub(link, soft = false) { + const { dep, prevSub, nextSub } = link; + if (prevSub) { + prevSub.nextSub = nextSub; + link.prevSub = void 0; + } + if (nextSub) { + nextSub.prevSub = prevSub; + link.nextSub = void 0; + } + if (dep.subs === link) { + dep.subs = prevSub; + if (!prevSub && dep.computed) { + dep.computed.flags &= -5; + for (let l2 = dep.computed.deps; l2; l2 = l2.nextDep) { + removeSub(l2, true); + } + } + } + if (!soft && !--dep.sc && dep.map) { + dep.map.delete(dep.key); + } +} +function removeDep(link) { + const { prevDep, nextDep } = link; + if (prevDep) { + prevDep.nextDep = nextDep; + link.prevDep = void 0; + } + if (nextDep) { + nextDep.prevDep = prevDep; + link.nextDep = void 0; + } +} +let shouldTrack = true; +const trackStack = []; +function pauseTracking() { + trackStack.push(shouldTrack); + shouldTrack = false; +} +function resetTracking() { + const last = trackStack.pop(); + shouldTrack = last === void 0 ? true : last; +} +function cleanupEffect(e) { + const { cleanup } = e; + e.cleanup = void 0; + if (cleanup) { + const prevSub = activeSub; + activeSub = void 0; + try { + cleanup(); + } finally { + activeSub = prevSub; + } + } +} +let globalVersion = 0; +class Link { + constructor(sub, dep) { + this.sub = sub; + this.dep = dep; + this.version = dep.version; + this.nextDep = this.prevDep = this.nextSub = this.prevSub = this.prevActiveLink = void 0; + } +} +class Dep { + // TODO isolatedDeclarations "__v_skip" + constructor(computed2) { + this.computed = computed2; + this.version = 0; + this.activeLink = void 0; + this.subs = void 0; + this.map = void 0; + this.key = void 0; + this.sc = 0; + this.__v_skip = true; + } + track(debugInfo) { + if (!activeSub || !shouldTrack || activeSub === this.computed) { + return; + } + let link = this.activeLink; + if (link === void 0 || link.sub !== activeSub) { + link = this.activeLink = new Link(activeSub, this); + if (!activeSub.deps) { + activeSub.deps = activeSub.depsTail = link; + } else { + link.prevDep = activeSub.depsTail; + activeSub.depsTail.nextDep = link; + activeSub.depsTail = link; + } + addSub(link); + } else if (link.version === -1) { + link.version = this.version; + if (link.nextDep) { + const next = link.nextDep; + next.prevDep = link.prevDep; + if (link.prevDep) { + link.prevDep.nextDep = next; + } + link.prevDep = activeSub.depsTail; + link.nextDep = void 0; + activeSub.depsTail.nextDep = link; + activeSub.depsTail = link; + if (activeSub.deps === link) { + activeSub.deps = next; + } + } + } + return link; + } + trigger(debugInfo) { + this.version++; + globalVersion++; + this.notify(debugInfo); + } + notify(debugInfo) { + startBatch(); + try { + if (false) ; + for (let link = this.subs; link; link = link.prevSub) { + if (link.sub.notify()) { + ; + link.sub.dep.notify(); + } + } + } finally { + endBatch(); + } + } +} +function addSub(link) { + link.dep.sc++; + if (link.sub.flags & 4) { + const computed2 = link.dep.computed; + if (computed2 && !link.dep.subs) { + computed2.flags |= 4 | 16; + for (let l2 = computed2.deps; l2; l2 = l2.nextDep) { + addSub(l2); + } + } + const currentTail = link.dep.subs; + if (currentTail !== link) { + link.prevSub = currentTail; + if (currentTail) currentTail.nextSub = link; + } + link.dep.subs = link; + } +} +const targetMap = /* @__PURE__ */ new WeakMap(); +const ITERATE_KEY = /* @__PURE__ */ Symbol( + "" +); +const MAP_KEY_ITERATE_KEY = /* @__PURE__ */ Symbol( + "" +); +const ARRAY_ITERATE_KEY = /* @__PURE__ */ Symbol( + "" +); +function track(target, type, key) { + if (shouldTrack && activeSub) { + let depsMap = targetMap.get(target); + if (!depsMap) { + targetMap.set(target, depsMap = /* @__PURE__ */ new Map()); + } + let dep = depsMap.get(key); + if (!dep) { + depsMap.set(key, dep = new Dep()); + dep.map = depsMap; + dep.key = key; + } + { + dep.track(); + } + } +} +function trigger(target, type, key, newValue, oldValue, oldTarget) { + const depsMap = targetMap.get(target); + if (!depsMap) { + globalVersion++; + return; + } + const run = (dep) => { + if (dep) { + { + dep.trigger(); + } + } + }; + startBatch(); + if (type === "clear") { + depsMap.forEach(run); + } else { + const targetIsArray = isArray(target); + const isArrayIndex = targetIsArray && isIntegerKey(key); + if (targetIsArray && key === "length") { + const newLength = Number(newValue); + depsMap.forEach((dep, key2) => { + if (key2 === "length" || key2 === ARRAY_ITERATE_KEY || !isSymbol(key2) && key2 >= newLength) { + run(dep); + } + }); + } else { + if (key !== void 0 || depsMap.has(void 0)) { + run(depsMap.get(key)); + } + if (isArrayIndex) { + run(depsMap.get(ARRAY_ITERATE_KEY)); + } + switch (type) { + case "add": + if (!targetIsArray) { + run(depsMap.get(ITERATE_KEY)); + if (isMap(target)) { + run(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } else if (isArrayIndex) { + run(depsMap.get("length")); + } + break; + case "delete": + if (!targetIsArray) { + run(depsMap.get(ITERATE_KEY)); + if (isMap(target)) { + run(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } + break; + case "set": + if (isMap(target)) { + run(depsMap.get(ITERATE_KEY)); + } + break; + } + } + } + endBatch(); +} +function reactiveReadArray(array) { + const raw = toRaw(array); + if (raw === array) return raw; + track(raw, "iterate", ARRAY_ITERATE_KEY); + return isShallow(array) ? raw : raw.map(toReactive); +} +function shallowReadArray(arr) { + track(arr = toRaw(arr), "iterate", ARRAY_ITERATE_KEY); + return arr; +} +function toWrapped(target, item) { + if (isReadonly(target)) { + return isReactive(target) ? toReadonly(toReactive(item)) : toReadonly(item); + } + return toReactive(item); +} +const arrayInstrumentations = { + __proto__: null, + [Symbol.iterator]() { + return iterator(this, Symbol.iterator, (item) => toWrapped(this, item)); + }, + concat(...args) { + return reactiveReadArray(this).concat( + ...args.map((x) => isArray(x) ? reactiveReadArray(x) : x) + ); + }, + entries() { + return iterator(this, "entries", (value) => { + value[1] = toWrapped(this, value[1]); + return value; + }); + }, + every(fn, thisArg) { + return apply(this, "every", fn, thisArg, void 0, arguments); + }, + filter(fn, thisArg) { + return apply( + this, + "filter", + fn, + thisArg, + (v2) => v2.map((item) => toWrapped(this, item)), + arguments + ); + }, + find(fn, thisArg) { + return apply( + this, + "find", + fn, + thisArg, + (item) => toWrapped(this, item), + arguments + ); + }, + findIndex(fn, thisArg) { + return apply(this, "findIndex", fn, thisArg, void 0, arguments); + }, + findLast(fn, thisArg) { + return apply( + this, + "findLast", + fn, + thisArg, + (item) => toWrapped(this, item), + arguments + ); + }, + findLastIndex(fn, thisArg) { + return apply(this, "findLastIndex", fn, thisArg, void 0, arguments); + }, + // flat, flatMap could benefit from ARRAY_ITERATE but are not straight-forward to implement + forEach(fn, thisArg) { + return apply(this, "forEach", fn, thisArg, void 0, arguments); + }, + includes(...args) { + return searchProxy(this, "includes", args); + }, + indexOf(...args) { + return searchProxy(this, "indexOf", args); + }, + join(separator) { + return reactiveReadArray(this).join(separator); + }, + // keys() iterator only reads `length`, no optimization required + lastIndexOf(...args) { + return searchProxy(this, "lastIndexOf", args); + }, + map(fn, thisArg) { + return apply(this, "map", fn, thisArg, void 0, arguments); + }, + pop() { + return noTracking(this, "pop"); + }, + push(...args) { + return noTracking(this, "push", args); + }, + reduce(fn, ...args) { + return reduce(this, "reduce", fn, args); + }, + reduceRight(fn, ...args) { + return reduce(this, "reduceRight", fn, args); + }, + shift() { + return noTracking(this, "shift"); + }, + // slice could use ARRAY_ITERATE but also seems to beg for range tracking + some(fn, thisArg) { + return apply(this, "some", fn, thisArg, void 0, arguments); + }, + splice(...args) { + return noTracking(this, "splice", args); + }, + toReversed() { + return reactiveReadArray(this).toReversed(); + }, + toSorted(comparer) { + return reactiveReadArray(this).toSorted(comparer); + }, + toSpliced(...args) { + return reactiveReadArray(this).toSpliced(...args); + }, + unshift(...args) { + return noTracking(this, "unshift", args); + }, + values() { + return iterator(this, "values", (item) => toWrapped(this, item)); + } +}; +function iterator(self2, method, wrapValue) { + const arr = shallowReadArray(self2); + const iter = arr[method](); + if (arr !== self2 && !isShallow(self2)) { + iter._next = iter.next; + iter.next = () => { + const result = iter._next(); + if (!result.done) { + result.value = wrapValue(result.value); + } + return result; + }; + } + return iter; +} +const arrayProto = Array.prototype; +function apply(self2, method, fn, thisArg, wrappedRetFn, args) { + const arr = shallowReadArray(self2); + const needsWrap = arr !== self2 && !isShallow(self2); + const methodFn = arr[method]; + if (methodFn !== arrayProto[method]) { + const result2 = methodFn.apply(self2, args); + return needsWrap ? toReactive(result2) : result2; + } + let wrappedFn = fn; + if (arr !== self2) { + if (needsWrap) { + wrappedFn = function(item, index) { + return fn.call(this, toWrapped(self2, item), index, self2); + }; + } else if (fn.length > 2) { + wrappedFn = function(item, index) { + return fn.call(this, item, index, self2); + }; + } + } + const result = methodFn.call(arr, wrappedFn, thisArg); + return needsWrap && wrappedRetFn ? wrappedRetFn(result) : result; +} +function reduce(self2, method, fn, args) { + const arr = shallowReadArray(self2); + let wrappedFn = fn; + if (arr !== self2) { + if (!isShallow(self2)) { + wrappedFn = function(acc, item, index) { + return fn.call(this, acc, toWrapped(self2, item), index, self2); + }; + } else if (fn.length > 3) { + wrappedFn = function(acc, item, index) { + return fn.call(this, acc, item, index, self2); + }; + } + } + return arr[method](wrappedFn, ...args); +} +function searchProxy(self2, method, args) { + const arr = toRaw(self2); + track(arr, "iterate", ARRAY_ITERATE_KEY); + const res = arr[method](...args); + if ((res === -1 || res === false) && isProxy(args[0])) { + args[0] = toRaw(args[0]); + return arr[method](...args); + } + return res; +} +function noTracking(self2, method, args = []) { + pauseTracking(); + startBatch(); + const res = toRaw(self2)[method].apply(self2, args); + endBatch(); + resetTracking(); + return res; +} +const isNonTrackableKeys = /* @__PURE__ */ makeMap(`__proto__,__v_isRef,__isVue`); +const builtInSymbols = new Set( + /* @__PURE__ */ Object.getOwnPropertyNames(Symbol).filter((key) => key !== "arguments" && key !== "caller").map((key) => Symbol[key]).filter(isSymbol) +); +function hasOwnProperty(key) { + if (!isSymbol(key)) key = String(key); + const obj = toRaw(this); + track(obj, "has", key); + return obj.hasOwnProperty(key); +} +class BaseReactiveHandler { + constructor(_isReadonly = false, _isShallow = false) { + this._isReadonly = _isReadonly; + this._isShallow = _isShallow; + } + get(target, key, receiver) { + if (key === "__v_skip") return target["__v_skip"]; + const isReadonly2 = this._isReadonly, isShallow2 = this._isShallow; + if (key === "__v_isReactive") { + return !isReadonly2; + } else if (key === "__v_isReadonly") { + return isReadonly2; + } else if (key === "__v_isShallow") { + return isShallow2; + } else if (key === "__v_raw") { + if (receiver === (isReadonly2 ? isShallow2 ? shallowReadonlyMap : readonlyMap : isShallow2 ? shallowReactiveMap : reactiveMap).get(target) || // receiver is not the reactive proxy, but has the same prototype + // this means the receiver is a user proxy of the reactive proxy + Object.getPrototypeOf(target) === Object.getPrototypeOf(receiver)) { + return target; + } + return; + } + const targetIsArray = isArray(target); + if (!isReadonly2) { + let fn; + if (targetIsArray && (fn = arrayInstrumentations[key])) { + return fn; + } + if (key === "hasOwnProperty") { + return hasOwnProperty; + } + } + const res = Reflect.get( + target, + key, + // if this is a proxy wrapping a ref, return methods using the raw ref + // as receiver so that we don't have to call `toRaw` on the ref in all + // its class methods + isRef(target) ? target : receiver + ); + if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) { + return res; + } + if (!isReadonly2) { + track(target, "get", key); + } + if (isShallow2) { + return res; + } + if (isRef(res)) { + const value = targetIsArray && isIntegerKey(key) ? res : res.value; + return isReadonly2 && isObject(value) ? readonly(value) : value; + } + if (isObject(res)) { + return isReadonly2 ? readonly(res) : reactive(res); + } + return res; + } +} +class MutableReactiveHandler extends BaseReactiveHandler { + constructor(isShallow2 = false) { + super(false, isShallow2); + } + set(target, key, value, receiver) { + let oldValue = target[key]; + const isArrayWithIntegerKey = isArray(target) && isIntegerKey(key); + if (!this._isShallow) { + const isOldValueReadonly = isReadonly(oldValue); + if (!isShallow(value) && !isReadonly(value)) { + oldValue = toRaw(oldValue); + value = toRaw(value); + } + if (!isArrayWithIntegerKey && isRef(oldValue) && !isRef(value)) { + if (isOldValueReadonly) { + return true; + } else { + oldValue.value = value; + return true; + } + } + } + const hadKey = isArrayWithIntegerKey ? Number(key) < target.length : hasOwn(target, key); + const result = Reflect.set( + target, + key, + value, + isRef(target) ? target : receiver + ); + if (target === toRaw(receiver)) { + if (!hadKey) { + trigger(target, "add", key, value); + } else if (hasChanged(value, oldValue)) { + trigger(target, "set", key, value); + } + } + return result; + } + deleteProperty(target, key) { + const hadKey = hasOwn(target, key); + target[key]; + const result = Reflect.deleteProperty(target, key); + if (result && hadKey) { + trigger(target, "delete", key, void 0); + } + return result; + } + has(target, key) { + const result = Reflect.has(target, key); + if (!isSymbol(key) || !builtInSymbols.has(key)) { + track(target, "has", key); + } + return result; + } + ownKeys(target) { + track( + target, + "iterate", + isArray(target) ? "length" : ITERATE_KEY + ); + return Reflect.ownKeys(target); + } +} +class ReadonlyReactiveHandler extends BaseReactiveHandler { + constructor(isShallow2 = false) { + super(true, isShallow2); + } + set(target, key) { + return true; + } + deleteProperty(target, key) { + return true; + } +} +const mutableHandlers = /* @__PURE__ */ new MutableReactiveHandler(); +const readonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler(); +const shallowReactiveHandlers = /* @__PURE__ */ new MutableReactiveHandler(true); +const shallowReadonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler(true); +const toShallow = (value) => value; +const getProto = (v2) => Reflect.getPrototypeOf(v2); +function createIterableMethod(method, isReadonly2, isShallow2) { + return function(...args) { + const target = this["__v_raw"]; + const rawTarget = toRaw(target); + const targetIsMap = isMap(rawTarget); + const isPair = method === "entries" || method === Symbol.iterator && targetIsMap; + const isKeyOnly = method === "keys" && targetIsMap; + const innerIterator = target[method](...args); + const wrap = isShallow2 ? toShallow : isReadonly2 ? toReadonly : toReactive; + !isReadonly2 && track( + rawTarget, + "iterate", + isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY + ); + return { + // iterator protocol + next() { + const { value, done } = innerIterator.next(); + return done ? { value, done } : { + value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value), + done + }; + }, + // iterable protocol + [Symbol.iterator]() { + return this; + } + }; + }; +} +function createReadonlyMethod(type) { + return function(...args) { + return type === "delete" ? false : type === "clear" ? void 0 : this; + }; +} +function createInstrumentations(readonly2, shallow) { + const instrumentations = { + get(key) { + const target = this["__v_raw"]; + const rawTarget = toRaw(target); + const rawKey = toRaw(key); + if (!readonly2) { + if (hasChanged(key, rawKey)) { + track(rawTarget, "get", key); + } + track(rawTarget, "get", rawKey); + } + const { has } = getProto(rawTarget); + const wrap = shallow ? toShallow : readonly2 ? toReadonly : toReactive; + if (has.call(rawTarget, key)) { + return wrap(target.get(key)); + } else if (has.call(rawTarget, rawKey)) { + return wrap(target.get(rawKey)); + } else if (target !== rawTarget) { + target.get(key); + } + }, + get size() { + const target = this["__v_raw"]; + !readonly2 && track(toRaw(target), "iterate", ITERATE_KEY); + return target.size; + }, + has(key) { + const target = this["__v_raw"]; + const rawTarget = toRaw(target); + const rawKey = toRaw(key); + if (!readonly2) { + if (hasChanged(key, rawKey)) { + track(rawTarget, "has", key); + } + track(rawTarget, "has", rawKey); + } + return key === rawKey ? target.has(key) : target.has(key) || target.has(rawKey); + }, + forEach(callback, thisArg) { + const observed = this; + const target = observed["__v_raw"]; + const rawTarget = toRaw(target); + const wrap = shallow ? toShallow : readonly2 ? toReadonly : toReactive; + !readonly2 && track(rawTarget, "iterate", ITERATE_KEY); + return target.forEach((value, key) => { + return callback.call(thisArg, wrap(value), wrap(key), observed); + }); + } + }; + extend( + instrumentations, + readonly2 ? { + add: createReadonlyMethod("add"), + set: createReadonlyMethod("set"), + delete: createReadonlyMethod("delete"), + clear: createReadonlyMethod("clear") + } : { + add(value) { + if (!shallow && !isShallow(value) && !isReadonly(value)) { + value = toRaw(value); + } + const target = toRaw(this); + const proto = getProto(target); + const hadKey = proto.has.call(target, value); + if (!hadKey) { + target.add(value); + trigger(target, "add", value, value); + } + return this; + }, + set(key, value) { + if (!shallow && !isShallow(value) && !isReadonly(value)) { + value = toRaw(value); + } + const target = toRaw(this); + const { has, get } = getProto(target); + let hadKey = has.call(target, key); + if (!hadKey) { + key = toRaw(key); + hadKey = has.call(target, key); + } + const oldValue = get.call(target, key); + target.set(key, value); + if (!hadKey) { + trigger(target, "add", key, value); + } else if (hasChanged(value, oldValue)) { + trigger(target, "set", key, value); + } + return this; + }, + delete(key) { + const target = toRaw(this); + const { has, get } = getProto(target); + let hadKey = has.call(target, key); + if (!hadKey) { + key = toRaw(key); + hadKey = has.call(target, key); + } + get ? get.call(target, key) : void 0; + const result = target.delete(key); + if (hadKey) { + trigger(target, "delete", key, void 0); + } + return result; + }, + clear() { + const target = toRaw(this); + const hadItems = target.size !== 0; + const result = target.clear(); + if (hadItems) { + trigger( + target, + "clear", + void 0, + void 0 + ); + } + return result; + } + } + ); + const iteratorMethods = [ + "keys", + "values", + "entries", + Symbol.iterator + ]; + iteratorMethods.forEach((method) => { + instrumentations[method] = createIterableMethod(method, readonly2, shallow); + }); + return instrumentations; +} +function createInstrumentationGetter(isReadonly2, shallow) { + const instrumentations = createInstrumentations(isReadonly2, shallow); + return (target, key, receiver) => { + if (key === "__v_isReactive") { + return !isReadonly2; + } else if (key === "__v_isReadonly") { + return isReadonly2; + } else if (key === "__v_raw") { + return target; + } + return Reflect.get( + hasOwn(instrumentations, key) && key in target ? instrumentations : target, + key, + receiver + ); + }; +} +const mutableCollectionHandlers = { + get: /* @__PURE__ */ createInstrumentationGetter(false, false) +}; +const shallowCollectionHandlers = { + get: /* @__PURE__ */ createInstrumentationGetter(false, true) +}; +const readonlyCollectionHandlers = { + get: /* @__PURE__ */ createInstrumentationGetter(true, false) +}; +const shallowReadonlyCollectionHandlers = { + get: /* @__PURE__ */ createInstrumentationGetter(true, true) +}; +const reactiveMap = /* @__PURE__ */ new WeakMap(); +const shallowReactiveMap = /* @__PURE__ */ new WeakMap(); +const readonlyMap = /* @__PURE__ */ new WeakMap(); +const shallowReadonlyMap = /* @__PURE__ */ new WeakMap(); +function targetTypeMap(rawType) { + switch (rawType) { + case "Object": + case "Array": + return 1; + case "Map": + case "Set": + case "WeakMap": + case "WeakSet": + return 2; + default: + return 0; + } +} +function getTargetType(value) { + return value["__v_skip"] || !Object.isExtensible(value) ? 0 : targetTypeMap(toRawType(value)); +} +function reactive(target) { + if (isReadonly(target)) { + return target; + } + return createReactiveObject( + target, + false, + mutableHandlers, + mutableCollectionHandlers, + reactiveMap + ); +} +function shallowReactive(target) { + return createReactiveObject( + target, + false, + shallowReactiveHandlers, + shallowCollectionHandlers, + shallowReactiveMap + ); +} +function readonly(target) { + return createReactiveObject( + target, + true, + readonlyHandlers, + readonlyCollectionHandlers, + readonlyMap + ); +} +function shallowReadonly(target) { + return createReactiveObject( + target, + true, + shallowReadonlyHandlers, + shallowReadonlyCollectionHandlers, + shallowReadonlyMap + ); +} +function createReactiveObject(target, isReadonly2, baseHandlers, collectionHandlers, proxyMap) { + if (!isObject(target)) { + return target; + } + if (target["__v_raw"] && !(isReadonly2 && target["__v_isReactive"])) { + return target; + } + const targetType = getTargetType(target); + if (targetType === 0) { + return target; + } + const existingProxy = proxyMap.get(target); + if (existingProxy) { + return existingProxy; + } + const proxy = new Proxy( + target, + targetType === 2 ? collectionHandlers : baseHandlers + ); + proxyMap.set(target, proxy); + return proxy; +} +function isReactive(value) { + if (isReadonly(value)) { + return isReactive(value["__v_raw"]); + } + return !!(value && value["__v_isReactive"]); +} +function isReadonly(value) { + return !!(value && value["__v_isReadonly"]); +} +function isShallow(value) { + return !!(value && value["__v_isShallow"]); +} +function isProxy(value) { + return value ? !!value["__v_raw"] : false; +} +function toRaw(observed) { + const raw = observed && observed["__v_raw"]; + return raw ? toRaw(raw) : observed; +} +function markRaw(value) { + if (!hasOwn(value, "__v_skip") && Object.isExtensible(value)) { + def(value, "__v_skip", true); + } + return value; +} +const toReactive = (value) => isObject(value) ? reactive(value) : value; +const toReadonly = (value) => isObject(value) ? readonly(value) : value; +function isRef(r) { + return r ? r["__v_isRef"] === true : false; +} +function ref(value) { + return createRef(value, false); +} +function createRef(rawValue, shallow) { + if (isRef(rawValue)) { + return rawValue; + } + return new RefImpl(rawValue, shallow); +} +class RefImpl { + constructor(value, isShallow2) { + this.dep = new Dep(); + this["__v_isRef"] = true; + this["__v_isShallow"] = false; + this._rawValue = isShallow2 ? value : toRaw(value); + this._value = isShallow2 ? value : toReactive(value); + this["__v_isShallow"] = isShallow2; + } + get value() { + { + this.dep.track(); + } + return this._value; + } + set value(newValue) { + const oldValue = this._rawValue; + const useDirectValue = this["__v_isShallow"] || isShallow(newValue) || isReadonly(newValue); + newValue = useDirectValue ? newValue : toRaw(newValue); + if (hasChanged(newValue, oldValue)) { + this._rawValue = newValue; + this._value = useDirectValue ? newValue : toReactive(newValue); + { + this.dep.trigger(); + } + } + } +} +function unref(ref2) { + return isRef(ref2) ? ref2.value : ref2; +} +const shallowUnwrapHandlers = { + get: (target, key, receiver) => key === "__v_raw" ? target : unref(Reflect.get(target, key, receiver)), + set: (target, key, value, receiver) => { + const oldValue = target[key]; + if (isRef(oldValue) && !isRef(value)) { + oldValue.value = value; + return true; + } else { + return Reflect.set(target, key, value, receiver); + } + } +}; +function proxyRefs(objectWithRefs) { + return isReactive(objectWithRefs) ? objectWithRefs : new Proxy(objectWithRefs, shallowUnwrapHandlers); +} +class ComputedRefImpl { + constructor(fn, setter, isSSR) { + this.fn = fn; + this.setter = setter; + this._value = void 0; + this.dep = new Dep(this); + this.__v_isRef = true; + this.deps = void 0; + this.depsTail = void 0; + this.flags = 16; + this.globalVersion = globalVersion - 1; + this.next = void 0; + this.effect = this; + this["__v_isReadonly"] = !setter; + this.isSSR = isSSR; + } + /** + * @internal + */ + notify() { + this.flags |= 16; + if (!(this.flags & 8) && // avoid infinite self recursion + activeSub !== this) { + batch(this, true); + return true; + } + } + get value() { + const link = this.dep.track(); + refreshComputed(this); + if (link) { + link.version = this.dep.version; + } + return this._value; + } + set value(newValue) { + if (this.setter) { + this.setter(newValue); + } + } +} +function computed$1(getterOrOptions, debugOptions, isSSR = false) { + let getter; + let setter; + if (isFunction(getterOrOptions)) { + getter = getterOrOptions; + } else { + getter = getterOrOptions.get; + setter = getterOrOptions.set; + } + const cRef = new ComputedRefImpl(getter, setter, isSSR); + return cRef; +} +const INITIAL_WATCHER_VALUE = {}; +const cleanupMap = /* @__PURE__ */ new WeakMap(); +let activeWatcher = void 0; +function onWatcherCleanup(cleanupFn, failSilently = false, owner = activeWatcher) { + if (owner) { + let cleanups = cleanupMap.get(owner); + if (!cleanups) cleanupMap.set(owner, cleanups = []); + cleanups.push(cleanupFn); + } +} +function watch$1(source, cb, options = EMPTY_OBJ) { + const { immediate, deep, once, scheduler, augmentJob, call } = options; + const reactiveGetter = (source2) => { + if (deep) return source2; + if (isShallow(source2) || deep === false || deep === 0) + return traverse(source2, 1); + return traverse(source2); + }; + let effect2; + let getter; + let cleanup; + let boundCleanup; + let forceTrigger = false; + let isMultiSource = false; + if (isRef(source)) { + getter = () => source.value; + forceTrigger = isShallow(source); + } else if (isReactive(source)) { + getter = () => reactiveGetter(source); + forceTrigger = true; + } else if (isArray(source)) { + isMultiSource = true; + forceTrigger = source.some((s2) => isReactive(s2) || isShallow(s2)); + getter = () => source.map((s2) => { + if (isRef(s2)) { + return s2.value; + } else if (isReactive(s2)) { + return reactiveGetter(s2); + } else if (isFunction(s2)) { + return call ? call(s2, 2) : s2(); + } else ; + }); + } else if (isFunction(source)) { + if (cb) { + getter = call ? () => call(source, 2) : source; + } else { + getter = () => { + if (cleanup) { + pauseTracking(); + try { + cleanup(); + } finally { + resetTracking(); + } + } + const currentEffect = activeWatcher; + activeWatcher = effect2; + try { + return call ? call(source, 3, [boundCleanup]) : source(boundCleanup); + } finally { + activeWatcher = currentEffect; + } + }; + } + } else { + getter = NOOP; + } + if (cb && deep) { + const baseGetter = getter; + const depth = deep === true ? Infinity : deep; + getter = () => traverse(baseGetter(), depth); + } + const scope = getCurrentScope(); + const watchHandle = () => { + effect2.stop(); + if (scope && scope.active) { + remove(scope.effects, effect2); + } + }; + if (once && cb) { + const _cb = cb; + cb = (...args) => { + _cb(...args); + watchHandle(); + }; + } + let oldValue = isMultiSource ? new Array(source.length).fill(INITIAL_WATCHER_VALUE) : INITIAL_WATCHER_VALUE; + const job = (immediateFirstRun) => { + if (!(effect2.flags & 1) || !effect2.dirty && !immediateFirstRun) { + return; + } + if (cb) { + const newValue = effect2.run(); + if (deep || forceTrigger || (isMultiSource ? newValue.some((v2, i2) => hasChanged(v2, oldValue[i2])) : hasChanged(newValue, oldValue))) { + if (cleanup) { + cleanup(); + } + const currentWatcher = activeWatcher; + activeWatcher = effect2; + try { + const args = [ + newValue, + // pass undefined as the old value when it's changed for the first time + oldValue === INITIAL_WATCHER_VALUE ? void 0 : isMultiSource && oldValue[0] === INITIAL_WATCHER_VALUE ? [] : oldValue, + boundCleanup + ]; + oldValue = newValue; + call ? call(cb, 3, args) : ( + // @ts-expect-error + cb(...args) + ); + } finally { + activeWatcher = currentWatcher; + } + } + } else { + effect2.run(); + } + }; + if (augmentJob) { + augmentJob(job); + } + effect2 = new ReactiveEffect(getter); + effect2.scheduler = scheduler ? () => scheduler(job, false) : job; + boundCleanup = (fn) => onWatcherCleanup(fn, false, effect2); + cleanup = effect2.onStop = () => { + const cleanups = cleanupMap.get(effect2); + if (cleanups) { + if (call) { + call(cleanups, 4); + } else { + for (const cleanup2 of cleanups) cleanup2(); + } + cleanupMap.delete(effect2); + } + }; + if (cb) { + if (immediate) { + job(true); + } else { + oldValue = effect2.run(); + } + } else if (scheduler) { + scheduler(job.bind(null, true), true); + } else { + effect2.run(); + } + watchHandle.pause = effect2.pause.bind(effect2); + watchHandle.resume = effect2.resume.bind(effect2); + watchHandle.stop = watchHandle; + return watchHandle; +} +function traverse(value, depth = Infinity, seen) { + if (depth <= 0 || !isObject(value) || value["__v_skip"]) { + return value; + } + seen = seen || /* @__PURE__ */ new Map(); + if ((seen.get(value) || 0) >= depth) { + return value; + } + seen.set(value, depth); + depth--; + if (isRef(value)) { + traverse(value.value, depth, seen); + } else if (isArray(value)) { + for (let i2 = 0; i2 < value.length; i2++) { + traverse(value[i2], depth, seen); + } + } else if (isSet(value) || isMap(value)) { + value.forEach((v2) => { + traverse(v2, depth, seen); + }); + } else if (isPlainObject(value)) { + for (const key in value) { + traverse(value[key], depth, seen); + } + for (const key of Object.getOwnPropertySymbols(value)) { + if (Object.prototype.propertyIsEnumerable.call(value, key)) { + traverse(value[key], depth, seen); + } + } + } + return value; +} +/** +* @vue/runtime-core v3.5.26 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/ +const stack = []; +let isWarning = false; +function warn$1(msg, ...args) { + if (isWarning) return; + isWarning = true; + pauseTracking(); + const instance = stack.length ? stack[stack.length - 1].component : null; + const appWarnHandler = instance && instance.appContext.config.warnHandler; + const trace = getComponentTrace(); + if (appWarnHandler) { + callWithErrorHandling( + appWarnHandler, + instance, + 11, + [ + // eslint-disable-next-line no-restricted-syntax + msg + args.map((a2) => { + var _a, _b; + return (_b = (_a = a2.toString) == null ? void 0 : _a.call(a2)) != null ? _b : JSON.stringify(a2); + }).join(""), + instance && instance.proxy, + trace.map( + ({ vnode }) => `at <${formatComponentName(instance, vnode.type)}>` + ).join("\n"), + trace + ] + ); + } else { + const warnArgs = [`[Vue warn]: ${msg}`, ...args]; + if (trace.length && // avoid spamming console during tests + true) { + warnArgs.push(` +`, ...formatTrace(trace)); + } + console.warn(...warnArgs); + } + resetTracking(); + isWarning = false; +} +function getComponentTrace() { + let currentVNode = stack[stack.length - 1]; + if (!currentVNode) { + return []; + } + const normalizedStack = []; + while (currentVNode) { + const last = normalizedStack[0]; + if (last && last.vnode === currentVNode) { + last.recurseCount++; + } else { + normalizedStack.push({ + vnode: currentVNode, + recurseCount: 0 + }); + } + const parentInstance = currentVNode.component && currentVNode.component.parent; + currentVNode = parentInstance && parentInstance.vnode; + } + return normalizedStack; +} +function formatTrace(trace) { + const logs = []; + trace.forEach((entry, i2) => { + logs.push(...i2 === 0 ? [] : [` +`], ...formatTraceEntry(entry)); + }); + return logs; +} +function formatTraceEntry({ vnode, recurseCount }) { + const postfix = recurseCount > 0 ? `... (${recurseCount} recursive calls)` : ``; + const isRoot = vnode.component ? vnode.component.parent == null : false; + const open = ` at <${formatComponentName( + vnode.component, + vnode.type, + isRoot + )}`; + const close = `>` + postfix; + return vnode.props ? [open, ...formatProps(vnode.props), close] : [open + close]; +} +function formatProps(props) { + const res = []; + const keys = Object.keys(props); + keys.slice(0, 3).forEach((key) => { + res.push(...formatProp(key, props[key])); + }); + if (keys.length > 3) { + res.push(` ...`); + } + return res; +} +function formatProp(key, value, raw) { + if (isString(value)) { + value = JSON.stringify(value); + return raw ? value : [`${key}=${value}`]; + } else if (typeof value === "number" || typeof value === "boolean" || value == null) { + return raw ? value : [`${key}=${value}`]; + } else if (isRef(value)) { + value = formatProp(key, toRaw(value.value), true); + return raw ? value : [`${key}=Ref<`, value, `>`]; + } else if (isFunction(value)) { + return [`${key}=fn${value.name ? `<${value.name}>` : ``}`]; + } else { + value = toRaw(value); + return raw ? value : [`${key}=`, value]; + } +} +function callWithErrorHandling(fn, instance, type, args) { + try { + return args ? fn(...args) : fn(); + } catch (err) { + handleError(err, instance, type); + } +} +function callWithAsyncErrorHandling(fn, instance, type, args) { + if (isFunction(fn)) { + const res = callWithErrorHandling(fn, instance, type, args); + if (res && isPromise(res)) { + res.catch((err) => { + handleError(err, instance, type); + }); + } + return res; + } + if (isArray(fn)) { + const values = []; + for (let i2 = 0; i2 < fn.length; i2++) { + values.push(callWithAsyncErrorHandling(fn[i2], instance, type, args)); + } + return values; + } +} +function handleError(err, instance, type, throwInDev = true) { + const contextVNode = instance ? instance.vnode : null; + const { errorHandler, throwUnhandledErrorInProduction } = instance && instance.appContext.config || EMPTY_OBJ; + if (instance) { + let cur = instance.parent; + const exposedInstance = instance.proxy; + const errorInfo = `https://vuejs.org/error-reference/#runtime-${type}`; + while (cur) { + const errorCapturedHooks = cur.ec; + if (errorCapturedHooks) { + for (let i2 = 0; i2 < errorCapturedHooks.length; i2++) { + if (errorCapturedHooks[i2](err, exposedInstance, errorInfo) === false) { + return; + } + } + } + cur = cur.parent; + } + if (errorHandler) { + pauseTracking(); + callWithErrorHandling(errorHandler, null, 10, [ + err, + exposedInstance, + errorInfo + ]); + resetTracking(); + return; + } + } + logError(err, type, contextVNode, throwInDev, throwUnhandledErrorInProduction); +} +function logError(err, type, contextVNode, throwInDev = true, throwInProd = false) { + if (throwInProd) { + throw err; + } else { + console.error(err); + } +} +const queue = []; +let flushIndex = -1; +const pendingPostFlushCbs = []; +let activePostFlushCbs = null; +let postFlushIndex = 0; +const resolvedPromise = /* @__PURE__ */ Promise.resolve(); +let currentFlushPromise = null; +function nextTick(fn) { + const p2 = currentFlushPromise || resolvedPromise; + return fn ? p2.then(this ? fn.bind(this) : fn) : p2; +} +function findInsertionIndex(id) { + let start = flushIndex + 1; + let end = queue.length; + while (start < end) { + const middle = start + end >>> 1; + const middleJob = queue[middle]; + const middleJobId = getId(middleJob); + if (middleJobId < id || middleJobId === id && middleJob.flags & 2) { + start = middle + 1; + } else { + end = middle; + } + } + return start; +} +function queueJob(job) { + if (!(job.flags & 1)) { + const jobId = getId(job); + const lastJob = queue[queue.length - 1]; + if (!lastJob || // fast path when the job id is larger than the tail + !(job.flags & 2) && jobId >= getId(lastJob)) { + queue.push(job); + } else { + queue.splice(findInsertionIndex(jobId), 0, job); + } + job.flags |= 1; + queueFlush(); + } +} +function queueFlush() { + if (!currentFlushPromise) { + currentFlushPromise = resolvedPromise.then(flushJobs); + } +} +function queuePostFlushCb(cb) { + if (!isArray(cb)) { + if (activePostFlushCbs && cb.id === -1) { + activePostFlushCbs.splice(postFlushIndex + 1, 0, cb); + } else if (!(cb.flags & 1)) { + pendingPostFlushCbs.push(cb); + cb.flags |= 1; + } + } else { + pendingPostFlushCbs.push(...cb); + } + queueFlush(); +} +function flushPreFlushCbs(instance, seen, i2 = flushIndex + 1) { + for (; i2 < queue.length; i2++) { + const cb = queue[i2]; + if (cb && cb.flags & 2) { + if (instance && cb.id !== instance.uid) { + continue; + } + queue.splice(i2, 1); + i2--; + if (cb.flags & 4) { + cb.flags &= -2; + } + cb(); + if (!(cb.flags & 4)) { + cb.flags &= -2; + } + } + } +} +function flushPostFlushCbs(seen) { + if (pendingPostFlushCbs.length) { + const deduped = [...new Set(pendingPostFlushCbs)].sort( + (a2, b2) => getId(a2) - getId(b2) + ); + pendingPostFlushCbs.length = 0; + if (activePostFlushCbs) { + activePostFlushCbs.push(...deduped); + return; + } + activePostFlushCbs = deduped; + for (postFlushIndex = 0; postFlushIndex < activePostFlushCbs.length; postFlushIndex++) { + const cb = activePostFlushCbs[postFlushIndex]; + if (cb.flags & 4) { + cb.flags &= -2; + } + if (!(cb.flags & 8)) cb(); + cb.flags &= -2; + } + activePostFlushCbs = null; + postFlushIndex = 0; + } +} +const getId = (job) => job.id == null ? job.flags & 2 ? -1 : Infinity : job.id; +function flushJobs(seen) { + try { + for (flushIndex = 0; flushIndex < queue.length; flushIndex++) { + const job = queue[flushIndex]; + if (job && !(job.flags & 8)) { + if (false) ; + if (job.flags & 4) { + job.flags &= ~1; + } + callWithErrorHandling( + job, + job.i, + job.i ? 15 : 14 + ); + if (!(job.flags & 4)) { + job.flags &= ~1; + } + } + } + } finally { + for (; flushIndex < queue.length; flushIndex++) { + const job = queue[flushIndex]; + if (job) { + job.flags &= -2; + } + } + flushIndex = -1; + queue.length = 0; + flushPostFlushCbs(); + currentFlushPromise = null; + if (queue.length || pendingPostFlushCbs.length) { + flushJobs(); + } + } +} +let currentRenderingInstance = null; +let currentScopeId = null; +function setCurrentRenderingInstance(instance) { + const prev = currentRenderingInstance; + currentRenderingInstance = instance; + currentScopeId = instance && instance.type.__scopeId || null; + return prev; +} +function withCtx(fn, ctx = currentRenderingInstance, isNonScopedSlot) { + if (!ctx) return fn; + if (fn._n) { + return fn; + } + const renderFnWithContext = (...args) => { + if (renderFnWithContext._d) { + setBlockTracking(-1); + } + const prevInstance = setCurrentRenderingInstance(ctx); + let res; + try { + res = fn(...args); + } finally { + setCurrentRenderingInstance(prevInstance); + if (renderFnWithContext._d) { + setBlockTracking(1); + } + } + return res; + }; + renderFnWithContext._n = true; + renderFnWithContext._c = true; + renderFnWithContext._d = true; + return renderFnWithContext; +} +function withDirectives(vnode, directives) { + if (currentRenderingInstance === null) { + return vnode; + } + const instance = getComponentPublicInstance(currentRenderingInstance); + const bindings = vnode.dirs || (vnode.dirs = []); + for (let i2 = 0; i2 < directives.length; i2++) { + let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i2]; + if (dir) { + if (isFunction(dir)) { + dir = { + mounted: dir, + updated: dir + }; + } + if (dir.deep) { + traverse(value); + } + bindings.push({ + dir, + instance, + value, + oldValue: void 0, + arg, + modifiers + }); + } + } + return vnode; +} +function invokeDirectiveHook(vnode, prevVNode, instance, name) { + const bindings = vnode.dirs; + const oldBindings = prevVNode && prevVNode.dirs; + for (let i2 = 0; i2 < bindings.length; i2++) { + const binding = bindings[i2]; + if (oldBindings) { + binding.oldValue = oldBindings[i2].value; + } + let hook = binding.dir[name]; + if (hook) { + pauseTracking(); + callWithAsyncErrorHandling(hook, instance, 8, [ + vnode.el, + binding, + vnode, + prevVNode + ]); + resetTracking(); + } + } +} +function provide(key, value) { + if (currentInstance) { + let provides = currentInstance.provides; + const parentProvides = currentInstance.parent && currentInstance.parent.provides; + if (parentProvides === provides) { + provides = currentInstance.provides = Object.create(parentProvides); + } + provides[key] = value; + } +} +function inject(key, defaultValue2, treatDefaultAsFactory = false) { + const instance = getCurrentInstance(); + if (instance || currentApp) { + let provides = currentApp ? currentApp._context.provides : instance ? instance.parent == null || instance.ce ? instance.vnode.appContext && instance.vnode.appContext.provides : instance.parent.provides : void 0; + if (provides && key in provides) { + return provides[key]; + } else if (arguments.length > 1) { + return treatDefaultAsFactory && isFunction(defaultValue2) ? defaultValue2.call(instance && instance.proxy) : defaultValue2; + } else ; + } +} +const ssrContextKey = /* @__PURE__ */ Symbol.for("v-scx"); +const useSSRContext = () => { + { + const ctx = inject(ssrContextKey); + return ctx; + } +}; +function watch(source, cb, options) { + return doWatch(source, cb, options); +} +function doWatch(source, cb, options = EMPTY_OBJ) { + const { immediate, deep, flush, once } = options; + const baseWatchOptions = extend({}, options); + const runsImmediately = cb && immediate || !cb && flush !== "post"; + let ssrCleanup; + if (isInSSRComponentSetup) { + if (flush === "sync") { + const ctx = useSSRContext(); + ssrCleanup = ctx.__watcherHandles || (ctx.__watcherHandles = []); + } else if (!runsImmediately) { + const watchStopHandle = () => { + }; + watchStopHandle.stop = NOOP; + watchStopHandle.resume = NOOP; + watchStopHandle.pause = NOOP; + return watchStopHandle; + } + } + const instance = currentInstance; + baseWatchOptions.call = (fn, type, args) => callWithAsyncErrorHandling(fn, instance, type, args); + let isPre = false; + if (flush === "post") { + baseWatchOptions.scheduler = (job) => { + queuePostRenderEffect(job, instance && instance.suspense); + }; + } else if (flush !== "sync") { + isPre = true; + baseWatchOptions.scheduler = (job, isFirstRun) => { + if (isFirstRun) { + job(); + } else { + queueJob(job); + } + }; + } + baseWatchOptions.augmentJob = (job) => { + if (cb) { + job.flags |= 4; + } + if (isPre) { + job.flags |= 2; + if (instance) { + job.id = instance.uid; + job.i = instance; + } + } + }; + const watchHandle = watch$1(source, cb, baseWatchOptions); + if (isInSSRComponentSetup) { + if (ssrCleanup) { + ssrCleanup.push(watchHandle); + } else if (runsImmediately) { + watchHandle(); + } + } + return watchHandle; +} +function instanceWatch(source, value, options) { + const publicThis = this.proxy; + const getter = isString(source) ? source.includes(".") ? createPathGetter(publicThis, source) : () => publicThis[source] : source.bind(publicThis, publicThis); + let cb; + if (isFunction(value)) { + cb = value; + } else { + cb = value.handler; + options = value; + } + const reset = setCurrentInstance(this); + const res = doWatch(getter, cb.bind(publicThis), options); + reset(); + return res; +} +function createPathGetter(ctx, path) { + const segments = path.split("."); + return () => { + let cur = ctx; + for (let i2 = 0; i2 < segments.length && cur; i2++) { + cur = cur[segments[i2]]; + } + return cur; + }; +} +const TeleportEndKey = /* @__PURE__ */ Symbol("_vte"); +const isTeleport = (type) => type.__isTeleport; +const leaveCbKey = /* @__PURE__ */ Symbol("_leaveCb"); +function setTransitionHooks(vnode, hooks) { + if (vnode.shapeFlag & 6 && vnode.component) { + vnode.transition = hooks; + setTransitionHooks(vnode.component.subTree, hooks); + } else if (vnode.shapeFlag & 128) { + vnode.ssContent.transition = hooks.clone(vnode.ssContent); + vnode.ssFallback.transition = hooks.clone(vnode.ssFallback); + } else { + vnode.transition = hooks; + } +} +// @__NO_SIDE_EFFECTS__ +function defineComponent(options, extraOptions) { + return isFunction(options) ? ( + // #8236: extend call and options.name access are considered side-effects + // by Rollup, so we have to wrap it in a pure-annotated IIFE. + /* @__PURE__ */ (() => extend({ name: options.name }, extraOptions, { setup: options }))() + ) : options; +} +function useId() { + const i2 = getCurrentInstance(); + if (i2) { + return (i2.appContext.config.idPrefix || "v") + "-" + i2.ids[0] + i2.ids[1]++; + } + return ""; +} +function markAsyncBoundary(instance) { + instance.ids = [instance.ids[0] + instance.ids[2]++ + "-", 0, 0]; +} +const pendingSetRefMap = /* @__PURE__ */ new WeakMap(); +function setRef(rawRef, oldRawRef, parentSuspense, vnode, isUnmount = false) { + if (isArray(rawRef)) { + rawRef.forEach( + (r, i2) => setRef( + r, + oldRawRef && (isArray(oldRawRef) ? oldRawRef[i2] : oldRawRef), + parentSuspense, + vnode, + isUnmount + ) + ); + return; + } + if (isAsyncWrapper(vnode) && !isUnmount) { + if (vnode.shapeFlag & 512 && vnode.type.__asyncResolved && vnode.component.subTree.component) { + setRef(rawRef, oldRawRef, parentSuspense, vnode.component.subTree); + } + return; + } + const refValue = vnode.shapeFlag & 4 ? getComponentPublicInstance(vnode.component) : vnode.el; + const value = isUnmount ? null : refValue; + const { i: owner, r: ref3 } = rawRef; + const oldRef = oldRawRef && oldRawRef.r; + const refs = owner.refs === EMPTY_OBJ ? owner.refs = {} : owner.refs; + const setupState = owner.setupState; + const rawSetupState = toRaw(setupState); + const canSetSetupRef = setupState === EMPTY_OBJ ? NO : (key) => { + return hasOwn(rawSetupState, key); + }; + if (oldRef != null && oldRef !== ref3) { + invalidatePendingSetRef(oldRawRef); + if (isString(oldRef)) { + refs[oldRef] = null; + if (canSetSetupRef(oldRef)) { + setupState[oldRef] = null; + } + } else if (isRef(oldRef)) { + { + oldRef.value = null; + } + const oldRawRefAtom = oldRawRef; + if (oldRawRefAtom.k) refs[oldRawRefAtom.k] = null; + } + } + if (isFunction(ref3)) { + callWithErrorHandling(ref3, owner, 12, [value, refs]); + } else { + const _isString = isString(ref3); + const _isRef = isRef(ref3); + if (_isString || _isRef) { + const doSet = () => { + if (rawRef.f) { + const existing = _isString ? canSetSetupRef(ref3) ? setupState[ref3] : refs[ref3] : ref3.value; + if (isUnmount) { + isArray(existing) && remove(existing, refValue); + } else { + if (!isArray(existing)) { + if (_isString) { + refs[ref3] = [refValue]; + if (canSetSetupRef(ref3)) { + setupState[ref3] = refs[ref3]; + } + } else { + const newVal = [refValue]; + { + ref3.value = newVal; + } + if (rawRef.k) refs[rawRef.k] = newVal; + } + } else if (!existing.includes(refValue)) { + existing.push(refValue); + } + } + } else if (_isString) { + refs[ref3] = value; + if (canSetSetupRef(ref3)) { + setupState[ref3] = value; + } + } else if (_isRef) { + { + ref3.value = value; + } + if (rawRef.k) refs[rawRef.k] = value; + } else ; + }; + if (value) { + const job = () => { + doSet(); + pendingSetRefMap.delete(rawRef); + }; + job.id = -1; + pendingSetRefMap.set(rawRef, job); + queuePostRenderEffect(job, parentSuspense); + } else { + invalidatePendingSetRef(rawRef); + doSet(); + } + } + } +} +function invalidatePendingSetRef(rawRef) { + const pendingSetRef = pendingSetRefMap.get(rawRef); + if (pendingSetRef) { + pendingSetRef.flags |= 8; + pendingSetRefMap.delete(rawRef); + } +} +getGlobalThis().requestIdleCallback || ((cb) => setTimeout(cb, 1)); +getGlobalThis().cancelIdleCallback || ((id) => clearTimeout(id)); +const isAsyncWrapper = (i2) => !!i2.type.__asyncLoader; +const isKeepAlive = (vnode) => vnode.type.__isKeepAlive; +function onActivated(hook, target) { + registerKeepAliveHook(hook, "a", target); +} +function onDeactivated(hook, target) { + registerKeepAliveHook(hook, "da", target); +} +function registerKeepAliveHook(hook, type, target = currentInstance) { + const wrappedHook = hook.__wdc || (hook.__wdc = () => { + let current = target; + while (current) { + if (current.isDeactivated) { + return; + } + current = current.parent; + } + return hook(); + }); + injectHook(type, wrappedHook, target); + if (target) { + let current = target.parent; + while (current && current.parent) { + if (isKeepAlive(current.parent.vnode)) { + injectToKeepAliveRoot(wrappedHook, type, target, current); + } + current = current.parent; + } + } +} +function injectToKeepAliveRoot(hook, type, target, keepAliveRoot) { + const injected = injectHook( + type, + hook, + keepAliveRoot, + true + /* prepend */ + ); + onUnmounted(() => { + remove(keepAliveRoot[type], injected); + }, target); +} +function injectHook(type, hook, target = currentInstance, prepend = false) { + if (target) { + const hooks = target[type] || (target[type] = []); + const wrappedHook = hook.__weh || (hook.__weh = (...args) => { + pauseTracking(); + const reset = setCurrentInstance(target); + const res = callWithAsyncErrorHandling(hook, target, type, args); + reset(); + resetTracking(); + return res; + }); + if (prepend) { + hooks.unshift(wrappedHook); + } else { + hooks.push(wrappedHook); + } + return wrappedHook; + } +} +const createHook = (lifecycle) => (hook, target = currentInstance) => { + if (!isInSSRComponentSetup || lifecycle === "sp") { + injectHook(lifecycle, (...args) => hook(...args), target); + } +}; +const onBeforeMount = createHook("bm"); +const onMounted = createHook("m"); +const onBeforeUpdate = createHook( + "bu" +); +const onUpdated = createHook("u"); +const onBeforeUnmount = createHook( + "bum" +); +const onUnmounted = createHook("um"); +const onServerPrefetch = createHook( + "sp" +); +const onRenderTriggered = createHook("rtg"); +const onRenderTracked = createHook("rtc"); +function onErrorCaptured(hook, target = currentInstance) { + injectHook("ec", hook, target); +} +const COMPONENTS = "components"; +const DIRECTIVES = "directives"; +function resolveComponent(name, maybeSelfReference) { + return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name; +} +const NULL_DYNAMIC_COMPONENT = /* @__PURE__ */ Symbol.for("v-ndc"); +function resolveDynamicComponent(component) { + if (isString(component)) { + return resolveAsset(COMPONENTS, component, false) || component; + } else { + return component || NULL_DYNAMIC_COMPONENT; + } +} +function resolveDirective(name) { + return resolveAsset(DIRECTIVES, name); +} +function resolveAsset(type, name, warnMissing = true, maybeSelfReference = false) { + const instance = currentRenderingInstance || currentInstance; + if (instance) { + const Component = instance.type; + if (type === COMPONENTS) { + const selfName = getComponentName( + Component, + false + ); + if (selfName && (selfName === name || selfName === camelize(name) || selfName === capitalize(camelize(name)))) { + return Component; + } + } + const res = ( + // local registration + // check instance[type] first which is resolved for options API + resolve(instance[type] || Component[type], name) || // global registration + resolve(instance.appContext[type], name) + ); + if (!res && maybeSelfReference) { + return Component; + } + return res; + } +} +function resolve(registry, name) { + return registry && (registry[name] || registry[camelize(name)] || registry[capitalize(camelize(name))]); +} +function renderSlot(slots, name, props = {}, fallback, noSlotted) { + if (currentRenderingInstance.ce || currentRenderingInstance.parent && isAsyncWrapper(currentRenderingInstance.parent) && currentRenderingInstance.parent.ce) { + const hasProps = Object.keys(props).length > 0; + if (name !== "default") props.name = name; + return openBlock(), createBlock( + Fragment, + null, + [createVNode("slot", props, fallback && fallback())], + hasProps ? -2 : 64 + ); + } + let slot = slots[name]; + if (slot && slot._c) { + slot._d = false; + } + openBlock(); + const validSlotContent = slot && ensureValidVNode(slot(props)); + const slotKey = props.key || // slot content array of a dynamic conditional slot may have a branch + // key attached in the `createSlots` helper, respect that + validSlotContent && validSlotContent.key; + const rendered = createBlock( + Fragment, + { + key: (slotKey && !isSymbol(slotKey) ? slotKey : `_${name}`) + // #7256 force differentiate fallback content from actual content + (!validSlotContent && fallback ? "_fb" : "") + }, + validSlotContent || (fallback ? fallback() : []), + validSlotContent && slots._ === 1 ? 64 : -2 + ); + if (rendered.scopeId) { + rendered.slotScopeIds = [rendered.scopeId + "-s"]; + } + if (slot && slot._c) { + slot._d = true; + } + return rendered; +} +function ensureValidVNode(vnodes) { + return vnodes.some((child) => { + if (!isVNode(child)) return true; + if (child.type === Comment) return false; + if (child.type === Fragment && !ensureValidVNode(child.children)) + return false; + return true; + }) ? vnodes : null; +} +function toHandlers(obj, preserveCaseIfNecessary) { + const ret = {}; + for (const key in obj) { + ret[/[A-Z]/.test(key) ? `on:${key}` : toHandlerKey(key)] = obj[key]; + } + return ret; +} +const getPublicInstance = (i2) => { + if (!i2) return null; + if (isStatefulComponent(i2)) return getComponentPublicInstance(i2); + return getPublicInstance(i2.parent); +}; +const publicPropertiesMap = ( + // Move PURE marker to new line to workaround compiler discarding it + // due to type annotation + /* @__PURE__ */ extend(/* @__PURE__ */ Object.create(null), { + $: (i2) => i2, + $el: (i2) => i2.vnode.el, + $data: (i2) => i2.data, + $props: (i2) => i2.props, + $attrs: (i2) => i2.attrs, + $slots: (i2) => i2.slots, + $refs: (i2) => i2.refs, + $parent: (i2) => getPublicInstance(i2.parent), + $root: (i2) => getPublicInstance(i2.root), + $host: (i2) => i2.ce, + $emit: (i2) => i2.emit, + $options: (i2) => resolveMergedOptions(i2), + $forceUpdate: (i2) => i2.f || (i2.f = () => { + queueJob(i2.update); + }), + $nextTick: (i2) => i2.n || (i2.n = nextTick.bind(i2.proxy)), + $watch: (i2) => instanceWatch.bind(i2) + }) +); +const hasSetupBinding = (state, key) => state !== EMPTY_OBJ && !state.__isScriptSetup && hasOwn(state, key); +const PublicInstanceProxyHandlers = { + get({ _: instance }, key) { + if (key === "__v_skip") { + return true; + } + const { ctx, setupState, data: data3, props, accessCache, type, appContext } = instance; + if (key[0] !== "$") { + const n = accessCache[key]; + if (n !== void 0) { + switch (n) { + case 1: + return setupState[key]; + case 2: + return data3[key]; + case 4: + return ctx[key]; + case 3: + return props[key]; + } + } else if (hasSetupBinding(setupState, key)) { + accessCache[key] = 1; + return setupState[key]; + } else if (data3 !== EMPTY_OBJ && hasOwn(data3, key)) { + accessCache[key] = 2; + return data3[key]; + } else if (hasOwn(props, key)) { + accessCache[key] = 3; + return props[key]; + } else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) { + accessCache[key] = 4; + return ctx[key]; + } else if (shouldCacheAccess) { + accessCache[key] = 0; + } + } + const publicGetter = publicPropertiesMap[key]; + let cssModule, globalProperties; + if (publicGetter) { + if (key === "$attrs") { + track(instance.attrs, "get", ""); + } + return publicGetter(instance); + } else if ( + // css module (injected by vue-loader) + (cssModule = type.__cssModules) && (cssModule = cssModule[key]) + ) { + return cssModule; + } else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) { + accessCache[key] = 4; + return ctx[key]; + } else if ( + // global properties + globalProperties = appContext.config.globalProperties, hasOwn(globalProperties, key) + ) { + { + return globalProperties[key]; + } + } else ; + }, + set({ _: instance }, key, value) { + const { data: data3, setupState, ctx } = instance; + if (hasSetupBinding(setupState, key)) { + setupState[key] = value; + return true; + } else if (data3 !== EMPTY_OBJ && hasOwn(data3, key)) { + data3[key] = value; + return true; + } else if (hasOwn(instance.props, key)) { + return false; + } + if (key[0] === "$" && key.slice(1) in instance) { + return false; + } else { + { + ctx[key] = value; + } + } + return true; + }, + has({ + _: { data: data3, setupState, accessCache, ctx, appContext, props, type } + }, key) { + let cssModules; + return !!(accessCache[key] || data3 !== EMPTY_OBJ && key[0] !== "$" && hasOwn(data3, key) || hasSetupBinding(setupState, key) || hasOwn(props, key) || hasOwn(ctx, key) || hasOwn(publicPropertiesMap, key) || hasOwn(appContext.config.globalProperties, key) || (cssModules = type.__cssModules) && cssModules[key]); + }, + defineProperty(target, key, descriptor) { + if (descriptor.get != null) { + target._.accessCache[key] = 0; + } else if (hasOwn(descriptor, "value")) { + this.set(target, key, descriptor.value, null); + } + return Reflect.defineProperty(target, key, descriptor); + } +}; +function normalizePropsOrEmits(props) { + return isArray(props) ? props.reduce( + (normalized, p2) => (normalized[p2] = null, normalized), + {} + ) : props; +} +let shouldCacheAccess = true; +function applyOptions(instance) { + const options = resolveMergedOptions(instance); + const publicThis = instance.proxy; + const ctx = instance.ctx; + shouldCacheAccess = false; + if (options.beforeCreate) { + callHook(options.beforeCreate, instance, "bc"); + } + const { + // state + data: dataOptions, + computed: computedOptions, + methods, + watch: watchOptions, + provide: provideOptions, + inject: injectOptions, + // lifecycle + created: created3, + beforeMount: beforeMount2, + mounted: mounted3, + beforeUpdate: beforeUpdate2, + updated: updated2, + activated, + deactivated, + beforeDestroy, + beforeUnmount: beforeUnmount2, + destroyed, + unmounted: unmounted3, + render: render2, + renderTracked, + renderTriggered, + errorCaptured, + serverPrefetch, + // public API + expose, + inheritAttrs, + // assets + components, + directives, + filters + } = options; + const checkDuplicateProperties = null; + if (injectOptions) { + resolveInjections(injectOptions, ctx, checkDuplicateProperties); + } + if (methods) { + for (const key in methods) { + const methodHandler = methods[key]; + if (isFunction(methodHandler)) { + { + ctx[key] = methodHandler.bind(publicThis); + } + } + } + } + if (dataOptions) { + const data3 = dataOptions.call(publicThis, publicThis); + if (!isObject(data3)) ; + else { + instance.data = reactive(data3); + } + } + shouldCacheAccess = true; + if (computedOptions) { + for (const key in computedOptions) { + const opt = computedOptions[key]; + const get = isFunction(opt) ? opt.bind(publicThis, publicThis) : isFunction(opt.get) ? opt.get.bind(publicThis, publicThis) : NOOP; + const set = !isFunction(opt) && isFunction(opt.set) ? opt.set.bind(publicThis) : NOOP; + const c2 = computed({ + get, + set + }); + Object.defineProperty(ctx, key, { + enumerable: true, + configurable: true, + get: () => c2.value, + set: (v2) => c2.value = v2 + }); + } + } + if (watchOptions) { + for (const key in watchOptions) { + createWatcher(watchOptions[key], ctx, publicThis, key); + } + } + if (provideOptions) { + const provides = isFunction(provideOptions) ? provideOptions.call(publicThis) : provideOptions; + Reflect.ownKeys(provides).forEach((key) => { + provide(key, provides[key]); + }); + } + if (created3) { + callHook(created3, instance, "c"); + } + function registerLifecycleHook(register, hook) { + if (isArray(hook)) { + hook.forEach((_hook3) => register(_hook3.bind(publicThis))); + } else if (hook) { + register(hook.bind(publicThis)); + } + } + registerLifecycleHook(onBeforeMount, beforeMount2); + registerLifecycleHook(onMounted, mounted3); + registerLifecycleHook(onBeforeUpdate, beforeUpdate2); + registerLifecycleHook(onUpdated, updated2); + registerLifecycleHook(onActivated, activated); + registerLifecycleHook(onDeactivated, deactivated); + registerLifecycleHook(onErrorCaptured, errorCaptured); + registerLifecycleHook(onRenderTracked, renderTracked); + registerLifecycleHook(onRenderTriggered, renderTriggered); + registerLifecycleHook(onBeforeUnmount, beforeUnmount2); + registerLifecycleHook(onUnmounted, unmounted3); + registerLifecycleHook(onServerPrefetch, serverPrefetch); + if (isArray(expose)) { + if (expose.length) { + const exposed = instance.exposed || (instance.exposed = {}); + expose.forEach((key) => { + Object.defineProperty(exposed, key, { + get: () => publicThis[key], + set: (val) => publicThis[key] = val, + enumerable: true + }); + }); + } else if (!instance.exposed) { + instance.exposed = {}; + } + } + if (render2 && instance.render === NOOP) { + instance.render = render2; + } + if (inheritAttrs != null) { + instance.inheritAttrs = inheritAttrs; + } + if (components) instance.components = components; + if (directives) instance.directives = directives; + if (serverPrefetch) { + markAsyncBoundary(instance); + } +} +function resolveInjections(injectOptions, ctx, checkDuplicateProperties = NOOP) { + if (isArray(injectOptions)) { + injectOptions = normalizeInject(injectOptions); + } + for (const key in injectOptions) { + const opt = injectOptions[key]; + let injected; + if (isObject(opt)) { + if ("default" in opt) { + injected = inject( + opt.from || key, + opt.default, + true + ); + } else { + injected = inject(opt.from || key); + } + } else { + injected = inject(opt); + } + if (isRef(injected)) { + Object.defineProperty(ctx, key, { + enumerable: true, + configurable: true, + get: () => injected.value, + set: (v2) => injected.value = v2 + }); + } else { + ctx[key] = injected; + } + } +} +function callHook(hook, instance, type) { + callWithAsyncErrorHandling( + isArray(hook) ? hook.map((h2) => h2.bind(instance.proxy)) : hook.bind(instance.proxy), + instance, + type + ); +} +function createWatcher(raw, ctx, publicThis, key) { + let getter = key.includes(".") ? createPathGetter(publicThis, key) : () => publicThis[key]; + if (isString(raw)) { + const handler9 = ctx[raw]; + if (isFunction(handler9)) { + { + watch(getter, handler9); + } + } + } else if (isFunction(raw)) { + { + watch(getter, raw.bind(publicThis)); + } + } else if (isObject(raw)) { + if (isArray(raw)) { + raw.forEach((r) => createWatcher(r, ctx, publicThis, key)); + } else { + const handler9 = isFunction(raw.handler) ? raw.handler.bind(publicThis) : ctx[raw.handler]; + if (isFunction(handler9)) { + watch(getter, handler9, raw); + } + } + } else ; +} +function resolveMergedOptions(instance) { + const base = instance.type; + const { mixins, extends: extendsOptions } = base; + const { + mixins: globalMixins, + optionsCache: cache, + config: { optionMergeStrategies } + } = instance.appContext; + const cached = cache.get(base); + let resolved; + if (cached) { + resolved = cached; + } else if (!globalMixins.length && !mixins && !extendsOptions) { + { + resolved = base; + } + } else { + resolved = {}; + if (globalMixins.length) { + globalMixins.forEach( + (m2) => mergeOptions(resolved, m2, optionMergeStrategies, true) + ); + } + mergeOptions(resolved, base, optionMergeStrategies); + } + if (isObject(base)) { + cache.set(base, resolved); + } + return resolved; +} +function mergeOptions(to, from, strats, asMixin = false) { + const { mixins, extends: extendsOptions } = from; + if (extendsOptions) { + mergeOptions(to, extendsOptions, strats, true); + } + if (mixins) { + mixins.forEach( + (m2) => mergeOptions(to, m2, strats, true) + ); + } + for (const key in from) { + if (asMixin && key === "expose") ; + else { + const strat = internalOptionMergeStrats[key] || strats && strats[key]; + to[key] = strat ? strat(to[key], from[key]) : from[key]; + } + } + return to; +} +const internalOptionMergeStrats = { + data: mergeDataFn, + props: mergeEmitsOrPropsOptions, + emits: mergeEmitsOrPropsOptions, + // objects + methods: mergeObjectOptions, + computed: mergeObjectOptions, + // lifecycle + beforeCreate: mergeAsArray, + created: mergeAsArray, + beforeMount: mergeAsArray, + mounted: mergeAsArray, + beforeUpdate: mergeAsArray, + updated: mergeAsArray, + beforeDestroy: mergeAsArray, + beforeUnmount: mergeAsArray, + destroyed: mergeAsArray, + unmounted: mergeAsArray, + activated: mergeAsArray, + deactivated: mergeAsArray, + errorCaptured: mergeAsArray, + serverPrefetch: mergeAsArray, + // assets + components: mergeObjectOptions, + directives: mergeObjectOptions, + // watch + watch: mergeWatchOptions, + // provide / inject + provide: mergeDataFn, + inject: mergeInject +}; +function mergeDataFn(to, from) { + if (!from) { + return to; + } + if (!to) { + return from; + } + return function mergedDataFn() { + return extend( + isFunction(to) ? to.call(this, this) : to, + isFunction(from) ? from.call(this, this) : from + ); + }; +} +function mergeInject(to, from) { + return mergeObjectOptions(normalizeInject(to), normalizeInject(from)); +} +function normalizeInject(raw) { + if (isArray(raw)) { + const res = {}; + for (let i2 = 0; i2 < raw.length; i2++) { + res[raw[i2]] = raw[i2]; + } + return res; + } + return raw; +} +function mergeAsArray(to, from) { + return to ? [...new Set([].concat(to, from))] : from; +} +function mergeObjectOptions(to, from) { + return to ? extend(/* @__PURE__ */ Object.create(null), to, from) : from; +} +function mergeEmitsOrPropsOptions(to, from) { + if (to) { + if (isArray(to) && isArray(from)) { + return [.../* @__PURE__ */ new Set([...to, ...from])]; + } + return extend( + /* @__PURE__ */ Object.create(null), + normalizePropsOrEmits(to), + normalizePropsOrEmits(from != null ? from : {}) + ); + } else { + return from; + } +} +function mergeWatchOptions(to, from) { + if (!to) return from; + if (!from) return to; + const merged = extend(/* @__PURE__ */ Object.create(null), to); + for (const key in from) { + merged[key] = mergeAsArray(to[key], from[key]); + } + return merged; +} +function createAppContext() { + return { + app: null, + config: { + isNativeTag: NO, + performance: false, + globalProperties: {}, + optionMergeStrategies: {}, + errorHandler: void 0, + warnHandler: void 0, + compilerOptions: {} + }, + mixins: [], + components: {}, + directives: {}, + provides: /* @__PURE__ */ Object.create(null), + optionsCache: /* @__PURE__ */ new WeakMap(), + propsCache: /* @__PURE__ */ new WeakMap(), + emitsCache: /* @__PURE__ */ new WeakMap() + }; +} +let uid$1 = 0; +function createAppAPI(render2, hydrate) { + return function createApp2(rootComponent, rootProps = null) { + if (!isFunction(rootComponent)) { + rootComponent = extend({}, rootComponent); + } + if (rootProps != null && !isObject(rootProps)) { + rootProps = null; + } + const context = createAppContext(); + const installedPlugins = /* @__PURE__ */ new WeakSet(); + const pluginCleanupFns = []; + let isMounted = false; + const app2 = context.app = { + _uid: uid$1++, + _component: rootComponent, + _props: rootProps, + _container: null, + _context: context, + _instance: null, + version, + get config() { + return context.config; + }, + set config(v2) { + }, + use(plugin, ...options) { + if (installedPlugins.has(plugin)) ; + else if (plugin && isFunction(plugin.install)) { + installedPlugins.add(plugin); + plugin.install(app2, ...options); + } else if (isFunction(plugin)) { + installedPlugins.add(plugin); + plugin(app2, ...options); + } else ; + return app2; + }, + mixin(mixin) { + { + if (!context.mixins.includes(mixin)) { + context.mixins.push(mixin); + } + } + return app2; + }, + component(name, component) { + if (!component) { + return context.components[name]; + } + context.components[name] = component; + return app2; + }, + directive(name, directive) { + if (!directive) { + return context.directives[name]; + } + context.directives[name] = directive; + return app2; + }, + mount(rootContainer, isHydrate, namespace) { + if (!isMounted) { + const vnode = app2._ceVNode || createVNode(rootComponent, rootProps); + vnode.appContext = context; + if (namespace === true) { + namespace = "svg"; + } else if (namespace === false) { + namespace = void 0; + } + { + render2(vnode, rootContainer, namespace); + } + isMounted = true; + app2._container = rootContainer; + rootContainer.__vue_app__ = app2; + return getComponentPublicInstance(vnode.component); + } + }, + onUnmount(cleanupFn) { + pluginCleanupFns.push(cleanupFn); + }, + unmount() { + if (isMounted) { + callWithAsyncErrorHandling( + pluginCleanupFns, + app2._instance, + 16 + ); + render2(null, app2._container); + delete app2._container.__vue_app__; + } + }, + provide(key, value) { + context.provides[key] = value; + return app2; + }, + runWithContext(fn) { + const lastApp = currentApp; + currentApp = app2; + try { + return fn(); + } finally { + currentApp = lastApp; + } + } + }; + return app2; + }; +} +let currentApp = null; +const getModelModifiers = (props, modelName) => { + return modelName === "modelValue" || modelName === "model-value" ? props.modelModifiers : props[`${modelName}Modifiers`] || props[`${camelize(modelName)}Modifiers`] || props[`${hyphenate(modelName)}Modifiers`]; +}; +function emit(instance, event, ...rawArgs) { + if (instance.isUnmounted) return; + const props = instance.vnode.props || EMPTY_OBJ; + let args = rawArgs; + const isModelListener2 = event.startsWith("update:"); + const modifiers = isModelListener2 && getModelModifiers(props, event.slice(7)); + if (modifiers) { + if (modifiers.trim) { + args = rawArgs.map((a2) => isString(a2) ? a2.trim() : a2); + } + if (modifiers.number) { + args = rawArgs.map(looseToNumber); + } + } + let handlerName; + let handler9 = props[handlerName = toHandlerKey(event)] || // also try camelCase event handler (#2249) + props[handlerName = toHandlerKey(camelize(event))]; + if (!handler9 && isModelListener2) { + handler9 = props[handlerName = toHandlerKey(hyphenate(event))]; + } + if (handler9) { + callWithAsyncErrorHandling( + handler9, + instance, + 6, + args + ); + } + const onceHandler = props[handlerName + `Once`]; + if (onceHandler) { + if (!instance.emitted) { + instance.emitted = {}; + } else if (instance.emitted[handlerName]) { + return; + } + instance.emitted[handlerName] = true; + callWithAsyncErrorHandling( + onceHandler, + instance, + 6, + args + ); + } +} +const mixinEmitsCache = /* @__PURE__ */ new WeakMap(); +function normalizeEmitsOptions(comp, appContext, asMixin = false) { + const cache = asMixin ? mixinEmitsCache : appContext.emitsCache; + const cached = cache.get(comp); + if (cached !== void 0) { + return cached; + } + const raw = comp.emits; + let normalized = {}; + let hasExtends = false; + if (!isFunction(comp)) { + const extendEmits = (raw2) => { + const normalizedFromExtend = normalizeEmitsOptions(raw2, appContext, true); + if (normalizedFromExtend) { + hasExtends = true; + extend(normalized, normalizedFromExtend); + } + }; + if (!asMixin && appContext.mixins.length) { + appContext.mixins.forEach(extendEmits); + } + if (comp.extends) { + extendEmits(comp.extends); + } + if (comp.mixins) { + comp.mixins.forEach(extendEmits); + } + } + if (!raw && !hasExtends) { + if (isObject(comp)) { + cache.set(comp, null); + } + return null; + } + if (isArray(raw)) { + raw.forEach((key) => normalized[key] = null); + } else { + extend(normalized, raw); + } + if (isObject(comp)) { + cache.set(comp, normalized); + } + return normalized; +} +function isEmitListener(options, key) { + if (!options || !isOn(key)) { + return false; + } + key = key.slice(2).replace(/Once$/, ""); + return hasOwn(options, key[0].toLowerCase() + key.slice(1)) || hasOwn(options, hyphenate(key)) || hasOwn(options, key); +} +function markAttrsAccessed() { +} +function renderComponentRoot(instance) { + const { + type: Component, + vnode, + proxy, + withProxy, + propsOptions: [propsOptions], + slots, + attrs: attrs3, + emit: emit2, + render: render2, + renderCache, + props, + data: data3, + setupState, + ctx, + inheritAttrs + } = instance; + const prev = setCurrentRenderingInstance(instance); + let result; + let fallthroughAttrs; + try { + if (vnode.shapeFlag & 4) { + const proxyToUse = withProxy || proxy; + const thisProxy = false ? new Proxy(proxyToUse, { + get(target, key, receiver) { + warn$1( + `Property '${String( + key + )}' was accessed via 'this'. Avoid using 'this' in templates.` + ); + return Reflect.get(target, key, receiver); + } + }) : proxyToUse; + result = normalizeVNode( + render2.call( + thisProxy, + proxyToUse, + renderCache, + false ? shallowReadonly(props) : props, + setupState, + data3, + ctx + ) + ); + fallthroughAttrs = attrs3; + } else { + const render22 = Component; + if (false) ; + result = normalizeVNode( + render22.length > 1 ? render22( + false ? shallowReadonly(props) : props, + false ? { + get attrs() { + markAttrsAccessed(); + return shallowReadonly(attrs3); + }, + slots, + emit: emit2 + } : { attrs: attrs3, slots, emit: emit2 } + ) : render22( + false ? shallowReadonly(props) : props, + null + ) + ); + fallthroughAttrs = Component.props ? attrs3 : getFunctionalFallthrough(attrs3); + } + } catch (err) { + blockStack.length = 0; + handleError(err, instance, 1); + result = createVNode(Comment); + } + let root5 = result; + if (fallthroughAttrs && inheritAttrs !== false) { + const keys = Object.keys(fallthroughAttrs); + const { shapeFlag } = root5; + if (keys.length) { + if (shapeFlag & (1 | 6)) { + if (propsOptions && keys.some(isModelListener)) { + fallthroughAttrs = filterModelListeners( + fallthroughAttrs, + propsOptions + ); + } + root5 = cloneVNode(root5, fallthroughAttrs, false, true); + } + } + } + if (vnode.dirs) { + root5 = cloneVNode(root5, null, false, true); + root5.dirs = root5.dirs ? root5.dirs.concat(vnode.dirs) : vnode.dirs; + } + if (vnode.transition) { + setTransitionHooks(root5, vnode.transition); + } + { + result = root5; + } + setCurrentRenderingInstance(prev); + return result; +} +const getFunctionalFallthrough = (attrs3) => { + let res; + for (const key in attrs3) { + if (key === "class" || key === "style" || isOn(key)) { + (res || (res = {}))[key] = attrs3[key]; + } + } + return res; +}; +const filterModelListeners = (attrs3, props) => { + const res = {}; + for (const key in attrs3) { + if (!isModelListener(key) || !(key.slice(9) in props)) { + res[key] = attrs3[key]; + } + } + return res; +}; +function shouldUpdateComponent(prevVNode, nextVNode, optimized) { + const { props: prevProps, children: prevChildren, component } = prevVNode; + const { props: nextProps, children: nextChildren, patchFlag } = nextVNode; + const emits = component.emitsOptions; + if (nextVNode.dirs || nextVNode.transition) { + return true; + } + if (optimized && patchFlag >= 0) { + if (patchFlag & 1024) { + return true; + } + if (patchFlag & 16) { + if (!prevProps) { + return !!nextProps; + } + return hasPropsChanged(prevProps, nextProps, emits); + } else if (patchFlag & 8) { + const dynamicProps = nextVNode.dynamicProps; + for (let i2 = 0; i2 < dynamicProps.length; i2++) { + const key = dynamicProps[i2]; + if (nextProps[key] !== prevProps[key] && !isEmitListener(emits, key)) { + return true; + } + } + } + } else { + if (prevChildren || nextChildren) { + if (!nextChildren || !nextChildren.$stable) { + return true; + } + } + if (prevProps === nextProps) { + return false; + } + if (!prevProps) { + return !!nextProps; + } + if (!nextProps) { + return true; + } + return hasPropsChanged(prevProps, nextProps, emits); + } + return false; +} +function hasPropsChanged(prevProps, nextProps, emitsOptions) { + const nextKeys = Object.keys(nextProps); + if (nextKeys.length !== Object.keys(prevProps).length) { + return true; + } + for (let i2 = 0; i2 < nextKeys.length; i2++) { + const key = nextKeys[i2]; + if (nextProps[key] !== prevProps[key] && !isEmitListener(emitsOptions, key)) { + return true; + } + } + return false; +} +function updateHOCHostEl({ vnode, parent }, el) { + while (parent) { + const root5 = parent.subTree; + if (root5.suspense && root5.suspense.activeBranch === vnode) { + root5.el = vnode.el; + } + if (root5 === vnode) { + (vnode = parent.vnode).el = el; + parent = parent.parent; + } else { + break; + } + } +} +const internalObjectProto = {}; +const createInternalObject = () => Object.create(internalObjectProto); +const isInternalObject = (obj) => Object.getPrototypeOf(obj) === internalObjectProto; +function initProps(instance, rawProps, isStateful, isSSR = false) { + const props = {}; + const attrs3 = createInternalObject(); + instance.propsDefaults = /* @__PURE__ */ Object.create(null); + setFullProps(instance, rawProps, props, attrs3); + for (const key in instance.propsOptions[0]) { + if (!(key in props)) { + props[key] = void 0; + } + } + if (isStateful) { + instance.props = isSSR ? props : shallowReactive(props); + } else { + if (!instance.type.props) { + instance.props = attrs3; + } else { + instance.props = props; + } + } + instance.attrs = attrs3; +} +function updateProps(instance, rawProps, rawPrevProps, optimized) { + const { + props, + attrs: attrs3, + vnode: { patchFlag } + } = instance; + const rawCurrentProps = toRaw(props); + const [options] = instance.propsOptions; + let hasAttrsChanged = false; + if ( + // always force full diff in dev + // - #1942 if hmr is enabled with sfc component + // - vite#872 non-sfc component used by sfc component + (optimized || patchFlag > 0) && !(patchFlag & 16) + ) { + if (patchFlag & 8) { + const propsToUpdate = instance.vnode.dynamicProps; + for (let i2 = 0; i2 < propsToUpdate.length; i2++) { + let key = propsToUpdate[i2]; + if (isEmitListener(instance.emitsOptions, key)) { + continue; + } + const value = rawProps[key]; + if (options) { + if (hasOwn(attrs3, key)) { + if (value !== attrs3[key]) { + attrs3[key] = value; + hasAttrsChanged = true; + } + } else { + const camelizedKey = camelize(key); + props[camelizedKey] = resolvePropValue( + options, + rawCurrentProps, + camelizedKey, + value, + instance, + false + ); + } + } else { + if (value !== attrs3[key]) { + attrs3[key] = value; + hasAttrsChanged = true; + } + } + } + } + } else { + if (setFullProps(instance, rawProps, props, attrs3)) { + hasAttrsChanged = true; + } + let kebabKey; + for (const key in rawCurrentProps) { + if (!rawProps || // for camelCase + !hasOwn(rawProps, key) && // it's possible the original props was passed in as kebab-case + // and converted to camelCase (#955) + ((kebabKey = hyphenate(key)) === key || !hasOwn(rawProps, kebabKey))) { + if (options) { + if (rawPrevProps && // for camelCase + (rawPrevProps[key] !== void 0 || // for kebab-case + rawPrevProps[kebabKey] !== void 0)) { + props[key] = resolvePropValue( + options, + rawCurrentProps, + key, + void 0, + instance, + true + ); + } + } else { + delete props[key]; + } + } + } + if (attrs3 !== rawCurrentProps) { + for (const key in attrs3) { + if (!rawProps || !hasOwn(rawProps, key) && true) { + delete attrs3[key]; + hasAttrsChanged = true; + } + } + } + } + if (hasAttrsChanged) { + trigger(instance.attrs, "set", ""); + } +} +function setFullProps(instance, rawProps, props, attrs3) { + const [options, needCastKeys] = instance.propsOptions; + let hasAttrsChanged = false; + let rawCastValues; + if (rawProps) { + for (let key in rawProps) { + if (isReservedProp(key)) { + continue; + } + const value = rawProps[key]; + let camelKey; + if (options && hasOwn(options, camelKey = camelize(key))) { + if (!needCastKeys || !needCastKeys.includes(camelKey)) { + props[camelKey] = value; + } else { + (rawCastValues || (rawCastValues = {}))[camelKey] = value; + } + } else if (!isEmitListener(instance.emitsOptions, key)) { + if (!(key in attrs3) || value !== attrs3[key]) { + attrs3[key] = value; + hasAttrsChanged = true; + } + } + } + } + if (needCastKeys) { + const rawCurrentProps = toRaw(props); + const castValues = rawCastValues || EMPTY_OBJ; + for (let i2 = 0; i2 < needCastKeys.length; i2++) { + const key = needCastKeys[i2]; + props[key] = resolvePropValue( + options, + rawCurrentProps, + key, + castValues[key], + instance, + !hasOwn(castValues, key) + ); + } + } + return hasAttrsChanged; +} +function resolvePropValue(options, props, key, value, instance, isAbsent) { + const opt = options[key]; + if (opt != null) { + const hasDefault = hasOwn(opt, "default"); + if (hasDefault && value === void 0) { + const defaultValue2 = opt.default; + if (opt.type !== Function && !opt.skipFactory && isFunction(defaultValue2)) { + const { propsDefaults } = instance; + if (key in propsDefaults) { + value = propsDefaults[key]; + } else { + const reset = setCurrentInstance(instance); + value = propsDefaults[key] = defaultValue2.call( + null, + props + ); + reset(); + } + } else { + value = defaultValue2; + } + if (instance.ce) { + instance.ce._setProp(key, value); + } + } + if (opt[ + 0 + /* shouldCast */ + ]) { + if (isAbsent && !hasDefault) { + value = false; + } else if (opt[ + 1 + /* shouldCastTrue */ + ] && (value === "" || value === hyphenate(key))) { + value = true; + } + } + } + return value; +} +const mixinPropsCache = /* @__PURE__ */ new WeakMap(); +function normalizePropsOptions(comp, appContext, asMixin = false) { + const cache = asMixin ? mixinPropsCache : appContext.propsCache; + const cached = cache.get(comp); + if (cached) { + return cached; + } + const raw = comp.props; + const normalized = {}; + const needCastKeys = []; + let hasExtends = false; + if (!isFunction(comp)) { + const extendProps = (raw2) => { + hasExtends = true; + const [props, keys] = normalizePropsOptions(raw2, appContext, true); + extend(normalized, props); + if (keys) needCastKeys.push(...keys); + }; + if (!asMixin && appContext.mixins.length) { + appContext.mixins.forEach(extendProps); + } + if (comp.extends) { + extendProps(comp.extends); + } + if (comp.mixins) { + comp.mixins.forEach(extendProps); + } + } + if (!raw && !hasExtends) { + if (isObject(comp)) { + cache.set(comp, EMPTY_ARR); + } + return EMPTY_ARR; + } + if (isArray(raw)) { + for (let i2 = 0; i2 < raw.length; i2++) { + const normalizedKey = camelize(raw[i2]); + if (validatePropName(normalizedKey)) { + normalized[normalizedKey] = EMPTY_OBJ; + } + } + } else if (raw) { + for (const key in raw) { + const normalizedKey = camelize(key); + if (validatePropName(normalizedKey)) { + const opt = raw[key]; + const prop = normalized[normalizedKey] = isArray(opt) || isFunction(opt) ? { type: opt } : extend({}, opt); + const propType = prop.type; + let shouldCast = false; + let shouldCastTrue = true; + if (isArray(propType)) { + for (let index = 0; index < propType.length; ++index) { + const type = propType[index]; + const typeName = isFunction(type) && type.name; + if (typeName === "Boolean") { + shouldCast = true; + break; + } else if (typeName === "String") { + shouldCastTrue = false; + } + } + } else { + shouldCast = isFunction(propType) && propType.name === "Boolean"; + } + prop[ + 0 + /* shouldCast */ + ] = shouldCast; + prop[ + 1 + /* shouldCastTrue */ + ] = shouldCastTrue; + if (shouldCast || hasOwn(prop, "default")) { + needCastKeys.push(normalizedKey); + } + } + } + } + const res = [normalized, needCastKeys]; + if (isObject(comp)) { + cache.set(comp, res); + } + return res; +} +function validatePropName(key) { + if (key[0] !== "$" && !isReservedProp(key)) { + return true; + } + return false; +} +const isInternalKey = (key) => key === "_" || key === "_ctx" || key === "$stable"; +const normalizeSlotValue = (value) => isArray(value) ? value.map(normalizeVNode) : [normalizeVNode(value)]; +const normalizeSlot = (key, rawSlot, ctx) => { + if (rawSlot._n) { + return rawSlot; + } + const normalized = withCtx((...args) => { + if (false) ; + return normalizeSlotValue(rawSlot(...args)); + }, ctx); + normalized._c = false; + return normalized; +}; +const normalizeObjectSlots = (rawSlots, slots, instance) => { + const ctx = rawSlots._ctx; + for (const key in rawSlots) { + if (isInternalKey(key)) continue; + const value = rawSlots[key]; + if (isFunction(value)) { + slots[key] = normalizeSlot(key, value, ctx); + } else if (value != null) { + const normalized = normalizeSlotValue(value); + slots[key] = () => normalized; + } + } +}; +const normalizeVNodeSlots = (instance, children) => { + const normalized = normalizeSlotValue(children); + instance.slots.default = () => normalized; +}; +const assignSlots = (slots, children, optimized) => { + for (const key in children) { + if (optimized || !isInternalKey(key)) { + slots[key] = children[key]; + } + } +}; +const initSlots = (instance, children, optimized) => { + const slots = instance.slots = createInternalObject(); + if (instance.vnode.shapeFlag & 32) { + const type = children._; + if (type) { + assignSlots(slots, children, optimized); + if (optimized) { + def(slots, "_", type, true); + } + } else { + normalizeObjectSlots(children, slots); + } + } else if (children) { + normalizeVNodeSlots(instance, children); + } +}; +const updateSlots = (instance, children, optimized) => { + const { vnode, slots } = instance; + let needDeletionCheck = true; + let deletionComparisonTarget = EMPTY_OBJ; + if (vnode.shapeFlag & 32) { + const type = children._; + if (type) { + if (optimized && type === 1) { + needDeletionCheck = false; + } else { + assignSlots(slots, children, optimized); + } + } else { + needDeletionCheck = !children.$stable; + normalizeObjectSlots(children, slots); + } + deletionComparisonTarget = children; + } else if (children) { + normalizeVNodeSlots(instance, children); + deletionComparisonTarget = { default: 1 }; + } + if (needDeletionCheck) { + for (const key in slots) { + if (!isInternalKey(key) && deletionComparisonTarget[key] == null) { + delete slots[key]; + } + } + } +}; +const queuePostRenderEffect = queueEffectWithSuspense; +function createRenderer(options) { + return baseCreateRenderer(options); +} +function baseCreateRenderer(options, createHydrationFns) { + const target = getGlobalThis(); + target.__VUE__ = true; + const { + insert: hostInsert, + remove: hostRemove, + patchProp: hostPatchProp, + createElement: hostCreateElement, + createText: hostCreateText, + createComment: hostCreateComment, + setText: hostSetText, + setElementText: hostSetElementText, + parentNode: hostParentNode, + nextSibling: hostNextSibling, + setScopeId: hostSetScopeId = NOOP, + insertStaticContent: hostInsertStaticContent + } = options; + const patch = (n1, n2, container, anchor = null, parentComponent = null, parentSuspense = null, namespace = void 0, slotScopeIds = null, optimized = !!n2.dynamicChildren) => { + if (n1 === n2) { + return; + } + if (n1 && !isSameVNodeType(n1, n2)) { + anchor = getNextHostNode(n1); + unmount(n1, parentComponent, parentSuspense, true); + n1 = null; + } + if (n2.patchFlag === -2) { + optimized = false; + n2.dynamicChildren = null; + } + const { type, ref: ref3, shapeFlag } = n2; + switch (type) { + case Text: + processText(n1, n2, container, anchor); + break; + case Comment: + processCommentNode(n1, n2, container, anchor); + break; + case Static: + if (n1 == null) { + mountStaticNode(n2, container, anchor, namespace); + } + break; + case Fragment: + processFragment( + n1, + n2, + container, + anchor, + parentComponent, + parentSuspense, + namespace, + slotScopeIds, + optimized + ); + break; + default: + if (shapeFlag & 1) { + processElement( + n1, + n2, + container, + anchor, + parentComponent, + parentSuspense, + namespace, + slotScopeIds, + optimized + ); + } else if (shapeFlag & 6) { + processComponent( + n1, + n2, + container, + anchor, + parentComponent, + parentSuspense, + namespace, + slotScopeIds, + optimized + ); + } else if (shapeFlag & 64) { + type.process( + n1, + n2, + container, + anchor, + parentComponent, + parentSuspense, + namespace, + slotScopeIds, + optimized, + internals + ); + } else if (shapeFlag & 128) { + type.process( + n1, + n2, + container, + anchor, + parentComponent, + parentSuspense, + namespace, + slotScopeIds, + optimized, + internals + ); + } else ; + } + if (ref3 != null && parentComponent) { + setRef(ref3, n1 && n1.ref, parentSuspense, n2 || n1, !n2); + } else if (ref3 == null && n1 && n1.ref != null) { + setRef(n1.ref, null, parentSuspense, n1, true); + } + }; + const processText = (n1, n2, container, anchor) => { + if (n1 == null) { + hostInsert( + n2.el = hostCreateText(n2.children), + container, + anchor + ); + } else { + const el = n2.el = n1.el; + if (n2.children !== n1.children) { + { + hostSetText(el, n2.children); + } + } + } + }; + const processCommentNode = (n1, n2, container, anchor) => { + if (n1 == null) { + hostInsert( + n2.el = hostCreateComment(n2.children || ""), + container, + anchor + ); + } else { + n2.el = n1.el; + } + }; + const mountStaticNode = (n2, container, anchor, namespace) => { + [n2.el, n2.anchor] = hostInsertStaticContent( + n2.children, + container, + anchor, + namespace, + n2.el, + n2.anchor + ); + }; + const moveStaticNode = ({ el, anchor }, container, nextSibling) => { + let next; + while (el && el !== anchor) { + next = hostNextSibling(el); + hostInsert(el, container, nextSibling); + el = next; + } + hostInsert(anchor, container, nextSibling); + }; + const removeStaticNode = ({ el, anchor }) => { + let next; + while (el && el !== anchor) { + next = hostNextSibling(el); + hostRemove(el); + el = next; + } + hostRemove(anchor); + }; + const processElement = (n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => { + if (n2.type === "svg") { + namespace = "svg"; + } else if (n2.type === "math") { + namespace = "mathml"; + } + if (n1 == null) { + mountElement( + n2, + container, + anchor, + parentComponent, + parentSuspense, + namespace, + slotScopeIds, + optimized + ); + } else { + const customElement = !!(n1.el && n1.el._isVueCE) ? n1.el : null; + try { + if (customElement) { + customElement._beginPatch(); + } + patchElement( + n1, + n2, + parentComponent, + parentSuspense, + namespace, + slotScopeIds, + optimized + ); + } finally { + if (customElement) { + customElement._endPatch(); + } + } + } + }; + const mountElement = (vnode, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => { + let el; + let vnodeHook; + const { props, shapeFlag, transition, dirs } = vnode; + el = vnode.el = hostCreateElement( + vnode.type, + namespace, + props && props.is, + props + ); + if (shapeFlag & 8) { + hostSetElementText(el, vnode.children); + } else if (shapeFlag & 16) { + mountChildren( + vnode.children, + el, + null, + parentComponent, + parentSuspense, + resolveChildrenNamespace(vnode, namespace), + slotScopeIds, + optimized + ); + } + if (dirs) { + invokeDirectiveHook(vnode, null, parentComponent, "created"); + } + setScopeId(el, vnode, vnode.scopeId, slotScopeIds, parentComponent); + if (props) { + for (const key in props) { + if (key !== "value" && !isReservedProp(key)) { + hostPatchProp(el, key, null, props[key], namespace, parentComponent); + } + } + if ("value" in props) { + hostPatchProp(el, "value", null, props.value, namespace); + } + if (vnodeHook = props.onVnodeBeforeMount) { + invokeVNodeHook(vnodeHook, parentComponent, vnode); + } + } + if (dirs) { + invokeDirectiveHook(vnode, null, parentComponent, "beforeMount"); + } + const needCallTransitionHooks = needTransition(parentSuspense, transition); + if (needCallTransitionHooks) { + transition.beforeEnter(el); + } + hostInsert(el, container, anchor); + if ((vnodeHook = props && props.onVnodeMounted) || needCallTransitionHooks || dirs) { + queuePostRenderEffect(() => { + vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode); + needCallTransitionHooks && transition.enter(el); + dirs && invokeDirectiveHook(vnode, null, parentComponent, "mounted"); + }, parentSuspense); + } + }; + const setScopeId = (el, vnode, scopeId, slotScopeIds, parentComponent) => { + if (scopeId) { + hostSetScopeId(el, scopeId); + } + if (slotScopeIds) { + for (let i2 = 0; i2 < slotScopeIds.length; i2++) { + hostSetScopeId(el, slotScopeIds[i2]); + } + } + if (parentComponent) { + let subTree = parentComponent.subTree; + if (vnode === subTree || isSuspense(subTree.type) && (subTree.ssContent === vnode || subTree.ssFallback === vnode)) { + const parentVNode = parentComponent.vnode; + setScopeId( + el, + parentVNode, + parentVNode.scopeId, + parentVNode.slotScopeIds, + parentComponent.parent + ); + } + } + }; + const mountChildren = (children, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized, start = 0) => { + for (let i2 = start; i2 < children.length; i2++) { + const child = children[i2] = optimized ? cloneIfMounted(children[i2]) : normalizeVNode(children[i2]); + patch( + null, + child, + container, + anchor, + parentComponent, + parentSuspense, + namespace, + slotScopeIds, + optimized + ); + } + }; + const patchElement = (n1, n2, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => { + const el = n2.el = n1.el; + let { patchFlag, dynamicChildren, dirs } = n2; + patchFlag |= n1.patchFlag & 16; + const oldProps = n1.props || EMPTY_OBJ; + const newProps = n2.props || EMPTY_OBJ; + let vnodeHook; + parentComponent && toggleRecurse(parentComponent, false); + if (vnodeHook = newProps.onVnodeBeforeUpdate) { + invokeVNodeHook(vnodeHook, parentComponent, n2, n1); + } + if (dirs) { + invokeDirectiveHook(n2, n1, parentComponent, "beforeUpdate"); + } + parentComponent && toggleRecurse(parentComponent, true); + if (oldProps.innerHTML && newProps.innerHTML == null || oldProps.textContent && newProps.textContent == null) { + hostSetElementText(el, ""); + } + if (dynamicChildren) { + patchBlockChildren( + n1.dynamicChildren, + dynamicChildren, + el, + parentComponent, + parentSuspense, + resolveChildrenNamespace(n2, namespace), + slotScopeIds + ); + } else if (!optimized) { + patchChildren( + n1, + n2, + el, + null, + parentComponent, + parentSuspense, + resolveChildrenNamespace(n2, namespace), + slotScopeIds, + false + ); + } + if (patchFlag > 0) { + if (patchFlag & 16) { + patchProps(el, oldProps, newProps, parentComponent, namespace); + } else { + if (patchFlag & 2) { + if (oldProps.class !== newProps.class) { + hostPatchProp(el, "class", null, newProps.class, namespace); + } + } + if (patchFlag & 4) { + hostPatchProp(el, "style", oldProps.style, newProps.style, namespace); + } + if (patchFlag & 8) { + const propsToUpdate = n2.dynamicProps; + for (let i2 = 0; i2 < propsToUpdate.length; i2++) { + const key = propsToUpdate[i2]; + const prev = oldProps[key]; + const next = newProps[key]; + if (next !== prev || key === "value") { + hostPatchProp(el, key, prev, next, namespace, parentComponent); + } + } + } + } + if (patchFlag & 1) { + if (n1.children !== n2.children) { + hostSetElementText(el, n2.children); + } + } + } else if (!optimized && dynamicChildren == null) { + patchProps(el, oldProps, newProps, parentComponent, namespace); + } + if ((vnodeHook = newProps.onVnodeUpdated) || dirs) { + queuePostRenderEffect(() => { + vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, n2, n1); + dirs && invokeDirectiveHook(n2, n1, parentComponent, "updated"); + }, parentSuspense); + } + }; + const patchBlockChildren = (oldChildren, newChildren, fallbackContainer, parentComponent, parentSuspense, namespace, slotScopeIds) => { + for (let i2 = 0; i2 < newChildren.length; i2++) { + const oldVNode = oldChildren[i2]; + const newVNode = newChildren[i2]; + const container = ( + // oldVNode may be an errored async setup() component inside Suspense + // which will not have a mounted element + oldVNode.el && // - In the case of a Fragment, we need to provide the actual parent + // of the Fragment itself so it can move its children. + (oldVNode.type === Fragment || // - In the case of different nodes, there is going to be a replacement + // which also requires the correct parent container + !isSameVNodeType(oldVNode, newVNode) || // - In the case of a component, it could contain anything. + oldVNode.shapeFlag & (6 | 64 | 128)) ? hostParentNode(oldVNode.el) : ( + // In other cases, the parent container is not actually used so we + // just pass the block element here to avoid a DOM parentNode call. + fallbackContainer + ) + ); + patch( + oldVNode, + newVNode, + container, + null, + parentComponent, + parentSuspense, + namespace, + slotScopeIds, + true + ); + } + }; + const patchProps = (el, oldProps, newProps, parentComponent, namespace) => { + if (oldProps !== newProps) { + if (oldProps !== EMPTY_OBJ) { + for (const key in oldProps) { + if (!isReservedProp(key) && !(key in newProps)) { + hostPatchProp( + el, + key, + oldProps[key], + null, + namespace, + parentComponent + ); + } + } + } + for (const key in newProps) { + if (isReservedProp(key)) continue; + const next = newProps[key]; + const prev = oldProps[key]; + if (next !== prev && key !== "value") { + hostPatchProp(el, key, prev, next, namespace, parentComponent); + } + } + if ("value" in newProps) { + hostPatchProp(el, "value", oldProps.value, newProps.value, namespace); + } + } + }; + const processFragment = (n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => { + const fragmentStartAnchor = n2.el = n1 ? n1.el : hostCreateText(""); + const fragmentEndAnchor = n2.anchor = n1 ? n1.anchor : hostCreateText(""); + let { patchFlag, dynamicChildren, slotScopeIds: fragmentSlotScopeIds } = n2; + if (fragmentSlotScopeIds) { + slotScopeIds = slotScopeIds ? slotScopeIds.concat(fragmentSlotScopeIds) : fragmentSlotScopeIds; + } + if (n1 == null) { + hostInsert(fragmentStartAnchor, container, anchor); + hostInsert(fragmentEndAnchor, container, anchor); + mountChildren( + // #10007 + // such fragment like `<>` will be compiled into + // a fragment which doesn't have a children. + // In this case fallback to an empty array + n2.children || [], + container, + fragmentEndAnchor, + parentComponent, + parentSuspense, + namespace, + slotScopeIds, + optimized + ); + } else { + if (patchFlag > 0 && patchFlag & 64 && dynamicChildren && // #2715 the previous fragment could've been a BAILed one as a result + // of renderSlot() with no valid children + n1.dynamicChildren && n1.dynamicChildren.length === dynamicChildren.length) { + patchBlockChildren( + n1.dynamicChildren, + dynamicChildren, + container, + parentComponent, + parentSuspense, + namespace, + slotScopeIds + ); + if ( + // #2080 if the stable fragment has a key, it's a