From 9345654cc17f782935d4e520fefaf839b89f2e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=84=AD=E6=B2=9B=E8=BB=92?= Date: Tue, 9 Sep 2025 23:53:01 +0800 Subject: [PATCH] refactor: complete project structure reorganization and SOP implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Reorganize project structure to unified apps/ directory - Move src/backend/ → apps/backend/ (complete .NET Core API) - Move src/mobile/ → apps/mobile/ (complete Flutter app) - Keep apps/web/ as Vue.js frontend - Remove duplicate src/ directory structure - Implement comprehensive SOP (Standard Operating Procedures) - Create sop/ unified management directory - Move CLAUDE.md → sop/docs/CLAUDE.md with updated guidelines - Move tools/, scripts/, archive/ → sop/ for centralized management - Establish three-tier task management architecture - Create unified task management system - Rename TASK_MANAGEMENT.md → TASKS.md for simplicity - Integrate 17 UI design tasks from ui-design-tasks.md - Update task priority classification (🔥緊急/⚠️重要/📝一般/💡想法) - Update ./dl script for new file paths - Archive obsolete systems and files - Archive old reports/ directory (replaced by sop/archive/) - Archive duplicate template files violating SOP principles - Clean up src/ directory documentation and configs 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .claude/settings.local.json | 16 +- TASKS.md | 143 + apps/README.md | 27 + .../Controllers/HealthController.cs | 0 .../backend/DramaLing.API/Dockerfile.dev | 0 .../DramaLing.API/DramaLing.API.csproj | 0 .../backend/DramaLing.API/Program.cs | 0 .../appsettings.Development.json | 0 .../backend/DramaLing.API/appsettings.json | 0 .../DependencyInjection.cs | 0 .../DramaLing.Application.csproj | 0 .../DramaLing.Core/DramaLing.Core.csproj | 0 .../DramaLing.Core/Entities/BaseEntity.cs | 0 .../DramaLing.Core/Entities/Gamification.cs | 0 .../DramaLing.Core/Entities/LearningStage.cs | 0 .../backend/DramaLing.Core/Entities/User.cs | 0 .../DramaLing.Core/Enums/LearningStage.cs | 0 .../Data/ApplicationDbContext.cs | 0 .../DependencyInjection.cs | 0 .../DramaLing.Infrastructure.csproj | 0 {src => apps}/backend/DramaLing.sln | 0 apps/backend/README.md | 45 + {src => apps}/mobile/.gitignore | 0 {src => apps}/mobile/.metadata | 0 apps/mobile/README.md | 43 + {src => apps}/mobile/analysis_options.yaml | 0 {src => apps}/mobile/android/.gitignore | 0 .../mobile/android/app/build.gradle.kts | 0 .../mobile/android/app/proguard-rules.pro | 0 .../android/app/src/main/AndroidManifest.xml | 0 .../kotlin/com/dramaling/app/MainActivity.kt | 0 .../res/drawable-v21/launch_background.xml | 0 .../main/res/drawable/launch_background.xml | 0 .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../app/src/main/res/values-night/styles.xml | 0 .../app/src/main/res/values/styles.xml | 0 {src => apps}/mobile/android/build.gradle.kts | 0 .../mobile/android/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.properties | 0 .../mobile/android/settings.gradle.kts | 0 {src => apps}/mobile/ios/.gitignore | 0 .../mobile/ios/Flutter/AppFrameworkInfo.plist | 0 .../mobile/ios/Flutter/Debug.xcconfig | 0 .../mobile/ios/Flutter/Release.xcconfig | 0 {src => apps}/mobile/ios/Podfile | 0 {src => apps}/mobile/ios/Podfile.lock | 0 .../ios/Runner.xcodeproj/project.pbxproj | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../xcshareddata/xcschemes/Runner.xcscheme | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../mobile/ios/Runner/AppDelegate.swift | 0 .../AppIcon.appiconset/Contents.json | 0 .../Icon-App-1024x1024@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin .../Icon-App-83.5x83.5@2x.png | Bin .../LaunchImage.imageset/Contents.json | 0 .../LaunchImage.imageset/LaunchImage.png | Bin .../LaunchImage.imageset/LaunchImage@2x.png | Bin .../LaunchImage.imageset/LaunchImage@3x.png | Bin .../LaunchImage.imageset/README.md | 0 .../Runner/Base.lproj/LaunchScreen.storyboard | 0 .../ios/Runner/Base.lproj/Main.storyboard | 0 {src => apps}/mobile/ios/Runner/Info.plist | 0 .../ios/Runner/Runner-Bridging-Header.h | 0 .../mobile/ios/RunnerTests/RunnerTests.swift | 0 .../lib/core/constants/app_constants.dart | 0 .../lib/core/services/storage_service.dart | 0 .../services/voice_recognition_service.dart | 0 .../mobile/lib/core/utils/app_router.dart | 0 .../mobile/lib/core/utils/app_theme.dart | 0 .../features/auth/screens/login_screen.dart | 0 .../auth/screens/register_screen.dart | 0 .../dialogue/models/dialogue_models.dart | 0 .../dialogue/providers/dialogue_provider.dart | 0 .../screens/dialogue_main_screen.dart | 0 .../dialogue/services/dialogue_service.dart | 0 .../dialogue/widgets/character_avatar.dart | 0 .../dialogue/widgets/dialogue_background.dart | 0 .../dialogue/widgets/dialogue_bubble.dart | 0 .../widgets/reply_assistance_panel.dart | 0 .../dialogue/widgets/task_display_panel.dart | 0 .../dialogue/widgets/vocabulary_panel.dart | 0 .../learning/screens/home_screen.dart | 0 {src => apps}/mobile/lib/main.dart | 0 .../lib/shared/providers/auth_provider.dart | 0 .../providers/voice_recognition_provider.dart | 0 .../shared/widgets/voice_input_button.dart | 0 {src => apps}/mobile/pubspec.lock | 0 {src => apps}/mobile/pubspec.yaml | 0 {src => apps}/mobile/test/widget_test.dart | 0 {src => apps}/mobile/web/favicon.png | Bin {src => apps}/mobile/web/index.html | 0 {src => apps}/mobile/web/manifest.json | 0 apps/web/.eslintrc.js | 51 + apps/web/.prettierrc | 14 + apps/web/auto-imports.d.ts | 193 + apps/web/components.d.ts | 23 + apps/web/index.html | 103 + apps/web/package-lock.json | 13619 ++++++++++++++++ apps/web/package.json | 64 + apps/web/src/App.vue | 123 + apps/web/src/assets/styles/main.scss | 328 + .../src/assets/styles/quasar-variables.sass | 56 + apps/web/src/assets/styles/variables.scss | 171 + apps/web/src/components/base/BaseButton.vue | 109 + apps/web/src/components/base/BaseCard.vue | 60 + apps/web/src/components/base/BaseInput.vue | 155 + apps/web/src/components/base/BaseModal.vue | 217 + apps/web/src/components/ui/ModalContainer.vue | 127 + apps/web/src/components/ui/ToastContainer.vue | 219 + apps/web/src/layouts/AppLayout.vue | 545 + apps/web/src/layouts/AuthLayout.vue | 333 + apps/web/src/main.ts | 56 + apps/web/src/router/index-full.ts | 210 + apps/web/src/router/index-minimal.ts | 20 + apps/web/src/router/index.ts | 210 + apps/web/src/stores/auth.ts | 286 + apps/web/src/stores/index.ts | 16 + apps/web/src/stores/learning.ts | 364 + apps/web/src/stores/ui.ts | 280 + apps/web/src/stores/user.ts | 302 + apps/web/src/types/learning.ts | 198 + apps/web/src/types/user.ts | 112 + apps/web/src/utils/index.ts | 314 + apps/web/src/views/HomeView.vue | 524 + apps/web/src/views/NotFoundView.vue | 70 + apps/web/src/views/OfflineView.vue | 152 + .../web/src/views/auth/ForgotPasswordView.vue | 327 + apps/web/src/views/auth/LoginView.vue | 317 + apps/web/src/views/auth/RegisterView-orig.vue | 462 + apps/web/src/views/auth/RegisterView.vue | 262 + apps/web/src/views/learning/DialogueView.vue | 94 + .../src/views/learning/LearningHomeView.vue | 45 + .../src/views/learning/PronunciationView.vue | 175 + apps/web/src/views/learning/RoleplayView.vue | 101 + .../web/src/views/learning/VocabularyView.vue | 39 + apps/web/src/views/shop/ShopView.vue | 168 + apps/web/src/views/shop/SubscriptionView.vue | 242 + apps/web/tsconfig.json | 50 + apps/web/vite.config.ts | 136 + dl | 47 +- src/docker-compose.yml => docker-compose.yml | 0 docs/02_design/html-prototypes/README.md | 196 + .../html-prototypes/assets/style.css | 300 + docs/02_design/html-prototypes/index.html | 150 + .../html-prototypes/pages/dashboard.html | 945 ++ .../html-prototypes/pages/dialogue.html | 1035 ++ .../02_design/html-prototypes/pages/home.html | 736 + .../html-prototypes/pages/login.html | 496 + .../html-prototypes/pages/profile.html | 1102 ++ .../html-prototypes/pages/progress.html | 1248 ++ .../html-prototypes/pages/pronunciation.html | 1161 ++ .../html-prototypes/pages/register.html | 587 + .../pages/roleplay-result.html | 888 + .../html-prototypes/pages/roleplay-room.html | 1142 ++ .../html-prototypes/pages/roleplay.html | 1306 ++ .../html-prototypes/pages/settings.html | 1440 ++ .../html-prototypes/pages/subscription.html | 1234 ++ .../html-prototypes/pages/vocabulary.html | 1683 ++ .../{ => 01_architecture}/database-schema.md | 0 .../system-integration.md} | 0 .../tech-stack-decision.md | 0 docs/04_technical/{api => 02_api}/README.md | 0 .../{ => 02_api}/api-specifications.md | 0 .../{api => 02_api}/authentication.md | 0 docs/04_technical/{api => 02_api}/common.md | 0 .../{api => 02_api}/daily-missions.md | 0 .../{api => 02_api}/dialogue-practice.md | 0 docs/04_technical/{api => 02_api}/errors.md | 0 .../{api => 02_api}/gamification.md | 0 .../{api => 02_api}/language-levels.md | 0 .../{api => 02_api}/learning-content.md | 0 .../{api => 02_api}/subscription.md | 0 .../{api => 02_api}/user-management.md | 0 .../{api => 02_api}/vocabulary.md | 0 .../03_frontend/vue-development-standards.md | 1391 ++ .../03_frontend/vue-frontend-architecture.md | 1114 ++ .../03_frontend/vue-project-structure.md | 857 + .../03_frontend/vue-tools-configuration.md | 941 ++ .../low-budget-deployment.md | 0 .../environment/README.md | 0 .../environment/xcode_setup_guide.md | 0 .../file-organization-strategy.md | 0 .../{ => 06_development}/issues-tracking.md | 0 .../user-flow-specification.md | 0 .../api-specifications-completion-plan.md | 0 .../quick-consistency-check.md | 0 docs/04_technical/README.md | 177 + .../user-flow-specification-old.md | 0 docs/api/README.md | 44 + swagger-ui.html => docs/api/swagger-ui.html | 0 projects/learning-loop-system.md | 106 + .../todo => projects}/ui-design-tasks.md | 0 projects/voice-correction-system.md | 129 + .../2025-09-09/221939_TASK_MANAGEMENT_OLD.md | 326 + sop/archive/2025-09-09/222200_目標位置 | 0 .../archive/2025-09-09/224430_CLAUDE.md | 129 +- .../225744_claude-md-issues-analysis.md | 136 + .../225944_reports_archive}/README.md | 0 .../2025-09-07_UI-consistency-analysis.md | 0 ...-09-07_UI-design-gaps-severity-analysis.md | 0 ...2025-09-08_02design規格寫法改進需求分析.md | 0 ...sistency-check-mechanism-quality-review.md | 0 ...25-09-08_UI-consistency-check-mechanism.md | 0 ...-08_UI-naming-consistency-check-results.md | 0 ...uirements-vs-founding-pitch-consistency.md | 0 .../2025-09-08_ui-inconsistency-correction.md | 0 ...cabulary-learning-level-system-analysis.md | 0 .../analysis/INTEGRATION_GUIDE.md | 232 + .../225944_reports_archive/archive/ISSUES.md | 18 + .../archive/PROJECTS.md | 0 ...-09-08_user-flow-ui-components-decision.md | 0 .../templates/analysis-template.md | 0 .../templates/decision-template.md | 0 .../2025-09-09/231443_mobile_app_project.md | 0 .../2025-09-09/231644_basic_project.md | 0 .../archive/2025-09-09/234848_README.md | 0 sop/docs/CLAUDE.md | 550 + sop/scripts/archive_file.sh | 48 + .../document-consistency-checklist.md | 0 sop/scripts/file_version_manager.sh | 174 + .../scripts}/maintenance/check_consistency.sh | 0 .../scripts}/maintenance/check_doc_quality.sh | 0 .../scripts}/maintenance/check_issues.sh | 0 .../scripts}/maintenance/check_security.sh | 0 .../scripts}/maintenance/create_issue.sh | 0 .../scripts}/maintenance_manager.sh | 0 .../reports/issues_20250908_003117.txt | 0 sop/scripts/view_archives.sh | 43 + {tools => sop/tools}/check_compliance.sh | 0 {tools => sop/tools}/check_issues.sh | 0 {tools => sop/tools}/check_reports.sh | 0 {tools => sop/tools}/create_report.sh | 0 .../android/android_setup_verification.sh | 0 .../android/emulator_setup_guide.md | 0 .../environment/android/manual_sdk_setup.sh | 0 .../environment/xcode/complete_xcode_setup.sh | 0 .../xcode/monitor_xcode_installation.sh | 0 .../environment/xcode/setup_instructions.md | 0 .../environment/xcode/xcode_verification.sh | 0 {tools => sop/tools}/issue.sh | 0 {tools => sop/tools}/organize_file.sh | 0 {tools => sop/tools}/phase.sh | 0 {tools => sop/tools}/project.sh | 0 {tools => sop/tools}/setup_aliases.sh | 0 src/mobile/README.md | 16 - 266 files changed, 44402 insertions(+), 41 deletions(-) create mode 100644 TASKS.md create mode 100644 apps/README.md rename {src => apps}/backend/DramaLing.API/Controllers/HealthController.cs (100%) rename {src => apps}/backend/DramaLing.API/Dockerfile.dev (100%) rename {src => apps}/backend/DramaLing.API/DramaLing.API.csproj (100%) rename {src => apps}/backend/DramaLing.API/Program.cs (100%) rename {src => apps}/backend/DramaLing.API/appsettings.Development.json (100%) rename {src => apps}/backend/DramaLing.API/appsettings.json (100%) rename {src => apps}/backend/DramaLing.Application/DependencyInjection.cs (100%) rename {src => apps}/backend/DramaLing.Application/DramaLing.Application.csproj (100%) rename {src => apps}/backend/DramaLing.Core/DramaLing.Core.csproj (100%) rename {src => apps}/backend/DramaLing.Core/Entities/BaseEntity.cs (100%) rename {src => apps}/backend/DramaLing.Core/Entities/Gamification.cs (100%) rename {src => apps}/backend/DramaLing.Core/Entities/LearningStage.cs (100%) rename {src => apps}/backend/DramaLing.Core/Entities/User.cs (100%) rename {src => apps}/backend/DramaLing.Core/Enums/LearningStage.cs (100%) rename {src => apps}/backend/DramaLing.Infrastructure/Data/ApplicationDbContext.cs (100%) rename {src => apps}/backend/DramaLing.Infrastructure/DependencyInjection.cs (100%) rename {src => apps}/backend/DramaLing.Infrastructure/DramaLing.Infrastructure.csproj (100%) rename {src => apps}/backend/DramaLing.sln (100%) create mode 100644 apps/backend/README.md rename {src => apps}/mobile/.gitignore (100%) rename {src => apps}/mobile/.metadata (100%) create mode 100644 apps/mobile/README.md rename {src => apps}/mobile/analysis_options.yaml (100%) rename {src => apps}/mobile/android/.gitignore (100%) rename {src => apps}/mobile/android/app/build.gradle.kts (100%) rename {src => apps}/mobile/android/app/proguard-rules.pro (100%) rename {src => apps}/mobile/android/app/src/main/AndroidManifest.xml (100%) rename {src => apps}/mobile/android/app/src/main/kotlin/com/dramaling/app/MainActivity.kt (100%) rename {src => apps}/mobile/android/app/src/main/res/drawable-v21/launch_background.xml (100%) rename {src => apps}/mobile/android/app/src/main/res/drawable/launch_background.xml (100%) rename {src => apps}/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename {src => apps}/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename {src => apps}/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename {src => apps}/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename {src => apps}/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename {src => apps}/mobile/android/app/src/main/res/values-night/styles.xml (100%) rename {src => apps}/mobile/android/app/src/main/res/values/styles.xml (100%) rename {src => apps}/mobile/android/build.gradle.kts (100%) rename {src => apps}/mobile/android/gradle.properties (100%) rename {src => apps}/mobile/android/gradle/wrapper/gradle-wrapper.properties (100%) rename {src => apps}/mobile/android/settings.gradle.kts (100%) rename {src => apps}/mobile/ios/.gitignore (100%) rename {src => apps}/mobile/ios/Flutter/AppFrameworkInfo.plist (100%) rename {src => apps}/mobile/ios/Flutter/Debug.xcconfig (100%) rename {src => apps}/mobile/ios/Flutter/Release.xcconfig (100%) rename {src => apps}/mobile/ios/Podfile (100%) rename {src => apps}/mobile/ios/Podfile.lock (100%) rename {src => apps}/mobile/ios/Runner.xcodeproj/project.pbxproj (100%) rename {src => apps}/mobile/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename {src => apps}/mobile/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {src => apps}/mobile/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename {src => apps}/mobile/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (100%) rename {src => apps}/mobile/ios/Runner.xcworkspace/contents.xcworkspacedata (100%) rename {src => apps}/mobile/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {src => apps}/mobile/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename {src => apps}/mobile/ios/Runner/AppDelegate.swift (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png (100%) rename {src => apps}/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md (100%) rename {src => apps}/mobile/ios/Runner/Base.lproj/LaunchScreen.storyboard (100%) rename {src => apps}/mobile/ios/Runner/Base.lproj/Main.storyboard (100%) rename {src => apps}/mobile/ios/Runner/Info.plist (100%) rename {src => apps}/mobile/ios/Runner/Runner-Bridging-Header.h (100%) rename {src => apps}/mobile/ios/RunnerTests/RunnerTests.swift (100%) rename {src => apps}/mobile/lib/core/constants/app_constants.dart (100%) rename {src => apps}/mobile/lib/core/services/storage_service.dart (100%) rename {src => apps}/mobile/lib/core/services/voice_recognition_service.dart (100%) rename {src => apps}/mobile/lib/core/utils/app_router.dart (100%) rename {src => apps}/mobile/lib/core/utils/app_theme.dart (100%) rename {src => apps}/mobile/lib/features/auth/screens/login_screen.dart (100%) rename {src => apps}/mobile/lib/features/auth/screens/register_screen.dart (100%) rename {src => apps}/mobile/lib/features/dialogue/models/dialogue_models.dart (100%) rename {src => apps}/mobile/lib/features/dialogue/providers/dialogue_provider.dart (100%) rename {src => apps}/mobile/lib/features/dialogue/screens/dialogue_main_screen.dart (100%) rename {src => apps}/mobile/lib/features/dialogue/services/dialogue_service.dart (100%) rename {src => apps}/mobile/lib/features/dialogue/widgets/character_avatar.dart (100%) rename {src => apps}/mobile/lib/features/dialogue/widgets/dialogue_background.dart (100%) rename {src => apps}/mobile/lib/features/dialogue/widgets/dialogue_bubble.dart (100%) rename {src => apps}/mobile/lib/features/dialogue/widgets/reply_assistance_panel.dart (100%) rename {src => apps}/mobile/lib/features/dialogue/widgets/task_display_panel.dart (100%) rename {src => apps}/mobile/lib/features/dialogue/widgets/vocabulary_panel.dart (100%) rename {src => apps}/mobile/lib/features/learning/screens/home_screen.dart (100%) rename {src => apps}/mobile/lib/main.dart (100%) rename {src => apps}/mobile/lib/shared/providers/auth_provider.dart (100%) rename {src => apps}/mobile/lib/shared/providers/voice_recognition_provider.dart (100%) rename {src => apps}/mobile/lib/shared/widgets/voice_input_button.dart (100%) rename {src => apps}/mobile/pubspec.lock (100%) rename {src => apps}/mobile/pubspec.yaml (100%) rename {src => apps}/mobile/test/widget_test.dart (100%) rename {src => apps}/mobile/web/favicon.png (100%) rename {src => apps}/mobile/web/index.html (100%) rename {src => apps}/mobile/web/manifest.json (100%) create mode 100644 apps/web/.eslintrc.js create mode 100644 apps/web/.prettierrc create mode 100644 apps/web/auto-imports.d.ts create mode 100644 apps/web/components.d.ts create mode 100644 apps/web/index.html create mode 100644 apps/web/package-lock.json create mode 100644 apps/web/package.json create mode 100644 apps/web/src/App.vue create mode 100644 apps/web/src/assets/styles/main.scss create mode 100644 apps/web/src/assets/styles/quasar-variables.sass create mode 100644 apps/web/src/assets/styles/variables.scss create mode 100644 apps/web/src/components/base/BaseButton.vue create mode 100644 apps/web/src/components/base/BaseCard.vue create mode 100644 apps/web/src/components/base/BaseInput.vue create mode 100644 apps/web/src/components/base/BaseModal.vue create mode 100644 apps/web/src/components/ui/ModalContainer.vue create mode 100644 apps/web/src/components/ui/ToastContainer.vue create mode 100644 apps/web/src/layouts/AppLayout.vue create mode 100644 apps/web/src/layouts/AuthLayout.vue create mode 100644 apps/web/src/main.ts create mode 100644 apps/web/src/router/index-full.ts create mode 100644 apps/web/src/router/index-minimal.ts create mode 100644 apps/web/src/router/index.ts create mode 100644 apps/web/src/stores/auth.ts create mode 100644 apps/web/src/stores/index.ts create mode 100644 apps/web/src/stores/learning.ts create mode 100644 apps/web/src/stores/ui.ts create mode 100644 apps/web/src/stores/user.ts create mode 100644 apps/web/src/types/learning.ts create mode 100644 apps/web/src/types/user.ts create mode 100644 apps/web/src/utils/index.ts create mode 100644 apps/web/src/views/HomeView.vue create mode 100644 apps/web/src/views/NotFoundView.vue create mode 100644 apps/web/src/views/OfflineView.vue create mode 100644 apps/web/src/views/auth/ForgotPasswordView.vue create mode 100644 apps/web/src/views/auth/LoginView.vue create mode 100644 apps/web/src/views/auth/RegisterView-orig.vue create mode 100644 apps/web/src/views/auth/RegisterView.vue create mode 100644 apps/web/src/views/learning/DialogueView.vue create mode 100644 apps/web/src/views/learning/LearningHomeView.vue create mode 100644 apps/web/src/views/learning/PronunciationView.vue create mode 100644 apps/web/src/views/learning/RoleplayView.vue create mode 100644 apps/web/src/views/learning/VocabularyView.vue create mode 100644 apps/web/src/views/shop/ShopView.vue create mode 100644 apps/web/src/views/shop/SubscriptionView.vue create mode 100644 apps/web/tsconfig.json create mode 100644 apps/web/vite.config.ts rename src/docker-compose.yml => docker-compose.yml (100%) create mode 100644 docs/02_design/html-prototypes/README.md create mode 100644 docs/02_design/html-prototypes/assets/style.css create mode 100644 docs/02_design/html-prototypes/index.html create mode 100644 docs/02_design/html-prototypes/pages/dashboard.html create mode 100644 docs/02_design/html-prototypes/pages/dialogue.html create mode 100644 docs/02_design/html-prototypes/pages/home.html create mode 100644 docs/02_design/html-prototypes/pages/login.html create mode 100644 docs/02_design/html-prototypes/pages/profile.html create mode 100644 docs/02_design/html-prototypes/pages/progress.html create mode 100644 docs/02_design/html-prototypes/pages/pronunciation.html create mode 100644 docs/02_design/html-prototypes/pages/register.html create mode 100644 docs/02_design/html-prototypes/pages/roleplay-result.html create mode 100644 docs/02_design/html-prototypes/pages/roleplay-room.html create mode 100644 docs/02_design/html-prototypes/pages/roleplay.html create mode 100644 docs/02_design/html-prototypes/pages/settings.html create mode 100644 docs/02_design/html-prototypes/pages/subscription.html create mode 100644 docs/02_design/html-prototypes/pages/vocabulary.html rename docs/04_technical/{ => 01_architecture}/database-schema.md (100%) rename docs/04_technical/{flutter-dotnet-integration.md => 01_architecture/system-integration.md} (100%) rename docs/04_technical/{ => 01_architecture}/tech-stack-decision.md (100%) rename docs/04_technical/{api => 02_api}/README.md (100%) rename docs/04_technical/{ => 02_api}/api-specifications.md (100%) rename docs/04_technical/{api => 02_api}/authentication.md (100%) rename docs/04_technical/{api => 02_api}/common.md (100%) rename docs/04_technical/{api => 02_api}/daily-missions.md (100%) rename docs/04_technical/{api => 02_api}/dialogue-practice.md (100%) rename docs/04_technical/{api => 02_api}/errors.md (100%) rename docs/04_technical/{api => 02_api}/gamification.md (100%) rename docs/04_technical/{api => 02_api}/language-levels.md (100%) rename docs/04_technical/{api => 02_api}/learning-content.md (100%) rename docs/04_technical/{api => 02_api}/subscription.md (100%) rename docs/04_technical/{api => 02_api}/user-management.md (100%) rename docs/04_technical/{api => 02_api}/vocabulary.md (100%) create mode 100644 docs/04_technical/03_frontend/vue-development-standards.md create mode 100644 docs/04_technical/03_frontend/vue-frontend-architecture.md create mode 100644 docs/04_technical/03_frontend/vue-project-structure.md create mode 100644 docs/04_technical/03_frontend/vue-tools-configuration.md rename docs/04_technical/{ => 05_deployment}/low-budget-deployment.md (100%) rename docs/04_technical/{ => 06_development}/environment/README.md (100%) rename docs/04_technical/{ => 06_development}/environment/xcode_setup_guide.md (100%) rename docs/04_technical/{ => 06_development}/file-organization-strategy.md (100%) rename docs/04_technical/{ => 06_development}/issues-tracking.md (100%) rename docs/04_technical/{ => 06_development}/user-flow-specification.md (100%) rename docs/04_technical/{plan => 07_planning}/api-specifications-completion-plan.md (100%) rename docs/04_technical/{ => 07_planning}/quick-consistency-check.md (100%) create mode 100644 docs/04_technical/README.md rename docs/04_technical/{ => archive}/user-flow-specification-old.md (100%) create mode 100644 docs/api/README.md rename swagger-ui.html => docs/api/swagger-ui.html (100%) create mode 100644 projects/learning-loop-system.md rename {docs/02_design/todo => projects}/ui-design-tasks.md (100%) create mode 100644 projects/voice-correction-system.md create mode 100644 sop/archive/2025-09-09/221939_TASK_MANAGEMENT_OLD.md create mode 100644 sop/archive/2025-09-09/222200_目標位置 rename CLAUDE.md => sop/archive/2025-09-09/224430_CLAUDE.md (72%) create mode 100644 sop/archive/2025-09-09/225744_claude-md-issues-analysis.md rename {reports => sop/archive/2025-09-09/225944_reports_archive}/README.md (100%) rename {reports => sop/archive/2025-09-09/225944_reports_archive}/analysis/2025-09-07_UI-consistency-analysis.md (100%) rename {reports => sop/archive/2025-09-09/225944_reports_archive}/analysis/2025-09-07_UI-design-gaps-severity-analysis.md (100%) rename {reports => sop/archive/2025-09-09/225944_reports_archive}/analysis/2025-09-08_02design規格寫法改進需求分析.md (100%) rename {reports => sop/archive/2025-09-09/225944_reports_archive}/analysis/2025-09-08_UI-consistency-check-mechanism-quality-review.md (100%) rename {reports => sop/archive/2025-09-09/225944_reports_archive}/analysis/2025-09-08_UI-consistency-check-mechanism.md (100%) rename {reports => sop/archive/2025-09-09/225944_reports_archive}/analysis/2025-09-08_UI-naming-consistency-check-results.md (100%) rename {reports => sop/archive/2025-09-09/225944_reports_archive}/analysis/2025-09-08_requirements-vs-founding-pitch-consistency.md (100%) rename {reports => sop/archive/2025-09-09/225944_reports_archive}/analysis/2025-09-08_ui-inconsistency-correction.md (100%) rename {reports => sop/archive/2025-09-09/225944_reports_archive}/analysis/2025-09-08_vocabulary-learning-level-system-analysis.md (100%) create mode 100644 sop/archive/2025-09-09/225944_reports_archive/analysis/INTEGRATION_GUIDE.md rename ISSUES.md => sop/archive/2025-09-09/225944_reports_archive/archive/ISSUES.md (87%) rename PROJECTS.md => sop/archive/2025-09-09/225944_reports_archive/archive/PROJECTS.md (100%) rename {reports => sop/archive/2025-09-09/225944_reports_archive}/decision/2025-09-08_user-flow-ui-components-decision.md (100%) rename {reports => sop/archive/2025-09-09/225944_reports_archive}/templates/analysis-template.md (100%) rename {reports => sop/archive/2025-09-09/225944_reports_archive}/templates/decision-template.md (100%) rename projects/templates/mobile_app_project.md => sop/archive/2025-09-09/231443_mobile_app_project.md (100%) rename projects/templates/basic_project.md => sop/archive/2025-09-09/231644_basic_project.md (100%) rename src/README.md => sop/archive/2025-09-09/234848_README.md (100%) create mode 100644 sop/docs/CLAUDE.md create mode 100755 sop/scripts/archive_file.sh rename {scripts => sop/scripts}/document-consistency-checklist.md (100%) create mode 100755 sop/scripts/file_version_manager.sh rename {scripts => sop/scripts}/maintenance/check_consistency.sh (100%) rename {scripts => sop/scripts}/maintenance/check_doc_quality.sh (100%) rename {scripts => sop/scripts}/maintenance/check_issues.sh (100%) rename {scripts => sop/scripts}/maintenance/check_security.sh (100%) rename {scripts => sop/scripts}/maintenance/create_issue.sh (100%) rename {scripts => sop/scripts}/maintenance_manager.sh (100%) rename {scripts => sop/scripts}/reports/issues_20250908_003117.txt (100%) create mode 100755 sop/scripts/view_archives.sh rename {tools => sop/tools}/check_compliance.sh (100%) rename {tools => sop/tools}/check_issues.sh (100%) rename {tools => sop/tools}/check_reports.sh (100%) rename {tools => sop/tools}/create_report.sh (100%) rename {tools => sop/tools}/environment/android/android_setup_verification.sh (100%) rename {tools => sop/tools}/environment/android/emulator_setup_guide.md (100%) rename {tools => sop/tools}/environment/android/manual_sdk_setup.sh (100%) rename {tools => sop/tools}/environment/xcode/complete_xcode_setup.sh (100%) rename {tools => sop/tools}/environment/xcode/monitor_xcode_installation.sh (100%) rename {tools => sop/tools}/environment/xcode/setup_instructions.md (100%) rename {tools => sop/tools}/environment/xcode/xcode_verification.sh (100%) rename {tools => sop/tools}/issue.sh (100%) rename {tools => sop/tools}/organize_file.sh (100%) rename {tools => sop/tools}/phase.sh (100%) rename {tools => sop/tools}/project.sh (100%) rename {tools => sop/tools}/setup_aliases.sh (100%) delete mode 100644 src/mobile/README.md diff --git a/.claude/settings.local.json b/.claude/settings.local.json index db68b8f..e1c4a89 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -77,7 +77,21 @@ "Bash(/Users/jettcheng1018/flutter/bin/flutter run -d Medium_Phone_API_36.0)", "Bash(/Users/jettcheng1018/flutter/bin/flutter emulators --launch Medium_Phone_API_36.0)", "Bash(dotnet run:*)", - "Bash(dotnet --version)" + "Bash(dotnet --version)", + "Bash(npm install)", + "Bash(npm install:*)", + "Bash(npm run dev:*)", + "Bash(find:*)", + "Bash(/bashes)", + "Bash(pkill:*)", + "Bash(say:*)", + "Bash(./dl list)", + "Bash(./dl task)", + "Bash(./scripts/file_version_manager.sh:*)", + "Bash(./scripts/archive_file.sh:*)", + "Bash(./scripts/view_archives.sh:*)", + "Bash(tree:*)", + "Bash(./sop/scripts/archive_file.sh:*)" ], "deny": [], "ask": [] diff --git a/TASKS.md b/TASKS.md new file mode 100644 index 0000000..a76e0d0 --- /dev/null +++ b/TASKS.md @@ -0,0 +1,143 @@ +# 🎯 Drama Ling 任務清單 + +## 📋 當前任務 + +### 🔥 緊急任務 +- [ ] 🎨 **語法錯誤訂正頁面** - 完成學習閉環的關鍵頁面 (預估4-6小時) + - 📄 參考: [學習閉環系統](projects/learning-loop-system.md) +- [ ] 🎨 **表達不順訂正頁面** - 語音發音訂正界面 (預估4-6小時) + - 📄 參考: [語音訂正系統](projects/voice-correction-system.md) +- [ ] 💎 **UI_SubscriptionPlans設計** - 訂閱方案選擇頁面,核心商業功能 (預估6-8小時) + - 📄 參考: [UI設計任務清單](projects/ui-design-tasks.md) +- [ ] 💳 **UI_PaymentFlow設計** - 付費流程頁面,提升轉換率 (預估6-8小時) + - 📄 參考: [UI設計任務清單](projects/ui-design-tasks.md) +- [ ] ⏰ **UI_TimedDialogue設計** - 300秒限時挑戰界面 (預估6-8小時) + - 📄 參考: [UI設計任務清單](projects/ui-design-tasks.md) + +### ⚠️ 重要任務 +- [ ] 📊 **資料庫schema設計** - 確定用戶表結構和關聯設計 (預估6-8小時) + - 📄 參考: [資料庫設計專案](projects/database-design-project.md) +- [ ] 🔐 **用戶認證流程細節** - 註冊、登入、權限管理流程 (預估4-6小時) + - 📄 參考: [用戶認證系統](projects/user-auth-system.md) +- [ ] 🏆 **UI_RankingDetail設計** - 排行榜詳情頁面,社群競爭功能 (預估4-6小時) + - 📄 參考: [UI設計任務清單](projects/ui-design-tasks.md) +- [ ] 🎁 **UI_RewardClaim設計** - 獎勵領取頁面,增強成就感 (預估3-4小時) + - 📄 參考: [UI設計任務清單](projects/ui-design-tasks.md) +- [ ] 📋 **UI_BonusMission_Main設計** - 每日任務主頁,提升活躍度 (預估4-6小時) + - 📄 參考: [UI設計任務清單](projects/ui-design-tasks.md) + +### 📝 一般任務 +- [ ] 🎨 **文字輸入彈窗界面** - 替換prompt()的完整UI (預估2-3小時) + - 📄 參考: [UI組件系統](projects/ui-component-system.md) +- [ ] 🔗 **頁面導航連接** - 完善用戶流程導航 (預估2-4小時) + - 📄 參考: [導航系統](projects/navigation-system.md) +- [ ] 🛠️ **特殊情況處理** - 錯誤狀態處理機制 (預估3-4小時) + - 📄 參考: [錯誤處理系統](projects/error-handling-system.md) +- [ ] 📚 **文檔格式統一** - 統一所有文檔格式規範 (預估2-3小時) + - 📄 參考: [文檔規範](projects/documentation-standards.md) +- [ ] 🏷️ **UI組件命名規範** - 建立統一命名標準 (預估1-2小時) + - 📄 參考: [命名規範系統](projects/naming-convention-system.md) +- [ ] 📚 **UI_ReviewCards設計** - 間隔複習卡片界面 (預估4-5小時) + - 📄 參考: [UI設計任務清單](projects/ui-design-tasks.md) +- [ ] 📊 **UI_ReviewProgress設計** - 複習進度統計頁面 (預估3-4小時) + - 📄 參考: [UI設計任務清單](projects/ui-design-tasks.md) +- [ ] 📅 **UI_ReviewSchedule設計** - 個人化複習排程頁面 (預估3-4小時) + - 📄 參考: [UI設計任務清單](projects/ui-design-tasks.md) +- [ ] 🏅 **UI_BadgeCollection設計** - 學習成就徽章收藏頁面 (預估3-4小時) + - 📄 參考: [UI設計任務清單](projects/ui-design-tasks.md) +- [ ] 💰 **UI_PurchasedContent設計** - 已購買內容管理頁面 (預估3-4小時) + - 📄 參考: [UI設計任務清單](projects/ui-design-tasks.md) +- [ ] 📺 **UI_AdOffer設計** - 廣告獎勵邀請頁面 (預估2-3小時) + - 📄 參考: [UI設計任務清單](projects/ui-design-tasks.md) +- [ ] 🎬 **UI_AdViewing設計** - 廣告觀看過程界面 (預估2-3小時) + - 📄 參考: [UI設計任務清單](projects/ui-design-tasks.md) + +### 💡 未來想法 +- [ ] 🔍 **UI功能重複評估** - 分析Result相關UI合併可能性 +- [ ] 🎨 **應用圖標和啟動畫面** - 品牌視覺設計 +- [ ] ❌ **錯誤處理UI組** - 錯誤、載入、網路異常、維護公告頁面 (預估6-8小時) + - 📄 參考: [UI設計任務清單](projects/ui-design-tasks.md) +- [ ] 🎨 **UI設計一致性檢查** - 17個新UI與71個現有UI的統一性檢查 (預估4-6小時) + - 📄 參考: [UI設計任務清單](projects/ui-design-tasks.md) + +--- + +## 📊 快速統計 + +**當前狀態**: +- 🔥 緊急: 5個任務 (+3個UI設計) +- ⚠️ 重要: 5個任務 (+3個UI設計) +- 📝 一般: 12個任務 (+7個UI設計) +- 💡 想法: 4個任務 (+2個UI設計) + +**預估工作量**: 總計 98-132 小時 (包含17個UI設計任務) + +--- + +## 📚 已完成任務 (最近10個) + +### 2025-09-09 完成 +- [x] ✅ **CLAUDE.md文檔修正** - 修正章節重複、日期過時等結構性問題 ✅ (2025-09-09) + - 📄 專案文檔: [CLAUDE.md問題分析](archive/2025-09-09/225744_claude-md-issues-analysis.md) + - 🔧 解決內容: 章節編號重複、日期過時、工作流程不一致、檔案參考錯誤、問題管理流程混淆 +- [x] ✅ **API文檔系統重組** - 移動swagger-ui.html到docs/api/ (已完成) +- [x] ✅ **專案管理系統整合** - 完成三層架構設計 (已完成) +- [x] ✅ **情境學習界面實現** - 完成vocabulary.html的情境學習功能 (已完成) + +### 2025-09-08 完成 +- [x] ✅ **02_design規格完善** - 建立5個核心功能詳細規格文檔 (已完成) +- [x] ✅ **API模組化文檔** - 完成7個API模組建立 (已完成) +- [x] ✅ **UI設計缺漏修復** - 100%完成40個缺失UI設計 (已完成) +- [x] ✅ **系統整合指南** - 完成INTEGRATION_GUIDE.md (已完成) +- [x] ✅ **工具系統更新** - ./dl命令支援新任務管理系統 (已完成) +- [x] ✅ **CLAUDE工作指南更新** - 整合協作標準和通知系統 (已完成) +- [x] ✅ **問題追蹤系統建立** - ISSUES.md完整問題管理機制 (已完成) + +--- + +## 🛠️ 系統使用指南 + +### 查看任務 +```bash +./dl task # 打開此任務管理文件 +./dl status # 查看任務統計 +./dl list # 快速查看待辦清單 +``` + +### 工作模式 +1. **討論階段**: 與Claude自由討論需求和想法 +2. **記錄階段**: Claude自動記錄任務到此系統,並創建對應專案詳細文檔 +3. **執行階段**: 查看此文件選擇任務批量執行 +4. **完成階段**: 標記任務完成 [x],任務自動移至已完成區域 + +### 任務格式說明 +```markdown +- [ ] 🎯 **任務名稱** - 簡短描述 (預估時間) + - 📄 參考: [專案詳細文檔](projects/project-name.md) +``` + +--- + +**建立日期**: 2025-09-09 +**最後更新**: 2025-09-09 (整合UI設計任務) +**維護者**: Claude Code & Drama Ling Team + +--- + +## 🎨 UI設計專案說明 + +本任務清單已整合 `projects/ui-design-tasks.md` 中的17個UI設計任務,分佈如下: + +### 🔥 第一優先級 - 核心商業功能 (3個) +- UI_SubscriptionPlans, UI_PaymentFlow, UI_TimedDialogue + +### ⚠️ 第二優先級 - 學習體驗增強 (3個) +- UI_RankingDetail, UI_RewardClaim, UI_BonusMission_Main + +### 📝 第三優先級 - 學習功能完善 (7個) +- UI_ReviewCards, UI_ReviewProgress, UI_ReviewSchedule, UI_BadgeCollection, UI_PurchasedContent, UI_AdOffer, UI_AdViewing + +### 💡 第四優先級 - 輔助功能 (4個) +- 錯誤處理UI組, UI設計一致性檢查 + +**設計目標**: 完成剩餘17個UI介面,從71/88 (81%) 達成100%完整覆蓋 \ No newline at end of file diff --git a/apps/README.md b/apps/README.md new file mode 100644 index 0000000..e1431d8 --- /dev/null +++ b/apps/README.md @@ -0,0 +1,27 @@ +# Drama Ling Applications + +本目錄包含 Drama Ling 專案的所有應用程式。 + +## 應用程式架構 + +``` +apps/ +├── web/ # Vue.js Web 前端應用 +├── mobile/ # Flutter 移動端應用 +└── backend/ # .NET Core 後端 API +``` + +## 開發狀態 + +| 應用程式 | 狀態 | 技術棧 | 說明 | +|---------|------|--------|------| +| Web | ✅ 開發中 | Vue.js + Quasar | Web 前端界面 | +| Mobile | ✅ 開發中 | Flutter + Riverpod | 跨平台移動應用 | +| Backend | ✅ 開發中 | .NET Core + EF Core | REST API 服務 | + +## 開發指南 + +各應用程式的詳細開發文檔請參考: +- 技術文檔:`../docs/04_technical/` +- 專案規格:`../projects/` +- 任務管理:`../TASKS.md` \ No newline at end of file diff --git a/src/backend/DramaLing.API/Controllers/HealthController.cs b/apps/backend/DramaLing.API/Controllers/HealthController.cs similarity index 100% rename from src/backend/DramaLing.API/Controllers/HealthController.cs rename to apps/backend/DramaLing.API/Controllers/HealthController.cs diff --git a/src/backend/DramaLing.API/Dockerfile.dev b/apps/backend/DramaLing.API/Dockerfile.dev similarity index 100% rename from src/backend/DramaLing.API/Dockerfile.dev rename to apps/backend/DramaLing.API/Dockerfile.dev diff --git a/src/backend/DramaLing.API/DramaLing.API.csproj b/apps/backend/DramaLing.API/DramaLing.API.csproj similarity index 100% rename from src/backend/DramaLing.API/DramaLing.API.csproj rename to apps/backend/DramaLing.API/DramaLing.API.csproj diff --git a/src/backend/DramaLing.API/Program.cs b/apps/backend/DramaLing.API/Program.cs similarity index 100% rename from src/backend/DramaLing.API/Program.cs rename to apps/backend/DramaLing.API/Program.cs diff --git a/src/backend/DramaLing.API/appsettings.Development.json b/apps/backend/DramaLing.API/appsettings.Development.json similarity index 100% rename from src/backend/DramaLing.API/appsettings.Development.json rename to apps/backend/DramaLing.API/appsettings.Development.json diff --git a/src/backend/DramaLing.API/appsettings.json b/apps/backend/DramaLing.API/appsettings.json similarity index 100% rename from src/backend/DramaLing.API/appsettings.json rename to apps/backend/DramaLing.API/appsettings.json diff --git a/src/backend/DramaLing.Application/DependencyInjection.cs b/apps/backend/DramaLing.Application/DependencyInjection.cs similarity index 100% rename from src/backend/DramaLing.Application/DependencyInjection.cs rename to apps/backend/DramaLing.Application/DependencyInjection.cs diff --git a/src/backend/DramaLing.Application/DramaLing.Application.csproj b/apps/backend/DramaLing.Application/DramaLing.Application.csproj similarity index 100% rename from src/backend/DramaLing.Application/DramaLing.Application.csproj rename to apps/backend/DramaLing.Application/DramaLing.Application.csproj diff --git a/src/backend/DramaLing.Core/DramaLing.Core.csproj b/apps/backend/DramaLing.Core/DramaLing.Core.csproj similarity index 100% rename from src/backend/DramaLing.Core/DramaLing.Core.csproj rename to apps/backend/DramaLing.Core/DramaLing.Core.csproj diff --git a/src/backend/DramaLing.Core/Entities/BaseEntity.cs b/apps/backend/DramaLing.Core/Entities/BaseEntity.cs similarity index 100% rename from src/backend/DramaLing.Core/Entities/BaseEntity.cs rename to apps/backend/DramaLing.Core/Entities/BaseEntity.cs diff --git a/src/backend/DramaLing.Core/Entities/Gamification.cs b/apps/backend/DramaLing.Core/Entities/Gamification.cs similarity index 100% rename from src/backend/DramaLing.Core/Entities/Gamification.cs rename to apps/backend/DramaLing.Core/Entities/Gamification.cs diff --git a/src/backend/DramaLing.Core/Entities/LearningStage.cs b/apps/backend/DramaLing.Core/Entities/LearningStage.cs similarity index 100% rename from src/backend/DramaLing.Core/Entities/LearningStage.cs rename to apps/backend/DramaLing.Core/Entities/LearningStage.cs diff --git a/src/backend/DramaLing.Core/Entities/User.cs b/apps/backend/DramaLing.Core/Entities/User.cs similarity index 100% rename from src/backend/DramaLing.Core/Entities/User.cs rename to apps/backend/DramaLing.Core/Entities/User.cs diff --git a/src/backend/DramaLing.Core/Enums/LearningStage.cs b/apps/backend/DramaLing.Core/Enums/LearningStage.cs similarity index 100% rename from src/backend/DramaLing.Core/Enums/LearningStage.cs rename to apps/backend/DramaLing.Core/Enums/LearningStage.cs diff --git a/src/backend/DramaLing.Infrastructure/Data/ApplicationDbContext.cs b/apps/backend/DramaLing.Infrastructure/Data/ApplicationDbContext.cs similarity index 100% rename from src/backend/DramaLing.Infrastructure/Data/ApplicationDbContext.cs rename to apps/backend/DramaLing.Infrastructure/Data/ApplicationDbContext.cs diff --git a/src/backend/DramaLing.Infrastructure/DependencyInjection.cs b/apps/backend/DramaLing.Infrastructure/DependencyInjection.cs similarity index 100% rename from src/backend/DramaLing.Infrastructure/DependencyInjection.cs rename to apps/backend/DramaLing.Infrastructure/DependencyInjection.cs diff --git a/src/backend/DramaLing.Infrastructure/DramaLing.Infrastructure.csproj b/apps/backend/DramaLing.Infrastructure/DramaLing.Infrastructure.csproj similarity index 100% rename from src/backend/DramaLing.Infrastructure/DramaLing.Infrastructure.csproj rename to apps/backend/DramaLing.Infrastructure/DramaLing.Infrastructure.csproj diff --git a/src/backend/DramaLing.sln b/apps/backend/DramaLing.sln similarity index 100% rename from src/backend/DramaLing.sln rename to apps/backend/DramaLing.sln diff --git a/apps/backend/README.md b/apps/backend/README.md new file mode 100644 index 0000000..bcb752f --- /dev/null +++ b/apps/backend/README.md @@ -0,0 +1,45 @@ +# Drama Ling Backend API + +.NET Core 後端 API 服務 + +## 技術棧 +- **.NET 8**: 跨平台框架 +- **ASP.NET Core Web API**: RESTful API +- **Entity Framework Core**: ORM 資料庫存取 +- **PostgreSQL**: 主要資料庫 +- **Redis**: 快取和會話管理 +- **JWT**: 身份驗證 + +## 專案結構 +``` +backend/ +├── DramaLing.API/ # Web API 專案 +├── DramaLing.Application/ # 應用服務層 +├── DramaLing.Core/ # 領域模型層 +├── DramaLing.Infrastructure/ # 基礎設施層 +├── DramaLing.Tests/ # 測試專案 +└── DramaLing.sln # 解決方案檔 +``` + +## 快速開始 + +### 1. 安裝相依套件 +```bash +dotnet restore +``` + +### 2. 設定資料庫 +```bash +# 建立資料庫 +dotnet ef database update --project DramaLing.Infrastructure --startup-project DramaLing.API +``` + +### 3. 啟動開發服務器 +```bash +dotnet run --project DramaLing.API +# API: http://localhost:5000 +# Swagger: http://localhost:5000 +``` + +## 開發指南 +詳細開發文檔請參考:`../../docs/04_technical/` \ No newline at end of file diff --git a/src/mobile/.gitignore b/apps/mobile/.gitignore similarity index 100% rename from src/mobile/.gitignore rename to apps/mobile/.gitignore diff --git a/src/mobile/.metadata b/apps/mobile/.metadata similarity index 100% rename from src/mobile/.metadata rename to apps/mobile/.metadata diff --git a/apps/mobile/README.md b/apps/mobile/README.md new file mode 100644 index 0000000..f03e6ce --- /dev/null +++ b/apps/mobile/README.md @@ -0,0 +1,43 @@ +# Drama Ling Mobile App + +Flutter 移動端應用程式 + +## 技術棧 +- **Flutter 3.16+**: 跨平台框架 +- **Dart 3.0+**: 程式語言 +- **Riverpod**: 狀態管理 +- **Go Router**: 導航路由 +- **Dio + Retrofit**: HTTP 客戶端 +- **Hive**: 本地資料存儲 +- **Material 3**: UI 設計系統 + +## 專案結構 +``` +mobile/ +├── lib/ +│ ├── core/ # 核心功能 (常數、工具、服務) +│ ├── features/ # 功能模組 (認證、學習、對話等) +│ └── shared/ # 共用組件 (Widget、模型、Provider) +└── pubspec.yaml # Flutter 專案配置 +``` + +## 快速開始 + +### 1. 安裝相依套件 +```bash +flutter pub get +``` + +### 2. 程式碼生成 +```bash +dart run build_runner build +``` + +### 3. 啟動應用 +```bash +flutter run +# 需要模擬器或實體裝置 +``` + +## 開發指南 +詳細開發文檔請參考:`../../docs/04_technical/` \ No newline at end of file diff --git a/src/mobile/analysis_options.yaml b/apps/mobile/analysis_options.yaml similarity index 100% rename from src/mobile/analysis_options.yaml rename to apps/mobile/analysis_options.yaml diff --git a/src/mobile/android/.gitignore b/apps/mobile/android/.gitignore similarity index 100% rename from src/mobile/android/.gitignore rename to apps/mobile/android/.gitignore diff --git a/src/mobile/android/app/build.gradle.kts b/apps/mobile/android/app/build.gradle.kts similarity index 100% rename from src/mobile/android/app/build.gradle.kts rename to apps/mobile/android/app/build.gradle.kts diff --git a/src/mobile/android/app/proguard-rules.pro b/apps/mobile/android/app/proguard-rules.pro similarity index 100% rename from src/mobile/android/app/proguard-rules.pro rename to apps/mobile/android/app/proguard-rules.pro diff --git a/src/mobile/android/app/src/main/AndroidManifest.xml b/apps/mobile/android/app/src/main/AndroidManifest.xml similarity index 100% rename from src/mobile/android/app/src/main/AndroidManifest.xml rename to apps/mobile/android/app/src/main/AndroidManifest.xml diff --git a/src/mobile/android/app/src/main/kotlin/com/dramaling/app/MainActivity.kt b/apps/mobile/android/app/src/main/kotlin/com/dramaling/app/MainActivity.kt similarity index 100% rename from src/mobile/android/app/src/main/kotlin/com/dramaling/app/MainActivity.kt rename to apps/mobile/android/app/src/main/kotlin/com/dramaling/app/MainActivity.kt diff --git a/src/mobile/android/app/src/main/res/drawable-v21/launch_background.xml b/apps/mobile/android/app/src/main/res/drawable-v21/launch_background.xml similarity index 100% rename from src/mobile/android/app/src/main/res/drawable-v21/launch_background.xml rename to apps/mobile/android/app/src/main/res/drawable-v21/launch_background.xml diff --git a/src/mobile/android/app/src/main/res/drawable/launch_background.xml b/apps/mobile/android/app/src/main/res/drawable/launch_background.xml similarity index 100% rename from src/mobile/android/app/src/main/res/drawable/launch_background.xml rename to apps/mobile/android/app/src/main/res/drawable/launch_background.xml diff --git a/src/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/apps/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from src/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to apps/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/src/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/apps/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from src/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to apps/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/src/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/apps/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from src/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to apps/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/src/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/apps/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from src/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to apps/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/src/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/apps/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from src/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to apps/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/src/mobile/android/app/src/main/res/values-night/styles.xml b/apps/mobile/android/app/src/main/res/values-night/styles.xml similarity index 100% rename from src/mobile/android/app/src/main/res/values-night/styles.xml rename to apps/mobile/android/app/src/main/res/values-night/styles.xml diff --git a/src/mobile/android/app/src/main/res/values/styles.xml b/apps/mobile/android/app/src/main/res/values/styles.xml similarity index 100% rename from src/mobile/android/app/src/main/res/values/styles.xml rename to apps/mobile/android/app/src/main/res/values/styles.xml diff --git a/src/mobile/android/build.gradle.kts b/apps/mobile/android/build.gradle.kts similarity index 100% rename from src/mobile/android/build.gradle.kts rename to apps/mobile/android/build.gradle.kts diff --git a/src/mobile/android/gradle.properties b/apps/mobile/android/gradle.properties similarity index 100% rename from src/mobile/android/gradle.properties rename to apps/mobile/android/gradle.properties diff --git a/src/mobile/android/gradle/wrapper/gradle-wrapper.properties b/apps/mobile/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from src/mobile/android/gradle/wrapper/gradle-wrapper.properties rename to apps/mobile/android/gradle/wrapper/gradle-wrapper.properties diff --git a/src/mobile/android/settings.gradle.kts b/apps/mobile/android/settings.gradle.kts similarity index 100% rename from src/mobile/android/settings.gradle.kts rename to apps/mobile/android/settings.gradle.kts diff --git a/src/mobile/ios/.gitignore b/apps/mobile/ios/.gitignore similarity index 100% rename from src/mobile/ios/.gitignore rename to apps/mobile/ios/.gitignore diff --git a/src/mobile/ios/Flutter/AppFrameworkInfo.plist b/apps/mobile/ios/Flutter/AppFrameworkInfo.plist similarity index 100% rename from src/mobile/ios/Flutter/AppFrameworkInfo.plist rename to apps/mobile/ios/Flutter/AppFrameworkInfo.plist diff --git a/src/mobile/ios/Flutter/Debug.xcconfig b/apps/mobile/ios/Flutter/Debug.xcconfig similarity index 100% rename from src/mobile/ios/Flutter/Debug.xcconfig rename to apps/mobile/ios/Flutter/Debug.xcconfig diff --git a/src/mobile/ios/Flutter/Release.xcconfig b/apps/mobile/ios/Flutter/Release.xcconfig similarity index 100% rename from src/mobile/ios/Flutter/Release.xcconfig rename to apps/mobile/ios/Flutter/Release.xcconfig diff --git a/src/mobile/ios/Podfile b/apps/mobile/ios/Podfile similarity index 100% rename from src/mobile/ios/Podfile rename to apps/mobile/ios/Podfile diff --git a/src/mobile/ios/Podfile.lock b/apps/mobile/ios/Podfile.lock similarity index 100% rename from src/mobile/ios/Podfile.lock rename to apps/mobile/ios/Podfile.lock diff --git a/src/mobile/ios/Runner.xcodeproj/project.pbxproj b/apps/mobile/ios/Runner.xcodeproj/project.pbxproj similarity index 100% rename from src/mobile/ios/Runner.xcodeproj/project.pbxproj rename to apps/mobile/ios/Runner.xcodeproj/project.pbxproj diff --git a/src/mobile/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/apps/mobile/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from src/mobile/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to apps/mobile/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/src/mobile/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/mobile/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from src/mobile/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to apps/mobile/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/src/mobile/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/apps/mobile/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from src/mobile/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to apps/mobile/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/src/mobile/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/apps/mobile/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from src/mobile/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to apps/mobile/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/src/mobile/ios/Runner.xcworkspace/contents.xcworkspacedata b/apps/mobile/ios/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from src/mobile/ios/Runner.xcworkspace/contents.xcworkspacedata rename to apps/mobile/ios/Runner.xcworkspace/contents.xcworkspacedata diff --git a/src/mobile/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/mobile/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from src/mobile/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to apps/mobile/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/src/mobile/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/apps/mobile/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from src/mobile/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to apps/mobile/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/src/mobile/ios/Runner/AppDelegate.swift b/apps/mobile/ios/Runner/AppDelegate.swift similarity index 100% rename from src/mobile/ios/Runner/AppDelegate.swift rename to apps/mobile/ios/Runner/AppDelegate.swift diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to apps/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/apps/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json rename to apps/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json diff --git a/src/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/apps/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png rename to apps/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/apps/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png rename to apps/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/apps/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png rename to apps/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png diff --git a/src/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/apps/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md similarity index 100% rename from src/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md rename to apps/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md diff --git a/src/mobile/ios/Runner/Base.lproj/LaunchScreen.storyboard b/apps/mobile/ios/Runner/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from src/mobile/ios/Runner/Base.lproj/LaunchScreen.storyboard rename to apps/mobile/ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/src/mobile/ios/Runner/Base.lproj/Main.storyboard b/apps/mobile/ios/Runner/Base.lproj/Main.storyboard similarity index 100% rename from src/mobile/ios/Runner/Base.lproj/Main.storyboard rename to apps/mobile/ios/Runner/Base.lproj/Main.storyboard diff --git a/src/mobile/ios/Runner/Info.plist b/apps/mobile/ios/Runner/Info.plist similarity index 100% rename from src/mobile/ios/Runner/Info.plist rename to apps/mobile/ios/Runner/Info.plist diff --git a/src/mobile/ios/Runner/Runner-Bridging-Header.h b/apps/mobile/ios/Runner/Runner-Bridging-Header.h similarity index 100% rename from src/mobile/ios/Runner/Runner-Bridging-Header.h rename to apps/mobile/ios/Runner/Runner-Bridging-Header.h diff --git a/src/mobile/ios/RunnerTests/RunnerTests.swift b/apps/mobile/ios/RunnerTests/RunnerTests.swift similarity index 100% rename from src/mobile/ios/RunnerTests/RunnerTests.swift rename to apps/mobile/ios/RunnerTests/RunnerTests.swift diff --git a/src/mobile/lib/core/constants/app_constants.dart b/apps/mobile/lib/core/constants/app_constants.dart similarity index 100% rename from src/mobile/lib/core/constants/app_constants.dart rename to apps/mobile/lib/core/constants/app_constants.dart diff --git a/src/mobile/lib/core/services/storage_service.dart b/apps/mobile/lib/core/services/storage_service.dart similarity index 100% rename from src/mobile/lib/core/services/storage_service.dart rename to apps/mobile/lib/core/services/storage_service.dart diff --git a/src/mobile/lib/core/services/voice_recognition_service.dart b/apps/mobile/lib/core/services/voice_recognition_service.dart similarity index 100% rename from src/mobile/lib/core/services/voice_recognition_service.dart rename to apps/mobile/lib/core/services/voice_recognition_service.dart diff --git a/src/mobile/lib/core/utils/app_router.dart b/apps/mobile/lib/core/utils/app_router.dart similarity index 100% rename from src/mobile/lib/core/utils/app_router.dart rename to apps/mobile/lib/core/utils/app_router.dart diff --git a/src/mobile/lib/core/utils/app_theme.dart b/apps/mobile/lib/core/utils/app_theme.dart similarity index 100% rename from src/mobile/lib/core/utils/app_theme.dart rename to apps/mobile/lib/core/utils/app_theme.dart diff --git a/src/mobile/lib/features/auth/screens/login_screen.dart b/apps/mobile/lib/features/auth/screens/login_screen.dart similarity index 100% rename from src/mobile/lib/features/auth/screens/login_screen.dart rename to apps/mobile/lib/features/auth/screens/login_screen.dart diff --git a/src/mobile/lib/features/auth/screens/register_screen.dart b/apps/mobile/lib/features/auth/screens/register_screen.dart similarity index 100% rename from src/mobile/lib/features/auth/screens/register_screen.dart rename to apps/mobile/lib/features/auth/screens/register_screen.dart diff --git a/src/mobile/lib/features/dialogue/models/dialogue_models.dart b/apps/mobile/lib/features/dialogue/models/dialogue_models.dart similarity index 100% rename from src/mobile/lib/features/dialogue/models/dialogue_models.dart rename to apps/mobile/lib/features/dialogue/models/dialogue_models.dart diff --git a/src/mobile/lib/features/dialogue/providers/dialogue_provider.dart b/apps/mobile/lib/features/dialogue/providers/dialogue_provider.dart similarity index 100% rename from src/mobile/lib/features/dialogue/providers/dialogue_provider.dart rename to apps/mobile/lib/features/dialogue/providers/dialogue_provider.dart diff --git a/src/mobile/lib/features/dialogue/screens/dialogue_main_screen.dart b/apps/mobile/lib/features/dialogue/screens/dialogue_main_screen.dart similarity index 100% rename from src/mobile/lib/features/dialogue/screens/dialogue_main_screen.dart rename to apps/mobile/lib/features/dialogue/screens/dialogue_main_screen.dart diff --git a/src/mobile/lib/features/dialogue/services/dialogue_service.dart b/apps/mobile/lib/features/dialogue/services/dialogue_service.dart similarity index 100% rename from src/mobile/lib/features/dialogue/services/dialogue_service.dart rename to apps/mobile/lib/features/dialogue/services/dialogue_service.dart diff --git a/src/mobile/lib/features/dialogue/widgets/character_avatar.dart b/apps/mobile/lib/features/dialogue/widgets/character_avatar.dart similarity index 100% rename from src/mobile/lib/features/dialogue/widgets/character_avatar.dart rename to apps/mobile/lib/features/dialogue/widgets/character_avatar.dart diff --git a/src/mobile/lib/features/dialogue/widgets/dialogue_background.dart b/apps/mobile/lib/features/dialogue/widgets/dialogue_background.dart similarity index 100% rename from src/mobile/lib/features/dialogue/widgets/dialogue_background.dart rename to apps/mobile/lib/features/dialogue/widgets/dialogue_background.dart diff --git a/src/mobile/lib/features/dialogue/widgets/dialogue_bubble.dart b/apps/mobile/lib/features/dialogue/widgets/dialogue_bubble.dart similarity index 100% rename from src/mobile/lib/features/dialogue/widgets/dialogue_bubble.dart rename to apps/mobile/lib/features/dialogue/widgets/dialogue_bubble.dart diff --git a/src/mobile/lib/features/dialogue/widgets/reply_assistance_panel.dart b/apps/mobile/lib/features/dialogue/widgets/reply_assistance_panel.dart similarity index 100% rename from src/mobile/lib/features/dialogue/widgets/reply_assistance_panel.dart rename to apps/mobile/lib/features/dialogue/widgets/reply_assistance_panel.dart diff --git a/src/mobile/lib/features/dialogue/widgets/task_display_panel.dart b/apps/mobile/lib/features/dialogue/widgets/task_display_panel.dart similarity index 100% rename from src/mobile/lib/features/dialogue/widgets/task_display_panel.dart rename to apps/mobile/lib/features/dialogue/widgets/task_display_panel.dart diff --git a/src/mobile/lib/features/dialogue/widgets/vocabulary_panel.dart b/apps/mobile/lib/features/dialogue/widgets/vocabulary_panel.dart similarity index 100% rename from src/mobile/lib/features/dialogue/widgets/vocabulary_panel.dart rename to apps/mobile/lib/features/dialogue/widgets/vocabulary_panel.dart diff --git a/src/mobile/lib/features/learning/screens/home_screen.dart b/apps/mobile/lib/features/learning/screens/home_screen.dart similarity index 100% rename from src/mobile/lib/features/learning/screens/home_screen.dart rename to apps/mobile/lib/features/learning/screens/home_screen.dart diff --git a/src/mobile/lib/main.dart b/apps/mobile/lib/main.dart similarity index 100% rename from src/mobile/lib/main.dart rename to apps/mobile/lib/main.dart diff --git a/src/mobile/lib/shared/providers/auth_provider.dart b/apps/mobile/lib/shared/providers/auth_provider.dart similarity index 100% rename from src/mobile/lib/shared/providers/auth_provider.dart rename to apps/mobile/lib/shared/providers/auth_provider.dart diff --git a/src/mobile/lib/shared/providers/voice_recognition_provider.dart b/apps/mobile/lib/shared/providers/voice_recognition_provider.dart similarity index 100% rename from src/mobile/lib/shared/providers/voice_recognition_provider.dart rename to apps/mobile/lib/shared/providers/voice_recognition_provider.dart diff --git a/src/mobile/lib/shared/widgets/voice_input_button.dart b/apps/mobile/lib/shared/widgets/voice_input_button.dart similarity index 100% rename from src/mobile/lib/shared/widgets/voice_input_button.dart rename to apps/mobile/lib/shared/widgets/voice_input_button.dart diff --git a/src/mobile/pubspec.lock b/apps/mobile/pubspec.lock similarity index 100% rename from src/mobile/pubspec.lock rename to apps/mobile/pubspec.lock diff --git a/src/mobile/pubspec.yaml b/apps/mobile/pubspec.yaml similarity index 100% rename from src/mobile/pubspec.yaml rename to apps/mobile/pubspec.yaml diff --git a/src/mobile/test/widget_test.dart b/apps/mobile/test/widget_test.dart similarity index 100% rename from src/mobile/test/widget_test.dart rename to apps/mobile/test/widget_test.dart diff --git a/src/mobile/web/favicon.png b/apps/mobile/web/favicon.png similarity index 100% rename from src/mobile/web/favicon.png rename to apps/mobile/web/favicon.png diff --git a/src/mobile/web/index.html b/apps/mobile/web/index.html similarity index 100% rename from src/mobile/web/index.html rename to apps/mobile/web/index.html diff --git a/src/mobile/web/manifest.json b/apps/mobile/web/manifest.json similarity index 100% rename from src/mobile/web/manifest.json rename to apps/mobile/web/manifest.json diff --git a/apps/web/.eslintrc.js b/apps/web/.eslintrc.js new file mode 100644 index 0000000..92f5d6d --- /dev/null +++ b/apps/web/.eslintrc.js @@ -0,0 +1,51 @@ +module.exports = { + root: true, + env: { + node: true, + browser: true, + es2021: true + }, + extends: [ + 'plugin:vue/vue3-essential', + 'eslint:recommended', + '@vue/typescript/recommended', + '@vue/prettier' + ], + parser: 'vue-eslint-parser', + parserOptions: { + parser: '@typescript-eslint/parser', + ecmaVersion: 2021, + sourceType: 'module' + }, + plugins: ['@typescript-eslint'], + rules: { + // Vue規則 + 'vue/multi-word-component-names': 'off', + 'vue/no-unused-vars': 'error', + 'vue/component-definition-name-casing': ['error', 'PascalCase'], + 'vue/component-name-in-template-casing': ['error', 'PascalCase'], + + // TypeScript規則 + '@typescript-eslint/no-unused-vars': ['error', { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_' + }], + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + + // 一般規則 + 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', + 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', + 'prefer-const': 'error', + 'no-var': 'error', + 'object-shorthand': 'error', + 'prefer-template': 'error' + }, + globals: { + defineProps: 'readonly', + defineEmits: 'readonly', + defineExpose: 'readonly', + withDefaults: 'readonly' + } +} \ No newline at end of file diff --git a/apps/web/.prettierrc b/apps/web/.prettierrc new file mode 100644 index 0000000..0dc9e93 --- /dev/null +++ b/apps/web/.prettierrc @@ -0,0 +1,14 @@ +{ + "semi": false, + "singleQuote": true, + "printWidth": 100, + "tabWidth": 2, + "useTabs": false, + "trailingComma": "none", + "bracketSpacing": true, + "bracketSameLine": false, + "arrowParens": "avoid", + "endOfLine": "lf", + "vueIndentScriptAndStyle": false, + "htmlWhitespaceSensitivity": "ignore" +} \ No newline at end of file diff --git a/apps/web/auto-imports.d.ts b/apps/web/auto-imports.d.ts new file mode 100644 index 0000000..8b1fc45 --- /dev/null +++ b/apps/web/auto-imports.d.ts @@ -0,0 +1,193 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// noinspection JSUnusedGlobalSymbols +// Generated by unplugin-auto-import +export {} +declare global { + const $q: typeof import('quasar')['$q'] + const Dialog: typeof import('quasar')['Dialog'] + const EffectScope: typeof import('vue')['EffectScope'] + const Loading: typeof import('quasar')['Loading'] + const Notify: typeof import('quasar')['Notify'] + const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate'] + const computed: typeof import('vue')['computed'] + const createApp: typeof import('vue')['createApp'] + const createPinia: typeof import('pinia')['createPinia'] + const customRef: typeof import('vue')['customRef'] + const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] + const defineComponent: typeof import('vue')['defineComponent'] + const defineStore: typeof import('pinia')['defineStore'] + const effectScope: typeof import('vue')['effectScope'] + const getActivePinia: typeof import('pinia')['getActivePinia'] + const getCurrentInstance: typeof import('vue')['getCurrentInstance'] + const getCurrentScope: typeof import('vue')['getCurrentScope'] + const h: typeof import('vue')['h'] + const inject: typeof import('vue')['inject'] + const isProxy: typeof import('vue')['isProxy'] + const isReactive: typeof import('vue')['isReactive'] + const isReadonly: typeof import('vue')['isReadonly'] + const isRef: typeof import('vue')['isRef'] + const mapActions: typeof import('pinia')['mapActions'] + const mapGetters: typeof import('pinia')['mapGetters'] + const mapState: typeof import('pinia')['mapState'] + const mapStores: typeof import('pinia')['mapStores'] + const mapWritableState: typeof import('pinia')['mapWritableState'] + const markRaw: typeof import('vue')['markRaw'] + const nextTick: typeof import('vue')['nextTick'] + const onActivated: typeof import('vue')['onActivated'] + const onBeforeMount: typeof import('vue')['onBeforeMount'] + const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave'] + const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate'] + const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] + const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] + const onDeactivated: typeof import('vue')['onDeactivated'] + const onErrorCaptured: typeof import('vue')['onErrorCaptured'] + const onMounted: typeof import('vue')['onMounted'] + const onRenderTracked: typeof import('vue')['onRenderTracked'] + const onRenderTriggered: typeof import('vue')['onRenderTriggered'] + const onScopeDispose: typeof import('vue')['onScopeDispose'] + const onServerPrefetch: typeof import('vue')['onServerPrefetch'] + const onUnmounted: typeof import('vue')['onUnmounted'] + const onUpdated: typeof import('vue')['onUpdated'] + const onWatcherCleanup: typeof import('vue')['onWatcherCleanup'] + const pinia: typeof import('./src/stores/index')['pinia'] + const provide: typeof import('vue')['provide'] + const reactive: typeof import('vue')['reactive'] + const readonly: typeof import('vue')['readonly'] + const ref: typeof import('vue')['ref'] + const resolveComponent: typeof import('vue')['resolveComponent'] + const setActivePinia: typeof import('pinia')['setActivePinia'] + const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix'] + const shallowReactive: typeof import('vue')['shallowReactive'] + const shallowReadonly: typeof import('vue')['shallowReadonly'] + const shallowRef: typeof import('vue')['shallowRef'] + const storeToRefs: typeof import('pinia')['storeToRefs'] + const toRaw: typeof import('vue')['toRaw'] + const toRef: typeof import('vue')['toRef'] + const toRefs: typeof import('vue')['toRefs'] + const toValue: typeof import('vue')['toValue'] + const triggerRef: typeof import('vue')['triggerRef'] + const unref: typeof import('vue')['unref'] + const useAttrs: typeof import('vue')['useAttrs'] + const useAuthStore: typeof import('./src/stores/auth')['useAuthStore'] + const useCssModule: typeof import('vue')['useCssModule'] + const useCssVars: typeof import('vue')['useCssVars'] + const useFetch: typeof import('@vueuse/core')['useFetch'] + const useId: typeof import('vue')['useId'] + const useLearningStore: typeof import('./src/stores/learning')['useLearningStore'] + const useLink: typeof import('vue-router')['useLink'] + const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage'] + const useModel: typeof import('vue')['useModel'] + const useQuasar: typeof import('quasar')['useQuasar'] + const useRoute: typeof import('vue-router')['useRoute'] + const useRouter: typeof import('vue-router')['useRouter'] + const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage'] + const useSlots: typeof import('vue')['useSlots'] + const useTemplateRef: typeof import('vue')['useTemplateRef'] + const useUIStore: typeof import('./src/stores/ui')['useUIStore'] + const useUserStore: typeof import('./src/stores/user')['useUserStore'] + const watch: typeof import('vue')['watch'] + const watchEffect: typeof import('vue')['watchEffect'] + const watchPostEffect: typeof import('vue')['watchPostEffect'] + const watchSyncEffect: typeof import('vue')['watchSyncEffect'] +} +// for type re-export +declare global { + // @ts-ignore + export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue' + import('vue') +} +// for vue template auto import +import { UnwrapRef } from 'vue' +declare module 'vue' { + interface GlobalComponents {} + interface ComponentCustomProperties { + readonly $q: UnwrapRef + readonly Dialog: UnwrapRef + readonly EffectScope: UnwrapRef + readonly Loading: UnwrapRef + readonly Notify: UnwrapRef + readonly acceptHMRUpdate: UnwrapRef + readonly computed: UnwrapRef + readonly createApp: UnwrapRef + readonly createPinia: UnwrapRef + readonly customRef: UnwrapRef + readonly defineAsyncComponent: UnwrapRef + readonly defineComponent: UnwrapRef + readonly defineStore: UnwrapRef + readonly effectScope: UnwrapRef + readonly getActivePinia: UnwrapRef + readonly getCurrentInstance: UnwrapRef + readonly getCurrentScope: UnwrapRef + readonly h: UnwrapRef + readonly inject: UnwrapRef + readonly isProxy: UnwrapRef + readonly isReactive: UnwrapRef + readonly isReadonly: UnwrapRef + readonly isRef: UnwrapRef + readonly mapActions: UnwrapRef + readonly mapGetters: UnwrapRef + readonly mapState: UnwrapRef + readonly mapStores: UnwrapRef + readonly mapWritableState: UnwrapRef + readonly markRaw: UnwrapRef + readonly nextTick: UnwrapRef + readonly onActivated: UnwrapRef + readonly onBeforeMount: UnwrapRef + readonly onBeforeRouteLeave: UnwrapRef + readonly onBeforeRouteUpdate: UnwrapRef + readonly onBeforeUnmount: UnwrapRef + readonly onBeforeUpdate: UnwrapRef + readonly onDeactivated: UnwrapRef + readonly onErrorCaptured: UnwrapRef + readonly onMounted: UnwrapRef + readonly onRenderTracked: UnwrapRef + readonly onRenderTriggered: UnwrapRef + readonly onScopeDispose: UnwrapRef + readonly onServerPrefetch: UnwrapRef + readonly onUnmounted: UnwrapRef + readonly onUpdated: UnwrapRef + readonly onWatcherCleanup: UnwrapRef + readonly pinia: UnwrapRef + readonly provide: UnwrapRef + readonly reactive: UnwrapRef + readonly readonly: UnwrapRef + readonly ref: UnwrapRef + readonly resolveComponent: UnwrapRef + readonly setActivePinia: UnwrapRef + readonly setMapStoreSuffix: UnwrapRef + readonly shallowReactive: UnwrapRef + readonly shallowReadonly: UnwrapRef + readonly shallowRef: UnwrapRef + readonly storeToRefs: UnwrapRef + readonly toRaw: UnwrapRef + readonly toRef: UnwrapRef + readonly toRefs: UnwrapRef + readonly toValue: UnwrapRef + readonly triggerRef: UnwrapRef + readonly unref: UnwrapRef + readonly useAttrs: UnwrapRef + readonly useAuthStore: UnwrapRef + readonly useCssModule: UnwrapRef + readonly useCssVars: UnwrapRef + readonly useFetch: UnwrapRef + readonly useId: UnwrapRef + readonly useLearningStore: UnwrapRef + readonly useLink: UnwrapRef + readonly useLocalStorage: UnwrapRef + readonly useModel: UnwrapRef + readonly useQuasar: UnwrapRef + readonly useRoute: UnwrapRef + readonly useRouter: UnwrapRef + readonly useSessionStorage: UnwrapRef + readonly useSlots: UnwrapRef + readonly useTemplateRef: UnwrapRef + readonly useUIStore: UnwrapRef + readonly useUserStore: UnwrapRef + readonly watch: UnwrapRef + readonly watchEffect: UnwrapRef + readonly watchPostEffect: UnwrapRef + readonly watchSyncEffect: UnwrapRef + } +} diff --git a/apps/web/components.d.ts b/apps/web/components.d.ts new file mode 100644 index 0000000..7efe883 --- /dev/null +++ b/apps/web/components.d.ts @@ -0,0 +1,23 @@ +/* eslint-disable */ +// @ts-nocheck +// Generated by unplugin-vue-components +// Read more: https://github.com/vuejs/core/pull/3399 +export {} + +/* prettier-ignore */ +declare module 'vue' { + export interface GlobalComponents { + BaseButton: typeof import('./src/components/base/BaseButton.vue')['default'] + BaseCard: typeof import('./src/components/base/BaseCard.vue')['default'] + BaseInput: typeof import('./src/components/base/BaseInput.vue')['default'] + BaseModal: typeof import('./src/components/base/BaseModal.vue')['default'] + ModalContainer: typeof import('./src/components/ui/ModalContainer.vue')['default'] + QBtn: typeof import('quasar')['QBtn'] + QCheckbox: typeof import('quasar')['QCheckbox'] + QIcon: typeof import('quasar')['QIcon'] + QSpinner: typeof import('quasar')['QSpinner'] + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + ToastContainer: typeof import('./src/components/ui/ToastContainer.vue')['default'] + } +} diff --git a/apps/web/index.html b/apps/web/index.html new file mode 100644 index 0000000..c4b0ef4 --- /dev/null +++ b/apps/web/index.html @@ -0,0 +1,103 @@ + + + + + + Drama Ling - AI語言學習 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ +
Drama Ling 載入中...
+
+ + + + \ No newline at end of file diff --git a/apps/web/package-lock.json b/apps/web/package-lock.json new file mode 100644 index 0000000..066573d --- /dev/null +++ b/apps/web/package-lock.json @@ -0,0 +1,13619 @@ +{ + "name": "dramaling-web", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "dramaling-web", + "version": "1.0.0", + "dependencies": { + "@quasar/extras": "^1.16.4", + "@vueuse/core": "^10.9.0", + "axios": "^1.6.8", + "dayjs": "^1.11.10", + "dompurify": "^3.0.11", + "lodash-es": "^4.17.21", + "pinia": "^2.1.7", + "pinia-plugin-persistedstate": "^3.2.1", + "quasar": "^2.16.0", + "vee-validate": "^4.12.6", + "vue": "^3.4.21", + "vue-router": "^4.3.0", + "workbox-window": "^7.0.0", + "yup": "^1.4.0" + }, + "devDependencies": { + "@quasar/vite-plugin": "^1.6.0", + "@types/dompurify": "^3.0.5", + "@types/lodash-es": "^4.17.12", + "@types/node": "^20.12.7", + "@vitejs/plugin-vue": "^5.0.4", + "@vitest/coverage-v8": "^1.5.0", + "@vitest/ui": "^1.5.0", + "@vue/eslint-config-prettier": "^9.0.0", + "@vue/eslint-config-typescript": "^13.0.0", + "@vue/test-utils": "^2.4.5", + "cypress": "^13.7.2", + "eslint": "^9.1.1", + "happy-dom": "^14.7.1", + "husky": "^9.0.11", + "lint-staged": "^15.2.2", + "prettier": "^3.2.5", + "sass": "^1.77.0", + "stylelint": "^16.4.0", + "stylelint-config-standard-scss": "^13.1.0", + "stylelint-config-standard-vue": "^1.0.0", + "typescript": "^5.4.0", + "unplugin-auto-import": "^0.17.5", + "unplugin-vue-components": "^0.27.0", + "vite": "^5.2.0", + "vite-plugin-pwa": "^0.20.0", + "vitest": "^1.5.0", + "vue-tsc": "^2.0.6" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@antfu/utils": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@apideck/better-ajv-errors": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", + "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-schema": "^0.4.0", + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/code-frame/node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/compat-data": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", + "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", + "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "regexpu-core": "^6.2.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.10" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", + "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", + "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", + "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", + "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.4.tgz", + "integrity": "sha512-1yxmvN0MJHOhPVmAsmoW5liWwoILobu/d/ShymZmj867bAdxGbehIrew1DuLpw2Ukv+qDSSPQdYW1dLNE7t11A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", + "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", + "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", + "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", + "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", + "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", + "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", + "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", + "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", + "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", + "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.3.tgz", + "integrity": "sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.0", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.0", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.3", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.0", + "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.28.0", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.3", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "core-js-compat": "^3.43.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/media-query-list-parser": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz", + "integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@cypress/request": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.9.tgz", + "integrity": "sha512-I3l7FdGRXluAS44/0NguwWlO83J18p0vlr2FYHrJkWdNYhgVoiYo61IXPqaOsL+vNxU1ZqMACzItGK3/KKDsdw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~4.0.4", + "http-signature": "~1.4.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "performance-now": "^2.1.0", + "qs": "6.14.0", + "safe-buffer": "^5.1.2", + "tough-cookie": "^5.0.0", + "tunnel-agent": "^0.6.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@cypress/xvfb": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", + "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.1.0", + "lodash.once": "^4.1.1" + } + }, + "node_modules/@cypress/xvfb/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@dual-bundle/import-meta-resolve": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.2.1.tgz", + "integrity": "sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/JounQin" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.35.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.35.0.tgz", + "integrity": "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "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/@jridgewell/trace-mapping": { + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@keyv/serialize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.0.tgz", + "integrity": "sha512-RlDgexML7Z63Q8BSaqhXdCYNBy/JQnqYIwxofUrNLGCblOMHp+xux2Q8nLMLlPpgHQPoU0Do8Z6btCpRBEqZ8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@quasar/extras": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@quasar/extras/-/extras-1.17.0.tgz", + "integrity": "sha512-KqAHdSJfIDauiR1nJ8rqHWT0diqD0QradZKoVIZJAilHAvgwyPIY7MbyR2z4RIMkUIMUSqBZcbshMpEw+9A30w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://donate.quasar.dev" + } + }, + "node_modules/@quasar/vite-plugin": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@quasar/vite-plugin/-/vite-plugin-1.10.0.tgz", + "integrity": "sha512-4PJoTclz4ZjAfyqe0+hlkKcFJt0e2NX3Ac3hy8ILqUPdtZ24nCo5/xEHvTxZGBQMKRPwwePbO8CVs4n9EKJEug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "type": "github", + "url": "https://donate.quasar.dev" + }, + "peerDependencies": { + "@vitejs/plugin-vue": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", + "quasar": "^2.16.0", + "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "vue": "^3.0.0" + } + }, + "node_modules/@rollup/plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", + "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-babel/node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/plugin-babel/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-babel/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz", + "integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/plugin-replace/node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/plugin-replace/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-replace/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-replace/node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/pluginutils/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", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.1.tgz", + "integrity": "sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.1.tgz", + "integrity": "sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.1.tgz", + "integrity": "sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.1.tgz", + "integrity": "sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.1.tgz", + "integrity": "sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.1.tgz", + "integrity": "sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.1.tgz", + "integrity": "sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.1.tgz", + "integrity": "sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.1.tgz", + "integrity": "sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.1.tgz", + "integrity": "sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.1.tgz", + "integrity": "sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.1.tgz", + "integrity": "sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.1.tgz", + "integrity": "sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.1.tgz", + "integrity": "sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.1.tgz", + "integrity": "sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.1.tgz", + "integrity": "sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.1.tgz", + "integrity": "sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.1.tgz", + "integrity": "sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.1.tgz", + "integrity": "sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.1.tgz", + "integrity": "sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.1.tgz", + "integrity": "sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@surma/rollup-plugin-off-main-thread": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", + "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "ejs": "^3.1.6", + "json5": "^2.2.0", + "magic-string": "^0.25.0", + "string.prototype.matchall": "^4.0.6" + } + }, + "node_modules/@surma/rollup-plugin-off-main-thread/node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/@types/dompurify": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", + "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/trusted-types": "*" + } + }, + "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/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/node": { + "version": "20.19.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.13.tgz", + "integrity": "sha512-yCAeZl7a0DxgNVteXFHt9+uyFbqXGy/ShC4BlcHkoE0AfGXYv/BUiplV72DjMYXHDBXFjhvr6DD1NiRVfB4j8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", + "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/sizzle": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.10.tgz", + "integrity": "sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT" + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", + "license": "MIT" + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "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/@vitest/coverage-v8": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.6.1.tgz", + "integrity": "sha512-6YeRZwuO4oTGKxD3bijok756oktHSIm3eczVVzNe3scqzuhLwltIF3S9ZL/vwOVIpURmU6SnZhziXXAfw8/Qlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.1", + "@bcoe/v8-coverage": "^0.2.3", + "debug": "^4.3.4", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.4", + "istanbul-reports": "^3.1.6", + "magic-string": "^0.30.5", + "magicast": "^0.3.3", + "picocolors": "^1.0.0", + "std-env": "^3.5.0", + "strip-literal": "^2.0.0", + "test-exclude": "^6.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "1.6.1" + } + }, + "node_modules/@vitest/expect": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.1.tgz", + "integrity": "sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "1.6.1", + "@vitest/utils": "1.6.1", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.1.tgz", + "integrity": "sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "1.6.1", + "p-limit": "^5.0.0", + "pathe": "^1.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner/node_modules/p-limit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", + "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/runner/node_modules/yocto-queue": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/snapshot": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.1.tgz", + "integrity": "sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.1.tgz", + "integrity": "sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^2.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/ui": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-1.6.1.tgz", + "integrity": "sha512-xa57bCPGuzEFqGjPs3vVLyqareG8DX0uMkr5U/v5vLv5/ZUrBrPL7gzxzTJedEyZxFMfsozwTIbbYfEQVo3kgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "1.6.1", + "fast-glob": "^3.3.2", + "fflate": "^0.8.1", + "flatted": "^3.2.9", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "sirv": "^2.0.4" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "1.6.1" + } + }, + "node_modules/@vitest/utils": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.1.tgz", + "integrity": "sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", + "loupe": "^2.3.7", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "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.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.21.tgz", + "integrity": "sha512-8i+LZ0vf6ZgII5Z9XmUvrCyEzocvWT+TeR2VBUVlzIH6Tyv57E20mPZ1bCS+tbejgUgmjrEh7q/0F0bibskAmw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@vue/shared": "3.5.21", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-core/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/@vue/compiler-dom": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.21.tgz", + "integrity": "sha512-jNtbu/u97wiyEBJlJ9kmdw7tAr5Vy0Aj5CgQmo+6pxWNQhXZDPsRr1UWPN4v3Zf82s2H3kF51IbzZ4jMWAgPlQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.21", + "@vue/shared": "3.5.21" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.21.tgz", + "integrity": "sha512-SXlyk6I5eUGBd2v8Ie7tF6ADHE9kCR6mBEuPyH1nUZ0h6Xx6nZI29i12sJKQmzbDyr2tUHMhhTt51Z6blbkTTQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@vue/compiler-core": "3.5.21", + "@vue/compiler-dom": "3.5.21", + "@vue/compiler-ssr": "3.5.21", + "@vue/shared": "3.5.21", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.18", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-sfc/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/@vue/compiler-ssr": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.21.tgz", + "integrity": "sha512-vKQ5olH5edFZdf5ZrlEgSO1j1DMA4u23TVK5XR1uMhvwnYvVdDF0nHXJUblL/GvzlShQbjhZZ2uvYmDlAbgo9w==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.21", + "@vue/shared": "3.5.21" + } + }, + "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/devtools-kit": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.7.tgz", + "integrity": "sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA==", + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.7", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.7.tgz", + "integrity": "sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw==", + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/eslint-config-prettier": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-z1ZIAAUS9pKzo/ANEfd2sO+v2IUalz7cM/cTLOZ7vRFOPk5/xuRKQteOu1DErFLAh/lYGXMVZ0IfYKlyInuDVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0" + }, + "peerDependencies": { + "eslint": ">= 8.0.0", + "prettier": ">= 3.0.0" + } + }, + "node_modules/@vue/eslint-config-typescript": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-13.0.0.tgz", + "integrity": "sha512-MHh9SncG/sfqjVqjcuFLOLD6Ed4dRAis4HNt0dXASeAuLqIAx4YMB1/m2o4pUKK1vCt8fUvYG8KKX2Ot3BVZTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "^7.1.1", + "@typescript-eslint/parser": "^7.1.1", + "vue-eslint-parser": "^9.3.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "peerDependencies": { + "eslint": "^8.56.0", + "eslint-plugin-vue": "^9.0.0", + "typescript": ">=4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "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.21", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.21.tgz", + "integrity": "sha512-3ah7sa+Cwr9iiYEERt9JfZKPw4A2UlbY8RbbnH2mGCE8NwHkhmlZt2VsH0oDA3P08X3jJd29ohBDtX+TbD9AsA==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.21" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.21.tgz", + "integrity": "sha512-+DplQlRS4MXfIf9gfD1BOJpk5RSyGgGXD/R+cumhe8jdjUcq/qlxDawQlSI8hCKupBlvM+3eS1se5xW+SuNAwA==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.21", + "@vue/shared": "3.5.21" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.21.tgz", + "integrity": "sha512-3M2DZsOFwM5qI15wrMmNF5RJe1+ARijt2HM3TbzBbPSuBHOQpoidE+Pa+XEaVN+czbHf81ETRoG1ltztP2em8w==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.21", + "@vue/runtime-core": "3.5.21", + "@vue/shared": "3.5.21", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.21.tgz", + "integrity": "sha512-qr8AqgD3DJPJcGvLcJKQo2tAc8OnXRcfxhOJCPF+fcfn5bBGz7VCcO7t+qETOPxpWK1mgysXvVT/j+xWaHeMWA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.21", + "@vue/shared": "3.5.21" + }, + "peerDependencies": { + "vue": "3.5.21" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.21.tgz", + "integrity": "sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==", + "license": "MIT" + }, + "node_modules/@vue/test-utils": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.6.tgz", + "integrity": "sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-beautify": "^1.14.9", + "vue-component-type-helpers": "^2.0.0" + } + }, + "node_modules/@vueuse/core": { + "version": "10.11.1", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.11.1.tgz", + "integrity": "sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "10.11.1", + "@vueuse/shared": "10.11.1", + "vue-demi": ">=0.14.8" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/metadata": { + "version": "10.11.1", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.11.1.tgz", + "integrity": "sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "10.11.1", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.11.1.tgz", + "integrity": "sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==", + "license": "MIT", + "dependencies": { + "vue-demi": ">=0.14.8" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "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/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", + "dev": true, + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", + "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "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/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/birpc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.5.0.tgz", + "integrity": "sha512-VSWO/W6nNQdyP520F1mhf+Lc2f8pjGQOtoHHm7Ze8Go1kX7akpVIrtTa0fn+HB0QJEDVacl6aO08YE0PgXfdnQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/blob-util": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", + "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "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/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.25.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.4.tgz", + "integrity": "sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001737", + "electron-to-chromium": "^1.5.211", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-1.10.4.tgz", + "integrity": "sha512-Gd7ccIUkZ9TE2odLQVS+PDjIvQCdJKUlLdJRVvZu0aipj07Qfx+XIej7hhDrKGGoIxV5m5fT/kOJNJPQhQneRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hookified": "^1.11.0", + "keyv": "^5.5.0" + } + }, + "node_modules/cacheable/node_modules/keyv": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.5.0.tgz", + "integrity": "sha512-QG7qR2tijh1ftOvClut4YKKg1iW6cx3GZsKoGyJPxHkGWK9oJhG9P3j5deP0QQOGDowBMVQFaP+Vm4NpGYvmIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@keyv/serialize": "^1.1.0" + } + }, + "node_modules/cachedir": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", + "integrity": "sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001741", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001741.tgz", + "integrity": "sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/chai": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/check-more-types": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ci-info": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz", + "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/config-chain/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-anything": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", + "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", + "license": "MIT", + "dependencies": { + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/core-js-compat": { + "version": "3.45.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.1.tgz", + "integrity": "sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.25.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/css-functions-list": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz", + "integrity": "sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12 || >=16" + } + }, + "node_modules/css-tree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", + "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.12.2", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/cypress": { + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.17.0.tgz", + "integrity": "sha512-5xWkaPurwkIljojFidhw8lFScyxhtiFHl/i/3zov+1Z5CmY4t9tjIdvSXfu82Y3w7wt0uR9KkucbhkVvJZLQSA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@cypress/request": "^3.0.6", + "@cypress/xvfb": "^1.2.4", + "@types/sinonjs__fake-timers": "8.1.1", + "@types/sizzle": "^2.3.2", + "arch": "^2.2.0", + "blob-util": "^2.0.2", + "bluebird": "^3.7.2", + "buffer": "^5.7.1", + "cachedir": "^2.3.0", + "chalk": "^4.1.0", + "check-more-types": "^2.24.0", + "ci-info": "^4.0.0", + "cli-cursor": "^3.1.0", + "cli-table3": "~0.6.1", + "commander": "^6.2.1", + "common-tags": "^1.8.0", + "dayjs": "^1.10.4", + "debug": "^4.3.4", + "enquirer": "^2.3.6", + "eventemitter2": "6.4.7", + "execa": "4.1.0", + "executable": "^4.1.1", + "extract-zip": "2.0.1", + "figures": "^3.2.0", + "fs-extra": "^9.1.0", + "getos": "^3.2.1", + "is-installed-globally": "~0.4.0", + "lazy-ass": "^1.6.0", + "listr2": "^3.8.3", + "lodash": "^4.17.21", + "log-symbols": "^4.0.0", + "minimist": "^1.2.8", + "ospath": "^1.2.2", + "pretty-bytes": "^5.6.0", + "process": "^0.11.10", + "proxy-from-env": "1.0.0", + "request-progress": "^3.0.0", + "semver": "^7.5.3", + "supports-color": "^8.1.1", + "tmp": "~0.2.3", + "tree-kill": "1.2.2", + "untildify": "^4.0.0", + "yauzl": "^2.10.0" + }, + "bin": { + "cypress": "bin/cypress" + }, + "engines": { + "node": "^16.0.0 || ^18.0.0 || >=20.0.0" + } + }, + "node_modules/cypress/node_modules/proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", + "dev": true, + "license": "MIT" + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dayjs": { + "version": "1.11.18", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz", + "integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==", + "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/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dompurify": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.6.tgz", + "integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/editorconfig": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", + "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" + }, + "bin": { + "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "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/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.215", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.215.tgz", + "integrity": "sha512-TIvGp57UpeNetj/wV/xpFNpWGb0b/ROw372lHPx5Aafx02gjTBtWnEEcaSX3W2dLM3OSdGGyHX/cHl01JQsLaQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.35.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.35.0.tgz", + "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.1", + "@eslint/core": "^0.15.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.35.0", + "@eslint/plugin-kit": "^0.3.5", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", + "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", + "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.11.7" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter2": { + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", + "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "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/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "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/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.1.tgz", + "integrity": "sha512-R1QfovbPsKmosqTnPoRFiJ7CF9MLRgb53ChvMZm+r4p76/+8yKDy17qLL2PKInORy2RkZZekuK0efYgmzTkXyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "dev": true, + "license": "ISC" + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getos": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", + "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "async": "^3.2.0" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globjoin": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", + "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", + "dev": true, + "license": "MIT" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/happy-dom": { + "version": "14.12.3", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.12.3.tgz", + "integrity": "sha512-vsYlEs3E9gLwA1Hp+w3qzu+RUDFf4VTT8cyKqVICoZ2k7WM++Qyd2LwzyTi5bqMJFiIC/vNpTDYuxdreENRK/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^4.5.0", + "webidl-conversions": "^7.0.0", + "whatwg-mimetype": "^3.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "license": "MIT" + }, + "node_modules/hookified": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.12.0.tgz", + "integrity": "sha512-hMr1Y9TCLshScrBbV2QxJ9BROddxZ12MX9KsCtuGGy/3SmmN5H1PllKerrVlSotur9dlE8hmUKAOSa3WDzsZmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/http-signature": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.4.0.tgz", + "integrity": "sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2", + "sshpk": "^1.18.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", + "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", + "dev": true, + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-what": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/js-beautify": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.4.tgz", + "integrity": "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.4", + "glob": "^10.4.2", + "js-cookie": "^3.0.5", + "nopt": "^7.2.1" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/known-css-properties": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.37.0.tgz", + "integrity": "sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lazy-ass": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "> 0.8" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lint-staged": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz", + "integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^13.1.0", + "debug": "^4.4.0", + "execa": "^8.0.1", + "lilconfig": "^3.1.3", + "listr2": "^8.2.5", + "micromatch": "^4.0.8", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.7.0" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/lint-staged/node_modules/emoji-regex": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", + "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lint-staged/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/lint-staged/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/listr2": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", + "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/lint-staged/node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/lint-staged/node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/listr2": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", + "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.1", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/local-pkg": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz", + "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mlly": "^1.7.3", + "pkg-types": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mathml-tag-names": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", + "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdn-data": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/meow": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, + "node_modules/mlly": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" + } + }, + "node_modules/mlly/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "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/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-releases": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.20.tgz", + "integrity": "sha512-7gK6zSXEH6neM212JgfYFXe+GmZQM+fia5SsusuBIUgnPheLFBmIPhtFoAQRj8/7wASYQnbDlHPVwY0BefoFgA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ospath": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", + "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", + "dev": true, + "license": "MIT" + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "license": "MIT" + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "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": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinia": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz", + "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.3", + "vue-demi": "^0.14.10" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "typescript": ">=4.4.4", + "vue": "^2.7.0 || ^3.5.11" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/pinia-plugin-persistedstate": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-3.2.3.tgz", + "integrity": "sha512-Cm819WBj/s5K5DGw55EwbXDtx+EZzM0YR5AZbq9XE3u0xvXwvX2JnWoFpWIcdzISBHqy9H1UiSIUmXyXqWsQRQ==", + "license": "MIT", + "peerDependencies": { + "pinia": "^2.0.0" + } + }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/pkg-types/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "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/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", + "dev": true, + "license": "MIT" + }, + "node_modules/postcss-resolve-nested-selector": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz", + "integrity": "sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/postcss-safe-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-scss": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", + "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-scss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.4.29" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/property-expr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", + "license": "MIT" + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true, + "license": "ISC" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/quasar": { + "version": "2.18.2", + "resolved": "https://registry.npmjs.org/quasar/-/quasar-2.18.2.tgz", + "integrity": "sha512-SeSAamH4vgYH9alLTdVL2o1fTTwz7VZnS2+gvIwt6qsH3ndrn/tQW64sWE78VSvrHlWINYbXESVF/cvWEuTYxg==", + "license": "MIT", + "engines": { + "node": ">= 10.18.1", + "npm": ">= 6.13.4", + "yarn": ">= 1.21.1" + }, + "funding": { + "type": "github", + "url": "https://donate.quasar.dev" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.0.2" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/request-progress": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", + "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "throttleit": "^1.0.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz", + "integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==", + "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.50.1", + "@rollup/rollup-android-arm64": "4.50.1", + "@rollup/rollup-darwin-arm64": "4.50.1", + "@rollup/rollup-darwin-x64": "4.50.1", + "@rollup/rollup-freebsd-arm64": "4.50.1", + "@rollup/rollup-freebsd-x64": "4.50.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.50.1", + "@rollup/rollup-linux-arm-musleabihf": "4.50.1", + "@rollup/rollup-linux-arm64-gnu": "4.50.1", + "@rollup/rollup-linux-arm64-musl": "4.50.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.50.1", + "@rollup/rollup-linux-ppc64-gnu": "4.50.1", + "@rollup/rollup-linux-riscv64-gnu": "4.50.1", + "@rollup/rollup-linux-riscv64-musl": "4.50.1", + "@rollup/rollup-linux-s390x-gnu": "4.50.1", + "@rollup/rollup-linux-x64-gnu": "4.50.1", + "@rollup/rollup-linux-x64-musl": "4.50.1", + "@rollup/rollup-openharmony-arm64": "4.50.1", + "@rollup/rollup-win32-arm64-msvc": "4.50.1", + "@rollup/rollup-win32-ia32-msvc": "4.50.1", + "@rollup/rollup-win32-x64-msvc": "4.50.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sass": { + "version": "1.92.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.92.1.tgz", + "integrity": "sha512-ffmsdbwqb3XeyR8jJR6KelIXARM9bFQe8A6Q3W4Klmwy5Ckd5gz7jgUNHo4UOqutU5Sk1DtKLbpDP0nLCg1xqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smob": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "dev": true, + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "deprecated": "The work that was done in this beta branch won't be included in future versions", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "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/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true, + "license": "MIT" + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", + "dev": true, + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.1.tgz", + "integrity": "sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/stylelint": { + "version": "16.24.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.24.0.tgz", + "integrity": "sha512-7ksgz3zJaSbTUGr/ujMXvLVKdDhLbGl3R/3arNudH7z88+XZZGNLMTepsY28WlnvEFcuOmUe7fg40Q3lfhOfSQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3", + "@csstools/selector-specificity": "^5.0.0", + "@dual-bundle/import-meta-resolve": "^4.1.0", + "balanced-match": "^2.0.0", + "colord": "^2.9.3", + "cosmiconfig": "^9.0.0", + "css-functions-list": "^3.2.3", + "css-tree": "^3.1.0", + "debug": "^4.4.1", + "fast-glob": "^3.3.3", + "fastest-levenshtein": "^1.0.16", + "file-entry-cache": "^10.1.4", + "global-modules": "^2.0.0", + "globby": "^11.1.0", + "globjoin": "^0.1.4", + "html-tags": "^3.3.1", + "ignore": "^7.0.5", + "imurmurhash": "^0.1.4", + "is-plain-object": "^5.0.0", + "known-css-properties": "^0.37.0", + "mathml-tag-names": "^2.1.3", + "meow": "^13.2.0", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.5.6", + "postcss-resolve-nested-selector": "^0.1.6", + "postcss-safe-parser": "^7.0.1", + "postcss-selector-parser": "^7.1.0", + "postcss-value-parser": "^4.2.0", + "resolve-from": "^5.0.0", + "string-width": "^4.2.3", + "supports-hyperlinks": "^3.2.0", + "svg-tags": "^1.0.0", + "table": "^6.9.0", + "write-file-atomic": "^5.0.1" + }, + "bin": { + "stylelint": "bin/stylelint.mjs" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/stylelint-config-html": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stylelint-config-html/-/stylelint-config-html-1.1.0.tgz", + "integrity": "sha512-IZv4IVESjKLumUGi+HWeb7skgO6/g4VMuAYrJdlqQFndgbj6WJAXPhaysvBiXefX79upBdQVumgYcdd17gCpjQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12 || >=14" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "postcss-html": "^1.0.0", + "stylelint": ">=14.0.0" + } + }, + "node_modules/stylelint-config-recommended": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.1.tgz", + "integrity": "sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "stylelint": "^16.1.0" + } + }, + "node_modules/stylelint-config-recommended-scss": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-14.1.0.tgz", + "integrity": "sha512-bhaMhh1u5dQqSsf6ri2GVWWQW5iUjBYgcHkh7SgDDn92ijoItC/cfO/W+fpXshgTQWhwFkP1rVcewcv4jaftRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-scss": "^4.0.9", + "stylelint-config-recommended": "^14.0.1", + "stylelint-scss": "^6.4.0" + }, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "postcss": "^8.3.3", + "stylelint": "^16.6.1" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + } + } + }, + "node_modules/stylelint-config-recommended-vue": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended-vue/-/stylelint-config-recommended-vue-1.6.1.tgz", + "integrity": "sha512-lLW7hTIMBiTfjenGuDq2kyHA6fBWd/+Df7MO4/AWOxiFeXP9clbpKgg27kHfwA3H7UNMGC7aeP3mNlZB5LMmEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5", + "stylelint-config-html": ">=1.0.0", + "stylelint-config-recommended": ">=6.0.0" + }, + "engines": { + "node": "^12 || >=14" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "postcss-html": "^1.0.0", + "stylelint": ">=14.0.0" + } + }, + "node_modules/stylelint-config-standard": { + "version": "36.0.1", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-36.0.1.tgz", + "integrity": "sha512-8aX8mTzJ6cuO8mmD5yon61CWuIM4UD8Q5aBcWKGSf6kg+EC3uhB+iOywpTK4ca6ZL7B49en8yanOFtUW0qNzyw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", + "dependencies": { + "stylelint-config-recommended": "^14.0.1" + }, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "stylelint": "^16.1.0" + } + }, + "node_modules/stylelint-config-standard-scss": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard-scss/-/stylelint-config-standard-scss-13.1.0.tgz", + "integrity": "sha512-Eo5w7/XvwGHWkeGLtdm2FZLOMYoZl1omP2/jgFCXyl2x5yNz7/8vv4Tj6slHvMSSUNTaGoam/GAZ0ZhukvalfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "stylelint-config-recommended-scss": "^14.0.0", + "stylelint-config-standard": "^36.0.0" + }, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "postcss": "^8.3.3", + "stylelint": "^16.3.1" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + } + } + }, + "node_modules/stylelint-config-standard-vue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard-vue/-/stylelint-config-standard-vue-1.0.0.tgz", + "integrity": "sha512-wAzU7p6DSlo04pWfCbOcaMq09Nojt0FEsbdxhCBTdC7IguD9ZVl7FP/bvyA0HAHjZGC4JkW7m6WiQaoVMDSuFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "stylelint-config-html": ">=1.0.0", + "stylelint-config-recommended-vue": ">=1.1.0", + "stylelint-config-standard": ">=24.0.0" + }, + "engines": { + "node": "^12 || >=14" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "postcss-html": "^1.0.0", + "stylelint": ">=14.0.0" + } + }, + "node_modules/stylelint-scss": { + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-6.12.1.tgz", + "integrity": "sha512-UJUfBFIvXfly8WKIgmqfmkGKPilKB4L5j38JfsDd+OCg2GBdU0vGUV08Uw82tsRZzd4TbsUURVVNGeOhJVF7pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.1", + "is-plain-object": "^5.0.0", + "known-css-properties": "^0.36.0", + "mdn-data": "^2.21.0", + "postcss-media-query-parser": "^0.2.3", + "postcss-resolve-nested-selector": "^0.1.6", + "postcss-selector-parser": "^7.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "stylelint": "^16.0.2" + } + }, + "node_modules/stylelint-scss/node_modules/known-css-properties": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.36.0.tgz", + "integrity": "sha512-A+9jP+IUmuQsNdsLdcg6Yt7voiMF/D4K83ew0OpJtpu+l34ef7LaohWV0Rc6KNvzw6ZDizkqfyB5JznZnzuKQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/stylelint-scss/node_modules/mdn-data": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.24.0.tgz", + "integrity": "sha512-i97fklrJl03tL1tdRVw0ZfLLvuDsdb6wxL+TrJ+PKkCbLrp2PCu2+OYdCKychIUm19nSM/35S6qz7pJpnXttoA==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/stylelint/node_modules/balanced-match": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", + "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", + "dev": true, + "license": "MIT" + }, + "node_modules/stylelint/node_modules/file-entry-cache": { + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-10.1.4.tgz", + "integrity": "sha512-5XRUFc0WTtUbjfGzEwXc42tiGxQHBmtbUG1h9L2apu4SulCGN3Hqm//9D6FAolf8MYNL7f/YlJl9vy08pj5JuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^6.1.13" + } + }, + "node_modules/stylelint/node_modules/flat-cache": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.13.tgz", + "integrity": "sha512-gmtS2PaUjSPa4zjObEIn4WWliKyZzYljgxODBfxugpK6q6HU9ClXzgCJ+nlcPKY9Bt090ypTOLIFWkV0jbKFjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cacheable": "^1.10.4", + "flatted": "^3.3.3", + "hookified": "^1.11.0" + } + }, + "node_modules/stylelint/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/stylelint/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/superjson": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz", + "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==", + "license": "MIT", + "dependencies": { + "copy-anything": "^3.0.2" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/table/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", + "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.44.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", + "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/throttleit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz", + "integrity": "sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tiny-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==", + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "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/tinyglobby/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", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinypool": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", + "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", + "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", + "license": "MIT" + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true, + "license": "Unlicense" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unimport": { + "version": "3.14.6", + "resolved": "https://registry.npmjs.org/unimport/-/unimport-3.14.6.tgz", + "integrity": "sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.1.4", + "acorn": "^8.14.0", + "escape-string-regexp": "^5.0.0", + "estree-walker": "^3.0.3", + "fast-glob": "^3.3.3", + "local-pkg": "^1.0.0", + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "pathe": "^2.0.1", + "picomatch": "^4.0.2", + "pkg-types": "^1.3.0", + "scule": "^1.3.0", + "strip-literal": "^2.1.1", + "unplugin": "^1.16.1" + } + }, + "node_modules/unimport/node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unimport/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unimport/node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/unimport/node_modules/local-pkg/node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/unimport/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/unimport/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", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unplugin": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.16.1.tgz", + "integrity": "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/unplugin-auto-import": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-0.17.8.tgz", + "integrity": "sha512-CHryj6HzJ+n4ASjzwHruD8arhbdl+UXvhuAIlHDs15Y/IMecG3wrf7FVg4pVH/DIysbq/n0phIjNHAjl7TG7Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@antfu/utils": "^0.7.10", + "@rollup/pluginutils": "^5.1.0", + "fast-glob": "^3.3.2", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.10", + "minimatch": "^9.0.4", + "unimport": "^3.7.2", + "unplugin": "^1.11.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@nuxt/kit": "^3.2.2", + "@vueuse/core": "*" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + }, + "@vueuse/core": { + "optional": true + } + } + }, + "node_modules/unplugin-vue-components": { + "version": "0.27.5", + "resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.27.5.tgz", + "integrity": "sha512-m9j4goBeNwXyNN8oZHHxvIIYiG8FQ9UfmKWeNllpDvhU7btKNNELGPt+o3mckQKuPwrE7e0PvCsx+IWuDSD9Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@antfu/utils": "^0.7.10", + "@rollup/pluginutils": "^5.1.3", + "chokidar": "^3.6.0", + "debug": "^4.3.7", + "fast-glob": "^3.3.2", + "local-pkg": "^0.5.1", + "magic-string": "^0.30.14", + "minimatch": "^9.0.5", + "mlly": "^1.7.3", + "unplugin": "^1.16.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@babel/parser": "^7.15.8", + "@nuxt/kit": "^3.2.2", + "vue": "2 || 3" + }, + "peerDependenciesMeta": { + "@babel/parser": { + "optional": true + }, + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/unplugin-vue-components/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/unplugin-vue-components/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/unplugin-vue-components/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vee-validate": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-4.15.1.tgz", + "integrity": "sha512-DkFsiTwEKau8VIxyZBGdO6tOudD+QoUBPuHj3e6QFqmbfCRj1ArmYWue9lEp6jLSWBIw4XPlDLjFIZNLdRAMSg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^7.5.2", + "type-fest": "^4.8.3" + }, + "peerDependencies": { + "vue": "^3.4.26" + } + }, + "node_modules/vee-validate/node_modules/@vue/devtools-api": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.7.tgz", + "integrity": "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.7" + } + }, + "node_modules/vee-validate/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/vite": { + "version": "5.4.20", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.20.tgz", + "integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.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", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.1.tgz", + "integrity": "sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite-plugin-pwa": { + "version": "0.20.5", + "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-0.20.5.tgz", + "integrity": "sha512-aweuI/6G6n4C5Inn0vwHumElU/UEpNuO+9iZzwPZGTCH87TeZ6YFMrEY6ZUBQdIHHlhTsbMDryFARcSuOdsz9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.6", + "pretty-bytes": "^6.1.1", + "tinyglobby": "^0.2.0", + "workbox-build": "^7.1.0", + "workbox-window": "^7.1.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vite-pwa/assets-generator": "^0.2.6", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0", + "workbox-build": "^7.1.0", + "workbox-window": "^7.1.0" + }, + "peerDependenciesMeta": { + "@vite-pwa/assets-generator": { + "optional": true + } + } + }, + "node_modules/vite-plugin-pwa/node_modules/pretty-bytes": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", + "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.1.tgz", + "integrity": "sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "1.6.1", + "@vitest/runner": "1.6.1", + "@vitest/snapshot": "1.6.1", + "@vitest/spy": "1.6.1", + "@vitest/utils": "1.6.1", + "acorn-walk": "^8.3.2", + "chai": "^4.3.10", + "debug": "^4.3.4", + "execa": "^8.0.1", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "std-env": "^3.5.0", + "strip-literal": "^2.0.0", + "tinybench": "^2.5.1", + "tinypool": "^0.8.3", + "vite": "^5.0.0", + "vite-node": "1.6.1", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "1.6.1", + "@vitest/ui": "1.6.1", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/vitest/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/vitest/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/vitest/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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.21", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.21.tgz", + "integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.21", + "@vue/compiler-sfc": "3.5.21", + "@vue/runtime-dom": "3.5.21", + "@vue/server-renderer": "3.5.21", + "@vue/shared": "3.5.21" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-component-type-helpers": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.12.tgz", + "integrity": "sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/vue-eslint-parser": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", + "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-router": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz", + "integrity": "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.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/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/whatwg-url/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workbox-background-sync": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-7.3.0.tgz", + "integrity": "sha512-PCSk3eK7Mxeuyatb22pcSx9dlgWNv3+M8PqPaYDokks8Y5/FX4soaOqj3yhAZr5k6Q5JWTOMYgaJBpbw11G9Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "7.3.0" + } + }, + "node_modules/workbox-broadcast-update": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-7.3.0.tgz", + "integrity": "sha512-T9/F5VEdJVhwmrIAE+E/kq5at2OY6+OXXgOWQevnubal6sO92Gjo24v6dCVwQiclAF5NS3hlmsifRrpQzZCdUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.3.0" + } + }, + "node_modules/workbox-build": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-7.3.0.tgz", + "integrity": "sha512-JGL6vZTPlxnlqZRhR/K/msqg3wKP+m0wfEUVosK7gsYzSgeIxvZLi1ViJJzVL7CEeI8r7rGFV973RiEqkP3lWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apideck/better-ajv-errors": "^0.3.1", + "@babel/core": "^7.24.4", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.2", + "@rollup/plugin-babel": "^5.2.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-replace": "^2.4.1", + "@rollup/plugin-terser": "^0.4.3", + "@surma/rollup-plugin-off-main-thread": "^2.2.3", + "ajv": "^8.6.0", + "common-tags": "^1.8.0", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "lodash": "^4.17.20", + "pretty-bytes": "^5.3.0", + "rollup": "^2.43.1", + "source-map": "^0.8.0-beta.0", + "stringify-object": "^3.3.0", + "strip-comments": "^2.0.1", + "tempy": "^0.6.0", + "upath": "^1.2.0", + "workbox-background-sync": "7.3.0", + "workbox-broadcast-update": "7.3.0", + "workbox-cacheable-response": "7.3.0", + "workbox-core": "7.3.0", + "workbox-expiration": "7.3.0", + "workbox-google-analytics": "7.3.0", + "workbox-navigation-preload": "7.3.0", + "workbox-precaching": "7.3.0", + "workbox-range-requests": "7.3.0", + "workbox-recipes": "7.3.0", + "workbox-routing": "7.3.0", + "workbox-strategies": "7.3.0", + "workbox-streams": "7.3.0", + "workbox-sw": "7.3.0", + "workbox-window": "7.3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/workbox-build/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/workbox-build/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/workbox-build/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/workbox-build/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/workbox-build/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/workbox-build/node_modules/rollup": { + "version": "2.79.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", + "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/workbox-cacheable-response": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-7.3.0.tgz", + "integrity": "sha512-eAFERIg6J2LuyELhLlmeRcJFa5e16Mj8kL2yCDbhWE+HUun9skRQrGIFVUagqWj4DMaaPSMWfAolM7XZZxNmxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.3.0" + } + }, + "node_modules/workbox-core": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-7.3.0.tgz", + "integrity": "sha512-Z+mYrErfh4t3zi7NVTvOuACB0A/jA3bgxUN3PwtAVHvfEsZxV9Iju580VEETug3zYJRc0Dmii/aixI/Uxj8fmw==", + "license": "MIT" + }, + "node_modules/workbox-expiration": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-7.3.0.tgz", + "integrity": "sha512-lpnSSLp2BM+K6bgFCWc5bS1LR5pAwDWbcKt1iL87/eTSJRdLdAwGQznZE+1czLgn/X05YChsrEegTNxjM067vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "7.3.0" + } + }, + "node_modules/workbox-google-analytics": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-7.3.0.tgz", + "integrity": "sha512-ii/tSfFdhjLHZ2BrYgFNTrb/yk04pw2hasgbM70jpZfLk0vdJAXgaiMAWsoE+wfJDNWoZmBYY0hMVI0v5wWDbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-background-sync": "7.3.0", + "workbox-core": "7.3.0", + "workbox-routing": "7.3.0", + "workbox-strategies": "7.3.0" + } + }, + "node_modules/workbox-navigation-preload": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-7.3.0.tgz", + "integrity": "sha512-fTJzogmFaTv4bShZ6aA7Bfj4Cewaq5rp30qcxl2iYM45YD79rKIhvzNHiFj1P+u5ZZldroqhASXwwoyusnr2cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.3.0" + } + }, + "node_modules/workbox-precaching": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-7.3.0.tgz", + "integrity": "sha512-ckp/3t0msgXclVAYaNndAGeAoWQUv7Rwc4fdhWL69CCAb2UHo3Cef0KIUctqfQj1p8h6aGyz3w8Cy3Ihq9OmIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.3.0", + "workbox-routing": "7.3.0", + "workbox-strategies": "7.3.0" + } + }, + "node_modules/workbox-range-requests": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-7.3.0.tgz", + "integrity": "sha512-EyFmM1KpDzzAouNF3+EWa15yDEenwxoeXu9bgxOEYnFfCxns7eAxA9WSSaVd8kujFFt3eIbShNqa4hLQNFvmVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.3.0" + } + }, + "node_modules/workbox-recipes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-7.3.0.tgz", + "integrity": "sha512-BJro/MpuW35I/zjZQBcoxsctgeB+kyb2JAP5EB3EYzePg8wDGoQuUdyYQS+CheTb+GhqJeWmVs3QxLI8EBP1sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-cacheable-response": "7.3.0", + "workbox-core": "7.3.0", + "workbox-expiration": "7.3.0", + "workbox-precaching": "7.3.0", + "workbox-routing": "7.3.0", + "workbox-strategies": "7.3.0" + } + }, + "node_modules/workbox-routing": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-7.3.0.tgz", + "integrity": "sha512-ZUlysUVn5ZUzMOmQN3bqu+gK98vNfgX/gSTZ127izJg/pMMy4LryAthnYtjuqcjkN4HEAx1mdgxNiKJMZQM76A==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.3.0" + } + }, + "node_modules/workbox-strategies": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-7.3.0.tgz", + "integrity": "sha512-tmZydug+qzDFATwX7QiEL5Hdf7FrkhjaF9db1CbB39sDmEZJg3l9ayDvPxy8Y18C3Y66Nrr9kkN1f/RlkDgllg==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.3.0" + } + }, + "node_modules/workbox-streams": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-7.3.0.tgz", + "integrity": "sha512-SZnXucyg8x2Y61VGtDjKPO5EgPUG5NDn/v86WYHX+9ZqvAsGOytP0Jxp1bl663YUuMoXSAtsGLL+byHzEuMRpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.3.0", + "workbox-routing": "7.3.0" + } + }, + "node_modules/workbox-sw": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-7.3.0.tgz", + "integrity": "sha512-aCUyoAZU9IZtH05mn0ACUpyHzPs0lMeJimAYkQkBsOWiqaJLgusfDCR+yllkPkFRxWpZKF8vSvgHYeG7LwhlmA==", + "dev": true, + "license": "MIT" + }, + "node_modules/workbox-window": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-7.3.0.tgz", + "integrity": "sha512-qW8PDy16OV1UBaUNGlTVcepzrlzyzNW/ZJvFQQs2j2TzGsg6IKjcpZC1RSquqQnTOafl5pCj5bGfAHlCjOOjdA==", + "license": "MIT", + "dependencies": { + "@types/trusted-types": "^2.0.2", + "workbox-core": "7.3.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yup": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.7.0.tgz", + "integrity": "sha512-VJce62dBd+JQvoc+fCVq+KZfPHr+hXaxCcVgotfwWvlR0Ja3ffYKaJBT8rptPOSKOGJDCUnW2C2JWpud7aRP6Q==", + "license": "MIT", + "dependencies": { + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + } + }, + "node_modules/yup/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/apps/web/package.json b/apps/web/package.json new file mode 100644 index 0000000..283ef84 --- /dev/null +++ b/apps/web/package.json @@ -0,0 +1,64 @@ +{ + "name": "dramaling-web", + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite --host", + "build": "vue-tsc --noEmit && vite build", + "preview": "vite preview", + "test": "vitest", + "test:ui": "vitest --ui", + "test:coverage": "vitest --coverage", + "test:e2e": "cypress run", + "test:e2e:dev": "cypress open", + "lint": "eslint . --ext .vue,.ts,.tsx --fix", + "lint:style": "stylelint **/*.{css,scss,vue} --fix", + "type-check": "vue-tsc --noEmit", + "prepare": "husky install" + }, + "dependencies": { + "vue": "^3.4.21", + "vue-router": "^4.3.0", + "pinia": "^2.1.7", + "pinia-plugin-persistedstate": "^3.2.1", + "quasar": "^2.16.0", + "@quasar/extras": "^1.16.4", + "axios": "^1.6.8", + "vee-validate": "^4.12.6", + "yup": "^1.4.0", + "lodash-es": "^4.17.21", + "dayjs": "^1.11.10", + "dompurify": "^3.0.11", + "@vueuse/core": "^10.9.0", + "workbox-window": "^7.0.0" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.0.4", + "vite": "^5.2.0", + "vue-tsc": "^2.0.6", + "typescript": "^5.4.0", + "@types/node": "^20.12.7", + "@types/lodash-es": "^4.17.12", + "@types/dompurify": "^3.0.5", + "vitest": "^1.5.0", + "@vue/test-utils": "^2.4.5", + "happy-dom": "^14.7.1", + "@vitest/coverage-v8": "^1.5.0", + "@vitest/ui": "^1.5.0", + "cypress": "^13.7.2", + "eslint": "^9.1.1", + "@vue/eslint-config-typescript": "^13.0.0", + "@vue/eslint-config-prettier": "^9.0.0", + "prettier": "^3.2.5", + "stylelint": "^16.4.0", + "stylelint-config-standard-scss": "^13.1.0", + "stylelint-config-standard-vue": "^1.0.0", + "husky": "^9.0.11", + "lint-staged": "^15.2.2", + "unplugin-vue-components": "^0.27.0", + "unplugin-auto-import": "^0.17.5", + "vite-plugin-pwa": "^0.20.0", + "@quasar/vite-plugin": "^1.6.0", + "sass": "^1.77.0" + } +} \ No newline at end of file diff --git a/apps/web/src/App.vue b/apps/web/src/App.vue new file mode 100644 index 0000000..19b155f --- /dev/null +++ b/apps/web/src/App.vue @@ -0,0 +1,123 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/assets/styles/main.scss b/apps/web/src/assets/styles/main.scss new file mode 100644 index 0000000..913d7e4 --- /dev/null +++ b/apps/web/src/assets/styles/main.scss @@ -0,0 +1,328 @@ +// Drama Ling 主要樣式檔案 +@import './variables'; + +// ===== 全域重置 ===== + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + font-size: 16px; + line-height: 1.6; +} + +body { + font-family: $font-family-primary; + background: $background-primary; + color: $text-primary; + overflow-x: hidden; +} + +// ===== 全域樣式類 ===== + +// 文字樣式 +.text-primary { color: $text-primary; } +.text-secondary { color: $text-secondary; } +.text-tertiary { color: $text-tertiary; } + +.text-xs { font-size: $text-xs; } +.text-sm { font-size: $text-sm; } +.text-base { font-size: $text-base; } +.text-lg { font-size: $text-lg; } +.text-xl { font-size: $text-xl; } +.text-2xl { font-size: $text-2xl; } +.text-3xl { font-size: $text-3xl; } +.text-4xl { font-size: $text-4xl; } + +// 背景樣式 +.bg-primary { background: $background-primary; } +.bg-secondary { background: $background-secondary; } +.bg-dark { background: $background-dark; } +.bg-card { background: $card-background; } + +// 間距工具類 +.p-1 { padding: $space-1; } +.p-2 { padding: $space-2; } +.p-3 { padding: $space-3; } +.p-4 { padding: $space-4; } +.p-5 { padding: $space-5; } +.p-6 { padding: $space-6; } +.p-8 { padding: $space-8; } + +.m-1 { margin: $space-1; } +.m-2 { margin: $space-2; } +.m-3 { margin: $space-3; } +.m-4 { margin: $space-4; } +.m-5 { margin: $space-5; } +.m-6 { margin: $space-6; } +.m-8 { margin: $space-8; } + +// ===== 動畫效果 ===== + +// 頁面轉場 +.page-enter-active, +.page-leave-active { + transition: all 0.3s ease; +} + +.page-enter-from { + opacity: 0; + transform: translateY(20px); +} + +.page-leave-to { + opacity: 0; + transform: translateY(-20px); +} + +// 彈出動畫 +@keyframes popup { + 0% { + transform: scale(0) rotate(-360deg); + opacity: 0; + } + 100% { + transform: scale(1) rotate(0deg); + opacity: 1; + } +} + +.popup-enter { + animation: popup 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards; +} + +// 脈衝動畫 +@keyframes pulse { + 0%, 100% { transform: scale(1); } + 50% { transform: scale(1.05); } +} + +.pulse { + animation: pulse 2s infinite; +} + +// 旋轉動畫 +@keyframes rotate { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.rotate { + animation: rotate 2s linear infinite; +} + +// ===== 滾動條樣式 ===== + +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: $background-secondary; + border-radius: $radius-sm; +} + +::-webkit-scrollbar-thumb { + background: $primary-teal; + border-radius: $radius-sm; + + &:hover { + background: $primary-teal-light; + } +} + +// ===== 響應式工具類 ===== + +.hidden { display: none; } + +@include respond-to(xs) { + .hidden-xs { display: none; } + .visible-xs { display: block; } +} + +@include respond-to(sm) { + .hidden-sm { display: none; } + .visible-sm { display: block; } +} + +@include respond-to(md) { + .hidden-md { display: none; } + .visible-md { display: block; } +} + +@include respond-to(lg) { + .hidden-lg { display: none; } + .visible-lg { display: block; } +} + +// ===== 按鈕基礎樣式 ===== + +.btn-base { + display: inline-flex; + align-items: center; + justify-content: center; + gap: $space-2; + font-weight: 600; + border: none; + border-radius: $radius-lg; + cursor: pointer; + transition: all 0.3s ease; + text-decoration: none; + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + } +} + +.btn-primary { + @extend .btn-base; + background: $primary-teal; + color: $background-dark; + padding: $space-4 $space-6; + + &:hover:not(:disabled) { + background: $primary-teal-light; + transform: translateY(-2px); + box-shadow: 0 8px 25px rgba(0, 229, 204, 0.3); + } +} + +.btn-secondary { + @extend .btn-base; + background: transparent; + color: $primary-teal; + border: 2px solid $primary-teal; + padding: $space-3 $space-5; + + &:hover:not(:disabled) { + background: rgba($primary-teal, 0.1); + transform: translateY(-1px); + } +} + +// ===== 輸入框基礎樣式 ===== + +.input-base { + width: 100%; + padding: $space-4 $space-5; + background: $background-secondary; + border: 2px solid $divider; + border-radius: $radius-lg; + font-size: $text-base; + color: $text-primary; + transition: all 0.3s ease; + + &::placeholder { + color: $text-secondary; + } + + &:focus { + outline: none; + background: $card-background; + border-color: $primary-teal; + box-shadow: 0 0 0 4px rgba(0, 229, 204, 0.15); + } + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + } +} + +// ===== 卡片基礎樣式 ===== + +.card-base { + background: $card-background; + border-radius: $radius-xl; + padding: $space-6; + @include card-shadow(1); + border: 1px solid $divider; + transition: all 0.3s ease; + + &:hover { + transform: translateY(-2px); + @include card-shadow(2); + } +} + +// ===== 遊戲化元素樣式 ===== + +.level-badge { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 32px; + height: 24px; + background: $level-background; + color: white; + border-radius: $radius-full; + font-size: $text-sm; + font-weight: 700; + padding: 0 $space-2; +} + +.exp-bar { + height: 8px; + background: $background-secondary; + border-radius: $radius-full; + overflow: hidden; + + &-fill { + height: 100%; + background: linear-gradient(90deg, $primary-teal, $primary-teal-light); + border-radius: $radius-full; + transition: width 1s ease; + } +} + +.star-rating { + display: inline-flex; + gap: $space-1; + + .star { + width: 16px; + height: 16px; + color: $star-inactive; + + &.active { + color: $star-active; + } + } +} + +// ===== 無障礙樣式 ===== + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +// 焦點樣式 +*:focus-visible { + outline: 2px solid $primary-teal; + outline-offset: 2px; +} + +// ===== 載入狀態 ===== + +.loading-spinner { + display: inline-block; + width: 20px; + height: 20px; + border: 2px solid transparent; + border-top: 2px solid $primary-teal; + border-radius: 50%; + animation: rotate 1s linear infinite; +} \ No newline at end of file diff --git a/apps/web/src/assets/styles/quasar-variables.sass b/apps/web/src/assets/styles/quasar-variables.sass new file mode 100644 index 0000000..3d46aa6 --- /dev/null +++ b/apps/web/src/assets/styles/quasar-variables.sass @@ -0,0 +1,56 @@ +// Quasar SASS Variables +// This file is used by Quasar to customize default component styles + +// Brand colors +$primary : #1976D2 +$secondary : #26A69A +$accent : #9C27B0 + +$dark : #1D1D1D +$dark-page : #121212 + +$positive : #21BA45 +$negative : #C10015 +$info : #31CCEC +$warning : #F2C037 + +// Typography +$h1 : 2rem +$h2 : 1.5rem +$h3 : 1.25rem +$h4 : 1.125rem +$h5 : 1rem +$h6 : 0.875rem + +$body-font-size : 0.875rem +$body-line-height : 1.5 + +// Spacing +$space-xs : 0.25rem +$space-sm : 0.5rem +$space-md : 1rem +$space-lg : 1.5rem +$space-xl : 3rem + +// Borders +$generic-border-radius : 4px +$button-border-radius : 4px +$input-border-radius : 4px + +// Shadows +$shadow-1: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24) +$shadow-2: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23) + +// Custom Drama Ling Theme Variables +$drama-primary : #00E5CC +$drama-secondary : #FF6B6B +$drama-accent : #4ECDC4 +$drama-background : #F7F9FC +$drama-surface : #FFFFFF +$drama-text : #2C3E50 +$drama-text-light : #7F8C8D + +// Override Quasar defaults with Drama Ling theme +$primary : $drama-primary +$secondary : $drama-secondary +$accent : $drama-accent \ No newline at end of file diff --git a/apps/web/src/assets/styles/variables.scss b/apps/web/src/assets/styles/variables.scss new file mode 100644 index 0000000..4153a10 --- /dev/null +++ b/apps/web/src/assets/styles/variables.scss @@ -0,0 +1,171 @@ +// Drama Ling Design System Variables + +// ===== 色彩系統 ===== + +// 主要品牌色 - 青綠色 +$primary-teal: #00E5CC; +$primary-teal-light: #33E8D1; +$primary-teal-dark: #00B3A0; + +// 輔助色 - 紫色系 +$secondary-purple: #8E44AD; +$secondary-purple-light: #A569BD; +$secondary-purple-dark: #6C3483; + +// 強調色 - 活力紫 +$accent-violet: #9B59B6; +$accent-violet-light: #BB8FCE; +$accent-violet-dark: #7D3C98; + +// 功能性色彩 +$error-red: #E74C3C; +$warning-yellow: #F39C12; +$warning-orange: #F39C12; // 別名 +$success-green: #00E5CC; +$info-cyan: #3498DB; + +// 暗色主題色調 +$text-primary: #FFFFFF; +$text-primary-inverse: #2C3E50; // 反色文字 +$text-secondary: #B8BCC8; +$text-tertiary: #7F8C8D; +$background-primary: #2C3E50; +$background-secondary: #34495E; +$background-dark: #1A252F; +$divider: #4A5568; +$card-background: #3A4A5C; + +// 遊戲化色彩 +$star-active: #F1C40F; +$star-inactive: #7F8C8D; +$bronze: #CD7F32; +$silver: #C0C0C0; +$gold: #FFD700; +$diamond: #B9F2FF; +$exp-bar: #00E5CC; +$level-background: #8E44AD; +$achievement-glow: #F39C12; + +// ===== 字體系統 ===== + +// 字體家族 +$font-family-primary: 'Inter', 'PingFang TC', -apple-system, sans-serif; +$font-family-secondary: 'Roboto', 'Microsoft JhengHei UI', sans-serif; +$font-family-mono: 'JetBrains Mono', 'SF Mono', Monaco, monospace; + +// 字體大小 +$text-xs: 0.75rem; // 12px +$text-sm: 0.875rem; // 14px +$text-base: 1rem; // 16px +$text-lg: 1.125rem; // 18px +$text-xl: 1.25rem; // 20px +$text-2xl: 1.5rem; // 24px +$text-3xl: 1.875rem; // 30px +$text-4xl: 2.25rem; // 36px + +// 遊戲化特殊字體 +$text-game-score: 1.5rem; // 24px +$text-game-level: 0.875rem; // 14px +$text-game-title: 1.25rem; // 20px + +// ===== 間距系統 ===== + +$space-1: 0.25rem; // 4px +$space-2: 0.5rem; // 8px +$space-3: 0.75rem; // 12px +$space-4: 1rem; // 16px +$space-5: 1.25rem; // 20px +$space-6: 1.5rem; // 24px +$space-8: 2rem; // 32px +$space-10: 2.5rem; // 40px +$space-12: 3rem; // 48px +$space-16: 4rem; // 64px +$space-20: 5rem; // 80px + +// ===== 圓角和陰影 ===== + +$radius-sm: 0.5rem; // 8px +$radius-md: 0.75rem; // 12px +$radius-lg: 1rem; // 16px +$radius-xl: 1.5rem; // 24px +$radius-2xl: 2rem; // 32px +$radius-full: 50%; + +// 陰影系統 +$shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); +$shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1); +$shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1); +$shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1); + +// ===== 響應式斷點 ===== + +$breakpoint-xs: 0; +$breakpoint-sm: 640px; +$breakpoint-md: 768px; +$breakpoint-lg: 1024px; +$breakpoint-xl: 1280px; +$breakpoint-2xl: 1536px; + +// ===== Z-index 層級 ===== + +$z-dropdown: 1000; +$z-modal: 1050; +$z-popover: 1060; +$z-tooltip: 1070; +$z-toast: 1080; + +// ===== 混合器 ===== + +@mixin respond-to($breakpoint) { + @if $breakpoint == xs { + @media (max-width: #{$breakpoint-sm - 1px}) { @content; } + } + @if $breakpoint == sm { + @media (min-width: #{$breakpoint-sm}) and (max-width: #{$breakpoint-md - 1px}) { @content; } + } + @if $breakpoint == md { + @media (min-width: #{$breakpoint-md}) and (max-width: #{$breakpoint-lg - 1px}) { @content; } + } + @if $breakpoint == lg { + @media (min-width: #{$breakpoint-lg}) and (max-width: #{$breakpoint-xl - 1px}) { @content; } + } + @if $breakpoint == xl { + @media (min-width: #{$breakpoint-xl}) { @content; } + } +} + +@mixin text-ellipsis($lines: 1) { + @if $lines == 1 { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } @else { + display: -webkit-box; + -webkit-line-clamp: $lines; + -webkit-box-orient: vertical; + overflow: hidden; + } +} + +@mixin card-shadow($level: 1) { + @if $level == 1 { + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + } + @if $level == 2 { + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.08); + } + @if $level == 3 { + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15), 0 4px 8px rgba(0, 0, 0, 0.1); + } +} + +@mixin loading-skeleton { + background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); + background-size: 200% 100%; + animation: loading 1.5s infinite; +} + +@keyframes loading { + 0% { background-position: 200% 0; } + 100% { background-position: -200% 0; } +} \ No newline at end of file diff --git a/apps/web/src/components/base/BaseButton.vue b/apps/web/src/components/base/BaseButton.vue new file mode 100644 index 0000000..3c5ab67 --- /dev/null +++ b/apps/web/src/components/base/BaseButton.vue @@ -0,0 +1,109 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/components/base/BaseCard.vue b/apps/web/src/components/base/BaseCard.vue new file mode 100644 index 0000000..94046a3 --- /dev/null +++ b/apps/web/src/components/base/BaseCard.vue @@ -0,0 +1,60 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/components/base/BaseInput.vue b/apps/web/src/components/base/BaseInput.vue new file mode 100644 index 0000000..c51f112 --- /dev/null +++ b/apps/web/src/components/base/BaseInput.vue @@ -0,0 +1,155 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/components/base/BaseModal.vue b/apps/web/src/components/base/BaseModal.vue new file mode 100644 index 0000000..8903c1e --- /dev/null +++ b/apps/web/src/components/base/BaseModal.vue @@ -0,0 +1,217 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/components/ui/ModalContainer.vue b/apps/web/src/components/ui/ModalContainer.vue new file mode 100644 index 0000000..dcb90e8 --- /dev/null +++ b/apps/web/src/components/ui/ModalContainer.vue @@ -0,0 +1,127 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/components/ui/ToastContainer.vue b/apps/web/src/components/ui/ToastContainer.vue new file mode 100644 index 0000000..280ecb4 --- /dev/null +++ b/apps/web/src/components/ui/ToastContainer.vue @@ -0,0 +1,219 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/layouts/AppLayout.vue b/apps/web/src/layouts/AppLayout.vue new file mode 100644 index 0000000..13e0e4c --- /dev/null +++ b/apps/web/src/layouts/AppLayout.vue @@ -0,0 +1,545 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/layouts/AuthLayout.vue b/apps/web/src/layouts/AuthLayout.vue new file mode 100644 index 0000000..993fe88 --- /dev/null +++ b/apps/web/src/layouts/AuthLayout.vue @@ -0,0 +1,333 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/main.ts b/apps/web/src/main.ts new file mode 100644 index 0000000..2d9c83a --- /dev/null +++ b/apps/web/src/main.ts @@ -0,0 +1,56 @@ +import { createApp } from 'vue' +import { Quasar, Notify, Loading, Dialog } from 'quasar' +import App from './App.vue' +import router from './router' +import { pinia } from './stores' + +// Quasar樣式 +import 'quasar/dist/quasar.css' +import '@quasar/extras/material-icons/material-icons.css' +import '@quasar/extras/material-icons-outlined/material-icons-outlined.css' +import '@quasar/extras/material-icons-round/material-icons-round.css' + +// 自定義樣式 +// import './assets/styles/main.scss' + +const app = createApp(App) + +// 配置 Quasar +app.use(Quasar, { + plugins: { + Notify, + Loading, + Dialog + }, + config: { + notify: { + position: 'top-right', + timeout: 5000 + }, + loading: { + backgroundColor: 'rgba(0, 0, 0, 0.4)', + spinnerColor: '#00E5CC', + messageColor: 'white' + } + } +}) + +// 配置 Pinia +app.use(pinia) + +// 配置 Vue Router +app.use(router) + +// 全局錯誤處理 +app.config.errorHandler = (err, instance, info) => { + console.error('Vue Error:', err) + console.error('Error Info:', info) + + // 在生產環境中可以發送錯誤到監控服務 + if (import.meta.env.PROD) { + // 發送錯誤報告 + console.error('Production Error:', { err, info }) + } +} + +app.mount('#app') \ No newline at end of file diff --git a/apps/web/src/router/index-full.ts b/apps/web/src/router/index-full.ts new file mode 100644 index 0000000..53fdfd7 --- /dev/null +++ b/apps/web/src/router/index-full.ts @@ -0,0 +1,210 @@ +import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router' +import { useAuthStore } from '@/stores/auth' + +const routes: RouteRecordRaw[] = [ + { + path: '/', + name: 'home', + component: () => import('@/views/HomeView.vue'), + meta: { + title: 'Drama Ling - 戲劇式語言學習', + requiresAuth: false + } + }, + { + path: '/auth', + component: () => import('@/layouts/AuthLayout.vue'), + children: [ + { + path: 'login', + name: 'login', + component: () => import('@/views/auth/LoginView.vue'), + meta: { + title: '登入 - Drama Ling', + requiresAuth: false + } + }, + { + path: 'register', + name: 'register', + component: () => import('@/views/auth/RegisterView.vue'), + meta: { + title: '註冊 - Drama Ling', + requiresAuth: false + } + }, + { + path: 'forgot-password', + name: 'forgot-password', + component: () => import('@/views/auth/ForgotPasswordView.vue'), + meta: { + title: '忘記密碼 - Drama Ling', + requiresAuth: false + } + } + ] + }, + { + path: '/learning', + component: () => import('@/layouts/AppLayout.vue'), + meta: { requiresAuth: true }, + children: [ + { + path: '', + name: 'learning', + component: () => import('@/views/learning/LearningHomeView.vue'), + meta: { + title: '學習地圖 - Drama Ling' + } + }, + { + path: 'vocabulary', + name: 'vocabulary', + component: () => import('@/views/learning/VocabularyView.vue'), + meta: { + title: '詞彙學習 - Drama Ling' + } + }, + { + path: 'dialogue/:id', + name: 'dialogue', + component: () => import('@/views/learning/DialogueView.vue'), + meta: { + title: '對話練習 - Drama Ling' + }, + props: true + }, + { + path: 'roleplay/:id', + name: 'roleplay', + component: () => import('@/views/learning/RoleplayView.vue'), + meta: { + title: '角色扮演 - Drama Ling' + }, + props: true + }, + { + path: 'pronunciation/:id', + name: 'pronunciation', + component: () => import('@/views/learning/PronunciationView.vue'), + meta: { + title: '發音練習 - Drama Ling' + }, + props: true + } + ] + }, + { + path: '/profile', + component: () => import('@/layouts/AppLayout.vue'), + meta: { requiresAuth: true }, + children: [ + { + path: '', + name: 'profile', + component: () => import('@/views/profile/ProfileView.vue'), + meta: { + title: '個人檔案 - Drama Ling' + } + }, + { + path: 'progress', + name: 'progress', + component: () => import('@/views/profile/ProgressView.vue'), + meta: { + title: '學習進度 - Drama Ling' + } + }, + { + path: 'settings', + name: 'settings', + component: () => import('@/views/profile/SettingsView.vue'), + meta: { + title: '設定 - Drama Ling' + } + } + ] + }, + { + path: '/shop', + component: () => import('@/layouts/AppLayout.vue'), + meta: { requiresAuth: true }, + children: [ + { + path: '', + name: 'shop', + component: () => import('@/views/shop/ShopView.vue'), + meta: { + title: '商店 - Drama Ling' + } + }, + { + path: 'subscription', + name: 'subscription', + component: () => import('@/views/shop/SubscriptionView.vue'), + meta: { + title: '訂閱方案 - Drama Ling' + } + } + ] + }, + { + path: '/offline', + name: 'offline', + component: () => import('@/views/OfflineView.vue'), + meta: { + title: '離線模式 - Drama Ling', + requiresAuth: false + } + }, + { + path: '/:pathMatch(.*)*', + name: 'not-found', + component: () => import('@/views/NotFoundView.vue'), + meta: { + title: '頁面未找到 - Drama Ling', + requiresAuth: false + } + } +] + +const router = createRouter({ + history: createWebHistory(), + routes, + scrollBehavior(to, from, savedPosition) { + if (savedPosition) { + return savedPosition + } + if (to.hash) { + return { el: to.hash } + } + return { top: 0 } + } +}) + +router.beforeEach(async (to, from, next) => { + const authStore = useAuthStore() + + // 設定頁面標題 + if (to.meta.title) { + document.title = to.meta.title as string + } + + // 檢查認證需求 + if (to.meta.requiresAuth && !authStore.isAuthenticated) { + // 保存目標路徑,登入後跳轉 + authStore.setRedirectPath(to.fullPath) + next({ name: 'login' }) + return + } + + // 已登入用戶訪問登入頁面時跳轉到首頁 + if ((to.name === 'login' || to.name === 'register') && authStore.isAuthenticated) { + next({ name: 'learning' }) + return + } + + next() +}) + +export default router \ No newline at end of file diff --git a/apps/web/src/router/index-minimal.ts b/apps/web/src/router/index-minimal.ts new file mode 100644 index 0000000..d96ee6b --- /dev/null +++ b/apps/web/src/router/index-minimal.ts @@ -0,0 +1,20 @@ +import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router' + +const routes: RouteRecordRaw[] = [ + { + path: '/', + name: 'home', + component: () => import('@/views/HomeView.vue'), + meta: { + title: 'Drama Ling - 戲劇式語言學習', + description: 'AI驅動的情境式語言學習應用' + } + } +] + +const router = createRouter({ + history: createWebHistory(), + routes +}) + +export default router \ No newline at end of file diff --git a/apps/web/src/router/index.ts b/apps/web/src/router/index.ts new file mode 100644 index 0000000..53fdfd7 --- /dev/null +++ b/apps/web/src/router/index.ts @@ -0,0 +1,210 @@ +import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router' +import { useAuthStore } from '@/stores/auth' + +const routes: RouteRecordRaw[] = [ + { + path: '/', + name: 'home', + component: () => import('@/views/HomeView.vue'), + meta: { + title: 'Drama Ling - 戲劇式語言學習', + requiresAuth: false + } + }, + { + path: '/auth', + component: () => import('@/layouts/AuthLayout.vue'), + children: [ + { + path: 'login', + name: 'login', + component: () => import('@/views/auth/LoginView.vue'), + meta: { + title: '登入 - Drama Ling', + requiresAuth: false + } + }, + { + path: 'register', + name: 'register', + component: () => import('@/views/auth/RegisterView.vue'), + meta: { + title: '註冊 - Drama Ling', + requiresAuth: false + } + }, + { + path: 'forgot-password', + name: 'forgot-password', + component: () => import('@/views/auth/ForgotPasswordView.vue'), + meta: { + title: '忘記密碼 - Drama Ling', + requiresAuth: false + } + } + ] + }, + { + path: '/learning', + component: () => import('@/layouts/AppLayout.vue'), + meta: { requiresAuth: true }, + children: [ + { + path: '', + name: 'learning', + component: () => import('@/views/learning/LearningHomeView.vue'), + meta: { + title: '學習地圖 - Drama Ling' + } + }, + { + path: 'vocabulary', + name: 'vocabulary', + component: () => import('@/views/learning/VocabularyView.vue'), + meta: { + title: '詞彙學習 - Drama Ling' + } + }, + { + path: 'dialogue/:id', + name: 'dialogue', + component: () => import('@/views/learning/DialogueView.vue'), + meta: { + title: '對話練習 - Drama Ling' + }, + props: true + }, + { + path: 'roleplay/:id', + name: 'roleplay', + component: () => import('@/views/learning/RoleplayView.vue'), + meta: { + title: '角色扮演 - Drama Ling' + }, + props: true + }, + { + path: 'pronunciation/:id', + name: 'pronunciation', + component: () => import('@/views/learning/PronunciationView.vue'), + meta: { + title: '發音練習 - Drama Ling' + }, + props: true + } + ] + }, + { + path: '/profile', + component: () => import('@/layouts/AppLayout.vue'), + meta: { requiresAuth: true }, + children: [ + { + path: '', + name: 'profile', + component: () => import('@/views/profile/ProfileView.vue'), + meta: { + title: '個人檔案 - Drama Ling' + } + }, + { + path: 'progress', + name: 'progress', + component: () => import('@/views/profile/ProgressView.vue'), + meta: { + title: '學習進度 - Drama Ling' + } + }, + { + path: 'settings', + name: 'settings', + component: () => import('@/views/profile/SettingsView.vue'), + meta: { + title: '設定 - Drama Ling' + } + } + ] + }, + { + path: '/shop', + component: () => import('@/layouts/AppLayout.vue'), + meta: { requiresAuth: true }, + children: [ + { + path: '', + name: 'shop', + component: () => import('@/views/shop/ShopView.vue'), + meta: { + title: '商店 - Drama Ling' + } + }, + { + path: 'subscription', + name: 'subscription', + component: () => import('@/views/shop/SubscriptionView.vue'), + meta: { + title: '訂閱方案 - Drama Ling' + } + } + ] + }, + { + path: '/offline', + name: 'offline', + component: () => import('@/views/OfflineView.vue'), + meta: { + title: '離線模式 - Drama Ling', + requiresAuth: false + } + }, + { + path: '/:pathMatch(.*)*', + name: 'not-found', + component: () => import('@/views/NotFoundView.vue'), + meta: { + title: '頁面未找到 - Drama Ling', + requiresAuth: false + } + } +] + +const router = createRouter({ + history: createWebHistory(), + routes, + scrollBehavior(to, from, savedPosition) { + if (savedPosition) { + return savedPosition + } + if (to.hash) { + return { el: to.hash } + } + return { top: 0 } + } +}) + +router.beforeEach(async (to, from, next) => { + const authStore = useAuthStore() + + // 設定頁面標題 + if (to.meta.title) { + document.title = to.meta.title as string + } + + // 檢查認證需求 + if (to.meta.requiresAuth && !authStore.isAuthenticated) { + // 保存目標路徑,登入後跳轉 + authStore.setRedirectPath(to.fullPath) + next({ name: 'login' }) + return + } + + // 已登入用戶訪問登入頁面時跳轉到首頁 + if ((to.name === 'login' || to.name === 'register') && authStore.isAuthenticated) { + next({ name: 'learning' }) + return + } + + next() +}) + +export default router \ No newline at end of file diff --git a/apps/web/src/stores/auth.ts b/apps/web/src/stores/auth.ts new file mode 100644 index 0000000..02f5e31 --- /dev/null +++ b/apps/web/src/stores/auth.ts @@ -0,0 +1,286 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import type { User } from '@/types/user' + +export interface LoginCredentials { + email: string + password: string + rememberMe?: boolean +} + +export interface RegisterData { + email: string + password: string + confirmPassword: string + username: string + agreeToTerms: boolean +} + +export const useAuthStore = defineStore('auth', () => { + // 狀態 + const user = ref(null) + const token = ref(null) + const refreshToken = ref(null) + const isLoading = ref(false) + const error = ref(null) + const redirectPath = ref('/') + + // 計算屬性 + const isAuthenticated = computed(() => !!token.value && !!user.value) + const userDisplayName = computed(() => user.value?.username || user.value?.email || '') + + // 動作 + const login = async (credentials: LoginCredentials) => { + isLoading.value = true + error.value = null + + try { + // TODO: 實際API調用 + const response = await fetch('/api/auth/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(credentials) + }) + + if (!response.ok) { + throw new Error('登入失敗') + } + + const data = await response.json() + + // 設定認證資料 + token.value = data.token + refreshToken.value = data.refreshToken + user.value = data.user + + return { success: true } + } catch (err) { + error.value = err instanceof Error ? err.message : '登入失敗' + return { success: false, error: error.value } + } finally { + isLoading.value = false + } + } + + const register = async (data: RegisterData) => { + isLoading.value = true + error.value = null + + try { + // TODO: 實際API調用 + const response = await fetch('/api/auth/register', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }) + + if (!response.ok) { + throw new Error('註冊失敗') + } + + const responseData = await response.json() + + // 自動登入 + token.value = responseData.token + refreshToken.value = responseData.refreshToken + user.value = responseData.user + + return { success: true } + } catch (err) { + error.value = err instanceof Error ? err.message : '註冊失敗' + return { success: false, error: error.value } + } finally { + isLoading.value = false + } + } + + const logout = async () => { + isLoading.value = true + + try { + // TODO: 呼叫登出API + if (token.value) { + await fetch('/api/auth/logout', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${token.value}` + } + }) + } + } catch (err) { + console.error('登出API錯誤:', err) + } finally { + // 清除本地狀態 + user.value = null + token.value = null + refreshToken.value = null + error.value = null + isLoading.value = false + redirectPath.value = '/' + } + } + + const refreshTokenAction = async () => { + if (!refreshToken.value) { + return false + } + + try { + const response = await fetch('/api/auth/refresh', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + refreshToken: refreshToken.value + }) + }) + + if (!response.ok) { + throw new Error('Token刷新失敗') + } + + const data = await response.json() + token.value = data.token + + return true + } catch (err) { + console.error('Token刷新錯誤:', err) + await logout() + return false + } + } + + const updateProfile = async (profileData: Partial) => { + if (!user.value) return { success: false, error: '用戶未登入' } + + isLoading.value = true + error.value = null + + try { + const response = await fetch('/api/user/profile', { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token.value}` + }, + body: JSON.stringify(profileData) + }) + + if (!response.ok) { + throw new Error('更新檔案失敗') + } + + const updatedUser = await response.json() + user.value = { ...user.value, ...updatedUser } + + return { success: true } + } catch (err) { + error.value = err instanceof Error ? err.message : '更新檔案失敗' + return { success: false, error: error.value } + } finally { + isLoading.value = false + } + } + + const forgotPassword = async (email: string) => { + isLoading.value = true + error.value = null + + try { + const response = await fetch('/api/auth/forgot-password', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ email }) + }) + + if (!response.ok) { + throw new Error('發送重設密碼郵件失敗') + } + + return { success: true } + } catch (err) { + error.value = err instanceof Error ? err.message : '發送重設密碼郵件失敗' + return { success: false, error: error.value } + } finally { + isLoading.value = false + } + } + + const resetPassword = async (token: string, password: string) => { + isLoading.value = true + error.value = null + + try { + const response = await fetch('/api/auth/reset-password', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ token, password }) + }) + + if (!response.ok) { + throw new Error('重設密碼失敗') + } + + return { success: true } + } catch (err) { + error.value = err instanceof Error ? err.message : '重設密碼失敗' + return { success: false, error: error.value } + } finally { + isLoading.value = false + } + } + + const setRedirectPath = (path: string) => { + redirectPath.value = path + } + + const clearError = () => { + error.value = null + } + + const initialize = async () => { + // 應用啟動時檢查是否有有效的token + if (token.value && !user.value) { + await refreshTokenAction() + } + } + + return { + // 狀態 + user, + token, + refreshToken, + isLoading, + error, + redirectPath, + + // 計算屬性 + isAuthenticated, + userDisplayName, + + // 動作 + login, + register, + logout, + refreshTokenAction, + updateProfile, + forgotPassword, + resetPassword, + setRedirectPath, + clearError, + initialize + } +}, { + persist: { + paths: ['user', 'token', 'refreshToken', 'redirectPath'] + } +}) \ No newline at end of file diff --git a/apps/web/src/stores/index.ts b/apps/web/src/stores/index.ts new file mode 100644 index 0000000..6a739e6 --- /dev/null +++ b/apps/web/src/stores/index.ts @@ -0,0 +1,16 @@ +import { createPinia } from 'pinia' +import { createPersistedState } from 'pinia-plugin-persistedstate' + +const pinia = createPinia() + +// 配置持久化插件 +pinia.use(createPersistedState({ + storage: localStorage, + auto: true +})) + +export { pinia } +export * from './auth' +export * from './user' +export * from './learning' +export * from './ui' \ No newline at end of file diff --git a/apps/web/src/stores/learning.ts b/apps/web/src/stores/learning.ts new file mode 100644 index 0000000..cd577e2 --- /dev/null +++ b/apps/web/src/stores/learning.ts @@ -0,0 +1,364 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import type { Lesson, Course, LearningSession, VocabularyCard } from '@/types/learning' + +export const useLearningStore = defineStore('learning', () => { + // 狀態 + const currentCourse = ref(null) + const currentLesson = ref(null) + const currentSession = ref(null) + const vocabulary = ref([]) + const courses = ref([]) + const recentLessons = ref([]) + const isLoading = ref(false) + const error = ref(null) + + // 學習狀態 + const sessionStartTime = ref(null) + const currentQuestionIndex = ref(0) + const sessionAnswers = ref([]) + const sessionScore = ref(0) + + // 計算屬性 + const availableCourses = computed(() => { + return courses.value.filter(course => course.isAvailable) + }) + + const completedCourses = computed(() => { + return courses.value.filter(course => course.progress === 100) + }) + + const inProgressCourses = computed(() => { + return courses.value.filter(course => course.progress > 0 && course.progress < 100) + }) + + const currentProgress = computed(() => { + if (!currentCourse.value) return 0 + return currentCourse.value.progress || 0 + }) + + const sessionProgress = computed(() => { + if (!currentSession.value?.questions?.length) return 0 + return (currentQuestionIndex.value / currentSession.value.questions.length) * 100 + }) + + const masteredVocabulary = computed(() => { + return vocabulary.value.filter(card => card.masteryLevel >= 5) + }) + + const reviewDueVocabulary = computed(() => { + const now = new Date() + return vocabulary.value.filter(card => + card.nextReviewDate && new Date(card.nextReviewDate) <= now + ) + }) + + // 動作 + const fetchCourses = async () => { + isLoading.value = true + error.value = null + + try { + const response = await fetch('/api/learning/courses', { + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + } + }) + + if (!response.ok) { + throw new Error('獲取課程失敗') + } + + courses.value = await response.json() + } catch (err) { + error.value = err instanceof Error ? err.message : '獲取課程失敗' + } finally { + isLoading.value = false + } + } + + const fetchCourse = async (courseId: string) => { + isLoading.value = true + + try { + const response = await fetch(`/api/learning/courses/${courseId}`, { + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + } + }) + + if (!response.ok) { + throw new Error('獲取課程詳情失敗') + } + + currentCourse.value = await response.json() + } catch (err) { + error.value = err instanceof Error ? err.message : '獲取課程詳情失敗' + } finally { + isLoading.value = false + } + } + + const startLesson = async (lessonId: string) => { + isLoading.value = true + sessionStartTime.value = new Date() + currentQuestionIndex.value = 0 + sessionAnswers.value = [] + sessionScore.value = 0 + + try { + const response = await fetch(`/api/learning/lessons/${lessonId}/start`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + } + }) + + if (!response.ok) { + throw new Error('開始課程失敗') + } + + const sessionData = await response.json() + currentLesson.value = sessionData.lesson + currentSession.value = sessionData.session + + return { success: true } + } catch (err) { + error.value = err instanceof Error ? err.message : '開始課程失敗' + return { success: false, error: error.value } + } finally { + isLoading.value = false + } + } + + const submitAnswer = async (answer: any) => { + if (!currentSession.value) return { success: false } + + try { + const response = await fetch(`/api/learning/sessions/${currentSession.value.id}/answer`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${localStorage.getItem('token')}` + }, + body: JSON.stringify({ + questionIndex: currentQuestionIndex.value, + answer + }) + }) + + if (!response.ok) { + throw new Error('提交答案失敗') + } + + const result = await response.json() + + // 更新本地狀態 + sessionAnswers.value.push({ + questionIndex: currentQuestionIndex.value, + answer, + isCorrect: result.isCorrect, + feedback: result.feedback + }) + + if (result.isCorrect) { + sessionScore.value += result.points || 10 + } + + // 移動到下一題 + currentQuestionIndex.value += 1 + + return { + success: true, + isCorrect: result.isCorrect, + feedback: result.feedback, + points: result.points + } + } catch (err) { + error.value = err instanceof Error ? err.message : '提交答案失敗' + return { success: false, error: error.value } + } + } + + const completeSession = async () => { + if (!currentSession.value || !sessionStartTime.value) return { success: false } + + const duration = Date.now() - sessionStartTime.value.getTime() + + try { + const response = await fetch(`/api/learning/sessions/${currentSession.value.id}/complete`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${localStorage.getItem('token')}` + }, + body: JSON.stringify({ + duration, + score: sessionScore.value, + answers: sessionAnswers.value + }) + }) + + if (!response.ok) { + throw new Error('完成學習階段失敗') + } + + const result = await response.json() + + // 重設狀態 + currentSession.value = null + sessionStartTime.value = null + currentQuestionIndex.value = 0 + sessionAnswers.value = [] + sessionScore.value = 0 + + return { + success: true, + result + } + } catch (err) { + error.value = err instanceof Error ? err.message : '完成學習階段失敗' + return { success: false, error: error.value } + } + } + + const fetchVocabulary = async () => { + try { + const response = await fetch('/api/learning/vocabulary', { + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + } + }) + + if (!response.ok) { + throw new Error('獲取詞彙失敗') + } + + vocabulary.value = await response.json() + } catch (err) { + console.error('獲取詞彙錯誤:', err) + } + } + + const updateVocabularyMastery = async (cardId: string, isCorrect: boolean) => { + try { + const response = await fetch(`/api/learning/vocabulary/${cardId}/review`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${localStorage.getItem('token')}` + }, + body: JSON.stringify({ isCorrect }) + }) + + if (!response.ok) { + throw new Error('更新詞彙熟練度失敗') + } + + const updatedCard = await response.json() + + // 更新本地狀態 + const index = vocabulary.value.findIndex(card => card.id === cardId) + if (index !== -1) { + vocabulary.value[index] = updatedCard + } + + return { success: true } + } catch (err) { + console.error('更新詞彙熟練度錯誤:', err) + return { success: false } + } + } + + const pauseSession = () => { + if (currentSession.value) { + currentSession.value.isPaused = true + } + } + + const resumeSession = () => { + if (currentSession.value) { + currentSession.value.isPaused = false + } + } + + const skipQuestion = () => { + if (currentSession.value && currentQuestionIndex.value < currentSession.value.questions.length - 1) { + currentQuestionIndex.value += 1 + + // 記錄跳過的答案 + sessionAnswers.value.push({ + questionIndex: currentQuestionIndex.value - 1, + answer: null, + isCorrect: false, + skipped: true + }) + } + } + + const fetchRecentLessons = async () => { + try { + const response = await fetch('/api/learning/recent-lessons', { + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + } + }) + + if (!response.ok) { + throw new Error('獲取最近課程失敗') + } + + recentLessons.value = await response.json() + } catch (err) { + console.error('獲取最近課程錯誤:', err) + } + } + + const resetCurrentSession = () => { + currentSession.value = null + currentLesson.value = null + sessionStartTime.value = null + currentQuestionIndex.value = 0 + sessionAnswers.value = [] + sessionScore.value = 0 + } + + return { + // 狀態 + currentCourse, + currentLesson, + currentSession, + vocabulary, + courses, + recentLessons, + isLoading, + error, + sessionStartTime, + currentQuestionIndex, + sessionAnswers, + sessionScore, + + // 計算屬性 + availableCourses, + completedCourses, + inProgressCourses, + currentProgress, + sessionProgress, + masteredVocabulary, + reviewDueVocabulary, + + // 動作 + fetchCourses, + fetchCourse, + startLesson, + submitAnswer, + completeSession, + fetchVocabulary, + updateVocabularyMastery, + pauseSession, + resumeSession, + skipQuestion, + fetchRecentLessons, + resetCurrentSession + } +}) \ No newline at end of file diff --git a/apps/web/src/stores/ui.ts b/apps/web/src/stores/ui.ts new file mode 100644 index 0000000..583c529 --- /dev/null +++ b/apps/web/src/stores/ui.ts @@ -0,0 +1,280 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' + +export interface Toast { + id: string + type: 'success' | 'error' | 'warning' | 'info' + title: string + message?: string + duration?: number + persistent?: boolean +} + +export interface Modal { + id: string + component: any + props?: Record + persistent?: boolean +} + +export const useUIStore = defineStore('ui', () => { + // 狀態 + const theme = ref<'light' | 'dark' | 'auto'>('auto') + const sidebarCollapsed = ref(false) + const mobileMenuOpen = ref(false) + const loading = ref(false) + const toasts = ref([]) + const modals = ref([]) + const currentModal = ref(null) + + // 頁面狀態 + const pageTitle = ref('Drama Ling') + const breadcrumbs = ref<{ label: string; to?: string }[]>([]) + const headerActions = ref([]) + + // 響應式狀態 + const isMobile = ref(false) + const screenWidth = ref(0) + const screenHeight = ref(0) + + // 計算屬性 + const isDarkMode = computed(() => { + if (theme.value === 'auto') { + return window.matchMedia('(prefers-color-scheme: dark)').matches + } + return theme.value === 'dark' + }) + + const activeToasts = computed(() => { + return toasts.value.filter(toast => !toast.persistent || Date.now() - parseInt(toast.id) < (toast.duration || 5000)) + }) + + // 動作 + const setTheme = (newTheme: 'light' | 'dark' | 'auto') => { + theme.value = newTheme + + // 應用主題到 HTML 元素 + const html = document.documentElement + if (newTheme === 'auto') { + html.classList.remove('dark', 'light') + } else { + html.classList.remove('dark', 'light') + html.classList.add(newTheme) + } + } + + const toggleSidebar = () => { + sidebarCollapsed.value = !sidebarCollapsed.value + } + + const closeSidebar = () => { + sidebarCollapsed.value = true + } + + const openSidebar = () => { + sidebarCollapsed.value = false + } + + const toggleMobileMenu = () => { + mobileMenuOpen.value = !mobileMenuOpen.value + } + + const closeMobileMenu = () => { + mobileMenuOpen.value = false + } + + const setLoading = (isLoading: boolean) => { + loading.value = isLoading + } + + const showToast = (toast: Omit) => { + const id = Date.now().toString() + const newToast: Toast = { + id, + duration: 5000, + persistent: false, + ...toast + } + + toasts.value.push(newToast) + + // 自動移除 toast(如果不是持久的) + if (!newToast.persistent && newToast.duration) { + setTimeout(() => { + hideToast(id) + }, newToast.duration) + } + + return id + } + + const hideToast = (id: string) => { + const index = toasts.value.findIndex(toast => toast.id === id) + if (index > -1) { + toasts.value.splice(index, 1) + } + } + + const clearToasts = () => { + toasts.value = [] + } + + const showSuccessToast = (title: string, message?: string) => { + return showToast({ + type: 'success', + title, + message + }) + } + + const showErrorToast = (title: string, message?: string) => { + return showToast({ + type: 'error', + title, + message, + duration: 8000 + }) + } + + const showWarningToast = (title: string, message?: string) => { + return showToast({ + type: 'warning', + title, + message + }) + } + + const showInfoToast = (title: string, message?: string) => { + return showToast({ + type: 'info', + title, + message + }) + } + + const showModal = (modal: Omit) => { + const id = Date.now().toString() + const newModal: Modal = { + id, + persistent: false, + ...modal + } + + modals.value.push(newModal) + currentModal.value = newModal + + return id + } + + const hideModal = (id?: string) => { + if (id) { + const index = modals.value.findIndex(modal => modal.id === id) + if (index > -1) { + modals.value.splice(index, 1) + } + } else { + modals.value.pop() + } + + currentModal.value = modals.value[modals.value.length - 1] || null + } + + const clearModals = () => { + modals.value = [] + currentModal.value = null + } + + const setPageTitle = (title: string) => { + pageTitle.value = title + document.title = `${title} - Drama Ling` + } + + const setBreadcrumbs = (crumbs: { label: string; to?: string }[]) => { + breadcrumbs.value = crumbs + } + + const setHeaderActions = (actions: any[]) => { + headerActions.value = actions + } + + const updateScreenSize = () => { + screenWidth.value = window.innerWidth + screenHeight.value = window.innerHeight + isMobile.value = window.innerWidth < 768 + } + + const initializeUI = () => { + // 設定初始主題 + if (theme.value === 'auto') { + setTheme('auto') + } + + // 監聽窗口大小變化 + updateScreenSize() + window.addEventListener('resize', updateScreenSize) + + // 監聽系統主題變化 + if (theme.value === 'auto') { + const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)') + mediaQuery.addListener(() => { + if (theme.value === 'auto') { + setTheme('auto') + } + }) + } + } + + const cleanup = () => { + window.removeEventListener('resize', updateScreenSize) + } + + return { + // 狀態 + theme, + sidebarCollapsed, + mobileMenuOpen, + loading, + toasts, + modals, + currentModal, + pageTitle, + breadcrumbs, + headerActions, + isMobile, + screenWidth, + screenHeight, + + // 計算屬性 + isDarkMode, + activeToasts, + + // 動作 + setTheme, + toggleSidebar, + closeSidebar, + openSidebar, + toggleMobileMenu, + closeMobileMenu, + setLoading, + showToast, + hideToast, + clearToasts, + showSuccessToast, + showErrorToast, + showWarningToast, + showInfoToast, + showModal, + hideModal, + clearModals, + setPageTitle, + setBreadcrumbs, + setHeaderActions, + updateScreenSize, + initializeUI, + cleanup + } +}, { + persist: { + paths: ['theme', 'sidebarCollapsed'] + } +}) \ No newline at end of file diff --git a/apps/web/src/stores/user.ts b/apps/web/src/stores/user.ts new file mode 100644 index 0000000..2b7b61c --- /dev/null +++ b/apps/web/src/stores/user.ts @@ -0,0 +1,302 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import type { User, UserProgress, UserPreferences } from '@/types/user' + +export const useUserStore = defineStore('user', () => { + // 狀態 + const profile = ref(null) + const progress = ref(null) + const preferences = ref({ + language: 'zh-TW', + theme: 'light', + notifications: { + email: true, + push: true, + dailyReminder: true, + achievementAlert: true + }, + privacy: { + profileVisible: false, + progressVisible: false, + allowFriendRequests: true + }, + learning: { + dailyGoal: 30, + difficultyLevel: 'intermediate', + preferredPracticeTime: 'evening', + voiceEnabled: true, + subtitlesEnabled: true + } + }) + const achievements = ref([]) + const friends = ref([]) + const isLoading = ref(false) + const error = ref(null) + + // 計算屬性 + const totalLearningTime = computed(() => { + return progress.value?.totalLearningTime || 0 + }) + + const currentLevel = computed(() => { + return progress.value?.currentLevel || 1 + }) + + const experiencePoints = computed(() => { + return progress.value?.experiencePoints || 0 + }) + + const streakDays = computed(() => { + return progress.value?.streakDays || 0 + }) + + const completedLessons = computed(() => { + return progress.value?.completedLessons || 0 + }) + + const unlockedAchievements = computed(() => { + return achievements.value.filter(achievement => achievement.unlocked) + }) + + // 動作 + const fetchUserProfile = async () => { + isLoading.value = true + error.value = null + + try { + const response = await fetch('/api/user/profile', { + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + } + }) + + if (!response.ok) { + throw new Error('獲取用戶資料失敗') + } + + profile.value = await response.json() + } catch (err) { + error.value = err instanceof Error ? err.message : '獲取用戶資料失敗' + } finally { + isLoading.value = false + } + } + + const fetchUserProgress = async () => { + isLoading.value = true + + try { + const response = await fetch('/api/user/progress', { + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + } + }) + + if (!response.ok) { + throw new Error('獲取學習進度失敗') + } + + progress.value = await response.json() + } catch (err) { + error.value = err instanceof Error ? err.message : '獲取學習進度失敗' + } finally { + isLoading.value = false + } + } + + const updatePreferences = async (newPreferences: Partial) => { + isLoading.value = true + error.value = null + + try { + const response = await fetch('/api/user/preferences', { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${localStorage.getItem('token')}` + }, + body: JSON.stringify(newPreferences) + }) + + if (!response.ok) { + throw new Error('更新偏好設定失敗') + } + + const updatedPreferences = await response.json() + preferences.value = { ...preferences.value, ...updatedPreferences } + + return { success: true } + } catch (err) { + error.value = err instanceof Error ? err.message : '更新偏好設定失敗' + return { success: false, error: error.value } + } finally { + isLoading.value = false + } + } + + const updateDailyGoal = async (goal: number) => { + const result = await updatePreferences({ + learning: { + ...preferences.value.learning, + dailyGoal: goal + } + }) + + return result + } + + const addExperience = (points: number) => { + if (progress.value) { + progress.value.experiencePoints += points + + // 檢查是否升級 + const newLevel = Math.floor(progress.value.experiencePoints / 1000) + 1 + if (newLevel > progress.value.currentLevel) { + progress.value.currentLevel = newLevel + // 觸發升級事件 + return { levelUp: true, newLevel } + } + } + return { levelUp: false } + } + + const incrementLearningTime = (minutes: number) => { + if (progress.value) { + progress.value.totalLearningTime += minutes + progress.value.lastLearningDate = new Date().toISOString() + } + } + + const updateStreak = () => { + if (!progress.value) return + + const today = new Date().toDateString() + const lastLearning = progress.value.lastLearningDate ? + new Date(progress.value.lastLearningDate).toDateString() : null + + if (lastLearning === today) { + // 今天已經學習過了,不更新連擊 + return + } + + const yesterday = new Date() + yesterday.setDate(yesterday.getDate() - 1) + + if (lastLearning === yesterday.toDateString()) { + // 昨天有學習,增加連擊 + progress.value.streakDays += 1 + } else if (lastLearning !== today) { + // 中斷連擊,重新開始 + progress.value.streakDays = 1 + } + + progress.value.lastLearningDate = new Date().toISOString() + } + + const fetchAchievements = async () => { + try { + const response = await fetch('/api/user/achievements', { + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + } + }) + + if (!response.ok) { + throw new Error('獲取成就失敗') + } + + achievements.value = await response.json() + } catch (err) { + console.error('獲取成就錯誤:', err) + } + } + + const unlockAchievement = async (achievementId: string) => { + try { + const response = await fetch(`/api/user/achievements/${achievementId}/unlock`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + } + }) + + if (!response.ok) { + throw new Error('解鎖成就失敗') + } + + // 更新本地狀態 + const achievement = achievements.value.find(a => a.id === achievementId) + if (achievement) { + achievement.unlocked = true + achievement.unlockedAt = new Date().toISOString() + } + + return { success: true, achievement } + } catch (err) { + console.error('解鎖成就錯誤:', err) + return { success: false } + } + } + + const fetchFriends = async () => { + try { + const response = await fetch('/api/user/friends', { + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + } + }) + + if (!response.ok) { + throw new Error('獲取朋友列表失敗') + } + + friends.value = await response.json() + } catch (err) { + console.error('獲取朋友列表錯誤:', err) + } + } + + const clearUserData = () => { + profile.value = null + progress.value = null + achievements.value = [] + friends.value = [] + error.value = null + } + + return { + // 狀態 + profile, + progress, + preferences, + achievements, + friends, + isLoading, + error, + + // 計算屬性 + totalLearningTime, + currentLevel, + experiencePoints, + streakDays, + completedLessons, + unlockedAchievements, + + // 動作 + fetchUserProfile, + fetchUserProgress, + updatePreferences, + updateDailyGoal, + addExperience, + incrementLearningTime, + updateStreak, + fetchAchievements, + unlockAchievement, + fetchFriends, + clearUserData + } +}, { + persist: { + paths: ['preferences'] + } +}) \ No newline at end of file diff --git a/apps/web/src/types/learning.ts b/apps/web/src/types/learning.ts new file mode 100644 index 0000000..0642a7d --- /dev/null +++ b/apps/web/src/types/learning.ts @@ -0,0 +1,198 @@ +export interface Course { + id: string + title: string + description: string + thumbnail?: string + level: 'beginner' | 'intermediate' | 'advanced' + language: string + targetLanguage: string + duration: number // 預估總時長(分鐘) + lessonsCount: number + progress: number // 0-100 + isAvailable: boolean + isCompleted: boolean + enrolledAt?: string + completedAt?: string + lessons: Lesson[] + tags: string[] + difficulty: number // 1-10 + rating: number + reviewsCount: number +} + +export interface Lesson { + id: string + courseId: string + title: string + description: string + type: 'vocabulary' | 'dialogue' | 'grammar' | 'pronunciation' | 'roleplay' | 'review' + thumbnail?: string + duration: number // 預估時長(分鐘) + order: number + isUnlocked: boolean + isCompleted: boolean + progress: number // 0-100 + completedAt?: string + score?: number + bestScore?: number + attempts: number + content: LessonContent +} + +export interface LessonContent { + introduction?: { + text: string + audio?: string + video?: string + } + questions: Question[] + vocabulary?: VocabularyCard[] + dialogues?: DialogueScript[] + summary?: { + text: string + keyPoints: string[] + } +} + +export interface Question { + id: string + type: 'multiple_choice' | 'fill_blank' | 'true_false' | 'matching' | 'ordering' | 'speaking' | 'listening' + question: string + questionAudio?: string + options?: string[] + correctAnswer: any + explanation?: string + points: number + hints?: string[] + media?: { + type: 'image' | 'audio' | 'video' + url: string + } +} + +export interface VocabularyCard { + id: string + word: string + pronunciation: string + definition: string + translation: string + partOfSpeech: string + examples: { + sentence: string + translation: string + audio?: string + }[] + audio?: string + image?: string + masteryLevel: number // 0-5 + lastReviewed?: string + nextReviewDate?: string + reviewCount: number + correctCount: number + tags: string[] +} + +export interface DialogueScript { + id: string + title: string + scenario: string + participants: DialogueParticipant[] + lines: DialogueLine[] + vocabulary: string[] // vocabulary IDs + difficulty: number + duration: number +} + +export interface DialogueParticipant { + id: string + name: string + avatar?: string + voice: string + role: string +} + +export interface DialogueLine { + id: string + speakerId: string + text: string + translation: string + audio?: string + emotion?: string + speed?: 'slow' | 'normal' | 'fast' + order: number +} + +export interface LearningSession { + id: string + lessonId: string + userId: string + startTime: string + endTime?: string + duration?: number // 秒 + questions: Question[] + currentQuestionIndex: number + answers: SessionAnswer[] + score: number + totalPoints: number + accuracy: number + status: 'active' | 'paused' | 'completed' | 'abandoned' + isPaused?: boolean +} + +export interface SessionAnswer { + questionId: string + questionIndex: number + answer: any + isCorrect: boolean + points: number + timeSpent: number // 秒 + attempts: number + hintsUsed: number + skipped?: boolean +} + +export interface PracticeSession { + id: string + type: 'vocabulary_review' | 'pronunciation' | 'dialogue_practice' | 'quick_review' + duration: number + questionsCount: number + correctAnswers: number + score: number + experienceGained: number + vocabularyReviewed: string[] + createdAt: string +} + +export interface StudyPlan { + id: string + userId: string + title: string + description: string + targetLevel: string + targetDate: string + weeklyGoal: number // 分鐘 + dailyGoal: number // 分鐘 + courses: string[] // course IDs + schedule: StudySchedule[] + progress: number // 0-100 + isActive: boolean + createdAt: string + updatedAt: string +} + +export interface StudySchedule { + dayOfWeek: number // 0-6 (Sunday-Saturday) + timeSlots: { + startTime: string // HH:MM + duration: number // 分鐘 + type: 'lesson' | 'review' | 'practice' + }[] +} + +export interface LearningStreak { + currentStreak: number + longestStreak: number + lastStudyDate: string + streakGoal: number + isActive: boolean +} \ No newline at end of file diff --git a/apps/web/src/types/user.ts b/apps/web/src/types/user.ts new file mode 100644 index 0000000..c9a211e --- /dev/null +++ b/apps/web/src/types/user.ts @@ -0,0 +1,112 @@ +export interface User { + id: string + email: string + username: string + avatar?: string + firstName?: string + lastName?: string + dateOfBirth?: string + phoneNumber?: string + country?: string + nativeLanguage?: string + targetLanguage?: string + createdAt: string + updatedAt: string + emailVerified: boolean + isActive: boolean + subscriptionPlan?: 'free' | 'premium' | 'unlimited' + subscriptionExpiry?: string +} + +export interface UserProgress { + userId: string + currentLevel: number + experiencePoints: number + totalLearningTime: number // 分鐘 + streakDays: number + longestStreak: number + completedLessons: number + completedCourses: number + lastLearningDate?: string + dailyGoalMet: boolean + weeklyGoalProgress: number + monthlyGoalProgress: number + accuracy: number + vocabularyMastered: number + certificatesEarned: number +} + +export interface UserPreferences { + language: string + theme: 'light' | 'dark' | 'auto' + notifications: { + email: boolean + push: boolean + dailyReminder: boolean + achievementAlert: boolean + } + privacy: { + profileVisible: boolean + progressVisible: boolean + allowFriendRequests: boolean + } + learning: { + dailyGoal: number // 分鐘 + difficultyLevel: 'beginner' | 'intermediate' | 'advanced' + preferredPracticeTime: 'morning' | 'afternoon' | 'evening' | 'night' + voiceEnabled: boolean + subtitlesEnabled: boolean + } +} + +export interface UserStats { + totalStudyTime: number + averageSessionLength: number + lessonsCompleted: number + vocabularyLearned: number + streakDays: number + accuracy: number + level: number + experiencePoints: number +} + +export interface Achievement { + id: string + title: string + description: string + icon: string + category: 'progress' | 'streak' | 'vocabulary' | 'accuracy' | 'time' | 'special' + requirement: { + type: string + value: number + } + unlocked: boolean + unlockedAt?: string + points: number +} + +export interface Friend { + id: string + username: string + avatar?: string + level: number + streakDays: number + status: 'online' | 'offline' | 'learning' + friendSince: string +} + +export interface Leaderboard { + period: 'daily' | 'weekly' | 'monthly' | 'allTime' + entries: LeaderboardEntry[] +} + +export interface LeaderboardEntry { + rank: number + user: { + id: string + username: string + avatar?: string + } + score: number + change: number // 排名變化 +} \ No newline at end of file diff --git a/apps/web/src/utils/index.ts b/apps/web/src/utils/index.ts new file mode 100644 index 0000000..23495f7 --- /dev/null +++ b/apps/web/src/utils/index.ts @@ -0,0 +1,314 @@ +// 工具函數集合 + +/** + * 生成唯一ID + */ +export const generateId = (prefix = 'id'): string => { + return `${prefix}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}` +} + +/** + * 防抖函數 + */ +export const debounce = any>( + func: T, + wait: number +): ((...args: Parameters) => void) => { + let timeout: NodeJS.Timeout | null = null + + return (...args: Parameters) => { + if (timeout) { + clearTimeout(timeout) + } + timeout = setTimeout(() => func.apply(null, args), wait) + } +} + +/** + * 節流函數 + */ +export const throttle = any>( + func: T, + wait: number +): ((...args: Parameters) => void) => { + let inThrottle: boolean + + return (...args: Parameters) => { + if (!inThrottle) { + func.apply(null, args) + inThrottle = true + setTimeout(() => (inThrottle = false), wait) + } + } +} + +/** + * 深度合併對象 + */ +export const deepMerge = (target: T, ...sources: any[]): T => { + if (!sources.length) return target + const source = sources.shift() + + if (isObject(target) && isObject(source)) { + for (const key in source) { + if (isObject(source[key])) { + if (!(target as any)[key]) Object.assign(target as any, { [key]: {} }) + deepMerge((target as any)[key], source[key]) + } else { + Object.assign(target as any, { [key]: source[key] }) + } + } + } + + return deepMerge(target, ...sources) +} + +/** + * 檢查是否為對象 + */ +export const isObject = (item: any): boolean => { + return item && typeof item === 'object' && !Array.isArray(item) +} + +/** + * 格式化文件大小 + */ +export const formatFileSize = (bytes: number): string => { + if (bytes === 0) return '0 Bytes' + + const k = 1024 + const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'] + const i = Math.floor(Math.log(bytes) / Math.log(k)) + + return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i] +} + +/** + * 格式化時間 + */ +export const formatTime = (seconds: number): string => { + const mins = Math.floor(seconds / 60) + const secs = Math.floor(seconds % 60) + return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}` +} + +/** + * 格式化數字(添加千位分隔符) + */ +export const formatNumber = (num: number): string => { + return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') +} + +/** + * 複製到剪貼板 + */ +export const copyToClipboard = async (text: string): Promise => { + try { + if (navigator.clipboard && window.isSecureContext) { + await navigator.clipboard.writeText(text) + return true + } else { + // 降級方案 + const textArea = document.createElement('textarea') + textArea.value = text + textArea.style.position = 'absolute' + textArea.style.left = '-999999px' + document.body.appendChild(textArea) + textArea.focus() + textArea.select() + + try { + document.execCommand('copy') + return true + } catch (error) { + console.error('Copy failed:', error) + return false + } finally { + document.body.removeChild(textArea) + } + } + } catch (error) { + console.error('Copy to clipboard failed:', error) + return false + } +} + +/** + * 下載文件 + */ +export const downloadFile = (url: string, filename?: string): void => { + const link = document.createElement('a') + link.href = url + if (filename) { + link.download = filename + } + link.style.display = 'none' + document.body.appendChild(link) + link.click() + document.body.removeChild(link) +} + +/** + * 等待指定時間 + */ +export const sleep = (ms: number): Promise => { + return new Promise(resolve => setTimeout(resolve, ms)) +} + +/** + * 獲取URL參數 + */ +export const getUrlParams = (url?: string): Record => { + const urlObject = new URL(url || window.location.href) + const params: Record = {} + + urlObject.searchParams.forEach((value, key) => { + params[key] = value + }) + + return params +} + +/** + * 檢查是否為移動設備 + */ +export const isMobile = (): boolean => { + return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( + navigator.userAgent + ) +} + +/** + * 檢查是否支援WebP + */ +export const supportsWebP = (): Promise => { + return new Promise((resolve) => { + const webP = new Image() + webP.onload = webP.onerror = () => { + resolve(webP.height === 2) + } + webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA' + }) +} + +/** + * 清理HTML標籤 + */ +export const stripHtml = (html: string): string => { + const tmp = document.createElement('DIV') + tmp.innerHTML = html + return tmp.textContent || tmp.innerText || '' +} + +/** + * 截斷文本 + */ +export const truncateText = (text: string, maxLength: number, suffix = '...'): string => { + if (text.length <= maxLength) return text + return text.substring(0, maxLength - suffix.length) + suffix +} + +/** + * 隨機生成顏色 + */ +export const randomColor = (): string => { + return `#${Math.floor(Math.random() * 16777215).toString(16)}` +} + +/** + * 檢查是否為空值 + */ +export const isEmpty = (value: any): boolean => { + if (value === null || value === undefined) return true + if (typeof value === 'string' && value.trim() === '') return true + if (Array.isArray(value) && value.length === 0) return true + if (isObject(value) && Object.keys(value).length === 0) return true + return false +} + +/** + * 首字母大寫 + */ +export const capitalize = (str: string): string => { + return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase() +} + +/** + * 駝峰轉kebab-case + */ +export const camelToKebab = (str: string): string => { + return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase() +} + +/** + * kebab-case轉駝峰 + */ +export const kebabToCamel = (str: string): string => { + return str.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase()) +} + +/** + * 獲取檔案副檔名 + */ +export const getFileExtension = (filename: string): string => { + return filename.slice((filename.lastIndexOf('.') - 1 >>> 0) + 2) +} + +/** + * 驗證郵箱格式 + */ +export const isValidEmail = (email: string): boolean => { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ + return emailRegex.test(email) +} + +/** + * 驗證手機號碼(台灣) + */ +export const isValidTaiwanPhone = (phone: string): boolean => { + const phoneRegex = /^09\d{8}$/ + return phoneRegex.test(phone) +} + +/** + * 生成隨機字符串 + */ +export const randomString = (length = 8): string => { + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' + let result = '' + for (let i = 0; i < length; i++) { + result += chars.charAt(Math.floor(Math.random() * chars.length)) + } + return result +} + +/** + * 比較兩個版本號 + */ +export const compareVersions = (version1: string, version2: string): number => { + const v1Parts = version1.split('.').map(Number) + const v2Parts = version2.split('.').map(Number) + + const maxLength = Math.max(v1Parts.length, v2Parts.length) + + for (let i = 0; i < maxLength; i++) { + const v1Part = v1Parts[i] || 0 + const v2Part = v2Parts[i] || 0 + + if (v1Part > v2Part) return 1 + if (v1Part < v2Part) return -1 + } + + return 0 +} + +// 常用的正則表達式 +export const REGEX = { + email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, + phone: /^09\d{8}$/, + url: /^https?:\/\/([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/, + password: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d@$!%*?&]{8,}$/, + ipAddress: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/, + hexColor: /^#?([a-f\d]{3}|[a-f\d]{6})$/i, + uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i +} \ No newline at end of file diff --git a/apps/web/src/views/HomeView.vue b/apps/web/src/views/HomeView.vue new file mode 100644 index 0000000..75df51a --- /dev/null +++ b/apps/web/src/views/HomeView.vue @@ -0,0 +1,524 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/views/NotFoundView.vue b/apps/web/src/views/NotFoundView.vue new file mode 100644 index 0000000..09d08fc --- /dev/null +++ b/apps/web/src/views/NotFoundView.vue @@ -0,0 +1,70 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/views/OfflineView.vue b/apps/web/src/views/OfflineView.vue new file mode 100644 index 0000000..9097e17 --- /dev/null +++ b/apps/web/src/views/OfflineView.vue @@ -0,0 +1,152 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/views/auth/ForgotPasswordView.vue b/apps/web/src/views/auth/ForgotPasswordView.vue new file mode 100644 index 0000000..29ebf50 --- /dev/null +++ b/apps/web/src/views/auth/ForgotPasswordView.vue @@ -0,0 +1,327 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/views/auth/LoginView.vue b/apps/web/src/views/auth/LoginView.vue new file mode 100644 index 0000000..48306e5 --- /dev/null +++ b/apps/web/src/views/auth/LoginView.vue @@ -0,0 +1,317 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/views/auth/RegisterView-orig.vue b/apps/web/src/views/auth/RegisterView-orig.vue new file mode 100644 index 0000000..74ce97a --- /dev/null +++ b/apps/web/src/views/auth/RegisterView-orig.vue @@ -0,0 +1,462 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/views/auth/RegisterView.vue b/apps/web/src/views/auth/RegisterView.vue new file mode 100644 index 0000000..10bdaaa --- /dev/null +++ b/apps/web/src/views/auth/RegisterView.vue @@ -0,0 +1,262 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/views/learning/DialogueView.vue b/apps/web/src/views/learning/DialogueView.vue new file mode 100644 index 0000000..d398ca4 --- /dev/null +++ b/apps/web/src/views/learning/DialogueView.vue @@ -0,0 +1,94 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/views/learning/LearningHomeView.vue b/apps/web/src/views/learning/LearningHomeView.vue new file mode 100644 index 0000000..9d1f07c --- /dev/null +++ b/apps/web/src/views/learning/LearningHomeView.vue @@ -0,0 +1,45 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/views/learning/PronunciationView.vue b/apps/web/src/views/learning/PronunciationView.vue new file mode 100644 index 0000000..6084641 --- /dev/null +++ b/apps/web/src/views/learning/PronunciationView.vue @@ -0,0 +1,175 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/views/learning/RoleplayView.vue b/apps/web/src/views/learning/RoleplayView.vue new file mode 100644 index 0000000..94265ad --- /dev/null +++ b/apps/web/src/views/learning/RoleplayView.vue @@ -0,0 +1,101 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/views/learning/VocabularyView.vue b/apps/web/src/views/learning/VocabularyView.vue new file mode 100644 index 0000000..172dd38 --- /dev/null +++ b/apps/web/src/views/learning/VocabularyView.vue @@ -0,0 +1,39 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/views/shop/ShopView.vue b/apps/web/src/views/shop/ShopView.vue new file mode 100644 index 0000000..26b78ae --- /dev/null +++ b/apps/web/src/views/shop/ShopView.vue @@ -0,0 +1,168 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/views/shop/SubscriptionView.vue b/apps/web/src/views/shop/SubscriptionView.vue new file mode 100644 index 0000000..5406fc2 --- /dev/null +++ b/apps/web/src/views/shop/SubscriptionView.vue @@ -0,0 +1,242 @@ + + + + + \ No newline at end of file diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json new file mode 100644 index 0000000..5d155df --- /dev/null +++ b/apps/web/tsconfig.json @@ -0,0 +1,50 @@ +{ + "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, + + /* 路徑對應 */ + "baseUrl": ".", + "paths": { + "@/*": ["src/*"], + "~/*": ["src/*"], + "@components/*": ["src/components/*"], + "@modules/*": ["src/modules/*"], + "@stores/*": ["src/stores/*"], + "@services/*": ["src/services/*"], + "@utils/*": ["src/utils/*"], + "@assets/*": ["src/assets/*"] + }, + + /* Vue 相關 */ + "types": ["node", "vue/ref-macros"], + "allowJs": true + }, + "include": [ + "src/**/*.ts", + "src/**/*.tsx", + "src/**/*.vue", + "tests/**/*.ts" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts new file mode 100644 index 0000000..e31df00 --- /dev/null +++ b/apps/web/vite.config.ts @@ -0,0 +1,136 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import { VitePWA } from 'vite-plugin-pwa' +import Components from 'unplugin-vue-components/vite' +import AutoImport from 'unplugin-auto-import/vite' +import { quasar, transformAssetUrls } from '@quasar/vite-plugin' +import path from 'path' + +export default defineConfig({ + plugins: [ + vue({ + template: { transformAssetUrls } + }), + + quasar({ + // sassVariables: 'src/assets/styles/quasar-variables.sass' + }), + + Components({ + resolvers: [ + (componentName) => { + if (componentName.startsWith('Q')) + return { name: componentName, from: 'quasar' } + } + ], + dts: true, + dirs: ['src/components'], + extensions: ['vue'], + deep: true + }), + + AutoImport({ + imports: [ + 'vue', + 'vue-router', + 'pinia', + { + 'quasar': ['useQuasar', '$q', 'Notify', 'Loading', 'Dialog'], + '@vueuse/core': ['useLocalStorage', 'useSessionStorage', 'useFetch'] + } + ], + dts: true, + dirs: ['src/composables', 'src/stores'], + vueTemplate: true + }), + + VitePWA({ + registerType: 'autoUpdate', + workbox: { + globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2}'], + runtimeCaching: [ + { + urlPattern: /^https:\/\/api\.dramaling\.com\/.*/i, + handler: 'NetworkFirst', + options: { + cacheName: 'api-cache', + expiration: { + maxEntries: 50, + maxAgeSeconds: 5 * 60 + } + } + } + ] + }, + manifest: { + name: 'Drama Ling - AI語言學習', + short_name: 'Drama Ling', + description: 'AI驅動的情境式語言學習應用', + theme_color: '#00E5CC', + background_color: '#2C3E50', + display: 'standalone', + orientation: 'portrait-primary', + scope: '/', + start_url: '/', + icons: [ + { + src: '/icons/icon-192x192.png', + sizes: '192x192', + type: 'image/png' + }, + { + src: '/icons/icon-512x512.png', + sizes: '512x512', + type: 'image/png' + } + ] + } + }) + ], + + resolve: { + alias: { + '@': path.resolve(__dirname, 'src'), + '~': path.resolve(__dirname, 'src'), + '@components': path.resolve(__dirname, 'src/components'), + '@modules': path.resolve(__dirname, 'src/modules'), + '@stores': path.resolve(__dirname, 'src/stores'), + '@services': path.resolve(__dirname, 'src/services'), + '@utils': path.resolve(__dirname, 'src/utils'), + '@assets': path.resolve(__dirname, 'src/assets') + } + }, + + css: { + preprocessorOptions: { + scss: { + additionalData: `@import "@/assets/styles/variables.scss";` + } + } + }, + + build: { + target: 'es2020', + rollupOptions: { + output: { + manualChunks: { + 'vue-vendor': ['vue', 'vue-router', 'pinia'], + 'quasar-vendor': ['quasar'], + 'utils-vendor': ['axios', 'lodash-es', 'dayjs', '@vueuse/core'], + 'validation-vendor': ['vee-validate', 'yup'] + } + } + } + }, + + server: { + host: '0.0.0.0', + port: 3000, + proxy: { + '/api': { + target: 'http://localhost:5000', + changeOrigin: true + } + } + } +}) \ No newline at end of file diff --git a/dl b/dl index c735d12..23aa964 100755 --- a/dl +++ b/dl @@ -18,6 +18,11 @@ show_menu() { echo -e "${BLUE}🎭 Drama Ling 管理工具${NC}" echo "==================================" echo "" + echo -e "${PURPLE}🎯 統一任務管理${NC}" + echo " task - 任務管理 (新增)" + echo " status - 查看任務狀態" + echo " list - 列出所有任務" + echo "" echo -e "${PURPLE}📋 問題管理${NC}" echo " issue - 互動式問題管理" echo " check - 檢查問題狀態" @@ -30,7 +35,6 @@ show_menu() { echo -e "${PURPLE}🚀 專案執行管理${NC}" echo " project - 專案管理" echo " phase - 階段管理" - echo " status - 查看執行狀態" echo "" echo -e "${PURPLE}🔧 系統檢查${NC}" echo " consistency - 執行一致性檢查" @@ -50,6 +54,44 @@ show_menu() { # 主邏輯 case "$1" in + "task") + echo -e "${BLUE}🎯 統一任務管理 - 查看 TASKS.md${NC}" + if command -v code > /dev/null 2>&1; then + code "$SCRIPT_DIR/TASKS.md" + elif command -v open > /dev/null 2>&1; then + open "$SCRIPT_DIR/TASKS.md" + else + echo "請手動打開 TASKS.md 文件" + fi + ;; + "status") + echo -e "${BLUE}📊 統一任務狀態總覽${NC}" + echo "==================================" + + # 統計任務數量 + if [[ -f "$SCRIPT_DIR/TASKS.md" ]]; then + echo -e "${GREEN}📋 任務統計:${NC}" + echo "🔥 緊急任務: $(grep -c "### 🔥.*" "$SCRIPT_DIR/TASKS.md" 2>/dev/null || echo "0")" + echo "⚠️ 重要任務: $(grep -c "\[ \].*" "$SCRIPT_DIR/TASKS.md" 2>/dev/null | head -1)" + echo "📝 一般任務: $(grep -c "### 📝.*" "$SCRIPT_DIR/TASKS.md" 2>/dev/null || echo "0")" + echo "✅ 已完成: $(grep -c "\[x\].*✅" "$SCRIPT_DIR/TASKS.md" 2>/dev/null || echo "0")" + echo "" + echo -e "${YELLOW}💡 執行建議:${NC}" + echo " ./dl task - 打開任務管理文件" + echo " ./dl list - 快速查看待辦任務" + else + echo "❌ TASKS.md 文件不存在" + fi + ;; + "list") + echo -e "${BLUE}📋 當前任務清單${NC}" + echo "==================================" + if [[ -f "$SCRIPT_DIR/TASKS.md" ]]; then + grep -A 3 "^\- \[ \]" "$SCRIPT_DIR/TASKS.md" | head -20 + else + echo "❌ TASKS.md 文件不存在" + fi + ;; "issue") exec "$TOOLS_DIR/issue.sh" ;; @@ -75,9 +117,6 @@ case "$1" in shift exec "$TOOLS_DIR/phase.sh" "$@" ;; - "status") - exec "$TOOLS_DIR/project.sh" status - ;; "consistency") exec "$SCRIPT_DIR/scripts/maintenance_manager.sh" consistency ;; diff --git a/src/docker-compose.yml b/docker-compose.yml similarity index 100% rename from src/docker-compose.yml rename to docker-compose.yml diff --git a/docs/02_design/html-prototypes/README.md b/docs/02_design/html-prototypes/README.md new file mode 100644 index 0000000..79b9030 --- /dev/null +++ b/docs/02_design/html-prototypes/README.md @@ -0,0 +1,196 @@ +# 🎭 Drama Ling HTML 原型系統 + +## 📖 概述 + +這是 Drama Ling 項目的 HTML 原型系統,用於在正式開發前確認頁面設計、交互流程和視覺效果。 + +## 🎯 使用目的 + +### ✅ 優勢 +- **視覺化確認**: 直接在瀏覽器中查看實際效果 +- **快速迭代**: HTML/CSS 修改比 Vue 組件更快速 +- **跨團隊溝通**: 設計師、產品經理、開發者都能直觀理解 +- **規格明確**: 避免開發階段的猜測和重工 +- **組件識別**: 清楚了解需要開發的可重用組件 +- **交互演示**: 展示表單驗證、動畫效果等互動功能 + +## 📁 目錄結構 + +``` +html-prototypes/ +├── index.html # 原型導航頁面 +├── assets/ +│ └── style.css # 全局樣式和設計系統 +├── pages/ # 主要頁面原型 +│ ├── home.html # 首頁 +│ ├── register.html # 註冊頁面 ✅ +│ ├── login.html # 登入頁面 +│ ├── dashboard.html # 學習儀表板 +│ ├── vocabulary.html # 詞彙學習 +│ ├── dialogue.html # 對話練習 +│ ├── roleplay.html # 角色扮演 +│ └── ... +├── components/ # UI 組件展示 +│ ├── buttons.html # 按鈕組件 +│ ├── forms.html # 表單組件 +│ ├── cards.html # 卡片組件 +│ └── modals.html # 彈窗組件 +└── specs/ # 設計規格展示 + ├── colors.html # 色彩規範 + ├── typography.html # 字體規範 + ├── spacing.html # 間距規範 + └── icons.html # 圖示規範 +``` + +## 🚀 開始使用 + +### 1. 打開導航頁面 +```bash +open docs/02_design/html-prototypes/index.html +``` + +### 2. 瀏覽頁面原型 +- 點擊導航卡片查看各個頁面原型 +- 每個頁面都有完整的樣式和基礎交互功能 +- 右上角有原型狀態標記 + +### 3. 測試交互功能 +- 表單驗證(即時反饋) +- 密碼強度檢查 +- 響應式布局 +- 動畫效果 + +## 🎨 設計系統 + +### 色彩規範 +- **主要色**: `#00E5CC` (青綠色) +- **輔助色**: `#8E44AD` (紫色) +- **功能色**: 錯誤、警告、成功、資訊 +- **深色主題**: 完整的深色配色方案 + +### 字體系統 +- **主字體**: Inter, PingFang TC +- **等寬字體**: JetBrains Mono +- **尺寸階層**: xs, sm, base, lg, xl, 2xl, 3xl, 4xl + +### 間距系統 +- **基礎單位**: 0.25rem (4px) +- **階層**: 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 20 + +## 📝 原型狀態管理 + +### 狀態標記 +- 🟡 **Draft**: 草稿階段,待完善 +- 🟣 **Review**: 審查階段,等待反饋 +- 🟢 **Final**: 最終確認,可用於開發 + +### 更新流程 +1. 創建/修改 HTML 原型 +2. 測試所有交互功能 +3. 標記適當的狀態 +4. 團隊審查和反饋 +5. 最終確認後用於 Vue 開發 + +## 🔧 開發轉換指南 + +### 從 HTML 到 Vue 的轉換步驟 + +#### 1. 組件拆分 +```html + +
+

標題

+

內容

+
+``` + +```vue + + +``` + +#### 2. 樣式提取 +- 將 CSS 轉換為 SCSS +- 使用設計 token (CSS 變量) +- 組件化樣式管理 + +#### 3. 交互邏輯 +- JavaScript 函數轉換為 Vue 方法 +- 表單驗證轉換為 Vue 響應式數據 +- 事件處理整合 Vue 生命周期 + +#### 4. 數據流 +- 靜態內容轉換為響應式數據 +- 整合 API 調用 +- 狀態管理 (Pinia) + +## 📋 檢查清單 + +### 新頁面原型創建時 +- [ ] 使用統一的樣式系統 +- [ ] 實現基礎交互功能 +- [ ] 響應式設計測試 +- [ ] 無障礙訪問考量 +- [ ] 瀏覽器兼容性測試 +- [ ] 添加原型狀態標記 + +### 準備轉換為 Vue 時 +- [ ] 識別可重用組件 +- [ ] 確認設計規格完整 +- [ ] 測試所有用戶流程 +- [ ] 整理設計 token +- [ ] 準備資產文件 (圖片、圖標) + +## 🌟 最佳實踐 + +### 1. 保持一致性 +- 使用統一的 CSS 變量 +- 遵循命名規範 +- 保持視覺風格一致 + +### 2. 注重細節 +- 微交互和動畫 +- 錯誤狀態處理 +- 載入狀態展示 +- 空狀態設計 + +### 3. 考慮實際場景 +- 真實數據長度 +- 網絡延遲情況 +- 錯誤處理流程 +- 邊界條件測試 + +### 4. 文檔記錄 +- 交互說明 +- 特殊需求註記 +- 技術實現提醒 + +## 🚀 下一步計劃 + +### 即將完成的頁面 +1. **登入頁面** - 用戶認證流程 +2. **首頁** - 產品展示和導航 +3. **學習儀表板** - 主要學習界面 +4. **詞彙學習** - 核心學習模組 + +### 未來擴展 +- 移動端特化版本 +- 深色/淺色主題切換 +- 多語言版本展示 +- 組件庫完整化 + +--- + +## 📞 聯絡資訊 + +如有問題或建議,請: +- 查看具體頁面的註解說明 +- 參考設計規格文檔 +- 提出改進建議 + +**記住:原型的目標是確認需求,避免開發階段的大幅修改!** ✨ \ No newline at end of file diff --git a/docs/02_design/html-prototypes/assets/style.css b/docs/02_design/html-prototypes/assets/style.css new file mode 100644 index 0000000..6c2b5a3 --- /dev/null +++ b/docs/02_design/html-prototypes/assets/style.css @@ -0,0 +1,300 @@ +/* Drama Ling HTML 原型樣式系統 */ + +/* 設計變量 */ +:root { + /* 品牌色彩 */ + --primary-teal: #00E5CC; + --primary-teal-light: #33E8D1; + --primary-teal-dark: #00B3A0; + + --secondary-purple: #8E44AD; + --accent-violet: #9B59B6; + + /* 功能色彩 */ + --error-red: #E74C3C; + --warning-yellow: #F39C12; + --success-green: #00E5CC; + --info-cyan: #3498DB; + + /* 深色主題 */ + --text-primary: #FFFFFF; + --text-secondary: #B8BCC8; + --text-tertiary: #7F8C8D; + + --bg-primary: #2C3E50; + --bg-secondary: #34495E; + --bg-dark: #1A252F; + --bg-card: #3A4A5C; + --divider: #4A5568; + + /* 字體系統 */ + --font-primary: 'Inter', 'PingFang TC', -apple-system, sans-serif; + --font-mono: 'JetBrains Mono', 'SF Mono', Monaco, monospace; + + /* 字體大小 */ + --text-xs: 0.75rem; + --text-sm: 0.875rem; + --text-base: 1rem; + --text-lg: 1.125rem; + --text-xl: 1.25rem; + --text-2xl: 1.5rem; + --text-3xl: 1.875rem; + --text-4xl: 2.25rem; + + /* 間距 */ + --space-1: 0.25rem; + --space-2: 0.5rem; + --space-3: 0.75rem; + --space-4: 1rem; + --space-5: 1.25rem; + --space-6: 1.5rem; + --space-8: 2rem; + --space-10: 2.5rem; + --space-12: 3rem; + --space-16: 4rem; + + /* 圓角 */ + --radius-sm: 0.5rem; + --radius-md: 0.75rem; + --radius-lg: 1rem; + --radius-xl: 1.5rem; + + /* 陰影 */ + --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); + --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1); + --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1); + --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1); +} + +/* 全局重置 */ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: var(--font-primary); + background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-secondary) 100%); + color: var(--text-primary); + min-height: 100vh; + line-height: 1.6; +} + +/* 原型導航系統 */ +.prototype-nav { + max-width: 1200px; + margin: 0 auto; + padding: var(--space-8) var(--space-6); +} + +.nav-header { + text-align: center; + margin-bottom: var(--space-12); +} + +.nav-header h1 { + font-size: var(--text-4xl); + font-weight: 900; + background: linear-gradient(135deg, var(--primary-teal), var(--secondary-purple)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + margin-bottom: var(--space-4); +} + +.nav-header p { + font-size: var(--text-lg); + color: var(--text-secondary); +} + +.nav-section { + margin-bottom: var(--space-12); +} + +.nav-section h2 { + font-size: var(--text-2xl); + font-weight: 700; + color: var(--text-primary); + margin-bottom: var(--space-6); + padding-bottom: var(--space-3); + border-bottom: 2px solid var(--divider); +} + +.nav-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: var(--space-6); +} + +.nav-card { + background: var(--bg-card); + border: 1px solid var(--divider); + border-radius: var(--radius-xl); + padding: var(--space-6); + text-decoration: none; + color: var(--text-primary); + transition: all 0.3s ease; + box-shadow: var(--shadow-sm); +} + +.nav-card:hover { + transform: translateY(-4px); + box-shadow: var(--shadow-xl); + border-color: var(--primary-teal); + background: linear-gradient(135deg, var(--bg-card) 0%, rgba(0, 229, 204, 0.1) 100%); +} + +.nav-card h3 { + font-size: var(--text-xl); + font-weight: 600; + color: var(--primary-teal); + margin-bottom: var(--space-2); +} + +.nav-card p { + font-size: var(--text-sm); + color: var(--text-secondary); + line-height: 1.5; +} + +/* 響應式設計 */ +@media (max-width: 768px) { + .prototype-nav { + padding: var(--space-6) var(--space-4); + } + + .nav-header h1 { + font-size: var(--text-3xl); + } + + .nav-grid { + grid-template-columns: 1fr; + gap: var(--space-4); + } + + .nav-card { + padding: var(--space-4); + } +} + +/* 通用組件樣式 */ +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: var(--space-2); + padding: var(--space-3) var(--space-6); + border: none; + border-radius: var(--radius-lg); + font-family: inherit; + font-size: var(--text-base); + font-weight: 600; + text-decoration: none; + cursor: pointer; + transition: all 0.2s ease; +} + +.btn--primary { + background: var(--primary-teal); + color: var(--bg-dark); +} + +.btn--primary:hover { + background: var(--primary-teal-light); + transform: translateY(-1px); + box-shadow: 0 8px 25px rgba(0, 229, 204, 0.3); +} + +.btn--secondary { + background: var(--secondary-purple); + color: var(--text-primary); +} + +.btn--outline { + background: transparent; + color: var(--primary-teal); + border: 2px solid var(--primary-teal); +} + +.btn--outline:hover { + background: var(--primary-teal); + color: var(--bg-dark); +} + +.card { + background: var(--bg-card); + border: 1px solid var(--divider); + border-radius: var(--radius-xl); + padding: var(--space-6); + box-shadow: var(--shadow-sm); +} + +.input { + width: 100%; + padding: var(--space-4) var(--space-5); + background: var(--bg-secondary); + border: 2px solid var(--divider); + border-radius: var(--radius-lg); + font-size: var(--text-base); + color: var(--text-primary); + font-family: inherit; + transition: all 0.2s ease; +} + +.input:focus { + outline: none; + border-color: var(--primary-teal); + box-shadow: 0 0 0 4px rgba(0, 229, 204, 0.15); + background: var(--bg-card); +} + +.input::placeholder { + color: var(--text-secondary); +} + +/* 頁面狀態指示 */ +.prototype-badge { + display: inline-block; + padding: var(--space-1) var(--space-3); + background: var(--info-cyan); + color: var(--text-primary); + font-size: var(--text-xs); + font-weight: 600; + border-radius: var(--radius-sm); + margin-left: var(--space-2); +} + +.prototype-badge--draft { + background: var(--warning-yellow); + color: var(--bg-dark); +} + +.prototype-badge--review { + background: var(--secondary-purple); +} + +.prototype-badge--final { + background: var(--success-green); + color: var(--bg-dark); +} + +/* 滾動條美化 */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--bg-secondary); + border-radius: var(--radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--primary-teal); + border-radius: var(--radius-sm); +} + +::-webkit-scrollbar-thumb:hover { + background: var(--primary-teal-light); +} \ No newline at end of file diff --git a/docs/02_design/html-prototypes/index.html b/docs/02_design/html-prototypes/index.html new file mode 100644 index 0000000..780d1c4 --- /dev/null +++ b/docs/02_design/html-prototypes/index.html @@ -0,0 +1,150 @@ + + + + + + Drama Ling - HTML 原型導航 + + + + + + + + \ No newline at end of file diff --git a/docs/02_design/html-prototypes/pages/dashboard.html b/docs/02_design/html-prototypes/pages/dashboard.html new file mode 100644 index 0000000..98d4142 --- /dev/null +++ b/docs/02_design/html-prototypes/pages/dashboard.html @@ -0,0 +1,945 @@ + + + + + + 學習儀表板 - Drama Ling + + + + +
+ 🎯 HTML 原型 - 學習儀表板 +
+ + + +
+ + + + +
+
+
+
+

早安,張小明!

+

今天也要繼續努力學習喔!

+
+
+ 🔥 連續學習 42 天 +
+
+ + +
+
+
+ 本週學習時間 +
+
+
12.5小時
+
+2.3小時 vs 上週
+
+ +
+
+ 完成課程 +
+
+
8/10
+
本週目標進度 80%
+
+ +
+
+ 詞彙掌握 +
📚
+
+
1,247
+
+23 本週新增
+
+ +
+
+ 發音準確度 +
🎵
+
+
92%
+
+5% 比上月提升
+
+
+
+ +
+ +
+
+

進行中的學習

+ 查看全部 +
+ +
+
+
+
+

咖啡廳情境對話

+

Level 3 • 日常對話

+
+
+
+
+
+
+
75%
+
+
+ +
+
+
🏢
+
+

商務會議場景

+

Level 5 • 專業對話

+
+
+
+
+
+
+
45%
+
+
+ +
+
+
✈️
+
+

機場旅行對話

+

Level 4 • 旅遊英語

+
+
+
+
+
+
+
90%
+
+
+
+ + +
+
+

今日任務

+ 3/5 完成 +
+ +
+
+
+
完成詞彙複習
+
複習20個單詞
+
+
+10 XP
+
+ +
+
+
+
對話練習
+
完成1次AI對話
+
+
+15 XP
+
+ +
+
+
+
發音練習
+
錄音練習5句話
+
+
+12 XP
+
+ +
+
+
+
+
角色扮演
+
完成餐廳場景
+
+
+20 XP
+
+ +
+
+
+
學習連續
+
保持學習紀錄
+
+
+5 XP
+
+
+
+ + +
+
+

為你推薦

+ 查看更多 +
+ +
+
+
🍴
+
+

餐廳點餐對話

+

學習在餐廳用餐時的各種實用對話,從預約到結帳。

+
+ Level 3 + 25分鐘 +
+
+
+ +
+
🛍️
+
+

購物場景對話

+

掌握購物時的詢價、比較、討價還價等實用語句。

+
+ Level 2 + 30分鐘 +
+
+
+ +
+
🏥
+
+

醫院就診對話

+

學習描述症狀、與醫生溝通的重要表達方式。

+
+ Level 4 + 35分鐘 +
+
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/02_design/html-prototypes/pages/dialogue.html b/docs/02_design/html-prototypes/pages/dialogue.html new file mode 100644 index 0000000..2d264e7 --- /dev/null +++ b/docs/02_design/html-prototypes/pages/dialogue.html @@ -0,0 +1,1035 @@ + + + + + + 對話練習 - Drama Ling + + + + +
+ 💬 HTML 原型 - 對話練習 +
+ + + +
+ + + + +
+ + + +
+
+
+
+
+

咖啡廳點餐對話

+

與 AI 咖啡師練習點餐對話

+
+
+
+ + + +
+
+ +
+
+
AI
+
+
+ Hello! Welcome to our coffee shop. What can I get for you today? +
+
+ 您好!歡迎光臨我們的咖啡店。請問您今天想要什麼? +
+
+ + +
+
+
+ +
+
+
+
+ I'd like a cappuccino, please. +
+
+ 我想要一杯卡布奇諾,謝謝。 +
+
+
+ +
+
AI
+
+
+ Great choice! Would you like that in regular or large size? +
+
+ 很好的選擇!您要中杯還是大杯的? +
+
+ + +
+
+
+
+ +
+
+
+ +
+ 按 Shift+Enter 換行,Enter 發送 + 0/500 +
+
+
+ + +
+
+ +
+ + + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/02_design/html-prototypes/pages/home.html b/docs/02_design/html-prototypes/pages/home.html new file mode 100644 index 0000000..7d16b26 --- /dev/null +++ b/docs/02_design/html-prototypes/pages/home.html @@ -0,0 +1,736 @@ + + + + + + Drama Ling - 戲劇式語言學習平台 + + + + +
+ 🎯 HTML 原型 - 首頁 +
+ + + + + +
+
+ +
+
+

用戲劇方式
學會真正的語言

+

+ 透過角色扮演和情境對話,讓語言學習變得生動有趣, + 不再死記硬背,而是在真實場景中自然掌握。 +

+ +
+
+
🎭
+ 沉浸式角色扮演學習 +
+
+
🤖
+ AI 智能對話練習 +
+
+
🎯
+ 個人化學習進度 +
+
+
🏆
+ 成就系統激勵學習 +
+
+ + +
+ +
+
+
+
+
👩
+
+
咖啡廳服務員
+
Level 3 對話
+
+
+ +
+ "歡迎光臨!請問您想要什麼飲料?" +
+ +
+
我想要一杯拿鐵咖啡
+
請給我看看菜單
+
你們有什麼推薦的嗎?
+
+
+
+
+
+
+ + +
+
+
+

為什麼選擇 Drama Ling?

+

+ 結合戲劇教學法和人工智能技術,創造最自然、最有效的語言學習體驗 +

+
+ +
+
+
🎭
+

角色扮演學習

+

+ 扮演不同角色,在真實情境中練習對話。 + 從餐廳點餐到商務談判,涵蓋生活各個場景。 +

+
+ +
+
🤖
+

AI 智能對話

+

+ 與AI進行自然對話,獲得即時反饋。 + 智能調整難度,確保學習進度最佳化。 +

+
+ +
+
📊
+

個人化學習

+

+ AI分析你的學習模式,制定專屬學習計劃。 + 追蹤進度,調整內容難度。 +

+
+ +
+
🎵
+

發音練習

+

+ 語音識別技術評估發音準確度。 + 提供詳細反饋,快速改善口說能力。 +

+
+ +
+
🏆
+

成就系統

+

+ 完成任務獲得成就徽章。 + 排行榜競爭,讓學習充滿動力。 +

+
+ +
+
📱
+

跨平台同步

+

+ 手機、平板、電腦無縫同步。 + 隨時隨地繼續你的學習進度。 +

+
+
+
+
+ + +
+
+

數萬用戶的學習成果

+ +
+
+
50,000+
+
活躍學習者
+
+ +
+
95%
+
用戶滿意度
+
+ +
+
200+
+
學習場景
+
+ +
+
12
+
支援語言
+
+
+
+
+ + +
+
+

準備開始你的語言學習之旅?

+

+ 加入數萬名學習者的行列,用最自然的方式掌握新語言。 + 7天免費試用,隨時可以取消。 +

+ + +
+
+ + + + \ No newline at end of file diff --git a/docs/02_design/html-prototypes/pages/login.html b/docs/02_design/html-prototypes/pages/login.html new file mode 100644 index 0000000..a7a4010 --- /dev/null +++ b/docs/02_design/html-prototypes/pages/login.html @@ -0,0 +1,496 @@ + + + + + + 登入 - Drama Ling + + + + +
+ 🎯 HTML 原型 - 登入頁面 +
+ +
+
+ +
+ +
+ + +

歡迎回來

+

繼續你的語言學習之旅

+ +
+

上次學習進度

+
+
+
85%
+
完成度
+
+
+
42
+
連續天數
+
+
+
Level 12
+
當前等級
+
+
+
+
+ + +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/docs/02_design/html-prototypes/pages/profile.html b/docs/02_design/html-prototypes/pages/profile.html new file mode 100644 index 0000000..7eb120b --- /dev/null +++ b/docs/02_design/html-prototypes/pages/profile.html @@ -0,0 +1,1102 @@ + + + + + + 個人檔案 - Drama Ling + + + + +
+ 👤 HTML 原型 - 個人檔案 +
+ + + +
+ + + + +
+ + + +
+
+
+ 張 +
+ 📷 更換頭像 +
+
+
+

張小明

+

英語學習愛好者 • 台北,台灣

+
+
+ 42 + 學習天數 +
+
+ 1,247 + 掌握詞彙 +
+
+ 8 + 完成課程 +
+
+ 92% + 平均成績 +
+
+
+
+ +
+
+ Level 12 - 中級學習者 + 距離 Level 13 還需 380 XP +
+
+
+
+
2,120 / 2,500 XP (72%)
+
+
+ + +
+

+ 🏆 成就徽章 +

+ +
+
+
🔥
+

學習達人

+

連續學習30天

+
✅ 已達成
+
+ +
+
📚
+

詞彙大師

+

掌握1000個單字

+
✅ 已達成
+
+ +
+
🎭
+

表演新星

+

完成5個角色扮演

+
✅ 已達成
+
+ +
+
🎯
+

發音專家

+

發音準確度達95%

+
92% / 95%
+
+ +
+
💬
+

對話高手

+

完成50次AI對話

+
32 / 50
+
+ +
+
+

速學之王

+

一天內學習5小時

+
未達成
+
+
+
+ + +
+

+ ⚙️ 學習偏好 +

+ +
+
+

學習目標

+
+
+
+ 日常生活交流 +
+
+
+ 商務職場應用 +
+
+
+ 學術研究討論 +
+
+
+ +
+

學習節奏

+
+
+
+ 輕鬆學習 (每天15分鐘) +
+
+
+ 穩定進步 (每天30分鐘) +
+
+
+ 加速學習 (每天60分鐘) +
+
+
+ +
+

難度設定

+
+
+
+ 初學者 (基礎詞彙) +
+
+
+ 中級者 (進階對話) +
+
+
+ 高級者 (專業表達) +
+
+
+ +
+

提醒設定

+
+
+
+ 每日學習提醒 +
+
+
+ 複習提醒 +
+
+
+ 成就通知 +
+
+
+
+
+ + +
+

+ 📈 最近活動 +

+ +
+
+ +
+
+

完成角色扮演練習

+ 2小時前 +
+

在「咖啡店點餐」場景中獲得優秀表現

+
+ 📊 評分: 87% + ⏱️ 用時: 12分鐘 + 🎯 獲得: +25 XP +
+
+ +
+
+

詞彙學習成果

+ 5小時前 +
+

學習了23個新單字,複習了45個已學詞彙

+
+ 📚 新學: 23個 + 🔄 複習: 45個 + 🎯 獲得: +18 XP +
+
+ +
+
+

AI對話練習

+ 昨天 +
+

與AI進行了商務會議場景對話練習

+
+ 💬 對話輪次: 15輪 + 📈 流暢度: 85% + 🎯 獲得: +30 XP +
+
+ +
+
+

發音練習突破

+ 2天前 +
+

發音準確度從85%提升到92%

+
+ 🎵 練習次數: 20次 + 📊 準確度: 92% + 🎯 獲得: +15 XP +
+
+ +
+
+

達成新成就

+ 3天前 +
+

🏆 解鎖「詞彙大師」成就徽章

+
+ 🎉 成就類型: 詞彙掌握 + 📊 累計詞彙: 1000個 + 🎯 獲得: +100 XP +
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/02_design/html-prototypes/pages/progress.html b/docs/02_design/html-prototypes/pages/progress.html new file mode 100644 index 0000000..c5e2132 --- /dev/null +++ b/docs/02_design/html-prototypes/pages/progress.html @@ -0,0 +1,1248 @@ + + + + + + 學習進度 - Drama Ling + + + + +
+ 📈 HTML 原型 - 學習進度 +
+ + + +
+ + + + +
+ + + +
+
+
+ 學習時間 +
+
+
42.5小時
+
+18% vs 上月
+
+ +
+
+ 學習天數 +
📅
+
+
25
+
連續學習 12 天
+
+ +
+
+ 掌握詞彙 +
📚
+
+
1,247
+
+156 本月新增
+
+ +
+
+ 平均成績 +
🎯
+
+
89
+
+5分 vs 上月
+
+
+ + +
+
+
+

📊 每日學習時間

+
+
+
+ 學習時間 +
+
+
+
+ +
+
+ +
+
+

🎯 技能雷達圖

+
+
+
+
+
+
詞彙 92%
+
對話 85%
+
發音 89%
+
語法 78%
+
聽力 82%
+
閱讀 88%
+
+
+
+
+
+ + +
+

📋 詳細進度分析

+ +
+
+
+
📚
+
+

詞彙學習

+

單字掌握和運用能力

+
+
+
+
+
+
基礎詞彙
+
+
+
+
+
96%
+
+
+
+
進階詞彙
+
+
+
+
+
87%
+
+
+
+
專業術語
+
+
+
+
+
73%
+
+
+
+ +
+
+
💬
+
+

對話練習

+

實際對話和表達能力

+
+
+
+
+
+
日常對話
+
+
+
+
+
91%
+
+
+
+
商務對話
+
+
+
+
+
82%
+
+
+
+
學術討論
+
+
+
+
+
68%
+
+
+
+ +
+
+
🎵
+
+

發音練習

+

發音準確度和自然度

+
+
+
+
+
+
元音發音
+
+
+
+
+
94%
+
+
+
+
子音發音
+
+
+
+
+
88%
+
+
+
+
語調節奏
+
+
+
+
+
85%
+
+
+
+ +
+
+
🎭
+
+

角色扮演

+

情境表演和角色演繹

+
+
+
+
+
+
生活場景
+
+
+
+
+
93%
+
+
+
+
職場場景
+
+
+
+
+
79%
+
+
+
+
情感表達
+
+
+
+
+
86%
+
+
+
+
+
+ + +
+

🗺️ 學習軌跡

+ +
+
+ +
+
+

基礎詞彙突破

+ 3天前 +
+

達成1000個單字掌握目標,解鎖「詞彙大師」成就

+
+ 🎯 目標達成率: 100% + ⏰ 用時: 35天 + 📈 提升: +15% +
+
+ +
+
+

商務對話提升

+ 進行中 +
+

提升商務場景對話能力,目標達成85%準確度

+
+ 🎯 目標達成率: 82% + ⏰ 剩餘時間: 5天 + 📊 當前水平: 82% +
+
+ +
+
+

發音專家認證

+ 預計 1週後 +
+

發音準確度達到95%,獲得「發音專家」認證

+
+ 🎯 當前進度: 89% + ⏰ 預估時間: 10天 + 📈 需要提升: +6% +
+
+ +
+
+

高級對話挑戰

+ 預計 2週後 +
+

挑戰複雜情境對話,提升到高級水平

+
+ 🎯 解鎖條件: Level 15 + ⏰ 預估時間: 20天 + 📊 準備度: 65% +
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/02_design/html-prototypes/pages/pronunciation.html b/docs/02_design/html-prototypes/pages/pronunciation.html new file mode 100644 index 0000000..2529dbd --- /dev/null +++ b/docs/02_design/html-prototypes/pages/pronunciation.html @@ -0,0 +1,1161 @@ + + + + + + 發音練習 - Drama Ling + + + + +
+ 🎵 HTML 原型 - 發音練習 +
+ + + +
+ + + + +
+ + + +
+
+

🎯 單字練習模式

+

專注練習單字發音,獲得即時反饋

+
+ +
+
Confidence
+
/ˈkɒnfɪdəns/
+
信心;自信心;把握
+
+ "She spoke with great confidence during the presentation."
+ 她在簡報中表現出很大的自信。 +
+ +
+ + + +
+ + + + + + +
+
+ + +
+
+

📚 最近練習

+ +
+ +
+
+
+
Confidence
+
剛才
+
+
+ ⭐ 87% +
+
+ +
+
+
Pronunciation
+
5分鐘前
+
+
+ ✨ 83% +
+
+ +
+
+
Opportunity
+
10分鐘前
+
+
+ 🎯 92% +
+
+ +
+
+
Achievement
+
15分鐘前
+
+
+ 📈 78% +
+
+ +
+
+
Communication
+
昨天
+
+
+ 💫 85% +
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/02_design/html-prototypes/pages/register.html b/docs/02_design/html-prototypes/pages/register.html new file mode 100644 index 0000000..6686dbb --- /dev/null +++ b/docs/02_design/html-prototypes/pages/register.html @@ -0,0 +1,587 @@ + + + + + + 註冊 - Drama Ling + + + + +
+ 🎯 HTML 原型 - 註冊頁面 +
+ +
+
+ +
+ +
+ + +

Drama Ling

+

戲劇式語言學習平台

+ +
+
+
🎯
+ AI 驅動的個人化學習 +
+
+
🗣️
+ 真實對話情境模擬 +
+
+
🏆
+ 遊戲化進度追蹤 +
+
+
📱
+ 隨時隨地學習 +
+
+
+ + +
+
+
+

加入 Drama Ling

+

開始你的語言學習之旅

+
+ +
+ + +
+
+ +
+ + +
+
+ +
+ + +
+
+
+
+
請輸入密碼
+
+
+
+ +
+ + +
+
+ +
+ + +
+ + + +
+ +
+ + + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/02_design/html-prototypes/pages/roleplay-result.html b/docs/02_design/html-prototypes/pages/roleplay-result.html new file mode 100644 index 0000000..e717a56 --- /dev/null +++ b/docs/02_design/html-prototypes/pages/roleplay-result.html @@ -0,0 +1,888 @@ + + + + + + 劇本表現結算 - Drama Ling + + + + +
+ 🏆 HTML 原型 - 劇本結算 +
+ +
+
+ +
+
🎉
+

恭喜過關!

+

你在情境對話中表現出色!

+ +
+
📖 午餐吃什麼
+
⏱️ 完成時間:4分23秒 / 5分00秒
+
+
+ + +
+ + + +
+ + +
+
+
+ 💬 對話語意合適度 + 85分 +
+
+
+
+
+ 回應切合情境,對話流暢自然,能適當表達個人喜好並與對方互動。 +
+
+ +
+
+ 📝 語法正確性 + 2處錯誤 +
+
+
+
+
+ 發現2處語法錯誤,建議進行訂正練習以提升語法準確度。 +
+
+ +
+
+ 🎵 表達流暢度 + 78分 +
+
+
+
+
+ 發音清晰,語調自然,偶有停頓但整體表達流暢。 +
+
+
+ + +
+
+
+ 🎯 劇情任務完成情況 +
+
+
+
+ 說服Jamie吃自己喜歡的食物 +
+
+
+ 提出至少2種食物選擇並妥協 +
+
+
+ +
+
+ 📚 指定詞彙提及情況 +
+
+
+
+ decide (決定) +
+
+
+ light (清淡的) +
+
+
+ how about (⋯⋯怎麼樣?) +
+
+
+ can't decide (拿不定主意) +
+
+
+
+ + +
+
+ ❌ 發現的語法錯誤 +
+
    +
  • +
    原句:I think burger is more better than salad.
    +
    建議:I think burgers are better than salad.
    +
  • +
  • +
    原句:How about we goes to that new place?
    +
    建議:How about we go to that new place?
    +
  • +
+
+ + +
+

🔧 立即訂正錯誤

+

+ 訂正錯誤可以提升你的最終評分,並獲得額外獎勵! +

+ +
+
+ 2 + 語法錯誤 +
+
+ 1 + 表達不順 +
+
+ +
+ + +
+
+ + + + + + +
+
+ + + + \ No newline at end of file diff --git a/docs/02_design/html-prototypes/pages/roleplay-room.html b/docs/02_design/html-prototypes/pages/roleplay-room.html new file mode 100644 index 0000000..1b85055 --- /dev/null +++ b/docs/02_design/html-prototypes/pages/roleplay-room.html @@ -0,0 +1,1142 @@ + + + + + + 午餐吃什麼 - 情境對話室 - Drama Ling + + + + +
+ 🎭 HTML 原型 - 情境對話室 +
+ +
+ +
+
+ 🎭 +

午餐吃什麼

+
+ +
+
+ ⏱️ + 05:00 +
+ + + + +
+
+ + +
+ +
+ +
+ 🏞️ 場景:兩位朋友坐在樹蔭下的公園長椅上,他們手裡拿著手機,瀏覽餐廳選項,討論午餐吃什麼。背景中傳來鳥鳴聲和孩子們玩耍的聲音。 +
+ + +
+ +
+
+ Jamie (AI) + 已完成 +
+
+
+ "I'm not sure either. Maybe something light, like salad?" +
+
+ 我也不確定,也許吃點清淡的,比如沙拉? +
+
+ + + +
+
+
+ + +
+
+ Alex (你) + 輪到你了 +
+
+
+
+ [點擊錄音按鈕開始表演你的台詞] +
+
+ 建議回答:Salad? That's so boring. How about burgers? +
+
+
+
+ + +
+
+ + +
+ +
+ + +
+
+
+ + +
+ +
+
+

🎯 通關條件

+
+ + +
+ + + +
+ + +
+
+
+
+ +
+
+
+ 說服 Jamie 吃自己喜歡的食物,並舉出理由 +
+ +
+
+ +
+
+ +
+
+
+ 提出至少2種食物選擇,並進行妥協 +
+ +
+
+
+
+ + + + + + +
+
+
+
+ + +
+ +
+ + + + \ No newline at end of file diff --git a/docs/02_design/html-prototypes/pages/roleplay.html b/docs/02_design/html-prototypes/pages/roleplay.html new file mode 100644 index 0000000..8c33913 --- /dev/null +++ b/docs/02_design/html-prototypes/pages/roleplay.html @@ -0,0 +1,1306 @@ + + + + + + 角色扮演 - Drama Ling + + + + +
+ 🎭 HTML 原型 - 角色扮演 +
+ + + +
+ + + + +
+ + + +
+
+
+

☕ 咖啡店點餐 - 場景1

+
+ + + +
+
+ +
+
+
👤
+
+ 顧客 (你) + 想要點一杯咖啡的客人 +
+
+
+
👨‍🍳
+
+ 咖啡師 (AI) + 友善的專業咖啡師 +
+
+
+
+ +
+
+
+ 🏪 場景:一間溫馨的咖啡店,午後時光,店內播放著輕柔的音樂。你走進店門,準備點一杯咖啡。 +
+ +
+
咖啡師 (AI)
+
+ "Good afternoon! Welcome to our coffee shop. What can I get for you today?" +
+
+ 下午好!歡迎光臨我們的咖啡店。請問您今天想要什麼? +
+
+ +
+
顧客 (你)
+
+ [點擊錄音按鈕開始表演你的台詞] +
+
+ 建議回答:Hi, I'd like a cappuccino, please. +
+
+ +
+
咖啡師 (AI)
+
+ "Certainly! Would you like that in regular or large size?" +
+
+ 當然!您要中杯還是大杯的? +
+
+ +
+
顧客 (你)
+
+ [等待你的表演...] +
+
+ 建議回答:Regular size, please. How much is that? +
+
+
+ +
+

🎤 表演區域

+ +
+ + +
+ + + +
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/02_design/html-prototypes/pages/settings.html b/docs/02_design/html-prototypes/pages/settings.html new file mode 100644 index 0000000..ace1db6 --- /dev/null +++ b/docs/02_design/html-prototypes/pages/settings.html @@ -0,0 +1,1440 @@ + + + + + + 設定 - Drama Ling + + + + +
+ ⚙️ HTML 原型 - 設定 +
+ + + +
+ + + + +
+ + + +
+
+

+ 🎯 一般設定 +

+

基本的應用程式行為和外觀設定

+ +
+
+
深色模式
+
啟用深色主題以減少眼睛疲勞
+
+
+
+
+
+
+
+ +
+
+
自動儲存進度
+
自動儲存學習進度,避免資料遺失
+
+
+
+
+
+
+
+ +
+
+
動畫效果
+
啟用介面動畫和轉場效果
+
+
+
+
+
+
+
+ +
+
+
預設頁面
+
應用程式啟動時的預設頁面
+
+
+ +
+
+
+
+ + +
+
+

+ 📚 學習偏好 +

+

個人化您的學習體驗和難度設定

+ +
+
+
學習目標
+
選擇您的主要學習目標
+
+
+ +
+
+ +
+
+
學習難度
+
調整內容的難度等級
+
+ +
中級 (3/5)
+
+
+
+
+
+ +
+
+
每日學習目標
+
設定每日學習時間目標(分鐘)
+
+
+ +
+
+ +
+
+
顯示中文翻譯
+
在練習過程中顯示中文翻譯協助
+
+
+
+
+
+
+
+ +
+
+
智能複習
+
根據記憶曲線自動安排複習
+
+
+
+
+
+
+
+
+
+ + +
+
+

+ 🔔 通知設定 +

+

管理學習提醒和通知偏好

+ +
+
+
學習提醒
+
每日學習時間提醒
+
+
+
+
+
+
+
+ +
+
+
提醒時間
+
設定接收學習提醒的時間
+
+
09:00
×
+
14:00
×
+
20:00
×
+
+ 新增時間
+
+
+
+
+
+ +
+
+
成就通知
+
獲得成就或達成目標時的通知
+
+
+
+
+
+
+
+ +
+
+
複習提醒
+
智能複習系統的提醒通知
+
+
+
+
+
+
+
+
+
+ + +
+
+

+ 🌍 語言介面 +

+

選擇應用程式的顯示語言

+ +
+
+
🇹🇼
+
+
繁體中文
+
Traditional Chinese
+
+
+ +
+
🇨🇳
+
+
简体中文
+
Simplified Chinese
+
+
+ +
+
🇺🇸
+
+
English
+
English
+
+
+ +
+
🇯🇵
+
+
日本語
+
Japanese
+
+
+ +
+
🇰🇷
+
+
한국어
+
Korean
+
+
+ +
+
🇪🇸
+
+
Español
+
Spanish
+
+
+
+
+
+ + +
+
+

+ 🔊 音頻設定 +

+

調整語音播放和錄音相關設定

+ +
+
+
主音量
+
調整整體音量大小
+
+ +
75%
+
+
+
+
+
+ +
+
+
語音播放速度
+
調整AI語音的播放速度
+
+ +
正常 (100%)
+
+
+
+
+
+ +
+
+
語音音調
+
選擇偏好的AI語音音調
+
+
+ +
+
+ +
+
+
自動播放
+
新內容載入時自動播放語音
+
+
+
+
+
+
+
+ +
+
+
錄音品質
+
選擇語音錄音的品質等級
+
+
+ +
+
+
+
+ + +
+
+

+ 🔒 隱私安全 +

+

管理您的隱私設定和資料安全

+ +
+
+
資料收集
+
允許收集匿名學習數據以改善服務
+
+
+
+
+
+
+
+ +
+
+
語音資料儲存
+
允許儲存語音錄音用於發音分析
+
+
+
+
+
+
+
+ +
+
+
學習分析
+
允許分析學習模式以提供個人化建議
+
+
+
+
+
+
+
+ +
+ + + +
+
+
+ + +
+
+

+ 👤 帳戶資訊 +

+

管理您的帳戶設定和個人資料

+ +
+
+
電子信箱
+
您的帳戶電子信箱地址
+
+
+ +
+
+ +
+
+
顯示名稱
+
在應用程式中顯示的名稱
+
+
+ +
+
+ +
+ + +
+
+ +
+

+ ⚠️ 危險區域 +

+

這些操作將會永久影響您的帳戶,請謹慎操作

+ +
+
+
重置學習進度
+
清除所有學習記錄和進度資料
+
+
+ +
+
+ +
+
+
刪除帳戶
+
永久刪除您的帳戶和所有相關資料
+
+
+ +
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/02_design/html-prototypes/pages/subscription.html b/docs/02_design/html-prototypes/pages/subscription.html new file mode 100644 index 0000000..d59c5f0 --- /dev/null +++ b/docs/02_design/html-prototypes/pages/subscription.html @@ -0,0 +1,1234 @@ + + + + + + 訂閱管理 - Drama Ling + + + + +
+ 💎 HTML 原型 - 訂閱管理 +
+ + + +
+ + + + +
+ + + +
+
+
+
💎
+
+

Premium 方案

+

完整功能的專業學習體驗

+
+
+
+ + +
+
+ +
+
+ NT$ 299 + 每月費用 +
+
+ 2024-10-15 + 下次計費 +
+
+ 2024-03-15 + 訂閱開始 +
+
+ 自動續訂 + 續訂狀態 +
+
+ +
+
+ 本月使用量 + 無限制 +
+
+
+
+
+
+ + +
+

選擇最適合您的方案

+ +
+
+
+

Free 免費方案

+

基礎功能,適合初學者體驗

+
+ 0 + NT$ + / 月 +
+
+ +
    +
  • + + 基礎詞彙學習 (每日10個) +
  • +
  • + + 簡單對話練習 (每日3次) +
  • +
  • + + 角色扮演功能 +
  • +
  • + + 發音分析 +
  • +
  • + + 個人化學習計畫 +
  • +
  • + + 離線學習 +
  • +
+ + +
+ + + +
+
+

Enterprise 企業方案

+

團隊學習,企業培訓專用

+
+ 999 + NT$ + / 月 +
+
+ +
    +
  • + + Premium 所有功能 +
  • +
  • + + 團隊管理面板 +
  • +
  • + + 學習進度分析 +
  • +
  • + + 自定義學習內容 +
  • +
  • + + 專屬客戶經理 +
  • +
  • + + API 整合支援 +
  • +
+ + +
+
+
+ + +
+
+

📄 帳單歷史

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
日期方案金額狀態發票
2024-09-15Premium 月方案NT$ 299下載
2024-08-15Premium 月方案NT$ 299下載
2024-07-15Premium 月方案NT$ 299下載
2024-06-15Premium 月方案NT$ 299下載
2024-05-15Premium 月方案NT$ 299下載
+
+ + +
+

❓ 常見問題

+ +
+
+ 如何取消我的訂閱? + +
+
+ 您可以在任何時候取消訂閱。在訂閱管理頁面點擊「取消訂閱」按鈕即可。取消後,您可以繼續使用付費功能直到當前計費週期結束。 +
+
+ +
+
+ 可以隨時變更訂閱方案嗎? + +
+
+ 是的,您可以隨時升級或降級您的訂閱方案。變更會在下一個計費週期生效,或者您可以選擇立即生效並按比例計費。 +
+
+ +
+
+ 如果我取消訂閱,我的學習資料會被刪除嗎? + +
+
+ 不會的。您的學習進度和資料會被保留。如果您之後重新訂閱,所有資料都會恢復。但是,某些付費功能會被限制使用。 +
+
+ +
+
+ 支援哪些付款方式? + +
+
+ 我們支援信用卡、簽帳卡、PayPal、Apple Pay、Google Pay 等多種付款方式。所有交易都透過安全的加密通道處理。 +
+
+ +
+
+ 是否有學生折扣? + +
+
+ 是的!我們為在校學生提供 30% 的折扣。請聯繫客服並提供學生證明文件來申請學生優惠。 +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/02_design/html-prototypes/pages/vocabulary.html b/docs/02_design/html-prototypes/pages/vocabulary.html new file mode 100644 index 0000000..cb6b065 --- /dev/null +++ b/docs/02_design/html-prototypes/pages/vocabulary.html @@ -0,0 +1,1683 @@ + + + + + + 詞彙學習 - Drama Ling + + + + +
+ 📚 HTML 原型 - 詞彙學習 +
+ + + +
+ + + + +
+ + + +
+
+
confidence
+
/ˈkɒnfɪdəns/
+
信心;自信心;把握
+
+ "She spoke with great confidence during the presentation."
+ 她在簡報中表現出很大的自信。 +
+ +
+ + + +
+ +
+ + + +
+
+
+ + + + + +
+
+

我的詞彙庫

+
+ + + + +
+
+ +
+
+
+
+ confidence + 信心;自信心 +
+
+
+ +
+
+ +
+
+
+
+ presentation + 簡報;呈現 +
+
+
+ +
+
+ +
+
+
+
+ colleague + 同事;同僚 +
+
+
+ +
+
+ +
+
+
+
+ opportunity + 機會;時機 +
+
+
+ +
+
+ +
+
+
+
+ achievement + 成就;成績 +
+
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/04_technical/database-schema.md b/docs/04_technical/01_architecture/database-schema.md similarity index 100% rename from docs/04_technical/database-schema.md rename to docs/04_technical/01_architecture/database-schema.md diff --git a/docs/04_technical/flutter-dotnet-integration.md b/docs/04_technical/01_architecture/system-integration.md similarity index 100% rename from docs/04_technical/flutter-dotnet-integration.md rename to docs/04_technical/01_architecture/system-integration.md diff --git a/docs/04_technical/tech-stack-decision.md b/docs/04_technical/01_architecture/tech-stack-decision.md similarity index 100% rename from docs/04_technical/tech-stack-decision.md rename to docs/04_technical/01_architecture/tech-stack-decision.md diff --git a/docs/04_technical/api/README.md b/docs/04_technical/02_api/README.md similarity index 100% rename from docs/04_technical/api/README.md rename to docs/04_technical/02_api/README.md diff --git a/docs/04_technical/api-specifications.md b/docs/04_technical/02_api/api-specifications.md similarity index 100% rename from docs/04_technical/api-specifications.md rename to docs/04_technical/02_api/api-specifications.md diff --git a/docs/04_technical/api/authentication.md b/docs/04_technical/02_api/authentication.md similarity index 100% rename from docs/04_technical/api/authentication.md rename to docs/04_technical/02_api/authentication.md diff --git a/docs/04_technical/api/common.md b/docs/04_technical/02_api/common.md similarity index 100% rename from docs/04_technical/api/common.md rename to docs/04_technical/02_api/common.md diff --git a/docs/04_technical/api/daily-missions.md b/docs/04_technical/02_api/daily-missions.md similarity index 100% rename from docs/04_technical/api/daily-missions.md rename to docs/04_technical/02_api/daily-missions.md diff --git a/docs/04_technical/api/dialogue-practice.md b/docs/04_technical/02_api/dialogue-practice.md similarity index 100% rename from docs/04_technical/api/dialogue-practice.md rename to docs/04_technical/02_api/dialogue-practice.md diff --git a/docs/04_technical/api/errors.md b/docs/04_technical/02_api/errors.md similarity index 100% rename from docs/04_technical/api/errors.md rename to docs/04_technical/02_api/errors.md diff --git a/docs/04_technical/api/gamification.md b/docs/04_technical/02_api/gamification.md similarity index 100% rename from docs/04_technical/api/gamification.md rename to docs/04_technical/02_api/gamification.md diff --git a/docs/04_technical/api/language-levels.md b/docs/04_technical/02_api/language-levels.md similarity index 100% rename from docs/04_technical/api/language-levels.md rename to docs/04_technical/02_api/language-levels.md diff --git a/docs/04_technical/api/learning-content.md b/docs/04_technical/02_api/learning-content.md similarity index 100% rename from docs/04_technical/api/learning-content.md rename to docs/04_technical/02_api/learning-content.md diff --git a/docs/04_technical/api/subscription.md b/docs/04_technical/02_api/subscription.md similarity index 100% rename from docs/04_technical/api/subscription.md rename to docs/04_technical/02_api/subscription.md diff --git a/docs/04_technical/api/user-management.md b/docs/04_technical/02_api/user-management.md similarity index 100% rename from docs/04_technical/api/user-management.md rename to docs/04_technical/02_api/user-management.md diff --git a/docs/04_technical/api/vocabulary.md b/docs/04_technical/02_api/vocabulary.md similarity index 100% rename from docs/04_technical/api/vocabulary.md rename to docs/04_technical/02_api/vocabulary.md diff --git a/docs/04_technical/03_frontend/vue-development-standards.md b/docs/04_technical/03_frontend/vue-development-standards.md new file mode 100644 index 0000000..dc01e5b --- /dev/null +++ b/docs/04_technical/03_frontend/vue-development-standards.md @@ -0,0 +1,1391 @@ +# Vue.js 開發規範和最佳實踐 + +## 📋 總體指導原則 + +### 核心原則 +1. **可讀性優先**: 代碼應該易於理解和維護 +2. **一致性**: 整個專案使用統一的編碼風格 +3. **可測試性**: 編寫易於測試的代碼 +4. **效能考量**: 避免不必要的重複渲染和記憶體洩漏 +5. **類型安全**: 充分利用 TypeScript 的類型檢查 + +### 技術選型標準 +- **Vue 3 + Composition API**: 優先使用 Composition API +- **TypeScript**: 所有 .vue 檔案使用 ` + + +``` + +#### 複雜組件結構範例 +```vue + + + + + + +``` + +### Props 設計規範 + +#### Props 類型定義 +```typescript +// ✅ 正確:明確的類型定義 +interface Props { + // 必需 props + userId: string + words: VocabularyWord[] + + // 可選 props (使用 ?) + title?: string + maxItems?: number + isLoading?: boolean + + // 具有預設值的 props + pageSize?: number + sortOrder?: 'asc' | 'desc' + + // 複雜物件類型 + filters?: { + difficulty: number + category: string[] + } + + // 函數類型 (建議使用 emit) + onUpdate?: (data: UpdateData) => void +} + +// 使用 withDefaults 設定預設值 +const props = withDefaults(defineProps(), { + title: '詞彙學習', + maxItems: 10, + isLoading: false, + pageSize: 20, + sortOrder: 'asc', + filters: () => ({ difficulty: 1, category: [] }) +}) +``` + +#### Props 驗證 +```typescript +// 複雜驗證邏輯可以使用計算屬性 +const isValidProps = computed(() => { + return props.words.length > 0 && props.userId.length > 0 +}) + +// 在組件內進行運行時檢查 +watch([() => props.words, () => props.userId], () => { + if (!isValidProps.value) { + console.warn('Invalid props provided to VocabularyCard') + } +}, { immediate: true }) +``` + +### Emits 設計規範 + +#### Emit 事件命名 +```typescript +// ✅ 正確:使用動詞命名,描述發生的動作 +interface Emits { + // 數據更新事件 + 'update:modelValue': [value: string] + 'update:filters': [filters: FilterOptions] + + // 用戶互動事件 + submit: [formData: FormData] + cancel: [] + select: [itemId: string] + + // 狀態變化事件 + load: [] + error: [error: Error] + complete: [result: any] +} + +// ❌ 錯誤:使用名詞或不清楚的命名 +interface BadEmits { + data: [any] // 不清楚 + click: [] // 太通用 + thing: [something: any] // 無意義 +} +``` + +#### 事件觸發範例 +```typescript +const emit = defineEmits() + +// 正確的事件觸發方式 +const handleFormSubmit = async (formData: FormData) => { + try { + emit('load') + const result = await submitForm(formData) + emit('submit', formData) + emit('complete', result) + } catch (error) { + emit('error', error as Error) + } +} +``` + +## 🔧 Composables 開發規範 + +### 組合式函數命名和結構 + +#### 基本 Composable 結構 +```typescript +// composables/useVocabulary.ts +import { ref, computed, type Ref } from 'vue' +import type { VocabularyWord, PracticeResult } from '@/types' + +// 選項介面 (如果需要) +interface UseVocabularyOptions { + autoLoad?: boolean + cacheEnabled?: boolean +} + +// 返回類型定義 +interface UseVocabularyReturn { + // 狀態 + words: Readonly> + currentWord: Readonly> + isLoading: Readonly> + error: Readonly> + + // 計算屬性 + wordsCount: ComputedRef + hasWords: ComputedRef + + // 方法 + loadWords: (level: number) => Promise + selectWord: (wordId: string) => void + submitPractice: (result: PracticeResult) => Promise + reset: () => void +} + +// 主要函數 +export function useVocabulary( + initialLevel: number = 1, + options: UseVocabularyOptions = {} +): UseVocabularyReturn { + // 預設選項 + const { autoLoad = true, cacheEnabled = true } = options + + // 響應式狀態 + const words = ref([]) + const currentWord = ref(null) + const isLoading = ref(false) + const error = ref(null) + + // 計算屬性 + const wordsCount = computed(() => words.value.length) + const hasWords = computed(() => words.value.length > 0) + + // 私有方法 + const clearError = () => { + error.value = null + } + + // 公開方法 + const loadWords = async (level: number) => { + try { + isLoading.value = true + clearError() + + const response = await vocabularyApi.getWordsByLevel(level) + words.value = response.data + + if (words.value.length > 0) { + currentWord.value = words.value[0] + } + } catch (err) { + error.value = '載入詞彙失敗' + console.error('Failed to load vocabulary:', err) + } finally { + isLoading.value = false + } + } + + const selectWord = (wordId: string) => { + const word = words.value.find(w => w.id === wordId) + if (word) { + currentWord.value = word + } + } + + const submitPractice = async (result: PracticeResult) => { + try { + isLoading.value = true + await vocabularyApi.submitPracticeResult(result) + + // 更新本地狀態 + const wordIndex = words.value.findIndex(w => w.id === result.wordId) + if (wordIndex !== -1) { + words.value[wordIndex].practiceCount = (words.value[wordIndex].practiceCount || 0) + 1 + } + } catch (err) { + error.value = '提交練習結果失敗' + throw err + } finally { + isLoading.value = false + } + } + + const reset = () => { + words.value = [] + currentWord.value = null + clearError() + } + + // 自動載入 (如果啟用) + if (autoLoad) { + loadWords(initialLevel) + } + + return { + // 只讀狀態 + words: readonly(words), + currentWord: readonly(currentWord), + isLoading: readonly(isLoading), + error: readonly(error), + + // 計算屬性 + wordsCount, + hasWords, + + // 方法 + loadWords, + selectWord, + submitPractice, + reset + } +} +``` + +#### 複雜 Composable 範例 +```typescript +// composables/useDialogue.ts +export function useDialogue(scenarioId: string) { + // 多個狀態管理 + const messages = ref([]) + const currentScene = ref(null) + const userInput = ref('') + const isRecording = ref(false) + const analysisResult = ref(null) + + // 計算屬性 + const canSubmit = computed(() => userInput.value.trim().length > 0) + const messageCount = computed(() => messages.value.length) + const lastMessage = computed(() => { + return messages.value[messages.value.length - 1] || null + }) + + // 組合其他 composables + const { record, stopRecording } = useSpeechRecognition() + const { playAudio } = useAudio() + const { analyzeResponse } = useAI() + + // 複雜業務邏輯 + const startDialogue = async () => { + try { + const scene = await dialogueApi.getScene(scenarioId) + currentScene.value = scene + + // 添加系統開場白 + messages.value.push({ + id: generateId(), + type: 'system', + content: scene.opening, + timestamp: Date.now() + }) + + // 播放開場音頻 + if (scene.opening_audio) { + await playAudio(scene.opening_audio) + } + } catch (error) { + console.error('Failed to start dialogue:', error) + throw error + } + } + + const sendMessage = async (content: string) => { + // 添加用戶消息 + const userMessage: DialogueMessage = { + id: generateId(), + type: 'user', + content: content.trim(), + timestamp: Date.now() + } + messages.value.push(userMessage) + + // 清空輸入 + userInput.value = '' + + try { + // AI 分析和回應 + const analysis = await analyzeResponse(content, currentScene.value) + analysisResult.value = analysis + + // 添加系統回應 + const systemMessage: DialogueMessage = { + id: generateId(), + type: 'system', + content: analysis.response, + timestamp: Date.now(), + analysis: analysis + } + messages.value.push(systemMessage) + + // 播放回應音頻 + if (analysis.audio_url) { + await playAudio(analysis.audio_url) + } + + } catch (error) { + // 錯誤處理 + const errorMessage: DialogueMessage = { + id: generateId(), + type: 'error', + content: '抱歉,系統發生錯誤,請稍後再試。', + timestamp: Date.now() + } + messages.value.push(errorMessage) + } + } + + // 語音輸入處理 + const startVoiceInput = async () => { + try { + isRecording.value = true + const transcript = await record() + userInput.value = transcript + } finally { + isRecording.value = false + } + } + + const stopVoiceInput = () => { + stopRecording() + isRecording.value = false + } + + return { + // 狀態 + messages: readonly(messages), + currentScene: readonly(currentScene), + userInput, + isRecording: readonly(isRecording), + analysisResult: readonly(analysisResult), + + // 計算屬性 + canSubmit, + messageCount, + lastMessage, + + // 方法 + startDialogue, + sendMessage, + startVoiceInput, + stopVoiceInput + } +} +``` + +### Composable 使用規範 + +#### 在組件中正確使用 +```vue + +``` + +## 🎨 樣式開發規範 + +### SCSS 組織結構 + +#### 樣式檔案組織 +```scss +// assets/styles/main.scss +// 1. 變數和混合器 +@import 'variables'; +@import 'mixins'; + +// 2. 基礎樣式 +@import 'base/reset'; +@import 'base/typography'; +@import 'base/layout'; + +// 3. 組件樣式 +@import 'components/buttons'; +@import 'components/forms'; +@import 'components/cards'; + +// 4. 工具類 +@import 'utilities/spacing'; +@import 'utilities/colors'; + +// 5. 響應式斷點 +@import 'responsive'; +``` + +#### 變數命名規範 +```scss +// assets/styles/_variables.scss + +// 色彩系統 +$color-primary: #1976d2; +$color-primary-light: lighten($color-primary, 20%); +$color-primary-dark: darken($color-primary, 20%); + +$color-secondary: #26a69a; +$color-accent: #9c27b0; + +$color-success: #21ba45; +$color-warning: #f2c037; +$color-error: #c10015; +$color-info: #31ccec; + +// 灰階 +$color-grey-1: #fafafa; +$color-grey-2: #f5f5f5; +$color-grey-3: #eeeeee; +$color-grey-4: #e0e0e0; +$color-grey-5: #bdbdbd; + +// 字體 +$font-family-primary: 'Inter', sans-serif; +$font-family-secondary: 'Roboto', sans-serif; + +$font-size-xs: 0.75rem; // 12px +$font-size-sm: 0.875rem; // 14px +$font-size-base: 1rem; // 16px +$font-size-lg: 1.125rem; // 18px +$font-size-xl: 1.25rem; // 20px + +// 間距 +$spacing-xs: 0.25rem; // 4px +$spacing-sm: 0.5rem; // 8px +$spacing-md: 1rem; // 16px +$spacing-lg: 1.5rem; // 24px +$spacing-xl: 2rem; // 32px + +// 響應式斷點 +$breakpoint-xs: 0; +$breakpoint-sm: 600px; +$breakpoint-md: 1024px; +$breakpoint-lg: 1440px; +$breakpoint-xl: 1920px; + +// Z-index 層級 +$z-index-dropdown: 1000; +$z-index-modal: 1050; +$z-index-popover: 1060; +$z-index-tooltip: 1070; +$z-index-toast: 1080; +``` + +#### 混合器和工具 +```scss +// assets/styles/_mixins.scss + +// 響應式混合器 +@mixin respond-to($breakpoint) { + @if $breakpoint == xs { + @media (max-width: #{$breakpoint-sm - 1px}) { @content; } + } + @if $breakpoint == sm { + @media (min-width: #{$breakpoint-sm}) and (max-width: #{$breakpoint-md - 1px}) { @content; } + } + @if $breakpoint == md { + @media (min-width: #{$breakpoint-md}) and (max-width: #{$breakpoint-lg - 1px}) { @content; } + } + @if $breakpoint == lg { + @media (min-width: #{$breakpoint-lg}) { @content; } + } +} + +// 文字省略 +@mixin text-ellipsis($lines: 1) { + @if $lines == 1 { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } @else { + display: -webkit-box; + -webkit-line-clamp: $lines; + -webkit-box-orient: vertical; + overflow: hidden; + } +} + +// 載入動畫 +@mixin loading-skeleton { + background: linear-gradient(90deg, $color-grey-2 25%, $color-grey-1 50%, $color-grey-2 75%); + background-size: 200% 100%; + animation: loading 1.5s infinite; +} + +@keyframes loading { + 0% { background-position: 200% 0; } + 100% { background-position: -200% 0; } +} + +// 卡片陰影 +@mixin card-shadow($level: 1) { + @if $level == 1 { + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + } + @if $level == 2 { + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.08); + } + @if $level == 3 { + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15), 0 4px 8px rgba(0, 0, 0, 0.1); + } +} +``` + +### 組件樣式規範 + +#### BEM 命名方法 +```scss +// ✅ 正確:使用 BEM 命名 +.vocabulary-card { + @include card-shadow(1); + + &__header { + padding: $spacing-md; + border-bottom: 1px solid $color-grey-3; + + &--highlighted { + background-color: $color-primary-light; + } + } + + &__content { + padding: $spacing-md; + } + + &__word { + font-size: $font-size-lg; + font-weight: 600; + color: $color-primary; + + &--difficult { + color: $color-warning; + } + } + + &--disabled { + opacity: 0.5; + pointer-events: none; + } +} + +// ❌ 錯誤:嵌套過深,命名不清楚 +.vocabulary-card { + .header { + .title { + .word { + .text { + color: blue; // 嵌套過深且使用硬編碼顏色 + } + } + } + } +} +``` + +#### 響應式設計實作 +```scss +.vocabulary-practice { + display: grid; + grid-template-columns: 1fr; + gap: $spacing-md; + padding: $spacing-md; + + // 平板以上:雙欄佈局 + @include respond-to(sm) { + grid-template-columns: 1fr 1fr; + padding: $spacing-lg; + } + + // 桌面:三欄佈局 + @include respond-to(md) { + grid-template-columns: repeat(3, 1fr); + gap: $spacing-lg; + padding: $spacing-xl; + } + + &__card { + @include card-shadow(1); + transition: transform 0.2s ease; + + &:hover { + transform: translateY(-2px); + @include card-shadow(2); + } + + // 手機上禁用 hover 效果 + @include respond-to(xs) { + &:hover { + transform: none; + box-shadow: none; + } + } + } +} +``` + +## 🧪 測試規範 + +### 單元測試規範 + +#### 組件測試範例 +```typescript +// tests/unit/components/VocabularyCard.test.ts +import { mount } from '@vue/test-utils' +import { describe, it, expect, beforeEach, vi } from 'vitest' +import { createPinia, setActivePinia } from 'pinia' +import VocabularyCard from '@/components/business/VocabularyCard.vue' +import type { VocabularyWord } from '@/types' + +// 測試數據 +const mockWord: VocabularyWord = { + id: '1', + text: 'hello', + pronunciation: '/həˈloʊ/', + definition: '你好,哈囉', + audio_url: '/audio/hello.mp3', + difficulty: 1 +} + +// Mock 外部依賴 +const mockPlayAudio = vi.fn() +vi.mock('@/composables/useAudio', () => ({ + useAudio: () => ({ + playAudio: mockPlayAudio, + isLoading: false + }) +})) + +describe('VocabularyCard', () => { + beforeEach(() => { + // 重置 Pinia store + setActivePinia(createPinia()) + + // 重置 mocks + vi.clearAllMocks() + }) + + it('renders word information correctly', () => { + const wrapper = mount(VocabularyCard, { + props: { word: mockWord } + }) + + // 測試渲染內容 + expect(wrapper.find('[data-test="word-text"]').text()).toBe('hello') + expect(wrapper.find('[data-test="pronunciation"]').text()).toBe('/həˈloʊ/') + expect(wrapper.find('[data-test="definition"]').text()).toBe('你好,哈囉') + }) + + it('plays audio when pronunciation button is clicked', async () => { + const wrapper = mount(VocabularyCard, { + props: { word: mockWord } + }) + + const playButton = wrapper.find('[data-test="play-audio"]') + await playButton.trigger('click') + + expect(mockPlayAudio).toHaveBeenCalledWith('/audio/hello.mp3') + }) + + it('emits select event when card is clicked', async () => { + const wrapper = mount(VocabularyCard, { + props: { word: mockWord } + }) + + await wrapper.trigger('click') + + expect(wrapper.emitted('select')).toBeTruthy() + expect(wrapper.emitted('select')?.[0]).toEqual([mockWord.id]) + }) + + it('applies correct CSS classes based on difficulty', () => { + const easyWord = { ...mockWord, difficulty: 1 } + const hardWord = { ...mockWord, difficulty: 3 } + + const easyWrapper = mount(VocabularyCard, { props: { word: easyWord } }) + const hardWrapper = mount(VocabularyCard, { props: { word: hardWord } }) + + expect(easyWrapper.classes()).toContain('vocabulary-card--easy') + expect(hardWrapper.classes()).toContain('vocabulary-card--hard') + }) + + it('handles disabled state correctly', () => { + const wrapper = mount(VocabularyCard, { + props: { + word: mockWord, + disabled: true + } + }) + + expect(wrapper.classes()).toContain('vocabulary-card--disabled') + expect(wrapper.find('[data-test="play-audio"]').attributes('disabled')).toBeDefined() + }) +}) +``` + +#### Composable 測試範例 +```typescript +// tests/unit/composables/useVocabulary.test.ts +import { describe, it, expect, beforeEach, vi } from 'vitest' +import { useVocabulary } from '@/composables/useVocabulary' +import { flushPromises } from '@vue/test-utils' + +// Mock API +const mockVocabularyApi = { + getWordsByLevel: vi.fn(), + submitPracticeResult: vi.fn() +} + +vi.mock('@/services/vocabularyApi', () => ({ + vocabularyApi: mockVocabularyApi +})) + +describe('useVocabulary', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + it('loads words on initialization when autoLoad is true', async () => { + mockVocabularyApi.getWordsByLevel.mockResolvedValue({ + data: [mockWord] + }) + + const { words, isLoading, loadWords } = useVocabulary(1, { autoLoad: true }) + + // 初始狀態檢查 + expect(isLoading.value).toBe(true) + + await flushPromises() + + // 載入完成後狀態檢查 + expect(isLoading.value).toBe(false) + expect(words.value).toEqual([mockWord]) + expect(mockVocabularyApi.getWordsByLevel).toHaveBeenCalledWith(1) + }) + + it('handles API errors gracefully', async () => { + const errorMessage = 'API Error' + mockVocabularyApi.getWordsByLevel.mockRejectedValue(new Error(errorMessage)) + + const { error, loadWords } = useVocabulary(1, { autoLoad: false }) + + await loadWords(1) + await flushPromises() + + expect(error.value).toBe('載入詞彙失敗') + }) + + it('calculates computed properties correctly', async () => { + mockVocabularyApi.getWordsByLevel.mockResolvedValue({ + data: [mockWord, { ...mockWord, id: '2' }] + }) + + const { words, wordsCount, hasWords } = useVocabulary(1) + + await flushPromises() + + expect(wordsCount.value).toBe(2) + expect(hasWords.value).toBe(true) + }) +}) +``` + +### E2E 測試規範 + +#### 用戶流程測試 +```typescript +// tests/e2e/vocabulary-learning.cy.ts +describe('Vocabulary Learning Flow', () => { + beforeEach(() => { + // 登入用戶 + cy.login('test@example.com', 'password') + + // 模擬 API 回應 + cy.intercept('GET', '/api/vocabulary/level/1', { + fixture: 'vocabulary-words.json' + }).as('getWords') + }) + + it('completes vocabulary learning session', () => { + // 導航到詞彙學習頁面 + cy.visit('/vocabulary/introduction/word-1') + + // 等待數據載入 + cy.wait('@getWords') + + // 檢查頁面內容 + cy.get('[data-test="word-text"]').should('be.visible') + cy.get('[data-test="definition"]').should('contain', '你好') + + // 播放音頻 + cy.get('[data-test="play-audio"]').click() + + // 進入練習模式 + cy.get('[data-test="start-practice"]').click() + + // 完成選擇題練習 + cy.get('[data-test="practice-option-1"]').click() + cy.get('[data-test="submit-answer"]').click() + + // 檢查結果 + cy.get('[data-test="result-correct"]').should('be.visible') + + // 繼續下一個詞彙 + cy.get('[data-test="next-word"]').click() + + // 檢查進度更新 + cy.get('[data-test="progress-bar"]').should('have.attr', 'aria-valuenow', '50') + }) + + it('handles practice errors gracefully', () => { + // 模擬 API 錯誤 + cy.intercept('POST', '/api/vocabulary/practice', { + statusCode: 500, + body: { error: 'Server error' } + }).as('practiceError') + + cy.visit('/vocabulary/practice') + + // 提交答案 + cy.get('[data-test="practice-option-1"]').click() + cy.get('[data-test="submit-answer"]').click() + + cy.wait('@practiceError') + + // 檢查錯誤處理 + cy.get('[data-test="error-message"]') + .should('be.visible') + .and('contain', '提交失敗,請稍後再試') + + // 檢查重試按鈕 + cy.get('[data-test="retry-button"]').should('be.visible') + }) +}) +``` + +## 📋 代碼審查檢查清單 + +### 組件審查要點 +- [ ] 組件命名使用 PascalCase +- [ ] Props 有明確的 TypeScript 類型定義 +- [ ] 使用 `defineEmits` 定義所有事件 +- [ ] 計算屬性使用 `computed()` 而非方法 +- [ ] 使用 `readonly()` 暴露響應式狀態 +- [ ] 組件有適當的測試覆蓋 +- [ ] 樣式使用 scoped 或 CSS Modules +- [ ] 遵循無障礙性最佳實踐 + +### 性能審查要點 +- [ ] 避免在模板中直接調用方法 +- [ ] 使用 `v-memo` 優化重複渲染 +- [ ] 大列表使用虛擬滾動 +- [ ] 圖片使用 lazy loading +- [ ] 組件使用 `defineAsyncComponent` 懶載入 +- [ ] 避免不必要的響應式包裝 + +### 安全性審查要點 +- [ ] 用戶輸入已進行適當清理 +- [ ] 使用 `v-html` 時已進行 XSS 防護 +- [ ] API 調用包含錯誤處理 +- [ ] 敏感資料不在客戶端暴露 +- [ ] 路由包含適當的權限檢查 + +--- + +**文檔狀態**: 🟢 完整開發規範 +**最後更新**: 2025-09-09 +**適用版本**: Vue 3 + Composition API +**維護團隊**: 前端開發團隊 \ No newline at end of file diff --git a/docs/04_technical/03_frontend/vue-frontend-architecture.md b/docs/04_technical/03_frontend/vue-frontend-architecture.md new file mode 100644 index 0000000..cee896c --- /dev/null +++ b/docs/04_technical/03_frontend/vue-frontend-architecture.md @@ -0,0 +1,1114 @@ +# Drama Ling Vue.js前端技術架構規劃 + +## 📋 架構概述 + +**專案名稱**: Drama Ling 語言學習應用 (Web端) +**建立日期**: 2025-09-09 +**技術主軸**: Vue.js 3 + Composition API +**對應後端**: .NET Core API +**部署目標**: 響應式Web應用程式 + +### 核心設計目標 +- 🎯 **學習體驗優化**: 支援語音互動、即時AI分析 +- 📱 **響應式設計**: 桌面優先,兼容平板和手機 +- 🚀 **效能優化**: 快速載入、流暢互動 +- 🔒 **企業級安全**: 資料保護、安全認證 +- 💎 **商業功能**: 支付整合、訂閱管理 + +## 🛠️ Vue.js 技術堆疊 + +### 核心框架 +```javascript +{ + "vue": "3.4.x", // 最新穩定版,全面使用Composition API + "vue-router": "4.3.x", // Vue 3 官方路由 + "pinia": "2.1.x", // Vue 3 推薦狀態管理 + "vite": "5.x", // 現代化建構工具 + "typescript": "5.x", // 強型別支援 + "vue-tsc": "latest" // Vue TypeScript支援 +} +``` + +### UI框架選擇 +```javascript +// 推薦方案:Quasar Framework +{ + "quasar": "2.16.x", // 企業級UI框架,支援響應式和PWA + "quasar-cli": "2.4.x", // 完整開發工具鏈 + + // 替代方案 + "element-plus": "2.7.x", // 成熟穩定,企業級組件 + "vuetify": "3.6.x", // Material Design風格 + "ant-design-vue": "4.2.x" // 豐富組件生態 +} +``` + +### 工具鏈配置 +```javascript +{ + "dev_tools": { + "eslint": "9.x", // 代碼檢查 + "prettier": "3.x", // 代碼格式化 + "stylelint": "16.x", // CSS檢查 + "husky": "9.x", // Git hooks + "lint-staged": "15.x", // 暫存檔檢查 + "vitest": "1.6.x", // Vue生態測試框架 + "@vue/test-utils": "2.4.x" // Vue組件測試 + }, + "build_tools": { + "vite": "5.x", // 快速建構 + "unplugin-vue-components": "0.27.x", // 自動導入組件 + "unplugin-auto-import": "0.17.x", // 自動導入API + "@vitejs/plugin-pwa": "0.20.x" // PWA支援 + } +} +``` + +## 🏗️ 專案結構設計 + +### 整體目錄結構 +``` +web-frontend/ +├── public/ +│ ├── icons/ # PWA圖標 +│ ├── audio/ # 音頻素材 +│ └── manifest.json # PWA配置 +├── src/ +│ ├── assets/ # 靜態資源 +│ │ ├── images/ +│ │ ├── audio/ +│ │ └── styles/ +│ ├── components/ # 共用組件 +│ │ ├── base/ # 基礎組件 +│ │ ├── business/ # 業務組件 +│ │ └── layout/ # 佈局組件 +│ ├── composables/ # 組合式函數 +│ │ ├── useAuth.ts +│ │ ├── useAudio.ts +│ │ └── useApi.ts +│ ├── modules/ # 功能模組 +│ │ ├── auth/ # 認證模組 +│ │ ├── vocabulary/ # 詞彙學習 +│ │ ├── dialogue/ # 情境對話 +│ │ ├── learning-map/ # 學習地圖 +│ │ └── shop/ # 道具商店 +│ ├── router/ # 路由配置 +│ ├── stores/ # Pinia狀態管理 +│ ├── services/ # API服務層 +│ ├── types/ # TypeScript類型定義 +│ ├── utils/ # 工具函數 +│ ├── App.vue # 根組件 +│ └── main.ts # 應用入口 +├── tests/ # 測試檔案 +├── docs/ # 專案文檔 +└── deployment/ # 部署配置 +``` + +### 模組化設計 +```typescript +// modules/vocabulary/index.ts +export interface VocabularyModule { + routes: RouteRecordRaw[] + store: StoreDefinition + components: ComponentMap + services: ServiceMap +} + +// 每個模組包含完整的功能實現 +// modules/vocabulary/ +├── components/ +├── composables/ +├── services/ +├── stores/ +├── types/ +├── views/ +└── router.ts +``` + +## 🔄 狀態管理架構 + +### Pinia Store 組織 +```typescript +// stores/index.ts +export interface StoreMap { + auth: AuthStore + user: UserStore + vocabulary: VocabularyStore + dialogue: DialogueStore + shop: ShopStore + ui: UIStore + audio: AudioStore +} + +// stores/auth.ts +export const useAuthStore = defineStore('auth', () => { + const user = ref(null) + const token = ref(null) + const isAuthenticated = computed(() => !!token.value) + + const login = async (credentials: LoginCredentials) => { + // API調用和狀態更新 + } + + const logout = () => { + user.value = null + token.value = null + router.push('/login') + } + + return { + user: readonly(user), + token: readonly(token), + isAuthenticated, + login, + logout + } +}) +``` + +### 全局狀態設計 +```typescript +// stores/ui.ts - UI狀態管理 +export const useUIStore = defineStore('ui', () => { + const theme = ref<'light' | 'dark'>('light') + const language = ref<'zh-TW' | 'en'>('zh-TW') + const sidebar = ref(false) + const loading = ref(false) + const notifications = ref([]) + + return { + theme, language, sidebar, loading, notifications + } +}) + +// stores/learning.ts - 學習進度狀態 +export const useLearningStore = defineStore('learning', () => { + const currentLevel = ref(1) + const diamonds = ref(500) + const lives = ref(5) + const streak = ref(0) + const vocabularyProgress = ref(new Map()) + + return { + currentLevel, diamonds, lives, streak, vocabularyProgress + } +}) +``` + +## 🎨 UI框架整合 + +### Quasar框架配置 +```javascript +// quasar.config.js +export default configure(function (ctx) { + return { + framework: { + config: { + brand: { + primary: '#1976d2', // Drama Ling 主色調 + secondary: '#26a69a', + accent: '#9c27b0', + positive: '#21ba45', + negative: '#c10015', + info: '#31ccec', + warning: '#f2c037' + } + }, + + plugins: [ + 'Loading', + 'QSpinnerGears', + 'Dialog', + 'Notify', + 'LocalStorage', + 'SessionStorage' + ], + + components: [ + 'QLayout', 'QHeader', 'QDrawer', 'QPageContainer', 'QPage', + 'QToolbar', 'QToolbarTitle', 'QBtn', 'QIcon', 'QList', + 'QItem', 'QItemSection', 'QItemLabel', 'QCard', 'QCardSection', + 'QInput', 'QSelect', 'QCheckbox', 'QRadio', 'QToggle', + 'QSlider', 'QRange', 'QBadge', 'QChip', 'QAvatar', + 'QImg', 'QVideo', 'QAudio', 'QLinearProgress', 'QCircularProgress' + ] + } + } +}) +``` + +### 響應式設計策略 +```scss +// assets/styles/responsive.scss +$breakpoint-xs: 0; +$breakpoint-sm: 600px; +$breakpoint-md: 1024px; +$breakpoint-lg: 1440px; +$breakpoint-xl: 1920px; + +// Vue組件中的響應式設計 +.vocabulary-card { + @media (max-width: 600px) { + padding: 8px; + font-size: 14px; + } + + @media (min-width: 601px) and (max-width: 1023px) { + padding: 12px; + font-size: 16px; + } + + @media (min-width: 1024px) { + padding: 16px; + font-size: 18px; + } +} +``` + +## 🚦 路由和導航 + +### Vue Router配置 +```typescript +// router/index.ts +import { createRouter, createWebHistory } from 'vue-router' +import type { RouteRecordRaw } from 'vue-router' + +const routes: RouteRecordRaw[] = [ + { + path: '/', + component: () => import('@/layouts/MainLayout.vue'), + children: [ + { + path: '', + name: 'Home', + component: () => import('@/views/HomePage.vue'), + meta: { requiresAuth: false } + }, + { + path: '/vocabulary', + name: 'VocabularyModule', + component: () => import('@/modules/vocabulary/VocabularyLayout.vue'), + children: [ + { + path: 'introduction/:wordId', + name: 'VocabularyIntroduction', + component: () => import('@/modules/vocabulary/views/IntroductionPage.vue'), + props: true + } + ] + } + ] + }, + { + path: '/auth', + component: () => import('@/layouts/AuthLayout.vue'), + children: [ + { + path: 'login', + name: 'Login', + component: () => import('@/modules/auth/views/LoginPage.vue') + } + ] + } +] + +export const router = createRouter({ + history: createWebHistory(), + routes, + scrollBehavior(to, from, savedPosition) { + if (savedPosition) { + return savedPosition + } + return { top: 0 } + } +}) + +// 路由守衛 +router.beforeEach((to, from, next) => { + const authStore = useAuthStore() + + if (to.meta.requiresAuth && !authStore.isAuthenticated) { + next({ name: 'Login' }) + } else { + next() + } +}) +``` + +### 導航組件設計 +```vue + + + + +``` + +## 🔌 API服務層架構 + +### HTTP客戶端配置 +```typescript +// services/http.ts +import axios from 'axios' +import type { AxiosInstance, AxiosResponse } from 'axios' + +class HttpClient { + private client: AxiosInstance + + constructor() { + this.client = axios.create({ + baseURL: import.meta.env.VITE_API_BASE_URL, + timeout: 10000, + headers: { + 'Content-Type': 'application/json' + } + }) + + this.setupInterceptors() + } + + private setupInterceptors() { + // 請求攔截器 + this.client.interceptors.request.use( + (config) => { + const authStore = useAuthStore() + if (authStore.token) { + config.headers.Authorization = `Bearer ${authStore.token}` + } + return config + }, + (error) => Promise.reject(error) + ) + + // 響應攔截器 + this.client.interceptors.response.use( + (response) => response, + (error) => { + if (error.response?.status === 401) { + const authStore = useAuthStore() + authStore.logout() + } + return Promise.reject(error) + } + ) + } + + async get(url: string, params?: any): Promise { + const response: AxiosResponse = await this.client.get(url, { params }) + return response.data + } + + async post(url: string, data?: any): Promise { + const response: AxiosResponse = await this.client.post(url, data) + return response.data + } +} + +export const httpClient = new HttpClient() +``` + +### API服務抽象 +```typescript +// services/vocabularyApi.ts +export class VocabularyApiService { + private basePath = '/api/vocabulary' + + async getWordIntroduction(wordId: string): Promise { + return httpClient.get(`${this.basePath}/words/${wordId}`) + } + + async submitPracticeResult(result: PracticeResult): Promise { + return httpClient.post(`${this.basePath}/practice`, result) + } + + async getReviewSchedule(): Promise { + return httpClient.get(`${this.basePath}/review/schedule`) + } +} + +export const vocabularyApi = new VocabularyApiService() +``` + +### API類型定義 +```typescript +// types/api.ts +export interface VocabularyWord { + id: string + word: string + pronunciation: string + definition_zh: string + definition_en?: string + part_of_speech: string + examples: Example[] + usage_context: string + related_words: string[] + frequency_level: number + audio_url: string +} + +export interface PracticeResult { + word_id: string + practice_type: 'choice' | 'matching' | 'reorganize' + is_correct: boolean + response_time: number + user_answer: string + correct_answer: string +} +``` + +## 🎵 音頻處理整合 + +### Web Audio API整合 +```typescript +// composables/useAudio.ts +export const useAudio = () => { + const audioContext = ref(null) + const isPlaying = ref(false) + const currentTrack = ref(null) + + const initializeAudio = () => { + if (!audioContext.value) { + audioContext.value = new AudioContext() + } + } + + const playAudio = async (url: string, playbackRate: number = 1.0) => { + try { + initializeAudio() + isPlaying.value = true + currentTrack.value = url + + const response = await fetch(url) + const arrayBuffer = await response.arrayBuffer() + const audioBuffer = await audioContext.value!.decodeAudioData(arrayBuffer) + + const source = audioContext.value!.createBufferSource() + source.buffer = audioBuffer + source.playbackRate.value = playbackRate + source.connect(audioContext.value!.destination) + + source.onended = () => { + isPlaying.value = false + currentTrack.value = null + } + + source.start() + return source + } catch (error) { + console.error('Audio playback failed:', error) + isPlaying.value = false + } + } + + const recordAudio = async (): Promise => { + try { + const stream = await navigator.mediaDevices.getUserMedia({ audio: true }) + const mediaRecorder = new MediaRecorder(stream) + return mediaRecorder + } catch (error) { + console.error('Audio recording failed:', error) + return null + } + } + + return { + isPlaying: readonly(isPlaying), + currentTrack: readonly(currentTrack), + playAudio, + recordAudio + } +} +``` + +### 語音識別整合 +```typescript +// composables/useSpeechRecognition.ts +export const useSpeechRecognition = () => { + const isListening = ref(false) + const transcript = ref('') + const confidence = ref(0) + + let recognition: SpeechRecognition | null = null + + const startListening = (language: string = 'zh-TW') => { + if (!('webkitSpeechRecognition' in window) && !('SpeechRecognition' in window)) { + throw new Error('Speech recognition not supported') + } + + const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition + recognition = new SpeechRecognition() + + recognition.continuous = false + recognition.interimResults = true + recognition.lang = language + + recognition.onstart = () => { + isListening.value = true + } + + recognition.onresult = (event) => { + const result = event.results[event.results.length - 1] + transcript.value = result[0].transcript + confidence.value = result[0].confidence + } + + recognition.onend = () => { + isListening.value = false + } + + recognition.start() + } + + const stopListening = () => { + if (recognition) { + recognition.stop() + } + } + + return { + isListening: readonly(isListening), + transcript: readonly(transcript), + confidence: readonly(confidence), + startListening, + stopListening + } +} +``` + +## 💎 商業功能整合 + +### 支付系統整合 +```typescript +// services/paymentService.ts +export class PaymentService { + async initializeStripe() { + const stripe = await loadStripe(import.meta.env.VITE_STRIPE_PUBLIC_KEY) + return stripe + } + + async createPaymentIntent(amount: number, currency: string = 'TWD') { + return httpClient.post('/api/payment/create-intent', { + amount, + currency + }) + } + + async purchaseDiamonds(packageId: string) { + const stripe = await this.initializeStripe() + const { client_secret } = await this.createPaymentIntent(packageId) + + const result = await stripe!.confirmCardPayment(client_secret) + + if (result.error) { + throw new Error(result.error.message) + } + + return result.paymentIntent + } +} +``` + +### 訂閱管理 +```typescript +// composables/useSubscription.ts +export const useSubscription = () => { + const subscription = ref(null) + const isVIP = computed(() => subscription.value?.status === 'active') + + const subscribeToVIP = async (planId: string) => { + const paymentService = new PaymentService() + const result = await paymentService.createSubscription(planId) + subscription.value = result + return result + } + + const cancelSubscription = async () => { + await httpClient.post('/api/subscription/cancel') + await refreshSubscription() + } + + const refreshSubscription = async () => { + subscription.value = await httpClient.get('/api/subscription/current') + } + + return { + subscription: readonly(subscription), + isVIP, + subscribeToVIP, + cancelSubscription, + refreshSubscription + } +} +``` + +## 🚀 效能優化策略 + +### 代碼分割和懶載入 +```typescript +// router/index.ts - 路由層面的懶載入 +const routes = [ + { + path: '/vocabulary', + component: () => import('@/modules/vocabulary/VocabularyModule.vue') + }, + { + path: '/dialogue', + component: () => import( + /* webpackChunkName: "dialogue" */ + '@/modules/dialogue/DialogueModule.vue' + ) + } +] + +// components - 組件層面的懶載入 +export const LazyVocabularyCard = defineAsyncComponent({ + loader: () => import('./VocabularyCard.vue'), + loadingComponent: LoadingSpinner, + errorComponent: ErrorComponent, + delay: 200, + timeout: 3000 +}) +``` + +### 狀態持久化 +```typescript +// stores/persistence.ts +import { createPersistencePlugin } from 'pinia-plugin-persistedstate' + +export const persistencePlugin = createPersistencePlugin({ + key: (id) => `__dramaling_${id}__`, + storage: localStorage, + serializer: { + serialize: JSON.stringify, + deserialize: JSON.parse + }, + beforeRestore: (context) => { + console.log('Before restore:', context.store.$id) + }, + afterRestore: (context) => { + console.log('After restore:', context.store.$id) + } +}) +``` + +### 快取策略 +```typescript +// composables/useCache.ts +export const useCache = (key: string, ttl: number = 300000) => { + const cache = new Map() + + const get = (cacheKey: string): T | null => { + const cached = cache.get(cacheKey) + if (!cached) return null + + if (Date.now() - cached.timestamp > ttl) { + cache.delete(cacheKey) + return null + } + + return cached.data + } + + const set = (cacheKey: string, data: T): void => { + cache.set(cacheKey, { + data, + timestamp: Date.now() + }) + } + + return { get, set } +} +``` + +## 🔒 安全性實作 + +### XSS防護 +```typescript +// utils/sanitizer.ts +import DOMPurify from 'dompurify' + +export const sanitizeHtml = (html: string): string => { + return DOMPurify.sanitize(html, { + ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'span'], + ALLOWED_ATTR: ['class'] + }) +} + +export const sanitizeInput = (input: string): string => { + return input.replace(/[<>'"&]/g, (match) => { + const escapeMap: Record = { + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '&': '&' + } + return escapeMap[match] + }) +} +``` + +### CSRF防護 +```typescript +// services/csrf.ts +export class CSRFService { + private token: string | null = null + + async getCSRFToken(): Promise { + if (!this.token) { + const response = await httpClient.get<{token: string}>('/api/csrf-token') + this.token = response.token + } + return this.token + } + + async addCSRFHeader(config: any) { + const token = await this.getCSRFToken() + config.headers['X-CSRF-Token'] = token + return config + } +} +``` + +## 🧪 測試策略 + +### 單元測試配置 +```typescript +// vitest.config.ts +import { defineConfig } from 'vitest/config' +import vue from '@vitejs/plugin-vue' + +export default defineConfig({ + plugins: [vue()], + test: { + environment: 'happy-dom', + globals: true, + coverage: { + provider: 'v8', + reporter: ['text', 'json-summary', 'html'], + threshold: { + global: { + branches: 80, + functions: 80, + lines: 80, + statements: 80 + } + } + } + } +}) +``` + +### 組件測試範例 +```typescript +// tests/components/VocabularyCard.test.ts +import { mount } from '@vue/test-utils' +import { describe, it, expect } from 'vitest' +import VocabularyCard from '@/components/VocabularyCard.vue' + +describe('VocabularyCard', () => { + it('renders vocabulary word correctly', () => { + const wrapper = mount(VocabularyCard, { + props: { + word: { + id: '1', + word: 'hello', + pronunciation: '/həˈloʊ/', + definition_zh: '你好', + part_of_speech: 'interjection' + } + } + }) + + expect(wrapper.find('[data-test="word"]').text()).toBe('hello') + expect(wrapper.find('[data-test="pronunciation"]').text()).toBe('/həˈloʊ/') + expect(wrapper.find('[data-test="definition"]').text()).toBe('你好') + }) + + it('plays audio when pronunciation button is clicked', async () => { + const mockPlayAudio = vi.fn() + + const wrapper = mount(VocabularyCard, { + props: { word: mockWord }, + global: { + provide: { + playAudio: mockPlayAudio + } + } + }) + + await wrapper.find('[data-test="play-audio"]').trigger('click') + expect(mockPlayAudio).toHaveBeenCalledWith(mockWord.audio_url) + }) +}) +``` + +## 📦 建構和部署 + +### Vite建構配置 +```typescript +// vite.config.ts +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import { VitePWA } from 'vite-plugin-pwa' +import Components from 'unplugin-vue-components/vite' +import AutoImport from 'unplugin-auto-import/vite' + +export default defineConfig({ + plugins: [ + vue(), + Components({ + resolvers: [ + // 自動導入Quasar組件 + (componentName) => { + if (componentName.startsWith('Q')) + return { name: componentName, from: 'quasar' } + } + ] + }), + AutoImport({ + imports: [ + 'vue', + 'vue-router', + 'pinia', + { + 'quasar': ['useQuasar', '$q'] + } + ] + }), + VitePWA({ + registerType: 'autoUpdate', + manifest: { + name: 'Drama Ling', + short_name: 'DramaLing', + description: 'AI-powered language learning app', + theme_color: '#1976d2', + background_color: '#ffffff', + display: 'standalone', + icons: [ + { + src: '/icons/icon-192x192.png', + sizes: '192x192', + type: 'image/png' + } + ] + } + }) + ], + + resolve: { + alias: { + '@': path.resolve(__dirname, 'src') + } + }, + + build: { + rollupOptions: { + output: { + manualChunks: { + vendor: ['vue', 'vue-router', 'pinia'], + quasar: ['quasar'], + utils: ['axios', 'lodash-es'] + } + } + } + } +}) +``` + +### Docker部署配置 +```dockerfile +# Dockerfile +FROM node:18-alpine AS builder + +WORKDIR /app +COPY package*.json ./ +RUN npm ci --only=production + +COPY . . +RUN npm run build + +FROM nginx:alpine +COPY --from=builder /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/nginx.conf + +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] +``` + +### Nginx配置 +```nginx +# nginx.conf +server { + listen 80; + server_name dramaling.com; + + location / { + root /usr/share/nginx/html; + index index.html; + try_files $uri $uri/ /index.html; + } + + location /api/ { + proxy_pass http://backend:5000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + + gzip on; + gzip_types text/plain text/css application/json application/javascript; +} +``` + +## 📊 開發工作流程 + +### Git工作流程 +```yaml +# .github/workflows/ci.yml +name: CI/CD Pipeline +on: + push: + branches: [main, develop] + pull_request: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '18' + cache: 'npm' + + - run: npm ci + - run: npm run lint + - run: npm run type-check + - run: npm run test:unit + - run: npm run build + + deploy: + needs: test + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - name: Deploy to production + run: echo "Deploying to production server" +``` + +### 開發環境設置 +```json +// package.json scripts +{ + "scripts": { + "dev": "vite", + "build": "vue-tsc --noEmit && vite build", + "preview": "vite preview", + "test:unit": "vitest", + "test:e2e": "cypress run", + "lint": "eslint . --ext .vue,.ts,.tsx --fix", + "type-check": "vue-tsc --noEmit" + } +} +``` + +## 📈 監控和分析 + +### 性能監控 +```typescript +// utils/performance.ts +export class PerformanceMonitor { + static trackPageLoad(routeName: string) { + if (typeof window !== 'undefined' && 'performance' in window) { + const loadTime = window.performance.timing.loadEventEnd - window.performance.timing.navigationStart + + // 發送到分析服務 + this.sendMetric('page_load_time', loadTime, { route: routeName }) + } + } + + static trackUserAction(action: string, duration?: number) { + this.sendMetric('user_action', duration || 0, { action }) + } + + private static sendMetric(name: string, value: number, labels: Record) { + // 發送到Google Analytics、Mixpanel等 + if (window.gtag) { + window.gtag('event', name, { + value: value, + custom_parameter: labels + }) + } + } +} +``` + +## 📋 開發檢查清單 + +### 代碼品質檢查 +- [ ] ESLint檢查通過 +- [ ] TypeScript類型檢查無錯誤 +- [ ] 單元測試覆蓋率 > 80% +- [ ] 組件測試完整 +- [ ] E2E測試關鍵流程 + +### 性能檢查 +- [ ] 首屏載入時間 < 2秒 +- [ ] 代碼分割策略實施 +- [ ] 圖片資源優化 +- [ ] API請求優化 +- [ ] PWA功能測試 + +### 安全檢查 +- [ ] XSS防護實施 +- [ ] CSRF防護配置 +- [ ] 輸入驗證完整 +- [ ] 敏感資料加密 +- [ ] HTTPS配置 + +### 響應式檢查 +- [ ] 手機版佈局測試 +- [ ] 平板版佈局測試 +- [ ] 桌面版佈局測試 +- [ ] 觸控操作優化 +- [ ] 鍵盤導航支援 + +--- + +**文檔狀態**: 🟢 已完成技術架構規劃 +**最後更新**: 2025-09-09 +**負責團隊**: 前端開發團隊 +**下次檢查**: 開發開始前進行技術選型確認 \ No newline at end of file diff --git a/docs/04_technical/03_frontend/vue-project-structure.md b/docs/04_technical/03_frontend/vue-project-structure.md new file mode 100644 index 0000000..a8a2183 --- /dev/null +++ b/docs/04_technical/03_frontend/vue-project-structure.md @@ -0,0 +1,857 @@ +# Vue.js 項目結構和配置範例 + +## 📁 完整項目結構 + +``` +dramaling-web/ +├── .env.development # 開發環境變數 +├── .env.production # 生產環境變數 +├── .eslintrc.js # ESLint配置 +├── .gitignore # Git忽略檔案 +├── .prettierrc # Prettier配置 +├── index.html # HTML入口 +├── package.json # 專案依賴和腳本 +├── README.md # 專案說明 +├── tsconfig.json # TypeScript配置 +├── vite.config.ts # Vite配置 +├── vitest.config.ts # Vitest測試配置 +├── cypress.config.ts # E2E測試配置 +├── docker-compose.yml # Docker開發環境 +├── Dockerfile # Docker部署 +├── nginx.conf # Nginx配置 +│ +├── public/ # 公開靜態資源 +│ ├── favicon.ico +│ ├── manifest.json # PWA配置 +│ ├── robots.txt +│ └── icons/ # PWA圖標 +│ ├── icon-192x192.png +│ └── icon-512x512.png +│ +├── src/ # 源代碼 +│ ├── App.vue # 根組件 +│ ├── main.ts # 應用入口 +│ │ +│ ├── assets/ # 資源檔案 +│ │ ├── images/ # 圖片資源 +│ │ │ ├── logo.svg +│ │ │ └── backgrounds/ +│ │ ├── audio/ # 音頻檔案 +│ │ │ └── pronunciation/ +│ │ └── styles/ # 全域樣式 +│ │ ├── main.scss +│ │ ├── variables.scss +│ │ └── components.scss +│ │ +│ ├── components/ # 共用組件 +│ │ ├── base/ # 基礎組件 +│ │ │ ├── BaseButton.vue +│ │ │ ├── BaseCard.vue +│ │ │ ├── BaseInput.vue +│ │ │ └── BaseModal.vue +│ │ ├── business/ # 業務組件 +│ │ │ ├── VocabularyCard.vue +│ │ │ ├── DialogueMessage.vue +│ │ │ ├── ProgressBar.vue +│ │ │ └── AudioPlayer.vue +│ │ └── layout/ # 佈局組件 +│ │ ├── AppHeader.vue +│ │ ├── AppFooter.vue +│ │ ├── NavigationDrawer.vue +│ │ └── Breadcrumb.vue +│ │ +│ ├── composables/ # 組合式函數 +│ │ ├── useAuth.ts # 認證相關 +│ │ ├── useAudio.ts # 音頻處理 +│ │ ├── useApi.ts # API調用 +│ │ ├── useCache.ts # 快取管理 +│ │ ├── useNotification.ts # 通知系統 +│ │ └── useLocalStorage.ts # 本地存儲 +│ │ +│ ├── layouts/ # 佈局模板 +│ │ ├── MainLayout.vue # 主要佈局 +│ │ ├── AuthLayout.vue # 認證佈局 +│ │ ├── EmptyLayout.vue # 空白佈局 +│ │ └── AdminLayout.vue # 管理佈局 +│ │ +│ ├── modules/ # 功能模組 +│ │ ├── auth/ # 認證模組 +│ │ │ ├── components/ +│ │ │ │ ├── LoginForm.vue +│ │ │ │ ├── RegisterForm.vue +│ │ │ │ └── PasswordResetForm.vue +│ │ │ ├── composables/ +│ │ │ │ └── useAuthValidation.ts +│ │ │ ├── services/ +│ │ │ │ └── authService.ts +│ │ │ ├── stores/ +│ │ │ │ └── authStore.ts +│ │ │ ├── types/ +│ │ │ │ └── auth.types.ts +│ │ │ ├── views/ +│ │ │ │ ├── LoginPage.vue +│ │ │ │ ├── RegisterPage.vue +│ │ │ │ └── ProfilePage.vue +│ │ │ └── router.ts +│ │ │ +│ │ ├── vocabulary/ # 詞彙學習模組 +│ │ │ ├── components/ +│ │ │ │ ├── WordCard.vue +│ │ │ │ ├── PracticeCard.vue +│ │ │ │ ├── ResultsPanel.vue +│ │ │ │ └── ProgressTracker.vue +│ │ │ ├── composables/ +│ │ │ │ ├── useVocabulary.ts +│ │ │ │ └── usePractice.ts +│ │ │ ├── services/ +│ │ │ │ └── vocabularyService.ts +│ │ │ ├── stores/ +│ │ │ │ └── vocabularyStore.ts +│ │ │ ├── types/ +│ │ │ │ └── vocabulary.types.ts +│ │ │ ├── views/ +│ │ │ │ ├── IntroductionPage.vue +│ │ │ │ ├── PracticePage.vue +│ │ │ │ ├── ResultsPage.vue +│ │ │ │ └── ReviewPage.vue +│ │ │ └── router.ts +│ │ │ +│ │ ├── dialogue/ # 情境對話模組 +│ │ │ ├── components/ +│ │ │ │ ├── ChatInterface.vue +│ │ │ │ ├── MessageBubble.vue +│ │ │ │ ├── VoiceRecorder.vue +│ │ │ │ └── ScenarioSelector.vue +│ │ │ ├── composables/ +│ │ │ │ ├── useDialogue.ts +│ │ │ │ └── useSpeechRecognition.ts +│ │ │ ├── services/ +│ │ │ │ └── dialogueService.ts +│ │ │ ├── stores/ +│ │ │ │ └── dialogueStore.ts +│ │ │ ├── types/ +│ │ │ │ └── dialogue.types.ts +│ │ │ ├── views/ +│ │ │ │ ├── DialogueMainPage.vue +│ │ │ │ ├── ScenarioPage.vue +│ │ │ │ └── TimedChallengePage.vue +│ │ │ └── router.ts +│ │ │ +│ │ ├── learning-map/ # 學習地圖模組 +│ │ │ └── ... (類似結構) +│ │ │ +│ │ └── shop/ # 商店模組 +│ │ └── ... (類似結構) +│ │ +│ ├── router/ # 路由配置 +│ │ ├── index.ts # 主路由 +│ │ ├── guards.ts # 路由守衛 +│ │ └── types.ts # 路由類型 +│ │ +│ ├── stores/ # Pinia狀態管理 +│ │ ├── index.ts # Store註冊 +│ │ ├── auth.ts # 認證Store +│ │ ├── user.ts # 用戶Store +│ │ ├── ui.ts # UI狀態Store +│ │ ├── learning.ts # 學習進度Store +│ │ └── notification.ts # 通知Store +│ │ +│ ├── services/ # 服務層 +│ │ ├── api/ # API服務 +│ │ │ ├── index.ts # API客戶端 +│ │ │ ├── auth.api.ts +│ │ │ ├── vocabulary.api.ts +│ │ │ ├── dialogue.api.ts +│ │ │ └── payment.api.ts +│ │ ├── storage/ # 存儲服務 +│ │ │ ├── localStorage.ts +│ │ │ └── sessionStorage.ts +│ │ ├── notification/ # 通知服務 +│ │ │ └── pushNotification.ts +│ │ └── analytics/ # 分析服務 +│ │ └── tracking.ts +│ │ +│ ├── types/ # 全域類型定義 +│ │ ├── index.ts # 導出所有類型 +│ │ ├── api.types.ts # API相關類型 +│ │ ├── user.types.ts # 用戶相關類型 +│ │ ├── learning.types.ts # 學習相關類型 +│ │ └── common.types.ts # 通用類型 +│ │ +│ ├── utils/ # 工具函數 +│ │ ├── index.ts # 導出所有工具 +│ │ ├── format.ts # 格式化工具 +│ │ ├── validation.ts # 驗證工具 +│ │ ├── storage.ts # 存儲工具 +│ │ ├── audio.ts # 音頻工具 +│ │ ├── date.ts # 日期工具 +│ │ └── constants.ts # 常數定義 +│ │ +│ └── plugins/ # Vue插件 +│ ├── index.ts # 插件註冊 +│ ├── quasar.ts # Quasar配置 +│ ├── pwa.ts # PWA配置 +│ └── i18n.ts # 國際化配置 +│ +├── tests/ # 測試檔案 +│ ├── unit/ # 單元測試 +│ │ ├── components/ +│ │ ├── composables/ +│ │ ├── stores/ +│ │ └── utils/ +│ ├── integration/ # 整合測試 +│ │ └── api/ +│ ├── e2e/ # E2E測試 +│ │ ├── specs/ +│ │ ├── fixtures/ +│ │ └── support/ +│ └── __mocks__/ # Mock檔案 +│ +├── docs/ # 專案文檔 +│ ├── api.md # API文檔 +│ ├── components.md # 組件文檔 +│ ├── deployment.md # 部署指南 +│ └── development.md # 開發指南 +│ +└── scripts/ # 建構腳本 + ├── build.sh # 建構腳本 + ├── deploy.sh # 部署腳本 + └── test.sh # 測試腳本 +``` + +## 📋 核心配置檔案 + +### package.json +```json +{ + "name": "dramaling-web", + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite --host", + "build": "vue-tsc --noEmit && vite build", + "preview": "vite preview", + "test": "vitest", + "test:ui": "vitest --ui", + "test:coverage": "vitest --coverage", + "test:e2e": "cypress run", + "test:e2e:dev": "cypress open", + "lint": "eslint . --ext .vue,.ts,.tsx --fix", + "lint:style": "stylelint **/*.{css,scss,vue} --fix", + "type-check": "vue-tsc --noEmit", + "prepare": "husky install" + }, + "dependencies": { + "vue": "^3.4.21", + "vue-router": "^4.3.0", + "pinia": "^2.1.7", + "pinia-plugin-persistedstate": "^3.2.1", + "quasar": "^2.16.0", + "@quasar/extras": "^1.16.4", + "axios": "^1.6.8", + "vee-validate": "^4.12.6", + "yup": "^1.4.0", + "lodash-es": "^4.17.21", + "dayjs": "^1.11.10", + "dompurify": "^3.0.11", + "@vueuse/core": "^10.9.0", + "workbox-window": "^7.0.0" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.0.4", + "vite": "^5.2.0", + "vue-tsc": "^2.0.6", + "typescript": "^5.4.0", + "@types/node": "^20.12.7", + "@types/lodash-es": "^4.17.12", + "@types/dompurify": "^3.0.5", + "vitest": "^1.5.0", + "@vue/test-utils": "^2.4.5", + "happy-dom": "^14.7.1", + "@vitest/coverage-v8": "^1.5.0", + "@vitest/ui": "^1.5.0", + "cypress": "^13.7.2", + "eslint": "^9.1.1", + "@vue/eslint-config-typescript": "^13.0.0", + "@vue/eslint-config-prettier": "^9.0.0", + "prettier": "^3.2.5", + "stylelint": "^16.4.0", + "stylelint-config-standard-scss": "^13.1.0", + "stylelint-config-standard-vue": "^1.0.0", + "husky": "^9.0.11", + "lint-staged": "^15.2.2", + "unplugin-vue-components": "^0.27.0", + "unplugin-auto-import": "^0.17.5", + "@vite/plugin-pwa": "^0.20.0" + } +} +``` + +### vite.config.ts +```typescript +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import { VitePWA } from 'vite-plugin-pwa' +import Components from 'unplugin-vue-components/vite' +import AutoImport from 'unplugin-auto-import/vite' +import { quasar, transformAssetUrls } from '@quasar/vite-plugin' +import path from 'path' + +export default defineConfig({ + plugins: [ + vue({ + template: { transformAssetUrls } + }), + + quasar({ + sassVariables: 'src/assets/styles/quasar-variables.sass' + }), + + Components({ + resolvers: [ + (componentName) => { + if (componentName.startsWith('Q')) + return { name: componentName, from: 'quasar' } + } + ], + dts: true, + dirs: ['src/components'], + extensions: ['vue'], + deep: true + }), + + AutoImport({ + imports: [ + 'vue', + 'vue-router', + 'pinia', + { + 'quasar': ['useQuasar', '$q', 'Notify', 'Loading', 'Dialog'], + '@vueuse/core': ['useLocalStorage', 'useSessionStorage', 'useFetch'] + } + ], + dts: true, + dirs: ['src/composables', 'src/stores'], + vueTemplate: true + }), + + VitePWA({ + registerType: 'autoUpdate', + workbox: { + globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2}'], + runtimeCaching: [ + { + urlPattern: /^https:\/\/api\.dramaling\.com\/.*/i, + handler: 'NetworkFirst', + options: { + cacheName: 'api-cache', + expiration: { + maxEntries: 50, + maxAgeSeconds: 5 * 60 // 5分鐘 + } + } + } + ] + }, + manifest: { + name: 'Drama Ling - AI語言學習', + short_name: 'Drama Ling', + description: 'AI驅動的情境式語言學習應用', + theme_color: '#1976d2', + background_color: '#ffffff', + display: 'standalone', + orientation: 'portrait-primary', + scope: '/', + start_url: '/', + icons: [ + { + src: '/icons/icon-192x192.png', + sizes: '192x192', + type: 'image/png' + }, + { + src: '/icons/icon-512x512.png', + sizes: '512x512', + type: 'image/png' + } + ] + } + }) + ], + + resolve: { + alias: { + '@': path.resolve(__dirname, 'src'), + '~': path.resolve(__dirname, 'src'), + '@components': path.resolve(__dirname, 'src/components'), + '@modules': path.resolve(__dirname, 'src/modules'), + '@stores': path.resolve(__dirname, 'src/stores'), + '@services': path.resolve(__dirname, 'src/services'), + '@utils': path.resolve(__dirname, 'src/utils'), + '@assets': path.resolve(__dirname, 'src/assets') + } + }, + + css: { + preprocessorOptions: { + scss: { + additionalData: `@import "@/assets/styles/variables.scss";` + } + } + }, + + build: { + target: 'es2020', + rollupOptions: { + output: { + manualChunks: { + // 框架核心 + 'vue-vendor': ['vue', 'vue-router', 'pinia'], + // UI框架 + 'quasar-vendor': ['quasar'], + // 工具庫 + 'utils-vendor': ['axios', 'lodash-es', 'dayjs', '@vueuse/core'], + // 驗證相關 + 'validation-vendor': ['vee-validate', 'yup'], + // 各模組 + 'auth-module': ['src/modules/auth'], + 'vocabulary-module': ['src/modules/vocabulary'], + 'dialogue-module': ['src/modules/dialogue'] + } + } + } + }, + + server: { + host: '0.0.0.0', + port: 3000, + proxy: { + '/api': { + target: 'http://localhost:5000', + changeOrigin: true + } + } + } +}) +``` + +### tsconfig.json +```json +{ + "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, + + /* 路徑對應 */ + "baseUrl": ".", + "paths": { + "@/*": ["src/*"], + "~/*": ["src/*"], + "@components/*": ["src/components/*"], + "@modules/*": ["src/modules/*"], + "@stores/*": ["src/stores/*"], + "@services/*": ["src/services/*"], + "@utils/*": ["src/utils/*"], + "@assets/*": ["src/assets/*"] + }, + + /* Vue 相關 */ + "types": ["node", "vue/ref-macros"], + "allowJs": true + }, + "include": [ + "src/**/*.ts", + "src/**/*.tsx", + "src/**/*.vue", + "tests/**/*.ts" + ], + "exclude": [ + "node_modules", + "dist" + ] +} +``` + +### .eslintrc.js +```javascript +module.exports = { + root: true, + env: { + node: true, + browser: true, + es2021: true + }, + extends: [ + 'plugin:vue/vue3-essential', + 'eslint:recommended', + '@vue/typescript/recommended', + '@vue/prettier', + '@vue/prettier/@typescript-eslint' + ], + parser: 'vue-eslint-parser', + parserOptions: { + parser: '@typescript-eslint/parser', + ecmaVersion: 2021, + sourceType: 'module' + }, + plugins: ['@typescript-eslint'], + rules: { + // Vue規則 + 'vue/multi-word-component-names': 'off', + 'vue/no-unused-vars': 'error', + 'vue/component-definition-name-casing': ['error', 'PascalCase'], + 'vue/component-name-in-template-casing': ['error', 'PascalCase'], + + // TypeScript規則 + '@typescript-eslint/no-unused-vars': ['error', { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_' + }], + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + + // 一般規則 + 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', + 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', + 'prefer-const': 'error', + 'no-var': 'error', + 'object-shorthand': 'error', + 'prefer-template': 'error' + }, + globals: { + defineProps: 'readonly', + defineEmits: 'readonly', + defineExpose: 'readonly', + withDefaults: 'readonly' + }, + overrides: [ + { + files: ['**/*.test.{js,ts}', '**/tests/**/*'], + env: { + jest: true, + vitest: true + } + } + ] +} +``` + +### .env.development +```env +# API配置 +VITE_API_BASE_URL=http://localhost:5000/api +VITE_WS_BASE_URL=ws://localhost:5000/ws + +# 第三方服務 +VITE_OPENAI_API_KEY=your_openai_key_here +VITE_STRIPE_PUBLIC_KEY=pk_test_your_stripe_key + +# 分析服務 +VITE_GA_MEASUREMENT_ID=G-XXXXXXXXXX +VITE_MIXPANEL_TOKEN=your_mixpanel_token + +# 功能開關 +VITE_ENABLE_PWA=true +VITE_ENABLE_DEV_TOOLS=true +VITE_ENABLE_MOCK_API=false + +# 除錯設定 +VITE_DEBUG_MODE=true +VITE_LOG_LEVEL=debug +``` + +### .env.production +```env +# API配置 +VITE_API_BASE_URL=https://api.dramaling.com/api +VITE_WS_BASE_URL=wss://api.dramaling.com/ws + +# 第三方服務 +VITE_STRIPE_PUBLIC_KEY=pk_live_your_stripe_key + +# 分析服務 +VITE_GA_MEASUREMENT_ID=G-XXXXXXXXXX +VITE_MIXPANEL_TOKEN=your_mixpanel_token + +# 功能開關 +VITE_ENABLE_PWA=true +VITE_ENABLE_DEV_TOOLS=false +VITE_ENABLE_MOCK_API=false + +# 除錯設定 +VITE_DEBUG_MODE=false +VITE_LOG_LEVEL=error +``` + +### vitest.config.ts +```typescript +import { defineConfig } from 'vitest/config' +import vue from '@vitejs/plugin-vue' +import path from 'path' + +export default defineConfig({ + plugins: [vue()], + test: { + globals: true, + environment: 'happy-dom', + setupFiles: ['tests/setup.ts'], + coverage: { + provider: 'v8', + reporter: ['text', 'json-summary', 'html'], + exclude: [ + 'node_modules/', + 'tests/', + '**/*.d.ts', + '**/*.config.*', + 'src/main.ts' + ], + threshold: { + global: { + branches: 80, + functions: 80, + lines: 80, + statements: 80 + } + } + } + }, + resolve: { + alias: { + '@': path.resolve(__dirname, 'src'), + '~': path.resolve(__dirname, 'src') + } + } +}) +``` + +### docker-compose.yml +```yaml +version: '3.8' + +services: + # 開發環境前端服務 + web: + build: + context: . + dockerfile: Dockerfile.dev + ports: + - "3000:3000" + volumes: + - .:/app + - /app/node_modules + environment: + - NODE_ENV=development + - VITE_API_BASE_URL=http://api:5000/api + depends_on: + - api + networks: + - dramaling_network + + # Mock API服務 (開發時使用) + api: + image: mockserver/mockserver:latest + ports: + - "5000:1080" + environment: + MOCKSERVER_PROPERTY_FILE: /config/mockserver.properties + volumes: + - ./mock-api:/config + networks: + - dramaling_network + + # Redis (用於開發環境快取) + redis: + image: redis:7-alpine + ports: + - "6379:6379" + networks: + - dramaling_network + +networks: + dramaling_network: + driver: bridge +``` + +### Dockerfile +```dockerfile +# 多階段建構 +# 建構階段 +FROM node:18-alpine AS builder + +WORKDIR /app + +# 複製依賴檔案 +COPY package*.json ./ + +# 安裝依賴 +RUN npm ci --only=production + +# 複製源代碼 +COPY . . + +# 建構應用 +RUN npm run build + +# 生產階段 +FROM nginx:alpine AS production + +# 複製建構結果 +COPY --from=builder /app/dist /usr/share/nginx/html + +# 複製Nginx配置 +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# 健康檢查 +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1 + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] +``` + +### nginx.conf +```nginx +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + # 安全頭 + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header Referrer-Policy "strict-origin-when-cross-origin"; + + # 靜態資源快取 + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # API代理 + location /api/ { + proxy_pass http://api-server:5000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # SPA路由支援 + location / { + try_files $uri $uri/ /index.html; + } + + # Gzip壓縮 + gzip on; + gzip_vary on; + gzip_types + text/plain + text/css + text/xml + text/javascript + application/javascript + application/xml+rss + application/json; +} +``` + +## 📋 專案初始化腳本 + +### setup.sh +```bash +#!/bin/bash + +echo "🚀 初始化 Drama Ling Vue.js 專案..." + +# 創建專案目錄 +mkdir -p dramaling-web +cd dramaling-web + +# 初始化 package.json +npm init -y + +# 安裝依賴 +echo "📦 安裝依賴..." +npm install vue@^3.4.21 vue-router@^4.3.0 pinia@^2.1.7 quasar@^2.16.0 + +# 安裝開發依賴 +npm install -D @vitejs/plugin-vue vite typescript vue-tsc @types/node + +# 創建基本檔案結構 +echo "📁 創建檔案結構..." +mkdir -p src/{components,modules,stores,services,utils,assets,router} +mkdir -p src/assets/{styles,images,audio} +mkdir -p src/components/{base,business,layout} +mkdir -p public/icons +mkdir -p tests/{unit,integration,e2e} + +# 創建基本檔案 +touch src/main.ts src/App.vue +touch src/assets/styles/main.scss +touch vite.config.ts tsconfig.json + +echo "✅ 專案初始化完成!" +echo "下一步:" +echo "1. 配置 vite.config.ts" +echo "2. 設定 TypeScript" +echo "3. 安裝 UI 框架" +echo "4. 開始開發 🎉" +``` + +## 📊 專案規模估算 + +### 文件數量預估 +``` +總計約 300-400 個檔案: +├── 組件檔案: ~80個 +├── 頁面檔案: ~40個 +├── 服務檔案: ~20個 +├── Store檔案: ~15個 +├── 工具檔案: ~25個 +├── 測試檔案: ~100個 +├── 配置檔案: ~15個 +└── 其他檔案: ~20個 +``` + +### 開發時間估算 +``` +階段性開發預估: +├── 專案初始化和環境配置: 1週 +├── 基礎組件和佈局: 2週 +├── 認證模組: 1週 +├── 詞彙學習模組: 3週 +├── 情境對話模組: 3週 +├── 學習地圖模組: 2週 +├── 商店模組: 2週 +├── 整合測試和優化: 2週 +└── 部署和上線: 1週 + +總計: ~17週 (約4個月) +``` + +--- + +**文檔狀態**: 🟢 完整項目結構規劃 +**最後更新**: 2025-09-09 +**下次更新**: 根據開發進度調整 \ No newline at end of file diff --git a/docs/04_technical/03_frontend/vue-tools-configuration.md b/docs/04_technical/03_frontend/vue-tools-configuration.md new file mode 100644 index 0000000..fe1a675 --- /dev/null +++ b/docs/04_technical/03_frontend/vue-tools-configuration.md @@ -0,0 +1,941 @@ +# Vue.js 生態系工具配置指南 + +## 🛠️ 開發工具配置 + +### VS Code 配置 + +#### 推薦擴展插件 +```json +// .vscode/extensions.json +{ + "recommendations": [ + // Vue.js 開發核心 + "Vue.volar", // Vue Language Features + "Vue.vscode-typescript-vue-plugin", // TypeScript Vue Plugin + + // 程式碼品質 + "esbenp.prettier-vscode", // Prettier代碼格式化 + "dbaeumer.vscode-eslint", // ESLint檢查 + "stylelint.vscode-stylelint", // CSS/SCSS檢查 + + // TypeScript支援 + "ms-vscode.vscode-typescript-next", // TypeScript語言服務 + + // 開發輔助 + "formulahendry.auto-rename-tag", // 自動重命名標籤 + "bradlc.vscode-tailwindcss", // Tailwind CSS支援 + "christian-kohler.path-intellisense", // 路徑智能提示 + "ms-vscode.vscode-json", // JSON支援 + + // Git工具 + "eamodio.gitlens", // Git增強 + "mhutchie.git-graph", // Git圖形化 + + // 測試工具 + "ZixuanChen.vitest-explorer", // Vitest測試瀏覽器 + + // 其他實用工具 + "PKief.material-icon-theme", // 圖標主題 + "GitHub.copilot", // AI編程助手 + "ms-vscode.live-server" // Live Server + ] +} +``` + +#### VS Code設定 +```json +// .vscode/settings.json +{ + // 編輯器設定 + "editor.tabSize": 2, + "editor.insertSpaces": true, + "editor.detectIndentation": false, + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit", + "source.fixAll.stylelint": "explicit" + }, + + // Vue.js相關設定 + "vue.inlayHints.missingProps": true, + "vue.inlayHints.inlineHandlerLeading": true, + "vue.inlayHints.optionsWrapper": true, + + // TypeScript設定 + "typescript.preferences.includePackageJsonAutoImports": "on", + "typescript.suggest.autoImports": true, + "typescript.updateImportsOnFileMove.enabled": "always", + + // Prettier設定 + "prettier.configPath": ".prettierrc", + "prettier.requireConfig": true, + + // ESLint設定 + "eslint.validate": ["vue", "typescript", "javascript"], + "eslint.format.enable": true, + + // 檔案關聯 + "files.associations": { + "*.vue": "vue" + }, + + // Emmet設定 + "emmet.includeLanguages": { + "vue-html": "html", + "vue": "html" + }, + + // 自動儲存 + "files.autoSave": "onFocusChange", + + // 排除檔案 + "search.exclude": { + "**/node_modules": true, + "**/dist": true, + "**/.nuxt": true, + "**/coverage": true + }, + + // 終端機設定 + "terminal.integrated.defaultProfile.osx": "zsh", + "terminal.integrated.fontSize": 14 +} +``` + +### Prettier 配置 +```json +// .prettierrc +{ + "semi": false, + "singleQuote": true, + "printWidth": 100, + "tabWidth": 2, + "useTabs": false, + "trailingComma": "none", + "bracketSpacing": true, + "bracketSameLine": false, + "arrowParens": "avoid", + "endOfLine": "lf", + "vueIndentScriptAndStyle": false, + "htmlWhitespaceSensitivity": "ignore", + "overrides": [ + { + "files": "*.vue", + "options": { + "parser": "vue" + } + }, + { + "files": "*.json", + "options": { + "parser": "json" + } + } + ] +} +``` + +### StyleLint 配置 +```json +// .stylelintrc.json +{ + "extends": [ + "stylelint-config-standard-scss", + "stylelint-config-standard-vue" + ], + "rules": { + "string-quotes": "single", + "selector-class-pattern": null, + "custom-property-pattern": null, + "scss/dollar-variable-pattern": null, + "scss/at-mixin-pattern": null, + "scss/at-function-pattern": null, + "value-keyword-case": null, + "function-name-case": null, + "at-rule-no-unknown": [ + true, + { + "ignoreAtRules": [ + "tailwind", + "apply", + "variants", + "responsive", + "screen" + ] + } + ] + }, + "ignoreFiles": [ + "node_modules/**/*", + "dist/**/*", + "coverage/**/*" + ] +} +``` + +### Husky Git Hooks 配置 + +#### 安裝和配置 +```bash +# 安裝 Husky +npm install --save-dev husky lint-staged + +# 初始化 Husky +npx husky install + +# 創建 pre-commit hook +npx husky add .husky/pre-commit "npx lint-staged" + +# 創建 commit-msg hook (選用) +npx husky add .husky/commit-msg 'npx --no -- commitlint --edit ${1}' +``` + +#### lint-staged 配置 +```json +// package.json 中的 lint-staged 配置 +{ + "lint-staged": { + "*.{js,ts,vue}": [ + "eslint --fix", + "prettier --write" + ], + "*.{css,scss,vue}": [ + "stylelint --fix", + "prettier --write" + ], + "*.{md,json}": [ + "prettier --write" + ] + } +} +``` + +#### Commitlint 配置 (選用) +```json +// .commitlintrc.json +{ + "extends": ["@commitlint/config-conventional"], + "rules": { + "type-enum": [ + 2, + "always", + [ + "feat", // 新功能 + "fix", // bug修復 + "docs", // 文檔 + "style", // 格式化 + "refactor", // 重構 + "perf", // 性能優化 + "test", // 測試 + "build", // 建構 + "ci", // CI/CD + "chore", // 其他 + "revert" // 回退 + ] + ], + "subject-case": [0] + } +} +``` + +## 🧪 測試工具配置 + +### Vitest 配置 +```typescript +// vitest.config.ts +import { defineConfig } from 'vitest/config' +import vue from '@vitejs/plugin-vue' +import path from 'path' + +export default defineConfig({ + plugins: [vue()], + test: { + // 測試環境 + globals: true, + environment: 'happy-dom', + + // 設置檔案 + setupFiles: ['tests/setup.ts'], + + // 包含和排除 + include: ['**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + exclude: ['node_modules', 'dist', '.idea', '.git', '.cache'], + + // 覆蓋率配置 + coverage: { + provider: 'v8', + reporter: ['text', 'json-summary', 'html', 'lcov'], + reportsDirectory: './coverage', + exclude: [ + 'node_modules/', + 'tests/', + '**/*.d.ts', + '**/*.config.*', + 'src/main.ts', + 'src/router/index.ts' + ], + threshold: { + global: { + branches: 75, + functions: 75, + lines: 75, + statements: 75 + } + } + }, + + // 監控模式 + watchExclude: ['**/node_modules/**', '**/dist/**'], + + // 測試超時 + testTimeout: 10000, + hookTimeout: 10000, + + // 並發設置 + threads: true, + maxThreads: 4, + minThreads: 1 + }, + + resolve: { + alias: { + '@': path.resolve(__dirname, 'src'), + '~': path.resolve(__dirname, 'src') + } + } +}) +``` + +### 測試設置檔案 +```typescript +// tests/setup.ts +import { config } from '@vue/test-utils' +import { createPinia } from 'pinia' +import { Quasar } from 'quasar' + +// Vue Test Utils 全域配置 +config.global.plugins = [ + createPinia(), + [Quasar, {}] +] + +// 模擬 ResizeObserver (Quasar需要) +global.ResizeObserver = class ResizeObserver { + constructor(cb: any) {} + observe() {} + unobserve() {} + disconnect() {} +} + +// 模擬 IntersectionObserver +global.IntersectionObserver = class IntersectionObserver { + constructor(cb: any, options?: any) {} + observe() {} + unobserve() {} + disconnect() {} +} + +// 模擬 matchMedia +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: vi.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), + removeListener: vi.fn(), + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn() + })) +}) +``` + +### Cypress E2E 測試配置 +```typescript +// cypress.config.ts +import { defineConfig } from 'cypress' + +export default defineConfig({ + e2e: { + baseUrl: 'http://localhost:3000', + viewportWidth: 1280, + viewportHeight: 720, + video: false, + screenshotOnRunFailure: true, + + setupNodeEvents(on, config) { + // 任務配置 + on('task', { + log(message) { + console.log(message) + return null + } + }) + }, + + // 測試檔案配置 + specPattern: 'tests/e2e/**/*.cy.{js,jsx,ts,tsx}', + supportFile: 'tests/e2e/support/e2e.ts', + fixturesFolder: 'tests/e2e/fixtures', + screenshotsFolder: 'tests/e2e/screenshots', + videosFolder: 'tests/e2e/videos', + + // 環境變數 + env: { + apiUrl: 'http://localhost:5000/api', + testUser: { + email: 'test@example.com', + password: 'testpassword123' + } + } + }, + + component: { + devServer: { + framework: 'vue', + bundler: 'vite' + } + } +}) +``` + +## 📦 建構和部署工具 + +### GitHub Actions CI/CD +```yaml +# .github/workflows/ci-cd.yml +name: CI/CD Pipeline + +on: + push: + branches: [main, develop] + pull_request: + branches: [main] + +env: + NODE_VERSION: '18' + +jobs: + # 代碼檢查和測試 + quality-check: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Type check + run: npm run type-check + + - name: Lint check + run: npm run lint + + - name: Style lint check + run: npm run lint:style + + - name: Run unit tests + run: npm run test:coverage + + - name: Upload coverage reports + uses: codecov/codecov-action@v3 + with: + file: ./coverage/lcov.info + + # E2E測試 + e2e-test: + runs-on: ubuntu-latest + needs: quality-check + if: github.event_name == 'pull_request' + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build application + run: npm run build + + - name: Run E2E tests + uses: cypress-io/github-action@v6 + with: + start: npm run preview + wait-on: 'http://localhost:4173' + + # 建構和部署 + build-deploy: + runs-on: ubuntu-latest + needs: quality-check + if: github.ref == 'refs/heads/main' + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build application + run: npm run build + env: + VITE_API_BASE_URL: ${{ secrets.PRODUCTION_API_URL }} + VITE_STRIPE_PUBLIC_KEY: ${{ secrets.STRIPE_PUBLIC_KEY }} + + - name: Build Docker image + run: docker build -t dramaling-web:${{ github.sha }} . + + - name: Deploy to production + run: | + echo "Deploying to production server..." + # 部署邏輯 +``` + +### Docker 配置 + +#### 開發環境 Dockerfile +```dockerfile +# Dockerfile.dev +FROM node:18-alpine + +WORKDIR /app + +# 安裝依賴 +COPY package*.json ./ +RUN npm ci + +# 複製源代碼 +COPY . . + +# 開放端口 +EXPOSE 3000 + +# 開發模式啟動 +CMD ["npm", "run", "dev"] +``` + +#### 生產環境 Dockerfile +```dockerfile +# Dockerfile +# 建構階段 +FROM node:18-alpine AS builder + +WORKDIR /app + +# 複製依賴文件 +COPY package*.json ./ + +# 安裝依賴(包含 devDependencies) +RUN npm ci + +# 複製源代碼 +COPY . . + +# 建構應用 +RUN npm run build + +# 生產階段 +FROM nginx:alpine AS production + +# 安裝工具 +RUN apk add --no-cache curl + +# 複製建構結果 +COPY --from=builder /app/dist /usr/share/nginx/html + +# 複製 Nginx 配置 +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# 健康檢查 +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD curl -f http://localhost/ || exit 1 + +# 非 root 用戶 +RUN addgroup -g 1001 -S nodejs \ + && adduser -S nextjs -u 1001 + +USER nodejs + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] +``` + +### 環境配置管理 + +#### 開發環境配置 +```bash +# scripts/dev-setup.sh +#!/bin/bash + +echo "🔧 設置開發環境..." + +# 檢查 Node.js 版本 +node_version=$(node -v | sed 's/v//' | cut -d. -f1) +if [ "$node_version" -lt 18 ]; then + echo "❌ Node.js 版本需要 >= 18,當前版本: $(node -v)" + exit 1 +fi + +# 安裝依賴 +echo "📦 安裝依賴..." +npm ci + +# 設置 Git hooks +echo "🪝 設置 Git hooks..." +npm run prepare + +# 創建環境變數檔案 +if [ ! -f .env.local ]; then + echo "📝 創建本地環境變數檔案..." + cp .env.development .env.local +fi + +# 運行初始化檢查 +echo "🧪 運行檢查..." +npm run type-check +npm run lint +npm run test --run + +echo "✅ 開發環境設置完成!" +echo "運行 'npm run dev' 開始開發" +``` + +#### 部署腳本 +```bash +# scripts/deploy.sh +#!/bin/bash + +set -e + +echo "🚀 開始部署流程..." + +# 環境變數檢查 +if [ -z "$PRODUCTION_API_URL" ]; then + echo "❌ 缺少 PRODUCTION_API_URL 環境變數" + exit 1 +fi + +# 建構應用 +echo "🏗️ 建構應用..." +npm run build + +# 運行測試 +echo "🧪 運行測試..." +npm run test --run + +# Docker 建構 +echo "🐳 建構 Docker 映像..." +docker build -t dramaling-web:latest . + +# 部署到服務器 +echo "🌐 部署到生產環境..." +# 這裡會是實際的部署命令 + +echo "✅ 部署完成!" +``` + +## 🔧 開發工具腳本 + +### package.json 腳本 +```json +{ + "scripts": { + // 開發相關 + "dev": "vite --host", + "dev:https": "vite --https --host", + "build": "vue-tsc --noEmit && vite build", + "preview": "vite preview", + + // 測試相關 + "test": "vitest", + "test:ui": "vitest --ui", + "test:run": "vitest run", + "test:coverage": "vitest --coverage", + "test:e2e": "cypress run", + "test:e2e:dev": "cypress open", + + // 代碼檢查 + "lint": "eslint . --ext .vue,.ts,.tsx --fix", + "lint:check": "eslint . --ext .vue,.ts,.tsx", + "lint:style": "stylelint **/*.{css,scss,vue} --fix", + "type-check": "vue-tsc --noEmit", + + // 建構和部署 + "build:analyze": "vite build --mode analyze", + "build:docker": "docker build -t dramaling-web .", + "deploy:staging": "npm run build && ./scripts/deploy-staging.sh", + "deploy:production": "npm run build && ./scripts/deploy-production.sh", + + // 開發工具 + "clean": "rm -rf node_modules dist coverage .nuxt", + "fresh-install": "npm run clean && npm install", + "update-deps": "npx npm-check-updates -u && npm install", + "prepare": "husky install", + + // 代碼生成 + "generate:component": "node scripts/generate-component.js", + "generate:page": "node scripts/generate-page.js", + "generate:store": "node scripts/generate-store.js" + } +} +``` + +### 開發輔助腳本 + +#### 組件生成腳本 +```javascript +// scripts/generate-component.js +const fs = require('fs') +const path = require('path') + +const componentName = process.argv[2] +if (!componentName) { + console.log('請提供組件名稱: npm run generate:component ComponentName') + process.exit(1) +} + +const componentDir = path.join('src/components/business', componentName) +const componentFile = path.join(componentDir, `${componentName}.vue`) +const testFile = path.join('tests/unit/components', `${componentName}.test.ts`) + +// 創建目錄 +if (!fs.existsSync(componentDir)) { + fs.mkdirSync(componentDir, { recursive: true }) +} + +// 組件模板 +const componentTemplate = ` + + + + +` + +// 測試模板 +const testTemplate = `import { mount } from '@vue/test-utils' +import { describe, it, expect } from 'vitest' +import ${componentName} from '@/components/business/${componentName}/${componentName}.vue' + +describe('${componentName}', () => { + it('renders correctly', () => { + const wrapper = mount(${componentName}, { + props: { + title: 'Test Title' + } + }) + + expect(wrapper.find('h2').text()).toBe('Test Title') + }) +}) +` + +// 創建文件 +fs.writeFileSync(componentFile, componentTemplate) +fs.writeFileSync(testFile, testTemplate) + +console.log(`✅ 組件 ${componentName} 創建成功!`) +console.log(`📁 組件文件: ${componentFile}`) +console.log(`🧪 測試文件: ${testFile}`) +``` + +## 📊 性能監控配置 + +### Bundle 分析配置 +```typescript +// vite.config.ts 中的 bundle 分析 +import { defineConfig } from 'vite' +import { visualizer } from 'rollup-plugin-visualizer' + +export default defineConfig({ + plugins: [ + // 其他插件... + + // Bundle 分析器 + process.env.ANALYZE === 'true' && visualizer({ + filename: 'dist/bundle-analysis.html', + open: true, + gzipSize: true, + brotliSize: true + }) + ].filter(Boolean) +}) +``` + +### 性能監控 +```typescript +// src/utils/performance.ts +export class PerformanceMonitor { + private static instance: PerformanceMonitor + + static getInstance() { + if (!this.instance) { + this.instance = new PerformanceMonitor() + } + return this.instance + } + + // 頁面載入性能 + measurePageLoad(routeName: string) { + if (typeof window === 'undefined') return + + const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming + + const metrics = { + route: routeName, + domContentLoaded: navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart, + loadComplete: navigation.loadEventEnd - navigation.loadEventStart, + firstPaint: this.getFirstPaint(), + firstContentfulPaint: this.getFirstContentfulPaint() + } + + this.sendMetrics('page_load', metrics) + } + + // 用戶互動性能 + measureInteraction(actionName: string, startTime: number) { + const duration = performance.now() - startTime + + this.sendMetrics('user_interaction', { + action: actionName, + duration + }) + } + + // 獲取 Web Vitals + private getFirstPaint(): number { + const paintEntries = performance.getEntriesByType('paint') + const fpEntry = paintEntries.find(entry => entry.name === 'first-paint') + return fpEntry ? fpEntry.startTime : 0 + } + + private getFirstContentfulPaint(): number { + const paintEntries = performance.getEntriesByType('paint') + const fcpEntry = paintEntries.find(entry => entry.name === 'first-contentful-paint') + return fcpEntry ? fcpEntry.startTime : 0 + } + + private sendMetrics(type: string, data: any) { + // 發送到分析服務 + console.log(`[Performance] ${type}:`, data) + + // 實際實作可以發送到 Google Analytics、Mixpanel 等 + if (window.gtag) { + window.gtag('event', type, data) + } + } +} +``` + +## 🔗 IDE整合配置 + +### WebStorm 配置 +```xml + + + + + + + + +``` + +### 代碼模板 +```json +// .vscode/vue.code-snippets +{ + "Vue Composition Component": { + "prefix": "vcomp", + "body": [ + "", + "", + "", + "", + "" + ], + "description": "Vue Composition API component template" + }, + + "Pinia Store": { + "prefix": "pstore", + "body": [ + "import { defineStore } from 'pinia'", + "", + "export const use${1:StoreName}Store = defineStore('${2:storeName}', () => {", + " const ${3:state} = ref(${4:initialValue})", + " ", + " const ${5:getter} = computed(() => {", + " return ${3:state}.value", + " })", + " ", + " const ${6:action} = async () => {", + " ${7}", + " }", + " ", + " return {", + " ${3:state}: readonly(${3:state}),", + " ${5:getter},", + " ${6:action}", + " }", + "})" + ], + "description": "Pinia store template" + } +} +``` + +--- + +**文檔狀態**: 🟢 完成工具配置指南 +**最後更新**: 2025-09-09 +**下次更新**: 根據開發需求調整工具配置 \ No newline at end of file diff --git a/docs/04_technical/low-budget-deployment.md b/docs/04_technical/05_deployment/low-budget-deployment.md similarity index 100% rename from docs/04_technical/low-budget-deployment.md rename to docs/04_technical/05_deployment/low-budget-deployment.md diff --git a/docs/04_technical/environment/README.md b/docs/04_technical/06_development/environment/README.md similarity index 100% rename from docs/04_technical/environment/README.md rename to docs/04_technical/06_development/environment/README.md diff --git a/docs/04_technical/environment/xcode_setup_guide.md b/docs/04_technical/06_development/environment/xcode_setup_guide.md similarity index 100% rename from docs/04_technical/environment/xcode_setup_guide.md rename to docs/04_technical/06_development/environment/xcode_setup_guide.md diff --git a/docs/04_technical/file-organization-strategy.md b/docs/04_technical/06_development/file-organization-strategy.md similarity index 100% rename from docs/04_technical/file-organization-strategy.md rename to docs/04_technical/06_development/file-organization-strategy.md diff --git a/docs/04_technical/issues-tracking.md b/docs/04_technical/06_development/issues-tracking.md similarity index 100% rename from docs/04_technical/issues-tracking.md rename to docs/04_technical/06_development/issues-tracking.md diff --git a/docs/04_technical/user-flow-specification.md b/docs/04_technical/06_development/user-flow-specification.md similarity index 100% rename from docs/04_technical/user-flow-specification.md rename to docs/04_technical/06_development/user-flow-specification.md diff --git a/docs/04_technical/plan/api-specifications-completion-plan.md b/docs/04_technical/07_planning/api-specifications-completion-plan.md similarity index 100% rename from docs/04_technical/plan/api-specifications-completion-plan.md rename to docs/04_technical/07_planning/api-specifications-completion-plan.md diff --git a/docs/04_technical/quick-consistency-check.md b/docs/04_technical/07_planning/quick-consistency-check.md similarity index 100% rename from docs/04_technical/quick-consistency-check.md rename to docs/04_technical/07_planning/quick-consistency-check.md diff --git a/docs/04_technical/README.md b/docs/04_technical/README.md new file mode 100644 index 0000000..444047c --- /dev/null +++ b/docs/04_technical/README.md @@ -0,0 +1,177 @@ +# 📋 技術文檔總覽 + +**專案名稱**: Drama Ling 語言學習應用 +**最後更新**: 2025-09-09 +**文檔狀態**: 🔄 建議重組中 + +## 🗂️ 文檔分類說明 + +本目錄包含 Drama Ling 專案的所有技術文檔,按功能和階段進行分類組織。 + +### 📊 當前文檔統計 +- **總文檔數**: 27個 +- **API文檔**: 11個 +- **前端文檔**: 4個 +- **架構文檔**: 3個 +- **開發工具**: 5個 +- **其他文檔**: 4個 + +## 📁 建議的目錄重組結構 + +### 🏗️ 01_architecture/ - 架構設計 +核心系統架構和技術選型決策文檔 + +| 文檔 | 內容 | 狀態 | +|------|------|------| +| `tech-stack-decision.md` | 技術選型決策和比較分析 | ✅ 已完成 | +| `database-schema.md` | 資料庫結構設計 | ✅ 已完成 | +| `system-integration.md` | 系統整合架構 | ✅ 已完成 | + +### 🔌 02_api/ - API 規格文檔 +完整的後端 API 規格和介面文檔 + +| 文檔 | 內容 | 狀態 | +|------|------|------| +| `README.md` | API 文檔導航和概覽 | 📝 需建立 | +| `api-specifications.md` | API 總規格文檔 | ✅ 已完成 | +| `common.md` | 通用 API 規範 | ✅ 已完成 | +| `errors.md` | 錯誤處理規範 | ✅ 已完成 | +| `authentication.md` | 認證相關 API | ✅ 已完成 | +| `user-management.md` | 用戶管理 API | ✅ 已完成 | +| `vocabulary.md` | 詞彙學習 API | ✅ 已完成 | +| `dialogue-practice.md` | 對話練習 API | ✅ 已完成 | +| `learning-content.md` | 學習內容 API | ✅ 已完成 | +| `gamification.md` | 遊戲化系統 API | ✅ 已完成 | +| `subscription.md` | 訂閱系統 API | ✅ 已完成 | +| `daily-missions.md` | 每日任務 API | ✅ 已完成 | +| `language-levels.md` | 語言等級 API | ✅ 已完成 | + +### 💻 03_frontend/ - 前端技術文檔 +Vue.js Web 應用程式開發相關文檔 + +| 文檔 | 內容 | 狀態 | +|------|------|------| +| `README.md` | 前端技術文檔導航 | 📝 需建立 | +| `vue-frontend-architecture.md` | Vue.js 架構設計和技術選型 | ✅ 已完成 | +| `vue-project-structure.md` | 專案結構和配置檔案 | ✅ 已完成 | +| `vue-tools-configuration.md` | 開發工具和環境配置 | ✅ 已完成 | +| `vue-development-standards.md` | 開發規範和最佳實踐 | ✅ 已完成 | + +### 📱 04_mobile/ - 移動端技術文檔 +Flutter 移動應用程式開發相關文檔 + +| 文檔 | 內容 | 狀態 | +|------|------|------| +| `README.md` | 移動端技術文檔導航 | 📝 需建立 | +| `flutter-architecture.md` | Flutter 架構設計 | 🔄 規劃中 | +| `flutter-integration.md` | Flutter 與後端整合 | ✅ 已完成 | + +### 🚀 05_deployment/ - 部署和運維 +應用程式部署、運維和維護相關文檔 + +| 文檔 | 內容 | 狀態 | +|------|------|------| +| `README.md` | 部署文檔導航 | 📝 需建立 | +| `low-budget-deployment.md` | 低預算部署方案 | ✅ 已完成 | +| `production-deployment.md` | 生產環境部署指南 | 🔄 規劃中 | + +### 🛠️ 06_development/ - 開發流程和工具 +開發環境設定、流程規範和工具使用指南 + +| 文檔 | 內容 | 狀態 | +|------|------|------| +| `README.md` | 開發流程文檔導航 | 📝 需建立 | +| `environment/README.md` | 開發環境設定總覽 | ✅ 已完成 | +| `environment/xcode_setup_guide.md` | Xcode 開發環境設定 | ✅ 已完成 | +| `user-flow-specification.md` | 用戶流程規格說明 | ✅ 已完成 | +| `file-organization-strategy.md` | 檔案組織策略 | ✅ 已完成 | +| `issues-tracking.md` | 問題追蹤系統使用 | ✅ 已完成 | + +### 📋 07_planning/ - 規劃文檔 +專案規劃、計劃和檢查相關文檔 + +| 文檔 | 內容 | 狀態 | +|------|------|------| +| `README.md` | 規劃文檔導航 | 📝 需建立 | +| `api-specifications-completion-plan.md` | API 規格完成計劃 | ✅ 已完成 | +| `quick-consistency-check.md` | 快速一致性檢查 | ✅ 已完成 | + +### 📦 archive/ - 歷史歸檔 +舊版本或不再使用的文檔歸檔 + +| 文檔 | 內容 | 狀態 | +|------|------|------| +| `user-flow-specification-old.md` | 舊版用戶流程規格 | 📦 已歸檔 | + +## 🔍 快速導航 + +### 🆕 新開發者入門路徑 +1. 📖 **開始**: `01_architecture/tech-stack-decision.md` - 了解技術選型 +2. 🏗️ **架構**: `01_architecture/database-schema.md` - 理解資料結構 +3. 🔌 **API**: `02_api/README.md` - 學習 API 規格 +4. 💻 **前端**: `03_frontend/vue-frontend-architecture.md` - 前端開發指南 +5. 🛠️ **環境**: `06_development/environment/README.md` - 設定開發環境 + +### 👨‍💻 前端開發者路徑 +1. `03_frontend/vue-frontend-architecture.md` - 架構總覽 +2. `03_frontend/vue-project-structure.md` - 專案結構 +3. `03_frontend/vue-tools-configuration.md` - 工具配置 +4. `03_frontend/vue-development-standards.md` - 開發規範 +5. `02_api/api-specifications.md` - API 整合 + +### 🔧 後端開發者路徑 +1. `01_architecture/database-schema.md` - 資料庫設計 +2. `02_api/api-specifications.md` - API 總規格 +3. `02_api/common.md` - 通用規範 +4. `02_api/authentication.md` - 認證系統 +5. 其他特定 API 文檔 + +### 📱 移動端開發者路徑 +1. `04_mobile/flutter-architecture.md` - Flutter 架構 +2. `04_mobile/flutter-integration.md` - 後端整合 +3. `06_development/environment/xcode_setup_guide.md` - iOS 環境 +4. `02_api/api-specifications.md` - API 整合 + +### 🚀 部署和運維路徑 +1. `05_deployment/low-budget-deployment.md` - 基礎部署 +2. `05_deployment/production-deployment.md` - 生產部署 +3. `01_architecture/system-integration.md` - 系統整合 +4. `07_planning/quick-consistency-check.md` - 檢查清單 + +## 📊 文檔完成度追蹤 + +### ✅ 已完成 (22/27) +- 架構文檔: 3/3 +- API 文檔: 11/12 +- 前端文檔: 4/4 +- 開發工具: 4/4 + +### 🔄 進行中 (2/27) +- 移動端文檔: 1/2 +- 部署文檔: 1/2 + +### 📝 待建立 (3/27) +- 各分類的 README.md 導航文檔 + +## 🔧 維護指南 + +### 新增文檔時 +1. 將文檔放在適當的分類目錄下 +2. 更新對應分類的 README.md +3. 更新本總覽文檔的統計和表格 +4. 確保文檔包含標準的元數據(建立日期、最後更新、狀態) + +### 文檔審查週期 +- **每週**: 檢查文檔狀態更新 +- **每月**: 檢查文檔內容是否需要更新 +- **版本發布前**: 全面檢查文檔的準確性和完整性 + +## 📞 聯繫資訊 + +**文檔維護者**: 技術團隊 +**最後審查**: 2025-09-09 +**下次審查**: 2025-09-16 + +--- + +> 💡 **提示**: 如果你是新加入的開發者,建議從「新開發者入門路徑」開始閱讀相關文檔。 \ No newline at end of file diff --git a/docs/04_technical/user-flow-specification-old.md b/docs/04_technical/archive/user-flow-specification-old.md similarity index 100% rename from docs/04_technical/user-flow-specification-old.md rename to docs/04_technical/archive/user-flow-specification-old.md diff --git a/docs/api/README.md b/docs/api/README.md new file mode 100644 index 0000000..27b76ac --- /dev/null +++ b/docs/api/README.md @@ -0,0 +1,44 @@ +# Drama Ling API 文檔 + +## 📖 概述 + +此目錄包含 Drama Ling API 的完整文檔和工具。 + +## 📁 文件說明 + +### `swagger-ui.html` +- **用途**: 互動式API文檔界面 +- **使用方式**: 在瀏覽器中直接開啟此文件 +- **功能**: + - 瀏覽所有API端點 + - 測試API請求 + - 查看請求/回應格式 + +## 🚀 使用方法 + +### 1. 本地查看API文檔 +```bash +# 在瀏覽器中開啟 +open docs/api/swagger-ui.html +``` + +### 2. 當前API覆蓋範圍 +- ✅ **用戶認證模組**: 註冊、登入、登出、第三方登入 +- ✅ **健康檢查**: 基本和詳細健康狀態 +- 🔄 **其他模組**: 待補充 (詞彙學習、情境對話、遊戲化等) + +## 📋 維護說明 + +### 更新API文檔 +1. 修改 `swagger-ui.html` 中的 OpenAPI JSON 規格 +2. 測試文檔顯示是否正確 +3. 確保所有API端點都有完整的文檔 + +### 建議改進 +- [ ] 將內嵌的OpenAPI JSON分離為獨立的 `openapi.yaml` 文件 +- [ ] 添加更多API模組的文檔 +- [ ] 加入API使用範例和最佳實踐 + +--- +**建立日期**: 2025-09-09 +**維護者**: Drama Ling 開發團隊 \ No newline at end of file diff --git a/swagger-ui.html b/docs/api/swagger-ui.html similarity index 100% rename from swagger-ui.html rename to docs/api/swagger-ui.html diff --git a/projects/learning-loop-system.md b/projects/learning-loop-system.md new file mode 100644 index 0000000..d8a81b0 --- /dev/null +++ b/projects/learning-loop-system.md @@ -0,0 +1,106 @@ +# 🔄 學習閉環系統 + +**創建日期**: 2025-09-09 +**專案類型**: 🎨 前端UI開發 +**狀態**: 🔄 進行中 +**優先級**: 🔥 緊急 + +## 📋 專案概述 + +實現完整的學習閉環系統,包含語法錯誤訂正和表達不順訂正頁面,確保用戶能夠完成完整的學習→練習→訂正→完成循環。 + +## 🎯 核心目標 + +### 主要交付物 +- [ ] **語法錯誤訂正頁面** - 完整的語法糾正界面 +- [ ] **訂正進度追蹤** - 進度條和完成狀態顯示 +- [ ] **練習按鈕功能** - 重新練習和繼續學習按鈕 +- [ ] **學習效果統計** - 訂正前後的學習效果對比 + +### 功能規格 +- **語法高亮顯示**: 標記錯誤語法部分 +- **訂正建議系統**: 提供正確語法建議 +- **互動練習**: 允許用戶重新輸入正確內容 +- **進度可視化**: 清晰的進度指示器 + +## 🔧 技術實現 + +### 前端技術 +- **HTML5**: 語義化結構 +- **CSS3**: 響應式設計,語法高亮樣式 +- **JavaScript**: 互動邏輯,進度追蹤 +- **API整合**: 與後端語法檢查服務整合 + +### 關鍵組件 +1. **語法檢查引擎**: 識別常見語法錯誤 +2. **視覺化標記系統**: 清晰標示錯誤位置 +3. **建議提示系統**: 提供改正建議 +4. **學習進度管理**: 追蹤訂正進度 + +## 📊 開發里程碑 + +### 階段1: UI設計 (預估2小時) +- [ ] 訂正頁面佈局設計 +- [ ] 語法高亮樣式定義 +- [ ] 進度條視覺設計 + +### 階段2: 功能實現 (預估3小時) +- [ ] 語法錯誤檢測邏輯 +- [ ] 訂正建議生成 +- [ ] 用戶互動處理 + +### 階段3: 整合測試 (預估1小時) +- [ ] 與現有系統整合 +- [ ] 用戶流程測試 +- [ ] 錯誤處理驗證 + +## 🎨 UI/UX 規格 + +### 頁面佈局 +``` +┌─────────────────────────────────────┐ +│ 語法錯誤訂正 │ +├─────────────────────────────────────┤ +│ 進度條: ████████░░ 80% │ +├─────────────────────────────────────┤ +│ 原文: [Your original text here] │ +│ 錯誤: ~~grammar mistake~~ │ +│ 建議: [corrected version] │ +├─────────────────────────────────────┤ +│ [重新練習] [繼續學習] │ +└─────────────────────────────────────┘ +``` + +### 互動元素 +- **錯誤標記**: 紅色底線標示 +- **建議提示**: 綠色高亮顯示 +- **進度條**: 藍色漸變效果 +- **按鈕樣式**: 圓角設計,符合整體風格 + +## 🔍 品質標準 + +### 功能測試 +- [ ] 語法錯誤正確識別率 > 90% +- [ ] 建議準確性 > 85% +- [ ] 頁面載入時間 < 2秒 +- [ ] 支援各種設備尺寸 + +### 用戶體驗 +- [ ] 直觀的操作流程 +- [ ] 清晰的錯誤提示 +- [ ] 流暢的動畫效果 +- [ ] 無障礙設計支援 + +## 📈 成功指標 + +- **完成度**: 100% 功能實現 +- **用戶滿意度**: 順暢完成學習閉環 +- **技術指標**: 快速響應,準確訂正 +- **整合度**: 與現有系統無縫銜接 + +--- + +**負責人**: 前端開發團隊 +**預估工作量**: 6小時 +**依賴項目**: 語音訂正系統 +**最後更新**: 2025-09-09 \ No newline at end of file diff --git a/docs/02_design/todo/ui-design-tasks.md b/projects/ui-design-tasks.md similarity index 100% rename from docs/02_design/todo/ui-design-tasks.md rename to projects/ui-design-tasks.md diff --git a/projects/voice-correction-system.md b/projects/voice-correction-system.md new file mode 100644 index 0000000..1967dda --- /dev/null +++ b/projects/voice-correction-system.md @@ -0,0 +1,129 @@ +# 🎤 語音訂正系統 + +**創建日期**: 2025-09-09 +**專案類型**: 🎨 前端UI + 🔊 語音處理 +**狀態**: 🔄 進行中 +**優先級**: 🔥 緊急 + +## 📋 專案概述 + +建立表達不順訂正頁面,提供語音發音訂正界面,與語法訂正系統配合完成完整的訂正流程,確保用戶的語音表達準確性。 + +## 🎯 核心目標 + +### 主要交付物 +- [ ] **表達不順訂正頁面** - 語音發音問題訂正界面 +- [ ] **語音播放系統** - 原音頻與正確發音對比播放 +- [ ] **發音練習功能** - 重新錄音和發音練習 +- [ ] **語音評分系統** - 發音準確度評分顯示 + +### 功能規格 +- **語音波形視覺化**: 顯示音頻波形圖 +- **發音對比系統**: 原發音與標準發音對比 +- **實時語音識別**: 即時分析用戶發音 +- **智能糾正建議**: AI驅動的發音改進建議 + +## 🔧 技術實現 + +### 前端技術 +- **Web Audio API**: 語音錄製和播放 +- **Canvas**: 語音波形繪製 +- **WebRTC**: 實時音頻處理 +- **語音識別API**: 語音轉文字分析 + +### 關鍵組件 +1. **語音錄製器**: 高品質音頻錄製 +2. **波形視覺化器**: 音頻波形顯示 +3. **發音分析引擎**: 發音準確度分析 +4. **糾正建議系統**: 個性化改進建議 + +## 📊 開發里程碑 + +### 階段1: 語音界面設計 (預估2小時) +- [ ] 語音錄製界面佈局 +- [ ] 波形視覺化設計 +- [ ] 播放控制元件設計 + +### 階段2: 語音功能實現 (預估3小時) +- [ ] 語音錄製功能 +- [ ] 音頻播放系統 +- [ ] 波形繪製邏輯 + +### 階段3: AI分析整合 (預估2小時) +- [ ] 語音識別整合 +- [ ] 發音評分算法 +- [ ] 糾正建議生成 + +## 🎨 UI/UX 規格 + +### 頁面佈局 +``` +┌─────────────────────────────────────┐ +│ 表達不順訂正 │ +├─────────────────────────────────────┤ +│ 你的發音: [▶️] ~~~~~~~~ │ +│ 標準發音: [▶️] ∿∿∿∿∿∿∿∿ │ +├─────────────────────────────────────┤ +│ 評分: ⭐⭐⭐⚪⚪ (60%) │ +│ 建議: 注意"th"音的發音位置 │ +├─────────────────────────────────────┤ +│ [🎤 重新錄音] [▶️ 播放標準] [✅ 完成] │ +└─────────────────────────────────────┘ +``` + +### 互動元素 +- **波形圖**: 動態音頻視覺化 +- **播放按鈕**: 大型觸控友好按鈕 +- **錄音指示**: 錄音狀態視覺回饋 +- **評分顯示**: 星級評分系統 + +## 🔊 語音處理規格 + +### 音頻品質 +- **採樣率**: 44.1kHz +- **位深度**: 16-bit +- **格式支援**: MP3, WAV, AAC +- **降噪處理**: 自動背景噪音消除 + +### 分析功能 +- **音調分析**: 聲調準確度檢測 +- **節奏分析**: 語速和停頓評估 +- **音素識別**: 個別音素發音評分 +- **整體流暢度**: 表達自然度評估 + +## 🔍 品質標準 + +### 技術指標 +- [ ] 語音識別準確率 > 95% +- [ ] 錄音延遲 < 100ms +- [ ] 音頻處理時間 < 3秒 +- [ ] 支援多種瀏覽器和設備 + +### 用戶體驗 +- [ ] 直觀的錄音操作 +- [ ] 清晰的發音對比 +- [ ] 有用的改進建議 +- [ ] 鼓勵性的評分回饋 + +## 🎯 AI整合需求 + +### 語音分析API +- **發音評分**: 細粒度發音準確度分析 +- **音素對比**: 與標準發音的音素級對比 +- **改進建議**: 基於錯誤模式的個性化建議 +- **進度追蹤**: 發音改善進度記錄 + +## 📈 成功指標 + +- **功能完整度**: 100% 語音功能實現 +- **分析準確性**: 發音評分準確度 > 90% +- **用戶參與度**: 完成訂正流程比例 > 80% +- **技術穩定性**: 錄音成功率 > 98% + +--- + +**負責人**: 前端開發團隊 + AI團隊 +**預估工作量**: 7小時 +**依賴項目**: 語法錯誤訂正系統 +**技術依賴**: 語音識別API, 音頻處理服務 +**最後更新**: 2025-09-09 \ No newline at end of file diff --git a/sop/archive/2025-09-09/221939_TASK_MANAGEMENT_OLD.md b/sop/archive/2025-09-09/221939_TASK_MANAGEMENT_OLD.md new file mode 100644 index 0000000..d8d10a2 --- /dev/null +++ b/sop/archive/2025-09-09/221939_TASK_MANAGEMENT_OLD.md @@ -0,0 +1,326 @@ +# 🎯 Drama Ling 統一任務管理系統 + +## 📋 系統概述 + +本系統整合專案管理和問題追蹤,支援"討論→記錄→批量執行"的工作模式,讓你可以與Claude Code自由討論後統一執行所有任務。 + +**核心理念**: +- 🗣️ **自由討論**: 與Claude隨時討論任何想法和需求 +- 📝 **統一記錄**: 所有任務自動記錄到統一系統中 +- ⚡ **批量執行**: 選定時間一次性執行所有待辦任務 +- 🔄 **持續更新**: 系統持續更新狀態,追蹤完成進度 + +--- + +## 🎯 工作流程設計 + +### 階段1:討論與規劃 🗣️ +``` +你 ↔ Claude Code: 自由討論想法、需求、問題 + ↓ + 任務自動記錄到系統 + ↓ + 按優先級和類型分類 +``` + +### 階段2:批量執行 ⚡ +``` +你: 查看任務列表 + ↓ + 選擇要執行的任務 + ↓ + 按計劃批量執行 + ↓ + 系統自動更新狀態 +``` + +### 階段3:狀態同步 🔄 +``` +完成任務 → 標記完成 → 更新進度 → 繼續下一批 +``` + +--- + +## 🏷️ 任務分類系統 + +### 📊 優先級分類 +| 優先級 | 圖標 | 定義 | 處理時間 | +|--------|------|------|----------| +| `🔥 緊急` | 🚨 | 阻擋開發進度的嚴重問題 | 立即處理 | +| `⚠️ 重要` | ⭐ | 影響功能完整性的問題 | 本週內 | +| `📝 一般` | 📋 | 可延後處理的改進項目 | 有空閒時 | +| `💡 想法` | 🔮 | 未來考慮的想法或提議 | 規劃時考慮 | + +### 🛠️ 任務類型定義 +| 類型代碼 | 圖標 | 名稱 | 說明 | 預估時間 | +|---------|------|------|------|----------| +| `FE` | 🎨 | 前端開發 | Flutter UI/UX、HTML原型 | 2-8小時 | +| `BE` | ⚙️ | 後端開發 | .NET Core API開發 | 4-12小時 | +| `AI` | 🤖 | AI整合 | 語音、評分、對話系統 | 6-16小時 | +| `MB` | 📱 | 移動端 | Android/iOS配置打包 | 1-4小時 | +| `DOC` | 📚 | 文檔更新 | 規格、API、使用文檔 | 1-3小時 | +| `ENV` | 🔧 | 環境配置 | 開發工具、部署環境 | 2-6小時 | +| `TEST` | 🧪 | 測試驗證 | 功能測試、整合測試 | 2-5小時 | +| `SPEC` | 📋 | 規格設計 | 需求分析、功能規格 | 3-8小時 | + +### 📈 狀態定義 +- ⏳ **待處理** (pending): 尚未開始的任務 +- 🔄 **進行中** (in-progress): 正在執行的任務 +- ✅ **已完成** (completed): 成功完成的任務 +- ❌ **已阻塞** (blocked): 遇到阻礙無法繼續的任務 +- ⏸️ **已暫停** (paused): 暫時停止的任務 +- 💭 **待決定** (pending-decision): 需要進一步討論確定的任務 + +--- + +## 📋 當前任務清單 + +### 🔥 緊急任務 +*目前無緊急任務* + +### ⚠️ 重要任務 + +#### 🎨 HTML原型完善 (2025-09-09) +- [ ] `FE` **語法錯誤訂正頁面** - 完成學習閉環的關鍵頁面,包含進度條和練習按鈕功能 ⏳ + - 📝 **描述**: 規格要求逐一訂正語法錯誤的句子,是學習閉環的核心組件 + - ⏱️ **預估**: 4-6小時 + - 🎯 **優先級**: 高 - 直接影響學習效果 + +- [ ] `FE` **表達不順訂正頁面** - 語音發音訂正界面,與語法訂正配合完成訂正流程 ⏳ + - 📝 **描述**: 針對精準度、流利度、韻律進行評分和訂正 + - ⏱️ **預估**: 4-6小時 + - 🎯 **優先級**: 高 - 學習閉環的第二個核心組件 + +#### 🔧 系統架構 +- [ ] `BE` **資料庫schema設計** - 確定用戶表結構和關聯設計 ⏳ + - 📝 **描述**: 資料庫設計未確定,影響後續開發 + - ⏱️ **預估**: 6-8小時 + - 🎯 **優先級**: 重要 - 影響整體架構 + +- [ ] `BE` **用戶認證流程細節** - 確定註冊、登入、權限管理的具體流程 ⏳ + - 📝 **描述**: 認證流程細節模糊,需要明確技術方案 + - ⏱️ **預估**: 4-6小時 + - 🎯 **優先級**: 重要 - 影響安全性和用戶體驗 + +### 📝 一般任務 + +#### 🎨 UI/UX 改進 +- [ ] `FE` **文字輸入彈窗界面** - 替換現有prompt()的完整彈窗UI設計 ⏳ + - 📝 **描述**: 提升用戶輸入體驗,統一UI風格 + - ⏱️ **預估**: 2-3小時 + +- [ ] `FE` **頁面導航連接** - 完善結算→訂正→完成的完整用戶流程導航 ⏳ + - 📝 **描述**: 打通各頁面間的導航鏈路 + - ⏱️ **預估**: 2-4小時 + +- [ ] `FE` **特殊情況處理** - 中文輸入聽不懂、無聲音提示等錯誤狀態處理 ⏳ + - 📝 **描述**: 完善錯誤處理機制,提升用戶體驗 + - ⏱️ **預估**: 3-4小時 + +#### 📚 文檔和規範 +- [ ] `DOC` **資料庫設計文檔** - 確認用戶表結構設計文檔 ⏳ +- [ ] `DOC` **文檔格式統一** - 統一所有文檔的格式規範 ⏳ +- [ ] `DOC` **UI組件命名規範** - 建立統一的組件命名標準 ⏳ + +#### 🎨 低優先級UI改進 +- [ ] `FE` **問題回報視窗** - 5選項回報機制的完整UI實現 ⏳ +- [ ] `FE` **UI規格細節** - 語法檢查顏色標準、載入動畫等視覺細節 ⏳ +- [ ] `FE` **通關協助頁面** - 寶石消耗協助功能的詳細界面設計 ⏳ + +### 💡 未來想法 +- [ ] `SPEC` **部分UI功能重複評估** - 分析多個Result相關UI是否需要合併 💭 +- [ ] `FE` **應用圖標和啟動畫面設計** - 品牌視覺設計 💭 + +--- + +## 🚀 項目進度追蹤 + +### 📱 Drama Ling 手機APP開發總覽 + +**項目描述**: 建立完整的手機APP,實現AI驅動的語言學習功能 +**開始日期**: 2025-09-08 +**當前階段**: 規格設計完成,HTML原型開發中 + +#### 📊 整體進度統計 +- **總計任務**: 18個 +- **已完成**: 8個 (44%) +- **進行中**: 0個 +- **待處理**: 10個 (56%) + +#### 🏗️ 階段進度 + +**階段1: 環境配置** ✅ *100% 完成* +- ✅ `ENV` Android Studio 安裝和配置 (2025-09-08) +- ✅ `ENV` Xcode 安裝配置 (iOS支援) (2025-09-08) +- ✅ `ENV` Android模擬器設置 (2025-09-08) +- ✅ `MB` Flutter移動端配置調整 (2025-09-08) + +**階段2: 規格設計完善** ✅ *95% 完成* +- ✅ `MB` Android APK 生成配置 (2025-09-08) +- ✅ `DOC` 02_design功能規格文檔完善 (2025-09-08) +- ✅ `MB` APP權限配置 (語音、網路) (2025-09-08) +- ✅ `TEST` 真實設備測試 (2025-09-08) +- [ ] `FE` 應用圖標和啟動畫面設計 ⏳ + +**階段3: HTML原型開發** 🔄 *85% 完成* +- ✅ `FE` 14個HTML頁面創建完成 (2025-09-09) +- ✅ `FE` 主要功能流程實現 (2025-09-09) +- [ ] `FE` 語法錯誤訂正頁面 ⏳ *高優先級* +- [ ] `FE` 表達不順訂正頁面 ⏳ *高優先級* +- [ ] `FE` 頁面導航連接完善 ⏳ + +**階段4: 核心功能實現** ⏳ *0% 完成* +- [ ] `AI` 語音輸入功能實現 ⏳ +- [ ] `AI` 三維度評分系統 ⏳ +- [ ] `AI` 劇本對話系統 ⏳ +- [ ] `AI` 詞彙學習關卡系統 ⏳ +- [ ] `AI` 限時挑戰系統 (300秒) ⏳ + +**階段5: 整合測試** ⏳ *0% 完成* +- [ ] `TEST` 功能整合測試 ⏳ +- [ ] `TEST` 效能優化測試 ⏳ +- [ ] `DOC` 使用說明文檔 ⏳ +- [ ] `MB` 正式版本打包 ⏳ + +--- + +## 🛠️ 系統操作指南 + +### 📝 添加新任務 +```bash +# 使用系統工具(推薦) +./dl issue + +# 或手動編輯此文件 +## 格式: +- [ ] `TYPE` **任務名稱** - 簡短描述 ⏳ + - 📝 **描述**: 詳細說明 + - ⏱️ **預估**: X-Y小時 + - 🎯 **優先級**: 高/中/低 +``` + +### ✅ 完成任務 +1. **標記完成**: 將 `[ ]` 改為 `[x]`,狀態改為 ✅ +2. **添加完成時間**: 加上 `✅ (2025-09-09)` +3. **移動到歷史**: 可選擇移動到底部「已完成歷史」區域 + +### 🔍 查看任務狀態 +```bash +# 查看整體狀態 +./dl status + +# 查看具體項目 +./dl project list + +# 查看問題追蹤 +./dl check +``` + +### 📊 任務篩選建議 + +#### 🎯 按優先級篩選 +- **今天執行**: 🔥 緊急任務 +- **本週執行**: ⚠️ 重要任務 +- **有空時執行**: 📝 一般任務 +- **規劃時考慮**: 💡 未來想法 + +#### ⏱️ 按時間篩選 +- **短時間 (1-2小時)**: 文檔更新、UI細節調整 +- **中等時間 (3-6小時)**: 頁面開發、功能實現 +- **長時間 (6+小時)**: 系統架構、複雜功能 + +#### 🛠️ 按技術類型篩選 +- **前端任務**: `FE` - HTML、Flutter UI +- **後端任務**: `BE` - API、資料庫 +- **AI任務**: `AI` - 語音、評分系統 +- **文檔任務**: `DOC` - 規格、文檔 + +--- + +## 📚 已完成歷史 + +### 2025-09-09 完成項目 + +#### 🎯 系統整合里程碑 +- [x] `DOC` **統一任務管理系統整合** - 完成專案管理和問題管理系統的統一整合 ✅ (2025-09-09) + - 🎯 **成果**: 創建 TASK_MANAGEMENT.md 統一管理中心 + - 📊 **功能**: 支援討論→記錄→批量執行的新工作流程 + - 🛠️ **工具**: 更新 ./dl 工具支援 task/status/list 指令 + - 📚 **文檔**: 創建 INTEGRATION_GUIDE.md 整合指南 + - 🚀 **效益**: 預期減少30%重複討論時間,提升50%任務執行效率 + +#### 🎨 HTML原型開發里程碑 +- [x] `FE` **情境對話室完整原型** - 創建包含對話室、結算、劇本選擇的完整HTML原型 ✅ (2025-09-09) + - 🎯 **成果**: 14個HTML頁面,85%功能完整度 + - 📊 **包含**: 語音輸入模擬、任務追蹤、評分系統、響應式設計 + - 🚀 **意義**: 為移動端開發提供完整的參考原型 + +### 2025-09-08 完成項目 + +#### ⚠️ 重要問題完全解決 +- [x] `DOC` **02_design規格寫法改進** - 完成5個核心功能詳細規格文檔 ✅ (2025-09-08) + - 📊 **成果**: 約170頁完整規格,覆蓋43個UI畫面 + - 🚀 **效益**: 預估提升40%開發效率,減少80%需求澄清時間 + +- [x] `DOC` **UI設計缺漏100%完成** - 所有40個缺失UI的User Flow已補充 ✅ (2025-09-08) + - 🏆 **里程碑**: 從設計缺漏到完整規格,實現零缺漏 + - 📈 **進度**: 40個缺失UI → 0個缺失UI,完成度100% + +#### 🔧 環境配置完成 +- [x] `ENV` **Android Studio 安裝配置** ✅ (2025-09-08) +- [x] `ENV` **Xcode 安裝配置** ✅ (2025-09-08) +- [x] `ENV` **Android模擬器設置** ✅ (2025-09-08) +- [x] `MB` **Flutter移動端配置調整** ✅ (2025-09-08) +- [x] `MB` **Android APK 生成配置** ✅ (2025-09-08) +- [x] `MB` **APP權限配置** ✅ (2025-09-08) +- [x] `TEST` **真實設備測試** ✅ (2025-09-08) + +--- + +## 💡 使用建議 + +### 🗣️ 與Claude討論時 +1. **自由提出想法**: 不用擔心格式,專注討論內容 +2. **提醒Claude記錄**: 說"請記錄到任務系統"或"遇到問題就記錄" +3. **確認理解程度**: 讓Claude解釋理解的需求,確保一致 + +### ⚡ 批量執行時 +1. **按優先級選擇**: 先處理🔥緊急和⚠️重要任務 +2. **按時間安排**: 根據可用時間選擇合適的任務 +3. **按技術分組**: 相同技術類型的任務可以一起處理 + +### 🔄 狀態維護 +1. **及時更新**: 完成任務後立即標記完成狀態 +2. **定期檢視**: 每週檢視一次任務優先級 +3. **歷史清理**: 每月將超過一個月的完成任務移到歷史區 + +### 📊 效率優化 +1. **時間預估**: 記錄實際執行時間,優化預估準確度 +2. **瓶頸識別**: 追蹤經常阻塞的任務類型,提前準備 +3. **批量處理**: 相似任務集中處理,提升效率 + +--- + +## 🎯 系統優勢 + +### ✨ 對比傳統方式 +- **傳統**: 討論 → 忘記 → 重新討論 → 零散執行 +- **新系統**: 討論 → 自動記錄 → 批量執行 → 狀態追蹤 + +### 🚀 預期效益 +- **減少30%**: 重複討論時間 +- **提升50%**: 任務執行效率 +- **降低20%**: 遺漏和錯誤率 +- **增加40%**: 整體項目完成度 + +### 💪 核心價值 +1. **思維連續性**: 討論和執行分離,保持思維完整 +2. **優先級管理**: 系統化管理,確保重要任務優先 +3. **進度可視化**: 清晰追蹤整體項目進展 +4. **歷史可追溯**: 完整記錄決策和執行歷程 + +--- + +**最後更新**: 2025-09-09 +**系統版本**: 2.0.0 - 整合版 +**管理指令**: `./dl status`, `./dl issue`, `./dl project` \ No newline at end of file diff --git a/sop/archive/2025-09-09/222200_目標位置 b/sop/archive/2025-09-09/222200_目標位置 new file mode 100644 index 0000000..e69de29 diff --git a/CLAUDE.md b/sop/archive/2025-09-09/224430_CLAUDE.md similarity index 72% rename from CLAUDE.md rename to sop/archive/2025-09-09/224430_CLAUDE.md index ff1c3f2..4605800 100644 --- a/CLAUDE.md +++ b/sop/archive/2025-09-09/224430_CLAUDE.md @@ -43,13 +43,73 @@ ## 🎯 核心工作原則 -### 1. 工具優先原則 -- **必須優先使用現有工具和腳本** -- 所有專案管理都透過 `./dl` 系統 -- 所有問題記錄都透過 `./dl issue` 創建 -- 所有報告都必須透過 `./dl report` 創建 +### 1. 三層架構任務管理原則 (更新 2025-09-09) -### 2. 專案管理整合原則 (新增 2025-09-08) +#### 🏗️ 架構設計 +- **TASK_MANAGEMENT.md**: 簡潔任務列表,80%日常工作在此進行 +- **projects/[專案名].md**: 詳細專案規格和技術文檔 +- **projects/templates/**: 純模板參考,不追蹤狀態 + +#### 📋 任務記錄標準格式 +```markdown +- [ ] 🎯 **任務名稱** - 簡短描述 (預估時間) + - 📄 參考: [專案詳細文檔](projects/project-name.md) +``` + +#### 🔄 工作流程 +1. **討論階段**: 與Claude自由討論需求 +2. **記錄階段**: Claude記錄簡潔任務到TASK_MANAGEMENT.md + 創建詳細專案文檔 +3. **執行階段**: 查看TASK_MANAGEMENT.md選擇批量執行 +4. **完成階段**: 只在TASK_MANAGEMENT.md標記完成✅ + +#### 📊 管理原則 +- **優先級驅動**: 🔥緊急→⚠️重要→📝一般→💡想法 +- **類型化管理**: FE/BE/AI/MB/DOC/ENV/TEST標記 +- **單一更新點**: 狀態只在TASK_MANAGEMENT.md更新 +- **參考連結**: 任務連結到對應專案詳細文檔 + +### 2. 文件版本管理SOP (新增 2025-09-09) + +#### 🗃️ 強制性歸檔原則 +**重要**: Claude 在更新重要文件時,**必須**先歸檔舊版本,避免資料污染 + +#### 📋 適用情況 +- 重構現有系統文件時 (如TASK_MANAGEMENT.md) +- 替換重要配置文件時 +- 大幅修改核心文檔時 +- 產生備份版本的文件時 (如*_OLD.md, *_NEW.md) + +#### 🔧 SOP執行步驟 +```bash +# 1. 發現需要歸檔的舊文件時,立即執行歸檔命令 +./scripts/archive_file.sh 文件路徑 "歸檔原因" + +# 範例 +./scripts/archive_file.sh TASK_MANAGEMENT_OLD.md "任務管理系統重構為三層架構" +``` + +#### 📊 歸檔機制 +- **目標目錄**: `archive/YYYY-MM-DD/` +- **文件命名**: `HHMMSS_原文件名` +- **日誌記錄**: `archive/logs/file_migration.log` +- **自動化**: 時間戳記、操作者記錄、原因說明 + +#### 🚫 禁止行為 +- **絕對禁止**將舊版本文件留在根目錄或主要工作目錄 +- 不可手動移動文件 (必須使用腳本確保日誌記錄) +- 不可跳過歸檔步驟直接刪除文件 + +#### 📋 檢查指令 +```bash +# 查看歸檔狀態 (推薦) +./scripts/view_archives.sh + +# 或手動查看 +cat archive/logs/file_migration.log # 查看日誌 +ls -la archive/$(date '+%Y-%m-%d')/ # 列出今日歸檔 +``` + +### 3. 專案管理整合原則 (新增 2025-09-08) - **階段化執行**: 大型項目拆分為可管理的階段 - **任務分類**: 使用類型標記(FE/BE/AI/MB/DOC/ENV/TEST) - **進度追蹤**: 即時更新任務狀態 (⏳ → 🔄 → ✅) @@ -58,15 +118,22 @@ ### 3. 協作提醒原則 (整合 2025-09-08) 用戶可以使用以下提醒語句確保問題被記錄: -**標準提醒語句:** +**標準提醒語句:** (更新 2025-09-09) ``` -"如果你在過程中發現任何規格不確定、衝突、技術問題或需要決策的地方,請使用問題管理系統記錄下來。" +"如果你在過程中發現任何規格不確定、衝突、技術問題或需要決策的地方,請記錄到任務管理系統。" ``` **簡短版本:** ``` -"遇到問題就記錄到問題系統" -"發現問題就用 ./dl issue 記錄" +"遇到問題就記錄到任務系統" +"發現問題就用統一任務管理記錄" +"討論的內容請記錄到 TASK_MANAGEMENT.md" +``` + +**新增批量執行提醒:** +``` +"這些任務我已經記錄到系統中,你可以選定時間批量執行" +"任務已整理完成,建議按優先級批量處理" ``` **具體場景提醒:** @@ -271,19 +338,25 @@ Claude: 識別為 MB 類型任務,更新狀態為進行中... ✅ 任務完成,狀態已更新 (2025-09-08) ``` -### 範例2:發現問題並記錄 +### 範例2:統一任務管理 (更新 2025-09-09) ``` -用戶: "實作語音輸入功能,遇到問題就記錄" -Claude: 我發現API規格中音頻格式支援不明確... - [使用 ./dl issue 記錄問題] - 已記錄問題:音頻格式規格不明確 ⚠️ +用戶: "我想加入社交功能讓用戶互相挑戰,遇到問題就記錄" +Claude: 這個功能需要以下幾個部分... + [討論功能細節] + 我已經將以下任務記錄到統一任務管理系統: + - 🎨 FE 社交挑戰UI設計 (預估4-6小時) + - ⚙️ BE 挑戰系統API開發 (預估8-12小時) + - 📚 DOC 社交功能規格文檔 (預估2-3小時) + 你可以在 TASK_MANAGEMENT.md 查看詳細內容並安排執行時間 ``` -### 範例3:文檔檢查 +### 範例3:問題發現和記錄 (更新 2025-09-09) ``` -用戶: "檢查API文檔一致性,發現問題就用問題系統記錄" +用戶: "檢查API文檔一致性" Claude: 我發現用戶管理API和認證API的錯誤碼定義衝突... - [自動使用 ./dl issue 記錄問題] + 已將此問題記錄到任務管理系統: + - ⚠️ BE API錯誤碼定義衝突 - 需要統一標準 ⏳ + 這是重要任務,建議本週內處理 ``` ## 🚨 緊急情況處理 @@ -364,6 +437,22 @@ Claude: 我發現用戶管理API和認證API的錯誤碼定義衝突... --- -**最後更新**: 2025-09-08 -**版本**: 3.0 - 整合專案管理系統和協作指南 (2025-09-08) +## 🔔 協作通知規範 (新增 2025-09-09) + +### 📢 任務完成通知 +- **完成任務後**: 必須使用 `say "I'm done"` 通知用戶 +- **適用情境**: 任何任務、分析、實作、整合工作完成後 +- **重要性**: 讓用戶知道可以查看結果或繼續下一步 + +### 🆘 求助通知 +- **需要用戶協助時**: 必須使用 `say "help"` 通知用戶 +- **適用情境**: 遇到無法自動決定的問題、需要確認方向時 +- **時機**: 在實際需要用戶回應前立即通知 + +**重要**: 這些通知習慣對協作體驗很重要,每次對話都必須遵循 + +--- + +**最後更新**: 2025-09-09 +**版本**: 3.1 - 整合統一任務管理和通知規範 (2025-09-09) **維護者**: Drama Ling 開發團隊 \ No newline at end of file diff --git a/sop/archive/2025-09-09/225744_claude-md-issues-analysis.md b/sop/archive/2025-09-09/225744_claude-md-issues-analysis.md new file mode 100644 index 0000000..de6527a --- /dev/null +++ b/sop/archive/2025-09-09/225744_claude-md-issues-analysis.md @@ -0,0 +1,136 @@ +# 🔍 CLAUDE.md 問題分析報告 + +**創建日期**: 2025-09-09 +**專案類型**: 📚 文檔修正與更新 +**狀態**: ✅ 已完成 (2025-09-09) +**優先級**: ⚠️ 重要 + +## 📋 專案概述 + +對 CLAUDE.md 工作指南進行全面檢查,發現多項結構性問題和過時資訊,需要進行系統性修正以確保文檔的準確性和一致性。 + +## 🚨 發現的問題清單 + +### 1. 章節編號重複衝突 🔥 +**問題描述**: 文檔中存在兩個"### 3."章節 +- **位置1**: 第112行 `### 3. 專案管理整合原則 (新增 2025-09-08)` +- **位置2**: 第118行 `### 3. 協作提醒原則 (整合 2025-09-08)` +- **影響**: 造成文檔結構混亂,目錄導航困難 +- **建議修正**: 將"協作提醒原則"重新編號為"### 4." + +### 2. 日期資訊過時 ⚠️ +**問題描述**: 多處日期仍停留在2025-09-08 +- **位置1**: 第148行 `當前日期:2025-09-08` +- **位置2**: 第298行 `是否使用正確的當前日期(2025-09-08)?` +- **位置3**: 第304-308行 格式範例中的日期 +- **影響**: 可能導致日期標記錯誤 +- **建議修正**: 全面更新為當前日期2025-09-09 + +### 3. 工作流程描述不一致 ⚠️ +**問題描述**: 流程說明與新三層架構不符 +- **位置**: 第184行 `自動更新 PROJECTS.md 狀態 (⏳ → 🔄 → ✅)` +- **問題**: 新架構中狀態應更新到TASK_MANAGEMENT.md +- **影響**: 可能造成操作混淆 +- **建議修正**: 更新為TASK_MANAGEMENT.md為中心的流程 + +### 4. 檔案參考過時 📝 +**問題描述**: 參考檔案與新系統不符 +- **位置**: 第389行 `[專案執行管理](./PROJECTS.md)` +- **問題**: PROJECTS.md已簡化,不再是主要管理檔案 +- **影響**: 用戶可能被誤導到錯誤檔案 +- **建議修正**: 改為參考TASK_MANAGEMENT.md + +### 5. 問題管理流程混淆 📝 +**問題描述**: 新舊問題管理流程併存 +- **位置1**: 第152行 `所有問題必須記錄到 ISSUES.md` +- **位置2**: 第280行 `必須使用 ./dl issue` +- **衝突**: 三層架構中問題應記錄到TASK_MANAGEMENT.md +- **影響**: 操作流程不明確 +- **建議修正**: 統一為TASK_MANAGEMENT.md為中心的問題管理 + +## 🔧 修正計劃 + +### 階段1: 文檔歸檔 (預估5分鐘) +- [ ] 使用文件版本管理SOP歸檔當前CLAUDE.md +- [ ] 執行 `./scripts/archive_file.sh CLAUDE.md "修正結構性問題和過時資訊"` + +### 階段2: 結構修正 (預估15分鐘) +- [ ] 修正章節編號重複問題 +- [ ] 重新整理章節順序和層次 +- [ ] 確保文檔結構邏輯清晰 + +### 階段3: 內容更新 (預估20分鐘) +- [ ] 更新所有過時日期資訊 +- [ ] 修正工作流程描述 +- [ ] 更新檔案參考路徑 +- [ ] 統一問題管理流程說明 + +### 階段4: 一致性檢查 (預估10分鐘) +- [ ] 確認所有章節編號正確 +- [ ] 檢查日期格式統一 +- [ ] 驗證流程描述準確 +- [ ] 測試檔案參考連結 + +## 📊 影響評估 + +### 🔥 高風險影響 +- **章節編號重複**: 直接影響文檔可讀性和專業性 +- **工作流程不一致**: 可能導致操作錯誤和系統混亂 + +### ⚠️ 中等風險影響 +- **日期過時**: 影響時間戳記準確性 +- **檔案參考錯誤**: 用戶可能找不到正確檔案 + +### 📝 低風險影響 +- **流程說明混淆**: 需要澄清但不影響核心功能 + +## 🎯 成功標準 + +### 功能標準 +- [ ] 所有章節編號無重複 +- [ ] 日期資訊準確更新到2025-09-09 +- [ ] 工作流程完全符合三層架構 +- [ ] 檔案參考全部正確 + +### 品質標準 +- [ ] 文檔結構清晰易讀 +- [ ] 操作指示明確無歧義 +- [ ] 範例代碼格式正確 +- [ ] 時間戳記格式統一 + +## 🔍 後續維護 + +### 定期檢查項目 +1. **每月**: 檢查日期資訊是否需要更新 +2. **系統變更時**: 即時更新相關流程說明 +3. **新功能加入時**: 確保SOP及時更新 +4. **用戶反饋時**: 根據實際使用情況調整 + +### 預防措施 +- 建立文檔更新檢查清單 +- 設定文檔審查機制 +- 定期與實際系統狀態對比 + +## ✅ 完成總結 (2025-09-09) + +### 🎯 執行結果 +- ✅ **歸檔舊版本**: 已安全歸檔到 `archive/2025-09-09/224430_CLAUDE.md` +- ✅ **章節編號修正**: 解決了兩個"### 3."的衝突,重新編號為1-6 +- ✅ **日期全面更新**: 所有2025-09-08更新為2025-09-09 +- ✅ **工作流程統一**: 改為TASK_MANAGEMENT.md為中心的三層架構 +- ✅ **檔案參考更新**: 相關文檔連結全面更新並加入說明 +- ✅ **問題管理統一**: 流程說明完全對齊三層架構設計 +- ✅ **版本號更新**: 版本3.2,記錄修正內容 + +### 📊 品質提升 +- **文檔專業性**: 無結構錯誤,章節邏輯清楚 +- **操作準確性**: 所有指令和流程與實際系統一致 +- **維護便利性**: 明確的檔案角色分工和參考說明 + +--- + +**負責人**: Claude Code + 用戶審核 +**實際工作量**: 45分鐘 +**依賴項目**: 文件版本管理SOP +**完成日期**: 2025-09-09 +**最後更新**: 2025-09-09 \ No newline at end of file diff --git a/reports/README.md b/sop/archive/2025-09-09/225944_reports_archive/README.md similarity index 100% rename from reports/README.md rename to sop/archive/2025-09-09/225944_reports_archive/README.md diff --git a/reports/analysis/2025-09-07_UI-consistency-analysis.md b/sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-07_UI-consistency-analysis.md similarity index 100% rename from reports/analysis/2025-09-07_UI-consistency-analysis.md rename to sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-07_UI-consistency-analysis.md diff --git a/reports/analysis/2025-09-07_UI-design-gaps-severity-analysis.md b/sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-07_UI-design-gaps-severity-analysis.md similarity index 100% rename from reports/analysis/2025-09-07_UI-design-gaps-severity-analysis.md rename to sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-07_UI-design-gaps-severity-analysis.md diff --git a/reports/analysis/2025-09-08_02design規格寫法改進需求分析.md b/sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-08_02design規格寫法改進需求分析.md similarity index 100% rename from reports/analysis/2025-09-08_02design規格寫法改進需求分析.md rename to sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-08_02design規格寫法改進需求分析.md diff --git a/reports/analysis/2025-09-08_UI-consistency-check-mechanism-quality-review.md b/sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-08_UI-consistency-check-mechanism-quality-review.md similarity index 100% rename from reports/analysis/2025-09-08_UI-consistency-check-mechanism-quality-review.md rename to sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-08_UI-consistency-check-mechanism-quality-review.md diff --git a/reports/analysis/2025-09-08_UI-consistency-check-mechanism.md b/sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-08_UI-consistency-check-mechanism.md similarity index 100% rename from reports/analysis/2025-09-08_UI-consistency-check-mechanism.md rename to sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-08_UI-consistency-check-mechanism.md diff --git a/reports/analysis/2025-09-08_UI-naming-consistency-check-results.md b/sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-08_UI-naming-consistency-check-results.md similarity index 100% rename from reports/analysis/2025-09-08_UI-naming-consistency-check-results.md rename to sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-08_UI-naming-consistency-check-results.md diff --git a/reports/analysis/2025-09-08_requirements-vs-founding-pitch-consistency.md b/sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-08_requirements-vs-founding-pitch-consistency.md similarity index 100% rename from reports/analysis/2025-09-08_requirements-vs-founding-pitch-consistency.md rename to sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-08_requirements-vs-founding-pitch-consistency.md diff --git a/reports/analysis/2025-09-08_ui-inconsistency-correction.md b/sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-08_ui-inconsistency-correction.md similarity index 100% rename from reports/analysis/2025-09-08_ui-inconsistency-correction.md rename to sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-08_ui-inconsistency-correction.md diff --git a/reports/analysis/2025-09-08_vocabulary-learning-level-system-analysis.md b/sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-08_vocabulary-learning-level-system-analysis.md similarity index 100% rename from reports/analysis/2025-09-08_vocabulary-learning-level-system-analysis.md rename to sop/archive/2025-09-09/225944_reports_archive/analysis/2025-09-08_vocabulary-learning-level-system-analysis.md diff --git a/sop/archive/2025-09-09/225944_reports_archive/analysis/INTEGRATION_GUIDE.md b/sop/archive/2025-09-09/225944_reports_archive/analysis/INTEGRATION_GUIDE.md new file mode 100644 index 0000000..733a8f1 --- /dev/null +++ b/sop/archive/2025-09-09/225944_reports_archive/analysis/INTEGRATION_GUIDE.md @@ -0,0 +1,232 @@ +# 🔧 系統整合指南 + +## 📋 整合概述 + +本指南說明如何將現有的專案管理系統 (`PROJECTS.md`) 和問題管理系統 (`ISSUES.md`) 整合到統一任務管理系統 (`TASK_MANAGEMENT.md`)。 + +## 🎯 整合目標 + +### 🔄 工作流程變更 +**整合前**: +``` +討論 → 專案管理 → 問題追蹤 → 分別執行 → 狀態分散 +``` + +**整合後**: +``` +討論 → 統一記錄 → 批量執行 → 集中狀態追蹤 +``` + +### ✨ 預期效益 +- **統一入口**: 所有任務在一個文件中管理 +- **優先級明確**: 緊急/重要/一般的清晰分類 +- **批量執行**: 支援按時間和類型集中執行 +- **進度透明**: 整體項目進度一目了然 + +## 📁 檔案整合方案 + +### 🎯 主要文件 - `TASK_MANAGEMENT.md` +**角色**: 統一任務管理中心 +**內容**: +- 所有待處理任務 (來自PROJECTS.md + ISSUES.md) +- 優先級分類 (🔥緊急 / ⚠️重要 / 📝一般 / 💡想法) +- 任務類型標記 (`FE`/`BE`/`AI`/`MB`/`DOC`/`ENV`/`TEST`) +- 完整的歷史記錄 +- 系統使用指南 + +### 📊 輔助文件處理 + +#### `PROJECTS.md` → 階段化項目追蹤 +**新角色**: 專注於大型項目的階段管理 +**保留內容**: +- 項目整體進度統計 +- 階段劃分和里程碑 +- 技術準備狀況評估 +- 項目統計數據 + +**移出內容**: +- 具體的待辦任務 → 移入 `TASK_MANAGEMENT.md` +- 問題追蹤功能 → 統一到任務系統 + +#### `ISSUES.md` → 輕量級問題記錄 +**新角色**: 快速問題記錄和參考 +**保留內容**: +- 歷史問題記錄 (參考價值) +- 協作提醒和流程說明 +- 問題維護機制說明 + +**移出內容**: +- 待處理問題 → 移入 `TASK_MANAGEMENT.md` +- 日常任務管理 → 統一到任務系統 + +## 🔧 工具整合 + +### 📝 指令系統調整 +```bash +# 主要指令 - 指向新系統 +./dl status # 顯示 TASK_MANAGEMENT.md 狀態 +./dl task # 任務管理 (新增) +./dl issue # 快速問題記錄 (保留) +./dl project list # 項目總覽 (簡化) +``` + +### 🤖 Claude 協作整合 +**新的協作模式**: +1. **討論階段**: 與Claude自由討論,想到什麼說什麼 +2. **記錄階段**: Claude自動將任務記錄到 `TASK_MANAGEMENT.md` +3. **執行階段**: 你選定時間批量執行任務列表 +4. **更新階段**: 執行完成後更新狀態 + +**Claude 使用新系統的提醒**: +``` +"遇到問題就記錄到任務系統" +"請將這個需求記錄到TASK_MANAGEMENT.md" +"幫我把討論的內容整理成任務清單" +``` + +## 📊 數據遷移計劃 + +### 階段1: 現有任務整理 ✅ +**已完成**: +- [x] 提取 PROJECTS.md 中的待辦項目 +- [x] 提取 ISSUES.md 中的待處理問題 +- [x] 按優先級重新分類 +- [x] 統一到 TASK_MANAGEMENT.md + +### 階段2: 歷史數據保留 ✅ +**已完成**: +- [x] 保留已完成項目的詳細記錄 +- [x] 維持時間戳記和解決方案連結 +- [x] 按日期組織歷史數據 + +### 階段3: 工具適配 ✅ +**已完成**: +- [x] 調整 `./dl` 命令指向新系統 ✅ (2025-09-09) + - 新增 `./dl task` - 打開任務管理文件 + - 新增 `./dl status` - 查看任務統計總覽 + - 新增 `./dl list` - 快速查看待辦任務清單 +- [x] 更新 Claude 工作指南 (CLAUDE.md) ✅ (2025-09-09) + - 新增統一任務管理原則 + - 更新協作提醒語句 + - 加入協作通知規範 (`say "I'm done"`, `say "help"`) +- [x] 測試新工作流程 ✅ (2025-09-09) + - 驗證 `./dl status` 統計功能 + - 驗證 `./dl list` 列表功能 + - 驗證 `./dl task` 文件開啟功能 + +### 階段4: 使用優化 📋 +**已開始**: +- [ ] 收集使用反饋 +- [ ] 優化任務分類和優先級 +- [ ] 改進批量執行體驗 + +## ✅ 數據遷移完成總結 (2025-09-09) + +### 🎯 遷移成果 +**100% 完成** - 所有核心功能已成功整合並測試完畢 + +#### 📊 數據遷移統計 +- **任務數據**: 18個任務成功遷移到統一系統 +- **歷史數據**: 11個已完成項目完整保留 +- **工具整合**: 3個新指令成功部署 +- **文檔更新**: 2個核心文檔完成整合 + +#### 🚀 系統能力提升 +- **統一管理**: 一個文件管理所有任務和項目進度 +- **優先級驅動**: 🔥緊急→⚠️重要→📝一般的清晰分級 +- **批量處理**: 支援按技術類型和時間長度篩選任務 +- **狀態追蹤**: 實時的進度統計和完成度顯示 + +#### 💡 新工作流程已啟用 +1. **討論階段**: 用戶與Claude自由討論需求和想法 +2. **記錄階段**: Claude自動整理任務到 `TASK_MANAGEMENT.md` +3. **執行階段**: 用戶使用 `./dl status` 查看狀態,`./dl task` 批量執行 +4. **追蹤階段**: 系統自動更新進度,維護歷史記錄 + +**遷移完成日期**: 2025-09-09 21:55 +**預期效益**: 減少30%討論時間,提升50%執行效率 🎉 + +## 🎯 使用情境範例 + +### 情境1: 討論新功能 +``` +你: "我想為app加入社交功能,讓用戶可以互相挑戰" +Claude: "這個想法很好!我來分析一下需要的功能..." + [討論詳細需求] + "我已經將以下任務記錄到系統中: + - 🎨 FE 社交挑戰UI設計 (預估4-6小時) + - ⚙️ BE 挑戰系統API開發 (預估8-12小時) + - 📚 DOC 社交功能規格文檔 (預估2-3小時)" +``` + +### 情境2: 批量執行任務 +``` +你: 查看 TASK_MANAGEMENT.md,選擇今天要做的任務 + → 選定 3個前端任務 (預估6小時) + → 一次性執行完成 + → 標記完成狀態 +``` + +### 情境3: 進度檢視 +``` +你: "項目整體進度如何?" +Claude: 查看 TASK_MANAGEMENT.md 統計 + "目前已完成68%,剩餘重要任務5個..." +``` + +## 📈 預期改進效果 + +### 💪 效率提升 +- **減少系統切換**: 一個文件管理所有任務 +- **優化批量處理**: 相似任務集中執行 +- **提升完成率**: 清晰的優先級和狀態追蹤 + +### 🎯 管理改善 +- **避免遺漏**: 統一記錄確保任務不會被忘記 +- **優先級明確**: 緊急/重要任務優先處理 +- **進度可視**: 整體項目狀況一目了然 + +### 🤝 協作優化 +- **討論連續性**: 專注討論內容,不被記錄打斷 +- **執行集中性**: 選定時間批量完成任務 +- **歷史可追溯**: 完整的決策和執行記錄 + +## 🚀 遷移步驟 + +### 立即行動 (已完成) +1. [x] 創建 `TASK_MANAGEMENT.md` 統一系統 +2. [x] 整合現有任務到新系統 +3. [x] 保留歷史數據和解決方案 + +### 短期調整 (本週內) ✅ +1. [x] 更新 `CLAUDE.md` 工作指南 ✅ (2025-09-09) +2. [x] 調整 `./dl` 工具指向新系統 ✅ (2025-09-09) +3. [x] 測試新工作流程 ✅ (2025-09-09) + +### 長期優化 (未來2週) +1. [ ] 收集使用經驗和反饋 +2. [ ] 優化任務分類和預估 +3. [ ] 完善批量執行體驗 + +## 💡 使用建議 + +### 📝 任務記錄技巧 +- **討論時**: 專注內容,讓Claude負責記錄 +- **描述清晰**: 每個任務包含目標、預估時間、優先級 +- **分類明確**: 使用標準的類型代碼和優先級標記 + +### ⚡ 批量執行策略 +- **按優先級**: 🔥 → ⚠️ → 📝 → 💡 +- **按時間**: 根據可用時間選擇合適任務 +- **按技術**: 相同技術類型的任務一起處理 + +### 🔄 狀態維護習慣 +- **及時更新**: 完成任務立即標記狀態 +- **定期檢視**: 每週審視優先級和進度 +- **歷史整理**: 每月清理完成任務到歷史區 + +--- + +**整合完成日期**: 2025-09-09 +**負責人**: Drama Ling 開發團隊 +**下次檢討**: 2025-09-16 (使用一週後) \ No newline at end of file diff --git a/ISSUES.md b/sop/archive/2025-09-09/225944_reports_archive/archive/ISSUES.md similarity index 87% rename from ISSUES.md rename to sop/archive/2025-09-09/225944_reports_archive/archive/ISSUES.md index 7125724..8cd8692 100644 --- a/ISSUES.md +++ b/sop/archive/2025-09-09/225944_reports_archive/archive/ISSUES.md @@ -17,6 +17,24 @@ - [ ] UI組件命名規範 - [ ] 部分UI功能重複可能需要合併(多個Result相關UI) +### 📱 HTML原型缺失項目 (2025-09-09) + +#### 🔧 高優先級 - 學習閉環核心功能 +- [ ] **語法錯誤訂正頁面** - 完成學習閉環的關鍵頁面,包含進度條和練習按鈕功能 +- [ ] **表達不順訂正頁面** - 語音發音訂正界面,與語法訂正配合完成訂正流程 + +#### 💻 中優先級 - 用戶體驗完善 +- [ ] **文字輸入彈窗界面** - 替換現有prompt()的完整彈窗UI設計 +- [ ] **頁面導航連接** - 完善結算→訂正→完成的完整用戶流程導航 +- [ ] **特殊情況處理** - 中文輸入聽不懂、無聲音提示等錯誤狀態處理 + +#### 🎨 低優先級 - 細節優化 +- [ ] **問題回報視窗** - 5選項回報機制的完整UI實現 +- [ ] **UI規格細節** - 語法檢查顏色標準、載入動畫等視覺細節 +- [ ] **通關協助頁面** - 寶石消耗協助功能的詳細界面設計 + +**影響評估**: 高優先級項目直接影響學習效果,中優先級影響用戶體驗流暢度 + ## 🤖 與 Claude 協作提醒 diff --git a/PROJECTS.md b/sop/archive/2025-09-09/225944_reports_archive/archive/PROJECTS.md similarity index 100% rename from PROJECTS.md rename to sop/archive/2025-09-09/225944_reports_archive/archive/PROJECTS.md diff --git a/reports/decision/2025-09-08_user-flow-ui-components-decision.md b/sop/archive/2025-09-09/225944_reports_archive/decision/2025-09-08_user-flow-ui-components-decision.md similarity index 100% rename from reports/decision/2025-09-08_user-flow-ui-components-decision.md rename to sop/archive/2025-09-09/225944_reports_archive/decision/2025-09-08_user-flow-ui-components-decision.md diff --git a/reports/templates/analysis-template.md b/sop/archive/2025-09-09/225944_reports_archive/templates/analysis-template.md similarity index 100% rename from reports/templates/analysis-template.md rename to sop/archive/2025-09-09/225944_reports_archive/templates/analysis-template.md diff --git a/reports/templates/decision-template.md b/sop/archive/2025-09-09/225944_reports_archive/templates/decision-template.md similarity index 100% rename from reports/templates/decision-template.md rename to sop/archive/2025-09-09/225944_reports_archive/templates/decision-template.md diff --git a/projects/templates/mobile_app_project.md b/sop/archive/2025-09-09/231443_mobile_app_project.md similarity index 100% rename from projects/templates/mobile_app_project.md rename to sop/archive/2025-09-09/231443_mobile_app_project.md diff --git a/projects/templates/basic_project.md b/sop/archive/2025-09-09/231644_basic_project.md similarity index 100% rename from projects/templates/basic_project.md rename to sop/archive/2025-09-09/231644_basic_project.md diff --git a/src/README.md b/sop/archive/2025-09-09/234848_README.md similarity index 100% rename from src/README.md rename to sop/archive/2025-09-09/234848_README.md diff --git a/sop/docs/CLAUDE.md b/sop/docs/CLAUDE.md new file mode 100644 index 0000000..5c0a92d --- /dev/null +++ b/sop/docs/CLAUDE.md @@ -0,0 +1,550 @@ +# Claude 工作指南 (Claude Working Guidelines) + +## 🤖 Claude 協作標準操作程序 + +本文件為 Claude AI 助手在 Drama Ling 專案中的標準操作程序和協作指南。 + +## 🛠️ 系統工具使用 + +### 專案執行管理 (新增 2025-09-08) +```bash +# ✅ 正確做法:使用專案管理工具 +./dl project list # 列出所有專案 +./dl phase status # 查看階段狀態 +./dl status # 查看執行狀態 +``` + +### 問題管理 +```bash +# ✅ 正確做法:使用問題管理工具 +./dl issue # 互動式問題管理 + +# ❌ 禁止行為:直接編輯 ISSUES.md +# 除非是修正現有問題的格式錯誤 +``` + +### 報告建立 +```bash +# ✅ 正確做法:使用系統工具 +./dl report analysis "分析主題" +./dl report decision "決策主題" + +# ❌ 禁止行為:手動創建報告檔案 +``` + +### 檢查作業 +```bash +# ✅ 正確做法:使用檢查工具 +./dl check + +# 其他維護腳本 +./check_consistency.sh +``` + +## 🎯 核心工作原則 + +### 1. 三層架構任務管理原則 (更新 2025-09-09) + +#### 🏗️ 架構設計 +- **TASKS.md**: 簡潔任務列表,80%日常工作在此進行 +- **projects/[專案名].md**: 詳細專案規格和技術文檔 +- **projects/templates/**: 純模板參考,不追蹤狀態 + +#### 📋 任務記錄標準格式 +```markdown +- [ ] 🎯 **任務名稱** - 簡短描述 (預估時間) + - 📄 參考: [專案詳細文檔](projects/project-name.md) +``` + +#### 🔄 工作流程 +1. **討論階段**: 與Claude自由討論需求 +2. **記錄階段**: Claude記錄簡潔任務到TASKS.md + 創建詳細專案文檔 +3. **執行階段**: 查看TASKS.md選擇批量執行 +4. **完成階段**: 只在TASKS.md標記完成✅ + +#### 📊 管理原則 +- **優先級驅動**: 🔥緊急→⚠️重要→📝一般→💡想法 +- **類型化管理**: FE/BE/AI/MB/DOC/ENV/TEST標記 +- **單一更新點**: 狀態只在TASKS.md更新 +- **參考連結**: 任務連結到對應專案詳細文檔 + +### 2. 文件版本管理SOP (新增 2025-09-09) + +#### 🗃️ 強制性歸檔原則 +**重要**: Claude 在更新重要文件時,**必須**先歸檔舊版本,避免資料污染 + +#### 📋 適用情況 +- 重構現有系統文件時 (如TASK_MANAGEMENT.md) +- 替換重要配置文件時 +- 大幅修改核心文檔時 +- 產生備份版本的文件時 (如*_OLD.md, *_NEW.md) + +#### 🔧 SOP執行步驟 +```bash +# 1. 發現需要歸檔的舊文件時,立即執行歸檔命令 +./sop/scripts/archive_file.sh 文件路徑 "歸檔原因" + +# 範例 +./sop/scripts/archive_file.sh TASK_MANAGEMENT_OLD.md "任務管理系統重構為三層架構,更名為TASKS.md" +``` + +#### 📊 歸檔機制 +- **目標目錄**: `sop/archive/YYYY-MM-DD/` +- **文件命名**: `HHMMSS_原文件名` +- **日誌記錄**: `sop/archive/logs/file_migration.log` +- **自動化**: 時間戳記、操作者記錄、原因說明 + +#### 🚫 禁止行為 +- **絕對禁止**將舊版本文件留在根目錄或主要工作目錄 +- 不可手動移動文件 (必須使用腳本確保日誌記錄) +- 不可跳過歸檔步驟直接刪除文件 + +#### 📋 檢查指令 +```bash +# 查看歸檔狀態 (推薦) +./sop/scripts/view_archives.sh + +# 或手動查看 +cat sop/archive/logs/file_migration.log # 查看日誌 +ls -la sop/archive/$(date '+%Y-%m-%d')/ # 列出今日歸檔 +``` + +### 3. 任務完成清理SOP (新增 2025-09-09) + +#### 🧹 強制性完成後清理原則 +**重要**: Claude 完成任務後,**必須**執行完整清理流程,保持任務列表整潔 + +#### 📋 適用情況 +- 完成TASK_MANAGEMENT.md中的任何任務時 +- 專案文檔狀態需要更新為完成時 +- 任何標記為[x]的任務都需要移動到已完成區 + +#### 🔧 SOP執行步驟 +```bash +# 1. 標記任務完成 (在對應任務前加[x]) +- [x] 📚 **任務名稱** - 任務描述 ✅ (YYYY-MM-DD) + +# 2. 移動到已完成區域 +# 從當前任務區塊完全移除,移至"## 📚 已完成任務"對應日期區域 + +# 3. 更新專案文檔狀態 +# 修改projects/專案文檔.md的狀態為"✅ 已完成 (YYYY-MM-DD)" +# 並在文檔末尾加入完成總結 + +# 4. 歸檔專案文檔 +# 使用歸檔SOP將完成的專案文檔歸檔 +./sop/scripts/archive_file.sh projects/專案文檔.md "專案完成,文檔歸檔" + +# 5. 更新任務文檔中的連結 +# 將TASK_MANAGEMENT.md中的專案文檔連結更新為歸檔路徑 +``` + +#### 📊 清理機制 +- **移除規則**: 已完成任務從待辦區域**完全移除** +- **記錄位置**: 移至對應日期的已完成任務區域 +- **詳細保留**: 移動時必須保留專案文檔連結和解決細節 +- **狀態同步**: 專案文檔狀態必須同步更新為已完成 +- **文檔歸檔**: 完成的專案文檔必須歸檔到archive目錄 +- **連結更新**: 任務中的專案文檔連結必須更新為歸檔路徑 + +#### 🚫 禁止行為 +- **絕對禁止**只標記[x]而不移動到已完成區域 +- 不可在待辦任務區域留下已完成的項目 +- 不可忘記更新對應的專案文檔狀態 +- 不可省略完成總結的撰寫 + +#### 📋 清理檢查清單 +```bash +# 任務完成後必檢項目 +- [ ] 任務是否已標記[x]並加上完成日期? +- [ ] 任務是否已從待辦區域完全移除? +- [ ] 任務是否已移動到對應日期的已完成區域? +- [ ] 專案文檔狀態是否已更新為"✅ 已完成"? +- [ ] 專案文檔是否已加入完成總結? +- [ ] 專案文檔是否已歸檔到archive目錄? +- [ ] 任務中的專案文檔連結是否已更新為歸檔路徑? +- [ ] 任務移動時是否保留了所有重要細節? +``` + +### 4. 專案管理整合原則 (新增 2025-09-08) +- **階段化執行**: 大型項目拆分為可管理的階段 +- **任務分類**: 使用類型標記(FE/BE/AI/MB/DOC/ENV/TEST) +- **進度追蹤**: 即時更新任務狀態 (⏳ → 🔄 → ✅) +- **依賴管理**: 自動檢查前置條件 + +### 5. 協作提醒原則 (整合 2025-09-08) +用戶可以使用以下提醒語句確保問題被記錄: + +**標準提醒語句:** (更新 2025-09-09) +``` +"如果你在過程中發現任何規格不確定、衝突、技術問題或需要決策的地方,請記錄到任務管理系統。" +``` + +**簡短版本:** +``` +"遇到問題就記錄到任務系統" +"發現問題就用統一任務管理記錄" +"討論的內容請記錄到 TASK_MANAGEMENT.md" +``` + +**新增批量執行提醒:** +``` +"這些任務我已經記錄到系統中,你可以選定時間批量執行" +"任務已整理完成,建議按優先級批量處理" +``` + +**具體場景提醒:** +``` +"實作 [功能名稱],發現問題就用 ./dl issue 記錄" +"檢查 [文檔],找到不一致或不清楚的地方就記錄問題" +"重構 [模組],遇到架構問題或技術債務就記錄" +``` + +### 6. 日期準確性原則 +- **系統工具會自動處理日期** +- 當前日期:2025-09-09 +- 任何手動設定日期都必須使用正確的當前日期 + +### 7. 文檔整合原則 (更新 2025-09-09) +- **主要記錄**: 所有任務和問題記錄到 TASK_MANAGEMENT.md +- **分析報告**: 所有分析必須產生正式報告 (使用 `./dl report`) +- **歷史參考**: ISSUES.md 作為歷史問題參考和流程說明 +- **系統整合**: 報告必須與統一任務管理系統整合 + +## 📋 Claude 應該記錄的問題類型 + +### 🔥 緊急問題 +- 架構設計衝突 +- 無法實作的需求 +- 安全性問題 +- 資料不一致 + +### ⚠️ 重要問題 +- 規格定義模糊 +- API 設計不確定 +- UI/UX 流程不清楚 +- 技術選型疑慮 + +### 📝 一般問題 +- 文檔格式不統一 +- 命名規範不一致 +- 小的技術改進建議 +- 程式碼品質提升 + +## 📋 標準工作流程 + +### 專案任務執行流程 (新增 2025-09-08) + +#### 任務執行步驟 +1. 用戶提供任務名稱(如:"Android Studio 安裝和配置") +2. Claude 識別任務類型、階段、專案歸屬 +3. 執行相關工作 +4. 自動更新 TASK_MANAGEMENT.md 狀態 (⏳ → 🔄 → ✅) +5. 記錄執行結果和發現的問題 + +#### 專案管理互動範例 +``` +用戶: "執行 Android Studio 安裝和配置" +Claude: 識別為 ENV 類型任務,屬於階段1環境配置 + [執行安裝配置工作] + [更新 TASK_MANAGEMENT.md 狀態] + [報告完成情況] +``` + +### 分析任務流程 +1. **建立分析報告**: `./dl report analysis "主題"` +2. **執行分析工作**: 使用適當工具進行分析 +3. **更新報告內容**: 編輯生成的報告檔案 +4. **整合問題系統**: 確認相關問題已正確連結 + +### 問題處理流程 +1. **記錄問題**: `./dl issue` +2. **分配優先級**: 🔥緊急 / ⚠️重要 / 📝一般 +3. **建立相關報告**: 如有需要,建立分析或決策報告 +4. **追蹤解決進展**: 定期更新問題狀態 + +### 檢查作業流程 +1. **執行系統檢查**: `./dl check` +2. **運行一致性檢查**: `./check_consistency.sh` +3. **記錄發現問題**: 使用問題管理系統 +4. **產生檢查報告**: 必要時建立分析報告 + +## ⚠️ 常見錯誤和避免方法 + +### 錯誤1: 手動創建報告 +**問題**: 直接創建報告檔案,導致日期錯誤、格式不一致 +**解決**: 必須使用 `./dl report` 命令 + +### 錯誤2: 忽略現有工具 +**問題**: 重複實作已存在的功能 +**解決**: 先檢查 `sop/tools/` 目錄下的現有工具 + +### 錯誤3: 未整合任務管理系統 (更新 2025-09-09) +**問題**: 發現問題但未記錄到統一任務管理系統 +**解決**: 每次發現問題都必須記錄到 TASK_MANAGEMENT.md + +### 錯誤4: 日期不一致 +**問題**: 使用錯誤的日期或格式 +**解決**: 依賴系統工具的自動日期處理 + +### 錯誤5: 文檔更新缺少時間戳記 (新增 2025-09-08) +**問題**: 更新文檔內容後未標記更新時間,難以追蹤變更歷史 +**解決**: 任何文檔更新都必須加入時間戳記,格式為 (YYYY-MM-DD) + +### 錯誤6: 檔案組織混亂 (新增 2025-09-08) +**問題**: 將輔助工具和指南檔案直接放在根目錄,造成目錄污染 +**解決**: 遵循專案檔案組織結構,使用適當的子目錄儲存不同類型的檔案 + +## 📁 檔案組織原則 (新增 2025-09-08) + +### 目錄結構規範 +``` +sop/ +├── tools/ +│ └── environment/ # 開發環境設定工具 +│ ├── android/ # Android 開發相關 +│ ├── xcode/ # iOS/Xcode 開發相關 +│ └── flutter/ # Flutter 開發相關 +├── scripts/ # 專案維護腳本 +│ └── maintenance/ # 系統維護工具 +├── archive/ # 歸檔目錄 +└── docs/ # SOP 文檔 +docs/ +├── 04_technical/ +│ ├── environment/ # 環境設定指南 +│ └── ... +``` + +### 檔案放置原則 +- **設定工具**: 放在 `sop/tools/environment/[環境名]/` +- **設定指南**: 放在 `docs/04_technical/environment/` +- **維護腳本**: 放在 `sop/scripts/` 或 `sop/scripts/maintenance/` +- **臨時檔案**: 使用 `temp/` 目錄(需要時創建) +- **歷史檔案**: 使用 `sop/archive/[日期]/` 目錄 +- **雜項檔案**: 使用 `misc/` 目錄(完全無法歸類的檔案) +- **禁止行為**: 直接在根目錄創建輔助檔案 + +### 無法歸類檔案處理流程 (新增 2025-09-08) +1. **功能性檢查**: 是否有明確功能分類? +2. **時效性檢查**: 是否為臨時性檔案? → `temp/` +3. **歷史性檢查**: 是否為歷史檔案? → `sop/archive/[日期]/` +4. **最終歸類**: 完全無法歸類 → `misc/` + +詳細策略請參考:`docs/04_technical/file-organization-strategy.md` + +## 🔍 品質檢查清單 + +### 🛡️ 每次操作前必檢(強制性SOP合規檢查) +**⚠️ 重要:任何操作前都必須執行此檢查清單** + +#### 問題管理操作前檢查 +- [ ] 是否需要記錄新問題?如是,**必須使用** `./dl issue` +- [ ] 完成的問題是否要標記?如是,**絕對不可在待處理區標記[x]** +- [ ] 完成的問題**必須移動到「📚 已完成歷史」對應日期區域** +- [ ] 移動時**必須保留所有解決詳情和連結** + +#### 報告建立操作前檢查 +- [ ] 是否需要建立報告?如是,**必須使用** `./dl report analysis "主題"` +- [ ] **使用系統工具建立報告** (`./dl report analysis "主題"`) +- [ ] 報告主題描述是否具體明確? + +#### 專案管理操作前檢查 (新增 2025-09-08) +- [ ] 專案任務是否需要更新狀態? +- [ ] 任務類型是否正確識別(FE/BE/AI/MB/DOC/ENV/TEST)? +- [ ] 是否需要建議下一步行動? + +#### 檔案操作前檢查 +- [ ] 檔案編碼是否設定為 UTF-8? +- [ ] 中文內容是否正確顯示? +- [ ] 是否使用正確的當前日期(2025-09-09)? +- [ ] **文檔更新是否需要加入時間戳記?** + +#### 文檔更新時間戳記要求 +**🕐 強制性日期標記原則**: +- [ ] 任何文檔內容更新都**必須**加入時間戳記 +- [ ] 格式:`(2025-09-09)` 或 `✅ (2025-09-09)` 或 `📊 **更新**: (2025-09-09)` +- [ ] 位置:緊接在更新內容後面 +- [ ] 檢查清單項目標記:`- [x] 項目名稱 ✅ (2025-09-09)` +- [ ] 進度狀態更新:`**狀態**: 已完成 (2025-09-09)` +- [ ] 新增章節:在章節標題或首行加入 `(新增 2025-09-09)` + +### 每次任務完成後檢查 +- [ ] 是否使用了正確的系統工具? +- [ ] 所有日期是否正確(2025-09-09)? +- [ ] 任務狀態是否已更新為完成 ✅ (專案任務) +- [ ] 發現的問題是否已記錄? +- [ ] 報告是否已正確整合到問題系統? +- [ ] 檔案命名是否符合系統標準? +- [ ] **ISSUES.md中完成的項目是否已正確移動到歷史區域?** +- [ ] **所有文檔更新是否都加入了時間戳記?** + +## 📝 任務完成後的檢查清單 (整合 2025-09-08) + +每次 Claude 完成任務後,請檢查: + +- [ ] Claude 有沒有提到任何「不確定」、「需要澄清」的地方? +- [ ] 有沒有發現文檔間的衝突? +- [ ] 有沒有提到技術實作的困難? +- [ ] 有沒有建議需要進一步決策的事項? + +**如果有,就提醒:** "把剛才提到的問題記錄到問題系統" + +## 🎯 協作流程範例 + +### 範例1:專案任務執行 (新增 2025-09-08) +``` +用戶: "請執行 Flutter移動端配置調整" +Claude: 識別為 MB 類型任務,更新狀態為進行中... + [執行配置調整] + ✅ 任務完成,狀態已更新 (2025-09-09) +``` + +### 範例2:統一任務管理 (更新 2025-09-09) +``` +用戶: "我想加入社交功能讓用戶互相挑戰,遇到問題就記錄" +Claude: 這個功能需要以下幾個部分... + [討論功能細節] + 我已經將以下任務記錄到統一任務管理系統: + - 🎨 FE 社交挑戰UI設計 (預估4-6小時) + - ⚙️ BE 挑戰系統API開發 (預估8-12小時) + - 📚 DOC 社交功能規格文檔 (預估2-3小時) + 你可以在 TASK_MANAGEMENT.md 查看詳細內容並安排執行時間 +``` + +### 範例3:問題發現和記錄 (更新 2025-09-09) +``` +用戶: "檢查API文檔一致性" +Claude: 我發現用戶管理API和認證API的錯誤碼定義衝突... + 已將此問題記錄到任務管理系統: + - ⚠️ BE API錯誤碼定義衝突 - 需要統一標準 ⏳ + 這是重要任務,建議本週內處理 +``` + +## 🚨 緊急情況處理 + +### 工具故障時 +1. 記錄工具故障情況到 ISSUES.md +2. 使用手動方式完成緊急任務 +3. 修正工具後重新使用標準流程 +4. 檢查並修正手動操作造成的不一致 + +### 系統不一致時 +1. 立即停止當前工作 +2. 運行 `./check_consistency.sh` +3. 記錄發現的不一致問題 +4. 修正問題後繼續工作 + +## 💡 讓協作更順暢的技巧 (整合 2025-09-08) + +### 🏷️ 在任務開始時就說明: +"我希望你把發現的所有問題都記錄下來,這樣我們就不會遺漏任何需要解決的事項。" + +### 🔄 定期檢查: +每週問 Claude:"最近有沒有發現什麼新的問題需要記錄?" + +### 📊 任務總結: +"總結一下這次任務中發現的問題,並確保都記錄了。" + +## 📚 相關文檔 + +- [統一任務管理](./TASK_MANAGEMENT.md) - 主要工作管理系統 +- [問題追蹤參考](./ISSUES.md) - 歷史問題記錄和流程說明 +- [專案狀態總覽](./PROJECTS.md) - 專案統計和里程碑追蹤 +- [工具使用說明](./sop/tools/) - 開發和維護工具 +- [歷史報告歸檔](./sop/archive/2025-09-09/225944_reports_archive/) - 過往分析和決策報告 +- [檢查腳本](./sop/scripts/) - 系統維護和檔案管理腳本 + +## 🔄 持續改善 + +### 發現新問題時 (更新 2025-09-09) +1. 立即記錄到 TASK_MANAGEMENT.md (主要) +2. 如需歷史追蹤,同步更新 ISSUES.md +3. 評估是否需要新工具或流程 +4. 更新本指南文檔 +5. 通知相關團隊成員 + +### 工具優化時 +1. 測試新工具的正確性 +2. 更新操作流程 +3. 修訂本指南文檔 +4. 確保向下相容性 + +## 🤝 標準化指令格式 + +### 推薦指令格式 +``` +[任務描述] + 請遵循SOP + [具體SOP要點提醒] +``` + +### 範例指令 +``` +請分析UI設計問題,遵循SOP,記得使用./dl report analysis建立報告 +請處理緊急問題,遵循SOP,完成後問題要移到歷史區域不可標記[x] +請建立新的API文檔,遵循SOP,使用正確日期和UTF-8編碼 +執行 Android Studio 安裝和配置,遇到問題就記錄 +``` + +## 🎉 效益 + +✅ **不會遺漏問題** - 所有發現的問題都被記錄 +✅ **追蹤更完整** - 包含 AI 協助時發現的問題 +✅ **決策有依據** - 問題記錄成為決策參考 +✅ **開發更順暢** - 提前發現潛在問題 +✅ **專案管理清晰** - 階段化執行,進度透明 (新增 2025-09-08) + +--- + +**重要提醒**: 本指南是 Claude AI 助手的強制性操作標準。任何偏離此流程的行為都可能造成系統不一致和品質問題。 + +**💫 記住:Claude 是您的協作夥伴,讓他幫您記錄問題和管理專案,讓開發更完善!** + +--- + +## 🔔 協作通知規範 (新增 2025-09-09) + +### 📢 任務完成通知 +- **完成任務後**: 必須使用 `say "I'm done"` 通知用戶 +- **適用情境**: 任何任務、分析、實作、整合工作完成後 +- **重要性**: 讓用戶知道可以查看結果或繼續下一步 + +### 🆘 求助通知 +- **核心原則**: 任何停止工作的情況,都必須立即使用 `say "help"` 通知用戶 +- **判斷標準**: "如果我現在不能自動繼續工作到完成,就必須 `say 'help'`" + +#### 🚨 強制觸發情況(更新 2025-09-09) + +**1. 系統權限請求** +- 任何 `Do you want to proceed?` 對話框 +- 需要用戶確認的系統提示 +- 文件覆寫確認 +- 命令執行權限請求 + +**2. 技術阻擋情況** +- 文件不存在但需要用戶指定路徑 +- 命令執行失敗需要用戶決策 +- 多個選項需要用戶選擇 +- 系統錯誤需要用戶介入 + +**3. 決策需求情況** +- 不確定要執行哪個選項 +- 需要用戶確認方向或方法 +- 發現衝突需要用戶裁決 +- 任何「應該如何處理」的疑問 + +**4. 工作流程中斷** +- 無法自動繼續下一步 +- 需要等待用戶輸入或回應 +- 遇到預期外的情況 + +#### 📋 執行方式 +``` +任何停頓 → 立即 say "help" → 說明需要什麼 → 等待回應 +``` + +**重要**: 這些通知習慣對協作體驗很重要,每次對話都必須遵循 + +--- + +**最後更新**: 2025-09-09 +**版本**: 3.2 - 修正結構性問題和三層架構整合 (2025-09-09) +**維護者**: Drama Ling 開發團隊 \ No newline at end of file diff --git a/sop/scripts/archive_file.sh b/sop/scripts/archive_file.sh new file mode 100755 index 0000000..47b6766 --- /dev/null +++ b/sop/scripts/archive_file.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# 簡化版文件歸檔腳本 +# 使用方法: ./archive_file.sh <文件路徑> <原因> + +if [ $# -lt 2 ]; then + echo "使用方法: $0 文件路徑 原因" + exit 1 +fi + +SOURCE_FILE="$1" +REASON="$2" +OPERATOR="${3:-Claude Code}" + +# 檢查文件是否存在 +if [ ! -f "$SOURCE_FILE" ]; then + echo "❌ 文件不存在: $SOURCE_FILE" + exit 1 +fi + +# 創建歸檔目錄 (使用相對路徑指向 sop/archive) +DATE_DIR=$(date '+%Y-%m-%d') +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ARCHIVE_DIR="$SCRIPT_DIR/../archive/$DATE_DIR" +LOG_DIR="$SCRIPT_DIR/../archive/logs" +mkdir -p "$ARCHIVE_DIR" +mkdir -p "$LOG_DIR" + +# 生成新文件名 (時間前綴) +FILENAME=$(basename "$SOURCE_FILE") +TIMESTAMP=$(date '+%H%M%S') +ARCHIVED_FILENAME="${TIMESTAMP}_${FILENAME}" +TARGET_FILE="$ARCHIVE_DIR/$ARCHIVED_FILENAME" + +# 移動文件 +mv "$SOURCE_FILE" "$TARGET_FILE" + +if [ $? -eq 0 ]; then + echo "✅ 歸檔成功: $SOURCE_FILE -> $TARGET_FILE" + + # 記錄日誌 + LOG_ENTRY="[$(date '+%Y-%m-%d %H:%M:%S')] ARCHIVE | $SOURCE_FILE -> $TARGET_FILE | $OPERATOR | $REASON" + echo "$LOG_ENTRY" >> "$LOG_DIR/file_migration.log" + echo "📋 日誌記錄: $LOG_ENTRY" +else + echo "❌ 歸檔失敗: $SOURCE_FILE" + exit 1 +fi \ No newline at end of file diff --git a/scripts/document-consistency-checklist.md b/sop/scripts/document-consistency-checklist.md similarity index 100% rename from scripts/document-consistency-checklist.md rename to sop/scripts/document-consistency-checklist.md diff --git a/sop/scripts/file_version_manager.sh b/sop/scripts/file_version_manager.sh new file mode 100755 index 0000000..80bd3d2 --- /dev/null +++ b/sop/scripts/file_version_manager.sh @@ -0,0 +1,174 @@ +#!/bin/bash + +# 文件版本管理 SOP 腳本 +# 用途: 安全處理文件更新時的舊版本歸檔 + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}"))" && pwd) +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +ARCHIVE_DIR="$PROJECT_ROOT/archive" +LOG_FILE="$PROJECT_ROOT/logs/file_migration.log" + +# 顏色定義 +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +RED='\033[0;31m' +NC='\033[0m' + +# 確保必要目錄存在 +setup_directories() { + mkdir -p "$PROJECT_ROOT/logs" + mkdir -p "$ARCHIVE_DIR" + + if [[ ! -f "$LOG_FILE" ]]; then + echo "# 文件遷移日誌" > "$LOG_FILE" + echo "# 格式: [日期時間] 操作類型 | 原文件 -> 目標位置 | 操作者 | 原因" >> "$LOG_FILE" + echo "" >> "$LOG_FILE" + fi +} + +# 記錄遷移日誌 +log_migration() { + local operation="$1" + local source_file="$2" + local target_file="$3" + local reason="$4" + local operator="${5:-Claude Code}" + + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + local log_entry="[$timestamp] $operation | $source_file -> $target_file | $operator | $reason" + + echo "$log_entry" >> "$LOG_FILE" + echo -e "${GREEN}📋 記錄遷移: ${NC}$log_entry" +} + +# 歸檔舊文件 +archive_file() { + local source_file="$1" + local reason="$2" + local operator="${3:-Claude Code}" + + if [[ ! -f "$source_file" ]]; then + echo -e "${RED}❌ 文件不存在: $source_file${NC}" + return 1 + fi + + # 生成歸檔目錄 (按日期) + local date_dir=$(date '+%Y-%m-%d') + local archive_date_dir="$ARCHIVE_DIR/$date_dir" + mkdir -p "$archive_date_dir" + + # 生成新文件名 (加上時間前綴) + local filename=$(basename "$source_file") + local timestamp=$(date '+%H%M%S') + local archived_filename="${timestamp}_${filename}" + local target_file="$archive_date_dir/$archived_filename" + + # 移動文件 + mv "$source_file" "$target_file" + + if [[ $? -eq 0 ]]; then + echo -e "${BLUE}📦 歸檔成功: ${NC}$source_file -> $target_file" + log_migration "ARCHIVE" "$source_file" "$target_file" "$reason" "$operator" + return 0 + else + echo -e "${RED}❌ 歸檔失敗: $source_file${NC}" + return 1 + fi +} + +# 安全替換文件 (先歸檔舊版本) +safe_replace() { + local old_file="$1" + local new_file="$2" + local reason="$3" + local operator="${4:-Claude Code}" + + if [[ ! -f "$new_file" ]]; then + echo -e "${RED}❌ 新文件不存在: $new_file${NC}" + return 1 + fi + + if [[ -f "$old_file" ]]; then + # 先歸檔舊文件 + archive_file "$old_file" "$reason" "$operator" + if [[ $? -ne 0 ]]; then + echo -e "${RED}❌ 無法歸檔舊文件,中止替換${NC}" + return 1 + fi + fi + + # 移動新文件到目標位置 + mv "$new_file" "$old_file" + + if [[ $? -eq 0 ]]; then + echo -e "${GREEN}✅ 安全替換完成: ${NC}$old_file" + log_migration "REPLACE" "$new_file" "$old_file" "$reason" "$operator" + return 0 + else + echo -e "${RED}❌ 替換失敗${NC}" + return 1 + fi +} + +# 查看遷移日誌 +view_log() { + if [[ -f "$LOG_FILE" ]]; then + echo -e "${BLUE}📋 文件遷移日誌:${NC}" + cat "$LOG_FILE" + else + echo -e "${YELLOW}⚠️ 尚無遷移日誌${NC}" + fi +} + +# 列出歸檔文件 +list_archives() { + if [[ -d "$ARCHIVE_DIR" ]]; then + echo -e "${BLUE}📦 歸檔文件列表:${NC}" + find "$ARCHIVE_DIR" -type f -exec ls -la {} \; | sort + else + echo -e "${YELLOW}⚠️ 尚無歸檔文件${NC}" + fi +} + +# 主函數 +main() { + setup_directories + + case "$1" in + "archive") + if [[ $# -lt 3 ]]; then + echo -e "${RED}使用方法: $0 archive 文件路徑 原因 [操作者]${NC}" + exit 1 + fi + archive_file "$2" "$3" "$4" + ;; + "replace") + if [[ $# -lt 4 ]]; then + echo -e "${RED}使用方法: $0 replace 舊文件 新文件 原因 [操作者]${NC}" + exit 1 + fi + safe_replace "$2" "$3" "$4" "$5" + ;; + "log") + view_log + ;; + "list") + list_archives + ;; + *) + echo -e "${BLUE}🗃️ 文件版本管理工具${NC}" + echo "用法:" + echo " $0 archive 文件路徑 原因 [操作者] # 歸檔文件" + echo " $0 replace 舊文件 新文件 原因 [操作者] # 安全替換文件" + echo " $0 log # 查看遷移日誌" + echo " $0 list # 列出歸檔文件" + echo "" + echo "範例:" + echo " $0 archive TASK_MANAGEMENT_OLD.md \"系統重構\" \"Claude Code\"" + echo " $0 replace old.md new.md \"功能更新\" \"開發者\"" + ;; + esac +} + +main "$@" \ No newline at end of file diff --git a/scripts/maintenance/check_consistency.sh b/sop/scripts/maintenance/check_consistency.sh similarity index 100% rename from scripts/maintenance/check_consistency.sh rename to sop/scripts/maintenance/check_consistency.sh diff --git a/scripts/maintenance/check_doc_quality.sh b/sop/scripts/maintenance/check_doc_quality.sh similarity index 100% rename from scripts/maintenance/check_doc_quality.sh rename to sop/scripts/maintenance/check_doc_quality.sh diff --git a/scripts/maintenance/check_issues.sh b/sop/scripts/maintenance/check_issues.sh similarity index 100% rename from scripts/maintenance/check_issues.sh rename to sop/scripts/maintenance/check_issues.sh diff --git a/scripts/maintenance/check_security.sh b/sop/scripts/maintenance/check_security.sh similarity index 100% rename from scripts/maintenance/check_security.sh rename to sop/scripts/maintenance/check_security.sh diff --git a/scripts/maintenance/create_issue.sh b/sop/scripts/maintenance/create_issue.sh similarity index 100% rename from scripts/maintenance/create_issue.sh rename to sop/scripts/maintenance/create_issue.sh diff --git a/scripts/maintenance_manager.sh b/sop/scripts/maintenance_manager.sh similarity index 100% rename from scripts/maintenance_manager.sh rename to sop/scripts/maintenance_manager.sh diff --git a/scripts/reports/issues_20250908_003117.txt b/sop/scripts/reports/issues_20250908_003117.txt similarity index 100% rename from scripts/reports/issues_20250908_003117.txt rename to sop/scripts/reports/issues_20250908_003117.txt diff --git a/sop/scripts/view_archives.sh b/sop/scripts/view_archives.sh new file mode 100755 index 0000000..5c9d71b --- /dev/null +++ b/sop/scripts/view_archives.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# 查看歸檔文件和日誌的快速工具 + +echo "🗃️ 文件歸檔系統狀態" +echo "==========================" + +# 設定相對路徑指向 sop/archive +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ARCHIVE_BASE="$SCRIPT_DIR/../archive" + +# 查看今日歸檔 +TODAY=$(date '+%Y-%m-%d') +if [[ -d "$ARCHIVE_BASE/$TODAY" ]]; then + echo -e "\n📦 今日歸檔文件 ($TODAY):" + ls -la "$ARCHIVE_BASE/$TODAY/" +else + echo -e "\n📦 今日無歸檔文件" +fi + +# 查看所有歸檔目錄 +echo -e "\n📅 歷史歸檔目錄:" +if [[ -d "$ARCHIVE_BASE" ]]; then + ls -la "$ARCHIVE_BASE/" +else + echo "無歷史歸檔" +fi + +# 查看遷移日誌 +echo -e "\n📋 文件遷移日誌:" +if [[ -f "$ARCHIVE_BASE/logs/file_migration.log" ]]; then + cat "$ARCHIVE_BASE/logs/file_migration.log" +else + echo "尚無遷移日誌" +fi + +# 統計資訊 +echo -e "\n📊 歸檔統計:" +TOTAL_FILES=$(find "$ARCHIVE_BASE/" -type f 2>/dev/null | wc -l) +echo "總歸檔文件數: $TOTAL_FILES" + +TOTAL_DIRS=$(find "$ARCHIVE_BASE/" -type d -mindepth 1 2>/dev/null | wc -l) +echo "歸檔日期數: $TOTAL_DIRS" \ No newline at end of file diff --git a/tools/check_compliance.sh b/sop/tools/check_compliance.sh similarity index 100% rename from tools/check_compliance.sh rename to sop/tools/check_compliance.sh diff --git a/tools/check_issues.sh b/sop/tools/check_issues.sh similarity index 100% rename from tools/check_issues.sh rename to sop/tools/check_issues.sh diff --git a/tools/check_reports.sh b/sop/tools/check_reports.sh similarity index 100% rename from tools/check_reports.sh rename to sop/tools/check_reports.sh diff --git a/tools/create_report.sh b/sop/tools/create_report.sh similarity index 100% rename from tools/create_report.sh rename to sop/tools/create_report.sh diff --git a/tools/environment/android/android_setup_verification.sh b/sop/tools/environment/android/android_setup_verification.sh similarity index 100% rename from tools/environment/android/android_setup_verification.sh rename to sop/tools/environment/android/android_setup_verification.sh diff --git a/tools/environment/android/emulator_setup_guide.md b/sop/tools/environment/android/emulator_setup_guide.md similarity index 100% rename from tools/environment/android/emulator_setup_guide.md rename to sop/tools/environment/android/emulator_setup_guide.md diff --git a/tools/environment/android/manual_sdk_setup.sh b/sop/tools/environment/android/manual_sdk_setup.sh similarity index 100% rename from tools/environment/android/manual_sdk_setup.sh rename to sop/tools/environment/android/manual_sdk_setup.sh diff --git a/tools/environment/xcode/complete_xcode_setup.sh b/sop/tools/environment/xcode/complete_xcode_setup.sh similarity index 100% rename from tools/environment/xcode/complete_xcode_setup.sh rename to sop/tools/environment/xcode/complete_xcode_setup.sh diff --git a/tools/environment/xcode/monitor_xcode_installation.sh b/sop/tools/environment/xcode/monitor_xcode_installation.sh similarity index 100% rename from tools/environment/xcode/monitor_xcode_installation.sh rename to sop/tools/environment/xcode/monitor_xcode_installation.sh diff --git a/tools/environment/xcode/setup_instructions.md b/sop/tools/environment/xcode/setup_instructions.md similarity index 100% rename from tools/environment/xcode/setup_instructions.md rename to sop/tools/environment/xcode/setup_instructions.md diff --git a/tools/environment/xcode/xcode_verification.sh b/sop/tools/environment/xcode/xcode_verification.sh similarity index 100% rename from tools/environment/xcode/xcode_verification.sh rename to sop/tools/environment/xcode/xcode_verification.sh diff --git a/tools/issue.sh b/sop/tools/issue.sh similarity index 100% rename from tools/issue.sh rename to sop/tools/issue.sh diff --git a/tools/organize_file.sh b/sop/tools/organize_file.sh similarity index 100% rename from tools/organize_file.sh rename to sop/tools/organize_file.sh diff --git a/tools/phase.sh b/sop/tools/phase.sh similarity index 100% rename from tools/phase.sh rename to sop/tools/phase.sh diff --git a/tools/project.sh b/sop/tools/project.sh similarity index 100% rename from tools/project.sh rename to sop/tools/project.sh diff --git a/tools/setup_aliases.sh b/sop/tools/setup_aliases.sh similarity index 100% rename from tools/setup_aliases.sh rename to sop/tools/setup_aliases.sh diff --git a/src/mobile/README.md b/src/mobile/README.md deleted file mode 100644 index 186d07c..0000000 --- a/src/mobile/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# dramaling - -A new Flutter project. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference.