From 1e6c4bf7fc7eae2339635384f5e3f4f5d78d94b4 Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Wed, 15 Oct 2025 10:46:50 +0000 Subject: [PATCH] chore: initial commit --- test-apps/.gitignore | 127 + test-apps/EMULATOR_TROUBLESHOOTING.md | 280 - test-apps/README.md | 326 -- test-apps/SETUP_GUIDE.md | 384 -- test-apps/android-test/.eslintrc.cjs | 20 - test-apps/android-test/.gitignore | 105 - .../android-test/GRADLE_TROUBLESHOOTING.md | 160 - test-apps/android-test/README.md | 329 -- test-apps/android-test/capacitor.config.ts | 25 - test-apps/android-test/env.d.ts | 90 - test-apps/android-test/index.html | 73 - test-apps/android-test/package.json | 42 - test-apps/android-test/src/App.vue | 147 - .../src/components/cards/ActionCard.vue | 163 - .../src/components/cards/InfoCard.vue | 95 - .../src/components/cards/NotificationCard.vue | 181 - .../src/components/cards/StatusCard.vue | 264 - .../src/components/items/ActivityItem.vue | 141 - .../src/components/items/HistoryItem.vue | 170 - .../src/components/items/StatusItem.vue | 99 - .../src/components/layout/AppFooter.vue | 75 - .../src/components/layout/AppHeader.vue | 239 - test-apps/android-test/src/main.ts | 42 - test-apps/android-test/src/router/index.ts | 109 - .../android-test/src/stores/notifications.ts | 299 - .../android-test/src/views/HistoryView.vue | 144 - test-apps/android-test/src/views/HomeView.vue | 260 - test-apps/android-test/src/views/LogsView.vue | 629 --- .../android-test/src/views/NotFoundView.vue | 117 - .../src/views/NotificationsView.vue | 179 - .../android-test/src/views/ScheduleView.vue | 518 -- .../android-test/src/views/StatusView.vue | 310 -- test-apps/android-test/tsconfig.json | 45 - test-apps/android-test/vite.config.ts | 70 - test-apps/android-test/webpack.config.js | 33 - test-apps/check-environment.sh | 112 - test-apps/config/timesafari-config.json | 152 - .../daily-notification-test/.editorconfig | 8 + .../daily-notification-test/.gitattributes | 1 + test-apps/daily-notification-test/.gitignore | 30 + test-apps/daily-notification-test/README.md | 48 + .../android/.gitignore | 101 + .../android/app/.gitignore | 2 + .../android/app/build.gradle | 54 + .../android/app/capacitor.build.gradle | 19 + .../android/app/proguard-rules.pro | 21 + .../myapp/ExampleInstrumentedTest.java | 26 + .../android/app/src/main/AndroidManifest.xml | 73 + .../dailynotification/test/MainActivity.java | 5 + .../main/res/drawable-land-hdpi/splash.png | Bin 0 -> 7705 bytes .../main/res/drawable-land-mdpi/splash.png | Bin 0 -> 4040 bytes .../main/res/drawable-land-xhdpi/splash.png | Bin 0 -> 9251 bytes .../main/res/drawable-land-xxhdpi/splash.png | Bin 0 -> 13984 bytes .../main/res/drawable-land-xxxhdpi/splash.png | Bin 0 -> 17683 bytes .../main/res/drawable-port-hdpi/splash.png | Bin 0 -> 7934 bytes .../main/res/drawable-port-mdpi/splash.png | Bin 0 -> 4096 bytes .../main/res/drawable-port-xhdpi/splash.png | Bin 0 -> 9875 bytes .../main/res/drawable-port-xxhdpi/splash.png | Bin 0 -> 13346 bytes .../main/res/drawable-port-xxxhdpi/splash.png | Bin 0 -> 17489 bytes .../drawable-v24/ic_launcher_foreground.xml | 34 + .../res/drawable/ic_launcher_background.xml | 170 + .../app/src/main/res/drawable/splash.png | Bin 0 -> 4040 bytes .../app/src/main/res/layout/activity_main.xml | 12 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2786 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 3450 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4341 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1869 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 2110 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2725 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 3981 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 5036 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6593 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6644 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 9793 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10455 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9441 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 15529 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15916 bytes .../res/values/ic_launcher_background.xml | 4 + .../app/src/main/res/values/strings.xml | 7 + .../app/src/main/res/values/styles.xml | 22 + .../app/src/main/res/xml/file_paths.xml | 5 + .../getcapacitor/myapp/ExampleUnitTest.java | 18 + .../android/build.gradle | 29 + .../android/capacitor.settings.gradle | 3 + .../android/gradle.properties | 22 + .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + .../daily-notification-test/android/gradlew | 252 + .../android/gradlew.bat | 94 + .../android/settings.gradle | 5 + .../android/variables.gradle | 16 + .../capacitor.config.ts | 14 + test-apps/daily-notification-test/env.d.ts | 1 + .../daily-notification-test/eslint.config.ts | 20 + test-apps/daily-notification-test/index.html | 13 + .../package-lock.json | 3997 +++++++++----- .../daily-notification-test/package.json | 42 + .../public/favicon.ico | Bin 0 -> 4286 bytes test-apps/daily-notification-test/src/App.vue | 125 + .../src/assets/base.css | 86 + .../src/assets/logo.svg | 1 + .../src/assets/main.css | 35 + .../src/components/HelloWorld.vue | 41 + .../src/components/TheWelcome.vue | 94 + .../src/components/WelcomeItem.vue | 87 + .../src/components/cards/ActionCard.vue | 141 + .../src/components/cards/StatusCard.vue | 202 + .../src/components/icons/IconCommunity.vue | 7 + .../components/icons/IconDocumentation.vue | 7 + .../src/components/icons/IconEcosystem.vue | 7 + .../src/components/icons/IconSupport.vue | 7 + .../src/components/icons/IconTooling.vue | 19 + .../src/components/layout/AppFooter.vue | 113 + .../src/components/layout/AppHeader.vue | 270 + .../src/components/ui/ErrorDialog.vue | 114 +- .../src/components/ui/LoadingOverlay.vue | 35 +- test-apps/daily-notification-test/src/main.ts | 14 + .../src/router/index.ts | 109 + .../src/stores/app.ts | 1 + .../src/stores/counter.ts | 12 + .../src/views/AboutView.vue | 15 + .../src/views/HistoryView.vue | 54 + .../src/views/HomeView.vue | 332 ++ .../src/views/LogsView.vue | 475 ++ .../src/views/NotFoundView.vue | 70 + .../src/views/NotificationsView.vue | 54 + .../src/views/ScheduleView.vue | 180 + .../src/views/SettingsView.vue | 43 +- .../src/views/StatusView.vue | 54 + .../daily-notification-test/tsconfig.app.json | 14 + .../daily-notification-test/tsconfig.json | 11 + .../tsconfig.node.json | 19 + .../daily-notification-test/vite.config.ts | 18 + test-apps/electron-test/.gitignore | 114 - test-apps/electron-test/main.js | 117 - test-apps/electron-test/package.json | 28 - test-apps/electron-test/preload.js | 10 - test-apps/electron-test/src/index.html | 476 -- test-apps/electron-test/src/index.ts | 1085 ---- test-apps/electron-test/tsconfig.json | 15 - test-apps/electron-test/webpack.config.js | 28 - test-apps/ios-test/.gitignore | 105 - test-apps/ios-test/capacitor.config.ts | 25 - test-apps/ios-test/package.json | 29 - test-apps/ios-test/src/index.html | 476 -- test-apps/ios-test/src/index.ts | 1340 ----- test-apps/ios-test/tsconfig.json | 15 - test-apps/ios-test/webpack.config.js | 33 - test-apps/launch-emulator-angle.sh | 58 - test-apps/launch-emulator-gpu.sh | 85 - test-apps/launch-emulator-help.sh | 106 - test-apps/launch-emulator-max-performance.sh | 77 - test-apps/launch-emulator-mesa.sh | 53 - test-apps/launch-emulator-network-fix.sh | 62 - test-apps/launch-emulator-opengl.sh | 57 - test-apps/setup-android.sh | 123 - test-apps/setup-electron.sh | 56 - test-apps/setup-ios.sh | 101 - test-apps/shared/config-loader.ts | 552 -- .../shared/typescript/EndorserAPIClient.ts | 659 --- .../shared/typescript/SecurityManager.ts | 554 -- .../TimeSafariNotificationManager.ts | 640 --- test-apps/test-api/.gitignore | 152 - test-apps/test-api/README.md | 282 - test-apps/test-api/SETUP.md | 76 - test-apps/test-api/client.ts | 305 -- test-apps/test-api/package-lock.json | 4799 ----------------- test-apps/test-api/package.json | 33 - test-apps/test-api/server.js | 535 -- test-apps/test-api/test-demo.js | 294 - test-apps/verify-emulator-network.sh | 107 - 174 files changed, 6865 insertions(+), 21402 deletions(-) create mode 100644 test-apps/.gitignore delete mode 100644 test-apps/EMULATOR_TROUBLESHOOTING.md delete mode 100644 test-apps/README.md delete mode 100644 test-apps/SETUP_GUIDE.md delete mode 100644 test-apps/android-test/.eslintrc.cjs delete mode 100644 test-apps/android-test/.gitignore delete mode 100644 test-apps/android-test/GRADLE_TROUBLESHOOTING.md delete mode 100644 test-apps/android-test/README.md delete mode 100644 test-apps/android-test/capacitor.config.ts delete mode 100644 test-apps/android-test/env.d.ts delete mode 100644 test-apps/android-test/index.html delete mode 100644 test-apps/android-test/package.json delete mode 100644 test-apps/android-test/src/App.vue delete mode 100644 test-apps/android-test/src/components/cards/ActionCard.vue delete mode 100644 test-apps/android-test/src/components/cards/InfoCard.vue delete mode 100644 test-apps/android-test/src/components/cards/NotificationCard.vue delete mode 100644 test-apps/android-test/src/components/cards/StatusCard.vue delete mode 100644 test-apps/android-test/src/components/items/ActivityItem.vue delete mode 100644 test-apps/android-test/src/components/items/HistoryItem.vue delete mode 100644 test-apps/android-test/src/components/items/StatusItem.vue delete mode 100644 test-apps/android-test/src/components/layout/AppFooter.vue delete mode 100644 test-apps/android-test/src/components/layout/AppHeader.vue delete mode 100644 test-apps/android-test/src/main.ts delete mode 100644 test-apps/android-test/src/router/index.ts delete mode 100644 test-apps/android-test/src/stores/notifications.ts delete mode 100644 test-apps/android-test/src/views/HistoryView.vue delete mode 100644 test-apps/android-test/src/views/HomeView.vue delete mode 100644 test-apps/android-test/src/views/LogsView.vue delete mode 100644 test-apps/android-test/src/views/NotFoundView.vue delete mode 100644 test-apps/android-test/src/views/NotificationsView.vue delete mode 100644 test-apps/android-test/src/views/ScheduleView.vue delete mode 100644 test-apps/android-test/src/views/StatusView.vue delete mode 100644 test-apps/android-test/tsconfig.json delete mode 100644 test-apps/android-test/vite.config.ts delete mode 100644 test-apps/android-test/webpack.config.js delete mode 100755 test-apps/check-environment.sh delete mode 100644 test-apps/config/timesafari-config.json create mode 100644 test-apps/daily-notification-test/.editorconfig create mode 100644 test-apps/daily-notification-test/.gitattributes create mode 100644 test-apps/daily-notification-test/.gitignore create mode 100644 test-apps/daily-notification-test/README.md create mode 100644 test-apps/daily-notification-test/android/.gitignore create mode 100644 test-apps/daily-notification-test/android/app/.gitignore create mode 100644 test-apps/daily-notification-test/android/app/build.gradle create mode 100644 test-apps/daily-notification-test/android/app/capacitor.build.gradle create mode 100644 test-apps/daily-notification-test/android/app/proguard-rules.pro create mode 100644 test-apps/daily-notification-test/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java create mode 100644 test-apps/daily-notification-test/android/app/src/main/AndroidManifest.xml create mode 100644 test-apps/daily-notification-test/android/app/src/main/java/com/timesafari/dailynotification/test/MainActivity.java create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/drawable-land-hdpi/splash.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/drawable-land-mdpi/splash.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/drawable-land-xhdpi/splash.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/drawable-land-xxhdpi/splash.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/drawable-land-xxxhdpi/splash.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/drawable-port-hdpi/splash.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/drawable-port-mdpi/splash.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/drawable-port-xhdpi/splash.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/drawable-port-xxhdpi/splash.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/drawable-port-xxxhdpi/splash.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/drawable/splash.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/layout/activity_main.xml create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/values/ic_launcher_background.xml create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/values/strings.xml create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/values/styles.xml create mode 100644 test-apps/daily-notification-test/android/app/src/main/res/xml/file_paths.xml create mode 100644 test-apps/daily-notification-test/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java create mode 100644 test-apps/daily-notification-test/android/build.gradle create mode 100644 test-apps/daily-notification-test/android/capacitor.settings.gradle create mode 100644 test-apps/daily-notification-test/android/gradle.properties create mode 100644 test-apps/daily-notification-test/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 test-apps/daily-notification-test/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 test-apps/daily-notification-test/android/gradlew create mode 100644 test-apps/daily-notification-test/android/gradlew.bat create mode 100644 test-apps/daily-notification-test/android/settings.gradle create mode 100644 test-apps/daily-notification-test/android/variables.gradle create mode 100644 test-apps/daily-notification-test/capacitor.config.ts create mode 100644 test-apps/daily-notification-test/env.d.ts create mode 100644 test-apps/daily-notification-test/eslint.config.ts create mode 100644 test-apps/daily-notification-test/index.html rename test-apps/{android-test => daily-notification-test}/package-lock.json (56%) create mode 100644 test-apps/daily-notification-test/package.json create mode 100644 test-apps/daily-notification-test/public/favicon.ico create mode 100644 test-apps/daily-notification-test/src/App.vue create mode 100644 test-apps/daily-notification-test/src/assets/base.css create mode 100644 test-apps/daily-notification-test/src/assets/logo.svg create mode 100644 test-apps/daily-notification-test/src/assets/main.css create mode 100644 test-apps/daily-notification-test/src/components/HelloWorld.vue create mode 100644 test-apps/daily-notification-test/src/components/TheWelcome.vue create mode 100644 test-apps/daily-notification-test/src/components/WelcomeItem.vue create mode 100644 test-apps/daily-notification-test/src/components/cards/ActionCard.vue create mode 100644 test-apps/daily-notification-test/src/components/cards/StatusCard.vue create mode 100644 test-apps/daily-notification-test/src/components/icons/IconCommunity.vue create mode 100644 test-apps/daily-notification-test/src/components/icons/IconDocumentation.vue create mode 100644 test-apps/daily-notification-test/src/components/icons/IconEcosystem.vue create mode 100644 test-apps/daily-notification-test/src/components/icons/IconSupport.vue create mode 100644 test-apps/daily-notification-test/src/components/icons/IconTooling.vue create mode 100644 test-apps/daily-notification-test/src/components/layout/AppFooter.vue create mode 100644 test-apps/daily-notification-test/src/components/layout/AppHeader.vue rename test-apps/{android-test => daily-notification-test}/src/components/ui/ErrorDialog.vue (54%) rename test-apps/{android-test => daily-notification-test}/src/components/ui/LoadingOverlay.vue (57%) create mode 100644 test-apps/daily-notification-test/src/main.ts create mode 100644 test-apps/daily-notification-test/src/router/index.ts rename test-apps/{android-test => daily-notification-test}/src/stores/app.ts (97%) create mode 100644 test-apps/daily-notification-test/src/stores/counter.ts create mode 100644 test-apps/daily-notification-test/src/views/AboutView.vue create mode 100644 test-apps/daily-notification-test/src/views/HistoryView.vue create mode 100644 test-apps/daily-notification-test/src/views/HomeView.vue create mode 100644 test-apps/daily-notification-test/src/views/LogsView.vue create mode 100644 test-apps/daily-notification-test/src/views/NotFoundView.vue create mode 100644 test-apps/daily-notification-test/src/views/NotificationsView.vue create mode 100644 test-apps/daily-notification-test/src/views/ScheduleView.vue rename test-apps/{android-test => daily-notification-test}/src/views/SettingsView.vue (62%) create mode 100644 test-apps/daily-notification-test/src/views/StatusView.vue create mode 100644 test-apps/daily-notification-test/tsconfig.app.json create mode 100644 test-apps/daily-notification-test/tsconfig.json create mode 100644 test-apps/daily-notification-test/tsconfig.node.json create mode 100644 test-apps/daily-notification-test/vite.config.ts delete mode 100644 test-apps/electron-test/.gitignore delete mode 100644 test-apps/electron-test/main.js delete mode 100644 test-apps/electron-test/package.json delete mode 100644 test-apps/electron-test/preload.js delete mode 100644 test-apps/electron-test/src/index.html delete mode 100644 test-apps/electron-test/src/index.ts delete mode 100644 test-apps/electron-test/tsconfig.json delete mode 100644 test-apps/electron-test/webpack.config.js delete mode 100644 test-apps/ios-test/.gitignore delete mode 100644 test-apps/ios-test/capacitor.config.ts delete mode 100644 test-apps/ios-test/package.json delete mode 100644 test-apps/ios-test/src/index.html delete mode 100644 test-apps/ios-test/src/index.ts delete mode 100644 test-apps/ios-test/tsconfig.json delete mode 100644 test-apps/ios-test/webpack.config.js delete mode 100755 test-apps/launch-emulator-angle.sh delete mode 100755 test-apps/launch-emulator-gpu.sh delete mode 100755 test-apps/launch-emulator-help.sh delete mode 100755 test-apps/launch-emulator-max-performance.sh delete mode 100755 test-apps/launch-emulator-mesa.sh delete mode 100755 test-apps/launch-emulator-network-fix.sh delete mode 100755 test-apps/launch-emulator-opengl.sh delete mode 100755 test-apps/setup-android.sh delete mode 100755 test-apps/setup-electron.sh delete mode 100755 test-apps/setup-ios.sh delete mode 100644 test-apps/shared/config-loader.ts delete mode 100644 test-apps/shared/typescript/EndorserAPIClient.ts delete mode 100644 test-apps/shared/typescript/SecurityManager.ts delete mode 100644 test-apps/shared/typescript/TimeSafariNotificationManager.ts delete mode 100644 test-apps/test-api/.gitignore delete mode 100644 test-apps/test-api/README.md delete mode 100644 test-apps/test-api/SETUP.md delete mode 100644 test-apps/test-api/client.ts delete mode 100644 test-apps/test-api/package-lock.json delete mode 100644 test-apps/test-api/package.json delete mode 100644 test-apps/test-api/server.js delete mode 100644 test-apps/test-api/test-demo.js delete mode 100755 test-apps/verify-emulator-network.sh diff --git a/test-apps/.gitignore b/test-apps/.gitignore new file mode 100644 index 0000000..34c104c --- /dev/null +++ b/test-apps/.gitignore @@ -0,0 +1,127 @@ +# Dependencies +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +# Build outputs +dist/ +build/ +*.tsbuildinfo + +# Environment files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Logs +logs/ +*.log + +# Runtime data +pids/ +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage/ +*.lcov + +# nyc test coverage +.nyc_output/ + +# Dependency directories +jspm_packages/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt + +# Storybook build outputs +.out +.storybook-out + +# Temporary folders +tmp/ +temp/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# Capacitor specific +android/app/build/ +android/build/ +android/.gradle/ +android/gradle/ +android/gradlew +android/gradlew.bat +android/local.properties +android/capacitor.settings.gradle +android/variables.gradle + +# iOS specific (for future use) +ios/App/build/ +ios/App/Pods/ +ios/App/public/ +ios/App/capacitor.config.json +ios/App/capacitor.plugins.json + +# Electron specific (for future use) +electron/dist/ +electron/build/ + +# Test coverage +coverage/ + +# Misc +*.tgz +*.tar.gz diff --git a/test-apps/EMULATOR_TROUBLESHOOTING.md b/test-apps/EMULATOR_TROUBLESHOOTING.md deleted file mode 100644 index d410cba..0000000 --- a/test-apps/EMULATOR_TROUBLESHOOTING.md +++ /dev/null @@ -1,280 +0,0 @@ -# Android Emulator GPU Troubleshooting Guide - -## Overview - -This guide helps resolve GPU binding issues when running Android emulators on Linux systems with NVIDIA graphics cards. The most common issue is when the emulator detects the NVIDIA GPU for Vulkan but still binds OpenGL rendering to the Intel iGPU. - -## Problem Diagnosis - -### GPU Binding Issues - -#### Symptoms -- Emulator runs but feels sluggish -- NVIDIA GPU shows low utilization in `nvidia-smi` -- Emulator banner shows Intel graphics in OpenGL renderer: - ``` - OpenGL Renderer=[Android Emulator OpenGL ES Translator (Mesa Intel(R) Graphics (RPL-S))] - ``` -- Vulkan detection works but OpenGL compositing uses Intel - -#### Root Cause -The emulator detects your NVIDIA GPU for Vulkan (`Selecting Vulkan device: NVIDIA GeForce RTX 4060...`) but the window/compositor path still binds to your Intel iGPU. Frames get decoded via gfxstream/Vulkan but final GL presentation rides the Intel driver. - -### Network Connectivity Issues - -#### Symptoms -- Play Services ANRs and timeouts -- "API failed to connect while resuming" errors -- `GmsClientSupervisor ... Timeout...` messages -- `Phenotype registration failed` errors -- NetworkMonitor shows hard failures: - - `ECONNREFUSED` on DNS lookups - - `UnknownHostException` for `www.google.com` / `connectivitycheck.gstatic.com` - - `[100 WIFI] validation failed` - -#### Root Cause -The emulator has no working internet/DNS connectivity, causing Google apps to stall and ANR. This is often caused by: -- DNS resolution failures -- VPN/killswitch blocking emulator traffic -- Firewall rules blocking outbound connections -- Corrupted network state from previous sessions - -## Solution Strategies - -### 1. Network Connectivity Fixes (Priority) - -If experiencing ANRs and Play Services failures, address network issues first: - -#### Quick Network Fix -```bash -cd test-apps -./launch-emulator-network-fix.sh -``` - -#### Verify Network Status -```bash -cd test-apps -./verify-emulator-network.sh -``` - -#### Manual Network Verification -```bash -# Check airplane mode -adb -e shell settings get global airplane_mode_on - -# Check network interfaces -adb -e shell ip addr; adb -e shell ip route - -# Test DNS resolution -adb -e shell ping -c1 8.8.8.8 -adb -e shell ping -c1 connectivitycheck.gstatic.com -``` - -#### Clear Play Services Cache -```bash -adb -e shell pm clear com.google.android.gms -adb -e shell pm clear com.android.vending -``` - -### 2. GPU Binding Solutions - -Use the enhanced launch script with all NVIDIA offloading variables: - -```bash -cd test-apps -./launch-emulator-gpu.sh -``` - -**What each variable does:** -- `__NV_PRIME_RENDER_OFFLOAD=1` + `__GLX_VENDOR_LIBRARY_NAME=nvidia`: Offload GL to NVIDIA -- `__VK_LAYER_NV_optimus=NVIDIA_only` + `VK_ICD_FILENAMES=...nvidia_icd.json`: Make Vulkan loader pick NVIDIA -- `DRI_PRIME=1`: Belt-and-suspenders in mixed Mesa/NVIDIA setups -- `QT_QPA_PLATFORM=xcb`: Avoids Wayland/Qt oddities -- `-no-snapshot-load`: Prevents flaky snapshots from different configs - -### 2. Alternative GPU Modes - -If the primary solution still binds to Intel, try these alternatives: - -#### Pure OpenGL Mode -```bash -cd test-apps -./launch-emulator-opengl.sh -``` -- Removes `-feature Vulkan` to avoid mixed VK+GL path -- Forces pure OpenGL rendering on NVIDIA -- Good when Vulkan+OpenGL mixed mode causes issues - -#### ANGLE Mode -```bash -cd test-apps -./launch-emulator-angle.sh -``` -- Uses ANGLE (Almost Native Graphics Layer Engine) -- Better NVIDIA compatibility on Linux -- More stable rendering pipeline - -#### Mesa Fallback -```bash -cd test-apps -./launch-emulator-mesa.sh -``` -- Software rendering as last resort -- Use only for stability testing -- More CPU intensive but very stable - -### 3. Manual Launch Commands - -If scripts don't work, use these manual commands: - -#### Enhanced GPU Launch -```bash -QT_QPA_PLATFORM=xcb \ -__NV_PRIME_RENDER_OFFLOAD=1 \ -__GLX_VENDOR_LIBRARY_NAME=nvidia \ -__VK_LAYER_NV_optimus=NVIDIA_only \ -VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json \ -DRI_PRIME=1 \ -emulator -avd TimeSafari_Emulator \ - -gpu host \ - -feature Vulkan \ - -accel on \ - -no-boot-anim \ - -no-snapshot-load -``` - -#### Pure OpenGL -```bash -QT_QPA_PLATFORM=xcb \ -__NV_PRIME_RENDER_OFFLOAD=1 \ -__GLX_VENDOR_LIBRARY_NAME=nvidia \ -DRI_PRIME=1 \ -emulator -avd TimeSafari_Emulator \ - -gpu host \ - -accel on \ - -no-boot-anim -``` - -#### ANGLE Mode -```bash -QT_QPA_PLATFORM=xcb \ -__NV_PRIME_RENDER_OFFLOAD=1 \ -__GLX_VENDOR_LIBRARY_NAME=nvidia \ -DRI_PRIME=1 \ -emulator -avd TimeSafari_Emulator \ - -gpu angle_indirect \ - -accel on \ - -no-boot-anim -``` - -## Verification - -### Check GPU Binding -After launching, check the emulator banner for: -- ✅ **Good**: `OpenGL Vendor=Google (NVIDIA)` or GL translator running atop NVIDIA -- ❌ **Bad**: `(Mesa Intel)` or Intel graphics in renderer - -### Monitor GPU Usage -```bash -# Real-time GPU utilization -nvidia-smi dmon -s u - -# Check emulator process specifically -watch -n1 "nvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv,noheader | grep qemu" -``` - -You should see non-zero GPU utilization/memory for the emulator process. - -## Additional Optimizations - -### Clean Snapshots -Snapshots made with different configs can cause issues: -```bash -# Delete snapshots for clean state -rm -rf ~/.android/avd/TimeSafari_Emulator.avd/snapshots/ -``` - -### Fix ADB Issues -"Device offline" after boot is common with snapshots: -```bash -adb kill-server && adb start-server -adb -e wait-for-device -``` - -### Disable Unnecessary Features -Save CPU, reduce log spam, and prevent hangs: -```bash -emulator -avd TimeSafari_Emulator \ - -gpu host -accel on -no-boot-anim \ - -feature -Bluetooth -camera-back none -camera-front none -no-audio -``` - -**Key Benefits:** -- `-feature -Bluetooth`: Prevents Bluetooth-related hangs and ANRs -- `-camera-back none -camera-front none`: Disables camera hardware -- `-no-audio`: Disables audio system (saves resources) - -### CPU/RAM Configuration -Keep your existing settings: -```bash -emulator -avd TimeSafari_Emulator \ - -cores 6 -memory 4096 \ - -gpu host -accel on -no-boot-anim -``` - -## Troubleshooting Checklist - -### Before Launch -- [ ] NVIDIA drivers installed and working -- [ ] Vulkan ICD file exists: `/usr/share/vulkan/icd.d/nvidia_icd.json` -- [ ] AVD exists and is properly configured -- [ ] Android SDK and emulator in PATH - -### After Launch -- [ ] Check emulator banner for correct GPU binding -- [ ] Monitor `nvidia-smi` for GPU utilization -- [ ] Verify ADB connection with `adb devices` -- [ ] Test app installation and functionality - -### If Still Having Issues -- [ ] Try different GPU modes (OpenGL, ANGLE, Mesa) -- [ ] Clean snapshots and restart -- [ ] Check system logs for GPU errors -- [ ] Verify NVIDIA driver compatibility -- [ ] Consider software rendering for stability testing - -## Performance Expectations - -### Hardware Acceleration (NVIDIA) -- **GPU Utilization**: 20-60% during normal use -- **Memory Usage**: 500MB-2GB GPU memory -- **UI Responsiveness**: Smooth, 60fps target -- **Startup Time**: 30-60 seconds - -### Software Rendering (Mesa) -- **CPU Usage**: 50-80% on all cores -- **Memory Usage**: 1-4GB system RAM -- **UI Responsiveness**: Slower, 30fps typical -- **Startup Time**: 60-120 seconds - -## System Requirements - -### Minimum -- **CPU**: 4 cores, 2.5GHz+ -- **RAM**: 8GB system, 4GB for emulator -- **GPU**: Any with OpenGL 3.0+ support -- **Storage**: 10GB free space - -### Recommended -- **CPU**: 6+ cores, 3.0GHz+ -- **RAM**: 16GB system, 6GB for emulator -- **GPU**: NVIDIA GTX 1060+ or equivalent -- **Storage**: 20GB free space, SSD preferred - -## Support - -If you continue experiencing issues: -1. Check the [Android Emulator documentation](https://developer.android.com/studio/run/emulator) -2. Review [NVIDIA Linux driver documentation](https://docs.nvidia.com/driver/) -3. Test with different AVD configurations -4. Consider using physical Android devices for testing diff --git a/test-apps/README.md b/test-apps/README.md deleted file mode 100644 index 4113885..0000000 --- a/test-apps/README.md +++ /dev/null @@ -1,326 +0,0 @@ -# TimeSafari Test Apps Setup Guide - -## Overview - -This guide creates minimal Capacitor test apps for validating the TimeSafari Daily Notification Plugin integration across all target platforms. The test apps demonstrate TimeSafari's community-building features, Endorser.ch API integration, and notification patterns. - -## Directory Structure - -``` -test-apps/ -├── android-test/ # Android test app -├── ios-test/ # iOS test app -├── electron-test/ # Electron test app -├── test-api/ # TimeSafari Test API server -├── shared/ # Shared configuration and utilities -│ └── config-loader.ts # Configuration loader and mock services -├── config/ # Configuration files -│ └── timesafari-config.json -├── setup-android.sh # Android setup script -├── setup-ios.sh # iOS setup script -├── setup-electron.sh # Electron setup script -├── check-environment.sh # Environment verification -├── SETUP_GUIDE.md # Enhanced setup guide -└── README.md # This guide -``` - -## Prerequisites - -- Node.js 18+ -- Capacitor CLI: `npm install -g @capacitor/cli` -- Android Studio (for Android) -- Xcode (for iOS) -- Platform-specific SDKs -- Understanding of TimeSafari's community-building purpose -- Familiarity with Endorser.ch API patterns - -## Quick Start - -### Option 1: Automated Setup (Recommended) -```bash -# Navigate to test-apps directory first -cd test-apps - -# Setup all platforms (run from test-apps directory) -./setup-android.sh -./setup-ios.sh -./setup-electron.sh -``` - -**⚠️ Important**: Run setup scripts from the `test-apps` directory, not from individual platform directories. - -### Option 2: Manual Setup -See [Enhanced Setup Guide](SETUP_GUIDE.md) for detailed manual setup instructions and troubleshooting. - -### Prerequisites Check -```bash -# Check your environment before setup -./check-environment.sh -``` - -**Required Software**: -- **Node.js 18+**: Required for all platforms -- **Android Studio**: Required for Android testing -- **Xcode**: Required for iOS testing (macOS only) -- **No additional requirements**: For Electron testing - -## Test App Features - -Each test app includes comprehensive UI patterns and testing capabilities: - -### **Core Testing Features** -- **TimeSafari Configuration**: Test community-focused notification settings -- **Generic Polling Interface**: Test new structured request/response polling system -- **Endorser.ch API Integration**: Test real API patterns with pagination -- **Community Notification Scheduling**: Test offers, projects, people, and items notifications -- **Static Daily Reminders**: Test simple daily notifications without network content -- **Performance Monitoring**: Metrics collection and display -- **Error Handling**: Comprehensive error testing -- **Debug Information**: Platform-specific debug data - -### **Enhanced UI Components** -- **Permission Management**: Request dialogs, status displays, settings integration -- **Configuration Panels**: Settings toggles, time pickers, content type selection -- **Status Dashboards**: Real-time monitoring with performance metrics -- **Platform-Specific Features**: - - **Android**: Battery optimization, exact alarm permissions, reboot recovery - - **iOS**: Background app refresh, rolling window management, BGTaskScheduler - - **Electron**: Service worker status, push notifications, IPC communication -- **Error Handling UI**: User-friendly error displays with retry mechanisms -- **Testing Tools**: Test notification panels, debug info, log export - -### **UI Design Features** -- **Responsive Design**: Mobile-first approach with touch-friendly interfaces -- **Accessibility**: WCAG 2.1 AA compliance with keyboard navigation -- **Platform Native**: Material Design (Android), Human Interface Guidelines (iOS) -- **Progressive Disclosure**: Essential features first, advanced options on demand -- **Real-time Updates**: Live status monitoring and performance metrics - -## TimeSafari Test API Server - -A comprehensive REST API server (`test-api/`) simulates Endorser.ch API endpoints for testing the plugin's TimeSafari-specific functionality: - -### Quick Start -```bash -# Start the TimeSafari Test API server -cd test-apps/test-api -npm install -npm start - -# Test the API -npm run demo -``` - -### Key Features -- **Endorser.ch API Simulation**: Mock endpoints for offers, projects, and pagination -- **TimeSafari Notification Bundle**: Single route for bundled notifications -- **Community Analytics**: Analytics endpoint for community events -- **Pagination Support**: Full afterId/beforeId pagination testing -- **ETag Support**: HTTP caching with conditional requests -- **Error Simulation**: Test various error scenarios -- **Metrics**: Monitor API usage and performance -- **CORS Enabled**: Cross-origin requests supported - -### API Endpoints - -#### Endorser.ch API Endpoints -- `GET /api/v2/report/offers` - Get offers to person -- `GET /api/v2/report/offersToPlansOwnedByMe` - Get offers to user's projects -- `POST /api/v2/report/plansLastUpdatedBetween` - Get changes to starred projects - -#### TimeSafari API Endpoints -- `GET /api/v2/report/notifications/bundle` - Get bundled notifications -- `POST /api/analytics/community-events` - Send community analytics - -#### Legacy Endpoints -- `GET /health` - Health check -- `GET /api/content/:slotId` - Get notification content -- `GET /api/metrics` - API metrics - -### Platform-Specific URLs -- **Web/Electron**: `http://localhost:3001` -- **Android Emulator**: `http://10.0.2.2:3001` -- **iOS Simulator**: `http://localhost:3001` -- **Physical Devices**: `http://[YOUR_IP]:3001` - -## Platform-Specific Testing - -### Android Test App -- **TimeSafari Configuration**: Test community notification settings -- **Generic Polling Interface**: Test structured request/response polling with Android WorkManager -- **Endorser.ch API Integration**: Test parallel API requests -- **Exact Alarm Status**: Check permission and capability -- **Permission Requests**: Test exact alarm permission flow -- **Performance Metrics**: Monitor Android-specific optimizations -- **Reboot Recovery**: Validate system restart handling -- **Enhanced UI**: Permission dialogs, battery optimization, exact alarm management -- **Status Dashboard**: Real-time monitoring with Android-specific metrics -- **Error Handling**: User-friendly error displays with retry mechanisms - -### iOS Test App -- **TimeSafari Configuration**: Test iOS community features -- **Generic Polling Interface**: Test structured request/response polling with iOS BGTaskScheduler -- **Rolling Window**: Test notification limit management -- **Endorser.ch API Integration**: Test pagination patterns -- **Background Tasks**: Validate BGTaskScheduler integration -- **Performance Metrics**: Monitor iOS-specific optimizations -- **Memory Management**: Test object pooling and cleanup -- **Enhanced UI**: Background refresh dialogs, rolling window controls, BGTaskScheduler status -- **Status Dashboard**: Real-time monitoring with iOS-specific metrics -- **Error Handling**: User-friendly error displays with retry mechanisms - -### Electron Test App -- **TimeSafari Configuration**: Test Electron community features -- **Mock Implementations**: Test web platform compatibility -- **Endorser.ch API Integration**: Test API patterns -- **IPC Communication**: Validate Electron-specific APIs -- **Development Workflow**: Test plugin integration -- **Debug Information**: Platform-specific status display -- **Enhanced UI**: Service worker status, push notification setup, debug information -- **Status Dashboard**: Real-time monitoring with Electron-specific metrics -- **Error Handling**: User-friendly error displays with retry mechanisms - -## Running the Test Apps - -### Android -```bash -cd android-test -npm run dev # Web development server -npx cap open android # Open in Android Studio -npx cap run android # Run on device/emulator -``` - -#### High-Performance Emulator Launch (Linux + NVIDIA) - -For optimal GPU acceleration on Linux systems: - -```bash -# Launch with GPU acceleration and performance optimizations -QT_QPA_PLATFORM=xcb \ -__NV_PRIME_RENDER_OFFLOAD=1 \ -__GLX_VENDOR_LIBRARY_NAME=nvidia \ -__VK_LAYER_NV_optimus=NVIDIA_only \ -VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json \ -DRI_PRIME=1 \ -emulator -avd TimeSafari_Emulator \ - -gpu host \ - -feature Vulkan \ - -accel on \ - -no-boot-anim \ - -no-snapshot-load -``` - -**Benefits:** -- Hardware GPU acceleration for smoother UI -- Vulkan graphics API support -- Faster startup (no boot animation) -- Clean state (no snapshot loading) -- Optimized for NVIDIA graphics cards - -#### Alternative GPU Modes - -If you experience GPU binding issues, try these alternatives: - -```bash -# Pure OpenGL mode (no Vulkan) -./launch-emulator-opengl.sh - -# ANGLE mode (better NVIDIA compatibility) -./launch-emulator-angle.sh - -# Mesa fallback (software rendering) -./launch-emulator-mesa.sh -``` - -**Troubleshooting:** -- See [EMULATOR_TROUBLESHOOTING.md](./EMULATOR_TROUBLESHOOTING.md) for detailed GPU binding solutions -- Check emulator banner for correct GPU binding -- Monitor GPU usage with `nvidia-smi dmon -s u` - -### iOS -```bash -cd ios-test -npm run dev # Web development server -npx cap open ios # Open in Xcode -npx cap run ios # Run on device/simulator -``` - -### Electron -```bash -cd electron-test -npm start # Run Electron app -npm run dev # Run in development mode -``` - -## Testing Checklist - -### Core Functionality -- [ ] TimeSafari configuration works -- [ ] Generic polling interface functions properly -- [ ] Community notification scheduling succeeds -- [ ] Endorser.ch API integration functions properly -- [ ] Error handling functions properly -- [ ] Performance metrics are accurate - -### Enhanced UI Testing -- [ ] Permission management dialogs display correctly -- [ ] Settings panels save and load configuration -- [ ] Status dashboards show real-time data -- [ ] Error handling UI displays user-friendly messages -- [ ] Platform-specific features work as expected -- [ ] Responsive design works on different screen sizes -- [ ] Accessibility features function properly - -### Platform-Specific -- [ ] Android exact alarm permissions, battery optimization, reboot recovery -- [ ] iOS rolling window management, background refresh, BGTaskScheduler -- [ ] Electron mock implementations, service worker, push notifications -- [ ] Cross-platform API consistency - -### TimeSafari Integration -- [ ] Plugin loads without errors -- [ ] Configuration persists across sessions -- [ ] Endorser.ch API pagination works -- [ ] Community notification types process correctly -- [ ] Performance optimizations active -- [ ] Debug information accessible - -## Troubleshooting - -### Common Issues -1. **"Unknown command: cap"** → Install Capacitor CLI: `npm install -g @capacitor/cli` -2. **"android platform has not been added yet"** → Run `npx cap add android` first -3. **Build failures** → Check Node.js version (18+) and clear cache: `npm cache clean --force` -4. **Platform errors** → Verify platform-specific SDKs are installed -5. **API connection errors** → Ensure test API server is running on port 3001 - -### Quick Fixes -```bash -# Check environment -./check-environment.sh - -# Reinstall dependencies -rm -rf node_modules && npm install - -# Clear Capacitor cache -npx cap clean - -# Re-sync platforms -npx cap sync - -# Restart test API server -cd test-api && npm start -``` - -### Detailed Help -See [Enhanced Setup Guide](SETUP_GUIDE.md) for comprehensive troubleshooting and platform-specific solutions. - -## Next Steps - -1. **Run Setup Scripts**: Execute platform-specific setup -2. **Start Test API Server**: Run the TimeSafari Test API server -3. **Test Core Features**: Validate basic TimeSafari functionality -4. **Test Platform Features**: Verify platform-specific capabilities -5. **Test Endorser.ch Integration**: Validate API patterns and pagination -6. **Integration Testing**: Test with actual plugin implementation -7. **Performance Validation**: Monitor metrics and optimizations diff --git a/test-apps/SETUP_GUIDE.md b/test-apps/SETUP_GUIDE.md deleted file mode 100644 index e311bfa..0000000 --- a/test-apps/SETUP_GUIDE.md +++ /dev/null @@ -1,384 +0,0 @@ -# Enhanced Test Apps Setup Guide - -## Overview - -This guide creates minimal Capacitor test apps for validating the Daily Notification Plugin across all target platforms with robust error handling and clear troubleshooting. - -## Prerequisites - -### Required Software -- **Node.js 18+**: Download from [nodejs.org](https://nodejs.org/) -- **npm**: Comes with Node.js -- **Git**: For version control - -### Platform-Specific Requirements - -#### Android -- **Android Studio**: Download from [developer.android.com/studio](https://developer.android.com/studio) -- **Android SDK**: Installed via Android Studio -- **Java Development Kit (JDK)**: Version 11 or higher - -#### iOS (macOS only) -- **Xcode**: Install from Mac App Store -- **Xcode Command Line Tools**: `xcode-select --install` -- **iOS Simulator**: Included with Xcode - -#### Electron -- **No additional requirements**: Works on any platform with Node.js - -## Quick Start - -### Option 1: Automated Setup (Recommended) - -```bash -# Navigate to test-apps directory -cd test-apps - -# Setup all platforms (run from test-apps directory) -./setup-android.sh -./setup-ios.sh -./setup-electron.sh -``` - -### Option 2: Manual Setup - -#### Android Manual Setup -```bash -cd test-apps/android-test - -# Install dependencies -npm install - -# Install Capacitor CLI globally -npm install -g @capacitor/cli - -# Initialize Capacitor -npx cap init "Daily Notification Android Test" "com.timesafari.dailynotification.androidtest" - -# Add Android platform -npx cap add android - -# Build web assets -npm run build - -# Sync to native -npx cap sync android -``` - -#### iOS Manual Setup -```bash -cd test-apps/ios-test - -# Install dependencies -npm install - -# Install Capacitor CLI globally -npm install -g @capacitor/cli - -# Initialize Capacitor -npx cap init "Daily Notification iOS Test" "com.timesafari.dailynotification.iostest" - -# Add iOS platform -npx cap add ios - -# Build web assets -npm run build - -# Sync to native -npx cap sync ios -``` - -#### Electron Manual Setup -```bash -cd test-apps/electron-test - -# Install dependencies -npm install - -# Build web assets -npm run build-web -``` - -## Common Issues and Solutions - -### Issue: "Unknown command: cap" -**Solution**: Install Capacitor CLI globally -```bash -npm install -g @capacitor/cli -``` - -### Issue: "android platform has not been added yet" -**Solution**: Add the Android platform first -```bash -npx cap add android -``` - -### Issue: "Failed to add Android platform" -**Solutions**: -1. Install Android Studio and Android SDK -2. Set `ANDROID_HOME` environment variable -3. Add Android SDK tools to your PATH - -### Issue: "Failed to add iOS platform" -**Solutions**: -1. Install Xcode from Mac App Store -2. Install Xcode Command Line Tools: `xcode-select --install` -3. Ensure you're running on macOS - -### Issue: Build failures -**Solutions**: -1. Check Node.js version: `node --version` (should be 18+) -2. Clear npm cache: `npm cache clean --force` -3. Delete `node_modules` and reinstall: `rm -rf node_modules && npm install` - -## Platform-Specific Setup - -### Android Setup Verification - -```bash -# Check Android Studio installation -which studio - -# Check Android SDK -echo $ANDROID_HOME - -# Check Java -java -version -``` - -**Required Environment Variables**: -```bash -export ANDROID_HOME=/path/to/android/sdk -export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools -``` - -### iOS Setup Verification - -```bash -# Check Xcode installation -xcodebuild -version - -# Check iOS Simulator -xcrun simctl list devices - -# Check Command Line Tools -xcode-select -p -``` - -### Electron Setup Verification - -```bash -# Check Node.js version -node --version - -# Check npm -npm --version - -# Test Electron installation -npx electron --version -``` - -## Running the Test Apps - -### Android -```bash -cd test-apps/android-test - -# Web development server (for testing) -npm run dev - -# Open in Android Studio -npx cap open android - -# Run on device/emulator -npx cap run android -``` - -#### Advanced Emulator Launch (GPU Acceleration) - -For optimal performance on Linux systems with NVIDIA graphics: - -```bash -# Launch emulator with GPU acceleration and performance tuning -QT_QPA_PLATFORM=xcb \ -__NV_PRIME_RENDER_OFFLOAD=1 \ -__GLX_VENDOR_LIBRARY_NAME=nvidia \ -__VK_LAYER_NV_optimus=NVIDIA_only \ -VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json \ -DRI_PRIME=1 \ -emulator -avd TimeSafari_Emulator \ - -gpu host \ - -feature Vulkan \ - -accel on \ - -cores 6 \ - -memory 4096 \ - -no-boot-anim \ - -no-snapshot-load \ - -dns-server 8.8.8.8,1.1.1.1 -``` - -**Environment Variables Explained:** - -- `QT_QPA_PLATFORM=xcb`: Use X11 backend for Qt applications -- `__NV_PRIME_RENDER_OFFLOAD=1`: Enable NVIDIA GPU offloading -- `__GLX_VENDOR_LIBRARY_NAME=nvidia`: Use NVIDIA OpenGL library -- `__VK_LAYER_NV_optimus=NVIDIA_only`: Force NVIDIA Vulkan layer -- `VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json`: Specify NVIDIA Vulkan driver -- `DRI_PRIME=1`: Enable DRI Prime for GPU selection - -**Emulator Flags Explained:** - -- `-gpu host`: Use host GPU for hardware acceleration -- `-feature Vulkan`: Enable Vulkan graphics API support -- `-accel on`: Enable hardware acceleration -- `-cores 6`: Allocate 6 CPU cores to emulator -- `-memory 4096`: Allocate 4GB RAM to emulator -- `-no-boot-anim`: Skip boot animation for faster startup -- `-no-snapshot-load`: Don't load snapshots for clean state -- `-dns-server 8.8.8.8,1.1.1.1`: Use explicit DNS servers -- `-feature -Bluetooth`: Disable Bluetooth to prevent hangs - -#### Alternative GPU Modes - -If you experience GPU binding issues (OpenGL using Intel iGPU instead of NVIDIA), try these alternative launch scripts: - -```bash -# Pure OpenGL mode (no Vulkan) -./launch-emulator-opengl.sh - -# ANGLE mode (better NVIDIA compatibility) -./launch-emulator-angle.sh - -# Mesa fallback (software rendering) -./launch-emulator-mesa.sh -``` - -**Troubleshooting GPU Issues:** - -- Check emulator banner for `OpenGL Vendor=Google (NVIDIA)` -- Monitor GPU usage: `nvidia-smi dmon -s u` -- See [EMULATOR_TROUBLESHOOTING.md](./EMULATOR_TROUBLESHOOTING.md) for detailed solutions - -### iOS - -```bash -cd test-apps/ios-test - -# Web development server (for testing) -npm run dev - -# Open in Xcode -npx cap open ios - -# Run on device/simulator -npx cap run ios -``` - -### Electron - -```bash -cd test-apps/electron-test - -# Run Electron app -npm start - -# Run in development mode -npm run dev - -# Build and run -npm run electron -``` - -## Testing Workflow - -### 1. Web Testing (Recommended First) - -```bash -# Test each platform's web version first -cd test-apps/android-test && npm run dev -cd test-apps/ios-test && npm run dev -cd test-apps/electron-test && npm start -``` - -### 2. Native Testing - -```bash -# After web testing succeeds, test native platforms -cd test-apps/android-test && npx cap run android -cd test-apps/ios-test && npx cap run ios -``` - -### 3. Integration Testing - -- Test plugin configuration -- Test notification scheduling -- Test platform-specific features -- Test error handling -- Test performance metrics - -## Troubleshooting Checklist - -### General Issues - -- [ ] Node.js 18+ installed -- [ ] npm working correctly -- [ ] Capacitor CLI installed globally -- [ ] Dependencies installed (`npm install`) - -### Android Issues - -- [ ] Android Studio installed -- [ ] Android SDK configured -- [ ] `ANDROID_HOME` environment variable set -- [ ] Java JDK 11+ installed -- [ ] Android platform added (`npx cap add android`) - -### iOS Issues - -- [ ] Xcode installed (macOS only) -- [ ] Xcode Command Line Tools installed -- [ ] iOS Simulator available -- [ ] iOS platform added (`npx cap add ios`) - -### Electron Issues - -- [ ] Node.js working correctly -- [ ] Dependencies installed -- [ ] Web assets built (`npm run build-web`) - -## Development Tips - -### Web Development - -- Use `npm run dev` for hot reloading -- Test plugin APIs in browser console -- Use browser dev tools for debugging - -### Native Development - -- Use `npx cap sync` after making changes -- Check native logs for detailed errors -- Test on both physical devices and simulators - -### Debugging - -- Check console logs for errors -- Use `npx cap doctor` to diagnose issues -- Verify platform-specific requirements - -## Next Steps - -1. **Run Setup Scripts**: Execute platform-specific setup -2. **Test Web Versions**: Validate basic functionality -3. **Test Native Platforms**: Verify platform-specific features -4. **Integration Testing**: Test with actual plugin implementation -5. **Performance Validation**: Monitor metrics and optimizations - -## Support - -If you encounter issues not covered in this guide: - -1. Check the [Capacitor Documentation](https://capacitorjs.com/docs) -2. Verify platform-specific requirements -3. Check console logs for detailed error messages -4. Ensure all prerequisites are properly installed diff --git a/test-apps/android-test/.eslintrc.cjs b/test-apps/android-test/.eslintrc.cjs deleted file mode 100644 index b7406d6..0000000 --- a/test-apps/android-test/.eslintrc.cjs +++ /dev/null @@ -1,20 +0,0 @@ -/* eslint-env node */ -require('@rushstack/eslint-patch/modern-module-resolution') - -module.exports = { - root: true, - 'extends': [ - 'plugin:vue/vue3-essential', - 'eslint:recommended', - '@vue/eslint-config-typescript' - ], - parserOptions: { - ecmaVersion: 'latest' - }, - rules: { - 'vue/multi-word-component-names': 'off', - '@typescript-eslint/no-unused-vars': ['error', { 'argsIgnorePattern': '^_' }], - 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', - 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off' - } -} diff --git a/test-apps/android-test/.gitignore b/test-apps/android-test/.gitignore deleted file mode 100644 index a217c10..0000000 --- a/test-apps/android-test/.gitignore +++ /dev/null @@ -1,105 +0,0 @@ -# Dependencies -node_modules/ -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Build outputs -dist/ -build/ -*.tsbuildinfo - -# Capacitor -android/ -ios/ -.capacitor/ - -# IDE and editor files -.vscode/ -.idea/ -*.swp -*.swo -*~ - -# OS generated files -.DS_Store -.DS_Store? -._* -.Spotlight-V100 -.Trashes -ehthumbs.db -Thumbs.db - -# Logs -logs -*.log - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Coverage directory used by tools like istanbul -coverage/ -*.lcov - -# nyc test coverage -.nyc_output - -# Dependency directories -jspm_packages/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test -.env.local -.env.development.local -.env.test.local -.env.production.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# next.js build output -.next - -# nuxt.js build output -.nuxt - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port diff --git a/test-apps/android-test/GRADLE_TROUBLESHOOTING.md b/test-apps/android-test/GRADLE_TROUBLESHOOTING.md deleted file mode 100644 index 7ca40aa..0000000 --- a/test-apps/android-test/GRADLE_TROUBLESHOOTING.md +++ /dev/null @@ -1,160 +0,0 @@ -# Android Test App Gradle Sync Troubleshooting - -## Problem: Gradle Sync Failure - -**Error Message:** -``` -Unable to find method 'org.gradle.api.artifacts.Dependency org.gradle.api.artifacts.dsl.DependencyHandler.module(java.lang.Object)' -``` - -## Root Cause - -The Android test app was using **Gradle 9.0-milestone-1** (pre-release) with **Android Gradle Plugin 8.0.0**, causing version incompatibility issues. - -## Solution Applied - -### 1. Updated Gradle Version -**File:** `android/gradle/wrapper/gradle-wrapper.properties` -```properties -# Changed from: -distributionUrl=https\://services.gradle.org/distributions/gradle-9.0-milestone-1-bin.zip - -# To: -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip -``` - -### 2. Updated Android Gradle Plugin -**File:** `android/build.gradle` -```gradle -// Changed from: -classpath 'com.android.tools.build:gradle:8.0.0' - -// To: -classpath 'com.android.tools.build:gradle:8.13.0' -``` - -### 3. Updated Google Services Plugin -```gradle -// Changed from: -classpath 'com.google.gms:google-services:4.3.15' - -// To: -classpath 'com.google.gms:google-services:4.4.0' -``` - -### 4. Updated AndroidX Dependencies -**File:** `android/variables.gradle` -```gradle -// Updated to latest stable versions: -androidxAppCompatVersion = '1.7.1' // was 1.6.1 -androidxActivityVersion = '1.8.2' // was 1.7.0 -androidxCoreVersion = '1.12.0' // was 1.10.0 -androidxFragmentVersion = '1.6.2' // was 1.5.6 -coreSplashScreenVersion = '1.0.1' // was 1.0.0 -androidxWebkitVersion = '1.8.0' // was 1.6.1 -compileSdkVersion = 34 // was 33 -targetSdkVersion = 34 // was 33 -``` - -## Manual Fix Steps - -If you encounter this issue again: - -### Step 1: Clean Gradle Cache -```bash -cd test-apps/android-test/android -./gradlew clean -./gradlew --stop -``` - -### Step 2: Clear Gradle Wrapper Cache -```bash -rm -rf ~/.gradle/wrapper/dists/gradle-9.0-milestone-1* -``` - -### Step 3: Re-sync Project -In Android Studio: -1. Click **File** → **Sync Project with Gradle Files** -2. Or click the **Sync Now** link in the error banner - -### Step 4: If Still Failing -```bash -# Delete all Gradle caches -rm -rf ~/.gradle/caches -rm -rf ~/.gradle/wrapper - -# Re-download Gradle -cd test-apps/android-test/android -./gradlew wrapper --gradle-version 8.4 -``` - -## Prevention - -### Use Stable Versions -Always use stable, tested version combinations: - -| Android Gradle Plugin | Gradle Version | Status | -|----------------------|----------------|---------| -| 8.13.0 | 8.13 | ✅ Latest Stable | -| 8.1.4 | 8.4 | ✅ Stable | -| 8.0.0 | 8.0 | ✅ Stable | -| 7.4.2 | 7.5 | ✅ Stable | -| 8.0.0 | 9.0-milestone-1 | ❌ Incompatible | - -### Version Compatibility Check -- **Android Gradle Plugin 8.13.0** requires **Gradle 8.0+** -- **Gradle 8.13** is the latest stable version -- **AndroidX AppCompat 1.7.1** is the latest stable version -- Avoid pre-release versions in production - -## Additional Troubleshooting - -### If Sync Still Fails - -1. **Check Java Version** - ```bash - java -version - # Should be Java 17+ for AGP 8.1.4 - ``` - -2. **Check Android SDK** - ```bash - echo $ANDROID_HOME - # Should point to Android SDK location - ``` - -3. **Check Local Properties** - ```bash - # Verify android/local.properties exists - cat test-apps/android-test/android/local.properties - ``` - -4. **Recreate Project** - ```bash - cd test-apps/android-test - rm -rf android/ - npx cap add android - ``` - -## Success Indicators - -After applying the fix, you should see: -- ✅ **Gradle sync successful** -- ✅ **No red error banners** -- ✅ **Build.gradle file opens without errors** -- ✅ **Project structure loads correctly** - -## Next Steps - -Once Gradle sync is successful: -1. **Build the project**: `./gradlew build` -2. **Run on device**: `npx cap run android` -3. **Test plugin functionality**: Use the test API server -4. **Validate notifications**: Test the Daily Notification Plugin - -## Related Issues - -- **Build failures**: Usually resolved by Gradle sync fix -- **Plugin not found**: Check Capacitor plugin installation -- **Permission errors**: Verify Android manifest permissions -- **Runtime crashes**: Check plugin initialization code diff --git a/test-apps/android-test/README.md b/test-apps/android-test/README.md deleted file mode 100644 index bacca5e..0000000 --- a/test-apps/android-test/README.md +++ /dev/null @@ -1,329 +0,0 @@ -# Daily Notification Test App - Vue 3 - -A modern Vue 3 + Vite + Capacitor test application for the Daily Notification Plugin, built with vue-facing-decorator for TypeScript class-based components. - -## 🚀 Features - -- **Vue 3** with Composition API and TypeScript -- **Vite** for fast development and building -- **vue-facing-decorator** for class-based components -- **Pinia** for state management -- **Vue Router** for navigation -- **Capacitor** for native Android functionality -- **Modern UI** with glassmorphism design -- **Responsive** design for mobile and desktop - -## 📱 App Structure - -``` -src/ -├── components/ # Reusable Vue components -│ ├── cards/ # Card components (ActionCard, StatusCard, etc.) -│ ├── items/ # List item components -│ ├── layout/ # Layout components (Header, Footer) -│ └── ui/ # UI components (Loading, Error, etc.) -├── stores/ # Pinia stores -│ ├── app.ts # Global app state -│ └── notifications.ts # Notification management -├── views/ # Page components -│ ├── HomeView.vue # Dashboard -│ ├── ScheduleView.vue # Schedule notifications -│ ├── NotificationsView.vue # Manage notifications -│ ├── StatusView.vue # System status -│ ├── HistoryView.vue # Notification history -│ └── SettingsView.vue # App settings -├── router/ # Vue Router configuration -├── types/ # TypeScript type definitions -└── utils/ # Utility functions -``` - -## 🛠️ Development - -### Prerequisites - -- Node.js 18+ -- npm or yarn -- Android Studio (for Android development) -- Capacitor CLI - -### Installation - -```bash -# Install dependencies -npm install - -# Start development server -npm run dev - -# Build for production -npm run build - -# Type checking -npm run type-check - -# Linting -npm run lint -``` - -### Android Development - -```bash -# Sync with Capacitor -npm run sync - -# Open Android Studio -npm run open - -# Run on Android device/emulator -npm run android -``` - -## 🎨 UI Components - -### Class-Based Components - -All components use vue-facing-decorator for TypeScript class-based syntax: - -```typescript -@Component({ - components: { - ChildComponent - } -}) -export default class MyComponent extends Vue { - @Prop() title!: string - - private data = ref('') - - get computedValue(): string { - return this.data.value.toUpperCase() - } - - private handleClick(): void { - // Handle click - } -} -``` - -### State Management - -Uses Pinia stores for reactive state management: - -```typescript -// stores/notifications.ts -export const useNotificationsStore = defineStore('notifications', () => { - const scheduledNotifications = ref([]) - - async function scheduleNotification(options: ScheduleOptions): Promise { - // Schedule logic - } - - return { - scheduledNotifications, - scheduleNotification - } -}) -``` - -## 📊 Features - -### Dashboard (Home) -- Quick action cards -- System status overview -- Next scheduled notification -- Recent activity feed - -### Schedule Notifications -- Time picker -- Title and message inputs -- Sound and priority options -- URL support for deep linking -- Quick schedule presets - -### Notification Management -- View all scheduled notifications -- Cancel notifications -- Status indicators - -### System Status -- Permission checks -- Channel status -- Exact alarm settings -- Platform information -- Test notification functionality - -### History -- Delivered notification history -- Click and dismiss tracking -- Time-based filtering - -## 🔧 Configuration - -### Capacitor Config - -```typescript -// capacitor.config.ts -const config: CapacitorConfig = { - appId: 'com.timesafari.dailynotification.androidtest', - appName: 'Daily Notification Test - Vue 3', - webDir: 'dist', - plugins: { - DailyNotification: { - storage: 'shared', - ttlSeconds: 1800, - prefetchLeadMinutes: 15, - enableETagSupport: true, - enableErrorHandling: true, - enablePerformanceOptimization: true - } - } -} -``` - -### Vite Config - -```typescript -// vite.config.ts -export default defineConfig({ - plugins: [vue()], - build: { - outDir: 'dist', - sourcemap: true - }, - resolve: { - alias: { - '@': resolve(__dirname, 'src') - } - } -}) -``` - -## 🎯 Testing the Plugin - -1. **Start Development Server** - ```bash - npm run dev - ``` - -2. **Build and Sync** - ```bash - npm run build - npm run sync - ``` - -3. **Run on Android** - ```bash - npm run android - ``` - -4. **Test Features** - - Schedule notifications - - Check system status - - View notification history - - Test clickable notifications - -## 📱 Native Features - -- **Notification Scheduling** - Schedule daily notifications -- **Permission Management** - Check and request permissions -- **Status Monitoring** - Real-time system status -- **Deep Linking** - URL support in notifications -- **Background Processing** - WorkManager integration - -## 🎨 Design System - -### Colors -- Primary: Linear gradient (purple to blue) -- Success: #4caf50 -- Warning: #ff9800 -- Error: #f44336 -- Info: #2196f3 - -### Typography -- Headers: Bold, white with text-shadow -- Body: Regular, rgba white -- Code: Courier New monospace - -### Components -- Glassmorphism design with backdrop-filter -- Rounded corners (8px, 12px, 16px) -- Smooth transitions and hover effects -- Responsive grid layouts - -## 🚀 Production Build - -```bash -# Build for production -npm run build - -# Preview production build -npm run preview - -# Sync with Capacitor -npm run sync - -# Build Android APK -npm run android -``` - -## 📝 Scripts - -- `npm run dev` - Start development server -- `npm run build` - Build for production -- `npm run preview` - Preview production build -- `npm run android` - Run on Android -- `npm run sync` - Sync with Capacitor -- `npm run open` - Open Android Studio -- `npm run lint` - Run ESLint -- `npm run type-check` - TypeScript type checking - -## 🔍 Debugging - -### Vue DevTools -Install Vue DevTools browser extension for component inspection. - -### Capacitor Logs -```bash -# Android logs -adb logcat | grep -i "daily\|notification" - -# Capacitor logs -npx cap run android --livereload --external -``` - -### TypeScript -Enable strict mode in `tsconfig.json` for better type checking. - -## 📚 Dependencies - -### Core -- Vue 3.4+ -- Vite 5.0+ -- TypeScript 5.3+ -- Capacitor 5.0+ - -### UI & State -- vue-facing-decorator 3.0+ -- Pinia 2.1+ -- Vue Router 4.2+ - -### Development -- ESLint + TypeScript configs -- Vue TSC for type checking -- Modern module resolution - -## 🤝 Contributing - -1. Follow Vue 3 + TypeScript best practices -2. Use vue-facing-decorator for class components -3. Maintain responsive design -4. Add proper TypeScript types -5. Test on both web and Android - -## 📄 License - -MIT License - see LICENSE file for details. - ---- - -**Built with ❤️ using Vue 3 + Vite + Capacitor** diff --git a/test-apps/android-test/capacitor.config.ts b/test-apps/android-test/capacitor.config.ts deleted file mode 100644 index 2e0d5c3..0000000 --- a/test-apps/android-test/capacitor.config.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { CapacitorConfig } from '@capacitor/cli'; - -const config: CapacitorConfig = { - appId: 'com.timesafari.dailynotification.androidtest', - appName: 'Daily Notification Test - Vue 3', - webDir: 'dist', - server: { - androidScheme: 'https' - }, - plugins: { - DailyNotification: { - storage: 'shared', - ttlSeconds: 1800, - prefetchLeadMinutes: 15, - enableETagSupport: true, - enableErrorHandling: true, - enablePerformanceOptimization: true - } - }, - android: { - allowMixedContent: true - } -}; - -export default config; diff --git a/test-apps/android-test/env.d.ts b/test-apps/android-test/env.d.ts deleted file mode 100644 index 9e0a952..0000000 --- a/test-apps/android-test/env.d.ts +++ /dev/null @@ -1,90 +0,0 @@ -/** - * Environment Type Declarations - * - * @author Matthew Raymer - * @version 1.0.0 - */ - -/// - -declare module '*.vue' { - import type { DefineComponent } from 'vue' - const component: DefineComponent<{}, {}, any> - export default component -} - -// Capacitor plugin declarations -declare global { - interface Window { - DailyNotification: { - scheduleDailyNotification: (options: { - time: string - title?: string - body?: string - sound?: boolean - priority?: string - url?: string - }) => Promise - - scheduleDailyReminder: (options: { - id: string - title: string - body: string - time: string - sound?: boolean - vibration?: boolean - priority?: string - repeatDaily?: boolean - timezone?: string - }) => Promise - - cancelDailyReminder: (options: { - reminderId: string - }) => Promise - - updateDailyReminder: (options: { - reminderId: string - title?: string - body?: string - time?: string - sound?: boolean - vibration?: boolean - priority?: string - repeatDaily?: boolean - timezone?: string - }) => Promise - - getLastNotification: () => Promise<{ - id: string - title: string - body: string - scheduledTime: number - deliveredAt: number - }> - - checkStatus: () => Promise<{ - canScheduleNow: boolean - postNotificationsGranted: boolean - channelEnabled: boolean - channelImportance: number - channelId: string - exactAlarmsGranted: boolean - exactAlarmsSupported: boolean - androidVersion: number - nextScheduledAt: number - }> - - checkChannelStatus: () => Promise<{ - enabled: boolean - importance: number - id: string - }> - - openChannelSettings: () => Promise - - openExactAlarmSettings: () => Promise - } - } -} - -export {} diff --git a/test-apps/android-test/index.html b/test-apps/android-test/index.html deleted file mode 100644 index 8090857..0000000 --- a/test-apps/android-test/index.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - Daily Notification Test - Vue 3 - - - - - - - - - - - - - - - - -
-
-
- Loading Daily Notification Test App... -
-
- - - diff --git a/test-apps/android-test/package.json b/test-apps/android-test/package.json deleted file mode 100644 index e7f4339..0000000 --- a/test-apps/android-test/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "daily-notification-android-test", - "version": "1.0.0", - "description": "Vue 3 + Vite + Capacitor test app for Daily Notification Plugin", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview", - "android": "npx cap run android", - "sync": "npx cap sync android", - "open": "npx cap open android", - "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", - "type-check": "vue-tsc --noEmit" - }, - "keywords": ["capacitor", "android", "notifications", "test", "vue3", "vite", "typescript"], - "author": "Matthew Raymer", - "license": "MIT", - "dependencies": { - "@capacitor/core": "^5.0.0", - "@capacitor/android": "^5.0.0", - "@capacitor/cli": "^5.0.0", - "vue": "^3.4.0", - "vue-router": "^4.2.0", - "pinia": "^2.1.0", - "vue-facing-decorator": "^3.0.0" - }, - "devDependencies": { - "@capacitor/cli": "^5.0.0", - "@types/node": "^20.0.0", - "@typescript-eslint/eslint-plugin": "^6.0.0", - "@typescript-eslint/parser": "^6.0.0", - "@vitejs/plugin-vue": "^4.5.0", - "@vue/eslint-config-typescript": "^12.0.0", - "@vue/tsconfig": "^0.5.0", - "eslint": "^8.0.0", - "eslint-plugin-vue": "^9.0.0", - "typescript": "~5.3.0", - "vite": "^5.0.0", - "vue-tsc": "^1.8.0" - } -} \ No newline at end of file diff --git a/test-apps/android-test/src/App.vue b/test-apps/android-test/src/App.vue deleted file mode 100644 index faddc3b..0000000 --- a/test-apps/android-test/src/App.vue +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/components/cards/ActionCard.vue b/test-apps/android-test/src/components/cards/ActionCard.vue deleted file mode 100644 index e145772..0000000 --- a/test-apps/android-test/src/components/cards/ActionCard.vue +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/components/cards/InfoCard.vue b/test-apps/android-test/src/components/cards/InfoCard.vue deleted file mode 100644 index ffe1e44..0000000 --- a/test-apps/android-test/src/components/cards/InfoCard.vue +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/components/cards/NotificationCard.vue b/test-apps/android-test/src/components/cards/NotificationCard.vue deleted file mode 100644 index 49ff77c..0000000 --- a/test-apps/android-test/src/components/cards/NotificationCard.vue +++ /dev/null @@ -1,181 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/components/cards/StatusCard.vue b/test-apps/android-test/src/components/cards/StatusCard.vue deleted file mode 100644 index 8104b6e..0000000 --- a/test-apps/android-test/src/components/cards/StatusCard.vue +++ /dev/null @@ -1,264 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/components/items/ActivityItem.vue b/test-apps/android-test/src/components/items/ActivityItem.vue deleted file mode 100644 index 4451b82..0000000 --- a/test-apps/android-test/src/components/items/ActivityItem.vue +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/components/items/HistoryItem.vue b/test-apps/android-test/src/components/items/HistoryItem.vue deleted file mode 100644 index 1d62b02..0000000 --- a/test-apps/android-test/src/components/items/HistoryItem.vue +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/components/items/StatusItem.vue b/test-apps/android-test/src/components/items/StatusItem.vue deleted file mode 100644 index c644c0d..0000000 --- a/test-apps/android-test/src/components/items/StatusItem.vue +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/components/layout/AppFooter.vue b/test-apps/android-test/src/components/layout/AppFooter.vue deleted file mode 100644 index da13d58..0000000 --- a/test-apps/android-test/src/components/layout/AppFooter.vue +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/components/layout/AppHeader.vue b/test-apps/android-test/src/components/layout/AppHeader.vue deleted file mode 100644 index ed9fd91..0000000 --- a/test-apps/android-test/src/components/layout/AppHeader.vue +++ /dev/null @@ -1,239 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/main.ts b/test-apps/android-test/src/main.ts deleted file mode 100644 index dfec0c1..0000000 --- a/test-apps/android-test/src/main.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Main Application Entry Point - * - * Vue 3 + TypeScript + Capacitor + vue-facing-decorator setup - * - * @author Matthew Raymer - * @version 1.0.0 - */ - -import { createApp } from 'vue' -import { createPinia } from 'pinia' -import { Capacitor } from '@capacitor/core' -import App from './App.vue' -import router from './router' - -// Create Vue app instance -const app = createApp(App) - -// Configure Pinia for state management -const pinia = createPinia() -app.use(pinia) - -// Configure Vue Router -app.use(router) - -// Global error handler for Capacitor -app.config.errorHandler = (err, _instance, info) => { - console.error('Vue Error:', err, info) - if (Capacitor.isNativePlatform()) { - // Log to native platform - console.error('Native Platform Error:', err) - } -} - -// Mount the app -app.mount('#app') - -// Log platform information -console.log('🚀 Daily Notification Test App Started') -console.log('📱 Platform:', Capacitor.getPlatform()) -console.log('🔧 Native Platform:', Capacitor.isNativePlatform()) -console.log('🌐 Web Platform:', Capacitor.isPluginAvailable('App')) diff --git a/test-apps/android-test/src/router/index.ts b/test-apps/android-test/src/router/index.ts deleted file mode 100644 index 935d8e6..0000000 --- a/test-apps/android-test/src/router/index.ts +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Vue Router Configuration - * - * @author Matthew Raymer - * @version 1.0.0 - */ - -import { createRouter, createWebHistory } from 'vue-router' -import type { RouteRecordRaw } from 'vue-router' - -const routes: RouteRecordRaw[] = [ - { - path: '/', - name: 'Home', - component: () => import('@/views/HomeView.vue'), - meta: { - title: 'Daily Notification Test', - requiresAuth: false - } - }, - { - path: '/notifications', - name: 'Notifications', - component: () => import('@/views/NotificationsView.vue'), - meta: { - title: 'Notification Management', - requiresAuth: false - } - }, - { - path: '/schedule', - name: 'Schedule', - component: () => import('@/views/ScheduleView.vue'), - meta: { - title: 'Schedule Notification', - requiresAuth: false - } - }, - { - path: '/status', - name: 'Status', - component: () => import('@/views/StatusView.vue'), - meta: { - title: 'System Status', - requiresAuth: false - } - }, - { - path: '/history', - name: 'History', - component: () => import('@/views/HistoryView.vue'), - meta: { - title: 'Notification History', - requiresAuth: false - } - }, - { - path: '/logs', - name: 'Logs', - component: () => import('@/views/LogsView.vue'), - meta: { - title: 'Android Logs', - requiresAuth: false - } - }, - { - path: '/settings', - name: 'Settings', - component: () => import('@/views/SettingsView.vue'), - meta: { - title: 'Settings', - requiresAuth: false - } - }, - { - path: '/:pathMatch(.*)*', - name: 'NotFound', - component: () => import('@/views/NotFoundView.vue'), - meta: { - title: 'Page Not Found', - requiresAuth: false - } - } -] - -const router = createRouter({ - history: createWebHistory(), - routes -}) - -// Global navigation guards -router.beforeEach((to, from, next) => { - // Set page title - if (to.meta?.title) { - document.title = `${to.meta.title} - Daily Notification Test` - } - - // Add loading state - console.log(`🔄 Navigating from ${String(from.name) || 'unknown'} to ${String(to.name) || 'unknown'}`) - - next() -}) - -router.afterEach((to) => { - // Clear any previous errors on successful navigation - console.log(`✅ Navigation completed: ${String(to.name) || 'unknown'}`) -}) - -export default router diff --git a/test-apps/android-test/src/stores/notifications.ts b/test-apps/android-test/src/stores/notifications.ts deleted file mode 100644 index 52a7a0a..0000000 --- a/test-apps/android-test/src/stores/notifications.ts +++ /dev/null @@ -1,299 +0,0 @@ -/** - * Notifications Store - Notification Management State - * - * Pinia store for managing notification scheduling, status, and history - * - * @author Matthew Raymer - * @version 1.0.0 - */ - -import { defineStore } from 'pinia' -import { ref, computed } from 'vue' -import { Capacitor } from '@capacitor/core' - -export interface ScheduledNotification { - id: string - title: string - body: string - scheduledTime: number - deliveredAt?: number - status: 'scheduled' | 'delivered' | 'cancelled' -} - -export interface NotificationHistory { - id: string - title: string - body: string - scheduledTime: number - deliveredAt: number - clicked: boolean - dismissed: boolean -} - -export const useNotificationsStore = defineStore('notifications', () => { - // State - const scheduledNotifications = ref([]) - const notificationHistory = ref([]) - const isScheduling = ref(false) - const lastError = ref(null) - - // Getters - const hasScheduledNotifications = computed(() => - scheduledNotifications.value.length > 0 - ) - - const nextNotification = computed(() => { - const future = scheduledNotifications.value - .filter(n => n.status === 'scheduled' && n.scheduledTime > Date.now()) - .sort((a, b) => a.scheduledTime - b.scheduledTime) - return future.length > 0 ? future[0] : null - }) - - const notificationCount = computed(() => - scheduledNotifications.value.length - ) - - // Actions - async function scheduleNotification(options: { - time: string - title?: string - body?: string - sound?: boolean - priority?: string - url?: string - }): Promise { - if (!Capacitor.isNativePlatform()) { - throw new Error('DailyNotification plugin only available on native platforms') - } - - if (!window.DailyNotification) { - throw new Error('DailyNotification plugin not loaded. Please restart the app.') - } - - try { - isScheduling.value = true - lastError.value = null - - await window.DailyNotification.scheduleDailyNotification(options) - - // Add to local state (we'll get the actual ID from the plugin) - const notification: ScheduledNotification = { - id: `temp-${Date.now()}`, - title: options.title || 'Daily Update', - body: options.body || 'Your daily notification is ready', - scheduledTime: parseTimeToTimestamp(options.time), - status: 'scheduled' - } - - scheduledNotifications.value.push(notification) - - console.log('✅ Notification scheduled successfully') - - } catch (error) { - const errorMessage = (error as Error).message - lastError.value = errorMessage - console.error('❌ Failed to schedule notification:', errorMessage) - throw error - } finally { - isScheduling.value = false - } - } - - async function scheduleReminder(options: { - id: string - title: string - body: string - time: string - sound?: boolean - vibration?: boolean - priority?: string - repeatDaily?: boolean - timezone?: string - }): Promise { - if (!Capacitor.isNativePlatform()) { - throw new Error('DailyNotification plugin only available on native platforms') - } - - if (!window.DailyNotification) { - throw new Error('DailyNotification plugin not loaded. Please restart the app.') - } - - try { - isScheduling.value = true - lastError.value = null - - await window.DailyNotification.scheduleDailyReminder(options) - - // Add to local state - const notification: ScheduledNotification = { - id: options.id, - title: options.title, - body: options.body, - scheduledTime: parseTimeToTimestamp(options.time), - status: 'scheduled' - } - - scheduledNotifications.value.push(notification) - - console.log('✅ Reminder scheduled successfully') - - } catch (error) { - const errorMessage = (error as Error).message - lastError.value = errorMessage - console.error('❌ Failed to schedule reminder:', errorMessage) - throw error - } finally { - isScheduling.value = false - } - } - - async function cancelReminder(reminderId: string): Promise { - if (!Capacitor.isNativePlatform()) { - throw new Error('DailyNotification plugin only available on native platforms') - } - - if (!window.DailyNotification) { - throw new Error('DailyNotification plugin not loaded. Please restart the app.') - } - - try { - isScheduling.value = true - lastError.value = null - - await window.DailyNotification.cancelDailyReminder({ reminderId }) - - // Update local state - const index = scheduledNotifications.value.findIndex(n => n.id === reminderId) - if (index !== -1) { - scheduledNotifications.value[index].status = 'cancelled' - } - - console.log('✅ Reminder cancelled successfully') - - } catch (error) { - const errorMessage = (error as Error).message - lastError.value = errorMessage - console.error('❌ Failed to cancel reminder:', errorMessage) - throw error - } finally { - isScheduling.value = false - } - } - - async function checkStatus(): Promise { - if (!Capacitor.isNativePlatform()) { - console.warn('DailyNotification plugin only available on native platforms') - return - } - - if (!window.DailyNotification) { - console.warn('DailyNotification plugin not loaded') - return - } - - try { - const status = await window.DailyNotification.checkStatus() - console.log('📊 Notification Status:', status) - - // Update app store with status - const { useAppStore } = await import('@/stores/app') - const appStore = useAppStore() - appStore.setNotificationStatus(status) - - } catch (error) { - console.error('❌ Failed to check notification status:', error) - } - } - - async function getLastNotification(): Promise { - if (!Capacitor.isNativePlatform()) { - console.warn('DailyNotification plugin only available on native platforms') - return - } - - if (!window.DailyNotification) { - console.warn('DailyNotification plugin not loaded') - return - } - - try { - const lastNotification = await window.DailyNotification.getLastNotification() - console.log('📱 Last Notification:', lastNotification) - - // Add to history - const historyItem: NotificationHistory = { - id: lastNotification.id, - title: lastNotification.title, - body: lastNotification.body, - scheduledTime: lastNotification.scheduledTime, - deliveredAt: lastNotification.deliveredAt, - clicked: false, - dismissed: false - } - - notificationHistory.value.unshift(historyItem) - - // Keep only last 50 items - if (notificationHistory.value.length > 50) { - notificationHistory.value = notificationHistory.value.slice(0, 50) - } - - } catch (error) { - console.error('❌ Failed to get last notification:', error) - } - } - - function clearError(): void { - lastError.value = null - } - - function clearHistory(): void { - notificationHistory.value = [] - } - - // Helper function to parse time string to timestamp - function parseTimeToTimestamp(timeString: string): number { - const [hours, minutes] = timeString.split(':').map(Number) - const now = new Date() - const scheduled = new Date() - scheduled.setHours(hours, minutes, 0, 0) - - // If time has passed today, schedule for tomorrow - if (scheduled <= now) { - scheduled.setDate(scheduled.getDate() + 1) - } - - return scheduled.getTime() - } - - // Reset store - function $reset(): void { - scheduledNotifications.value = [] - notificationHistory.value = [] - isScheduling.value = false - lastError.value = null - } - - return { - // State - scheduledNotifications, - notificationHistory, - isScheduling, - lastError, - - // Getters - hasScheduledNotifications, - nextNotification, - notificationCount, - - // Actions - scheduleNotification, - scheduleReminder, - cancelReminder, - checkStatus, - getLastNotification, - clearError, - clearHistory, - $reset - } -}) diff --git a/test-apps/android-test/src/views/HistoryView.vue b/test-apps/android-test/src/views/HistoryView.vue deleted file mode 100644 index a322ecc..0000000 --- a/test-apps/android-test/src/views/HistoryView.vue +++ /dev/null @@ -1,144 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/views/HomeView.vue b/test-apps/android-test/src/views/HomeView.vue deleted file mode 100644 index aeb8e61..0000000 --- a/test-apps/android-test/src/views/HomeView.vue +++ /dev/null @@ -1,260 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/views/LogsView.vue b/test-apps/android-test/src/views/LogsView.vue deleted file mode 100644 index e2c97db..0000000 --- a/test-apps/android-test/src/views/LogsView.vue +++ /dev/null @@ -1,629 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/views/NotFoundView.vue b/test-apps/android-test/src/views/NotFoundView.vue deleted file mode 100644 index 91f4b28..0000000 --- a/test-apps/android-test/src/views/NotFoundView.vue +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/views/NotificationsView.vue b/test-apps/android-test/src/views/NotificationsView.vue deleted file mode 100644 index e69db72..0000000 --- a/test-apps/android-test/src/views/NotificationsView.vue +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/views/ScheduleView.vue b/test-apps/android-test/src/views/ScheduleView.vue deleted file mode 100644 index 822b82a..0000000 --- a/test-apps/android-test/src/views/ScheduleView.vue +++ /dev/null @@ -1,518 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/src/views/StatusView.vue b/test-apps/android-test/src/views/StatusView.vue deleted file mode 100644 index 6033dce..0000000 --- a/test-apps/android-test/src/views/StatusView.vue +++ /dev/null @@ -1,310 +0,0 @@ - - - - - - - diff --git a/test-apps/android-test/tsconfig.json b/test-apps/android-test/tsconfig.json deleted file mode 100644 index d8c617b..0000000 --- a/test-apps/android-test/tsconfig.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "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": false, - "noUnusedParameters": false, - "noFallthroughCasesInSwitch": true, - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"], - "@components/*": ["./src/components/*"], - "@views/*": ["./src/views/*"], - "@stores/*": ["./src/stores/*"], - "@services/*": ["./src/services/*"], - "@types/*": ["./src/types/*"], - "@utils/*": ["./src/utils/*"] - }, - "types": [ - "vite/client", - "node" - ] - }, - "include": [ - "env.d.ts", - "src/**/*", - "src/**/*.vue" - ], - "exclude": [ - "src/**/__tests__/*", - "node_modules", - "dist" - ] -} \ No newline at end of file diff --git a/test-apps/android-test/vite.config.ts b/test-apps/android-test/vite.config.ts deleted file mode 100644 index ea79110..0000000 --- a/test-apps/android-test/vite.config.ts +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Vite Configuration for Daily Notification Test App - * - * Vue 3 + TypeScript + Capacitor setup with vue-facing-decorator support - * - * @author Matthew Raymer - * @version 1.0.0 - */ - -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import { resolve } from 'path' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue()], - - // Build configuration for Capacitor - build: { - outDir: 'dist', - assetsDir: 'assets', - sourcemap: true, - rollupOptions: { - input: { - main: resolve(__dirname, 'index.html') - } - } - }, - - // Development server configuration - server: { - host: '0.0.0.0', - port: 3000, - strictPort: true, - hmr: { - port: 3001 - } - }, - - // Preview server configuration - preview: { - host: '0.0.0.0', - port: 4173, - strictPort: true - }, - - // Path resolution - resolve: { - alias: { - '@': resolve(__dirname, 'src'), - '@components': resolve(__dirname, 'src/components'), - '@views': resolve(__dirname, 'src/views'), - '@stores': resolve(__dirname, 'src/stores'), - '@services': resolve(__dirname, 'src/services'), - '@types': resolve(__dirname, 'src/types'), - '@utils': resolve(__dirname, 'src/utils') - } - }, - - // TypeScript configuration - esbuild: { - target: 'es2020' - }, - - // Define global constants - define: { - __VUE_OPTIONS_API__: true, - __VUE_PROD_DEVTOOLS__: false - } -}) diff --git a/test-apps/android-test/webpack.config.js b/test-apps/android-test/webpack.config.js deleted file mode 100644 index 2edfeef..0000000 --- a/test-apps/android-test/webpack.config.js +++ /dev/null @@ -1,33 +0,0 @@ -const path = require('path'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); - -module.exports = { - entry: './src/index.ts', - module: { - rules: [ - { - test: /\.ts$/, - use: 'ts-loader', - exclude: /node_modules/, - }, - ], - }, - resolve: { - extensions: ['.ts', '.js'], - }, - output: { - filename: 'bundle.js', - path: path.resolve(__dirname, 'dist'), - clean: true, - }, - plugins: [ - new HtmlWebpackPlugin({ - template: './src/index.html', - }), - ], - devServer: { - static: './dist', - port: 3000, - hot: true, - }, -}; diff --git a/test-apps/check-environment.sh b/test-apps/check-environment.sh deleted file mode 100755 index 365e08f..0000000 --- a/test-apps/check-environment.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/bash - -# Environment Verification Script for Test Apps -echo "🔍 Verifying Test Apps Environment..." -echo "" - -# Check Node.js -echo "📦 Node.js:" -if command -v node &> /dev/null; then - node_version=$(node --version) - echo " ✅ Installed: $node_version" - - # Check if version is 18+ - major_version=$(echo $node_version | cut -d'.' -f1 | sed 's/v//') - if [ "$major_version" -ge 18 ]; then - echo " ✅ Version 18+ (compatible)" - else - echo " ⚠️ Version $major_version (requires 18+)" - fi -else - echo " ❌ Not installed" -fi - -# Check npm -echo "" -echo "📦 npm:" -if command -v npm &> /dev/null; then - npm_version=$(npm --version) - echo " ✅ Installed: $npm_version" -else - echo " ❌ Not installed" -fi - -# Check Capacitor CLI -echo "" -echo "⚡ Capacitor CLI:" -if command -v cap &> /dev/null; then - cap_version=$(cap --version) - echo " ✅ Installed: $cap_version" -else - echo " ❌ Not installed (will be installed by setup scripts)" -fi - -# Check Android (if available) -echo "" -echo "📱 Android:" -if command -v studio &> /dev/null; then - echo " ✅ Android Studio installed" -else - echo " ❌ Android Studio not found" -fi - -if [ ! -z "$ANDROID_HOME" ]; then - echo " ✅ ANDROID_HOME set: $ANDROID_HOME" -else - echo " ❌ ANDROID_HOME not set" -fi - -if command -v java &> /dev/null; then - java_version=$(java -version 2>&1 | head -n 1) - echo " ✅ Java: $java_version" -else - echo " ❌ Java not found" -fi - -# Check iOS (if on macOS) -echo "" -echo "🍎 iOS:" -if [[ "$OSTYPE" == "darwin"* ]]; then - if command -v xcodebuild &> /dev/null; then - xcode_version=$(xcodebuild -version | head -n 1) - echo " ✅ Xcode: $xcode_version" - else - echo " ❌ Xcode not installed" - fi - - if command -v xcrun &> /dev/null; then - echo " ✅ Xcode Command Line Tools available" - else - echo " ❌ Xcode Command Line Tools not installed" - fi -else - echo " ⚠️ iOS development requires macOS" -fi - -# Check Electron -echo "" -echo "⚡ Electron:" -if command -v npx &> /dev/null; then - electron_version=$(npx electron --version 2>/dev/null) - if [ $? -eq 0 ]; then - echo " ✅ Electron available: $electron_version" - else - echo " ⚠️ Electron not installed (will be installed by setup)" - fi -else - echo " ❌ npx not available" -fi - -echo "" -echo "📋 Summary:" -echo " - Node.js 18+: $(command -v node &> /dev/null && node --version | cut -d'.' -f1 | sed 's/v//' | awk '{if($1>=18) print "✅"; else print "❌"}' || echo "❌")" -echo " - npm: $(command -v npm &> /dev/null && echo "✅" || echo "❌")" -echo " - Android Studio: $(command -v studio &> /dev/null && echo "✅" || echo "❌")" -echo " - Xcode: $(command -v xcodebuild &> /dev/null && echo "✅" || echo "❌")" -echo " - Electron: $(command -v npx &> /dev/null && npx electron --version &> /dev/null && echo "✅" || echo "❌")" - -echo "" -echo "🚀 Next Steps:" -echo " 1. Install missing prerequisites" -echo " 2. Run setup scripts: ./setup-*.sh" -echo " 3. See SETUP_GUIDE.md for detailed instructions" diff --git a/test-apps/config/timesafari-config.json b/test-apps/config/timesafari-config.json deleted file mode 100644 index 9303e1a..0000000 --- a/test-apps/config/timesafari-config.json +++ /dev/null @@ -1,152 +0,0 @@ -{ - "timesafari": { - "appId": "app.timesafari.test", - "appName": "TimeSafari Test", - "version": "1.0.0", - "description": "Test app for TimeSafari Daily Notification Plugin integration" - }, - "endorser": { - "baseUrl": "http://localhost:3001", - "apiVersion": "v2", - "endpoints": { - "offers": "/api/v2/report/offers", - "offersToPlans": "/api/v2/report/offersToPlansOwnedByMe", - "plansLastUpdated": "/api/v2/report/plansLastUpdatedBetween", - "notificationsBundle": "/api/v2/report/notifications/bundle" - }, - "authentication": { - "type": "Bearer", - "token": "test-jwt-token-12345", - "headers": { - "Authorization": "Bearer test-jwt-token-12345", - "Content-Type": "application/json", - "X-Privacy-Level": "user-controlled" - } - }, - "pagination": { - "defaultLimit": 50, - "maxLimit": 100, - "hitLimitThreshold": 50 - } - }, - "notificationTypes": { - "offers": { - "enabled": true, - "types": [ - "new_to_me", - "changed_to_me", - "new_to_projects", - "changed_to_projects", - "new_to_favorites", - "changed_to_favorites" - ] - }, - "projects": { - "enabled": true, - "types": [ - "local_new", - "local_changed", - "content_interest_new", - "favorited_changed" - ] - }, - "people": { - "enabled": true, - "types": [ - "local_new", - "local_changed", - "content_interest_new", - "favorited_changed", - "contacts_changed" - ] - }, - "items": { - "enabled": true, - "types": [ - "local_new", - "local_changed", - "favorited_changed" - ] - } - }, - "scheduling": { - "contentFetch": { - "schedule": "0 8 * * *", - "time": "08:00", - "description": "8 AM daily - fetch community updates" - }, - "userNotification": { - "schedule": "0 9 * * *", - "time": "09:00", - "description": "9 AM daily - notify users of community updates" - } - }, - "testData": { - "userDid": "did:example:testuser123", - "starredPlanIds": [ - "plan-community-garden", - "plan-local-food", - "plan-sustainability" - ], - "lastKnownOfferId": "01HSE3R9MAC0FT3P3KZ382TWV7", - "lastKnownPlanId": "01HSE3R9MAC0FT3P3KZ382TWV8", - "mockOffers": [ - { - "jwtId": "01HSE3R9MAC0FT3P3KZ382TWV7", - "handleId": "offer-web-dev-001", - "offeredByDid": "did:example:offerer123", - "recipientDid": "did:example:testuser123", - "objectDescription": "Web development services for community project", - "unit": "USD", - "amount": 1000, - "amountGiven": 500, - "amountGivenConfirmed": 250 - } - ], - "mockProjects": [ - { - "plan": { - "jwtId": "01HSE3R9MAC0FT3P3KZ382TWV8", - "handleId": "plan-community-garden", - "name": "Community Garden Project", - "description": "Building a community garden for local food production", - "issuerDid": "did:example:issuer123", - "agentDid": "did:example:agent123" - }, - "wrappedClaimBefore": null - } - ] - }, - "callbacks": { - "offers": { - "enabled": true, - "localHandler": "handleOffersNotification" - }, - "projects": { - "enabled": true, - "localHandler": "handleProjectsNotification" - }, - "people": { - "enabled": true, - "localHandler": "handlePeopleNotification" - }, - "items": { - "enabled": true, - "localHandler": "handleItemsNotification" - }, - "communityAnalytics": { - "enabled": true, - "endpoint": "http://localhost:3001/api/analytics/community-events", - "headers": { - "Content-Type": "application/json", - "X-Privacy-Level": "aggregated" - } - } - }, - "observability": { - "enableLogging": true, - "logLevel": "debug", - "enableMetrics": true, - "enableHealthChecks": true - } -} diff --git a/test-apps/daily-notification-test/.editorconfig b/test-apps/daily-notification-test/.editorconfig new file mode 100644 index 0000000..3b510aa --- /dev/null +++ b/test-apps/daily-notification-test/.editorconfig @@ -0,0 +1,8 @@ +[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue,css,scss,sass,less,styl}] +charset = utf-8 +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true +end_of_line = lf +max_line_length = 100 diff --git a/test-apps/daily-notification-test/.gitattributes b/test-apps/daily-notification-test/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/test-apps/daily-notification-test/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/test-apps/daily-notification-test/.gitignore b/test-apps/daily-notification-test/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/test-apps/daily-notification-test/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/test-apps/daily-notification-test/README.md b/test-apps/daily-notification-test/README.md new file mode 100644 index 0000000..9c44d3a --- /dev/null +++ b/test-apps/daily-notification-test/README.md @@ -0,0 +1,48 @@ +# daily-notification-test + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VS Code](https://code.visualstudio.com/) + [Vue (Official)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Recommended Browser Setup + +- Chromium-based browsers (Chrome, Edge, Brave, etc.): + - [Vue.js devtools](https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd) + - [Turn on Custom Object Formatter in Chrome DevTools](http://bit.ly/object-formatters) +- Firefox: + - [Vue.js devtools](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/) + - [Turn on Custom Object Formatter in Firefox DevTools](https://fxdx.dev/firefox-devtools-custom-object-formatters/) + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vite.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/test-apps/daily-notification-test/android/.gitignore b/test-apps/daily-notification-test/android/.gitignore new file mode 100644 index 0000000..48354a3 --- /dev/null +++ b/test-apps/daily-notification-test/android/.gitignore @@ -0,0 +1,101 @@ +# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore + +# Built application files +*.apk +*.aar +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ +# Uncomment the following line in case you need and you don't have the release build type files in your app +# release/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +# Android Studio 3 in .gitignore file. +.idea/caches +.idea/modules.xml +# Comment next line if keeping position of elements in Navigation Editor is relevant for you +.idea/navEditor.xml + +# Keystore files +# Uncomment the following lines if you do not want to check your keystore files in. +#*.jks +#*.keystore + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild +.cxx/ + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md + +# Version control +vcs.xml + +# lint +lint/intermediates/ +lint/generated/ +lint/outputs/ +lint/tmp/ +# lint/reports/ + +# Android Profiling +*.hprof + +# Cordova plugins for Capacitor +capacitor-cordova-android-plugins + +# Copied web assets +app/src/main/assets/public + +# Generated Config files +app/src/main/assets/capacitor.config.json +app/src/main/assets/capacitor.plugins.json +app/src/main/res/xml/config.xml diff --git a/test-apps/daily-notification-test/android/app/.gitignore b/test-apps/daily-notification-test/android/app/.gitignore new file mode 100644 index 0000000..043df80 --- /dev/null +++ b/test-apps/daily-notification-test/android/app/.gitignore @@ -0,0 +1,2 @@ +/build/* +!/build/.npmkeep diff --git a/test-apps/daily-notification-test/android/app/build.gradle b/test-apps/daily-notification-test/android/app/build.gradle new file mode 100644 index 0000000..14c6924 --- /dev/null +++ b/test-apps/daily-notification-test/android/app/build.gradle @@ -0,0 +1,54 @@ +apply plugin: 'com.android.application' + +android { + namespace "com.timesafari.dailynotification.test" + compileSdkVersion rootProject.ext.compileSdkVersion + defaultConfig { + applicationId "com.timesafari.dailynotification.test" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + aaptOptions { + // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. + // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61 + ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~' + } + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +repositories { + flatDir{ + dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs' + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" + implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion" + implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion" + implementation project(':capacitor-android') + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" + implementation project(':capacitor-cordova-android-plugins') +} + +apply from: 'capacitor.build.gradle' + +try { + def servicesJSON = file('google-services.json') + if (servicesJSON.text) { + apply plugin: 'com.google.gms.google-services' + } +} catch(Exception e) { + logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work") +} diff --git a/test-apps/daily-notification-test/android/app/capacitor.build.gradle b/test-apps/daily-notification-test/android/app/capacitor.build.gradle new file mode 100644 index 0000000..fdb4970 --- /dev/null +++ b/test-apps/daily-notification-test/android/app/capacitor.build.gradle @@ -0,0 +1,19 @@ +// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN + +android { + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } +} + +apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" +dependencies { + + +} + + +if (hasProperty('postBuildExtras')) { + postBuildExtras() +} diff --git a/test-apps/daily-notification-test/android/app/proguard-rules.pro b/test-apps/daily-notification-test/android/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/test-apps/daily-notification-test/android/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/test-apps/daily-notification-test/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java b/test-apps/daily-notification-test/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java new file mode 100644 index 0000000..f2c2217 --- /dev/null +++ b/test-apps/daily-notification-test/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.getcapacitor.myapp; + +import static org.junit.Assert.*; + +import android.content.Context; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + assertEquals("com.getcapacitor.app", appContext.getPackageName()); + } +} diff --git a/test-apps/daily-notification-test/android/app/src/main/AndroidManifest.xml b/test-apps/daily-notification-test/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..5c411e0 --- /dev/null +++ b/test-apps/daily-notification-test/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-apps/daily-notification-test/android/app/src/main/java/com/timesafari/dailynotification/test/MainActivity.java b/test-apps/daily-notification-test/android/app/src/main/java/com/timesafari/dailynotification/test/MainActivity.java new file mode 100644 index 0000000..d9ffcc7 --- /dev/null +++ b/test-apps/daily-notification-test/android/app/src/main/java/com/timesafari/dailynotification/test/MainActivity.java @@ -0,0 +1,5 @@ +package com.timesafari.dailynotification.test; + +import com.getcapacitor.BridgeActivity; + +public class MainActivity extends BridgeActivity {} diff --git a/test-apps/daily-notification-test/android/app/src/main/res/drawable-land-hdpi/splash.png b/test-apps/daily-notification-test/android/app/src/main/res/drawable-land-hdpi/splash.png new file mode 100644 index 0000000000000000000000000000000000000000..e31573b4fc93e60d171f4046c0220e1463075d9e GIT binary patch literal 7705 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 wKmFJ0_JHhk1&0B>;%YXATM literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/android/app/src/main/res/drawable-land-mdpi/splash.png b/test-apps/daily-notification-test/android/app/src/main/res/drawable-land-mdpi/splash.png new file mode 100644 index 0000000000000000000000000000000000000000..f7a64923ea1a0565d25fa139c176d6bf42184e48 GIT binary patch literal 4040 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 XyOn+%7f`N3b2T^T3uj5+eShz7v)7qy literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/android/app/src/main/res/drawable-land-xhdpi/splash.png b/test-apps/daily-notification-test/android/app/src/main/res/drawable-land-xhdpi/splash.png new file mode 100644 index 0000000000000000000000000000000000000000..807725501bdd92e94e51e7b2b0006f69e0083a0b GIT binary patch literal 9251 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 literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/android/app/src/main/res/drawable-land-xxhdpi/splash.png b/test-apps/daily-notification-test/android/app/src/main/res/drawable-land-xxhdpi/splash.png new file mode 100644 index 0000000000000000000000000000000000000000..14c6c8fe39fcd51a0414866ad28cbe8ff3acb060 GIT binary patch literal 13984 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®q@N z14_H8ofW)l{|J8q+a)eH)I0r)>WXdzV%7J>PA~6_J)KLT90iYa^K=Wz7D!OybzqSru=f4?|KFl;Y)gP_H6V4x`~kZ6fE(xM1&;?72-TZNk+0 zr+Crr5yl%Iy@vfmt3eYFl!jIvPGFz^8Ek+2`48O1_pCX3xNWh-zBa{rIcc%+=|XVj zANYTg&s}TKb#OztQrCW(Xk?V^i{`q~%HtcveTxq(_HKeC9GzrtguMT4Nvs@KakPTA z9>*8bBZmLz`lK5=l)=b|=dT3a5ag^a1^znZyx5QKfUb1b9yacArRp%3@QWo(hrsCU z-K!-=jDmv!zb7XT>)r|-Z0Ry}lk2;dk-ECqMwr_nKN#x*X6~B5hVIN>6$1HwBz3Of z=Pk){AL5*=d90f17_qZEJLm;Q%WMdX=*N&!ki@E&cy7?>{1ssAH(tACtp*r@d^til z)x(1#6(kPD+joSF&J3sxJU@{-sWCS+pZq{Gsx=?z4wP;>?)1yHv0?X?VP{}cX4~aH zxeBPKw_rgW8rvewS1W2#^y+c>-183iMbJCqc38RN_o~__9-n|jcd&oA`m7*&Fqqpc z;Tev*0LS-ZK47Sq1unfvP1S43uA12P?PJmI8BeTYPr~R*tYUm^0;U%Hmu?bSZHEK6 zPjsW=E67Kq-&trmf;)UkmRABH2U)V)-eRT$j(%G12lLMsThSsU10iP#{)ZnvjzN$d z*K%P3`}oqyvpWP~venr>3viH8^`)Ma*=B31hw*Q+tqE>i2y7w!(o^lI^Yss^=tHW( z;cnCT(%B1gLz+TRGW9roFjI1EQTu-u`(f#RmZ8;FSN(bsC1J;+(i_R6mrW=yYx$cy z#%QKVrEx~kVMg~yo?^N28Wnk6x%L;J8i|*|ANEiNjq(Vhzuzl3ikpA*G!Z}kLAzAI z9qnySo%D|AuJj12%h;Otqjs(>LPj?rNdeU8so>P(C>XMzlho94ZD#w=cCOOU;=3&^ zsqAG!i{~lY271D|m>ztPV`)X@FO_;`wPjppYNQpM+ncvtz1lZjN>!Q^*I}T%uP78Z7tbV2$q3W_)14=kLFyJ z1GqL6T>ClgeZorL!}xP4f%OB_EsmJ`uw7dGWNV9OLlhb|UMpVhc{4@Bhh`tO!ZqzD zhusd<=K^ah!L@gQ?6dOpI-ge^e>S5W9eII57Zu16eU?GRbgKTeVk9yS{iK|O(zLR> zheb?;jwGCHS80NCn=jKxgJ>}qu4l%5NPihjzazGv#J?Jcyl;<#IW&x4mm>nrW8>}C z3U@aeD~)*F(0o^2{GnKVm$Jr#aZE ztl~TOkM^SdzJapQ((!-i8b!RkVQBKkL`2ZCBuy!qI1L{3Er526plVols~68U-^9Px zR(3{j;Z9RHX^muc0dUywJ|`yyZFf=k&-Gb#m4u73Lm5Ks%BfHj%2|gjn#i> zLC5pO$2Em9H;qoKQmMtl<@wgtPF1%2HariD5O~u>8=^*J&au~JH%Ih@&2Uging3U_ z0bzfKucW$ZHSx}!#buB?+-J)%RQbbXM-!BJTS&#dU_@lxU6>te2O+9 z@F{F{Nb!;{Cd`Gx+$G?11aB~S#wIH%D=*=7f7H@D@%B1)&bF$@t3JDq4l*%(wJTlh zo`?uMq{YilKUewPNaC)GuOr<8j9&ofqRU__BRUX^x8Cj3a;a$rXzgXqW>LR#CUn%~m)t zYC&ol(gAkbc^fd`xWU&bk5vT6KbFmsR=O78Bn%t7 znbw&=c+|T&#r+bls5rU6D#HMvqA<|;)BV%jOMonkm^p$7Vcel-Wwn$=uAJv&(8W>% z9))Fxpl*(%E#wFm_m!U~2HqgZs^2vaGeY(UfYKrSHV}w^D0N6!se5Ewy)Yy-!(2

aKj2hWG7>znxs|SE zN4rHtiSPqLskWp(?(_YYwgq+1@8v+~8As|(bC>$D(atG3ZE8-ZM3SVcg|vHQz$I=!(A`k`5= zOqR>&%G)$)k*QLz7MTB9wleWpv&N9Sta64wy}3Ytd?x!Ja8z>(z~(3UNFu^eFmn#6 zw!!gUxOuZi$PQIs*ixfZR3iLyADJ z5&s%tPfk>V!x|A-;oq%1!yk9H$UBP0ToA*EDtz(^!_AnF1bBQ7joj|? z5b)gSI8c8O$PYFE!vXJ<4gebg*9G9P2wcB{#kv0FItc5T@PDNo)}Rh4Us}L{e}xzW zhwt`)j`M)mP=G6H0;^&q=I0{jU%bIRkF#uLF;{vVC&H|_uc literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/android/app/src/main/res/drawable-land-xxxhdpi/splash.png b/test-apps/daily-notification-test/android/app/src/main/res/drawable-land-xxxhdpi/splash.png new file mode 100644 index 0000000000000000000000000000000000000000..244ca2506dbe0fd8f6a05520ac7d1a629ea81438 GIT binary patch literal 17683 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 literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/android/app/src/main/res/drawable-port-xxhdpi/splash.png b/test-apps/daily-notification-test/android/app/src/main/res/drawable-port-xxhdpi/splash.png new file mode 100644 index 0000000000000000000000000000000000000000..bfabe6871a17a5e95b78fb30d49b7d2b4d2fe4c0 GIT binary patch literal 13346 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

VwO4Hu8X}%XHUAz_J@50rzbkIsat>4oWtQt< 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 literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/android/app/src/main/res/drawable-port-xxxhdpi/splash.png b/test-apps/daily-notification-test/android/app/src/main/res/drawable-port-xxxhdpi/splash.png new file mode 100644 index 0000000000000000000000000000000000000000..6929071268eb03ee0f088142b6523566b78550e2 GIT binary patch literal 17489 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 KR&><$`~L^lv%S~= literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/test-apps/daily-notification-test/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..c7bd21d --- /dev/null +++ b/test-apps/daily-notification-test/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/test-apps/daily-notification-test/android/app/src/main/res/drawable/ic_launcher_background.xml b/test-apps/daily-notification-test/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..d5fccc5 --- /dev/null +++ b/test-apps/daily-notification-test/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-apps/daily-notification-test/android/app/src/main/res/drawable/splash.png b/test-apps/daily-notification-test/android/app/src/main/res/drawable/splash.png new file mode 100644 index 0000000000000000000000000000000000000000..f7a64923ea1a0565d25fa139c176d6bf42184e48 GIT binary patch literal 4040 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 XyOn+%7f`N3b2T^T3uj5+eShz7v)7qy literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/android/app/src/main/res/layout/activity_main.xml b/test-apps/daily-notification-test/android/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..b5ad138 --- /dev/null +++ b/test-apps/daily-notification-test/android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/test-apps/daily-notification-test/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/test-apps/daily-notification-test/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..036d09b --- /dev/null +++ b/test-apps/daily-notification-test/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/test-apps/daily-notification-test/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/test-apps/daily-notification-test/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..036d09b --- /dev/null +++ b/test-apps/daily-notification-test/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/test-apps/daily-notification-test/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/test-apps/daily-notification-test/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..c023e50595074292c7361183a64de08cf9686c9c GIT binary patch literal 2786 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 literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/test-apps/daily-notification-test/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..2127973b2d318df7085734d236d0ec649a2b0292 GIT binary patch literal 3450 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 literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/test-apps/daily-notification-test/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d1e077104cd61e6a4c3707e87363b523077245a GIT binary patch literal 3981 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 nm0GElTB(&OnKI&V600000NkvXXu0mjff+~0a literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/test-apps/daily-notification-test/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..df0f15880bee46332dfc6622583215194f948b0f GIT binary patch literal 5036 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 literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/test-apps/daily-notification-test/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..6cdf97c1196d48e9833487ff6de7c4cfc4e1232d GIT binary patch literal 6644 zcmZ{pXFL_||NoDW?HrtJha-DLIVbC69wc;}LWs%=Q3!R8%&a5HUWX12AsLxPvg`0M z4%vI3LpIs#@B6?1yK#+s*Lz*p^YOagQKokd*qHg50RRA-;ceu-i#6_lgYojkOx2(J z4gm1|FhpvbVaC=zTE$&4#|MuVHK$myjH# zaR><-@RxJ^M@VC6^+G<*Okqst5fUDIQ9WVJ5cXClVR6gh zFmq4#{2DHp(xxs?nQ3QtH_YQje$8KoOpb$NxwsXr7j(5D24KC~kbOKX$ob|zL&y1< zvY)r2?2A%s8p86w&=5Jg)zhrGPn0~G~ z#k1it{z_(l*yq0NgX*Uf!dU^I^6@0F-pV%RX+%(uH4~wcVOg@l&Wf8)=nF?{6(fT6 zT1ez={Z8gSw!~xWMl&~ln&9tcO2&!r-%Izrj;n1X^5xl>A8r7r1sWS&|C?-No)*dq z@%SeY;bmZ?h13jo#qTT^gaV&8=^8ZKwKk4kb$~w{W)nE?xw;8@j=|MPc*-*yXR-lN zOV;2?#Y{50B9kp}W^D1Dea72;(#9?8QdP3{g5Syd70l%+8PEI23PSm@`|YV zRg5K62lJnK%|@)k&&wgR&7lm+EjB%vst9|Toj`t=d@Qs*-%_P-1FMjHZ-U(ae=%sPO`E95q@ za+?(wg5XR#Af8 z84W_KwbOh=6e!vuR<0GcPv#=bh!I;6_^TIZr|N&{dCe2dFdM4)SkfStjlZnn=HpZWm8bo8B*7vIZvQ3A zM!m(+hdm(}{Fdg4w{EfMJ8%ywCCS`40?{u?rkfU5ib)^`Z29hq8li?1IybXpttJ$>fDi6PPTtg!z zx7%}>e9%%Tomft}4Wxsk`1zjNDu3j`4JUOLuO$b>%jEOkf$n?A24h$%CtQr!{OydG zMF|M>nA<~iVpdU)Nq}qMe@Z;w5Mi+J7fx=O1g;smIscE_|05i-m+Kt~mjRevRML>-?0U z=+0@B9d*Zv2_tqBSjhiE^-ufE%x8*v-};%jp34f8zIr`0&>FN0Oken=;InO_dhQ3A zaIak!n`ktU)E)Gn&AAI}fSuABJiN+0Z!&$XYi@hfLH_H;s%3|0>}i%BCCDYddffPB zO@c6@@Od5Tp=0wgckS^v?!#S+Xq&>tAJiDNK1mcizpO>^vlzuk4qdxphlp!Pb7`EV zu78*_U(?PG&^A~QSA*BVYawecA$F!K+ie?#QhQ!RzyEx=hIJc7#JyeqPraOo6eQz>1X`9 z7C%08Tf|z>z9+$7)PQTZEkh~u-*aah%=#M-K@kfa{hafR(`IgRW&`RQ%*5%lGMR)x12Yg-{KK5I05|>VCy^Cx2;Tl>g4c{#%$KTJRzx^ zLLXNUVFj0~2y6t3G^#py6@R;lS7Lx1d^?`rZ)3O!RST$5{YeccG+_W47<^H*+t$2I z4$aIn11#DbK;UC5_C={MxQC zbFR_5$b1P#E(o84aYP)z#yE@0Q#PYmTfcUi#|Ua-E3gv9`7U*-;?+(ApQVteJaQGU zA`PchToSIEtZJ)$fNL#~x#+t`-v&!;>;40^hYEkc7g;FFC+btBH_Mbl+NMMqzfOHu zvi#IL`mZcJ=0~B1Jn0D3RQa?(4>IW~(n}05ikg=df{vfB*uCMcZj1E#zR*$$ZnCNyO(xy^0m`xB40j0#li-YyYRk+i ztAdMTFi_%VHhCoFxaCjq(g;q^V#BAJ{fZ`1;0P+Jv>;+FnkHF93(kq^wVT>AkWD;V z5%Z=r-G4RfIvx}556tb$Wcy&X@IYOzqIf)6O-lo3dXx1#I^{j8N~KHEzTI*djs|2$ zN+VQZXYNbD1tFVUzfEJm;Fg=Ss+++Stp68TFwqGL%6a@xlM|G~*9Mx-a`#WWLIjzF zb?DhlwO76=78dpAJKeMa0}gcuuZp)`e~8i=IcXbm!4<0N218B-{Y4d>;o4bJa-;3_ z?>738Mlil6J2<8eZ};hh{7LeuGy@~(#Us;cqvvQ z2|=opVCqXC(+REsM`Z=D-`IXNb6rLoxny%RpK0|ahpme9>6&p}*BJnP+>NG2Esc$G zHao>q-~1V;S!ud|H=+RAKh1m^GSj+3NcHG!QA#j1-{Vyeb!i>|woRAfH%hb7+t5dz4LMy&d(5?9FD9En1Slug&XxUh& z+c!&-|3yuRugxWel+aO=XRnsNRT4D_B6ce~bvWAT=Da6{Qc~z7*D9X^pYBKAx4cs^l z>8(+Fq+ujGS&?uAeO?aoHCTx92N_BV>~|!SB(#x2PakC!tR2z*(oVX92=w0D)_7%7 z1rtMwF>@GU-Q|$iDRRn#^+S6PGh4~Ks+mnyj z+dXAv6A~pVxt~N$I$#sR5-T)8frn+0zwc>k$5oe1P|D=C%f?3&V**X8%x?V8!$tNj zZ7w?&`&Ea4zCDJPJ1W+(3BO<2JQ`JUk9U4m*8tj$#6v~laVRs6VyrpH>m$LqmEsGwxw6jW&u~@5U zzyBDZ^%$pH96mV_x!bqQwhe8eGI+S#*E?yp)o_Nv3U%KGI4{ugMjUgK@3Ou;V>4O{d zIJ}9O{AiO;ZQt7QSE*O9J#;%=iFNCnzfk3ByeYHjeMmG*uCsyJ%Y)((7DxO`sKzU5 zlfxhi-p}wBSoQ{QP$U{piNc8JL>?LmBg{mhW7pAKc1aQJ-=x2;auiGYg({&Ot>@ug z5n zPIMP!lS8%VDPKsEUGo^q#(%ei9>#i8cxaJ~K(#Je=-iQbG5{$nD&qGl^$XVVj&{pX z4~WRdx>%kDX8l5)4G7_XMZDo6s<(AdE)o0K^3OOq#Gu>z#dpDFE?Y35um7Wg8DnCs6&LhQFVgLPa6wKEE$Pt-Tzx`g zh?h@QXjh!Gq#o2qzg8z*&#Rt9AA4DtHfSy;mld>I$F6i_?E32R7iFI(iq7PaX}D+e zHx@9XeLRu?hf z!2vFWCH*@ojt&D)yA^Q~@>=N410y5{Q89~A_vB~m=#?UIxDV!4kP`1|A0g;8%Qthy%+JBI_-S!LD>?bAe!a3B2;Q=g-Tj z*ZN9bX$3DOuRq2uF~zj-xwU?k?ZMiGcE2Vz`;0KsKr~47v7!vIuPv-3;6sL+NnY3% zx49BSK{2^Y@zd0t=f0T6k&vYWL`eTlu;%#SK7LE+Q3J`>e(`aYF;Rq@4WEQ77YVPD(?&CB1$b z$=)iPW&`aDSuTYHI1*-7_G!Z6gE?2YuX22ZRGzf15iR&KIShd|u84m|kmJ@*6d@Y6 z;PEC8YxCawX0~SDM9Q;(Ch0-che%fuZ8Y? z)e{zZOA?qXcqQ?3!)3Mp*z$hmCnidiBUkbZRR(AP!{uieQu)9wv)=%M&AaLyy#8~4 zY8g|hzESUeZDi~IBdc)nA2rF!$TRj$V#n_)cJ876VBEPi3)9$-*BcMMO$Q!#s}#JR z@FKmJR(6GXQ( z@cBNSP5gONEnVjgb%o&kDgT{rrCF-e@S`_tubZPam$e<+TUzn%NuR}xnFlN1;&yNE z6vN{gVsl*i4^MW;WSfB9!D&)${cME5)7c5iCD3is^KX-TLI>DM*|Pd=a%gDizmglo zsZtqQgj|Qd9i~XeJ3;X|?zj5>PT0YnzZcL}JntVLH?k;u^iz=9o6-3JL8IgBwg(@! z@s>Y1ffP0e3G?y>dp1xC^}#-WdixEUZ3UjFxgWjeZiWP6*dBFy+qQ08Hx`)k7x)I* zvWcV?&G(Jq^Nl7SqhW}+k^gor6D5~|rDsRynHdA>ug`%Q_$sey1Qy=*) z(`Wvu^`<_G^j_|Ey#_GZau+YESAAgP^~+>)hk>klezLv3zOF=y6_!lC6RvVylvNMj zB)E+9$?j;LhThoZ${sa?-(T{Zs6Z;OMX|~~m3;u8yT!b2r-J9ImN-}N45jz=hcww~ zc+Jrr{_96IT30_C>{oG~n&{r5yc|msB$=TWp|uaX)0LCf=62Sm-MJubeXfmVOIA#`GRZEf6RRo&C{?^L!`%;cLrzSGlFn_(f9 zUXRtomzp*T`;)+yfH(Vdrwnu&$53x-=}+b!y$275A-!rVPd+G8y}u|sKfrpA#24&s zxj}vM&jlCw$$URP<>tgDpM)HBf8 znJzG22QR0>qavxItYV<@U@EhFo8tL5NrFui8N~cjl~HX-xrO00dbH9x=)9uy+K*3h z6s8`Uu3!6}ck63wCo;a|w{nFs^2{}?1*rIRm2SGP4idWL#UA94Ph~u=dEPzi%ELe@*qf@gvSATw~wkjraBbjEv=m!)LYHnjt2qLNp9xFikdM1hG07L*9Dt$TU1X`wlehm5ev+D^ literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/test-apps/daily-notification-test/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..2960cbb6104b915c84760f889deed9bff2b3e17a GIT binary patch literal 9793 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 y3vD~Wi9;mL_v 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 literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/test-apps/daily-notification-test/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..a40d73e9c68ea638c28c7b13e4bcd1e179a3a102 GIT binary patch literal 15916 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 + + #FFFFFF + \ No newline at end of file diff --git a/test-apps/daily-notification-test/android/app/src/main/res/values/strings.xml b/test-apps/daily-notification-test/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..edab104 --- /dev/null +++ b/test-apps/daily-notification-test/android/app/src/main/res/values/strings.xml @@ -0,0 +1,7 @@ + + + Daily Notification Test + Daily Notification Test + com.timesafari.dailynotification.test + com.timesafari.dailynotification.test + diff --git a/test-apps/daily-notification-test/android/app/src/main/res/values/styles.xml b/test-apps/daily-notification-test/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..be874e5 --- /dev/null +++ b/test-apps/daily-notification-test/android/app/src/main/res/values/styles.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/test-apps/daily-notification-test/android/app/src/main/res/xml/file_paths.xml b/test-apps/daily-notification-test/android/app/src/main/res/xml/file_paths.xml new file mode 100644 index 0000000..bd0c4d8 --- /dev/null +++ b/test-apps/daily-notification-test/android/app/src/main/res/xml/file_paths.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/test-apps/daily-notification-test/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java b/test-apps/daily-notification-test/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java new file mode 100644 index 0000000..0297327 --- /dev/null +++ b/test-apps/daily-notification-test/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java @@ -0,0 +1,18 @@ +package com.getcapacitor.myapp; + +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} diff --git a/test-apps/daily-notification-test/android/build.gradle b/test-apps/daily-notification-test/android/build.gradle new file mode 100644 index 0000000..f1b3b0e --- /dev/null +++ b/test-apps/daily-notification-test/android/build.gradle @@ -0,0 +1,29 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:8.7.2' + classpath 'com.google.gms:google-services:4.4.2' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +apply from: "variables.gradle" + +allprojects { + repositories { + google() + mavenCentral() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/test-apps/daily-notification-test/android/capacitor.settings.gradle b/test-apps/daily-notification-test/android/capacitor.settings.gradle new file mode 100644 index 0000000..9a5fa87 --- /dev/null +++ b/test-apps/daily-notification-test/android/capacitor.settings.gradle @@ -0,0 +1,3 @@ +// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN +include ':capacitor-android' +project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') diff --git a/test-apps/daily-notification-test/android/gradle.properties b/test-apps/daily-notification-test/android/gradle.properties new file mode 100644 index 0000000..2e87c52 --- /dev/null +++ b/test-apps/daily-notification-test/android/gradle.properties @@ -0,0 +1,22 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true diff --git a/test-apps/daily-notification-test/android/gradle/wrapper/gradle-wrapper.jar b/test-apps/daily-notification-test/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ zQccdaaVK$5bz;*rnyK{_SQYM>;aES6Qs^lj9lEs6_J+%nIiuQC*fN;z8md>r_~Mfl zU%p5Dt_YT>gQqfr@`cR!$NWr~+`CZb%dn;WtzrAOI>P_JtsB76PYe*<%H(y>qx-`Kq!X_; z<{RpAqYhE=L1r*M)gNF3B8r(<%8mo*SR2hu zccLRZwGARt)Hlo1euqTyM>^!HK*!Q2P;4UYrysje@;(<|$&%vQekbn|0Ruu_Io(w4#%p6ld2Yp7tlA`Y$cciThP zKzNGIMPXX%&Ud0uQh!uQZz|FB`4KGD?3!ND?wQt6!n*f4EmCoJUh&b?;B{|lxs#F- z31~HQ`SF4x$&v00@(P+j1pAaj5!s`)b2RDBp*PB=2IB>oBF!*6vwr7Dp%zpAx*dPr zb@Zjq^XjN?O4QcZ*O+8>)|HlrR>oD*?WQl5ri3R#2?*W6iJ>>kH%KnnME&TT@ZzrHS$Q%LC?n|e>V+D+8D zYc4)QddFz7I8#}y#Wj6>4P%34dZH~OUDb?uP%-E zwjXM(?Sg~1!|wI(RVuxbu)-rH+O=igSho_pDCw(c6b=P zKk4ATlB?bj9+HHlh<_!&z0rx13K3ZrAR8W)!@Y}o`?a*JJsD+twZIv`W)@Y?Amu_u zz``@-e2X}27$i(2=9rvIu5uTUOVhzwu%mNazS|lZb&PT;XE2|B&W1>=B58#*!~D&) zfVmJGg8UdP*fx(>Cj^?yS^zH#o-$Q-*$SnK(ZVFkw+er=>N^7!)FtP3y~Xxnu^nzY zikgB>Nj0%;WOltWIob|}%lo?_C7<``a5hEkx&1ku$|)i>Rh6@3h*`slY=9U}(Ql_< zaNG*J8vb&@zpdhAvv`?{=zDedJ23TD&Zg__snRAH4eh~^oawdYi6A3w8<Ozh@Kw)#bdktM^GVb zrG08?0bG?|NG+w^&JvD*7LAbjED{_Zkc`3H!My>0u5Q}m!+6VokMLXxl`Mkd=g&Xx z-a>m*#G3SLlhbKB!)tnzfWOBV;u;ftU}S!NdD5+YtOjLg?X}dl>7m^gOpihrf1;PY zvll&>dIuUGs{Qnd- zwIR3oIrct8Va^Tm0t#(bJD7c$Z7DO9*7NnRZorrSm`b`cxz>OIC;jSE3DO8`hX955ui`s%||YQtt2 z5DNA&pG-V+4oI2s*x^>-$6J?p=I>C|9wZF8z;VjR??Icg?1w2v5Me+FgAeGGa8(3S z4vg*$>zC-WIVZtJ7}o9{D-7d>zCe|z#<9>CFve-OPAYsneTb^JH!Enaza#j}^mXy1 z+ULn^10+rWLF6j2>Ya@@Kq?26>AqK{A_| zQKb*~F1>sE*=d?A?W7N2j?L09_7n+HGi{VY;MoTGr_)G9)ot$p!-UY5zZ2Xtbm=t z@dpPSGwgH=QtIcEulQNI>S-#ifbnO5EWkI;$A|pxJd885oM+ zGZ0_0gDvG8q2xebj+fbCHYfAXuZStH2j~|d^sBAzo46(K8n59+T6rzBwK)^rfPT+B zyIFw)9YC-V^rhtK`!3jrhmW-sTmM+tPH+;nwjL#-SjQPUZ53L@A>y*rt(#M(qsiB2 zx6B)dI}6Wlsw%bJ8h|(lhkJVogQZA&n{?Vgs6gNSXzuZpEyu*xySy8ro07QZ7Vk1!3tJphN_5V7qOiyK8p z#@jcDD8nmtYi1^l8ml;AF<#IPK?!pqf9D4moYk>d99Im}Jtwj6c#+A;f)CQ*f-hZ< z=p_T86jog%!p)D&5g9taSwYi&eP z#JuEK%+NULWus;0w32-SYFku#i}d~+{Pkho&^{;RxzP&0!RCm3-9K6`>KZpnzS6?L z^H^V*s!8<>x8bomvD%rh>Zp3>Db%kyin;qtl+jAv8Oo~1g~mqGAC&Qi_wy|xEt2iz zWAJEfTV%cl2Cs<1L&DLRVVH05EDq`pH7Oh7sR`NNkL%wi}8n>IXcO40hp+J+sC!W?!krJf!GJNE8uj zg-y~Ns-<~D?yqbzVRB}G>0A^f0!^N7l=$m0OdZuqAOQqLc zX?AEGr1Ht+inZ-Qiwnl@Z0qukd__a!C*CKuGdy5#nD7VUBM^6OCpxCa2A(X;e0&V4 zM&WR8+wErQ7UIc6LY~Q9x%Sn*Tn>>P`^t&idaOEnOd(Ufw#>NoR^1QdhJ8s`h^|R_ zXX`c5*O~Xdvh%q;7L!_!ohf$NfEBmCde|#uVZvEo>OfEq%+Ns7&_f$OR9xsihRpBb z+cjk8LyDm@U{YN>+r46?nn{7Gh(;WhFw6GAxtcKD+YWV?uge>;+q#Xx4!GpRkVZYu zzsF}1)7$?%s9g9CH=Zs+B%M_)+~*j3L0&Q9u7!|+T`^O{xE6qvAP?XWv9_MrZKdo& z%IyU)$Q95AB4!#hT!_dA>4e@zjOBD*Y=XjtMm)V|+IXzjuM;(l+8aA5#Kaz_$rR6! zj>#&^DidYD$nUY(D$mH`9eb|dtV0b{S>H6FBfq>t5`;OxA4Nn{J(+XihF(stSche7$es&~N$epi&PDM_N`As;*9D^L==2Q7Z2zD+CiU(|+-kL*VG+&9!Yb3LgPy?A zm7Z&^qRG_JIxK7-FBzZI3Q<;{`DIxtc48k> zc|0dmX;Z=W$+)qE)~`yn6MdoJ4co;%!`ddy+FV538Y)j(vg}5*k(WK)KWZ3WaOG!8 z!syGn=s{H$odtpqFrT#JGM*utN7B((abXnpDM6w56nhw}OY}0TiTG1#f*VFZr+^-g zbP10`$LPq_;PvrA1XXlyx2uM^mrjTzX}w{yuLo-cOClE8MMk47T25G8M!9Z5ypOSV zAJUBGEg5L2fY)ZGJb^E34R2zJ?}Vf>{~gB!8=5Z) z9y$>5c)=;o0HeHHSuE4U)#vG&KF|I%-cF6f$~pdYJWk_dD}iOA>iA$O$+4%@>JU08 zS`ep)$XLPJ+n0_i@PkF#ri6T8?ZeAot$6JIYHm&P6EB=BiaNY|aA$W0I+nz*zkz_z zkEru!tj!QUffq%)8y0y`T&`fuus-1p>=^hnBiBqD^hXrPs`PY9tU3m0np~rISY09> z`P3s=-kt_cYcxWd{de@}TwSqg*xVhp;E9zCsnXo6z z?f&Sv^U7n4`xr=mXle94HzOdN!2kB~4=%)u&N!+2;z6UYKUDqi-s6AZ!haB;@&B`? z_TRX0%@suz^TRdCb?!vNJYPY8L_}&07uySH9%W^Tc&1pia6y1q#?*Drf}GjGbPjBS zbOPcUY#*$3sL2x4v_i*Y=N7E$mR}J%|GUI(>WEr+28+V z%v5{#e!UF*6~G&%;l*q*$V?&r$Pp^sE^i-0$+RH3ERUUdQ0>rAq2(2QAbG}$y{de( z>{qD~GGuOk559Y@%$?N^1ApVL_a704>8OD%8Y%8B;FCt%AoPu8*D1 zLB5X>b}Syz81pn;xnB}%0FnwazlWfUV)Z-~rZg6~b z6!9J$EcE&sEbzcy?CI~=boWA&eeIa%z(7SE^qgVLz??1Vbc1*aRvc%Mri)AJaAG!p z$X!_9Ds;Zz)f+;%s&dRcJt2==P{^j3bf0M=nJd&xwUGlUFn?H=2W(*2I2Gdu zv!gYCwM10aeus)`RIZSrCK=&oKaO_Ry~D1B5!y0R=%!i2*KfXGYX&gNv_u+n9wiR5 z*e$Zjju&ODRW3phN925%S(jL+bCHv6rZtc?!*`1TyYXT6%Ju=|X;6D@lq$8T zW{Y|e39ioPez(pBH%k)HzFITXHvnD6hw^lIoUMA;qAJ^CU?top1fo@s7xT13Fvn1H z6JWa-6+FJF#x>~+A;D~;VDs26>^oH0EI`IYT2iagy23?nyJ==i{g4%HrAf1-*v zK1)~@&(KkwR7TL}L(A@C_S0G;-GMDy=MJn2$FP5s<%wC)4jC5PXoxrQBFZ_k0P{{s@sz+gX`-!=T8rcB(=7vW}^K6oLWMmp(rwDh}b zwaGGd>yEy6fHv%jM$yJXo5oMAQ>c9j`**}F?MCry;T@47@r?&sKHgVe$MCqk#Z_3S z1GZI~nOEN*P~+UaFGnj{{Jo@16`(qVNtbU>O0Hf57-P>x8Jikp=`s8xWs^dAJ9lCQ z)GFm+=OV%AMVqVATtN@|vp61VVAHRn87}%PC^RAzJ%JngmZTasWBAWsoAqBU+8L8u z4A&Pe?fmTm0?mK-BL9t+{y7o(7jm+RpOhL9KnY#E&qu^}B6=K_dB}*VlSEiC9fn)+V=J;OnN)Ta5v66ic1rG+dGAJ1 z1%Zb_+!$=tQ~lxQrzv3x#CPb?CekEkA}0MYSgx$Jdd}q8+R=ma$|&1a#)TQ=l$1tQ z=tL9&_^vJ)Pk}EDO-va`UCT1m#Uty1{v^A3P~83_#v^ozH}6*9mIjIr;t3Uv%@VeW zGL6(CwCUp)Jq%G0bIG%?{_*Y#5IHf*5M@wPo6A{$Um++Co$wLC=J1aoG93&T7Ho}P z=mGEPP7GbvoG!uD$k(H3A$Z))+i{Hy?QHdk>3xSBXR0j!11O^mEe9RHmw!pvzv?Ua~2_l2Yh~_!s1qS`|0~0)YsbHSz8!mG)WiJE| z2f($6TQtt6L_f~ApQYQKSb=`053LgrQq7G@98#igV>y#i==-nEjQ!XNu9 z~;mE+gtj4IDDNQJ~JVk5Ux6&LCSFL!y=>79kE9=V}J7tD==Ga+IW zX)r7>VZ9dY=V&}DR))xUoV!u(Z|%3ciQi_2jl}3=$Agc(`RPb z8kEBpvY>1FGQ9W$n>Cq=DIpski};nE)`p3IUw1Oz0|wxll^)4dq3;CCY@RyJgFgc# zKouFh!`?Xuo{IMz^xi-h=StCis_M7yq$u) z?XHvw*HP0VgR+KR6wI)jEMX|ssqYvSf*_3W8zVTQzD?3>H!#>InzpSO)@SC8q*ii- z%%h}_#0{4JG;Jm`4zg};BPTGkYamx$Xo#O~lBirRY)q=5M45n{GCfV7h9qwyu1NxOMoP4)jjZMxmT|IQQh0U7C$EbnMN<3)Kk?fFHYq$d|ICu>KbY_hO zTZM+uKHe(cIZfEqyzyYSUBZa8;Fcut-GN!HSA9ius`ltNebF46ZX_BbZNU}}ZOm{M2&nANL9@0qvih15(|`S~z}m&h!u4x~(%MAO$jHRWNfuxWF#B)E&g3ghSQ9|> z(MFaLQj)NE0lowyjvg8z0#m6FIuKE9lDO~Glg}nSb7`~^&#(Lw{}GVOS>U)m8bF}x zVjbXljBm34Cs-yM6TVusr+3kYFjr28STT3g056y3cH5Tmge~ASxBj z%|yb>$eF;WgrcOZf569sDZOVwoo%8>XO>XQOX1OyN9I-SQgrm;U;+#3OI(zrWyow3 zk==|{lt2xrQ%FIXOTejR>;wv(Pb8u8}BUpx?yd(Abh6? zsoO3VYWkeLnF43&@*#MQ9-i-d0t*xN-UEyNKeyNMHw|A(k(_6QKO=nKMCxD(W(Yop zsRQ)QeL4X3Lxp^L%wzi2-WVSsf61dqliPUM7srDB?Wm6Lzn0&{*}|IsKQW;02(Y&| zaTKv|`U(pSzuvR6Rduu$wzK_W-Y-7>7s?G$)U}&uK;<>vU}^^ns@Z!p+9?St1s)dG zK%y6xkPyyS1$~&6v{kl?Md6gwM|>mt6Upm>oa8RLD^8T{0?HC!Z>;(Bob7el(DV6x zi`I)$&E&ngwFS@bi4^xFLAn`=fzTC;aimE^!cMI2n@Vo%Ae-ne`RF((&5y6xsjjAZ zVguVoQ?Z9uk$2ON;ersE%PU*xGO@T*;j1BO5#TuZKEf(mB7|g7pcEA=nYJ{s3vlbg zd4-DUlD{*6o%Gc^N!Nptgay>j6E5;3psI+C3Q!1ZIbeCubW%w4pq9)MSDyB{HLm|k zxv-{$$A*pS@csolri$Ge<4VZ}e~78JOL-EVyrbxKra^d{?|NnPp86!q>t<&IP07?Z z^>~IK^k#OEKgRH+LjllZXk7iA>2cfH6+(e&9ku5poo~6y{GC5>(bRK7hwjiurqAiZ zg*DmtgY}v83IjE&AbiWgMyFbaRUPZ{lYiz$U^&Zt2YjG<%m((&_JUbZcfJ22(>bi5 z!J?<7AySj0JZ&<-qXX;mcV!f~>G=sB0KnjWca4}vrtunD^1TrpfeS^4dvFr!65knK zZh`d;*VOkPs4*-9kL>$GP0`(M!j~B;#x?Ba~&s6CopvO86oM?-? zOw#dIRc;6A6T?B`Qp%^<U5 z19x(ywSH$_N+Io!6;e?`tWaM$`=Db!gzx|lQ${DG!zb1Zl&|{kX0y6xvO1o z220r<-oaS^^R2pEyY;=Qllqpmue|5yI~D|iI!IGt@iod{Opz@*ml^w2bNs)p`M(Io z|E;;m*Xpjd9l)4G#KaWfV(t8YUn@A;nK^#xgv=LtnArX|vWQVuw3}B${h+frU2>9^ z!l6)!Uo4`5k`<<;E(ido7M6lKTgWezNLq>U*=uz&s=cc$1%>VrAeOoUtA|T6gO4>UNqsdK=NF*8|~*sl&wI=x9-EGiq*aqV!(VVXA57 zw9*o6Ir8Lj1npUXvlevtn(_+^X5rzdR>#(}4YcB9O50q97%rW2me5_L=%ffYPUSRc z!vv?Kv>dH994Qi>U(a<0KF6NH5b16enCp+mw^Hb3Xs1^tThFpz!3QuN#}KBbww`(h z7GO)1olDqy6?T$()R7y%NYx*B0k_2IBiZ14&8|JPFxeMF{vW>HF-Vi3+ZOI=+qP}n zw(+!WcTd~4ZJX1!ZM&y!+uyt=&i!+~d(V%GjH;-NsEEv6nS1TERt|RHh!0>W4+4pp z1-*EzAM~i`+1f(VEHI8So`S`akPfPTfq*`l{Fz`hS%k#JS0cjT2mS0#QLGf=J?1`he3W*;m4)ce8*WFq1sdP=~$5RlH1EdWm|~dCvKOi4*I_96{^95p#B<(n!d?B z=o`0{t+&OMwKcxiBECznJcfH!fL(z3OvmxP#oWd48|mMjpE||zdiTBdWelj8&Qosv zZFp@&UgXuvJw5y=q6*28AtxZzo-UUpkRW%ne+Ylf!V-0+uQXBW=5S1o#6LXNtY5!I z%Rkz#(S8Pjz*P7bqB6L|M#Er{|QLae-Y{KA>`^} z@lPjeX>90X|34S-7}ZVXe{wEei1<{*e8T-Nbj8JmD4iwcE+Hg_zhkPVm#=@b$;)h6 z<<6y`nPa`f3I6`!28d@kdM{uJOgM%`EvlQ5B2bL)Sl=|y@YB3KeOzz=9cUW3clPAU z^sYc}xf9{4Oj?L5MOlYxR{+>w=vJjvbyO5}ptT(o6dR|ygO$)nVCvNGnq(6;bHlBd zl?w-|plD8spjDF03g5ip;W3Z z><0{BCq!Dw;h5~#1BuQilq*TwEu)qy50@+BE4bX28+7erX{BD4H)N+7U`AVEuREE8 z;X?~fyhF-x_sRfHIj~6f(+^@H)D=ngP;mwJjxhQUbUdzk8f94Ab%59-eRIq?ZKrwD z(BFI=)xrUlgu(b|hAysqK<}8bslmNNeD=#JW*}^~Nrswn^xw*nL@Tx!49bfJecV&KC2G4q5a!NSv)06A_5N3Y?veAz;Gv+@U3R% z)~UA8-0LvVE{}8LVDOHzp~2twReqf}ODIyXMM6=W>kL|OHcx9P%+aJGYi_Om)b!xe zF40Vntn0+VP>o<$AtP&JANjXBn7$}C@{+@3I@cqlwR2MdwGhVPxlTIcRVu@Ho-wO` z_~Or~IMG)A_`6-p)KPS@cT9mu9RGA>dVh5wY$NM9-^c@N=hcNaw4ITjm;iWSP^ZX| z)_XpaI61<+La+U&&%2a z0za$)-wZP@mwSELo#3!PGTt$uy0C(nTT@9NX*r3Ctw6J~7A(m#8fE)0RBd`TdKfAT zCf@$MAxjP`O(u9s@c0Fd@|}UQ6qp)O5Q5DPCeE6mSIh|Rj{$cAVIWsA=xPKVKxdhg zLzPZ`3CS+KIO;T}0Ip!fAUaNU>++ZJZRk@I(h<)RsJUhZ&Ru9*!4Ptn;gX^~4E8W^TSR&~3BAZc#HquXn)OW|TJ`CTahk+{qe`5+ixON^zA9IFd8)kc%*!AiLu z>`SFoZ5bW-%7}xZ>gpJcx_hpF$2l+533{gW{a7ce^B9sIdmLrI0)4yivZ^(Vh@-1q zFT!NQK$Iz^xu%|EOK=n>ug;(7J4OnS$;yWmq>A;hsD_0oAbLYhW^1Vdt9>;(JIYjf zdb+&f&D4@4AS?!*XpH>8egQvSVX`36jMd>$+RgI|pEg))^djhGSo&#lhS~9%NuWfX zDDH;3T*GzRT@5=7ibO>N-6_XPBYxno@mD_3I#rDD?iADxX`! zh*v8^i*JEMzyN#bGEBz7;UYXki*Xr(9xXax(_1qVW=Ml)kSuvK$coq2A(5ZGhs_pF z$*w}FbN6+QDseuB9=fdp_MTs)nQf!2SlROQ!gBJBCXD&@-VurqHj0wm@LWX-TDmS= z71M__vAok|@!qgi#H&H%Vg-((ZfxPAL8AI{x|VV!9)ZE}_l>iWk8UPTGHs*?u7RfP z5MC&=c6X;XlUzrz5q?(!eO@~* zoh2I*%J7dF!!_!vXoSIn5o|wj1#_>K*&CIn{qSaRc&iFVxt*^20ngCL;QonIS>I5^ zMw8HXm>W0PGd*}Ko)f|~dDd%;Wu_RWI_d;&2g6R3S63Uzjd7dn%Svu-OKpx*o|N>F zZg=-~qLb~VRLpv`k zWSdfHh@?dp=s_X`{yxOlxE$4iuyS;Z-x!*E6eqmEm*j2bE@=ZI0YZ5%Yj29!5+J$4h{s($nakA`xgbO8w zi=*r}PWz#lTL_DSAu1?f%-2OjD}NHXp4pXOsCW;DS@BC3h-q4_l`<))8WgzkdXg3! zs1WMt32kS2E#L0p_|x+x**TFV=gn`m9BWlzF{b%6j-odf4{7a4y4Uaef@YaeuPhU8 zHBvRqN^;$Jizy+ z=zW{E5<>2gp$pH{M@S*!sJVQU)b*J5*bX4h>5VJve#Q6ga}cQ&iL#=(u+KroWrxa%8&~p{WEUF0il=db;-$=A;&9M{Rq`ouZ5m%BHT6%st%saGsD6)fQgLN}x@d3q>FC;=f%O3Cyg=Ke@Gh`XW za@RajqOE9UB6eE=zhG%|dYS)IW)&y&Id2n7r)6p_)vlRP7NJL(x4UbhlcFXWT8?K=%s7;z?Vjts?y2+r|uk8Wt(DM*73^W%pAkZa1Jd zNoE)8FvQA>Z`eR5Z@Ig6kS5?0h;`Y&OL2D&xnnAUzQz{YSdh0k zB3exx%A2TyI)M*EM6htrxSlep!Kk(P(VP`$p0G~f$smld6W1r_Z+o?=IB@^weq>5VYsYZZR@` z&XJFxd5{|KPZmVOSxc@^%71C@;z}}WhbF9p!%yLj3j%YOlPL5s>7I3vj25 z@xmf=*z%Wb4;Va6SDk9cv|r*lhZ`(y_*M@>q;wrn)oQx%B(2A$9(74>;$zmQ!4fN; z>XurIk-7@wZys<+7XL@0Fhe-f%*=(weaQEdR9Eh6>Kl-EcI({qoZqyzziGwpg-GM#251sK_ z=3|kitS!j%;fpc@oWn65SEL73^N&t>Ix37xgs= zYG%eQDJc|rqHFia0!_sm7`@lvcv)gfy(+KXA@E{3t1DaZ$DijWAcA)E0@X?2ziJ{v z&KOYZ|DdkM{}t+@{@*6ge}m%xfjIxi%qh`=^2Rwz@w0cCvZ&Tc#UmCDbVwABrON^x zEBK43FO@weA8s7zggCOWhMvGGE`baZ62cC)VHyy!5Zbt%ieH+XN|OLbAFPZWyC6)p z4P3%8sq9HdS3=ih^0OOlqTPbKuzQ?lBEI{w^ReUO{V?@`ARsL|S*%yOS=Z%sF)>-y z(LAQdhgAcuF6LQjRYfdbD1g4o%tV4EiK&ElLB&^VZHbrV1K>tHTO{#XTo>)2UMm`2 z^t4s;vnMQgf-njU-RVBRw0P0-m#d-u`(kq7NL&2T)TjI_@iKuPAK-@oH(J8?%(e!0Ir$yG32@CGUPn5w4)+9@8c&pGx z+K3GKESI4*`tYlmMHt@br;jBWTei&(a=iYslc^c#RU3Q&sYp zSG){)V<(g7+8W!Wxeb5zJb4XE{I|&Y4UrFWr%LHkdQ;~XU zgy^dH-Z3lmY+0G~?DrC_S4@=>0oM8Isw%g(id10gWkoz2Q%7W$bFk@mIzTCcIB(K8 zc<5h&ZzCdT=9n-D>&a8vl+=ZF*`uTvQviG_bLde*k>{^)&0o*b05x$MO3gVLUx`xZ z43j+>!u?XV)Yp@MmG%Y`+COH2?nQcMrQ%k~6#O%PeD_WvFO~Kct za4XoCM_X!c5vhRkIdV=xUB3xI2NNStK*8_Zl!cFjOvp-AY=D;5{uXj}GV{LK1~IE2 z|KffUiBaStRr;10R~K2VVtf{TzM7FaPm;Y(zQjILn+tIPSrJh&EMf6evaBKIvi42-WYU9Vhj~3< zZSM-B;E`g_o8_XTM9IzEL=9Lb^SPhe(f(-`Yh=X6O7+6ALXnTcUFpI>ekl6v)ZQeNCg2 z^H|{SKXHU*%nBQ@I3It0m^h+6tvI@FS=MYS$ZpBaG7j#V@P2ZuYySbp@hA# ze(kc;P4i_-_UDP?%<6>%tTRih6VBgScKU^BV6Aoeg6Uh(W^#J^V$Xo^4#Ekp ztqQVK^g9gKMTHvV7nb64UU7p~!B?>Y0oFH5T7#BSW#YfSB@5PtE~#SCCg3p^o=NkMk$<8- z6PT*yIKGrvne7+y3}_!AC8NNeI?iTY(&nakN>>U-zT0wzZf-RuyZk^X9H-DT_*wk= z;&0}6LsGtfVa1q)CEUPlx#(ED@-?H<1_FrHU#z5^P3lEB|qsxEyn%FOpjx z3S?~gvoXy~L(Q{Jh6*i~=f%9kM1>RGjBzQh_SaIDfSU_9!<>*Pm>l)cJD@wlyxpBV z4Fmhc2q=R_wHCEK69<*wG%}mgD1=FHi4h!98B-*vMu4ZGW~%IrYSLGU{^TuseqVgV zLP<%wirIL`VLyJv9XG_p8w@Q4HzNt-o;U@Au{7%Ji;53!7V8Rv0^Lu^Vf*sL>R(;c zQG_ZuFl)Mh-xEIkGu}?_(HwkB2jS;HdPLSxVU&Jxy9*XRG~^HY(f0g8Q}iqnVmgjI zfd=``2&8GsycjR?M%(zMjn;tn9agcq;&rR!Hp z$B*gzHsQ~aXw8c|a(L^LW(|`yGc!qOnV(ZjU_Q-4z1&0;jG&vAKuNG=F|H?@m5^N@ zq{E!1n;)kNTJ>|Hb2ODt-7U~-MOIFo%9I)_@7fnX+eMMNh>)V$IXesJpBn|uo8f~#aOFytCT zf9&%MCLf8mp4kwHTcojWmM3LU=#|{3L>E}SKwOd?%{HogCZ_Z1BSA}P#O(%H$;z7XyJ^sjGX;j5 zrzp>|Ud;*&VAU3x#f{CKwY7Vc{%TKKqmB@oTHA9;>?!nvMA;8+Jh=cambHz#J18x~ zs!dF>$*AnsQ{{82r5Aw&^7eRCdvcgyxH?*DV5(I$qXh^zS>us*I66_MbL8y4d3ULj z{S(ipo+T3Ag!+5`NU2sc+@*m{_X|&p#O-SAqF&g_n7ObB82~$p%fXA5GLHMC+#qqL zdt`sJC&6C2)=juQ_!NeD>U8lDVpAOkW*khf7MCcs$A(wiIl#B9HM%~GtQ^}yBPjT@ z+E=|A!Z?A(rwzZ;T}o6pOVqHzTr*i;Wrc%&36kc@jXq~+w8kVrs;%=IFdACoLAcCAmhFNpbP8;s`zG|HC2Gv?I~w4ITy=g$`0qMQdkijLSOtX6xW%Z9Nw<;M- zMN`c7=$QxN00DiSjbVt9Mi6-pjv*j(_8PyV-il8Q-&TwBwH1gz1uoxs6~uU}PrgWB zIAE_I-a1EqlIaGQNbcp@iI8W1sm9fBBNOk(k&iLBe%MCo#?xI$%ZmGA?=)M9D=0t7 zc)Q0LnI)kCy{`jCGy9lYX%mUsDWwsY`;jE(;Us@gmWPqjmXL+Hu#^;k%eT>{nMtzj zsV`Iy6leTA8-PndszF;N^X@CJrTw5IIm!GPeu)H2#FQitR{1p;MasQVAG3*+=9FYK zw*k!HT(YQorfQj+1*mCV458(T5=fH`um$gS38hw(OqVMyunQ;rW5aPbF##A3fGH6h z@W)i9Uff?qz`YbK4c}JzQpuxuE3pcQO)%xBRZp{zJ^-*|oryTxJ-rR+MXJ)!f=+pp z10H|DdGd2exhi+hftcYbM0_}C0ZI-2vh+$fU1acsB-YXid7O|=9L!3e@$H*6?G*Zp z%qFB(sgl=FcC=E4CYGp4CN>=M8#5r!RU!u+FJVlH6=gI5xHVD&k;Ta*M28BsxfMV~ zLz+@6TxnfLhF@5=yQo^1&S}cmTN@m!7*c6z;}~*!hNBjuE>NLVl2EwN!F+)0$R1S! zR|lF%n!9fkZ@gPW|x|B={V6x3`=jS*$Pu0+5OWf?wnIy>Y1MbbGSncpKO0qE(qO=ts z!~@&!N`10S593pVQu4FzpOh!tvg}p%zCU(aV5=~K#bKi zHdJ1>tQSrhW%KOky;iW+O_n;`l9~omqM%sdxdLtI`TrJzN6BQz+7xOl*rM>xVI2~# z)7FJ^Dc{DC<%~VS?@WXzuOG$YPLC;>#vUJ^MmtbSL`_yXtNKa$Hk+l-c!aC7gn(Cg ze?YPYZ(2Jw{SF6MiO5(%_pTo7j@&DHNW`|lD`~{iH+_eSTS&OC*2WTT*a`?|9w1dh zh1nh@$a}T#WE5$7Od~NvSEU)T(W$p$s5fe^GpG+7fdJ9=enRT9$wEk+ZaB>G3$KQO zgq?-rZZnIv!p#>Ty~}c*Lb_jxJg$eGM*XwHUwuQ|o^}b3^T6Bxx{!?va8aC@-xK*H ztJBFvFfsSWu89%@b^l3-B~O!CXs)I6Y}y#0C0U0R0WG zybjroj$io0j}3%P7zADXOwHwafT#uu*zfM!oD$6aJx7+WL%t-@6^rD_a_M?S^>c;z zMK580bZXo1f*L$CuMeM4Mp!;P@}b~$cd(s5*q~FP+NHSq;nw3fbWyH)i2)-;gQl{S zZO!T}A}fC}vUdskGSq&{`oxt~0i?0xhr6I47_tBc`fqaSrMOzR4>0H^;A zF)hX1nfHs)%Zb-(YGX;=#2R6C{BG;k=?FfP?9{_uFLri~-~AJ;jw({4MU7e*d)?P@ zXX*GkNY9ItFjhwgAIWq7Y!ksbMzfqpG)IrqKx9q{zu%Mdl+{Dis#p9q`02pr1LG8R z@As?eG!>IoROgS!@J*to<27coFc1zpkh?w=)h9CbYe%^Q!Ui46Y*HO0mr% zEff-*$ndMNw}H2a5@BsGj5oFfd!T(F&0$<{GO!Qdd?McKkorh=5{EIjDTHU`So>8V zBA-fqVLb2;u7UhDV1xMI?y>fe3~4urv3%PX)lDw+HYa;HFkaLqi4c~VtCm&Ca+9C~ zge+67hp#R9`+Euq59WhHX&7~RlXn=--m8$iZ~~1C8cv^2(qO#X0?vl91gzUKBeR1J z^p4!!&7)3#@@X&2aF2-)1Ffcc^F8r|RtdL2X%HgN&XU-KH2SLCbpw?J5xJ*!F-ypZ zMG%AJ!Pr&}`LW?E!K~=(NJxuSVTRCGJ$2a*Ao=uUDSys!OFYu!Vs2IT;xQ6EubLIl z+?+nMGeQQhh~??0!s4iQ#gm3!BpMpnY?04kK375e((Uc7B3RMj;wE?BCoQGu=UlZt!EZ1Q*auI)dj3Jj{Ujgt zW5hd~-HWBLI_3HuO) zNrb^XzPsTIb=*a69wAAA3J6AAZZ1VsYbIG}a`=d6?PjM)3EPaDpW2YP$|GrBX{q*! z$KBHNif)OKMBCFP5>!1d=DK>8u+Upm-{hj5o|Wn$vh1&K!lVfDB&47lw$tJ?d5|=B z^(_9=(1T3Fte)z^>|3**n}mIX;mMN5v2F#l(q*CvU{Ga`@VMp#%rQkDBy7kYbmb-q z<5!4iuB#Q_lLZ8}h|hPODI^U6`gzLJre9u3k3c#%86IKI*^H-@I48Bi*@avYm4v!n0+v zWu{M{&F8#p9cx+gF0yTB_<2QUrjMPo9*7^-uP#~gGW~y3nfPAoV%amgr>PSyVAd@l)}8#X zR5zV6t*uKJZL}?NYvPVK6J0v4iVpwiN|>+t3aYiZSp;m0!(1`bHO}TEtWR1tY%BPB z(W!0DmXbZAsT$iC13p4f>u*ZAy@JoLAkJhzFf1#4;#1deO8#8d&89}en&z!W&A3++^1(;>0SB1*54d@y&9Pn;^IAf3GiXbfT`_>{R+Xv; zQvgL>+0#8-laO!j#-WB~(I>l0NCMt_;@Gp_f0#^c)t?&#Xh1-7RR0@zPyBz!U#0Av zT?}n({(p?p7!4S2ZBw)#KdCG)uPnZe+U|0{BW!m)9 zi_9$F?m<`2!`JNFv+w8MK_K)qJ^aO@7-Ig>cM4-r0bi=>?B_2mFNJ}aE3<+QCzRr*NA!QjHw# z`1OsvcoD0?%jq{*7b!l|L1+Tw0TTAM4XMq7*ntc-Ived>Sj_ZtS|uVdpfg1_I9knY z2{GM_j5sDC7(W&}#s{jqbybqJWyn?{PW*&cQIU|*v8YGOKKlGl@?c#TCnmnAkAzV- zmK={|1G90zz=YUvC}+fMqts0d4vgA%t6Jhjv?d;(Z}(Ep8fTZfHA9``fdUHkA+z3+ zhh{ohP%Bj?T~{i0sYCQ}uC#5BwN`skI7`|c%kqkyWIQ;!ysvA8H`b-t()n6>GJj6xlYDu~8qX{AFo$Cm3d|XFL=4uvc?Keb zzb0ZmMoXca6Mob>JqkNuoP>B2Z>D`Q(TvrG6m`j}-1rGP!g|qoL=$FVQYxJQjFn33lODt3Wb1j8VR zlR++vIT6^DtYxAv_hxupbLLN3e0%A%a+hWTKDV3!Fjr^cWJ{scsAdfhpI)`Bms^M6 zQG$waKgFr=c|p9Piug=fcJvZ1ThMnNhQvBAg-8~b1?6wL*WyqXhtj^g(Ke}mEfZVM zJuLNTUVh#WsE*a6uqiz`b#9ZYg3+2%=C(6AvZGc=u&<6??!slB1a9K)=VL zY9EL^mfyKnD zSJyYBc_>G;5RRnrNgzJz#Rkn3S1`mZgO`(r5;Hw6MveN(URf_XS-r58Cn80K)ArH4 z#Rrd~LG1W&@ttw85cjp8xV&>$b%nSXH_*W}7Ch2pg$$c0BdEo-HWRTZcxngIBJad> z;C>b{jIXjb_9Jis?NZJsdm^EG}e*pR&DAy0EaSGi3XWTa(>C%tz1n$u?5Fb z1qtl?;_yjYo)(gB^iQq?=jusF%kywm?CJP~zEHi0NbZ);$(H$w(Hy@{i>$wcVRD_X|w-~(0Z9BJyh zhNh;+eQ9BEIs;tPz%jSVnfCP!3L&9YtEP;svoj_bNzeGSQIAjd zBss@A;)R^WAu-37RQrM%{DfBNRx>v!G31Z}8-El9IOJlb_MSoMu2}GDYycNaf>uny z+8xykD-7ONCM!APry_Lw6-yT>5!tR}W;W`C)1>pxSs5o1z#j7%m=&=7O4hz+Lsqm` z*>{+xsabZPr&X=}G@obTb{nPTkccJX8w3CG7X+1+t{JcMabv~UNv+G?txRqXib~c^Mo}`q{$`;EBNJ;#F*{gvS12kV?AZ%O0SFB$^ zn+}!HbmEj}w{Vq(G)OGAzH}R~kS^;(-s&=ectz8vN!_)Yl$$U@HNTI-pV`LSj7Opu zTZ5zZ)-S_{GcEQPIQXLQ#oMS`HPu{`SQiAZ)m1at*Hy%3xma|>o`h%E%8BEbi9p0r zVjcsh<{NBKQ4eKlXU|}@XJ#@uQw*$4BxKn6#W~I4T<^f99~(=}a`&3(ur8R9t+|AQ zWkQx7l}wa48-jO@ft2h+7qn%SJtL%~890FG0s5g*kNbL3I&@brh&f6)TlM`K^(bhr zJWM6N6x3flOw$@|C@kPi7yP&SP?bzP-E|HSXQXG>7gk|R9BTj`e=4de9C6+H7H7n# z#GJeVs1mtHhLDmVO?LkYRQc`DVOJ_vdl8VUihO-j#t=0T3%Fc1f9F73ufJz*adn*p zc%&vi(4NqHu^R>sAT_0EDjVR8bc%wTz#$;%NU-kbDyL_dg0%TFafZwZ?5KZpcuaO54Z9hX zD$u>q!-9`U6-D`E#`W~fIfiIF5_m6{fvM)b1NG3xf4Auw;Go~Fu7cth#DlUn{@~yu z=B;RT*dp?bO}o%4x7k9v{r=Y@^YQ^UUm(Qmliw8brO^=NP+UOohLYiaEB3^DB56&V zK?4jV61B|1Uj_5fBKW;8LdwOFZKWp)g{B%7g1~DgO&N& z#lisxf?R~Z@?3E$Mms$$JK8oe@X`5m98V*aV6Ua}8Xs2#A!{x?IP|N(%nxsH?^c{& z@vY&R1QmQs83BW28qAmJfS7MYi=h(YK??@EhjL-t*5W!p z^gYX!Q6-vBqcv~ruw@oMaU&qp0Fb(dbVzm5xJN%0o_^@fWq$oa3X?9s%+b)x4w-q5Koe(@j6Ez7V@~NRFvd zfBH~)U5!ix3isg`6be__wBJp=1@yfsCMw1C@y+9WYD9_C%{Q~7^0AF2KFryfLlUP# zwrtJEcH)jm48!6tUcxiurAMaiD04C&tPe6DI0#aoqz#Bt0_7_*X*TsF7u*zv(iEfA z;$@?XVu~oX#1YXtceQL{dSneL&*nDug^OW$DSLF0M1Im|sSX8R26&)<0Fbh^*l6!5wfSu8MpMoh=2l z^^0Sr$UpZp*9oqa23fcCfm7`ya2<4wzJ`Axt7e4jJrRFVf?nY~2&tRL* zd;6_njcz01c>$IvN=?K}9ie%Z(BO@JG2J}fT#BJQ+f5LFSgup7i!xWRKw6)iITjZU z%l6hPZia>R!`aZjwCp}I zg)%20;}f+&@t;(%5;RHL>K_&7MH^S+7<|(SZH!u zznW|jz$uA`P9@ZWtJgv$EFp>)K&Gt+4C6#*khZQXS*S~6N%JDT$r`aJDs9|uXWdbg zBwho$phWx}x!qy8&}6y5Vr$G{yGSE*r$^r{}pw zVTZKvikRZ`J_IJrjc=X1uw?estdwm&bEahku&D04HD+0Bm~q#YGS6gp!KLf$A{%Qd z&&yX@Hp>~(wU{|(#U&Bf92+1i&Q*-S+=y=3pSZy$#8Uc$#7oiJUuO{cE6=tsPhwPe| zxQpK>`Dbka`V)$}e6_OXKLB%i76~4N*zA?X+PrhH<&)}prET;kel24kW%+9))G^JI zsq7L{P}^#QsZViX%KgxBvEugr>ZmFqe^oAg?{EI=&_O#e)F3V#rc z8$4}0Zr19qd3tE4#$3_f=Bbx9oV6VO!d3(R===i-7p=Vj`520w0D3W6lQfY48}!D* z&)lZMG;~er2qBoI2gsX+Ts-hnpS~NYRDtPd^FPzn!^&yxRy#CSz(b&E*tL|jIkq|l zf%>)7Dtu>jCf`-7R#*GhGn4FkYf;B$+9IxmqH|lf6$4irg{0ept__%)V*R_OK=T06 zyT_m-o@Kp6U{l5h>W1hGq*X#8*y@<;vsOFqEjTQXFEotR+{3}ODDnj;o0@!bB5x=N z394FojuGOtVKBlVRLtHp%EJv_G5q=AgF)SKyRN5=cGBjDWv4LDn$IL`*=~J7u&Dy5 zrMc83y+w^F&{?X(KOOAl-sWZDb{9X9#jrQtmrEXD?;h-}SYT7yM(X_6qksM=K_a;Z z3u0qT0TtaNvDER_8x*rxXw&C^|h{P1qxK|@pS7vdlZ#P z7PdB7MmC2}%sdzAxt>;WM1s0??`1983O4nFK|hVAbHcZ3x{PzytQLkCVk7hA!Lo` zEJH?4qw|}WH{dc4z%aB=0XqsFW?^p=X}4xnCJXK%c#ItOSjdSO`UXJyuc8bh^Cf}8 z@Ht|vXd^6{Fgai8*tmyRGmD_s_nv~r^Fy7j`Bu`6=G)5H$i7Q7lvQnmea&TGvJp9a|qOrUymZ$6G|Ly z#zOCg++$3iB$!6!>215A4!iryregKuUT344X)jQb3|9qY>c0LO{6Vby05n~VFzd?q zgGZv&FGlkiH*`fTurp>B8v&nSxNz)=5IF$=@rgND4d`!AaaX;_lK~)-U8la_Wa8i?NJC@BURO*sUW)E9oyv3RG^YGfN%BmxzjlT)bp*$<| zX3tt?EAy<&K+bhIuMs-g#=d1}N_?isY)6Ay$mDOKRh z4v1asEGWoAp=srraLW^h&_Uw|6O+r;wns=uwYm=JN4Q!quD8SQRSeEcGh|Eb5Jg8m zOT}u;N|x@aq)=&;wufCc^#)5U^VcZw;d_wwaoh9$p@Xrc{DD6GZUqZ ziC6OT^zSq@-lhbgR8B+e;7_Giv;DK5gn^$bs<6~SUadiosfewWDJu`XsBfOd1|p=q zE>m=zF}!lObA%ePey~gqU8S6h-^J2Y?>7)L2+%8kV}Gp=h`Xm_}rlm)SyUS=`=S7msKu zC|T!gPiI1rWGb1z$Md?0YJQ;%>uPLOXf1Z>N~`~JHJ!^@D5kSXQ4ugnFZ>^`zH8CAiZmp z6Ms|#2gcGsQ{{u7+Nb9sA?U>(0e$5V1|WVwY`Kn)rsnnZ4=1u=7u!4WexZD^IQ1Jk zfF#NLe>W$3m&C^ULjdw+5|)-BSHwpegdyt9NYC{3@QtMfd8GrIWDu`gd0nv-3LpGCh@wgBaG z176tikL!_NXM+Bv#7q^cyn9$XSeZR6#!B4JE@GVH zoobHZN_*RF#@_SVYKkQ_igme-Y5U}cV(hkR#k1c{bQNMji zU7aE`?dHyx=1`kOYZo_8U7?3-7vHOp`Qe%Z*i+FX!s?6huNp0iCEW-Z7E&jRWmUW_ z67j>)Ew!yq)hhG4o?^z}HWH-e=es#xJUhDRc4B51M4~E-l5VZ!&zQq`gWe`?}#b~7w1LH4Xa-UCT5LXkXQWheBa2YJYbyQ zl1pXR%b(KCXMO0OsXgl0P0Og<{(@&z1aokU-Pq`eQq*JYgt8xdFQ6S z6Z3IFSua8W&M#`~*L#r>Jfd6*BzJ?JFdBR#bDv$_0N!_5vnmo@!>vULcDm`MFU823 zpG9pqjqz^FE5zMDoGqhs5OMmC{Y3iVcl>F}5Rs24Y5B^mYQ;1T&ks@pIApHOdrzXF z-SdX}Hf{X;TaSxG_T$0~#RhqKISGKNK47}0*x&nRIPtmdwxc&QT3$8&!3fWu1eZ_P zJveQj^hJL#Sn!*4k`3}(d(aasl&7G0j0-*_2xtAnoX1@9+h zO#c>YQg60Z;o{Bi=3i7S`Ic+ZE>K{(u|#)9y}q*j8uKQ1^>+(BI}m%1v3$=4ojGBc zm+o1*!T&b}-lVvZqIUBc8V}QyFEgm#oyIuC{8WqUNV{Toz`oxhYpP!_p2oHHh5P@iB*NVo~2=GQm+8Yrkm2Xjc_VyHg1c0>+o~@>*Qzo zHVBJS>$$}$_4EniTI;b1WShX<5-p#TPB&!;lP!lBVBbLOOxh6FuYloD%m;n{r|;MU3!q4AVkua~fieeWu2 zQAQ$ue(IklX6+V;F1vCu-&V?I3d42FgWgsb_e^29ol}HYft?{SLf>DrmOp9o!t>I^ zY7fBCk+E8n_|apgM|-;^=#B?6RnFKlN`oR)`e$+;D=yO-(U^jV;rft^G_zl`n7qnM zL z*-Y4Phq+ZI1$j$F-f;`CD#|`-T~OM5Q>x}a>B~Gb3-+9i>Lfr|Ca6S^8g*{*?_5!x zH_N!SoRP=gX1?)q%>QTY!r77e2j9W(I!uAz{T`NdNmPBBUzi2{`XMB^zJGGwFWeA9 z{fk33#*9SO0)DjROug+(M)I-pKA!CX;IY(#gE!UxXVsa)X!UftIN98{pt#4MJHOhY zM$_l}-TJlxY?LS6Nuz1T<44m<4i^8k@D$zuCPrkmz@sdv+{ciyFJG2Zwy&%c7;atIeTdh!a(R^QXnu1Oq1b42*OQFWnyQ zWeQrdvP|w_idy53Wa<{QH^lFmEd+VlJkyiC>6B#s)F;w-{c;aKIm;Kp50HnA-o3lY z9B~F$gJ@yYE#g#X&3ADx&tO+P_@mnQTz9gv30_sTsaGXkfNYXY{$(>*PEN3QL>I!k zp)KibPhrfX3%Z$H6SY`rXGYS~143wZrG2;=FLj50+VM6soI~up_>fU(2Wl@{BRsMi zO%sL3x?2l1cXTF)k&moNsHfQrQ+wu(gBt{sk#CU=UhrvJIncy@tJX5klLjgMn>~h= zg|FR&;@eh|C7`>s_9c~0-{IAPV){l|Ts`i=)AW;d9&KPc3fMeoTS%8@V~D8*h;&(^>yjT84MM}=%#LS7shLAuuj(0VAYoozhWjq z4LEr?wUe2^WGwdTIgWBkDUJa>YP@5d9^Rs$kCXmMRxuF*YMVrn?0NFyPl}>`&dqZb z<5eqR=ZG3>n2{6v6BvJ`YBZeeTtB88TAY(x0a58EWyuf>+^|x8Qa6wA|1Nb_p|nA zWWa}|z8a)--Wj`LqyFk_a3gN2>5{Rl_wbW?#by7&i*^hRknK%jwIH6=dQ8*-_{*x0j^DUfMX0`|K@6C<|1cgZ~D(e5vBFFm;HTZF(!vT8=T$K+|F)x3kqzBV4-=p1V(lzi(s7jdu0>LD#N=$Lk#3HkG!a zIF<7>%B7sRNzJ66KrFV76J<2bdYhxll0y2^_rdG=I%AgW4~)1Nvz=$1UkE^J%BxLo z+lUci`UcU062os*=`-j4IfSQA{w@y|3}Vk?i;&SSdh8n+$iHA#%ERL{;EpXl6u&8@ zzg}?hkEOUOJt?ZL=pWZFJ19mI1@P=$U5*Im1e_8Z${JsM>Ov?nh8Z zP5QvI!{Jy@&BP48%P2{Jr_VgzW;P@7)M9n|lDT|Ep#}7C$&ud&6>C^5ZiwKIg2McPU(4jhM!BD@@L(Gd*Nu$ji(ljZ<{FIeW_1Mmf;76{LU z-ywN~=uNN)Xi6$<12A9y)K%X|(W0p|&>>4OXB?IiYr||WKDOJPxiSe01NSV-h24^L z_>m$;|C+q!Mj**-qQ$L-*++en(g|hw;M!^%_h-iDjFHLo-n3JpB;p?+o2;`*jpvJU zLY^lt)Un4joij^^)O(CKs@7E%*!w>!HA4Q?0}oBJ7Nr8NQ7QmY^4~jvf0-`%waOLn zdNjAPaC0_7c|RVhw)+71NWjRi!y>C+Bl;Z`NiL^zn2*0kmj5gyhCLCxts*cWCdRI| zjsd=sT5BVJc^$GxP~YF$-U{-?kW6r@^vHXB%{CqYzU@1>dzf#3SYedJG-Rm6^RB7s zGM5PR(yKPKR)>?~vpUIeTP7A1sc8-knnJk*9)3t^e%izbdm>Y=W{$wm(cy1RB-19i za#828DMBY+ps#7Y8^6t)=Ea@%Nkt)O6JCx|ybC;Ap}Z@Zw~*}3P>MZLPb4Enxz9Wf zssobT^(R@KuShj8>@!1M7tm|2%-pYYDxz-5`rCbaTCG5{;Uxm z*g=+H1X8{NUvFGzz~wXa%Eo};I;~`37*WrRU&K0dPSB$yk(Z*@K&+mFal^?c zurbqB-+|Kb5|sznT;?Pj!+kgFY1#Dr;_%A(GIQC{3ct|{*Bji%FNa6c-thbpBkA;U zURV!Dr&X{0J}iht#-Qp2=xzuh(fM>zRoiGrYl5ttw2#r34gC41CCOC31m~^UPTK@s z6;A@)7O7_%C)>bnAXerYuAHdE93>j2N}H${zEc6&SbZ|-fiG*-qtGuy-qDelH(|u$ zorf8_T6Zqe#Ub!+e3oSyrskt_HyW_^5lrWt#30l)tHk|j$@YyEkXUOV;6B51L;M@=NIWZXU;GrAa(LGxO%|im%7F<-6N;en0Cr zLH>l*y?pMwt`1*cH~LdBPFY_l;~`N!Clyfr;7w<^X;&(ZiVdF1S5e(+Q%60zgh)s4 zn2yj$+mE=miVERP(g8}G4<85^-5f@qxh2ec?n+$A_`?qN=iyT1?U@t?V6DM~BIlBB z>u~eXm-aE>R0sQy!-I4xtCNi!!qh?R1!kKf6BoH2GG{L4%PAz0{Sh6xpuyI%*~u)s z%rLuFl)uQUCBQAtMyN;%)zFMx4loh7uTfKeB2Xif`lN?2gq6NhWhfz0u5WP9J>=V2 zo{mLtSy&BA!mSzs&CrKWq^y40JF5a&GSXIi2= z{EYb59J4}VwikL4P=>+mc6{($FNE@e=VUwG+KV21;<@lrN`mnz5jYGASyvz7BOG_6(p^eTxD-4O#lROgon;R35=|nj#eHIfJBYPWG>H>`dHKCDZ3`R{-?HO0mE~(5_WYcFmp8sU?wr*UkAQiNDGc6T zA%}GOLXlOWqL?WwfHO8MB#8M8*~Y*gz;1rWWoVSXP&IbKxbQ8+s%4Jnt?kDsq7btI zCDr0PZ)b;B%!lu&CT#RJzm{l{2fq|BcY85`w~3LSK<><@(2EdzFLt9Y_`;WXL6x`0 zDoQ?=?I@Hbr;*VVll1Gmd8*%tiXggMK81a+T(5Gx6;eNb8=uYn z5BG-0g>pP21NPn>$ntBh>`*})Fl|38oC^9Qz>~MAazH%3Q~Qb!ALMf$srexgPZ2@&c~+hxRi1;}+)-06)!#Mq<6GhP z-Q?qmgo${aFBApb5p}$1OJKTClfi8%PpnczyVKkoHw7Ml9e7ikrF0d~UB}i3vizos zXW4DN$SiEV9{faLt5bHy2a>33K%7Td-n5C*N;f&ZqAg#2hIqEb(y<&f4u5BWJ>2^4 z414GosL=Aom#m&=x_v<0-fp1r%oVJ{T-(xnomNJ(Dryv zh?vj+%=II_nV+@NR+(!fZZVM&(W6{6%9cm+o+Z6}KqzLw{(>E86uA1`_K$HqINlb1 zKelh3-jr2I9V?ych`{hta9wQ2c9=MM`2cC{m6^MhlL2{DLv7C^j z$xXBCnDl_;l|bPGMX@*tV)B!c|4oZyftUlP*?$YU9C_eAsuVHJ58?)zpbr30P*C`T z7y#ao`uE-SOG(Pi+`$=e^mle~)pRrdwL5)N;o{gpW21of(QE#U6w%*C~`v-z0QqBML!!5EeYA5IQB0 z^l01c;L6E(iytN!LhL}wfwP7W9PNAkb+)Cst?qg#$n;z41O4&v+8-zPs+XNb-q zIeeBCh#ivnFLUCwfS;p{LC0O7tm+Sf9Jn)~b%uwP{%69;QC)Ok0t%*a5M+=;y8j=v z#!*pp$9@!x;UMIs4~hP#pnfVc!%-D<+wsG@R2+J&%73lK|2G!EQC)O05TCV=&3g)C!lT=czLpZ@Sa%TYuoE?v8T8`V;e$#Zf2_Nj6nvBgh1)2 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/android/gradle/wrapper/gradle-wrapper.properties b/test-apps/daily-notification-test/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..c1d5e01 --- /dev/null +++ b/test-apps/daily-notification-test/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/test-apps/daily-notification-test/android/gradlew b/test-apps/daily-notification-test/android/gradlew new file mode 100755 index 0000000..f5feea6 --- /dev/null +++ b/test-apps/daily-notification-test/android/gradlew @@ -0,0 +1,252 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/test-apps/daily-notification-test/android/gradlew.bat b/test-apps/daily-notification-test/android/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/test-apps/daily-notification-test/android/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/test-apps/daily-notification-test/android/settings.gradle b/test-apps/daily-notification-test/android/settings.gradle new file mode 100644 index 0000000..3b4431d --- /dev/null +++ b/test-apps/daily-notification-test/android/settings.gradle @@ -0,0 +1,5 @@ +include ':app' +include ':capacitor-cordova-android-plugins' +project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/') + +apply from: 'capacitor.settings.gradle' \ No newline at end of file diff --git a/test-apps/daily-notification-test/android/variables.gradle b/test-apps/daily-notification-test/android/variables.gradle new file mode 100644 index 0000000..2c8e408 --- /dev/null +++ b/test-apps/daily-notification-test/android/variables.gradle @@ -0,0 +1,16 @@ +ext { + minSdkVersion = 23 + compileSdkVersion = 35 + targetSdkVersion = 35 + androidxActivityVersion = '1.9.2' + androidxAppCompatVersion = '1.7.0' + androidxCoordinatorLayoutVersion = '1.2.0' + androidxCoreVersion = '1.15.0' + androidxFragmentVersion = '1.8.4' + coreSplashScreenVersion = '1.0.1' + androidxWebkitVersion = '1.12.1' + junitVersion = '4.13.2' + androidxJunitVersion = '1.2.1' + androidxEspressoCoreVersion = '3.6.1' + cordovaAndroidVersion = '10.1.1' +} \ No newline at end of file diff --git a/test-apps/daily-notification-test/capacitor.config.ts b/test-apps/daily-notification-test/capacitor.config.ts new file mode 100644 index 0000000..4ba1229 --- /dev/null +++ b/test-apps/daily-notification-test/capacitor.config.ts @@ -0,0 +1,14 @@ +import type { CapacitorConfig } from '@capacitor/cli'; + +const config: CapacitorConfig = { + appId: 'com.timesafari.dailynotification.test', + appName: 'Daily Notification Test', + webDir: 'dist', + plugins: { + Clipboard: { + // Enable clipboard functionality + } + } +}; + +export default config; diff --git a/test-apps/daily-notification-test/env.d.ts b/test-apps/daily-notification-test/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/test-apps/daily-notification-test/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/test-apps/daily-notification-test/eslint.config.ts b/test-apps/daily-notification-test/eslint.config.ts new file mode 100644 index 0000000..edb1bbb --- /dev/null +++ b/test-apps/daily-notification-test/eslint.config.ts @@ -0,0 +1,20 @@ +import { globalIgnores } from 'eslint/config' +import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' +import pluginVue from 'eslint-plugin-vue' + +// To allow more languages other than `ts` in `.vue` files, uncomment the following lines: +// import { configureVueProject } from '@vue/eslint-config-typescript' +// configureVueProject({ scriptLangs: ['ts', 'tsx'] }) +// More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.{ts,mts,tsx,vue}'], + }, + + globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']), + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommended, +) diff --git a/test-apps/daily-notification-test/index.html b/test-apps/daily-notification-test/index.html new file mode 100644 index 0000000..9e5fc8f --- /dev/null +++ b/test-apps/daily-notification-test/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +

+ + + diff --git a/test-apps/android-test/package-lock.json b/test-apps/daily-notification-test/package-lock.json similarity index 56% rename from test-apps/android-test/package-lock.json rename to test-apps/daily-notification-test/package-lock.json index dfa1eac..18080d8 100644 --- a/test-apps/android-test/package-lock.json +++ b/test-apps/daily-notification-test/package-lock.json @@ -1,35 +1,305 @@ { - "name": "daily-notification-android-test", - "version": "1.0.0", + "name": "daily-notification-test", + "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "daily-notification-android-test", - "version": "1.0.0", + "name": "daily-notification-test", + "version": "0.0.0", + "dependencies": { + "@capacitor/android": "^6.2.1", + "@capacitor/cli": "^6.2.1", + "@capacitor/core": "^6.2.1", + "date-fns": "^4.1.0", + "pinia": "^3.0.3", + "vue": "^3.5.22", + "vue-facing-decorator": "^4.0.1", + "vue-router": "^4.5.1" + }, + "devDependencies": { + "@tsconfig/node22": "^22.0.2", + "@types/node": "^22.18.6", + "@vitejs/plugin-vue": "^6.0.1", + "@vue/eslint-config-typescript": "^14.6.0", + "@vue/tsconfig": "^0.8.1", + "eslint": "^9.33.0", + "eslint-plugin-vue": "~10.4.0", + "jiti": "^2.5.1", + "npm-run-all2": "^8.0.4", + "typescript": "~5.9.0", + "vite": "^7.1.7", + "vite-plugin-vue-devtools": "^8.0.2", + "vue-tsc": "^3.1.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "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": { - "@capacitor/android": "^5.0.0", - "@capacitor/cli": "^5.0.0", - "@capacitor/core": "^5.0.0", - "pinia": "^2.1.0", - "vue": "^3.4.0", - "vue-facing-decorator": "^3.0.0", - "vue-router": "^4.2.0" + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, - "devDependencies": { - "@capacitor/cli": "^5.0.0", - "@types/node": "^20.0.0", - "@typescript-eslint/eslint-plugin": "^6.0.0", - "@typescript-eslint/parser": "^6.0.0", - "@vitejs/plugin-vue": "^4.5.0", - "@vue/eslint-config-typescript": "^12.0.0", - "@vue/tsconfig": "^0.5.0", - "eslint": "^8.0.0", - "eslint-plugin-vue": "^9.0.0", - "typescript": "~5.3.0", - "vite": "^5.0.0", - "vue-tsc": "^1.8.0" + "engines": { + "node": ">=6.9.0" + } + }, + "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/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-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-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": { @@ -50,6 +320,30 @@ "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/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", @@ -65,6 +359,155 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.28.0.tgz", + "integrity": "sha512-zOiZqvANjWDUaUS9xMxbMcK/Zccztbe/6ikvUXaG9nsPH3w6qh5UaPGAnirI/WhIbZ8m3OHU0ReyPrknG+ZKeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-decorators": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.27.1.tgz", + "integrity": "sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A==", + "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-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "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-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "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-typescript": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz", + "integrity": "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-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", @@ -79,60 +522,112 @@ } }, "node_modules/@capacitor/android": { - "version": "5.7.8", - "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.7.8.tgz", - "integrity": "sha512-ooWclwcuW0dy3YfqgoozkHkjatX8H2fb2/RwRsJa3cew1P1lUXIXri3Dquuy4LdqFAJA7UHcJ19Bl/6UKdsZYA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-6.2.1.tgz", + "integrity": "sha512-8gd4CIiQO5LAIlPIfd5mCuodBRxMMdZZEdj8qG8m+dQ1sQ2xyemVpzHmRK8qSCHorsBUCg3D62j2cp6bEBAkdw==", "license": "MIT", "peerDependencies": { - "@capacitor/core": "^5.7.0" + "@capacitor/core": "^6.2.0" } }, "node_modules/@capacitor/cli": { - "version": "5.7.8", - "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-5.7.8.tgz", - "integrity": "sha512-qN8LDlREMhrYhOvVXahoJVNkP8LP55/YPRJrzTAFrMqlNJC18L3CzgWYIblFPnuwfbH/RxbfoZT/ydkwgVpMrw==", - "dev": true, + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-6.2.1.tgz", + "integrity": "sha512-JKl0FpFge8PgQNInw12kcKieQ4BmOyazQ4JGJOfEpVXlgrX1yPhSZTPjngupzTCiK3I7q7iGG5kjun0fDqgSCA==", + "license": "MIT", + "dependencies": { + "@ionic/cli-framework-output": "^2.2.5", + "@ionic/utils-fs": "^3.1.6", + "@ionic/utils-subprocess": "2.1.11", + "@ionic/utils-terminal": "^2.3.3", + "commander": "^9.3.0", + "debug": "^4.3.4", + "env-paths": "^2.2.0", + "kleur": "^4.1.4", + "native-run": "^2.0.0", + "open": "^8.4.0", + "plist": "^3.0.5", + "prompts": "^2.4.2", + "rimraf": "^4.4.1", + "semver": "^7.3.7", + "tar": "^6.1.11", + "tslib": "^2.4.0", + "xml2js": "^0.5.0" + }, + "bin": { + "cap": "bin/capacitor", + "capacitor": "bin/capacitor" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@capacitor/cli/node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@capacitor/cli/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@capacitor/cli/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@capacitor/cli/node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", "license": "MIT", "dependencies": { - "@ionic/cli-framework-output": "^2.2.5", - "@ionic/utils-fs": "^3.1.6", - "@ionic/utils-subprocess": "^2.1.11", - "@ionic/utils-terminal": "^2.3.3", - "commander": "^9.3.0", - "debug": "^4.3.4", - "env-paths": "^2.2.0", - "kleur": "^4.1.4", - "native-run": "^2.0.0", - "open": "^8.4.0", - "plist": "^3.0.5", - "prompts": "^2.4.2", - "rimraf": "^4.4.1", - "semver": "^7.3.7", - "tar": "^6.1.11", - "tslib": "^2.4.0", - "xml2js": "^0.5.0" - }, - "bin": { - "cap": "bin/capacitor", - "capacitor": "bin/capacitor" + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@capacitor/core": { - "version": "5.7.8", - "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.7.8.tgz", - "integrity": "sha512-rrZcm/2vJM0WdWRQup1TUidbjQV9PfIadSkV4rAGLD7R6PuzZSMPGT0gmoZzCRlXkqrazrWWDkurei3ozU02FA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-6.2.1.tgz", + "integrity": "sha512-urZwxa7hVE/BnA18oCFAdizXPse6fCKanQyEqpmz6cBJ2vObwMpyJDG5jBeoSsgocS9+Ax+9vb4ducWJn0y2qQ==", "license": "MIT", "dependencies": { "tslib": "^2.1.0" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", + "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", "cpu": [ "ppc64" ], @@ -143,13 +638,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", + "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", "cpu": [ "arm" ], @@ -160,13 +655,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", + "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", "cpu": [ "arm64" ], @@ -177,13 +672,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", + "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", "cpu": [ "x64" ], @@ -194,13 +689,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", + "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", "cpu": [ "arm64" ], @@ -211,13 +706,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", + "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", "cpu": [ "x64" ], @@ -228,13 +723,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", + "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", "cpu": [ "arm64" ], @@ -245,13 +740,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", + "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", "cpu": [ "x64" ], @@ -262,13 +757,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", + "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", "cpu": [ "arm" ], @@ -279,13 +774,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", + "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", "cpu": [ "arm64" ], @@ -296,13 +791,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", + "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", "cpu": [ "ia32" ], @@ -313,13 +808,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", + "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", "cpu": [ "loong64" ], @@ -330,13 +825,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", + "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", "cpu": [ "mips64el" ], @@ -347,13 +842,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", + "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", "cpu": [ "ppc64" ], @@ -364,13 +859,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", + "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", "cpu": [ "riscv64" ], @@ -381,13 +876,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", + "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", "cpu": [ "s390x" ], @@ -398,13 +893,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", + "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", "cpu": [ "x64" ], @@ -415,13 +910,30 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", + "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", + "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", "cpu": [ "x64" ], @@ -432,13 +944,30 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", + "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", + "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", "cpu": [ "x64" ], @@ -449,13 +978,30 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", + "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", + "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", "cpu": [ "x64" ], @@ -466,13 +1012,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", + "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", "cpu": [ "arm64" ], @@ -483,13 +1029,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", + "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", "cpu": [ "ia32" ], @@ -500,13 +1046,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", + "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", "cpu": [ "x64" ], @@ -517,7 +1063,7 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { @@ -549,17 +1095,82 @@ "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.4.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.0.tgz", + "integrity": "sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.16.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz", + "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==", + "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": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "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": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -567,29 +1178,12 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -601,13 +1195,6 @@ "concat-map": "0.0.1" } }, - "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -622,53 +1209,64 @@ } }, "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "version": "9.37.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.37.0.tgz", + "integrity": "sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "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/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@eslint/plugin-kit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.0.tgz", + "integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@eslint/core": "^0.16.0", + "levn": "^0.4.1" }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/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==", + "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": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/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==", + "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": "ISC", + "license": "Apache-2.0", "dependencies": { - "brace-expansion": "^1.1.7" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { - "node": "*" + "node": ">=18.18.0" } }, "node_modules/@humanwhocodes/module-importer": { @@ -685,19 +1283,24 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", + "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": "BSD-3-Clause" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@ionic/cli-framework-output": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/@ionic/cli-framework-output/-/cli-framework-output-2.2.8.tgz", "integrity": "sha512-TshtaFQsovB4NWRBydbNFawql6yul7d5bMiW1WYYf17hd99V6xdDdk3vtF51bw6sLkxON3bDQpWsnUc9/hVo3g==", - "dev": true, "license": "MIT", "dependencies": { "@ionic/utils-terminal": "2.3.5", @@ -709,24 +1312,22 @@ } }, "node_modules/@ionic/utils-array": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@ionic/utils-array/-/utils-array-2.1.6.tgz", - "integrity": "sha512-0JZ1Zkp3wURnv8oq6Qt7fMPo5MpjbLoUoa9Bu2Q4PJuSDWM8H8gwF3dQO7VTeUj3/0o1IB1wGkFWZZYgUXZMUg==", - "dev": true, + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@ionic/utils-array/-/utils-array-2.1.5.tgz", + "integrity": "sha512-HD72a71IQVBmQckDwmA8RxNVMTbxnaLbgFOl+dO5tbvW9CkkSFCv41h6fUuNsSEVgngfkn0i98HDuZC8mk+lTA==", "license": "MIT", "dependencies": { "debug": "^4.0.0", "tslib": "^2.0.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=10.3.0" } }, "node_modules/@ionic/utils-fs": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/@ionic/utils-fs/-/utils-fs-3.1.7.tgz", "integrity": "sha512-2EknRvMVfhnyhL1VhFkSLa5gOcycK91VnjfrTB0kbqkTFCOXyXgVLI5whzq7SLrgD9t1aqos3lMMQyVzaQ5gVA==", - "dev": true, "license": "MIT", "dependencies": { "@types/fs-extra": "^8.0.0", @@ -739,42 +1340,39 @@ } }, "node_modules/@ionic/utils-object": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@ionic/utils-object/-/utils-object-2.1.6.tgz", - "integrity": "sha512-vCl7sl6JjBHFw99CuAqHljYJpcE88YaH2ZW4ELiC/Zwxl5tiwn4kbdP/gxi2OT3MQb1vOtgAmSNRtusvgxI8ww==", - "dev": true, + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@ionic/utils-object/-/utils-object-2.1.5.tgz", + "integrity": "sha512-XnYNSwfewUqxq+yjER1hxTKggftpNjFLJH0s37jcrNDwbzmbpFTQTVAp4ikNK4rd9DOebX/jbeZb8jfD86IYxw==", "license": "MIT", "dependencies": { "debug": "^4.0.0", "tslib": "^2.0.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=10.3.0" } }, "node_modules/@ionic/utils-process": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.11.tgz", - "integrity": "sha512-Uavxn+x8j3rDlZEk1X7YnaN6wCgbCwYQOeIjv/m94i1dzslqWhqIHEqxEyeE8HsT5Negboagg7GtQiABy+BLbA==", - "dev": true, + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.10.tgz", + "integrity": "sha512-mZ7JEowcuGQK+SKsJXi0liYTcXd2bNMR3nE0CyTROpMECUpJeAvvaBaPGZf5ERQUPeWBVuwqAqjUmIdxhz5bxw==", "license": "MIT", "dependencies": { - "@ionic/utils-object": "2.1.6", - "@ionic/utils-terminal": "2.3.4", + "@ionic/utils-object": "2.1.5", + "@ionic/utils-terminal": "2.3.3", "debug": "^4.0.0", "signal-exit": "^3.0.3", "tree-kill": "^1.2.2", "tslib": "^2.0.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=10.3.0" } }, "node_modules/@ionic/utils-process/node_modules/@ionic/utils-terminal": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.4.tgz", - "integrity": "sha512-cEiMFl3jklE0sW60r8JHH3ijFTwh/jkdEKWbylSyExQwZ8pPuwoXz7gpkWoJRLuoRHHSvg+wzNYyPJazIHfoJA==", - "dev": true, + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.3.tgz", + "integrity": "sha512-RnuSfNZ5fLEyX3R5mtcMY97cGD1A0NVBbarsSQ6yMMfRJ5YHU7hHVyUfvZeClbqkBC/pAqI/rYJuXKCT9YeMCQ==", "license": "MIT", "dependencies": { "@types/slice-ansi": "^4.0.0", @@ -788,48 +1386,66 @@ "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=10.3.0" } }, + "node_modules/@ionic/utils-process/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==", + "license": "ISC" + }, "node_modules/@ionic/utils-stream": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.6.tgz", - "integrity": "sha512-4+Kitey1lTA1yGtnigeYNhV/0tggI3lWBMjC7tBs1K9GXa/q7q4CtOISppdh8QgtOhrhAXS2Igp8rbko/Cj+lA==", - "dev": true, + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.5.tgz", + "integrity": "sha512-hkm46uHvEC05X/8PHgdJi4l4zv9VQDELZTM+Kz69odtO9zZYfnt8DkfXHJqJ+PxmtiE5mk/ehJWLnn/XAczTUw==", "license": "MIT", "dependencies": { "debug": "^4.0.0", "tslib": "^2.0.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=10.3.0" } }, "node_modules/@ionic/utils-subprocess": { - "version": "2.1.14", - "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-2.1.14.tgz", - "integrity": "sha512-nGYvyGVjU0kjPUcSRFr4ROTraT3w/7r502f5QJEsMRKTqa4eEzCshtwRk+/mpASm0kgBN5rrjYA5A/OZg8ahqg==", - "dev": true, + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-2.1.11.tgz", + "integrity": "sha512-6zCDixNmZCbMCy5np8klSxOZF85kuDyzZSTTQKQP90ZtYNCcPYmuFSzaqDwApJT4r5L3MY3JrqK1gLkc6xiUPw==", "license": "MIT", "dependencies": { - "@ionic/utils-array": "2.1.6", - "@ionic/utils-fs": "3.1.7", - "@ionic/utils-process": "2.1.11", - "@ionic/utils-stream": "3.1.6", - "@ionic/utils-terminal": "2.3.4", + "@ionic/utils-array": "2.1.5", + "@ionic/utils-fs": "3.1.6", + "@ionic/utils-process": "2.1.10", + "@ionic/utils-stream": "3.1.5", + "@ionic/utils-terminal": "2.3.3", "cross-spawn": "^7.0.3", "debug": "^4.0.0", "tslib": "^2.0.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=10.3.0" + } + }, + "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-fs": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@ionic/utils-fs/-/utils-fs-3.1.6.tgz", + "integrity": "sha512-eikrNkK89CfGPmexjTfSWl4EYqsPSBh0Ka7by4F0PLc1hJZYtJxUZV3X4r5ecA8ikjicUmcbU7zJmAjmqutG/w==", + "license": "MIT", + "dependencies": { + "@types/fs-extra": "^8.0.0", + "debug": "^4.0.0", + "fs-extra": "^9.0.0", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=10.3.0" } }, "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-terminal": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.4.tgz", - "integrity": "sha512-cEiMFl3jklE0sW60r8JHH3ijFTwh/jkdEKWbylSyExQwZ8pPuwoXz7gpkWoJRLuoRHHSvg+wzNYyPJazIHfoJA==", - "dev": true, + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.3.tgz", + "integrity": "sha512-RnuSfNZ5fLEyX3R5mtcMY97cGD1A0NVBbarsSQ6yMMfRJ5YHU7hHVyUfvZeClbqkBC/pAqI/rYJuXKCT9YeMCQ==", "license": "MIT", "dependencies": { "@types/slice-ansi": "^4.0.0", @@ -843,14 +1459,19 @@ "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=10.3.0" } }, + "node_modules/@ionic/utils-subprocess/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==", + "license": "ISC" + }, "node_modules/@ionic/utils-terminal": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.5.tgz", "integrity": "sha512-3cKScz9Jx2/Pr9ijj1OzGlBDfcmx7OMVBt4+P1uRR0SSW4cm1/y3Mo4OY3lfkuaYifMNBW8Wz6lQHbs1bihr7A==", - "dev": true, "license": "MIT", "dependencies": { "@types/slice-ansi": "^4.0.0", @@ -867,16 +1488,31 @@ "node": ">=16.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==", + "node_modules/@ionic/utils-terminal/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==", + "license": "ISC" + }, + "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", - "optional": true, - "peer": true, "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, @@ -886,25 +1522,10 @@ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "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", - "optional": true, - "peer": true, - "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", @@ -912,13 +1533,11 @@ "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==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -962,6 +1581,20 @@ "node": ">= 8" } }, + "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/@rolldown/pluginutils": { + "version": "1.0.0-beta.29", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.29.tgz", + "integrity": "sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.52.4", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz", @@ -1270,6 +1903,33 @@ "win32" ] }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@tsconfig/node22": { + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node22/-/node22-22.0.2.tgz", + "integrity": "sha512-Kmwj4u8sDRDrMYRoN9FDEcXD8UpBSaPQQ24Gz+Gamqfm7xxn+GBR7ge/Z7pK8OXNGyUzbSwJj+TH6B+DS/epyA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1281,7 +1941,6 @@ "version": "8.1.5", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -1295,148 +1954,175 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.21.tgz", - "integrity": "sha512-CsGG2P3I5y48RPMfprQGfy4JPRZ6csfC3ltBZSRItG3ngggmNY/qs2uZKp4p9VbrpqNNSMzUZNFZKzgOGnd/VA==", - "dev": true, + "version": "22.18.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.10.tgz", + "integrity": "sha512-anNG/V/Efn/YZY4pRzbACnKxNKoBng2VTFydVu8RRs5hQjikP8CQfaeAV59VFSCzKNp90mXiVXW2QzV56rwMrg==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" } }, - "node_modules/@types/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/slice-ansi/-/slice-ansi-4.0.0.tgz", "integrity": "sha512-+OpjSaq85gvlZAYINyzKpLeiFkSC4EsC6IIiT6v6TLSU5k5U83fHGj9Lel8oKEXM0HqgrMVCjXPDPVICtxF7EQ==", - "dev": true, "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.1.tgz", + "integrity": "sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.46.1", + "@typescript-eslint/type-utils": "8.46.1", + "@typescript-eslint/utils": "8.46.1", + "@typescript-eslint/visitor-keys": "8.46.1", "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "ignore": "^7.0.0", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@typescript-eslint/parser": "^8.46.1", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/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/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.1.tgz", + "integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/scope-manager": "8.46.1", + "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/typescript-estree": "8.46.1", + "@typescript-eslint/visitor-keys": "8.46.1", "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.1.tgz", + "integrity": "sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.46.1", + "@typescript-eslint/types": "^8.46.1", + "debug": "^4.3.4" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.1.tgz", + "integrity": "sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/visitor-keys": "8.46.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.1.tgz", + "integrity": "sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g==", + "dev": true, + "license": "MIT", "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.1.tgz", + "integrity": "sha512-+BlmiHIiqufBxkVnOtFwjah/vrkF4MtKKvpXrKSPLCkCtAp8H01/VV43sfqA98Od7nJpDcFnkwgyfQbOG0AMvw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/typescript-estree": "8.46.1", + "@typescript-eslint/utils": "8.46.1", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.1.tgz", + "integrity": "sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ==", "dev": true, "license": "MIT", "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -1444,144 +2130,186 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.1.tgz", + "integrity": "sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/project-service": "8.46.1", + "@typescript-eslint/tsconfig-utils": "8.46.1", + "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/visitor-keys": "8.46.1", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.1.tgz", + "integrity": "sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.46.1", + "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/typescript-estree": "8.46.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.1.tgz", + "integrity": "sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/types": "8.46.1", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "node_modules/@typescript-eslint/visitor-keys/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": "ISC" + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, "node_modules/@vitejs/plugin-vue": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.6.2.tgz", - "integrity": "sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.1.tgz", + "integrity": "sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw==", "dev": true, "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-beta.29" + }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^4.0.0 || ^5.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0", "vue": "^3.2.25" } }, "node_modules/@volar/language-core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.11.1.tgz", - "integrity": "sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==", + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.23.tgz", + "integrity": "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==", "dev": true, "license": "MIT", "dependencies": { - "@volar/source-map": "1.11.1" + "@volar/source-map": "2.4.23" } }, "node_modules/@volar/source-map": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.11.1.tgz", - "integrity": "sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==", + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.23.tgz", + "integrity": "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.23.tgz", + "integrity": "sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==", "dev": true, "license": "MIT", "dependencies": { - "muggle-string": "^0.3.1" + "@volar/language-core": "2.4.23", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" } }, - "node_modules/@volar/typescript": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.11.1.tgz", - "integrity": "sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==", + "node_modules/@vue/babel-helper-vue-transform-on": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.5.0.tgz", + "integrity": "sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/babel-plugin-jsx": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.5.0.tgz", + "integrity": "sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==", "dev": true, "license": "MIT", "dependencies": { - "@volar/language-core": "1.11.1", - "path-browserify": "^1.0.1" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.2", + "@vue/babel-helper-vue-transform-on": "1.5.0", + "@vue/babel-plugin-resolve-type": "1.5.0", + "@vue/shared": "^3.5.18" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + } + } + }, + "node_modules/@vue/babel-plugin-resolve-type": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.5.0.tgz", + "integrity": "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/parser": "^7.28.0", + "@vue/compiler-sfc": "^3.5.18" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@vue/compiler-core": { @@ -1597,18 +2325,6 @@ "source-map-js": "^1.2.1" } }, - "node_modules/@vue/compiler-core/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/@vue/compiler-dom": { "version": "3.5.22", "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.22.tgz", @@ -1647,29 +2363,127 @@ } }, "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==", + "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/@vue/devtools-core": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-8.0.2.tgz", + "integrity": "sha512-V7eKTTHoS6KfK8PSGMLZMhGv/9yNDrmv6Qc3r71QILulnzPnqK2frsTyx3e2MrhdUZnENPEm6hcb4z0GZOqNhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^8.0.2", + "@vue/devtools-shared": "^8.0.2", + "mitt": "^3.0.1", + "nanoid": "^5.1.5", + "pathe": "^2.0.3", + "vite-hot-client": "^2.1.0" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/@vue/devtools-core/node_modules/@vue/devtools-kit": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.0.2.tgz", + "integrity": "sha512-yjZKdEmhJzQqbOh4KFBfTOQjDPMrjjBNCnHBvnTGJX+YLAqoUtY2J+cg7BE+EA8KUv8LprECq04ts75wCoIGWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^8.0.2", + "birpc": "^2.5.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^2.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-core/node_modules/@vue/devtools-shared": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.0.2.tgz", + "integrity": "sha512-mLU0QVdy5Lp40PMGSixDw/Kbd6v5dkQXltd2r+mdVQV7iUog2NlZuLxFZApFZ/mObUBDhoCpf0T3zF2FWWdeHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/devtools-core/node_modules/nanoid": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", + "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/@vue/devtools-core/node_modules/perfect-debounce": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.0.0.tgz", + "integrity": "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==", + "dev": true, "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-typescript": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-12.0.0.tgz", - "integrity": "sha512-StxLFet2Qe97T8+7L8pGlhYBBr8Eg05LPuTDVopQV6il+SK6qqom59BA/rcFipUef2jD8P2X44Vd8tMFytfvlg==", + "version": "14.6.0", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-14.6.0.tgz", + "integrity": "sha512-UpiRY/7go4Yps4mYCjkvlIbVWmn9YvPGQDxTAlcKLphyaD77LjIu3plH4Y9zNT0GB4f3K5tMmhhtRhPOgrQ/bQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "^6.7.0", - "@typescript-eslint/parser": "^6.7.0", - "vue-eslint-parser": "^9.3.1" + "@typescript-eslint/utils": "^8.35.1", + "fast-glob": "^3.3.3", + "typescript-eslint": "^8.35.1", + "vue-eslint-parser": "^10.2.0" }, "engines": { - "node": "^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "peerDependencies": { - "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0", - "eslint-plugin-vue": "^9.0.0", - "typescript": "*" + "eslint": "^9.10.0", + "eslint-plugin-vue": "^9.28.0 || ^10.0.0", + "typescript": ">=4.8.4" }, "peerDependenciesMeta": { "typescript": { @@ -1678,21 +2492,19 @@ } }, "node_modules/@vue/language-core": { - "version": "1.8.27", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.27.tgz", - "integrity": "sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.1.1.tgz", + "integrity": "sha512-qjMY3Q+hUCjdH+jLrQapqgpsJ0rd/2mAY02lZoHG3VFJZZZKLjAlV+Oo9QmWIT4jh8+Rx8RUGUi++d7T9Wb6Mw==", "dev": true, "license": "MIT", "dependencies": { - "@volar/language-core": "~1.11.1", - "@volar/source-map": "~1.11.1", - "@vue/compiler-dom": "^3.3.0", - "@vue/shared": "^3.3.0", - "computeds": "^0.0.1", - "minimatch": "^9.0.3", - "muggle-string": "^0.3.1", + "@volar/language-core": "2.4.23", + "@vue/compiler-dom": "^3.5.0", + "@vue/shared": "^3.5.0", + "alien-signals": "^3.0.0", + "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", - "vue-template-compiler": "^2.7.14" + "picomatch": "^4.0.2" }, "peerDependencies": { "typescript": "*" @@ -1703,20 +2515,17 @@ } } }, - "node_modules/@vue/language-core/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "node_modules/@vue/language-core/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": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, + "license": "MIT", "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/@vue/reactivity": { @@ -1770,17 +2579,28 @@ "license": "MIT" }, "node_modules/@vue/tsconfig": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.5.1.tgz", - "integrity": "sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.8.1.tgz", + "integrity": "sha512-aK7feIWPXFSUhsCP9PFqPyFOcz4ENkb8hZ2pneL6m2UjCkccvaOhC/5KCKluuBufvp2KzkbdA2W2pk20vLzu3g==", "dev": true, - "license": "MIT" + "license": "MIT", + "peerDependencies": { + "typescript": "5.x", + "vue": "^3.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "vue": { + "optional": true + } + } }, "node_modules/@xmldom/xmldom": { "version": "0.8.11", "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -1809,11 +2629,34 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.0.0.tgz", + "integrity": "sha512-JHoRJf18Y6HN4/KZALr3iU+0vW9LKG+8FMThQlbn4+gv8utsLIkwpomjElGPccGeNwh0FI2HN6BLnyFLo6OyLQ==", + "dev": true, + "license": "MIT" + }, "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" @@ -1823,7 +2666,6 @@ "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" @@ -1835,6 +2677,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/ansis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz", + "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1842,21 +2694,10 @@ "dev": true, "license": "Python-2.0" }, - "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/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" @@ -1866,7 +2707,6 @@ "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" @@ -1876,14 +2716,12 @@ "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", @@ -1900,16 +2738,34 @@ ], "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.16", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.16.tgz", + "integrity": "sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, "node_modules/big-integer": { "version": "1.6.52", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", - "dev": true, "license": "Unlicense", "engines": { "node": ">=0.6" } }, + "node_modules/birpc": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.6.1.tgz", + "integrity": "sha512-LPnFhlDpdSH6FJhJyn4M0kFO7vtQ5iPw24FnG0y21q09xC7e8+1LeR31S1MAIrDAHp4m7aas4bEkTDTvMAtebQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -1921,7 +2777,6 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.2.tgz", "integrity": "sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ==", - "dev": true, "license": "MIT", "dependencies": { "big-integer": "1.6.x" @@ -1934,7 +2789,6 @@ "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" @@ -1953,24 +2807,64 @@ "node": ">=8" } }, + "node_modules/browserslist": { + "version": "4.26.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", + "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", + "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": { + "baseline-browser-mapping": "^2.8.9", + "caniuse-lite": "^1.0.30001746", + "electron-to-chromium": "^1.5.227", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "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==", + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, "license": "MIT", - "optional": true, - "peer": true + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/callsites": { "version": "3.1.0", @@ -1982,6 +2876,27 @@ "node": ">=6" } }, + "node_modules/caniuse-lite": { + "version": "1.0.30001750", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001750.tgz", + "integrity": "sha512-cuom0g5sdX6rw00qOoLNSFCJ9/mYIsuSOA+yzpDw8eopiFqcVwQvZHqov0vmEighRxX++cfC0Vg1G+1Iy/mSpQ==", + "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/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2003,7 +2918,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -2013,7 +2927,6 @@ "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" @@ -2026,26 +2939,17 @@ "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/commander": { "version": "9.5.0", "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "dev": true, "license": "MIT", "engines": { "node": "^12.20.0 || >=14" } }, - "node_modules/computeds": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", - "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", - "dev": true, - "license": "MIT" - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2053,11 +2957,32 @@ "dev": true, "license": "MIT" }, + "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/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", @@ -2087,18 +3012,20 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "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/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } }, "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, + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -2119,47 +3046,60 @@ "dev": true, "license": "MIT" }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", "dev": true, "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", "dev": true, "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/doctrine": { + "node_modules/define-lazy-prop": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, + "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/electron-to-chromium": { + "version": "1.5.237", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.237.tgz", + "integrity": "sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==", + "dev": true, + "license": "ISC" + }, "node_modules/elementtree": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/elementtree/-/elementtree-0.1.7.tgz", "integrity": "sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg==", - "dev": true, "license": "Apache-2.0", "dependencies": { "sax": "1.1.4" @@ -2172,23 +3112,43 @@ "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/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/error-stack-parser-es": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz", + "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "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==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", + "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2196,32 +3156,45 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "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" + "@esbuild/aix-ppc64": "0.25.11", + "@esbuild/android-arm": "0.25.11", + "@esbuild/android-arm64": "0.25.11", + "@esbuild/android-x64": "0.25.11", + "@esbuild/darwin-arm64": "0.25.11", + "@esbuild/darwin-x64": "0.25.11", + "@esbuild/freebsd-arm64": "0.25.11", + "@esbuild/freebsd-x64": "0.25.11", + "@esbuild/linux-arm": "0.25.11", + "@esbuild/linux-arm64": "0.25.11", + "@esbuild/linux-ia32": "0.25.11", + "@esbuild/linux-loong64": "0.25.11", + "@esbuild/linux-mips64el": "0.25.11", + "@esbuild/linux-ppc64": "0.25.11", + "@esbuild/linux-riscv64": "0.25.11", + "@esbuild/linux-s390x": "0.25.11", + "@esbuild/linux-x64": "0.25.11", + "@esbuild/netbsd-arm64": "0.25.11", + "@esbuild/netbsd-x64": "0.25.11", + "@esbuild/openbsd-arm64": "0.25.11", + "@esbuild/openbsd-x64": "0.25.11", + "@esbuild/openharmony-arm64": "0.25.11", + "@esbuild/sunos-x64": "0.25.11", + "@esbuild/win32-arm64": "0.25.11", + "@esbuild/win32-ia32": "0.25.11", + "@esbuild/win32-x64": "0.25.11" + } + }, + "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": { @@ -2238,204 +3211,146 @@ } }, "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "version": "9.37.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.37.0.tgz", + "integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.4.0", + "@eslint/core": "^0.16.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.37.0", + "@eslint/plugin-kit": "^0.4.0", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@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.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "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": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-plugin-vue": { - "version": "9.33.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.33.0.tgz", - "integrity": "sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.4.0.tgz", + "integrity": "sha512-K6tP0dW8FJVZLQxa2S7LcE1lLw3X8VvB3t887Q6CLrFVxHYBXGANbXvwNzYIu6Ughx1bSJ5BDT0YB3ybPT39lw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "globals": "^13.24.0", "natural-compare": "^1.4.0", "nth-check": "^2.1.1", "postcss-selector-parser": "^6.0.15", "semver": "^7.6.3", - "vue-eslint-parser": "^9.4.3", "xml-name-validator": "^4.0.0" }, "engines": { - "node": "^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "peerDependencies": { - "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" - } - }, - "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/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/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-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" + "@typescript-eslint/parser": "^7.0.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "vue-eslint-parser": "^10.0.0" }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/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" + "peerDependenciesMeta": { + "@typescript-eslint/parser": { + "optional": true + } } }, - "node_modules/eslint/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==", + "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": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/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==", + "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": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, + "license": "Apache-2.0", "engines": { - "node": ">=10.13.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/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/eslint/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==", + "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": { - "p-locate": "^5.0.0" - }, + "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": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/minimatch": { @@ -2451,51 +3366,32 @@ "node": "*" } }, - "node_modules/eslint/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/eslint/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==", + "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": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "p-limit": "^3.0.2" + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "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==", + "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": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, + "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -2514,16 +3410,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/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/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -2537,7 +3423,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -2563,6 +3449,39 @@ "node": ">=0.10.0" } }, + "node_modules/execa": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.0.tgz", + "integrity": "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/facing-metadata": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/facing-metadata/-/facing-metadata-2.0.3.tgz", + "integrity": "sha512-cznIFYEbjy5LCph7aolYr6+5B1PzJAPsW4q3xdsmJDdZgsepFCBq4vZkBgCGt2LZZKNwji0Qt1xU24JOqg/6xQ==", + "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", @@ -2587,6 +3506,19 @@ "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", @@ -2615,114 +3547,82 @@ "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/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "is-unicode-supported": "^2.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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": { - "to-regex-range": "^5.0.1" + "flat-cache": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=16.0.0" } }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "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": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "to-regex-range": "^5.0.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=8" } }, - "node_modules/flat-cache/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==", + "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": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/flat-cache/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" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": "*" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat-cache/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "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": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": "*" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=16" } }, "node_modules/flatted": { @@ -2736,7 +3636,6 @@ "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", @@ -2752,7 +3651,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -2765,7 +3663,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -2774,11 +3671,16 @@ "node": ">=8" } }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "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": { @@ -2796,11 +3698,37 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "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-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/glob": { "version": "9.3.5", "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", - "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -2816,50 +3744,41 @@ } }, "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==", + "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.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", + "node_modules/glob/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "license": "ISC", "dependencies": { - "type-fest": "^0.20.2" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "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", - "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" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2869,7 +3788,6 @@ "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": { @@ -2889,14 +3807,20 @@ "node": ">=8" } }, - "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==", + "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/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", "dev": true, - "license": "MIT", - "bin": { - "he": "bin/he" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" } }, "node_modules/ignore": { @@ -2917,23 +3841,13 @@ "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/import-fresh/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", + "resolve-from": "^4.0.0" + }, "engines": { - "node": ">=4" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/imurmurhash": { @@ -2946,46 +3860,32 @@ "node": ">=0.8.19" } }, - "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": "4.1.3", "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", - "dev": true, "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3005,7 +3905,6 @@ "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" @@ -3024,6 +3923,25 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -3034,36 +3952,96 @@ "node": ">=0.12.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==", + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, "license": "MIT", "dependencies": { - "is-docker": "^2.0.0" + "is-inside-container": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "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/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "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/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -3077,6 +4055,19 @@ "js-yaml": "bin/js-yaml.js" } }, + "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", @@ -3084,6 +4075,23 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-even-better-errors": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz", + "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "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", @@ -3091,11 +4099,23 @@ "dev": true, "license": "MIT" }, + "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" @@ -3118,12 +4138,18 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3138,12 +4164,21 @@ "node": ">= 0.8.0" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "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" + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -3153,11 +4188,14 @@ "license": "MIT" }, "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==", + "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" + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } }, "node_modules/magic-string": { "version": "0.30.19", @@ -3168,6 +4206,15 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -3193,9 +4240,9 @@ } }, "node_modules/minimatch": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", - "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "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": { @@ -3212,7 +4259,6 @@ "version": "4.2.8", "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", - "dev": true, "license": "ISC", "engines": { "node": ">=8" @@ -3222,7 +4268,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, "license": "MIT", "dependencies": { "minipass": "^3.0.0", @@ -3236,7 +4281,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -3245,11 +4289,22 @@ "node": ">=8" } }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "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/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" @@ -3258,17 +4313,26 @@ "node": ">=10" } }, + "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.3.1", - "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz", - "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==", + "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" }, @@ -3294,7 +4358,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/native-run/-/native-run-2.0.1.tgz", "integrity": "sha512-XfG1FBZLM50J10xH9361whJRC9SHZ0Bub4iNRhhI61C8Jv0e1ud19muex6sNKB51ibQNUJNuYn25MuYET/rE6w==", - "dev": true, "license": "MIT", "dependencies": { "@ionic/utils-fs": "^3.1.7", @@ -3323,6 +4386,132 @@ "dev": true, "license": "MIT" }, + "node_modules/node-releases": { + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", + "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/npm-normalize-package-bin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", + "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-run-all2": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-8.0.4.tgz", + "integrity": "sha512-wdbB5My48XKp2ZfJUlhnLVihzeuA1hgBnqB2J9ahV77wLS+/YAJAlN8I+X3DIFIPZ3m5L7nplmlbhNiFDmXRDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "cross-spawn": "^7.0.6", + "memorystream": "^0.3.1", + "picomatch": "^4.0.2", + "pidtree": "^0.6.0", + "read-package-json-fast": "^4.0.0", + "shell-quote": "^1.7.3", + "which": "^5.0.0" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "npm-run-all2": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": "^20.5.0 || >=22.0.0", + "npm": ">= 10" + } + }, + "node_modules/npm-run-all2/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/npm-run-all2/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/npm-run-all2/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/npm-run-all2/node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/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/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -3336,29 +4525,27 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "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==", + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } + "license": "MIT" }, "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", "dev": true, "license": "MIT", "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3382,6 +4569,38 @@ "node": ">= 0.8.0" } }, + "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/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3395,6 +4614,19 @@ "node": ">=6" } }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "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", @@ -3412,21 +4644,10 @@ "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" @@ -3436,7 +4657,6 @@ "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", @@ -3449,31 +4669,38 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-scurry/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==", + "license": "ISC" + }, "node_modules/path-scurry/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/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "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", - "engines": { - "node": ">=8" - } + "license": "MIT" }, "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/picocolors": { @@ -3495,14 +4722,26 @@ "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/pinia": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz", - "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.3.tgz", + "integrity": "sha512-ttXO/InUULUXkMHpTdp9Fj4hLpD/2AoJdmAbAeW2yu1iy1k+pkFekQXw5VpC0/5p51IOR/jDaDRfRWRnMMsGOA==", "license": "MIT", "dependencies": { - "@vue/devtools-api": "^6.6.3", - "vue-demi": "^0.14.10" + "@vue/devtools-api": "^7.7.2" }, "funding": { "url": "https://github.com/sponsors/posva" @@ -3521,7 +4760,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", - "dev": true, "license": "MIT", "dependencies": { "@xmldom/xmldom": "^0.8.8", @@ -3584,11 +4822,26 @@ "node": ">= 0.8.0" } }, + "node_modules/pretty-ms": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", + "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, "license": "MIT", "dependencies": { "kleur": "^3.0.3", @@ -3602,7 +4855,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -3639,11 +4891,24 @@ ], "license": "MIT" }, + "node_modules/read-package-json-fast": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-4.0.0.tgz", + "integrity": "sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==", + "dev": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^4.0.0", + "npm-normalize-package-bin": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -3654,6 +4919,16 @@ "node": ">= 6" } }, + "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/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -3665,11 +4940,16 @@ "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/rimraf": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", - "dev": true, "license": "ISC", "dependencies": { "glob": "^9.2.0" @@ -3726,6 +5006,19 @@ "fsevents": "~2.3.2" } }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -3754,7 +5047,6 @@ "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", @@ -3775,14 +5067,12 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz", "integrity": "sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg==", - "dev": true, "license": "ISC" }, "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, + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3795,7 +5085,6 @@ "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" @@ -3808,41 +5097,62 @@ "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/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==", + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", "dev": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "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": "MIT" + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", "dev": true, "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, "engines": { - "node": ">=8" + "node": ">=18" } }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, "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", @@ -3856,18 +5166,6 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "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", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -3877,24 +5175,19 @@ "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", - "optional": true, - "peer": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "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/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "dev": true, "license": "ISC", "engines": { "node": ">= 10.x" @@ -3904,7 +5197,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -3914,7 +5206,6 @@ "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", @@ -3929,7 +5220,6 @@ "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" @@ -3938,6 +5228,19 @@ "node": ">=8" } }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -3951,6 +5254,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3968,7 +5283,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "dev": true, "license": "ISC", "dependencies": { "chownr": "^2.0.0", @@ -3986,57 +5300,72 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, "license": "ISC", "engines": { "node": ">=8" } }, - "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==", + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "license": "MIT", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, + "license": "MIT", "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" + "fdir": "^6.5.0", + "picomatch": "^4.0.3" }, "engines": { - "node": ">=10" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "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==", + "node_modules/tinyglobby/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", - "optional": true, - "peer": true - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } }, - "node_modules/through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "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", - "dependencies": { - "readable-stream": "3" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/to-regex-range": { @@ -4045,34 +5374,43 @@ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "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": ">=8.0" + "node": ">=6" } }, "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==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18.12" }, "peerDependencies": { - "typescript": ">=4.2.0" + "typescript": ">=4.8.4" } }, "node_modules/tslib": { @@ -4094,23 +5432,10 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", "bin": { @@ -4121,33 +5446,128 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.1.tgz", + "integrity": "sha512-VHgijW803JafdSsDO8I761r3SHrgk4T00IdyQ+/UsthtgPRsBWQLqoSxOolxTpxRKi1kGXK0bSz4CoAc9ObqJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.46.1", + "@typescript-eslint/parser": "8.46.1", + "@typescript-eslint/typescript-estree": "8.46.1", + "@typescript-eslint/utils": "8.46.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, "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/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "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-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz", + "integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==", + "dev": true, + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/unplugin-utils/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/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/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", @@ -4162,25 +5582,27 @@ "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/vite": { - "version": "5.4.20", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.20.tgz", - "integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==", + "version": "7.1.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.10.tgz", + "integrity": "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -4189,19 +5611,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -4222,113 +5650,264 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, - "node_modules/vue": { - "version": "3.5.22", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz", - "integrity": "sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==", + "node_modules/vite-dev-rpc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vite-dev-rpc/-/vite-dev-rpc-1.1.0.tgz", + "integrity": "sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.22", - "@vue/compiler-sfc": "3.5.22", - "@vue/runtime-dom": "3.5.22", - "@vue/server-renderer": "3.5.22", - "@vue/shared": "3.5.22" + "birpc": "^2.4.0", + "vite-hot-client": "^2.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" }, "peerDependencies": { - "typescript": "*" + "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0" + } + }, + "node_modules/vite-hot-client": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vite-hot-client/-/vite-hot-client-2.1.0.tgz", + "integrity": "sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "vite": "^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0" } }, - "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, + "node_modules/vite-plugin-inspect": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-11.3.3.tgz", + "integrity": "sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==", + "dev": true, "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" + "dependencies": { + "ansis": "^4.1.0", + "debug": "^4.4.1", + "error-stack-parser-es": "^1.0.5", + "ohash": "^2.0.11", + "open": "^10.2.0", + "perfect-debounce": "^2.0.0", + "sirv": "^3.0.1", + "unplugin-utils": "^0.3.0", + "vite-dev-rpc": "^1.1.0" }, "engines": { - "node": ">=12" + "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/antfu" }, "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" + "vite": "^6.0.0 || ^7.0.0-0" }, "peerDependenciesMeta": { - "@vue/composition-api": { + "@nuxt/kit": { "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==", + "node_modules/vite-plugin-inspect/node_modules/perfect-debounce": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.0.0.tgz", + "integrity": "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite-plugin-vue-devtools": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-8.0.2.tgz", + "integrity": "sha512-1069qvMBcyAu3yXQlvYrkwoyLOk0lSSR/gTKy/vy+Det7TXnouGei6ZcKwr5TIe938v/14oLlp0ow6FSJkkORA==", "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" + "@vue/devtools-core": "^8.0.2", + "@vue/devtools-kit": "^8.0.2", + "@vue/devtools-shared": "^8.0.2", + "execa": "^9.6.0", + "sirv": "^3.0.2", + "vite-plugin-inspect": "^11.3.3", + "vite-plugin-vue-inspector": "^5.3.2" }, "engines": { - "node": "^14.17.0 || >=16.0.0" + "node": ">=v14.21.3" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0-0" + } + }, + "node_modules/vite-plugin-vue-devtools/node_modules/@vue/devtools-kit": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.0.2.tgz", + "integrity": "sha512-yjZKdEmhJzQqbOh4KFBfTOQjDPMrjjBNCnHBvnTGJX+YLAqoUtY2J+cg7BE+EA8KUv8LprECq04ts75wCoIGWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^8.0.2", + "birpc": "^2.5.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^2.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/vite-plugin-vue-devtools/node_modules/@vue/devtools-shared": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.0.2.tgz", + "integrity": "sha512-mLU0QVdy5Lp40PMGSixDw/Kbd6v5dkQXltd2r+mdVQV7iUog2NlZuLxFZApFZ/mObUBDhoCpf0T3zF2FWWdeHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/vite-plugin-vue-devtools/node_modules/perfect-debounce": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.0.0.tgz", + "integrity": "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite-plugin-vue-inspector": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/vite-plugin-vue-inspector/-/vite-plugin-vue-inspector-5.3.2.tgz", + "integrity": "sha512-YvEKooQcSiBTAs0DoYLfefNja9bLgkFM7NI2b07bE2SruuvX0MEa9cMaxjKVMkeCp5Nz9FRIdcN1rOdFVBeL6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.0", + "@babel/plugin-proposal-decorators": "^7.23.0", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-transform-typescript": "^7.22.15", + "@vue/babel-plugin-jsx": "^1.1.5", + "@vue/compiler-dom": "^3.3.4", + "kolorist": "^1.8.0", + "magic-string": "^0.30.4" + }, + "peerDependencies": { + "vite": "^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0" + } + }, + "node_modules/vite/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/vite/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/mysticatea" + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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.22", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz", + "integrity": "sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.22", + "@vue/compiler-sfc": "3.5.22", + "@vue/runtime-dom": "3.5.22", + "@vue/server-renderer": "3.5.22", + "@vue/shared": "3.5.22" }, "peerDependencies": { - "eslint": ">=6.0.0" + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "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==", + "node_modules/vue-eslint-parser": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.2.0.tgz", + "integrity": "sha512-CydUvFOQKD928UzZhTp4pr2vWz1L+H99t7Pkln2QSPdvmURT0MoC4wUccfCnuEaihNsu9aYYyk+bep8rlfkUXw==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "debug": "^4.4.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.6.0", + "semver": "^7.6.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" } }, - "node_modules/vue-eslint-parser/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/vue-eslint-parser/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": "BSD-2-Clause", + "license": "Apache-2.0", "engines": { - "node": ">=4.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/vue-facing-decorator": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/vue-facing-decorator/-/vue-facing-decorator-3.0.4.tgz", - "integrity": "sha512-Lk90PevJllB6qRRdLvLFjATZrv00nof1Ob6afavKL7Pc7V3eEin3vhdvEDRORdWKVvNoXhJbHejngWVuT0Pt0g==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/vue-facing-decorator/-/vue-facing-decorator-4.0.1.tgz", + "integrity": "sha512-zBvPoiXVVCOSctoKmcYUHFu2qu0AGYAZOfT6LnPqcrSSOpElTJTd21cOIrGrnA1rYwzlp8jhQLmlcBKv1ETNRA==", "license": "MIT", + "dependencies": { + "facing-metadata": "^2.0.0" + }, "peerDependencies": { "vue": "^3.0.0" } @@ -4348,40 +5927,33 @@ "vue": "^3.5.0" } }, - "node_modules/vue-template-compiler": { - "version": "2.7.16", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", - "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "de-indent": "^1.0.2", - "he": "^1.2.0" - } + "node_modules/vue-router/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-tsc": { - "version": "1.8.27", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.27.tgz", - "integrity": "sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.1.1.tgz", + "integrity": "sha512-fyixKxFniOVgn+L/4+g8zCG6dflLLt01Agz9jl3TO45Bgk87NZJRmJVPsiK+ouq3LB91jJCbOV+pDkzYTxbI7A==", "dev": true, "license": "MIT", "dependencies": { - "@volar/typescript": "~1.11.1", - "@vue/language-core": "1.8.27", - "semver": "^7.5.4" + "@volar/typescript": "2.4.23", + "@vue/language-core": "3.1.1" }, "bin": { "vue-tsc": "bin/vue-tsc.js" }, "peerDependencies": { - "typescript": "*" + "typescript": ">=5.0.0" } }, "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" @@ -4407,7 +5979,6 @@ "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", @@ -4421,12 +5992,21 @@ "url": "https://github.com/chalk/wrap-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==", + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", "dev": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/xml-name-validator": { "version": "4.0.0", @@ -4442,7 +6022,6 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", - "dev": true, "license": "MIT", "dependencies": { "sax": ">=0.6.0", @@ -4456,7 +6035,6 @@ "version": "11.0.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true, "license": "MIT", "engines": { "node": ">=4.0" @@ -4466,16 +6044,15 @@ "version": "15.1.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.0" } }, "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "license": "ISC" }, @@ -4483,7 +6060,6 @@ "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", @@ -4502,6 +6078,19 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/test-apps/daily-notification-test/package.json b/test-apps/daily-notification-test/package.json new file mode 100644 index 0000000..f992939 --- /dev/null +++ b/test-apps/daily-notification-test/package.json @@ -0,0 +1,42 @@ +{ + "name": "daily-notification-test", + "version": "0.0.0", + "private": true, + "type": "module", + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build", + "lint": "eslint . --fix" + }, + "dependencies": { + "@capacitor/android": "^6.2.1", + "@capacitor/cli": "^6.2.1", + "@capacitor/core": "^6.2.1", + "date-fns": "^4.1.0", + "pinia": "^3.0.3", + "vue": "^3.5.22", + "vue-facing-decorator": "^4.0.1", + "vue-router": "^4.5.1" + }, + "devDependencies": { + "@tsconfig/node22": "^22.0.2", + "@types/node": "^22.18.6", + "@vitejs/plugin-vue": "^6.0.1", + "@vue/eslint-config-typescript": "^14.6.0", + "@vue/tsconfig": "^0.8.1", + "eslint": "^9.33.0", + "eslint-plugin-vue": "~10.4.0", + "jiti": "^2.5.1", + "npm-run-all2": "^8.0.4", + "typescript": "~5.9.0", + "vite": "^7.1.7", + "vite-plugin-vue-devtools": "^8.0.2", + "vue-tsc": "^3.1.0" + } +} diff --git a/test-apps/daily-notification-test/public/favicon.ico b/test-apps/daily-notification-test/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df36fcfb72584e00488330b560ebcf34a41c64c2 GIT binary patch literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S literal 0 HcmV?d00001 diff --git a/test-apps/daily-notification-test/src/App.vue b/test-apps/daily-notification-test/src/App.vue new file mode 100644 index 0000000..8c1536b --- /dev/null +++ b/test-apps/daily-notification-test/src/App.vue @@ -0,0 +1,125 @@ + + + + + + + \ No newline at end of file diff --git a/test-apps/daily-notification-test/src/assets/base.css b/test-apps/daily-notification-test/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/test-apps/daily-notification-test/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/test-apps/daily-notification-test/src/assets/logo.svg b/test-apps/daily-notification-test/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/test-apps/daily-notification-test/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/test-apps/daily-notification-test/src/assets/main.css b/test-apps/daily-notification-test/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/test-apps/daily-notification-test/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/test-apps/daily-notification-test/src/components/HelloWorld.vue b/test-apps/daily-notification-test/src/components/HelloWorld.vue new file mode 100644 index 0000000..d174cf8 --- /dev/null +++ b/test-apps/daily-notification-test/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/test-apps/daily-notification-test/src/components/TheWelcome.vue b/test-apps/daily-notification-test/src/components/TheWelcome.vue new file mode 100644 index 0000000..6092dff --- /dev/null +++ b/test-apps/daily-notification-test/src/components/TheWelcome.vue @@ -0,0 +1,94 @@ + + + diff --git a/test-apps/daily-notification-test/src/components/WelcomeItem.vue b/test-apps/daily-notification-test/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/test-apps/daily-notification-test/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/test-apps/daily-notification-test/src/components/cards/ActionCard.vue b/test-apps/daily-notification-test/src/components/cards/ActionCard.vue new file mode 100644 index 0000000..adaa885 --- /dev/null +++ b/test-apps/daily-notification-test/src/components/cards/ActionCard.vue @@ -0,0 +1,141 @@ + + + + + + + diff --git a/test-apps/daily-notification-test/src/components/cards/StatusCard.vue b/test-apps/daily-notification-test/src/components/cards/StatusCard.vue new file mode 100644 index 0000000..9388a3a --- /dev/null +++ b/test-apps/daily-notification-test/src/components/cards/StatusCard.vue @@ -0,0 +1,202 @@ + + + + + + + diff --git a/test-apps/daily-notification-test/src/components/icons/IconCommunity.vue b/test-apps/daily-notification-test/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/test-apps/daily-notification-test/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/test-apps/daily-notification-test/src/components/icons/IconDocumentation.vue b/test-apps/daily-notification-test/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/test-apps/daily-notification-test/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/test-apps/daily-notification-test/src/components/icons/IconEcosystem.vue b/test-apps/daily-notification-test/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/test-apps/daily-notification-test/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/test-apps/daily-notification-test/src/components/icons/IconSupport.vue b/test-apps/daily-notification-test/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/test-apps/daily-notification-test/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/test-apps/daily-notification-test/src/components/icons/IconTooling.vue b/test-apps/daily-notification-test/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/test-apps/daily-notification-test/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/test-apps/daily-notification-test/src/components/layout/AppFooter.vue b/test-apps/daily-notification-test/src/components/layout/AppFooter.vue new file mode 100644 index 0000000..2354d89 --- /dev/null +++ b/test-apps/daily-notification-test/src/components/layout/AppFooter.vue @@ -0,0 +1,113 @@ + + + + + + + diff --git a/test-apps/daily-notification-test/src/components/layout/AppHeader.vue b/test-apps/daily-notification-test/src/components/layout/AppHeader.vue new file mode 100644 index 0000000..2f5d1f7 --- /dev/null +++ b/test-apps/daily-notification-test/src/components/layout/AppHeader.vue @@ -0,0 +1,270 @@ + + + + + + + diff --git a/test-apps/android-test/src/components/ui/ErrorDialog.vue b/test-apps/daily-notification-test/src/components/ui/ErrorDialog.vue similarity index 54% rename from test-apps/android-test/src/components/ui/ErrorDialog.vue rename to test-apps/daily-notification-test/src/components/ui/ErrorDialog.vue index b153e11..0375d43 100644 --- a/test-apps/android-test/src/components/ui/ErrorDialog.vue +++ b/test-apps/daily-notification-test/src/components/ui/ErrorDialog.vue @@ -1,8 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/test-apps/daily-notification-test/src/views/LogsView.vue b/test-apps/daily-notification-test/src/views/LogsView.vue new file mode 100644 index 0000000..17437e6 --- /dev/null +++ b/test-apps/daily-notification-test/src/views/LogsView.vue @@ -0,0 +1,475 @@ + + + + + + + diff --git a/test-apps/daily-notification-test/src/views/NotFoundView.vue b/test-apps/daily-notification-test/src/views/NotFoundView.vue new file mode 100644 index 0000000..ed6d6cb --- /dev/null +++ b/test-apps/daily-notification-test/src/views/NotFoundView.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/test-apps/daily-notification-test/src/views/NotificationsView.vue b/test-apps/daily-notification-test/src/views/NotificationsView.vue new file mode 100644 index 0000000..e98238f --- /dev/null +++ b/test-apps/daily-notification-test/src/views/NotificationsView.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/test-apps/daily-notification-test/src/views/ScheduleView.vue b/test-apps/daily-notification-test/src/views/ScheduleView.vue new file mode 100644 index 0000000..7ba05e2 --- /dev/null +++ b/test-apps/daily-notification-test/src/views/ScheduleView.vue @@ -0,0 +1,180 @@ + + + + + + + diff --git a/test-apps/android-test/src/views/SettingsView.vue b/test-apps/daily-notification-test/src/views/SettingsView.vue similarity index 62% rename from test-apps/android-test/src/views/SettingsView.vue rename to test-apps/daily-notification-test/src/views/SettingsView.vue index 65dd793..5c1741f 100644 --- a/test-apps/android-test/src/views/SettingsView.vue +++ b/test-apps/daily-notification-test/src/views/SettingsView.vue @@ -1,21 +1,11 @@ - - @@ -29,43 +19,36 @@ export default class SettingsView extends Vue {} diff --git a/test-apps/daily-notification-test/src/views/StatusView.vue b/test-apps/daily-notification-test/src/views/StatusView.vue new file mode 100644 index 0000000..1dfeca4 --- /dev/null +++ b/test-apps/daily-notification-test/src/views/StatusView.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/test-apps/daily-notification-test/tsconfig.app.json b/test-apps/daily-notification-test/tsconfig.app.json new file mode 100644 index 0000000..cbd2fbc --- /dev/null +++ b/test-apps/daily-notification-test/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "useDefineForClassFields": false, + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/test-apps/daily-notification-test/tsconfig.json b/test-apps/daily-notification-test/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/test-apps/daily-notification-test/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/test-apps/daily-notification-test/tsconfig.node.json b/test-apps/daily-notification-test/tsconfig.node.json new file mode 100644 index 0000000..a83dfc9 --- /dev/null +++ b/test-apps/daily-notification-test/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node22/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*", + "eslint.config.*" + ], + "compilerOptions": { + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/test-apps/daily-notification-test/vite.config.ts b/test-apps/daily-notification-test/vite.config.ts new file mode 100644 index 0000000..4217010 --- /dev/null +++ b/test-apps/daily-notification-test/vite.config.ts @@ -0,0 +1,18 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueDevTools from 'vite-plugin-vue-devtools' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + vueDevTools(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + }, + }, +}) diff --git a/test-apps/electron-test/.gitignore b/test-apps/electron-test/.gitignore deleted file mode 100644 index b84c901..0000000 --- a/test-apps/electron-test/.gitignore +++ /dev/null @@ -1,114 +0,0 @@ -# Dependencies -node_modules/ -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Build outputs -dist/ -build/ -*.tsbuildinfo - -# Electron -out/ -app/ -packages/ - -# IDE and editor files -.vscode/ -.idea/ -*.swp -*.swo -*~ - -# OS generated files -.DS_Store -.DS_Store? -._* -.Spotlight-V100 -.Trashes -ehthumbs.db -Thumbs.db - -# Logs -logs -*.log - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Coverage directory used by tools like istanbul -coverage/ -*.lcov - -# nyc test coverage -.nyc_output - -# Dependency directories -jspm_packages/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test -.env.local -.env.development.local -.env.test.local -.env.production.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# next.js build output -.next - -# nuxt.js build output -.nuxt - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Electron specific -*.app -*.dmg -*.exe -*.deb -*.rpm -*.AppImage -*.snap diff --git a/test-apps/electron-test/main.js b/test-apps/electron-test/main.js deleted file mode 100644 index 145dace..0000000 --- a/test-apps/electron-test/main.js +++ /dev/null @@ -1,117 +0,0 @@ -const { app, BrowserWindow, ipcMain } = require('electron'); -const path = require('path'); - -// Mock plugin for Electron development -const DailyNotification = { - async configure(options) { - console.log('Electron Configure called:', options); - return Promise.resolve(); - }, - async scheduleDailyNotification(options) { - console.log('Electron Schedule called:', options); - return Promise.resolve(); - }, - async getDebugInfo() { - return Promise.resolve({ - status: 'Electron Mock Mode', - configuration: { - storage: 'mock', - platform: 'electron', - version: '1.0.0' - }, - recentErrors: [], - performance: { - overallScore: 95, - memoryUsage: 15.2, - cpuUsage: 1.2 - } - }); - }, - async getPerformanceMetrics() { - return Promise.resolve({ - overallScore: 95, - databasePerformance: 100, - memoryEfficiency: 95, - batteryEfficiency: 100, - objectPoolEfficiency: 100, - totalDatabaseQueries: 0, - averageMemoryUsage: 15.2, - objectPoolHits: 0, - backgroundCpuUsage: 0.5, - totalNetworkRequests: 0, - recommendations: ['Electron mock mode - no optimizations needed'] - }); - } -}; - -// IPC handlers for Electron -ipcMain.handle('configure-plugin', async (event, options) => { - try { - await DailyNotification.configure(options); - return { success: true, message: 'Configuration successful' }; - } catch (error) { - return { success: false, error: error.message }; - } -}); - -ipcMain.handle('schedule-notification', async (event, options) => { - try { - await DailyNotification.scheduleDailyNotification(options); - return { success: true, message: 'Notification scheduled' }; - } catch (error) { - return { success: false, error: error.message }; - } -}); - -ipcMain.handle('get-debug-info', async () => { - try { - const info = await DailyNotification.getDebugInfo(); - return { success: true, data: info }; - } catch (error) { - return { success: false, error: error.message }; - } -}); - -ipcMain.handle('get-performance-metrics', async () => { - try { - const metrics = await DailyNotification.getPerformanceMetrics(); - return { success: true, data: metrics }; - } catch (error) { - return { success: false, error: error.message }; - } -}); - -function createWindow() { - const mainWindow = new BrowserWindow({ - width: 800, - height: 600, - webPreferences: { - nodeIntegration: false, - contextIsolation: true, - preload: path.join(__dirname, 'preload.js') - }, - title: 'Daily Notification - Electron Test' - }); - - // Load the web app - mainWindow.loadFile('dist/index.html'); - - // Open DevTools in development - if (process.argv.includes('--dev')) { - mainWindow.webContents.openDevTools(); - } -} - -app.whenReady().then(createWindow); - -app.on('window-all-closed', () => { - if (process.platform !== 'darwin') { - app.quit(); - } -}); - -app.on('activate', () => { - if (BrowserWindow.getAllWindows().length === 0) { - createWindow(); - } -}); diff --git a/test-apps/electron-test/package.json b/test-apps/electron-test/package.json deleted file mode 100644 index d38b31b..0000000 --- a/test-apps/electron-test/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "daily-notification-electron-test", - "version": "1.0.0", - "description": "Minimal Electron test app for Daily Notification Plugin", - "main": "main.js", - "scripts": { - "start": "electron .", - "dev": "electron . --dev", - "build": "webpack --mode=production", - "build-web": "webpack --mode=production", - "electron": "npm run build-web && electron ." - }, - "keywords": ["capacitor", "electron", "notifications", "test"], - "author": "Matthew Raymer", - "license": "MIT", - "dependencies": { - "@capacitor/core": "^5.0.0", - "@capacitor/cli": "^5.0.0", - "electron": "^25.0.0" - }, - "devDependencies": { - "webpack": "^5.88.0", - "webpack-cli": "^5.1.0", - "html-webpack-plugin": "^5.5.0", - "typescript": "^5.0.0", - "ts-loader": "^9.4.0" - } -} diff --git a/test-apps/electron-test/preload.js b/test-apps/electron-test/preload.js deleted file mode 100644 index aacb6cc..0000000 --- a/test-apps/electron-test/preload.js +++ /dev/null @@ -1,10 +0,0 @@ -const { contextBridge, ipcRenderer } = require('electron'); - -// Expose protected methods that allow the renderer process to use -// the ipcRenderer without exposing the entire object -contextBridge.exposeInMainWorld('electronAPI', { - configurePlugin: (options) => ipcRenderer.invoke('configure-plugin', options), - scheduleNotification: (options) => ipcRenderer.invoke('schedule-notification', options), - getDebugInfo: () => ipcRenderer.invoke('get-debug-info'), - getPerformanceMetrics: () => ipcRenderer.invoke('get-performance-metrics') -}); diff --git a/test-apps/electron-test/src/index.html b/test-apps/electron-test/src/index.html deleted file mode 100644 index 605eb44..0000000 --- a/test-apps/electron-test/src/index.html +++ /dev/null @@ -1,476 +0,0 @@ - - - - - - Daily Notification - Electron Test - - - -
-

⚡ TimeSafari Daily Notification - Electron Test

- -
Ready
- - -
-

🔐 Permission Management

-
-
- - - -
-
- - -
-

⚙️ Configuration

-
-
- - -
-
- - -
-

📊 Status Monitoring

-
-
- - -
-
- - -
-

⚡ Electron-Specific Features

-
-
- - - -
-
- - -
-

🧪 Testing & Debug

-
- - - - -
-
- - -
-

🚀 Phase 4: TimeSafari Components

-
- - - - -
-
- - -
-

⏰ Static Daily Reminders

-
- - - - -
-
-

Reminder Configuration

-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- -
-
-
- - -
-

⚠️ Error Handling

-
-
- - -
-

📝 Activity Log

-
- -
-
- - -
- - - - diff --git a/test-apps/electron-test/src/index.ts b/test-apps/electron-test/src/index.ts deleted file mode 100644 index 9ea4372..0000000 --- a/test-apps/electron-test/src/index.ts +++ /dev/null @@ -1,1085 +0,0 @@ -import { ConfigLoader, MockDailyNotificationService, TestLogger } from '../shared/config-loader'; - -// Phase 4: Import TimeSafari components -import { EndorserAPIClient } from '../shared/typescript/EndorserAPIClient'; -import { SecurityManager } from '../shared/typescript/SecurityManager'; -import { TimeSafariNotificationManager } from '../shared/typescript/TimeSafariNotificationManager'; -// import { -// TimeSafariUser, -// TimeSafariPreferences, -// EnhancedTimeSafariNotification, -// TimeSafariNotificationType -// } from '../../../src/definitions'; - -// Enhanced UI components for Electron testing -class PermissionManager { - private container: HTMLElement; - private dialogContainer: HTMLElement; - - constructor(container: HTMLElement, dialogContainer: HTMLElement) { - this.container = container; - this.dialogContainer = dialogContainer; - } - - async updateStatus(): Promise { - // Mock permission status for Electron testing - const mockStatus = { - granted: true, - notifications: 'granted' as const, - serviceWorker: 'active' as const - }; - - this.renderStatus(mockStatus); - } - - private renderStatus(status: Record): void { - const statusClass = status.granted ? 'status-granted' : 'status-denied'; - const statusText = status.granted ? 'Granted' : 'Denied'; - - this.container.innerHTML = ` -
-
- ${status.granted ? '✓' : '✗'} - ${statusText} -
-
-
- Notifications: - - ${status.notifications} - -
-
- Service Worker: - - ${status.serviceWorker} - -
-
-
- `; - } - - showPermissionDialog(): void { - const dialog = document.createElement('div'); - dialog.className = 'dialog-overlay'; - dialog.innerHTML = ` -
-

Enable Daily Notifications

-

Get notified about new offers, projects, people, and items in your TimeSafari community.

-
    -
  • New offers directed to you
  • -
  • Changes to your projects
  • -
  • Updates from favorited people
  • -
  • New items of interest
  • -
-
- - - -
-
- `; - - this.dialogContainer.appendChild(dialog); - - dialog.querySelector('#allow-permissions')?.addEventListener('click', () => { - this.hideDialog(); - this.updateStatus(); - }); - - dialog.querySelector('#deny-permissions')?.addEventListener('click', () => { - this.hideDialog(); - }); - - dialog.querySelector('#never-permissions')?.addEventListener('click', () => { - this.hideDialog(); - }); - } - - private hideDialog(): void { - const dialog = this.dialogContainer.querySelector('.dialog-overlay'); - if (dialog) { - dialog.remove(); - } - } -} - -class SettingsPanel { - private container: HTMLElement; - - constructor(container: HTMLElement) { - this.container = container; - } - - render(): void { - this.container.innerHTML = ` -
-
- -
- -
- - -
- -
- -
- - - - -
-
- -
- -
- - - -
-
- -
- -
-
- `; - } -} - -class StatusDashboard { - private container: HTMLElement; - - constructor(container: HTMLElement) { - this.container = container; - } - - render(): void { - this.container.innerHTML = ` -
-
-
-
Overall Status
-
Active
-
- -
-
Next Notification
-
2h 15m
-
- -
-
Last Outcome
-
Success
-
- -
-
Cache Age
-
1h 23m
-
-
- -
-

Performance

-
-
- Success Rate: - 95% -
-
- Error Count: - 2 -
-
-
-
- `; - } -} - -class ErrorDisplay { - private container: HTMLElement; - - constructor(container: HTMLElement) { - this.container = container; - } - - showError(error: Error): void { - this.container.innerHTML = ` -
-
⚠️
-
-

Something went wrong

-

${error.message}

-

Error Code: ${error.name}

-
-
- - -
-
- `; - } - - hide(): void { - this.container.innerHTML = ''; - } -} - -// Enhanced test interface for TimeSafari Electron integration -// Enhanced test interface for TimeSafari Electron integration with Phase 4 components -class TimeSafariElectronTestApp { - private statusElement: HTMLElement; - private logElement: HTMLElement; - private configLoader: ConfigLoader; - private notificationService: MockDailyNotificationService; - private logger: TestLogger; - - // Phase 4: TimeSafari components - private endorserAPIClient: EndorserAPIClient; - private securityManager: SecurityManager; - private timeSafariNotificationManager: TimeSafariNotificationManager; - - // UI Components - private permissionManager: PermissionManager; - private settingsPanel: SettingsPanel; - private statusDashboard: StatusDashboard; - private errorDisplay: ErrorDisplay; - - constructor() { - const statusElement = document.getElementById('status'); - const logElement = document.getElementById('log'); - if (!statusElement || !logElement) { - throw new Error('Required DOM elements not found'); - } - this.statusElement = statusElement; - this.logElement = logElement; - this.configLoader = ConfigLoader.getInstance(); - this.logger = new TestLogger('debug'); - this.notificationService = new MockDailyNotificationService(this.configLoader.getConfig()); - - // Phase 4: Initialize TimeSafari components - this.endorserAPIClient = new EndorserAPIClient(this.configLoader.getEndorserAPIConfig()); - this.securityManager = new SecurityManager(this.configLoader.getSecurityConfig()); - this.timeSafariNotificationManager = new TimeSafariNotificationManager(); - - // Initialize UI components - const permissionStatusContainer = document.getElementById('permission-status-container'); - const permissionDialogContainer = document.getElementById('permission-dialog-container'); - const settingsContainer = document.getElementById('settings-container'); - const statusContainer = document.getElementById('status-container'); - const errorContainer = document.getElementById('error-container'); - - if (!permissionStatusContainer || !permissionDialogContainer || !settingsContainer || !statusContainer || !errorContainer) { - throw new Error('Required UI containers not found'); - } - - this.permissionManager = new PermissionManager( - permissionStatusContainer, - permissionDialogContainer - ); - this.settingsPanel = new SettingsPanel(settingsContainer); - this.statusDashboard = new StatusDashboard(statusContainer); - this.errorDisplay = new ErrorDisplay(errorContainer); - - this.setupEventListeners(); - this.initializeUI(); - this.initializePhase4Components(); - this.log('TimeSafari Electron Test app initialized with Phase 4 components'); - } - - private setupEventListeners(): void { - // Original test functionality - document.getElementById('configure')?.addEventListener('click', () => this.testConfigure()); - document.getElementById('schedule')?.addEventListener('click', () => this.testSchedule()); - document.getElementById('endorser-api')?.addEventListener('click', () => this.testEndorserAPI()); - document.getElementById('callbacks')?.addEventListener('click', () => this.testCallbacks()); - document.getElementById('debug-info')?.addEventListener('click', () => this.testDebugInfo()); - document.getElementById('performance')?.addEventListener('click', () => this.testPerformance()); - document.getElementById('clear-log')?.addEventListener('click', () => this.clearLog()); - - // Enhanced UI functionality - document.getElementById('check-permissions')?.addEventListener('click', () => this.checkPermissions()); - document.getElementById('request-permissions')?.addEventListener('click', () => this.requestPermissions()); - document.getElementById('open-settings')?.addEventListener('click', () => this.openSettings()); - document.getElementById('test-notification')?.addEventListener('click', () => this.testNotification()); - document.getElementById('check-status')?.addEventListener('click', () => this.testStatus()); - document.getElementById('refresh-status')?.addEventListener('click', () => this.refreshStatus()); - document.getElementById('service-worker-status')?.addEventListener('click', () => this.checkServiceWorker()); - document.getElementById('push-notification-status')?.addEventListener('click', () => this.checkPushNotifications()); - - // Phase 4: TimeSafari component testing - document.getElementById('test-security-manager')?.addEventListener('click', () => this.testSecurityManager()); - document.getElementById('test-endorser-api-client')?.addEventListener('click', () => this.testEndorserAPIClient()); - document.getElementById('test-notification-manager')?.addEventListener('click', () => this.testTimeSafariNotificationManager()); - document.getElementById('test-phase4-integration')?.addEventListener('click', () => this.testPhase4Integration()); - - // Static Daily Reminder event listeners - document.getElementById('schedule-reminder')?.addEventListener('click', () => this.scheduleDailyReminder()); - document.getElementById('cancel-reminder')?.addEventListener('click', () => this.cancelDailyReminder()); - document.getElementById('get-reminders')?.addEventListener('click', () => this.getScheduledReminders()); - document.getElementById('update-reminder')?.addEventListener('click', () => this.updateDailyReminder()); - } - - private async initializeUI(): Promise { - try { - // Initialize UI components - await this.permissionManager.updateStatus(); - this.settingsPanel.render(); - this.statusDashboard.render(); - - this.log('✅ Enhanced UI components initialized'); - } catch (error) { - this.log(`❌ UI initialization failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - // Phase 4: Initialize TimeSafari components - private async initializePhase4Components(): Promise { - try { - this.log('Initializing Phase 4 TimeSafari components...'); - - // Initialize SecurityManager with test DID - const timeSafariUser = this.configLoader.getTimeSafariUser(); - const securityInitialized = await this.securityManager.initialize(timeSafariUser.activeDid); - - if (securityInitialized) { - this.log('✅ SecurityManager initialized successfully'); - - // Generate JWT token for API authentication - const jwt = await this.securityManager.generateJWT({ - scope: 'notifications', - audience: 'endorser-api' - }); - - if (jwt) { - this.endorserAPIClient.setAuthToken(jwt); - this.log('✅ JWT token generated and set for EndorserAPI'); - } - } else { - this.log('❌ SecurityManager initialization failed'); - } - - // Initialize TimeSafariNotificationManager - const managerInitialized = await this.timeSafariNotificationManager.initialize(timeSafariUser); - - if (managerInitialized) { - this.log('✅ TimeSafariNotificationManager initialized successfully'); - } else { - this.log('❌ TimeSafariNotificationManager initialization failed'); - } - - this.log('Phase 4 components initialization completed'); - - } catch (error) { - this.log('Error initializing Phase 4 components:', error); - this.errorDisplay.showError(error as Error); - } - } - - // Enhanced UI methods - private async checkPermissions(): Promise { - try { - this.log('Checking permissions...'); - await this.permissionManager.updateStatus(); - this.log('✅ Permission status updated'); - } catch (error) { - this.log(`❌ Permission check failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - private async requestPermissions(): Promise { - try { - this.log('Requesting permissions...'); - this.permissionManager.showPermissionDialog(); - this.log('✅ Permission dialog shown'); - } catch (error) { - this.log(`❌ Permission request failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - private async openSettings(): Promise { - try { - this.log('Opening settings...'); - // Mock settings opening - this.log('✅ Settings opened (mock)'); - } catch (error) { - this.log(`❌ Settings open failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - private async testNotification(): Promise { - try { - this.log('Sending test notification...'); - // Mock test notification - this.log('✅ Test notification sent (mock)'); - } catch (error) { - this.log(`❌ Test notification failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - private async refreshStatus(): Promise { - try { - this.log('Refreshing status...'); - this.statusDashboard.render(); - this.log('✅ Status refreshed'); - } catch (error) { - this.log(`❌ Status refresh failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - private async checkServiceWorker(): Promise { - try { - this.log('Checking service worker status...'); - // Mock service worker status - this.log('✅ Service worker: Active (mock)'); - } catch (error) { - this.log(`❌ Service worker check failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - private async checkPushNotifications(): Promise { - try { - this.log('Checking push notification status...'); - // Mock push notification status - this.log('✅ Push notifications: Enabled (mock)'); - } catch (error) { - this.log(`❌ Push notification check failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - private async testConfigure(): Promise { - try { - this.log('Testing TimeSafari Electron configuration...'); - await this.configLoader.loadConfig(); - const config = this.configLoader.getConfig(); - - await this.notificationService.initialize(); - - this.log('✅ TimeSafari Electron configuration successful', { - appId: config.timesafari.appId, - appName: config.timesafari.appName, - version: config.timesafari.version - }); - this.updateStatus('Configured'); - } catch (error) { - this.log(`❌ Configuration failed: ${error}`); - } - } - - private async testSchedule(): Promise { - try { - this.log('Testing TimeSafari Electron community notification scheduling...'); - const config = this.configLoader.getConfig(); - - const dualConfig = { - contentFetch: { - enabled: true, - schedule: config.scheduling.contentFetch.schedule, - url: this.configLoader.getEndorserUrl('notificationsBundle'), - headers: this.configLoader.getAuthHeaders(), - ttlSeconds: 3600, - timeout: 30000, - retryAttempts: 3, - retryDelay: 5000, - callbacks: { - onSuccess: async (data: Record): Promise => { - this.log('✅ Content fetch successful', data); - await this.processEndorserNotificationBundle(data); - }, - onError: async (error: Record): Promise => { - this.log('❌ Content fetch failed', error); - } - } - }, - userNotification: { - enabled: true, - schedule: config.scheduling.userNotification.schedule, - title: 'TimeSafari Community Update', - body: 'New offers, projects, people, and items await your attention!', - sound: true, - vibration: true, - priority: 'high', - actions: [ - { id: 'view_offers', title: 'View Offers' }, - { id: 'view_projects', title: 'See Projects' }, - { id: 'view_people', title: 'Check People' }, - { id: 'view_items', title: 'Browse Items' }, - { id: 'dismiss', title: 'Dismiss' } - ] - }, - relationship: { - autoLink: true, - contentTimeout: 300000, - fallbackBehavior: 'show_default' - } - }; - - await this.notificationService.scheduleDualNotification(dualConfig); - this.log('✅ Electron community notification scheduled successfully'); - this.updateStatus('Scheduled'); - } catch (error) { - this.log(`❌ Electron scheduling failed: ${error}`); - } - } - - private async testEndorserAPI(): Promise { - try { - this.log('Testing Endorser.ch API integration on Electron...'); - const config = this.configLoader.getConfig(); - const testData = config.testData; - - // Test parallel API requests pattern - const requests = [ - // Offers to person - fetch(`${this.configLoader.getEndorserUrl('offers')}?recipientId=${testData.userDid}&afterId=${testData.lastKnownOfferId}`, { - headers: this.configLoader.getAuthHeaders() - }), - - // Offers to user's projects - fetch(`${this.configLoader.getEndorserUrl('offersToPlans')}?afterId=${testData.lastKnownOfferId}`, { - headers: this.configLoader.getAuthHeaders() - }), - - // Changes to starred projects - fetch(this.configLoader.getEndorserUrl('plansLastUpdated'), { - method: 'POST', - headers: this.configLoader.getAuthHeaders(), - body: JSON.stringify({ - planIds: testData.starredPlanIds, - afterId: testData.lastKnownPlanId - }) - }) - ]; - - const [offersToPerson, offersToProjects, starredChanges] = await Promise.all(requests); - - const notificationData = { - offersToPerson: await offersToPerson.json(), - offersToProjects: await offersToProjects.json(), - starredChanges: await starredChanges.json() - }; - - this.log('✅ Endorser.ch API integration successful on Electron', { - offersToPerson: notificationData.offersToPerson.data?.length || 0, - offersToProjects: notificationData.offersToProjects.data?.length || 0, - starredChanges: notificationData.starredChanges.data?.length || 0 - }); - - this.updateStatus('API Connected'); - } catch (error) { - this.log(`❌ Endorser.ch API test failed: ${error}`); - } - } - - private async testCallbacks(): Promise { - try { - this.log('Testing TimeSafari Electron notification callbacks...'); - // const config = this.configLoader.getConfig(); - - // Register offers callback - await this.notificationService.registerCallback('offers', async (event: Record) => { - this.log('📨 Electron Offers callback triggered', event); - await this.handleOffersNotification(event); - }); - - // Register projects callback - await this.notificationService.registerCallback('projects', async (event: Record) => { - this.log('📨 Electron Projects callback triggered', event); - await this.handleProjectsNotification(event); - }); - - // Register people callback - await this.notificationService.registerCallback('people', async (event: Record) => { - this.log('📨 Electron People callback triggered', event); - await this.handlePeopleNotification(event); - }); - - // Register items callback - await this.notificationService.registerCallback('items', async (event: Record) => { - this.log('📨 Electron Items callback triggered', event); - await this.handleItemsNotification(event); - }); - - this.log('✅ All Electron callbacks registered successfully'); - this.updateStatus('Callbacks Registered'); - } catch (error) { - this.log(`❌ Electron callback registration failed: ${error}`); - } - } - - private async testDebugInfo(): Promise { - try { - this.log('Testing Electron debug info...'); - const debugInfo = { - platform: 'electron', - nodeVersion: process.versions.node, - electronVersion: process.versions.electron, - chromeVersion: process.versions.chrome, - status: 'running', - config: this.configLoader.getConfig().timesafari, - timestamp: new Date().toISOString() - }; - - this.log('🔍 Electron Debug Info:', debugInfo); - this.updateStatus(`Debug: ${debugInfo.status}`); - } catch (error) { - this.log(`❌ Debug info failed: ${error}`); - } - } - - private async testPerformance(): Promise { - try { - this.log('Testing Electron performance metrics...'); - const metrics = { - overallScore: 82, - databasePerformance: 85, - memoryEfficiency: 78, - batteryEfficiency: 80, - objectPoolEfficiency: 85, - totalDatabaseQueries: 100, - averageMemoryUsage: 30.2, - objectPoolHits: 25, - backgroundCpuUsage: 3.1, - totalNetworkRequests: 15, - recommendations: ['Optimize IPC communication', 'Reduce memory usage'] - }; - - this.log('📊 Electron Performance Metrics:', metrics); - this.updateStatus(`Performance: ${metrics.overallScore}/100`); - } catch (error) { - this.log(`❌ Performance check failed: ${error}`); - } - } - - /** - * Process Endorser.ch notification bundle using parallel API requests - */ - private async processEndorserNotificationBundle(data: Record): Promise { - try { - this.log('Processing Endorser.ch notification bundle on Electron...'); - - // Process each notification type - if (data.offersToPerson?.data?.length > 0) { - await this.handleOffersNotification(data.offersToPerson); - } - - if (data.starredChanges?.data?.length > 0) { - await this.handleProjectsNotification(data.starredChanges); - } - - this.log('✅ Electron notification bundle processed successfully'); - } catch (error) { - this.log(`❌ Electron bundle processing failed: ${error}`); - } - } - - /** - * Handle offers notification events from Endorser.ch API - */ - private async handleOffersNotification(event: Record): Promise { - this.log('Handling Electron offers notification:', event); - - if (event.data && event.data.length > 0) { - // Process OfferSummaryArrayMaybeMoreBody format - event.data.forEach((offer: Record) => { - this.log('Processing Electron offer:', { - jwtId: offer.jwtId, - handleId: offer.handleId, - offeredByDid: offer.offeredByDid, - recipientDid: offer.recipientDid, - objectDescription: offer.objectDescription - }); - }); - - // Check if there are more offers to fetch - if (event.hitLimit) { - const lastOffer = event.data[event.data.length - 1]; - this.log('More offers available, last JWT ID:', lastOffer.jwtId); - } - } - } - - /** - * Handle projects notification events from Endorser.ch API - */ - private async handleProjectsNotification(event: Record): Promise { - this.log('Handling Electron projects notification:', event); - - if (event.data && event.data.length > 0) { - // Process PlanSummaryAndPreviousClaimArrayMaybeMore format - event.data.forEach((planData: Record) => { - const { plan, wrappedClaimBefore } = planData; - this.log('Processing Electron project change:', { - jwtId: plan.jwtId, - handleId: plan.handleId, - name: plan.name, - issuerDid: plan.issuerDid, - hasPreviousClaim: !!wrappedClaimBefore - }); - }); - - // Check if there are more project changes to fetch - if (event.hitLimit) { - const lastPlan = event.data[event.data.length - 1]; - this.log('More project changes available, last JWT ID:', lastPlan.plan.jwtId); - } - } - } - - /** - * Handle people notification events - */ - private async handlePeopleNotification(event: Record): Promise { - this.log('Handling Electron people notification:', event); - // Implementation would process people data and update local state - } - - /** - * Handle items notification events - */ - private async handleItemsNotification(event: Record): Promise { - this.log('Handling Electron items notification:', event); - // Implementation would process items data and update local state - } - - private log(message: string, data?: Record): void { - const timestamp = new Date().toLocaleTimeString(); - const logEntry = document.createElement('div'); - logEntry.innerHTML = `[${timestamp}] ${message}`; - if (data) { - logEntry.innerHTML += `
${JSON.stringify(data, null, 2)}
`; - } - this.logElement.appendChild(logEntry); - this.logElement.scrollTop = this.logElement.scrollHeight; - } - - private clearLog(): void { - this.logElement.innerHTML = ''; - this.log('Log cleared'); - } - - private updateStatus(status: string): void { - this.statusElement.textContent = status; - } - - // Phase 4: TimeSafari component test methods - private async testSecurityManager(): Promise { - try { - this.log('🔐 Testing SecurityManager (Electron)...'); - - // const timeSafariUser = this.configLoader.getTimeSafariUser(); - - // Test JWT generation - const jwt = await this.securityManager.generateJWT({ - scope: 'test', - audience: 'test-api' - }); - - if (jwt) { - this.log('✅ JWT generation successful'); - this.log('JWT token:', jwt.substring(0, 50) + '...'); - - // Test JWT verification - const claims = await this.securityManager.verifyJWT(jwt); - if (claims) { - this.log('✅ JWT verification successful'); - this.log('Claims:', claims); - } else { - this.log('❌ JWT verification failed'); - } - } else { - this.log('❌ JWT generation failed'); - } - - // Test operation history - const history = this.securityManager.getOperationHistory(); - this.log(`Security operations performed: ${history.length}`); - - this.log('SecurityManager test completed'); - - } catch (error) { - this.log('SecurityManager test failed:', error); - this.errorDisplay.showError(error as Error); - } - } - - private async testEndorserAPIClient(): Promise { - try { - this.log('🌐 Testing EndorserAPIClient (Electron)...'); - - const timeSafariUser = this.configLoader.getTimeSafariUser(); - - // Test offers to person - this.log('Testing offers to person...'); - const offersResponse = await this.endorserAPIClient.fetchOffersToPerson( - timeSafariUser.activeDid, - timeSafariUser.lastKnownOfferId, - undefined - ); - - this.log(`✅ Offers fetched: ${offersResponse.data.length} offers`); - if (offersResponse.data.length > 0) { - this.log('Sample offer:', offersResponse.data[0]); - } - - // Test offers to projects - this.log('Testing offers to projects...'); - const projectsResponse = await this.endorserAPIClient.fetchOffersToProjectsOwnedByMe( - timeSafariUser.lastKnownOfferId - ); - - this.log(`✅ Project offers fetched: ${projectsResponse.data.length} offers`); - - // Test project updates - if (timeSafariUser.starredPlanIds && timeSafariUser.starredPlanIds.length > 0) { - this.log('Testing project updates...'); - const updatesResponse = await this.endorserAPIClient.fetchProjectsLastUpdated( - timeSafariUser.starredPlanIds, - timeSafariUser.lastKnownPlanId, - undefined - ); - - this.log(`✅ Project updates fetched: ${updatesResponse.data.length} updates`); - } - - this.log('EndorserAPIClient test completed'); - - } catch (error) { - this.log('EndorserAPIClient test failed:', error); - this.errorDisplay.showError(error as Error); - } - } - - private async testTimeSafariNotificationManager(): Promise { - try { - this.log('📱 Testing TimeSafariNotificationManager (Electron)...'); - - // Test notification generation - this.log('Generating TimeSafari notifications...'); - const notifications = await this.timeSafariNotificationManager.generateNotifications({ - forceFetch: false, - includeMetadata: true, - filterByPriority: true, - maxNotifications: 10, - cacheTtl: 300000 - }); - - this.log(`✅ Generated ${notifications.length} notifications`); - - // Display notification details - notifications.forEach((notification, index) => { - this.log(`Notification ${index + 1}:`, { - type: notification.type, - subtype: notification.subtype, - priority: notification.notificationPriority, - timestamp: new Date(notification.timestamp).toISOString(), - disabled: notification.disabled, - sound: notification.sound, - vibration: notification.vibration - }); - }); - - // Test statistics - const stats = this.timeSafariNotificationManager.getStatistics(); - this.log('Manager statistics:', stats); - - this.log('TimeSafariNotificationManager test completed'); - - } catch (error) { - this.log('TimeSafariNotificationManager test failed:', error); - this.errorDisplay.showError(error as Error); - } - } - - private async testPhase4Integration(): Promise { - try { - this.log('🚀 Testing complete Phase 4 integration (Electron)...'); - - const timeSafariUser = this.configLoader.getTimeSafariUser(); - - // Test complete workflow - this.log('Step 1: Security authentication...'); - const jwt = await this.securityManager.generateJWT({ - scope: 'notifications', - audience: 'endorser-api' - }); - - if (!jwt) { - throw new Error('JWT generation failed'); - } - - this.endorserAPIClient.setAuthToken(jwt); - this.log('✅ Authentication successful'); - - this.log('Step 2: Fetching TimeSafari data...'); - const bundle = await this.endorserAPIClient.fetchAllTimeSafariNotifications({ - activeDid: timeSafariUser.activeDid, - starredPlanIds: timeSafariUser.starredPlanIds || [], - lastKnownOfferId: timeSafariUser.lastKnownOfferId, - lastKnownPlanId: timeSafariUser.lastKnownPlanId, - fetchOffersToPerson: true, - fetchOffersToProjects: true, - fetchProjectUpdates: true, - notificationPreferences: { - offers: true, - projects: true, - people: false, - items: true - } - }); - - this.log(`✅ Data fetched successfully: ${bundle.success}`); - this.log('Bundle metadata:', bundle.metadata); - - this.log('Step 3: Generating notifications...'); - const notifications = await this.timeSafariNotificationManager.generateNotifications({ - forceFetch: true, - includeMetadata: true, - maxNotifications: 20 - }); - - this.log(`✅ Generated ${notifications.length} notifications`); - - // Summary - this.log('🎉 Phase 4 integration test completed successfully!'); - this.log('Summary:', { - securityInitialized: this.securityManager.isInitialized(), - apiClientReady: !!this.endorserAPIClient, - managerInitialized: this.timeSafariNotificationManager.isInitialized(), - notificationsGenerated: notifications.length, - bundleSuccess: bundle.success - }); - - } catch (error) { - this.log('Phase 4 integration test failed:', error); - this.errorDisplay.showError(error as Error); - } - } - - // Static Daily Reminder Methods - private async scheduleDailyReminder(): Promise { - try { - this.log('Scheduling daily reminder...'); - - const reminderOptions = { - id: (document.getElementById('reminder-id') as HTMLInputElement)?.value || 'morning_checkin', - title: (document.getElementById('reminder-title') as HTMLInputElement)?.value || 'Good Morning!', - body: (document.getElementById('reminder-body') as HTMLInputElement)?.value || 'Time to check your TimeSafari community updates', - time: (document.getElementById('reminder-time') as HTMLInputElement)?.value || '09:00', - sound: (document.getElementById('reminder-sound') as HTMLInputElement)?.checked ?? true, - vibration: (document.getElementById('reminder-vibration') as HTMLInputElement)?.checked ?? true, - priority: (document.getElementById('reminder-priority') as HTMLSelectElement)?.value || 'normal', - repeatDaily: (document.getElementById('reminder-repeat') as HTMLInputElement)?.checked ?? true - }; - - this.log('Reminder options:', reminderOptions); - - await this.plugin.scheduleDailyReminder(reminderOptions); - this.log('✅ Daily reminder scheduled successfully'); - this.errorDisplay.showSuccess('Daily reminder scheduled successfully!'); - - } catch (error) { - this.log('❌ Failed to schedule daily reminder:', error); - this.errorDisplay.showError(error as Error); - } - } - - private async cancelDailyReminder(): Promise { - try { - this.log('Cancelling daily reminder...'); - - const reminderId = (document.getElementById('reminder-id') as HTMLInputElement)?.value || 'morning_checkin'; - - await this.plugin.cancelDailyReminder(reminderId); - this.log('✅ Daily reminder cancelled successfully'); - this.errorDisplay.showSuccess('Daily reminder cancelled successfully!'); - - } catch (error) { - this.log('❌ Failed to cancel daily reminder:', error); - this.errorDisplay.showError(error as Error); - } - } - - private async getScheduledReminders(): Promise { - try { - this.log('Getting scheduled reminders...'); - - const result = await this.plugin.getScheduledReminders(); - this.log('✅ Scheduled reminders retrieved:', result); - - if (result.reminders && result.reminders.length > 0) { - this.errorDisplay.showSuccess(`Found ${result.reminders.length} scheduled reminders`); - // eslint-disable-next-line no-console - console.table(result.reminders); - } else { - this.errorDisplay.showInfo('No scheduled reminders found'); - } - - } catch (error) { - this.log('❌ Failed to get scheduled reminders:', error); - this.errorDisplay.showError(error as Error); - } - } - - private async updateDailyReminder(): Promise { - try { - this.log('Updating daily reminder...'); - - const reminderId = (document.getElementById('reminder-id') as HTMLInputElement)?.value || 'morning_checkin'; - - const updateOptions = { - title: (document.getElementById('reminder-title') as HTMLInputElement)?.value, - body: (document.getElementById('reminder-body') as HTMLInputElement)?.value, - time: (document.getElementById('reminder-time') as HTMLInputElement)?.value, - sound: (document.getElementById('reminder-sound') as HTMLInputElement)?.checked, - vibration: (document.getElementById('reminder-vibration') as HTMLInputElement)?.checked, - priority: (document.getElementById('reminder-priority') as HTMLSelectElement)?.value, - repeatDaily: (document.getElementById('reminder-repeat') as HTMLInputElement)?.checked - }; - - this.log('Update options:', updateOptions); - - await this.plugin.updateDailyReminder(reminderId, updateOptions); - this.log('✅ Daily reminder updated successfully'); - this.errorDisplay.showSuccess('Daily reminder updated successfully!'); - - } catch (error) { - this.log('❌ Failed to update daily reminder:', error); - this.errorDisplay.showError(error as Error); - } - } -} - -// Initialize app when DOM is ready -document.addEventListener('DOMContentLoaded', () => { - new TimeSafariElectronTestApp(); -}); diff --git a/test-apps/electron-test/tsconfig.json b/test-apps/electron-test/tsconfig.json deleted file mode 100644 index aa6eba6..0000000 --- a/test-apps/electron-test/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ES2020", - "moduleResolution": "node", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "outDir": "./dist", - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] -} diff --git a/test-apps/electron-test/webpack.config.js b/test-apps/electron-test/webpack.config.js deleted file mode 100644 index a818f67..0000000 --- a/test-apps/electron-test/webpack.config.js +++ /dev/null @@ -1,28 +0,0 @@ -const path = require('path'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); - -module.exports = { - entry: './src/index.ts', - module: { - rules: [ - { - test: /\.ts$/, - use: 'ts-loader', - exclude: /node_modules/, - }, - ], - }, - resolve: { - extensions: ['.ts', '.js'], - }, - output: { - filename: 'bundle.js', - path: path.resolve(__dirname, 'dist'), - clean: true, - }, - plugins: [ - new HtmlWebpackPlugin({ - template: './src/index.html', - }), - ], -}; diff --git a/test-apps/ios-test/.gitignore b/test-apps/ios-test/.gitignore deleted file mode 100644 index a217c10..0000000 --- a/test-apps/ios-test/.gitignore +++ /dev/null @@ -1,105 +0,0 @@ -# Dependencies -node_modules/ -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Build outputs -dist/ -build/ -*.tsbuildinfo - -# Capacitor -android/ -ios/ -.capacitor/ - -# IDE and editor files -.vscode/ -.idea/ -*.swp -*.swo -*~ - -# OS generated files -.DS_Store -.DS_Store? -._* -.Spotlight-V100 -.Trashes -ehthumbs.db -Thumbs.db - -# Logs -logs -*.log - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Coverage directory used by tools like istanbul -coverage/ -*.lcov - -# nyc test coverage -.nyc_output - -# Dependency directories -jspm_packages/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test -.env.local -.env.development.local -.env.test.local -.env.production.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# next.js build output -.next - -# nuxt.js build output -.nuxt - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port diff --git a/test-apps/ios-test/capacitor.config.ts b/test-apps/ios-test/capacitor.config.ts deleted file mode 100644 index 0e88c7b..0000000 --- a/test-apps/ios-test/capacitor.config.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { CapacitorConfig } from '@capacitor/cli'; - -const config: CapacitorConfig = { - appId: 'com.timesafari.dailynotification.iostest', - appName: 'Daily Notification iOS Test', - webDir: 'dist', - server: { - iosScheme: 'capacitor' - }, - plugins: { - DailyNotification: { - storage: 'shared', - ttlSeconds: 1800, - prefetchLeadMinutes: 15, - enableETagSupport: true, - enableErrorHandling: true, - enablePerformanceOptimization: true - } - }, - ios: { - scheme: 'Daily Notification iOS Test' - } -}; - -export default config; diff --git a/test-apps/ios-test/package.json b/test-apps/ios-test/package.json deleted file mode 100644 index 38d2b81..0000000 --- a/test-apps/ios-test/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "daily-notification-ios-test", - "version": "1.0.0", - "description": "Minimal iOS test app for Daily Notification Plugin", - "main": "index.js", - "scripts": { - "build": "webpack --mode=production", - "dev": "webpack serve --mode=development", - "ios": "npx cap run ios", - "sync": "npx cap sync ios", - "open": "npx cap open ios" - }, - "keywords": ["capacitor", "ios", "notifications", "test"], - "author": "Matthew Raymer", - "license": "MIT", - "dependencies": { - "@capacitor/core": "^5.0.0", - "@capacitor/ios": "^5.0.0", - "@capacitor/cli": "^5.0.0" - }, - "devDependencies": { - "webpack": "^5.88.0", - "webpack-cli": "^5.1.0", - "webpack-dev-server": "^4.15.0", - "html-webpack-plugin": "^5.5.0", - "typescript": "^5.0.0", - "ts-loader": "^9.4.0" - } -} diff --git a/test-apps/ios-test/src/index.html b/test-apps/ios-test/src/index.html deleted file mode 100644 index ab1241f..0000000 --- a/test-apps/ios-test/src/index.html +++ /dev/null @@ -1,476 +0,0 @@ - - - - - - Daily Notification - iOS Test - - - -
-

🍎 TimeSafari Daily Notification - iOS Test

- -
Ready
- - -
-

🔐 Permission Management

-
-
- - - -
-
- - -
-

⚙️ Configuration

-
-
- - -
-
- - -
-

📊 Status Monitoring

-
-
- - -
-
- - -
-

🍎 iOS-Specific Features

-
-
- - - -
-
- - -
-

🧪 Testing & Debug

-
- - - - -
-
- - -
-

🚀 Phase 4: TimeSafari Components

-
- - - - -
-
- - -
-

⏰ Static Daily Reminders

-
- - - - -
-
-

Reminder Configuration

-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- -
-
-
- - -
-

⚠️ Error Handling

-
-
- - -
-

📝 Activity Log

-
- -
-
- - -
- - - - diff --git a/test-apps/ios-test/src/index.ts b/test-apps/ios-test/src/index.ts deleted file mode 100644 index 6efb729..0000000 --- a/test-apps/ios-test/src/index.ts +++ /dev/null @@ -1,1340 +0,0 @@ -// import { Capacitor } from '@capacitor/core'; -import { ConfigLoader, MockDailyNotificationService, TestLogger } from '../shared/config-loader'; - -// Phase 4: Import TimeSafari components -import { EndorserAPIClient } from '../shared/typescript/EndorserAPIClient'; -import { SecurityManager } from '../shared/typescript/SecurityManager'; -import { TimeSafariNotificationManager } from '../shared/typescript/TimeSafariNotificationManager'; -// import { -// TimeSafariUser, -// TimeSafariPreferences, -// EnhancedTimeSafariNotification, -// TimeSafariNotificationType -// } from '../../../src/definitions'; - -// Generic Polling Interface -import { - GenericPollingRequest, - PollingScheduleConfig, - PollingResult, - StarredProjectsRequest, - StarredProjectsResponse, - calculateBackoffDelay, - createDefaultOutboxPressureManager -} from '../../../packages/polling-contracts/src'; - -// Enhanced UI components for iOS testing -class PermissionManager { - private container: HTMLElement; - private dialogContainer: HTMLElement; - - constructor(container: HTMLElement, dialogContainer: HTMLElement) { - this.container = container; - this.dialogContainer = dialogContainer; - } - - async updateStatus(): Promise { - // Mock permission status for iOS testing - const mockStatus = { - granted: true, - notifications: 'granted' as const, - backgroundRefresh: 'granted' as const - }; - - this.renderStatus(mockStatus); - } - - private renderStatus(status: Record): void { - const statusClass = status.granted ? 'status-granted' : 'status-denied'; - const statusText = status.granted ? 'Granted' : 'Denied'; - - this.container.innerHTML = ` -
-
- ${status.granted ? '✓' : '✗'} - ${statusText} -
-
-
- Notifications: - - ${status.notifications} - -
-
- Background Refresh: - - ${status.backgroundRefresh} - -
-
-
- `; - } - - showPermissionDialog(): void { - const dialog = document.createElement('div'); - dialog.className = 'dialog-overlay'; - dialog.innerHTML = ` -
-

Enable Daily Notifications

-

Get notified about new offers, projects, people, and items in your TimeSafari community.

-
    -
  • New offers directed to you
  • -
  • Changes to your projects
  • -
  • Updates from favorited people
  • -
  • New items of interest
  • -
-
- - - -
-
- `; - - this.dialogContainer.appendChild(dialog); - - dialog.querySelector('#allow-permissions')?.addEventListener('click', () => { - this.hideDialog(); - this.updateStatus(); - }); - - dialog.querySelector('#deny-permissions')?.addEventListener('click', () => { - this.hideDialog(); - }); - - dialog.querySelector('#never-permissions')?.addEventListener('click', () => { - this.hideDialog(); - }); - } - - private hideDialog(): void { - const dialog = this.dialogContainer.querySelector('.dialog-overlay'); - if (dialog) { - dialog.remove(); - } - } -} - -class SettingsPanel { - private container: HTMLElement; - - constructor(container: HTMLElement) { - this.container = container; - } - - render(): void { - this.container.innerHTML = ` -
-
- -
- -
- - -
- -
- -
- - - - -
-
- -
- -
- - - -
-
- -
- -
-
- `; - } -} - -class StatusDashboard { - private container: HTMLElement; - - constructor(container: HTMLElement) { - this.container = container; - } - - render(): void { - this.container.innerHTML = ` -
-
-
-
Overall Status
-
Active
-
- -
-
Next Notification
-
2h 15m
-
- -
-
Last Outcome
-
Success
-
- -
-
Cache Age
-
1h 23m
-
-
- -
-

Performance

-
-
- Success Rate: - 95% -
-
- Error Count: - 2 -
-
-
-
- `; - } -} - -class ErrorDisplay { - private container: HTMLElement; - - constructor(container: HTMLElement) { - this.container = container; - } - - showError(error: Error): void { - this.container.innerHTML = ` -
-
⚠️
-
-

Something went wrong

-

${error.message}

-

Error Code: ${error.name}

-
-
- - -
-
- `; - } - - hide(): void { - this.container.innerHTML = ''; - } -} - -// Enhanced test interface for TimeSafari iOS integration with Phase 4 components -class TimeSafariIOSTestApp { - private statusElement: HTMLElement; - private logElement: HTMLElement; - private configLoader: ConfigLoader; - private notificationService: MockDailyNotificationService; - private logger: TestLogger; - - // Phase 4: TimeSafari components - private endorserAPIClient: EndorserAPIClient; - private securityManager: SecurityManager; - private timeSafariNotificationManager: TimeSafariNotificationManager; - - // UI Components - private permissionManager: PermissionManager; - private settingsPanel: SettingsPanel; - private statusDashboard: StatusDashboard; - private errorDisplay: ErrorDisplay; - - constructor() { - const statusElement = document.getElementById('status'); - const logElement = document.getElementById('log'); - if (!statusElement || !logElement) { - throw new Error('Required DOM elements not found'); - } - this.statusElement = statusElement; - this.logElement = logElement; - this.configLoader = ConfigLoader.getInstance(); - this.logger = new TestLogger('debug'); - this.notificationService = new MockDailyNotificationService(this.configLoader.getConfig()); - - // Phase 4: Initialize TimeSafari components - const endorserAPIConfig = this.configLoader.getEndorserAPIConfig(); - const securityConfig = this.configLoader.getSecurityConfig(); - if (!endorserAPIConfig || !securityConfig) { - throw new Error('Required configurations not found'); - } - this.endorserAPIClient = new EndorserAPIClient(endorserAPIConfig); - this.securityManager = new SecurityManager(securityConfig); - this.timeSafariNotificationManager = new TimeSafariNotificationManager(); - - // Initialize UI components - const permissionStatusContainer = document.getElementById('permission-status-container'); - const permissionDialogContainer = document.getElementById('permission-dialog-container'); - const settingsContainer = document.getElementById('settings-container'); - const statusContainer = document.getElementById('status-container'); - const errorContainer = document.getElementById('error-container'); - - if (!permissionStatusContainer || !permissionDialogContainer || !settingsContainer || !statusContainer || !errorContainer) { - throw new Error('Required UI containers not found'); - } - - this.permissionManager = new PermissionManager( - permissionStatusContainer, - permissionDialogContainer - ); - this.settingsPanel = new SettingsPanel(settingsContainer); - this.statusDashboard = new StatusDashboard(statusContainer); - this.errorDisplay = new ErrorDisplay(errorContainer); - - this.setupEventListeners(); - this.initializeUI(); - this.initializePhase4Components(); - this.log('TimeSafari iOS Test app initialized with Phase 4 components'); - } - - private setupEventListeners(): void { - // Original test functionality - document.getElementById('configure')?.addEventListener('click', () => this.testConfigure()); - document.getElementById('schedule')?.addEventListener('click', () => this.testSchedule()); - document.getElementById('rolling-window')?.addEventListener('click', () => this.testRollingWindow()); - document.getElementById('endorser-api')?.addEventListener('click', () => this.testEndorserAPI()); - document.getElementById('callbacks')?.addEventListener('click', () => this.testCallbacks()); - document.getElementById('performance')?.addEventListener('click', () => this.testPerformance()); - document.getElementById('clear-log')?.addEventListener('click', () => this.clearLog()); - - // Enhanced UI functionality - document.getElementById('check-permissions')?.addEventListener('click', () => this.checkPermissions()); - document.getElementById('request-permissions')?.addEventListener('click', () => this.requestPermissions()); - document.getElementById('open-settings')?.addEventListener('click', () => this.openSettings()); - document.getElementById('test-notification')?.addEventListener('click', () => this.testNotification()); - document.getElementById('check-status')?.addEventListener('click', () => this.testStatus()); - document.getElementById('refresh-status')?.addEventListener('click', () => this.refreshStatus()); - document.getElementById('background-refresh-status')?.addEventListener('click', () => this.checkBackgroundRefresh()); - document.getElementById('bg-task-status')?.addEventListener('click', () => this.checkBGTaskStatus()); - - // Phase 4: TimeSafari component testing - document.getElementById('test-security-manager')?.addEventListener('click', () => this.testSecurityManager()); - document.getElementById('test-endorser-api-client')?.addEventListener('click', () => this.testEndorserAPIClient()); - document.getElementById('test-notification-manager')?.addEventListener('click', () => this.testTimeSafariNotificationManager()); - document.getElementById('test-phase4-integration')?.addEventListener('click', () => this.testPhase4Integration()); - - // Generic Polling Interface testing - document.getElementById('test-generic-polling')?.addEventListener('click', () => this.testGenericPolling()); - document.getElementById('test-polling-schedule')?.addEventListener('click', () => this.testPollingSchedule()); - document.getElementById('test-polling-results')?.addEventListener('click', () => this.testPollingResults()); - - // Static Daily Reminder event listeners - document.getElementById('schedule-reminder')?.addEventListener('click', () => this.scheduleDailyReminder()); - document.getElementById('cancel-reminder')?.addEventListener('click', () => this.cancelDailyReminder()); - document.getElementById('get-reminders')?.addEventListener('click', () => this.getScheduledReminders()); - document.getElementById('update-reminder')?.addEventListener('click', () => this.updateDailyReminder()); - } - - private async initializeUI(): Promise { - try { - // Initialize UI components - await this.permissionManager.updateStatus(); - this.settingsPanel.render(); - this.statusDashboard.render(); - - this.log('✅ Enhanced UI components initialized'); - } catch (error) { - this.log(`❌ UI initialization failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - // Phase 4: Initialize TimeSafari components - private async initializePhase4Components(): Promise { - try { - this.log('Initializing Phase 4 TimeSafari components...'); - - // Initialize SecurityManager with test DID - const timeSafariUser = this.configLoader.getTimeSafariUser(); - const securityInitialized = await this.securityManager.initialize(timeSafariUser.activeDid); - - if (securityInitialized) { - this.log('✅ SecurityManager initialized successfully'); - - // Generate JWT token for API authentication - const jwt = await this.securityManager.generateJWT({ - scope: 'notifications', - audience: 'endorser-api' - }); - - if (jwt) { - this.endorserAPIClient.setAuthToken(jwt); - this.log('✅ JWT token generated and set for EndorserAPI'); - } - } else { - this.log('❌ SecurityManager initialization failed'); - } - - // Initialize TimeSafariNotificationManager - const managerInitialized = await this.timeSafariNotificationManager.initialize(timeSafariUser); - - if (managerInitialized) { - this.log('✅ TimeSafariNotificationManager initialized successfully'); - } else { - this.log('❌ TimeSafariNotificationManager initialization failed'); - } - - this.log('Phase 4 components initialization completed'); - - } catch (error) { - this.log('Error initializing Phase 4 components:', error); - this.errorDisplay.showError(error as Error); - } - } - - // Enhanced UI methods - private async checkPermissions(): Promise { - try { - this.log('Checking permissions...'); - await this.permissionManager.updateStatus(); - this.log('✅ Permission status updated'); - } catch (error) { - this.log(`❌ Permission check failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - private async requestPermissions(): Promise { - try { - this.log('Requesting permissions...'); - this.permissionManager.showPermissionDialog(); - this.log('✅ Permission dialog shown'); - } catch (error) { - this.log(`❌ Permission request failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - private async openSettings(): Promise { - try { - this.log('Opening settings...'); - // Mock settings opening - this.log('✅ Settings opened (mock)'); - } catch (error) { - this.log(`❌ Settings open failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - private async testNotification(): Promise { - try { - this.log('Sending test notification...'); - // Mock test notification - this.log('✅ Test notification sent (mock)'); - } catch (error) { - this.log(`❌ Test notification failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - private async refreshStatus(): Promise { - try { - this.log('Refreshing status...'); - this.statusDashboard.render(); - this.log('✅ Status refreshed'); - } catch (error) { - this.log(`❌ Status refresh failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - private async checkBackgroundRefresh(): Promise { - try { - this.log('Checking background app refresh status...'); - // Mock background refresh status - this.log('✅ Background app refresh: Enabled (mock)'); - } catch (error) { - this.log(`❌ Background refresh check failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - private async checkBGTaskStatus(): Promise { - try { - this.log('Checking BGTaskScheduler status...'); - // Mock BGTaskScheduler status - this.log('✅ BGTaskScheduler: Active (mock)'); - } catch (error) { - this.log(`❌ BGTaskScheduler check failed: ${error}`); - this.errorDisplay.showError(error as Error); - } - } - - private async testConfigure(): Promise { - try { - this.log('Testing TimeSafari iOS configuration...'); - await this.configLoader.loadConfig(); - const config = this.configLoader.getConfig(); - - await this.notificationService.initialize(); - - this.log('✅ TimeSafari iOS configuration successful', { - appId: config.timesafari.appId, - appName: config.timesafari.appName, - version: config.timesafari.version - }); - this.updateStatus('Configured'); - } catch (error) { - this.log(`❌ Configuration failed: ${error}`); - } - } - - private async testSchedule(): Promise { - try { - this.log('Testing TimeSafari iOS community notification scheduling...'); - const config = this.configLoader.getConfig(); - - const dualConfig = { - contentFetch: { - enabled: true, - schedule: config.scheduling.contentFetch.schedule, - url: this.configLoader.getEndorserUrl('notificationsBundle'), - headers: this.configLoader.getAuthHeaders(), - ttlSeconds: 3600, - timeout: 30000, - retryAttempts: 3, - retryDelay: 5000, - callbacks: { - onSuccess: async (data: Record): Promise => { - this.log('✅ Content fetch successful', data); - await this.processEndorserNotificationBundle(data); - }, - onError: async (error: Record): Promise => { - this.log('❌ Content fetch failed', error); - } - } - }, - userNotification: { - enabled: true, - schedule: config.scheduling.userNotification.schedule, - title: 'TimeSafari Community Update', - body: 'New offers, projects, people, and items await your attention!', - sound: true, - vibration: true, - priority: 'high', - actions: [ - { id: 'view_offers', title: 'View Offers' }, - { id: 'view_projects', title: 'See Projects' }, - { id: 'view_people', title: 'Check People' }, - { id: 'view_items', title: 'Browse Items' }, - { id: 'dismiss', title: 'Dismiss' } - ] - }, - relationship: { - autoLink: true, - contentTimeout: 300000, - fallbackBehavior: 'show_default' - } - }; - - await this.notificationService.scheduleDualNotification(dualConfig); - this.log('✅ iOS community notification scheduled successfully'); - this.updateStatus('Scheduled'); - } catch (error) { - this.log(`❌ iOS scheduling failed: ${error}`); - } - } - - private async testRollingWindow(): Promise { - try { - this.log('Testing iOS rolling window maintenance...'); - // Simulate rolling window maintenance - const stats = { - stats: '64 pending notifications, 20 daily limit', - maintenanceNeeded: false, - timeUntilNextMaintenance: 900000 - }; - - this.log('✅ Rolling window maintenance completed', stats); - this.updateStatus('Rolling Window Maintained'); - } catch (error) { - this.log(`❌ Rolling window maintenance failed: ${error}`); - } - } - - private async testEndorserAPI(): Promise { - try { - this.log('Testing Endorser.ch API integration on iOS...'); - const config = this.configLoader.getConfig(); - const testData = config.testData; - - // Test parallel API requests pattern - const requests = [ - // Offers to person - fetch(`${this.configLoader.getEndorserUrl('offers')}?recipientId=${testData.userDid}&afterId=${testData.lastKnownOfferId}`, { - headers: this.configLoader.getAuthHeaders() - }), - - // Offers to user's projects - fetch(`${this.configLoader.getEndorserUrl('offersToPlans')}?afterId=${testData.lastKnownOfferId}`, { - headers: this.configLoader.getAuthHeaders() - }), - - // Changes to starred projects - fetch(this.configLoader.getEndorserUrl('plansLastUpdated'), { - method: 'POST', - headers: this.configLoader.getAuthHeaders(), - body: JSON.stringify({ - planIds: testData.starredPlanIds, - afterId: testData.lastKnownPlanId - }) - }) - ]; - - const [offersToPerson, offersToProjects, starredChanges] = await Promise.all(requests); - - const notificationData = { - offersToPerson: await offersToPerson.json(), - offersToProjects: await offersToProjects.json(), - starredChanges: await starredChanges.json() - }; - - this.log('✅ Endorser.ch API integration successful on iOS', { - offersToPerson: notificationData.offersToPerson.data?.length || 0, - offersToProjects: notificationData.offersToProjects.data?.length || 0, - starredChanges: notificationData.starredChanges.data?.length || 0 - }); - - this.updateStatus('API Connected'); - } catch (error) { - this.log(`❌ Endorser.ch API test failed: ${error}`); - } - } - - private async testCallbacks(): Promise { - try { - this.log('Testing TimeSafari iOS notification callbacks...'); - // const config = this.configLoader.getConfig(); - - // Register offers callback - await this.notificationService.registerCallback('offers', async (event: Record) => { - this.log('📨 iOS Offers callback triggered', event); - await this.handleOffersNotification(event); - }); - - // Register projects callback - await this.notificationService.registerCallback('projects', async (event: Record) => { - this.log('📨 iOS Projects callback triggered', event); - await this.handleProjectsNotification(event); - }); - - // Register people callback - await this.notificationService.registerCallback('people', async (event: Record) => { - this.log('📨 iOS People callback triggered', event); - await this.handlePeopleNotification(event); - }); - - // Register items callback - await this.notificationService.registerCallback('items', async (event: Record) => { - this.log('📨 iOS Items callback triggered', event); - await this.handleItemsNotification(event); - }); - - this.log('✅ All iOS callbacks registered successfully'); - this.updateStatus('Callbacks Registered'); - } catch (error) { - this.log(`❌ iOS callback registration failed: ${error}`); - } - } - - private async testPerformance(): Promise { - try { - this.log('Testing iOS performance metrics...'); - const metrics = { - overallScore: 88, - databasePerformance: 92, - memoryEfficiency: 85, - batteryEfficiency: 90, - objectPoolEfficiency: 88, - totalDatabaseQueries: 120, - averageMemoryUsage: 22.3, - objectPoolHits: 38, - backgroundCpuUsage: 1.8, - totalNetworkRequests: 8, - recommendations: ['Enable background tasks', 'Optimize memory usage'] - }; - - this.log('📊 iOS Performance Metrics:', metrics); - this.updateStatus(`Performance: ${metrics.overallScore}/100`); - } catch (error) { - this.log(`❌ Performance check failed: ${error}`); - } - } - - /** - * Process Endorser.ch notification bundle using parallel API requests - */ - private async processEndorserNotificationBundle(data: Record): Promise { - try { - this.log('Processing Endorser.ch notification bundle on iOS...'); - - // Process each notification type - if (data.offersToPerson?.data?.length > 0) { - await this.handleOffersNotification(data.offersToPerson); - } - - if (data.starredChanges?.data?.length > 0) { - await this.handleProjectsNotification(data.starredChanges); - } - - this.log('✅ iOS notification bundle processed successfully'); - } catch (error) { - this.log(`❌ iOS bundle processing failed: ${error}`); - } - } - - /** - * Handle offers notification events from Endorser.ch API - */ - private async handleOffersNotification(event: Record): Promise { - this.log('Handling iOS offers notification:', event); - - if (event.data && event.data.length > 0) { - // Process OfferSummaryArrayMaybeMoreBody format - event.data.forEach((offer: Record) => { - this.log('Processing iOS offer:', { - jwtId: offer.jwtId, - handleId: offer.handleId, - offeredByDid: offer.offeredByDid, - recipientDid: offer.recipientDid, - objectDescription: offer.objectDescription - }); - }); - - // Check if there are more offers to fetch - if (event.hitLimit) { - const lastOffer = event.data[event.data.length - 1]; - this.log('More offers available, last JWT ID:', lastOffer.jwtId); - } - } - } - - /** - * Handle projects notification events from Endorser.ch API - */ - private async handleProjectsNotification(event: Record): Promise { - this.log('Handling iOS projects notification:', event); - - if (event.data && event.data.length > 0) { - // Process PlanSummaryAndPreviousClaimArrayMaybeMore format - event.data.forEach((planData: Record) => { - const { plan, wrappedClaimBefore } = planData; - this.log('Processing iOS project change:', { - jwtId: plan.jwtId, - handleId: plan.handleId, - name: plan.name, - issuerDid: plan.issuerDid, - hasPreviousClaim: !!wrappedClaimBefore - }); - }); - - // Check if there are more project changes to fetch - if (event.hitLimit) { - const lastPlan = event.data[event.data.length - 1]; - this.log('More project changes available, last JWT ID:', lastPlan.plan.jwtId); - } - } - } - - /** - * Handle people notification events - */ - private async handlePeopleNotification(event: Record): Promise { - this.log('Handling iOS people notification:', event); - // Implementation would process people data and update local state - } - - /** - * Handle items notification events - */ - private async handleItemsNotification(event: Record): Promise { - this.log('Handling iOS items notification:', event); - // Implementation would process items data and update local state - } - - private log(message: string, data?: Record): void { - const timestamp = new Date().toLocaleTimeString(); - const logEntry = document.createElement('div'); - logEntry.innerHTML = `[${timestamp}] ${message}`; - if (data) { - logEntry.innerHTML += `
${JSON.stringify(data, null, 2)}
`; - } - this.logElement.appendChild(logEntry); - this.logElement.scrollTop = this.logElement.scrollHeight; - } - - private clearLog(): void { - this.logElement.innerHTML = ''; - this.log('Log cleared'); - } - - private updateStatus(status: string): void { - this.statusElement.textContent = status; - } - - // Phase 4: TimeSafari component test methods - private async testSecurityManager(): Promise { - try { - this.log('🔐 Testing SecurityManager (iOS)...'); - - // const timeSafariUser = this.configLoader.getTimeSafariUser(); - - // Test JWT generation - const jwt = await this.securityManager.generateJWT({ - scope: 'test', - audience: 'test-api' - }); - - if (jwt) { - this.log('✅ JWT generation successful'); - this.log('JWT token:', jwt.substring(0, 50) + '...'); - - // Test JWT verification - const claims = await this.securityManager.verifyJWT(jwt); - if (claims) { - this.log('✅ JWT verification successful'); - this.log('Claims:', claims); - } else { - this.log('❌ JWT verification failed'); - } - } else { - this.log('❌ JWT generation failed'); - } - - // Test operation history - const history = this.securityManager.getOperationHistory(); - this.log(`Security operations performed: ${history.length}`); - - this.log('SecurityManager test completed'); - - } catch (error) { - this.log('SecurityManager test failed:', error); - this.errorDisplay.showError(error as Error); - } - } - - private async testEndorserAPIClient(): Promise { - try { - this.log('🌐 Testing EndorserAPIClient (iOS)...'); - - const timeSafariUser = this.configLoader.getTimeSafariUser(); - - // Test offers to person - this.log('Testing offers to person...'); - const offersResponse = await this.endorserAPIClient.fetchOffersToPerson( - timeSafariUser.activeDid, - timeSafariUser.lastKnownOfferId, - undefined - ); - - this.log(`✅ Offers fetched: ${offersResponse.data.length} offers`); - if (offersResponse.data.length > 0) { - this.log('Sample offer:', offersResponse.data[0]); - } - - // Test offers to projects - this.log('Testing offers to projects...'); - const projectsResponse = await this.endorserAPIClient.fetchOffersToProjectsOwnedByMe( - timeSafariUser.lastKnownOfferId - ); - - this.log(`✅ Project offers fetched: ${projectsResponse.data.length} offers`); - - // Test project updates - if (timeSafariUser.starredPlanIds && timeSafariUser.starredPlanIds.length > 0) { - this.log('Testing project updates...'); - const updatesResponse = await this.endorserAPIClient.fetchProjectsLastUpdated( - timeSafariUser.starredPlanIds, - timeSafariUser.lastKnownPlanId, - undefined - ); - - this.log(`✅ Project updates fetched: ${updatesResponse.data.length} updates`); - } - - this.log('EndorserAPIClient test completed'); - - } catch (error) { - this.log('EndorserAPIClient test failed:', error); - this.errorDisplay.showError(error as Error); - } - } - - private async testTimeSafariNotificationManager(): Promise { - try { - this.log('📱 Testing TimeSafariNotificationManager (iOS)...'); - - // Test notification generation - this.log('Generating TimeSafari notifications...'); - const notifications = await this.timeSafariNotificationManager.generateNotifications({ - forceFetch: false, - includeMetadata: true, - filterByPriority: true, - maxNotifications: 10, - cacheTtl: 300000 - }); - - this.log(`✅ Generated ${notifications.length} notifications`); - - // Display notification details - notifications.forEach((notification, index) => { - this.log(`Notification ${index + 1}:`, { - type: notification.type, - subtype: notification.subtype, - priority: notification.notificationPriority, - timestamp: new Date(notification.timestamp).toISOString(), - disabled: notification.disabled, - sound: notification.sound, - vibration: notification.vibration - }); - }); - - // Test statistics - const stats = this.timeSafariNotificationManager.getStatistics(); - this.log('Manager statistics:', stats); - - this.log('TimeSafariNotificationManager test completed'); - - } catch (error) { - this.log('TimeSafariNotificationManager test failed:', error); - this.errorDisplay.showError(error as Error); - } - } - - private async testPhase4Integration(): Promise { - try { - this.log('🚀 Testing complete Phase 4 integration (iOS)...'); - - const timeSafariUser = this.configLoader.getTimeSafariUser(); - - // Test complete workflow - this.log('Step 1: Security authentication...'); - const jwt = await this.securityManager.generateJWT({ - scope: 'notifications', - audience: 'endorser-api' - }); - - if (!jwt) { - throw new Error('JWT generation failed'); - } - - this.endorserAPIClient.setAuthToken(jwt); - this.log('✅ Authentication successful'); - - this.log('Step 2: Fetching TimeSafari data...'); - const bundle = await this.endorserAPIClient.fetchAllTimeSafariNotifications({ - activeDid: timeSafariUser.activeDid, - starredPlanIds: timeSafariUser.starredPlanIds || [], - lastKnownOfferId: timeSafariUser.lastKnownOfferId, - lastKnownPlanId: timeSafariUser.lastKnownPlanId, - fetchOffersToPerson: true, - fetchOffersToProjects: true, - fetchProjectUpdates: true, - notificationPreferences: { - offers: true, - projects: true, - people: false, - items: true - } - }); - - this.log(`✅ Data fetched successfully: ${bundle.success}`); - this.log('Bundle metadata:', bundle.metadata); - - this.log('Step 3: Generating notifications...'); - const notifications = await this.timeSafariNotificationManager.generateNotifications({ - forceFetch: true, - includeMetadata: true, - maxNotifications: 20 - }); - - this.log(`✅ Generated ${notifications.length} notifications`); - - // Summary - this.log('🎉 Phase 4 integration test completed successfully!'); - this.log('Summary:', { - securityInitialized: this.securityManager.isInitialized(), - apiClientReady: !!this.endorserAPIClient, - managerInitialized: this.timeSafariNotificationManager.isInitialized(), - notificationsGenerated: notifications.length, - bundleSuccess: bundle.success - }); - - } catch (error) { - this.log('Phase 4 integration test failed:', error); - this.errorDisplay.showError(error as Error); - } - } - - // Generic Polling Interface Test Methods - private async testGenericPolling(): Promise { - try { - this.log('🔄 Testing Generic Polling Interface (iOS)...'); - - // Create a starred projects polling request - const starredProjectsRequest: GenericPollingRequest = { - endpoint: '/api/v2/report/plansLastUpdatedBetween', - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'User-Agent': 'TimeSafari-DailyNotificationPlugin/1.0.0', - 'Authorization': `Bearer ${await this.getJwtToken()}` - }, - body: { - planIds: ['plan:test-1', 'plan:test-2'], - afterId: '1704067200_abc123_12345678', - limit: 100 - }, - responseSchema: { - validate: (data: unknown): data is StarredProjectsResponse => { - return data && - Array.isArray(data.data) && - typeof data.hitLimit === 'boolean' && - data.pagination && - typeof data.pagination.hasMore === 'boolean'; - }, - transformError: (error: unknown) => ({ - code: 'VALIDATION_ERROR', - message: error.message || 'Validation failed', - retryable: false - }) - }, - retryConfig: { - maxAttempts: 3, - backoffStrategy: 'exponential', - baseDelayMs: 1000 - }, - timeoutMs: 30000 - }; - - this.log('✅ Generic polling request created successfully'); - this.log('Request details:', { - endpoint: starredProjectsRequest.endpoint, - method: starredProjectsRequest.method, - planIds: starredProjectsRequest.body.planIds, - afterId: starredProjectsRequest.body.afterId - }); - - // Test backoff calculation - const backoffDelay = calculateBackoffDelay(1, starredProjectsRequest.retryConfig); - this.log(`✅ Backoff delay calculated: ${backoffDelay}ms`); - - // Test outbox pressure manager - const pressureManager = createDefaultOutboxPressureManager(); - const pressureStatus = await pressureManager.checkStoragePressure(50); - this.log('✅ Outbox pressure check:', pressureStatus); - - this.log('Generic Polling Interface test completed successfully'); - - } catch (error) { - this.log('Generic Polling Interface test failed:', error); - this.errorDisplay.showError(error as Error); - } - } - - private async testPollingSchedule(): Promise { - try { - this.log('📅 Testing Polling Schedule Configuration (iOS)...'); - - const timeSafariUser = this.configLoader.getTimeSafariUser(); - - // Create schedule configuration - const scheduleConfig: PollingScheduleConfig = { - request: { - endpoint: '/api/v2/report/plansLastUpdatedBetween', - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'User-Agent': 'TimeSafari-DailyNotificationPlugin/1.0.0', - 'Authorization': `Bearer ${await this.getJwtToken()}` - }, - body: { - planIds: timeSafariUser.starredPlanIds || [], - afterId: timeSafariUser.lastKnownPlanId, - limit: 100 - }, - responseSchema: { - validate: (data: unknown): data is StarredProjectsResponse => { - return data && Array.isArray(data.data); - }, - transformError: (error: unknown) => ({ - code: 'VALIDATION_ERROR', - message: error.message, - retryable: false - }) - }, - retryConfig: { - maxAttempts: 3, - backoffStrategy: 'exponential', - baseDelayMs: 1000 - }, - timeoutMs: 30000 - }, - schedule: { - cronExpression: '0 10,16 * * *', // 10 AM and 4 PM daily - timezone: 'UTC', - maxConcurrentPolls: 1 - }, - notificationConfig: { - enabled: true, - templates: { - singleUpdate: '{projectName} has been updated', - multipleUpdates: 'You have {count} new updates in your starred projects' - }, - groupingRules: { - maxGroupSize: 5, - timeWindowMinutes: 5 - } - }, - stateConfig: { - watermarkKey: 'lastAckedStarredPlanChangesJwtId', - storageAdapter: 'timesafari' - } - }; - - this.log('✅ Polling schedule configuration created successfully'); - this.log('Schedule details:', { - cronExpression: scheduleConfig.schedule.cronExpression, - timezone: scheduleConfig.schedule.timezone, - maxConcurrentPolls: scheduleConfig.schedule.maxConcurrentPolls, - watermarkKey: scheduleConfig.stateConfig.watermarkKey - }); - - // Mock scheduling the poll - this.log('📅 Scheduling polling (mock)...'); - const scheduleId = `ios-poll-${Date.now()}`; - this.log(`✅ Polling scheduled with ID: ${scheduleId}`); - - this.log('Polling Schedule test completed successfully'); - - } catch (error) { - this.log('Polling Schedule test failed:', error); - this.errorDisplay.showError(error as Error); - } - } - - private async testPollingResults(): Promise { - try { - this.log('📊 Testing Polling Results Handling (iOS)...'); - - // Mock polling result - const mockResult: PollingResult = { - success: true, - data: { - data: [ - { - planSummary: { - jwtId: '1704153600_mno345_87654321', - handleId: 'test-project-1', - name: 'Test Project 1', - issuerDid: 'did:example:test-issuer', - locLat: 40.7128, - locLon: -74.0060, - url: 'https://test-project-1.com', - version: '1.0.0' - }, - previousClaim: { - jwtId: '1704067200_abc123_12345678', - claimType: 'project_update', - claimData: { - status: 'in_progress', - progress: 0.75 - }, - metadata: { - createdAt: '2025-01-01T10:00:00Z', - updatedAt: '2025-01-01T12:00:00Z' - } - } - } - ], - hitLimit: false, - pagination: { - hasMore: false, - nextAfterId: null - } - }, - metadata: { - requestId: 'req-ios-test-123', - timestamp: new Date().toISOString(), - duration: 1250, - attempt: 1 - } - }; - - this.log('✅ Mock polling result created'); - this.log('Result details:', { - success: mockResult.success, - dataCount: mockResult.data?.data.length || 0, - hitLimit: mockResult.data?.hitLimit, - hasMore: mockResult.data?.pagination.hasMore, - duration: mockResult.metadata?.duration - }); - - // Test result processing - if (mockResult.success && mockResult.data) { - const changes = mockResult.data.data; - - if (changes.length > 0) { - this.log('📝 Processing polling results...'); - - // Generate notifications - this.log(`✅ Generated notifications for ${changes.length} changes`); - - // Update watermark with CAS - const latestJwtId = changes[changes.length - 1].planSummary.jwtId; - this.log(`✅ Updated watermark to: ${latestJwtId}`); - - // Acknowledge changes with server - const jwtIds = changes.map(c => c.planSummary.jwtId); - this.log(`✅ Acknowledged ${jwtIds.length} changes with server`); - } - } - - this.log('Polling Results test completed successfully'); - - } catch (error) { - this.log('Polling Results test failed:', error); - this.errorDisplay.showError(error as Error); - } - } - - private async getJwtToken(): Promise { - // Mock JWT token generation - return 'mock-jwt-token-ios-test'; - } - - // Static Daily Reminder Methods - private async scheduleDailyReminder(): Promise { - try { - this.log('Scheduling daily reminder...'); - - const reminderOptions = { - id: (document.getElementById('reminder-id') as HTMLInputElement)?.value || 'morning_checkin', - title: (document.getElementById('reminder-title') as HTMLInputElement)?.value || 'Good Morning!', - body: (document.getElementById('reminder-body') as HTMLInputElement)?.value || 'Time to check your TimeSafari community updates', - time: (document.getElementById('reminder-time') as HTMLInputElement)?.value || '09:00', - sound: (document.getElementById('reminder-sound') as HTMLInputElement)?.checked ?? true, - vibration: (document.getElementById('reminder-vibration') as HTMLInputElement)?.checked ?? true, - priority: (document.getElementById('reminder-priority') as HTMLSelectElement)?.value || 'normal', - repeatDaily: (document.getElementById('reminder-repeat') as HTMLInputElement)?.checked ?? true - }; - - this.log('Reminder options:', reminderOptions); - - await this.plugin.scheduleDailyReminder(reminderOptions); - this.log('✅ Daily reminder scheduled successfully'); - this.errorDisplay.showSuccess('Daily reminder scheduled successfully!'); - - } catch (error) { - this.log('❌ Failed to schedule daily reminder:', error); - this.errorDisplay.showError(error as Error); - } - } - - private async cancelDailyReminder(): Promise { - try { - this.log('Cancelling daily reminder...'); - - const reminderId = (document.getElementById('reminder-id') as HTMLInputElement)?.value || 'morning_checkin'; - - await this.plugin.cancelDailyReminder(reminderId); - this.log('✅ Daily reminder cancelled successfully'); - this.errorDisplay.showSuccess('Daily reminder cancelled successfully!'); - - } catch (error) { - this.log('❌ Failed to cancel daily reminder:', error); - this.errorDisplay.showError(error as Error); - } - } - - private async getScheduledReminders(): Promise { - try { - this.log('Getting scheduled reminders...'); - - const result = await this.plugin.getScheduledReminders(); - this.log('✅ Scheduled reminders retrieved:', result); - - if (result.reminders && result.reminders.length > 0) { - this.errorDisplay.showSuccess(`Found ${result.reminders.length} scheduled reminders`); - // eslint-disable-next-line no-console - console.table(result.reminders); - } else { - this.errorDisplay.showInfo('No scheduled reminders found'); - } - - } catch (error) { - this.log('❌ Failed to get scheduled reminders:', error); - this.errorDisplay.showError(error as Error); - } - } - - private async updateDailyReminder(): Promise { - try { - this.log('Updating daily reminder...'); - - const reminderId = (document.getElementById('reminder-id') as HTMLInputElement)?.value || 'morning_checkin'; - - const updateOptions = { - title: (document.getElementById('reminder-title') as HTMLInputElement)?.value, - body: (document.getElementById('reminder-body') as HTMLInputElement)?.value, - time: (document.getElementById('reminder-time') as HTMLInputElement)?.value, - sound: (document.getElementById('reminder-sound') as HTMLInputElement)?.checked, - vibration: (document.getElementById('reminder-vibration') as HTMLInputElement)?.checked, - priority: (document.getElementById('reminder-priority') as HTMLSelectElement)?.value, - repeatDaily: (document.getElementById('reminder-repeat') as HTMLInputElement)?.checked - }; - - this.log('Update options:', updateOptions); - - await this.plugin.updateDailyReminder(reminderId, updateOptions); - this.log('✅ Daily reminder updated successfully'); - this.errorDisplay.showSuccess('Daily reminder updated successfully!'); - - } catch (error) { - this.log('❌ Failed to update daily reminder:', error); - this.errorDisplay.showError(error as Error); - } - } -} - -// Initialize app when DOM is ready -document.addEventListener('DOMContentLoaded', () => { - new TimeSafariIOSTestApp(); -}); diff --git a/test-apps/ios-test/tsconfig.json b/test-apps/ios-test/tsconfig.json deleted file mode 100644 index aa6eba6..0000000 --- a/test-apps/ios-test/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ES2020", - "moduleResolution": "node", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "outDir": "./dist", - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] -} diff --git a/test-apps/ios-test/webpack.config.js b/test-apps/ios-test/webpack.config.js deleted file mode 100644 index 4f64c73..0000000 --- a/test-apps/ios-test/webpack.config.js +++ /dev/null @@ -1,33 +0,0 @@ -const path = require('path'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); - -module.exports = { - entry: './src/index.ts', - module: { - rules: [ - { - test: /\.ts$/, - use: 'ts-loader', - exclude: /node_modules/, - }, - ], - }, - resolve: { - extensions: ['.ts', '.js'], - }, - output: { - filename: 'bundle.js', - path: path.resolve(__dirname, 'dist'), - clean: true, - }, - plugins: [ - new HtmlWebpackPlugin({ - template: './src/index.html', - }), - ], - devServer: { - static: './dist', - port: 3001, - hot: true, - }, -}; diff --git a/test-apps/launch-emulator-angle.sh b/test-apps/launch-emulator-angle.sh deleted file mode 100755 index 706d4ca..0000000 --- a/test-apps/launch-emulator-angle.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash - -# Android Emulator Launch Script - ANGLE Mode -# Uses ANGLE (Almost Native Graphics Layer Engine) for better NVIDIA compatibility -# Alternative to host GPU mode when experiencing binding issues -# Author: Matthew Raymer - -echo "🚀 Launching Android Emulator - ANGLE Mode..." - -# Check if emulator command exists -if ! command -v emulator &> /dev/null; then - echo "❌ Error: Android emulator not found!" - echo "Please install Android Studio and add emulator to PATH" - exit 1 -fi - -# Check if AVD exists -if ! emulator -list-avds | grep -q "TimeSafari_Emulator"; then - echo "❌ Error: TimeSafari_Emulator AVD not found!" - echo "Available AVDs:" - emulator -list-avds - exit 1 -fi - -echo "✅ Environment checks passed" -echo "🎮 Starting emulator with ANGLE rendering..." - -# Launch emulator with ANGLE and performance tuning -QT_QPA_PLATFORM=xcb \ -__NV_PRIME_RENDER_OFFLOAD=1 \ -__GLX_VENDOR_LIBRARY_NAME=nvidia \ -DRI_PRIME=1 \ -emulator -avd TimeSafari_Emulator \ - -gpu angle_indirect \ - -accel on \ - -cores 6 \ - -memory 4096 \ - -no-boot-anim \ - -no-snapshot-load \ - -feature -Bluetooth - -echo "🎯 Emulator launched with ANGLE rendering!" -echo "" -echo "📋 Configuration:" -echo " - ANGLE indirect rendering" -echo " - NVIDIA GPU offloading" -echo " - 6 CPU cores allocated" -echo " - 4GB RAM allocated" -echo " - Hardware acceleration enabled" -echo " - Fast startup (no boot animation)" -echo " - Clean state (no snapshot loading)" -echo " - Bluetooth disabled (prevents hangs)" -echo "" -echo "🔍 Benefits:" -echo " - Better NVIDIA compatibility on Linux" -echo " - Avoids mixed Vulkan+OpenGL binding issues" -echo " - More stable rendering pipeline" -echo " - Good fallback when host GPU mode fails" diff --git a/test-apps/launch-emulator-gpu.sh b/test-apps/launch-emulator-gpu.sh deleted file mode 100755 index 9649461..0000000 --- a/test-apps/launch-emulator-gpu.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash - -# High-Performance Android Emulator Launch Script -# Optimized for Linux systems with NVIDIA graphics cards -# Author: Matthew Raymer - -echo "🚀 Launching Android Emulator with GPU Acceleration..." - -# Check if emulator command exists -if ! command -v emulator &> /dev/null; then - echo "❌ Error: Android emulator not found!" - echo "Please install Android Studio and add emulator to PATH" - echo "export PATH=\$PATH:\$ANDROID_HOME/emulator" - exit 1 -fi - -# Check if AVD exists -if ! emulator -list-avds | grep -q "TimeSafari_Emulator"; then - echo "❌ Error: TimeSafari_Emulator AVD not found!" - echo "Available AVDs:" - emulator -list-avds - echo "" - echo "Please create TimeSafari_Emulator AVD or modify this script" - exit 1 -fi - -# Check if NVIDIA drivers are available -if ! ls /usr/share/vulkan/icd.d/nvidia_icd.json &> /dev/null; then - echo "⚠️ Warning: NVIDIA Vulkan ICD not found" - echo "GPU acceleration may not work optimally" - echo "Consider installing NVIDIA drivers with Vulkan support" -fi - -echo "✅ Environment checks passed" -echo "🎮 Starting emulator with GPU acceleration..." - -# Launch emulator with GPU acceleration, network fixes, and performance tuning -QT_QPA_PLATFORM=xcb \ -__NV_PRIME_RENDER_OFFLOAD=1 \ -__GLX_VENDOR_LIBRARY_NAME=nvidia \ -__VK_LAYER_NV_optimus=NVIDIA_only \ -VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json \ -DRI_PRIME=1 \ -emulator -avd TimeSafari_Emulator \ - -gpu host \ - -feature Vulkan \ - -accel on \ - -cores 6 \ - -memory 4096 \ - -no-boot-anim \ - -no-snapshot-load \ - -dns-server 8.8.8.8,1.1.1.1 \ - -feature -Bluetooth - -echo "🎯 Emulator launched with GPU acceleration!" -echo "" -echo "📋 Performance Features Enabled:" -echo " - Hardware GPU acceleration" -echo " - Vulkan graphics API support" -echo " - NVIDIA GPU offloading" -echo " - 6 CPU cores allocated" -echo " - 4GB RAM allocated" -echo " - Fast startup (no boot animation)" -echo " - Clean state (no snapshot loading)" -echo " - Fixed DNS servers (8.8.8.8, 1.1.1.1)" -echo " - Bluetooth disabled (prevents hangs)" -echo "" -echo "🔧 Troubleshooting:" -echo " - If emulator is slow, check NVIDIA drivers" -echo " - For Intel/AMD graphics, remove NVIDIA-specific variables" -echo " - Monitor GPU usage with: nvidia-smi" -echo "" -echo "🔍 GPU Binding Issues:" -echo " If OpenGL still binds to Intel iGPU instead of NVIDIA:" -echo " 1. Check emulator banner for 'OpenGL Vendor=Google (NVIDIA)'" -echo " 2. Try alternative GPU modes:" -echo " - Pure OpenGL: Remove -feature Vulkan flag" -echo " - ANGLE path: Use -gpu angle_indirect" -echo " - Mesa fallback: Use -gpu mesa" -echo " 3. Verify dGPU usage: nvidia-smi dmon -s u" -echo "" -echo "📋 Performance Verification:" -echo " - Monitor GPU utilization: watch -n1 'nvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv,noheader | grep qemu'" -echo " - Check ADB connection: adb kill-server && adb start-server" -echo " - Clean snapshots: Delete ~/.android/avd/TimeSafari_Emulator.avd/snapshots/" diff --git a/test-apps/launch-emulator-help.sh b/test-apps/launch-emulator-help.sh deleted file mode 100755 index b5aa6e6..0000000 --- a/test-apps/launch-emulator-help.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/bash - -# Android Emulator Launch Options Helper -# Lists all available launch scripts and their purposes -# Author: Matthew Raymer - -echo "🚀 Android Emulator Launch Options" -echo "==================================" -echo "" - -echo "📋 Available Launch Scripts:" -echo "" - -echo "1. 🎮 GPU Accelerated (Recommended)" -echo " ./launch-emulator-gpu.sh" -echo " - Full NVIDIA GPU acceleration with Vulkan" -echo " - Best performance for development" -echo " - Use when GPU binding works correctly" -echo "" - -echo "2. 🔧 Pure OpenGL Mode" -echo " ./launch-emulator-opengl.sh" -echo " - Pure OpenGL rendering (no Vulkan)" -echo " - Use when Vulkan+OpenGL mixed mode binds to Intel iGPU" -echo " - Good fallback for GPU binding issues" -echo "" - -echo "3. ⚡ ANGLE Mode" -echo " ./launch-emulator-angle.sh" -echo " - ANGLE (Almost Native Graphics Layer Engine)" -echo " - Better NVIDIA compatibility on Linux" -echo " - More stable rendering pipeline" -echo "" - -echo "4. 🛡️ Mesa Fallback" -echo " ./launch-emulator-mesa.sh" -echo " - Software rendering as last resort" -echo " - Use for stability testing" -echo " - More CPU intensive but very stable" -echo "" - -echo "5. 🌐 Network Fix Mode" -echo " ./launch-emulator-network-fix.sh" -echo " - Fixes DNS/network connectivity issues" -echo " - Resolves Play Services ANRs and timeouts" -echo " - Clean state with explicit DNS servers" -echo "" - -echo "6. 🔍 Network Verification" -echo " ./verify-emulator-network.sh" -echo " - Diagnoses network connectivity problems" -echo " - Tests DNS resolution and internet access" -echo " - Identifies root cause of ANRs" -echo "" - -echo "7. ⚡ Maximum Performance Mode" -echo " ./launch-emulator-max-performance.sh" -echo " - All performance optimizations enabled" -echo " - 8 CPU cores, 6GB RAM allocated" -echo " - Disabled unnecessary features" -echo " - Use only on high-end systems (16GB+ RAM)" -echo "" - -echo "🔍 Troubleshooting:" -echo "" - -echo "If experiencing ANRs and Play Services failures:" -echo "1. Run network verification: ./verify-emulator-network.sh" -echo "2. Try network fix mode: ./launch-emulator-network-fix.sh" -echo "3. Clear Play Services cache if needed" -echo "4. Check VPN/firewall settings on host" -echo "" - -echo "If emulator feels sluggish or GPU utilization is low:" -echo "1. Check emulator banner for 'OpenGL Vendor=Google (NVIDIA)'" -echo "2. Monitor GPU usage: nvidia-smi dmon -s u" -echo "3. Try different GPU modes in order: GPU → OpenGL → ANGLE → Mesa" -echo "4. See EMULATOR_TROUBLESHOOTING.md for detailed solutions" -echo "" - -echo "📊 Performance Expectations:" -echo "" -echo "Hardware Acceleration (NVIDIA):" -echo " - GPU Utilization: 20-60%" -echo " - UI Responsiveness: Smooth, 60fps" -echo " - Startup Time: 30-60 seconds" -echo "" -echo "Software Rendering (Mesa):" -echo " - CPU Usage: 50-80%" -echo " - UI Responsiveness: Slower, 30fps" -echo " - Startup Time: 60-120 seconds" -echo "" - -echo "📚 Documentation:" -echo " - SETUP_GUIDE.md - Complete setup instructions" -echo " - EMULATOR_TROUBLESHOOTING.md - GPU binding solutions" -echo " - README.md - Project overview and quick start" -echo "" - -echo "🎯 Quick Start:" -echo " 1. If ANRs/Play Services issues: ./verify-emulator-network.sh" -echo " 2. If network issues: ./launch-emulator-network-fix.sh" -echo " 3. For GPU issues: ./launch-emulator-gpu.sh" -echo " 4. If GPU binding issues: ./launch-emulator-opengl.sh" -echo " 5. For maximum performance: ./launch-emulator-max-performance.sh" -echo " 6. Last resort: ./launch-emulator-mesa.sh" diff --git a/test-apps/launch-emulator-max-performance.sh b/test-apps/launch-emulator-max-performance.sh deleted file mode 100755 index 8e184e9..0000000 --- a/test-apps/launch-emulator-max-performance.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/bash - -# Android Emulator Launch Script - High Performance Mode -# Maximum performance with all optimizations enabled -# Author: Matthew Raymer - -echo "🚀 Launching Android Emulator - High Performance Mode..." - -# Check if emulator command exists -if ! command -v emulator &> /dev/null; then - echo "❌ Error: Android emulator not found!" - echo "Please install Android Studio and add emulator to PATH" - exit 1 -fi - -# Check if AVD exists -if ! emulator -list-avds | grep -q "TimeSafari_Emulator"; then - echo "❌ Error: TimeSafari_Emulator AVD not found!" - echo "Available AVDs:" - emulator -list-avds - exit 1 -fi - -# Check if NVIDIA drivers are available -if ! ls /usr/share/vulkan/icd.d/nvidia_icd.json &> /dev/null; then - echo "⚠️ Warning: NVIDIA Vulkan ICD not found" - echo "GPU acceleration may not work optimally" -fi - -echo "✅ Environment checks passed" -echo "🎮 Starting emulator with maximum performance..." - -# Launch emulator with all performance optimizations -QT_QPA_PLATFORM=xcb \ -__NV_PRIME_RENDER_OFFLOAD=1 \ -__GLX_VENDOR_LIBRARY_NAME=nvidia \ -__VK_LAYER_NV_optimus=NVIDIA_only \ -VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json \ -DRI_PRIME=1 \ -emulator -avd TimeSafari_Emulator \ - -gpu host \ - -feature Vulkan \ - -accel on \ - -cores 8 \ - -memory 6144 \ - -no-boot-anim \ - -no-snapshot-load \ - -dns-server 8.8.8.8,1.1.1.1 \ - -feature -Bluetooth \ - -camera-back none \ - -camera-front none \ - -no-audio - -echo "🎯 Emulator launched with maximum performance!" -echo "" -echo "📋 High Performance Features:" -echo " - Hardware GPU acceleration with Vulkan" -echo " - NVIDIA GPU offloading" -echo " - 8 CPU cores allocated (maximum)" -echo " - 6GB RAM allocated (high memory)" -echo " - Fast startup (no boot animation)" -echo " - Clean state (no snapshot loading)" -echo " - Fixed DNS servers (8.8.8.8, 1.1.1.1)" -echo " - Disabled unnecessary features:" -echo " - Bluetooth disabled" -echo " - Cameras disabled" -echo " - Audio disabled" -echo "" -echo "🔍 Performance Monitoring:" -echo " - GPU usage: nvidia-smi dmon -s u" -echo " - CPU usage: htop" -echo " - Memory usage: free -h" -echo "" -echo "⚠️ Note: This configuration uses maximum resources" -echo " - Ensure your system has sufficient RAM (16GB+ recommended)" -echo " - Monitor system performance during use" -echo " - Adjust -cores and -memory if system becomes unresponsive" diff --git a/test-apps/launch-emulator-mesa.sh b/test-apps/launch-emulator-mesa.sh deleted file mode 100755 index 1318685..0000000 --- a/test-apps/launch-emulator-mesa.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash - -# Android Emulator Launch Script - Mesa Fallback Mode -# Uses Mesa software rendering as last resort for stability -# Use when hardware acceleration causes issues -# Author: Matthew Raymer - -echo "🚀 Launching Android Emulator - Mesa Fallback Mode..." - -# Check if emulator command exists -if ! command -v emulator &> /dev/null; then - echo "❌ Error: Android emulator not found!" - echo "Please install Android Studio and add emulator to PATH" - exit 1 -fi - -# Check if AVD exists -if ! emulator -list-avds | grep -q "TimeSafari_Emulator"; then - echo "❌ Error: TimeSafari_Emulator AVD not found!" - echo "Available AVDs:" - emulator -list-avds - exit 1 -fi - -echo "✅ Environment checks passed" -echo "🎮 Starting emulator with Mesa software rendering..." - -# Launch emulator with Mesa software rendering -emulator -avd TimeSafari_Emulator \ - -gpu mesa \ - -no-boot-anim \ - -no-snapshot-load \ - -feature -Bluetooth - -echo "🎯 Emulator launched with Mesa software rendering!" -echo "" -echo "📋 Configuration:" -echo " - Mesa software rendering" -echo " - No hardware acceleration" -echo " - Fast startup (no boot animation)" -echo " - Clean state (no snapshot loading)" -echo " - Bluetooth disabled (prevents hangs)" -echo "" -echo "⚠️ Performance Notes:" -echo " - Slower than hardware acceleration" -echo " - More CPU intensive" -echo " - Use only for stability testing" -echo " - Good for debugging GPU issues" -echo "" -echo "🔄 To return to hardware acceleration:" -echo " - Use ./launch-emulator-gpu.sh for NVIDIA GPU" -echo " - Use ./launch-emulator-opengl.sh for Pure OpenGL" -echo " - Use ./launch-emulator-angle.sh for ANGLE mode" diff --git a/test-apps/launch-emulator-network-fix.sh b/test-apps/launch-emulator-network-fix.sh deleted file mode 100755 index cb2c3d5..0000000 --- a/test-apps/launch-emulator-network-fix.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -# Android Emulator Launch Script - Network Fix Mode -# Addresses DNS/network connectivity issues that cause ANRs and Play Services failures -# Author: Matthew Raymer - -echo "🚀 Launching Android Emulator - Network Fix Mode..." - -# Check if emulator command exists -if ! command -v emulator &> /dev/null; then - echo "❌ Error: Android emulator not found!" - echo "Please install Android Studio and add emulator to PATH" - exit 1 -fi - -# Check if AVD exists -if ! emulator -list-avds | grep -q "TimeSafari_Emulator"; then - echo "❌ Error: TimeSafari_Emulator AVD not found!" - echo "Available AVDs:" - emulator -list-avds - exit 1 -fi - -echo "✅ Environment checks passed" -echo "🌐 Starting emulator with network fixes..." - -# Launch emulator with network fixes, performance tuning, and clean state -QT_QPA_PLATFORM=xcb \ -emulator -avd TimeSafari_Emulator \ - -gpu host \ - -accel on \ - -cores 6 \ - -memory 4096 \ - -no-boot-anim \ - -no-snapshot-load \ - -wipe-data \ - -dns-server 8.8.8.8,1.1.1.1 \ - -feature -Bluetooth - -echo "🎯 Emulator launched with network fixes!" -echo "" -echo "📋 Network Fixes Applied:" -echo " - Explicit DNS servers (8.8.8.8, 1.1.1.1)" -echo " - Clean state (wipe-data)" -echo " - No snapshot loading" -echo " - 6 CPU cores allocated" -echo " - 4GB RAM allocated" -echo " - Fast startup (no boot animation)" -echo " - Bluetooth disabled (prevents hangs)" -echo "" -echo "🔍 Network Verification Commands:" -echo " # Check airplane mode" -echo " adb -e shell settings get global airplane_mode_on" -echo "" -echo " # Check network interfaces" -echo " adb -e shell ip addr; adb -e shell ip route" -echo "" -echo " # Test DNS resolution" -echo " adb -e shell ping -c1 8.8.8.8" -echo " adb -e shell ping -c1 connectivitycheck.gstatic.com" -echo "" -echo "⚠️ Note: This will wipe emulator data for clean network state" diff --git a/test-apps/launch-emulator-opengl.sh b/test-apps/launch-emulator-opengl.sh deleted file mode 100755 index fd07252..0000000 --- a/test-apps/launch-emulator-opengl.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash - -# Android Emulator Launch Script - Pure OpenGL Mode -# Forces OpenGL rendering on NVIDIA GPU (no Vulkan) -# Use when Vulkan+OpenGL mixed mode binds to Intel iGPU -# Author: Matthew Raymer - -echo "🚀 Launching Android Emulator - Pure OpenGL Mode..." - -# Check if emulator command exists -if ! command -v emulator &> /dev/null; then - echo "❌ Error: Android emulator not found!" - echo "Please install Android Studio and add emulator to PATH" - exit 1 -fi - -# Check if AVD exists -if ! emulator -list-avds | grep -q "TimeSafari_Emulator"; then - echo "❌ Error: TimeSafari_Emulator AVD not found!" - echo "Available AVDs:" - emulator -list-avds - exit 1 -fi - -echo "✅ Environment checks passed" -echo "🎮 Starting emulator with Pure OpenGL rendering..." - -# Launch emulator with Pure OpenGL and performance tuning -QT_QPA_PLATFORM=xcb \ -__NV_PRIME_RENDER_OFFLOAD=1 \ -__GLX_VENDOR_LIBRARY_NAME=nvidia \ -DRI_PRIME=1 \ -emulator -avd TimeSafari_Emulator \ - -gpu host \ - -accel on \ - -cores 6 \ - -memory 4096 \ - -no-boot-anim \ - -no-snapshot-load \ - -feature -Bluetooth - -echo "🎯 Emulator launched with Pure OpenGL rendering!" -echo "" -echo "📋 Configuration:" -echo " - Pure OpenGL rendering (no Vulkan)" -echo " - NVIDIA GPU offloading" -echo " - 6 CPU cores allocated" -echo " - 4GB RAM allocated" -echo " - Hardware acceleration enabled" -echo " - Fast startup (no boot animation)" -echo " - Clean state (no snapshot loading)" -echo " - Bluetooth disabled (prevents hangs)" -echo "" -echo "🔍 Verification:" -echo " - Check banner for 'OpenGL Vendor=Google (NVIDIA)'" -echo " - Monitor GPU: nvidia-smi dmon -s u" -echo " - Should avoid Intel iGPU binding issues" diff --git a/test-apps/setup-android.sh b/test-apps/setup-android.sh deleted file mode 100755 index 2d14829..0000000 --- a/test-apps/setup-android.sh +++ /dev/null @@ -1,123 +0,0 @@ -#!/bin/bash - -# Android Test App Setup Script -echo "🚀 Setting up Android Test App..." - -# Check if we're in the right directory -if [ ! -d "android-test" ]; then - echo "❌ Error: android-test directory not found!" - echo "Please run this script from the test-apps directory" - exit 1 -fi - -cd android-test - -# Check Node.js version -echo "🔍 Checking Node.js version..." -node_version=$(node --version 2>/dev/null) -if [ $? -ne 0 ]; then - echo "❌ Error: Node.js not found!" - echo "Please install Node.js 18+ from https://nodejs.org/" - exit 1 -fi -echo "✅ Node.js version: $node_version" - -# Install dependencies -echo "📦 Installing dependencies..." -npm install -if [ $? -ne 0 ]; then - echo "❌ Error: Failed to install dependencies!" - exit 1 -fi - -# Install Capacitor CLI globally if not present -if ! command -v cap &> /dev/null; then - echo "🔧 Installing Capacitor CLI globally..." - npm install -g @capacitor/cli - if [ $? -ne 0 ]; then - echo "❌ Error: Failed to install Capacitor CLI!" - exit 1 - fi -else - echo "✅ Capacitor CLI already installed" -fi - -# Initialize Capacitor (only if not already initialized) -if [ ! -f "capacitor.config.ts" ]; then - echo "⚡ Initializing Capacitor..." - npx cap init "Daily Notification Android Test" "com.timesafari.dailynotification.androidtest" - if [ $? -ne 0 ]; then - echo "❌ Error: Failed to initialize Capacitor!" - exit 1 - fi -else - echo "✅ Capacitor already initialized" -fi - -# Add Android platform (only if not already added) -if [ ! -d "android" ]; then - echo "📱 Adding Android platform..." - npx cap add android - if [ $? -ne 0 ]; then - echo "❌ Error: Failed to add Android platform!" - echo "Make sure Android Studio and Android SDK are installed" - exit 1 - fi -else - echo "✅ Android platform already added" -fi - -# Build web assets -echo "🔨 Building web assets..." -npm run build -if [ $? -ne 0 ]; then - echo "❌ Error: Failed to build web assets!" - exit 1 -fi - -# Sync to native -echo "🔄 Syncing to native..." -npx cap sync android -if [ $? -ne 0 ]; then - echo "❌ Error: Failed to sync to native!" - echo "🔧 Attempting to fix Gradle sync issues..." - - # Fix common Gradle sync issues - cd android - ./gradlew clean - ./gradlew --stop - - # Clear Gradle cache if needed - if [ -d ~/.gradle/wrapper/dists/gradle-9.0-milestone-1* ]; then - echo "🧹 Clearing incompatible Gradle cache..." - rm -rf ~/.gradle/wrapper/dists/gradle-9.0-milestone-1* - fi - - cd .. - - # Try sync again - echo "🔄 Retrying sync..." - npx cap sync android - if [ $? -ne 0 ]; then - echo "❌ Error: Sync still failing after cleanup" - echo "📋 See GRADLE_TROUBLESHOOTING.md for manual fixes" - exit 1 - fi -fi - -echo "" -echo "✅ Android test app setup complete!" -echo "" -echo "📋 Prerequisites check:" -echo "- Android Studio installed: $(command -v studio &> /dev/null && echo '✅' || echo '❌')" -echo "- Android SDK configured: $(echo $ANDROID_HOME | grep -q . && echo '✅' || echo '❌')" -echo "" -echo "🚀 Next steps:" -echo "1. Open Android Studio: npx cap open android" -echo "2. Run on device/emulator: npx cap run android" -echo "3. Or test web version: npm run dev" -echo "" -echo "🔧 Troubleshooting:" -echo "- If Android Studio doesn't open, install it from https://developer.android.com/studio" -echo "- If sync fails, check Android SDK installation" -echo "- For web testing, run: npm run dev" diff --git a/test-apps/setup-electron.sh b/test-apps/setup-electron.sh deleted file mode 100755 index 4b7a9f7..0000000 --- a/test-apps/setup-electron.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash - -# Electron Test App Setup Script -echo "🚀 Setting up Electron Test App..." - -# Check if we're in the right directory -if [ ! -d "electron-test" ]; then - echo "❌ Error: electron-test directory not found!" - echo "Please run this script from the test-apps directory" - exit 1 -fi - -cd electron-test - -# Check Node.js version -echo "🔍 Checking Node.js version..." -node_version=$(node --version 2>/dev/null) -if [ $? -ne 0 ]; then - echo "❌ Error: Node.js not found!" - echo "Please install Node.js 18+ from https://nodejs.org/" - exit 1 -fi -echo "✅ Node.js version: $node_version" - -# Install dependencies -echo "📦 Installing dependencies..." -npm install -if [ $? -ne 0 ]; then - echo "❌ Error: Failed to install dependencies!" - exit 1 -fi - -# Build web assets -echo "🔨 Building web assets..." -npm run build-web -if [ $? -ne 0 ]; then - echo "❌ Error: Failed to build web assets!" - exit 1 -fi - -echo "" -echo "✅ Electron test app setup complete!" -echo "" -echo "📋 Prerequisites check:" -echo "- Node.js installed: ✅" -echo "- Electron dependencies: ✅" -echo "" -echo "🚀 Next steps:" -echo "1. Run Electron app: npm start" -echo "2. Run in dev mode: npm run dev" -echo "3. Build and run: npm run electron" -echo "" -echo "🔧 Troubleshooting:" -echo "- If Electron doesn't start, check Node.js version (18+)" -echo "- For development, use: npm run dev" -echo "- Check console logs for detailed error information" diff --git a/test-apps/setup-ios.sh b/test-apps/setup-ios.sh deleted file mode 100755 index f603782..0000000 --- a/test-apps/setup-ios.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/bash - -# iOS Test App Setup Script -echo "🚀 Setting up iOS Test App..." - -# Check if we're in the right directory -if [ ! -d "ios-test" ]; then - echo "❌ Error: ios-test directory not found!" - echo "Please run this script from the test-apps directory" - exit 1 -fi - -cd ios-test - -# Check Node.js version -echo "🔍 Checking Node.js version..." -node_version=$(node --version 2>/dev/null) -if [ $? -ne 0 ]; then - echo "❌ Error: Node.js not found!" - echo "Please install Node.js 18+ from https://nodejs.org/" - exit 1 -fi -echo "✅ Node.js version: $node_version" - -# Install dependencies -echo "📦 Installing dependencies..." -npm install -if [ $? -ne 0 ]; then - echo "❌ Error: Failed to install dependencies!" - exit 1 -fi - -# Install Capacitor CLI globally if not present -if ! command -v cap &> /dev/null; then - echo "🔧 Installing Capacitor CLI globally..." - npm install -g @capacitor/cli - if [ $? -ne 0 ]; then - echo "❌ Error: Failed to install Capacitor CLI!" - exit 1 - fi -else - echo "✅ Capacitor CLI already installed" -fi - -# Initialize Capacitor (only if not already initialized) -if [ ! -f "capacitor.config.ts" ]; then - echo "⚡ Initializing Capacitor..." - npx cap init "Daily Notification iOS Test" "com.timesafari.dailynotification.iostest" - if [ $? -ne 0 ]; then - echo "❌ Error: Failed to initialize Capacitor!" - exit 1 - fi -else - echo "✅ Capacitor already initialized" -fi - -# Add iOS platform (only if not already added) -if [ ! -d "ios" ]; then - echo "🍎 Adding iOS platform..." - npx cap add ios - if [ $? -ne 0 ]; then - echo "❌ Error: Failed to add iOS platform!" - echo "Make sure Xcode and iOS SDK are installed" - exit 1 - fi -else - echo "✅ iOS platform already added" -fi - -# Build web assets -echo "🔨 Building web assets..." -npm run build -if [ $? -ne 0 ]; then - echo "❌ Error: Failed to build web assets!" - exit 1 -fi - -# Sync to native -echo "🔄 Syncing to native..." -npx cap sync ios -if [ $? -ne 0 ]; then - echo "❌ Error: Failed to sync to native!" - exit 1 -fi - -echo "" -echo "✅ iOS test app setup complete!" -echo "" -echo "📋 Prerequisites check:" -echo "- Xcode installed: $(command -v xcodebuild &> /dev/null && echo '✅' || echo '❌')" -echo "- iOS Simulator available: $(xcrun simctl list devices &> /dev/null && echo '✅' || echo '❌')" -echo "" -echo "🚀 Next steps:" -echo "1. Open Xcode: npx cap open ios" -echo "2. Run on device/simulator: npx cap run ios" -echo "3. Or test web version: npm run dev" -echo "" -echo "🔧 Troubleshooting:" -echo "- If Xcode doesn't open, install it from the Mac App Store" -echo "- If sync fails, check Xcode command line tools: xcode-select --install" -echo "- For web testing, run: npm run dev" diff --git a/test-apps/shared/config-loader.ts b/test-apps/shared/config-loader.ts deleted file mode 100644 index b3ba1bf..0000000 --- a/test-apps/shared/config-loader.ts +++ /dev/null @@ -1,552 +0,0 @@ -/** - * Configuration loader for TimeSafari test apps - * - * Loads configuration from JSON files and provides typed access - * to TimeSafari-specific settings, Endorser.ch API endpoints, - * and test data. - * - * @author Matthew Raymer - * @version 1.0.0 - */ - -export interface TimeSafariConfig { - timesafari: { - appId: string; - appName: string; - version: string; - description: string; - }; - endorser: { - baseUrl: string; - apiVersion: string; - endpoints: { - offers: string; - offersToPlans: string; - plansLastUpdated: string; - notificationsBundle: string; - }; - authentication: { - type: string; - token: string; - headers: Record; - }; - pagination: { - defaultLimit: number; - maxLimit: number; - hitLimitThreshold: number; - }; - }; - notificationTypes: { - offers: { - enabled: boolean; - types: string[]; - }; - projects: { - enabled: boolean; - types: string[]; - }; - people: { - enabled: boolean; - types: string[]; - }; - items: { - enabled: boolean; - types: string[]; - }; - }; - scheduling: { - contentFetch: { - schedule: string; - time: string; - description: string; - }; - userNotification: { - schedule: string; - time: string; - description: string; - }; - }; - testData: { - userDid: string; - starredPlanIds: string[]; - lastKnownOfferId: string; - lastKnownPlanId: string; - mockOffers: Record[]; - mockProjects: Record[]; - }; - callbacks: { - offers: { - enabled: boolean; - localHandler: string; - }; - projects: { - enabled: boolean; - localHandler: string; - }; - people: { - enabled: boolean; - localHandler: string; - }; - items: { - enabled: boolean; - localHandler: string; - }; - communityAnalytics: { - enabled: boolean; - endpoint: string; - headers: Record; - }; - }; - observability: { - enableLogging: boolean; - logLevel: string; - enableMetrics: boolean; - enableHealthChecks: boolean; - }; -} - -/** - * Configuration loader class - */ -export class ConfigLoader { - private static instance: ConfigLoader; - private config: TimeSafariConfig | null = null; - - private constructor() { - // Private constructor for singleton pattern - } - - /** - * Get singleton instance - */ - public static getInstance(): ConfigLoader { - if (!ConfigLoader.instance) { - ConfigLoader.instance = new ConfigLoader(); - } - return ConfigLoader.instance; - } - - /** - * Load configuration from JSON file - */ - public async loadConfig(): Promise { - if (this.config) { - return this.config; - } - - try { - // In a real app, this would fetch from a config file - // For test apps, we'll use a hardcoded config - this.config = { - timesafari: { - appId: "app.timesafari.test", - appName: "TimeSafari Test", - version: "1.0.0", - description: "Test app for TimeSafari Daily Notification Plugin integration" - }, - endorser: { - baseUrl: "http://localhost:3001", - apiVersion: "v2", - endpoints: { - offers: "/api/v2/report/offers", - offersToPlans: "/api/v2/report/offersToPlansOwnedByMe", - plansLastUpdated: "/api/v2/report/plansLastUpdatedBetween", - notificationsBundle: "/api/v2/report/notifications/bundle" - }, - authentication: { - type: "Bearer", - token: "test-jwt-token-12345", - headers: { - "Authorization": "Bearer test-jwt-token-12345", - "Content-Type": "application/json", - "X-Privacy-Level": "user-controlled" - } - }, - pagination: { - defaultLimit: 50, - maxLimit: 100, - hitLimitThreshold: 50 - } - }, - notificationTypes: { - offers: { - enabled: true, - types: [ - "new_to_me", - "changed_to_me", - "new_to_projects", - "changed_to_projects", - "new_to_favorites", - "changed_to_favorites" - ] - }, - projects: { - enabled: true, - types: [ - "local_new", - "local_changed", - "content_interest_new", - "favorited_changed" - ] - }, - people: { - enabled: true, - types: [ - "local_new", - "local_changed", - "content_interest_new", - "favorited_changed", - "contacts_changed" - ] - }, - items: { - enabled: true, - types: [ - "local_new", - "local_changed", - "favorited_changed" - ] - } - }, - scheduling: { - contentFetch: { - schedule: "0 8 * * *", - time: "08:00", - description: "8 AM daily - fetch community updates" - }, - userNotification: { - schedule: "0 9 * * *", - time: "09:00", - description: "9 AM daily - notify users of community updates" - } - }, - testData: { - userDid: "did:example:testuser123", - starredPlanIds: [ - "plan-community-garden", - "plan-local-food", - "plan-sustainability" - ], - lastKnownOfferId: "01HSE3R9MAC0FT3P3KZ382TWV7", - lastKnownPlanId: "01HSE3R9MAC0FT3P3KZ382TWV8", - mockOffers: [ - { - jwtId: "01HSE3R9MAC0FT3P3KZ382TWV7", - handleId: "offer-web-dev-001", - offeredByDid: "did:example:offerer123", - recipientDid: "did:example:testuser123", - objectDescription: "Web development services for community project", - unit: "USD", - amount: 1000, - amountGiven: 500, - amountGivenConfirmed: 250 - } - ], - mockProjects: [ - { - plan: { - jwtId: "01HSE3R9MAC0FT3P3KZ382TWV8", - handleId: "plan-community-garden", - name: "Community Garden Project", - description: "Building a community garden for local food production", - issuerDid: "did:example:issuer123", - agentDid: "did:example:agent123" - }, - wrappedClaimBefore: null - } - ] - }, - callbacks: { - offers: { - enabled: true, - localHandler: "handleOffersNotification" - }, - projects: { - enabled: true, - localHandler: "handleProjectsNotification" - }, - people: { - enabled: true, - localHandler: "handlePeopleNotification" - }, - items: { - enabled: true, - localHandler: "handleItemsNotification" - }, - communityAnalytics: { - enabled: true, - endpoint: "http://localhost:3001/api/analytics/community-events", - headers: { - "Content-Type": "application/json", - "X-Privacy-Level": "aggregated" - } - } - }, - observability: { - enableLogging: true, - logLevel: "debug", - enableMetrics: true, - enableHealthChecks: true - } - }; - - return this.config; - } catch (error) { - console.error('Failed to load configuration:', error); - throw error; - } - } - - /** - * Get configuration - */ - public getConfig(): TimeSafariConfig { - if (!this.config) { - throw new Error('Configuration not loaded. Call loadConfig() first.'); - } - return this.config; - } - - /** - * Get Endorser.ch API URL for a specific endpoint - */ - public getEndorserUrl(endpoint: keyof TimeSafariConfig['endorser']['endpoints']): string { - const config = this.getConfig(); - return `${config.endorser.baseUrl}${config.endorser.endpoints[endpoint]}`; - } - - /** - * Get authentication headers - */ - public getAuthHeaders(): Record { - const config = this.getConfig(); - return config.endorser.authentication.headers; - } - - /** - * Get test data - */ - public getTestData(): Record { - const config = this.getConfig(); - return config.testData; - } - - /** - * Get notification types for a specific category - */ - public getNotificationTypes(category: keyof TimeSafariConfig['notificationTypes']): Record { - const config = this.getConfig(); - return config.notificationTypes[category]; - } -} - -/** - * Logger utility for test apps - */ -export class TestLogger { - private logLevel: string; - private logs: string[] = []; - - constructor(logLevel = 'debug') { - this.logLevel = logLevel; - } - - private shouldLog(level: string): boolean { - const levels = ['error', 'warn', 'info', 'debug']; - return levels.indexOf(level) <= levels.indexOf(this.logLevel); - } - - private addToLogs(level: string, message: string, _data?: Record): void { - const timestamp = new Date().toISOString(); - const logEntry = `[${timestamp}] [${level.toUpperCase()}] ${message}`; - this.logs.push(logEntry); - - // Keep only last 1000 logs to prevent memory issues - if (this.logs.length > 1000) { - this.logs = this.logs.slice(-1000); - } - } - - public debug(message: string, data?: Record): void { - if (this.shouldLog('debug')) { - // console.log(`[DEBUG] ${message}`, data || ''); - this.addToLogs('debug', message, data); - } - } - - public info(message: string, data?: Record): void { - if (this.shouldLog('info')) { - // console.log(`[INFO] ${message}`, data || ''); - this.addToLogs('info', message, data); - } - } - - public warn(message: string, data?: Record): void { - if (this.shouldLog('warn')) { - // console.warn(`[WARN] ${message}`, data || ''); - this.addToLogs('warn', message, data); - } - } - - public error(message: string, data?: Record): void { - if (this.shouldLog('error')) { - // console.error(`[ERROR] ${message}`, data || ''); - this.addToLogs('error', message, data); - } - } - - public getLogs(): string[] { - return [...this.logs]; - } - - public clearLogs(): void { - this.logs = []; - } - - public exportLogs(): string { - return this.logs.join('\n'); - } -} - -/** - * Mock DailyNotificationService for test apps - */ -export class MockDailyNotificationService { - private config: TimeSafariConfig; - private logger: TestLogger; - private isInitialized = false; - - constructor(config: TimeSafariConfig) { - this.config = config; - this.logger = new TestLogger(config.observability.logLevel); - } - - /** - * Initialize the service - */ - public async initialize(): Promise { - this.logger.info('Initializing Mock DailyNotificationService'); - this.isInitialized = true; - this.logger.info('Mock DailyNotificationService initialized successfully'); - } - - /** - * Schedule dual notification (content fetch + user notification) - */ - public async scheduleDualNotification(config: Record): Promise { - if (!this.isInitialized) { - throw new Error('Service not initialized'); - } - - this.logger.info('Scheduling dual notification', config); - - // Simulate content fetch - if (config.contentFetch?.enabled) { - await this.simulateContentFetch(config.contentFetch); - } - - // Simulate user notification - if (config.userNotification?.enabled) { - await this.simulateUserNotification(config.userNotification); - } - - this.logger.info('Dual notification scheduled successfully'); - } - - /** - * Register callback - */ - public async registerCallback(name: string, _callback: (...args: unknown[]) => void): Promise { - this.logger.info(`Registering callback: ${name}`); - // In a real implementation, this would register the callback - this.logger.info(`Callback ${name} registered successfully`); - } - - /** - * Get dual schedule status - */ - public async getDualScheduleStatus(): Promise> { - return { - contentFetch: { - enabled: true, - lastFetch: new Date().toISOString(), - nextFetch: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString() - }, - userNotification: { - enabled: true, - lastNotification: new Date().toISOString(), - nextNotification: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString() - } - }; - } - - /** - * Cancel all notifications - */ - public async cancelAllNotifications(): Promise { - this.logger.info('Cancelling all notifications'); - this.logger.info('All notifications cancelled successfully'); - } - - /** - * Simulate content fetch using Endorser.ch API patterns - */ - private async simulateContentFetch(config: Record): Promise { - this.logger.info('Simulating content fetch from Endorser.ch API'); - - try { - // Simulate parallel API requests - const testData = this.config.testData; - - // Mock offers to person - const offersToPerson = { - data: testData.mockOffers, - hitLimit: false - }; - - // Mock offers to projects - const offersToProjects = { - data: [], - hitLimit: false - }; - - // Mock starred project changes - const starredChanges = { - data: testData.mockProjects, - hitLimit: false - }; - - this.logger.info('Content fetch simulation completed', { - offersToPerson: offersToPerson.data.length, - offersToProjects: offersToProjects.data.length, - starredChanges: starredChanges.data.length - }); - - // Call success callback if provided - if (config.callbacks?.onSuccess) { - await config.callbacks.onSuccess({ - offersToPerson, - offersToProjects, - starredChanges - }); - } - } catch (error) { - this.logger.error('Content fetch simulation failed', error); - if (config.callbacks?.onError) { - await config.callbacks.onError(error); - } - } - } - - /** - * Simulate user notification - */ - private async simulateUserNotification(config: Record): Promise { - this.logger.info('Simulating user notification', { - title: config.title, - body: config.body, - time: config.schedule - }); - this.logger.info('User notification simulation completed'); - } -} diff --git a/test-apps/shared/typescript/EndorserAPIClient.ts b/test-apps/shared/typescript/EndorserAPIClient.ts deleted file mode 100644 index 29d8a29..0000000 --- a/test-apps/shared/typescript/EndorserAPIClient.ts +++ /dev/null @@ -1,659 +0,0 @@ -/** - * EndorserAPIClient.ts - * - * Complete implementation of Endorser.ch API client for TimeSafari notifications - * Supports offers, projects, people, and items notification types with pagination - * - * @author Matthew Raymer - * @version 4.0.0 - */ - -import { - OffersResponse, - OffersToPlansResponse, - PlansLastUpdatedResponse, - TimeSafariNotificationBundle, - TimeSafariUserConfig, - TimeSafariNotificationType -} from '../definitions'; - -export interface EndorserAPIConfig { - baseUrl: string; - timeoutMs: number; - maxRetries: number; - enableParallel: boolean; - maxConcurrent: number; - jwtSecret?: string; -} - -export interface EndorserAPIRequest { - endpoint: string; - params?: Record; - body?: Record; - method: 'GET' | 'POST'; - timeoutMs?: number; - authRequired: boolean; -} - -export interface EndorserAPIError { - statusCode: number; - message: string; - endpoint: string; - timestamp: number; - retryable: boolean; -} - -/** - * Default EndorserAPI configuration for TimeSafari - */ -export const TIMESAFARI_ENDSORER_CONFIG: EndorserAPIConfig = { - baseUrl: 'https://api.endorser.ch', - timeoutMs: 15000, - maxRetries: 3, - enableParallel: true, - maxConcurrent: 3, - jwtSecret: process.env.ENDORSER_JWT_SECRET -}; - -/** - * Endorser.ch API Client for TimeSafari integrations - */ -export class EndorserAPIClient { - private config: EndorserAPIConfig; - private authToken?: string; - private rateLimiter: Map = new Map(); - private requestCache: Map = new Map(); - - constructor(config: Partial = {}) { - this.config = { ...TIMESAFARI_ENDSORER_CONFIG, ...config }; - } - - /** - * Set authentication token for API requests - */ - setAuthToken(token: string): void { - this.authToken = token; - } - - /** - * Generate JWT token for DID-based authentication - */ - async generateJWTForDID(activeDid: string, _jwtSecret?: string): Promise { - try { - // In a real implementation, this would use a JWT library like di-djwt - // For Phase 4, we'll generate a mock JWT structure - const issuedAt = Math.floor(Date.now() / 1000); - const expiresAt = issuedAt + 3600; // 1 hour expiration - - const payload = { - iss: activeDid, - sub: activeDid, - aud: 'endorser-api', - exp: expiresAt, - iat: issuedAt, - jti: `notification-${Date.now()}-${Math.random().toString(36).substr(2, 9)}` - }; - - // Mock JWT generation - in production, would use proper signing - const header = btoa(JSON.stringify({ alg: 'ES256K', typ: 'JWT' })); - const payload_b64 = btoa(JSON.stringify(payload)); - const signature = btoa(`${activeDid}-${Date.now()}-mock-signature`); - - return `${header}.${payload_b64}.${signature}`; - - } catch (error) { - console.error('Error generating JWT for DID:', error); - throw new Error(`JWT generation failed: ${error instanceof Error ? error.message : 'Unknown error'}`); - } - } - - /** - * Fetch offers directed to a specific person - * Endpoint: GET /api/v2/report/offers?recipientId={did} - */ - async fetchOffersToPerson( - recipientDid: string, - afterId?: string, - beforeId?: string, - options?: { validThrough?: string; offeredByDid?: string } - ): Promise { - try { - const params = new URLSearchParams(); - params.set('recipientId', recipientDid); - if (afterId) params.set('afterId', afterId); - if (beforeId) params.set('beforeId', beforeId); - if (options?.validThrough) params.set('validThrough', options.validThrough); - if (options?.offeredByDid) params.set('offeredByDid', options.offeredByDid); - - const response = await this.request({ - endpoint: `/api/v2/report/offers`, - method: 'GET', - params: Object.fromEntries(params), - authRequired: true - }); - - return response as OffersResponse; - - } catch (error) { - console.error('Error fetching offers to person:', error instanceof Error ? error.message : 'Unknown error'); - return { data: [], hitLimit: false }; - } - } - - /** - * Fetch offers directed to projects owned by authenticated user - * Endpoint: GET /api/v2/report/offersToPlansOwnedByMe - */ - async fetchOffersToProjectsOwnedByMe( - afterId?: string, - beforeId?: string - ): Promise { - try { - const params: Record = {}; - if (afterId) params.afterId = afterId; - if (beforeId) params.beforeId = beforeId; - - const response = await this.request({ - endpoint: `/api/v2/report/offersToPlansOwnedByMe`, - method: 'GET', - params, - authRequired: true - }); - - return response as OffersToPlansResponse; - - } catch (error) { - console.error('Error fetching offers to projects:', error instanceof Error ? error.message : 'Unknown error'); - return { data: [], hitLimit: false }; - } - } - - /** - * Fetch changes to specific projects since a given point - * Endpoint: POST /api/v2/report/plansLastUpdatedBetween - */ - async fetchProjectsLastUpdated( - planIds: string[], - afterId?: string, - beforeId?: string - ): Promise { - try { - const body: Record = { - planIds - }; - if (afterId) body.afterId = afterId; - if (beforeId) body.beforeId = beforeId; - - const response = await this.request({ - endpoint: `/api/v2/report/plansLastUpdatedBetween`, - method: 'POST', - body, - authRequired: true - }); - - return response as PlansLastUpdatedResponse; - - } catch (error) { - console.error('Error fetching project updates:', error instanceof Error ? error.message : 'Unknown error'); - return { data: [], hitLimit: false }; - } - } - - /** - * Fetch all TimeSafari notification data in parallel - * This is the main method for TimeSafari integration - */ - async fetchAllTimeSafariNotifications( - userConfig: TimeSafariUserConfig - ): Promise { - const startTime = Date.now(); - const bundle: TimeSafariNotificationBundle = { - offersToPerson: undefined, - offersToProjects: undefined, - projectUpdates: undefined, - fetchTimestamp: startTime, - success: false, - metadata: { - activeDid: userConfig.activeDid, - fetchDurationMs: 0, - cachedResponses: 0, - networkResponses: 0 - } - }; - - try { - // Fetching all TimeSafari notifications for user - - // Ensure authentication - const token = await this.generateJWTForDID(userConfig.activeDid); - this.setAuthToken(token); - - const requests: Promise[] = []; - - // 1. Offers to Person - if (userConfig.fetchOffersToPerson !== false) { - requests.push( - this.fetchOffersToPerson( - userConfig.activeDid, - userConfig.lastKnownOfferId, - undefined - ).then(response => { - bundle.offersToPerson = response; - if (bundle.metadata) { - bundle.metadata.networkResponses++; - } - }) - ); - } - - // 2. Offers it Plans Owned by Current User - if (userConfig.fetchOffersToProjects !== false) { - requests.push( - this.fetchOffersToProjectsOwnedByMe(userConfig.lastKnownOfferId) - .then(response => { - bundle.offersToProjects = response; - if (bundle.metadata) { - bundle.metadata.networkResponses++; - } - }) - ); - } - - // 3. Starred Project Changes - if (userConfig.fetchProjectUpdates && userConfig.starredPlanIds && userConfig.starredPlanIds.length > 0) { - requests.push( - this.fetchProjectsLastUpdated( - userConfig.starredPlanIds, - userConfig.lastKnownPlanId, - undefined - ).then(response => { - bundle.projectUpdates = response; - if (bundle.metadata) { - bundle.metadata.networkResponses++; - } - }) - ); - } - - // Execute all requests in parallel - if (requests.length > 0) { - await Promise.allSettled(requests); - } - - bundle.success = true; - - } catch (error) { - console.error('Error fetching TimeSafari notifications:', error instanceof Error ? error.message : 'Unknown error'); - bundle.success = false; - bundle.error = error instanceof Error ? error.message : 'Unknown error'; - - // Ensure we have partial data even on error - if (bundle.metadata) { - bundle.metadata.networkResponses = bundle.metadata.networkResponses || 0; - } - - } finally { - if (bundle.metadata) { - bundle.metadata.fetchDurationMs = Date.now() - startTime; - } - if (bundle.metadata) { - // TimeSafari notification fetch completed - } - } - - return bundle; - } - - /** - * Generate TimeSafari-specific notification content from API responses - */ - generateTimeSafariNotifications(bundle: TimeSafariNotificationBundle): TimeSafariNotificationType[] { - const notifications: TimeSafariNotificationType[] = []; - - try { - // Generate offer notifications - this.generateOfferNotifications(bundle, notifications); - - // Generate project notification notifications - this.generateProjectNotifications(bundle, notifications); - - // Generate people notifications (derived from offers and projects) - this.generatePeopleNotifications(bundle, notifications); - - // Generate items notifications (derived from projects) - this.generateItemNotifications(bundle, notifications); - - // Generated TimeSafari notifications - return notifications; - - } catch (error) { - console.error('Error generating TimeSafari notifications:', error); - return []; - } - } - - /** - * Generate notification-specific notification content - */ - private generateOfferNotifications( - bundle: TimeSafariNotificationBundle, - notifications: TimeSafariNotificationType[] - ): void { - try { - // New offers to person - if (bundle.offersToPerson?.data && bundle.offersToPerson.data.length > 0) { - bundle.offersToPerson.data.forEach(offer => { - notifications.push({ - type: 'offer', - subtype: 'new_to_me', - offer, - notificationPriority: 'high', - timestamp: Date.now() - }); - }); - } - - // New offers to projects owned by user - if (bundle.offersToProjects?.data && bundle.offersToProjects.data.length > 0) { - bundle.offersToProjects.data.forEach(offerToPlan => { - notifications.push({ - type: 'offer', - subtype: 'new_to_projects', - offer: { - jwtId: offerToPlan.jwtId, - handleId: offerToPlan.handleId, - issuedAt: offerToPlan.issuedAt, - offeredByDid: offerToPlan.offeredByDid, - recipientDid: '', // Placeholder - would be derived from context - unit: offerToPlan.unit, - amount: offerToPlan.amount, - amountGiven: offerToPlan.amountGiven, - amountGivenConfirmed: 0, // Placeholder - objectDescription: offerToPlan.objectDescription, - validThrough: offerToPlan.validThrough, - fullClaim: {} // Placeholder - }, - relevantProjects: [], // Would be populated from plan lookup - notificationPriority: 'medium', - timestamp: Date.now() - }); - }); - } - - } catch (error) { - console.error('Error generating offer notifications:', error); - } - } - - /** - * Generate project-specific notification content - */ - private generateProjectNotifications( - bundle: TimeSafariNotificationBundle, - notifications: TimeSafariNotificationType[] - ): void { - try { - if (bundle.projectUpdates?.data && bundle.projectUpdates.data.length > 0) { - bundle.projectUpdates.data.forEach(update => { - notifications.push({ - type: 'project', - subtype: 'favorite_and_changed', - project: update.plan, - previousClaim: update.wrappedClaimBefore, - notificationPriority: 'medium', - timestamp: Date.now() - }); - }); - } - - } catch (error) { - console.error('Error generating project notifications:', error); - } - } - - /** - * Generate people-specific notification content - */ - private generatePeopleNotifications( - bundle: TimeSafariNotificationBundle, - notifications: TimeSafariNotificationType[] - ): void { - try { - // Extract unique people from offers - const people = new Set(); - - if (bundle.offersToPerson?.data) { - bundle.offersToPerson.data.forEach(offer => { - if (offer.offeredByDid) people.add(offer.offeredByDid); - }); - } - - // Generate people notifications - people.forEach(did => { - notifications.push({ - type: 'person', - subtype: 'with_content_and_new', - personDid: did, - person: { did, name: `User-${did.slice(-6)}` }, // Placeholder name - notificationPriority: 'low', - timestamp: Date.now() - }); - }); - - } catch (error) { - console.error('Error generating people notifications:', error); - } - } - - /** - * Generate items-specific notification content - */ - private generateItemNotifications( - bundle: TimeSafariNotificationBundle, - notifications: TimeSafariNotificationType[] - ): void { - try { - if (bundle.projectUpdates?.data) { - bundle.projectUpdates.data.forEach(update => { - notifications.push({ - type: 'item', - subtype: 'favorite_and_changed', - itemId: update.plan.jwtId, - item: { - id: update.plan.jwtId, - name: update.plan.name, - type: 'project' - }, - notificationPriority: 'low', - timestamp: Date.now() - }); - }); - } - - } catch (error) { - console.error('Error generating item notifications:', error); - } - } - - /** - * Execute authenticated request with retry logic - */ - private async request(requestConfig: EndorserAPIRequest): Promise { - const url = `${this.config.baseUrl}${requestConfig.endpoint}`; - - try { - // Check rate limiting - this.checkRateLimit(requestConfig.endpoint); - - // Check cache - const cached = this.getCachedResponse(url); - if (cached) { - // Returning cached response - return cached; - } - - // Prepare headers - const headers: Record = { - 'Content-Type': 'application/json', - 'User-Agent': 'TimeSafari-DailyNotificationPlugin/1.0.0' - }; - - // Add authentication if required - if (requestConfig.authRequired && this.authToken) { - headers['Authorization'] = `Bearer ${this.authToken}`; - } - - // Prepare request options - const options: RequestInit = { - method: requestConfig.method, - headers, - signal: AbortSignal.timeout(requestConfig.timeoutMs || this.config.timeoutMs) - }; - - // Add body for POST requests - if (requestConfig.method === 'POST' && requestConfig.body) { - options.body = JSON.stringify(requestConfig.body); - } else if (requestConfig.method === 'GET' && requestConfig.params) { - // Add query parameters for GET requests - const params = new URLSearchParams(requestConfig.params); - const fullUrl = `${url}?${params}`; - return this.executeRequest(fullUrl, options, requestConfig.endpoint); - } - - return await this.executeRequest(url, options, requestConfig.endpoint); - - } catch (error) { - console.error(`Error executing request to ${requestConfig.endpoint}:`, error); - throw error; - } - } - - /** - * Execute HTTP request with retry logic - */ - private async executeRequest(url: string, options: RequestInit, endpoint: string): Promise { - let lastError: Error | undefined; - - for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) { - try { - // Executing request attempt - - const response = await fetch(url, options); - - if (response.ok) { - const data = await response.json(); - - // Cache successful response - this.cacheResponse(url, data); - - // Update rate limiter - this.rateLimiter.set(endpoint, Date.now()); - - return data; - - } else if (response.status === 401 || response.status === 403) { - throw new EndorserAPIError( - response.status, - 'Authentication failed', - endpoint, - Date.now(), - false - ); - - } else if (response.status >= 500) { - lastError = new EndorserAPIError( - response.status, - 'Server error - retryable', - endpoint, - Date.now(), - true - ); - - // Continue to retry for server errors - - } else { - throw new EndorserAPIError( - response.status, - 'Client error', - endpoint, - Date.now(), - false - ); - } - - } catch (error) { - lastError = error instanceof EndorserAPIError ? error : new Error(error instanceof Error ? error.message : 'Unknown error'); - - if (!(lastError instanceof EndorserAPIError && lastError.retryable) || attempt >= this.config.maxRetries) { - throw lastError; - } - - // Wait before retry with exponential backoff - const waitTime = Math.min(1000 * Math.pow(2, attempt), 5000); - // Request failed, retrying - await new Promise(resolve => setTimeout(resolve, waitTime)); - } - } - - throw lastError; - } - - /** - * Check and enforce rate limiting - */ - private checkRateLimit(endpoint: string): void { - const lastRequest = this.rateLimiter.get(endpoint); - if (lastRequest) { - const timeSinceLastRequest = Date.now() - lastRequest; - if (timeSinceLastRequest < 1000) { // 1 second between requests - // Rate limiting detected, waiting - throw new Error('Rate limited'); - } - } - } - - /** - * Cache response for future use - */ - private cacheResponse(url: string, data: unknown): void { - this.requestCache.set(url, { - data, - timestamp: Date.now() - }); - } - - /** - * Get cached response if fresh enough - */ - private getCachedResponse(url: string): unknown { - const cached = this.requestCache.get(url); - if (cached && (Date.now() - cached.timestamp) < 30000) { // 30 seconds cache - return cached.data; - } - return null; - } - - /** - * Clear cache (useful after activeDid changes) - */ - clearCache(): void { - this.requestCache.clear(); - // EndorserAPI cache cleared - } -} - -/** - * Error class for EndorserAPI errors - */ -export class EndorserAPIError extends Error { - constructor( - public statusCode: number, - public message: string, - public endpoint: string, - public timestamp: number, - public retryable: boolean - ) { - super(message); - this.name = 'EndorserAPIError'; - } -} diff --git a/test-apps/shared/typescript/SecurityManager.ts b/test-apps/shared/typescript/SecurityManager.ts deleted file mode 100644 index ea4a40e..0000000 --- a/test-apps/shared/typescript/SecurityManager.ts +++ /dev/null @@ -1,554 +0,0 @@ -/** - * SecurityManager.ts - * - * Enhanced security manager for DID-based authentication and cryptographic verification - * Supports JWT generation, signature verification, and secure credential management - * - * @author Matthew Raymer - * @version 4.0.0 - */ - -// PlatformService import removed - not used in Phase 4 implementation - -export interface DIDCredentials { - did: string; - privateKey?: string; // Encrypted private key - publicKey?: string; // Public key in JWK format - keyType: 'secp256k1' | 'Ed25519' | 'RSA'; - keyManagement: 'local' | 'platform_service' | 'secure_element'; -} - -export interface JWTClaims { - iss: string; // Issuer DID - sub: string; // Subject DID - aud: string; // Audience - exp: number; // Expiration time - iat: number; // Issued at - jti: string; // JWT ID - nonce?: string; // Nonce for replay protection - scope?: string; // Permission scope -} - -export interface SecurityConfig { - enableCryptoSigning: boolean; - enableJWTGeneration: boolean; - enableCredentialStorage: boolean; - jwtExpirationMinutes: number; - signatureAlgorithm: 'ES256K' | 'EdDSA' | 'RS256'; - keyDerivation: boolean; - credentialStorage: 'secure_element' | 'keychain' | 'encrypted_storage'; -} - -export interface CryptoOperation { - success: boolean; - data?: Record; - error?: string; - timestamp: number; - operation: string; -} - -/** - * Default security configuration for TimeSafari - */ -export const TIMESAFARI_SECURITY_CONFIG: SecurityConfig = { - enableCryptoSigning: true, - enableJWTGeneration: true, - enableCredentialStorage: true, - jwtExpirationMinutes: 60, - signatureAlgorithm: 'ES256K', - keyDerivation: true, - credentialStorage: 'secure_element' -}; - -/** - * Secure credential storage interface - */ -interface CredentialStorage { - storeCredentials(did: string, credentials: DIDCredentials): Promise; - retrieveCredentials(did: string): Promise; - deleteCredentials(did: string): Promise; - listCredentials(): Promise; -} - -/** - * Secure element credential storage implementation - */ -class SecureElementStorage implements CredentialStorage { - async storeCredentials(did: string, credentials: DIDCredentials): Promise { - try { - // In a real implementation, this would use platform-specific secure storage - // For Phase 4, we'll use a mock secure storage - const secureData = { - did: credentials.did, - keyType: credentials.keyType, - timestamp: Date.now(), - encrypted: true - }; - - await this.writeToSecureElement(`cred_${did}`, JSON.stringify(secureData)); - return true; - - } catch (error) { - console.error('Error storing credentials:', error instanceof Error ? error.message : 'Unknown error'); - return false; - } - } - - async retrieveCredentials(did: string): Promise { - try { - const data = await this.readFromSecureElement(`cred_${did}`); - if (data) { - const parsed = JSON.parse(data); - return { - did: parsed.did, - keyType: parsed.keyType, - keyManagement: 'secure_element' - }; - } - return undefined; - - } catch (error) { - console.error('Error retrieving credentials:', error instanceof Error ? error.message : 'Unknown error'); - return undefined; - } - } - - async deleteCredentials(did: string): Promise { - try { - await this.deleteFromSecureElement(`cred_${did}`); - return true; - - } catch (error) { - console.error('Error deleting credentials:', error instanceof Error ? error.message : 'Unknown error'); - return false; - } - } - - async listCredentials(): Promise { - try { - // Mock implementation - would list actual secure element entries - return ['did:example:alice', 'did:example:bob']; - - } catch (error) { - console.error('Error listing credentials:', error); - return []; - } - } - - private async writeToSecureElement(_key: string, _data: string): Promise { - // Mock secure element write - in production would use platform APIs - // Mock secure element write operation - } - - private async readFromSecureElement(_key: string): Promise { - // Mock secure element read - in production would use platform APIs - // Mock secure element read operation - return `{"did":"${_key}", "keyType":"secp256k1", "timestamp":${Date.now()}, "encrypted":true}`; - } - - private async deleteFromSecureElement(_key: string): Promise { - // Mock secure element delete - in production would use platform APIs - // Mock secure element delete operation - } -} - -/** - * Enhanced Security Manager for TimeSafari DID operations - */ -export class SecurityManager { - private config: SecurityConfig; - private credentialStorage: CredentialStorage; - private activeDid?: string; - private activeCredentials?: DIDCredentials; - private operationHistory: CryptoOperation[] = []; - - constructor(config: Partial = {}) { - this.config = { ...TIMESAFARI_SECURITY_CONFIG, ...config }; - this.credentialStorage = new SecureElementStorage(); - } - - /** - * Initialize security manager with active DID - */ - async initialize(activeDid: string): Promise { - try { - // Initializing SecurityManager for DID - - this.activeDid = activeDid; - - // Retrieve stored credentials - this.activeCredentials = await this.credentialStorage.retrieveCredentials(activeDid); - - if (!this.activeCredentials) { - // No stored credentials found, initializing new ones - const newCredentials = await this.generateNewCredentials(activeDid); - - if (newCredentials) { - await this.credentialStorage.storeCredentials(activeDid, newCredentials); - this.activeCredentials = newCredentials; - } - } - - // SecurityManager initialized successfully - return true; - - } catch (error) { - console.error('Error initializing SecurityManager:', error); - return false; - } - } - - /** - * Generate new DID credentials - */ - async generateNewCredentials(did: string): Promise { - try { - // Generating new credentials for DID - - const credentials: DIDCredentials = { - did, - keyType: this.config.signatureAlgorithm === 'ES256K' ? 'secp256k1' - : this.config.signatureAlgorithm === 'EdDSA' ? 'Ed25519' - : 'RSA', - keyManagement: 'secure_element' - }; - - // Generate cryptographic keys based on platform capabilities - if (this.config.enableCryptoSigning) { - const keys = await this.generateKeys(credentials.keyType); - credentials.privateKey = keys.privateKey; - credentials.publicKey = keys.publicKey; - } - - this.logOperation({ - success: true, - timestamp: Date.now(), - operation: 'generate_credentials' - }); - - return credentials; - - } catch (error) { - console.error('Error generating credentials:', error); - this.logOperation({ - success: false, - error: error instanceof Error ? error.message : 'Unknown error', - timestamp: Date.now(), - operation: 'generate_credentials' - }); - return null; - } - } - - /** - * Generate cryptographic keys - */ - private async generateKeys(keyType: 'secp256k1' | 'Ed25519' | 'RSA'): Promise<{ privateKey: string; publicKey: string }> { - try { - // In a real implementation, this would use platform cryptographic APIs - // For Phase 4, we'll generate mock keys - - const timestamp = Date.now(); - const mockKeys = { - privateKey: `mock_private_key_${keyType}_${timestamp}`, - publicKey: `mock_public_key_${keyType}_${timestamp}` - }; - - // Generated keys for secure operations - return mockKeys; - - } catch (error) { - console.error('Error generating keys:', error); - throw error instanceof Error ? error : new Error('Unknown error'); - } - } - - /** - * Generate JWT token for authentication - */ - async generateJWT(claims: Partial, audience = 'endorser-api'): Promise { - try { - if (!this.activeDid || !this.activeCredentials) { - throw new Error('No active DID or credentials available'); - } - - // Generating JWT for DID - - const now = Math.floor(Date.now() / 1000); - const fullClaims: JWTClaims = { - iss: this.activeDid, - sub: this.activeDid, - aud: audience, - exp: now + (this.config.jwtExpirationMinutes * 60), - iat: now, - jti: `jwt_${now}_${Math.random().toString(36).substr(2, 9)}`, - nonce: this.generateNonce(), - scope: 'notifications', - ...claims - }; - - let jwt: string; - - if (this.config.enableCryptoSigning && this.activeCredentials.privateKey) { - // Generate signed JWT - jwt = await this.generateSignedJWT(fullClaims); - } else { - // Generate unsigned JWT (for development/testing) - jwt = await this.generateUnsignedJWT(fullClaims); - } - - this.logOperation({ - success: true, - data: { iss: fullClaims.iss, exp: fullClaims.exp }, - timestamp: Date.now(), - operation: 'generate_jwt' - }); - - // JWT generated successfully - return jwt; - - } catch (error) { - console.error('Error generating JWT:', error instanceof Error ? error.message : 'Unknown error'); - this.logOperation({ - success: false, - error: error instanceof Error ? error.message : 'Unknown error', - timestamp: Date.now(), - operation: 'generate_jwt' - }); - return null; - } - } - - /** - * Generate signed JWT with cryptographic signature - */ - private async generateSignedJWT(claims: JWTClaims): Promise { - try { - // In a real implementation, this would use proper JWT signing libraries - // For Phase 4, we'll create a mock signed JWT structure - - const header = { - alg: this.config.signatureAlgorithm, - typ: 'JWT' - }; - - const encodedHeader = btoa(JSON.stringify(header)); - const encodedPayload = btoa(JSON.stringify(claims)); - - // Mock signature generation - const signature = btoa(`signature_${claims.jti}_${Date.now()}`); - - const jwt = `${encodedHeader}.${encodedPayload}.${signature}`; - - // Generated signed JWT - return jwt; - - } catch (error) { - console.error('Error generating signed JWT:', error); - throw error; - } - } - - /** - * Generate unsigned JWT (for development/testing) - */ - private async generateUnsignedJWT(claims: JWTClaims): Promise { - try { - const header = { - alg: 'none', - typ: 'JWT' - }; - - const encodedHeader = btoa(JSON.stringify(header)); - const encodedPayload = btoa(JSON.stringify(claims)); - - const jwt = `${encodedHeader}.${encodedPayload}.`; - - // Generated unsigned JWT (development mode) - return jwt; - - } catch (error) { - console.error('Error generating unsigned JWT:', error); - throw error; - } - } - - /** - * Verify JWT signature and claims - */ - async verifyJWT(token: string): Promise { - try { - // Verifying JWT token - - const parts = token.split('.'); - if (parts.length !== 3) { - throw new Error('Invalid JWT format'); - } - - const [headerEncoded, payloadEncoded, signature] = parts; - - // Decode header and payload - const header = JSON.parse(atob(headerEncoded)); - const claims = JSON.parse(atob(payloadEncoded)); - - // Verify expiration - const now = Math.floor(Date.now() / 1000); - if (claims.exp && claims.exp < now) { - throw new Error('JWT expired'); - } - - // Verify signature (in production, would use proper verification) - if (header.alg !== 'none' && !this.verifySignature(header, payloadEncoded, signature)) { - throw new Error('Invalid JWT signature'); - } - - this.logOperation({ - success: true, - data: 'verified claims', - timestamp: Date.now(), - operation: 'verify_jwt' - }); - - // JWT verified successfully - return claims; - - } catch (error) { - console.error('Error verifying JWT:', error instanceof Error ? error.message : 'Unknown error'); - this.logOperation({ - success: false, - error: error instanceof Error ? error.message : 'Unknown error', - timestamp: Date.now(), - operation: 'verify_jwt' - }); - return null; - } - } - - /** - * Verify cryptographic signature - */ - private verifySignature(_header: Record, _payload: string, signature: string): boolean { - try { - // In a real implementation, this would verify the signature using the public key - // For Phase 4, we'll perform basic signature format validation - - return signature.length > 0 && !signature.endsWith('.'); - - } catch (error) { - console.error('Error verifying signature:', error); - return false; - } - } - - /** - * Generate cryptographically secure nonce - */ - private generateNonce(): string { - // Generate a secure nonce for replay protection - const bytes = new Uint8Array(16); - if (typeof crypto !== 'undefined' && crypto.getRandomValues) { - crypto.getRandomValues(bytes); - } else { - // Fallback for environments without crypto.getRandomValues - for (let i = 0; i < bytes.length; i++) { - bytes[i] = Math.floor(Math.random() * 256); - } - } - - return Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join(''); - } - - /** - * Log cryptographic operations for audit and debugging - */ - private logOperation(operation: CryptoOperation): void { - this.operationHistory.push(operation); - - // Keep only last 100 operations - if (this.operationHistory.length > 100) { - this.operationHistory = this.operationHistory.slice(-100); - } - } - - /** - * Get operation history for audit purposes - */ - getOperationHistory(): CryptoOperation[] { - return [...this.operationHistory]; - } - - /** - * Clear credentials and reset security manager - */ - async reset(): Promise { - try { - // Clear active credentials - this.activeDid = undefined; - this.activeCredentials = undefined; - - // Clear operation history - this.operationHistory = []; - - // SecurityManager reset completed - - } catch (error) { - console.error('Error resetting SecurityManager:', error); - } - } - - /** - * Update active DID (for identity changes) - */ - async updateActiveDid(newActiveDid: string): Promise { - try { - // Updating active DID - - // Retrieve credentials for new DID - const credentials = await this.credentialStorage.retrieveCredentials(newActiveDid); - - if (!credentials) { - // No credentials found for new DID, generating new ones - const newCredentials = await this.generateNewCredentials(newActiveDid); - - if (newCredentials) { - await this.credentialStorage.storeCredentials(newActiveDid, newCredentials); - this.activeCredentials = newCredentials; - } else { - return false; - } - } else { - this.activeCredentials = credentials; - } - - this.activeDid = newActiveDid; - - // Active DID updated successfully - return true; - - } catch (error) { - console.error('Error updating active DID:', error); - return false; - } - } - - /** - * Get current active DID - */ - getActiveDid(): string | undefined { - return this.activeDid; - } - - /** - * Get security configuration - */ - getSecurityConfig(): SecurityConfig { - return { ...this.config }; - } - - /** - * Check if security manager is properly initialized - */ - isInitialized(): boolean { - return !!this.activeDid && !!this.activeCredentials; - } -} diff --git a/test-apps/shared/typescript/TimeSafariNotificationManager.ts b/test-apps/shared/typescript/TimeSafariNotificationManager.ts deleted file mode 100644 index ffe1c95..0000000 --- a/test-apps/shared/typescript/TimeSafariNotificationManager.ts +++ /dev/null @@ -1,640 +0,0 @@ -/** - * TimeSafariNotificationManager.ts - * - * High-level TimeSafari notification manager integrating EndorserAPI and security - * Manages notification generation, user preferences, and TimeSafari-specific features - * - * @author Matthew Raymer - * @version 4.0.0 - */ - -import { - EndorserAPIClient, - TIMESAFARI_ENDSORER_CONFIG -} from './EndorserAPIClient'; -import { - SecurityManager, - TIMESAFARI_SECURITY_CONFIG -} from './SecurityManager'; -import { - TimeSafariUserConfig, - EnhancedTimeSafariNotification as TimeSafariNotification, - TimeSafariNotificationType, - CoordinationStatus -} from '../definitions'; - -export interface TimeSafariPreferences { - notificationTypes: { - offers: boolean; - projects: boolean; - people: boolean; - items: boolean; - }; - offerSubtypes: { - new_to_me: boolean; - changed_to_me: boolean; - new_to_projects: boolean; - changed_to_projects: boolean; - new_to_favorites: boolean; - changed_to_favorites: boolean; - }; - projectSubtypes: { - local_and_new: boolean; - local_and_changed: boolean; - with_content_and_new: boolean; - favorite_and_changed: boolean; - }; - peopleSubtypes: { - local_and_new: boolean; - local_and_changed: boolean; - with_content_and_new: boolean; - favorite_and_changed: boolean; - }; - itemsSubtypes: { - local_and_new: boolean; - local_and_changed: boolean; - favorite_and_changed: boolean; - }; - frequency: { - immediate: boolean; - daily: boolean; - weekly: boolean; - custom?: string; // Cron expression - }; - priority: 'low' | 'medium' | 'high'; - sound: boolean; - vibration: boolean; - badge: boolean; -} - -export interface TimeSafariUser { - activeDid: string; - preferences: TimeSafariPreferences; - starredPlanIds: string[]; - favoritePersonIds: string[]; - favoriteItemIds: string[]; - lastKnownOfferId?: string; - lastKnownPlanId?: string; - coordinationStatus?: CoordinationStatus; -} - -export interface NotificationGenerationOptions { - forceFetch: boolean; - includeMetadata: boolean; - filterByPriority: boolean; - maxNotifications: number; - cacheTtl: number; // TTL in milliseconds -} - -/** - * Default TimeSafari preferences - */ -export const DEFAULT_TIMESAFARI_PREFERENCES: TimeSafariPreferences = { - notificationTypes: { - offers: true, - projects: true, - people: false, - items: true - }, - offerSubtypes: { - new_to_me: true, - changed_to_me: false, - new_to_projects: true, - changed_to_projects: false, - new_to_favorites: true, - changed_to_favorites: false - }, - projectSubtypes: { - local_and_new: false, - local_and_changed: false, - with_content_and_new: true, - favorite_and_changed: true - }, - peopleSubtypes: { - local_and_new: false, - local_and_changed: false, - with_content_and_new: false, - favorite_and_changed: false - }, - itemsSubtypes: { - local_and_new: false, - local_and_changed: false, - favorite_and_changed: true - }, - frequency: { - immediate: true, - daily: true, - weekly: false - }, - priority: 'medium', - sound: true, - vibration: true, - badge: true -}; - -/** - * TimeSafari-specific notification manager - */ -export class TimeSafariNotificationManager { - private apiClient: EndorserAPIClient; - private securityManager: SecurityManager; - private user?: TimeSafariUser; - private cache: Map = new Map(); - private activeGeneration = new Set(); - - constructor() { - this.apiClient = new EndorserAPIClient(TIMESAFARI_ENDSORER_CONFIG); - this.securityManager = new SecurityManager(TIMESAFARI_SECURITY_CONFIG); - } - - /** - * Initialize manager for specific TimeSafari user - */ - async initialize(user: TimeSafariUser): Promise { - try { - // Initializing TimeSafariNotificationManager for user - - // Initialize security manager with active DID - const securityInitialized = await this.securityManager.initialize(user.activeDid); - if (!securityInitialized) { - console.error('Failed to initialize security manager'); - return false; - } - - // Generate JWT token for API authentication - const token = await this.securityManager.generateJWT({ - scope: 'notifications' - }); - - if (token) { - this.apiClient.setAuthToken(token); - } - - // Set user configuration - this.user = user; - - // TimeSafariNotificationManager initialized successfully - return true; - - } catch (error) { - console.error('Error initializing TimeSafariNotificationManager:', error); - return false; - } - } - - /** - * Generate TimeSafari-specific notifications based on user preferences - */ - async generateNotifications( - options: Partial = {} - ): Promise { - if (!this.user) { - throw new Error('TimeSafariNotificationManager not initialized'); - } - - // const generationId = `generation_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`; - const generationOptions: NotificationGenerationOptions = { - forceFetch: false, - includeMetadata: true, - filterByPriority: true, - maxNotifications: 50, - cacheTtl: 300000, // 5 minutes - ...options - }; - - try { - // Starting notification generation - - // Prevent concurrent generations for same user - if (this.activeGeneration.has(this.user.activeDid)) { - // Generation already in progress, skipping - return []; - } - - this.activeGeneration.add(this.user.activeDid); - - // Check cache first - const cached = options.forceFetch ? null : this.getCachedNotifications(); - if (cached) { - // Returning cached notifications - return this.filterNotificationsByPreferences(cached, generationOptions); - } - - // Fetch fresh data from EndorserAPI - const userConfig = this.buildUserConfig(); - const bundle = await this.apiClient.fetchAllTimeSafariNotifications(userConfig); - - if (!bundle.success) { - console.error('Failed to fetch TimeSafari data:', bundle.error); - return this.generateFallbackNotifications(); - } - - // Generate TimeSafari notifications - const allNotifications = this.apiClient.generateTimeSafariNotifications(bundle); - - // Cache the results - this.cacheNotifications(allNotifications, bundle.fetchTimestamp); - - // Filter by user preferences - const filteredNotifications = this.filterNotificationsByPreferences( - allNotifications, - generationOptions - ); - - // Generated notifications successfully - - return filteredNotifications; - - } catch (error) { - console.error('Error generating notifications:', error); - return this.generateFallbackNotifications(); - - } finally { - this.activeGeneration.delete(this.user.activeDid); - } - } - - /** - * Build user configuration from user preferences and state - */ - private buildUserConfig(): TimeSafariUserConfig { - if (!this.user) { - throw new Error('User not initialized'); - } - - return { - activeDid: this.user.activeDid, - starredPlanIds: this.user.starredPlanIds || [], - lastKnownOfferId: this.user.lastKnownOfferId, - lastKnownPlanId: this.user.lastKnownPlanId, - fetchOffersToPerson: this.user.preferences.notificationTypes.offers, - fetchOffersToProjects: this.user.preferences.notificationTypes.offers, - fetchProjectUpdates: this.user.preferences.notificationTypes.projects, - notificationPreferences: { - offers: this.user.preferences.notificationTypes.offers, - projects: this.user.preferences.notificationTypes.projects, - people: this.user.preferences.notificationTypes.people, - items: this.user.preferences.notificationTypes.items - } - }; - } - - /** - * Filter notifications by user preferences - */ - private filterNotificationsByPreferences( - notifications: TimeSafariNotificationType[], - options: NotificationGenerationOptions - ): TimeSafariNotification[] { - if (!this.user) { - return []; - } - - const prefs = this.user.preferences; - const filtered: TimeSafariNotification[] = []; - - for (const notification of notifications) { - // Check if notification type is enabled - if (!this.isNotificationTypeEnabled(notification.type, prefs)) { - continue; - } - - // Check if notification subtype is enabled - if (!this.isNotificationSubtypeEnabled(notification, prefs)) { - continue; - } - - // Check priority filtering - if (options.filterByPriority && !this.meetsPriorityThreshold(notification)) { - continue; - } - - // Apply user preferences - const enhancedNotification: TimeSafariNotification = { - ...notification, - disabled: prefs.frequency.immediate ? false : true, - sound: prefs.sound, - vibration: prefs.vibration, - badge: prefs.badge, - priority: this.mapPriorityFromPreferences(prefs.priority) - }; - - // Add metadata if requested - if (options.includeMetadata) { - enhancedNotification.metadata = { - generatedAt: Date.now(), - platform: 'timesafari', - userDid: this.user.activeDid, - preferencesVersion: 1 - }; - } - - filtered.push(enhancedNotification); - - // Respect max notifications limit - if (filtered.length >= options.maxNotifications) { - break; - } - } - - // Sort by priority and timestamp - filtered.sort((a, b) => { - const priorityOrder: { [key: string]: number } = { high: 3, medium: 2, low: 1 }; - const priorityDiff = priorityOrder[b.notificationPriority] - priorityOrder[a.notificationPriority]; - - if (priorityDiff !== 0) { - return priorityDiff; - } - - return b.timestamp - a.timestamp; - }); - - return filtered; - } - - /** - * Check if notification type is enabled in preferences - */ - private isNotificationTypeEnabled(type: string, prefs: TimeSafariPreferences): boolean { - switch (type) { - case 'offer': - return prefs.notificationTypes.offers; - case 'project': - return prefs.notificationTypes.projects; - case 'person': - return prefs.notificationTypes.people; - case 'item': - return prefs.notificationTypes.items; - default: - return false; - } - } - - /** - * Check if notification subtype is enabled in preferences - */ - private isNotificationSubtypeEnabled( - notification: TimeSafariNotificationType, - prefs: TimeSafariPreferences - ): boolean { - const subtype = notification.subtype; - - switch (notification.type) { - case 'offer': - return (prefs.offerSubtypes as Record)[subtype] || false; - case 'project': - return (prefs.projectSubtypes as Record)[subtype] || false; - case 'person': - return (prefs.peopleSubtypes as Record)[subtype] || false; - case 'item': - return (prefs.itemsSubtypes as Record)[subtype] || false; - default: - return false; - } - } - - /** - * Check if notification meets priority threshold - */ - private meetsPriorityThreshold(notification: TimeSafariNotificationType): boolean { - if (!this.user) return false; - - const requiredPriority = this.user.preferences.priority; - const notificationPriority = notification.notificationPriority; - - const priorityOrder = { high: 3, medium: 2, low: 1 }; - const requiredLevel = priorityOrder[requiredPriority]; - const notificationLevel = priorityOrder[notificationPriority]; - - return notificationLevel >= requiredLevel; - } - - /** - * Map user preference priority to notification priority - */ - private mapPriorityFromPreferences(preferencePriority: 'low' | 'medium' | 'high'): 'low' | 'normal' | 'high' { - switch (preferencePriority) { - case 'low': - return 'low'; - case 'medium': - return 'normal'; - case 'high': - return 'high'; - default: - return 'normal'; - } - } - - /** - * Generate fallback notifications when API fails - */ - private generateFallbackNotifications(): TimeSafariNotification[] { - // Generating fallback notifications - - const fallbackNotifications: TimeSafariNotification[] = [ - { - type: 'offer', - subtype: 'new_to_me', - notificationPriority: 'medium', - timestamp: Date.now(), - disabled: false, - sound: true, - vibration: true, - badge: true, - priority: 'normal', - offer: { - jwtId: 'fallback-offer', - handleId: 'fallback', - issuedAt: new Date().toISOString(), - offeredByDid: 'system', - recipientDid: 'unknown', - unit: 'USD', - amount: 0, - amountGiven: 0, - amountGivenConfirmed: 0, - objectDescription: 'Fallback notification', - validThrough: new Date(Date.now() + 86400000).toISOString(), - fullClaim: {} - }, - metadata: { - generatedAt: Date.now(), - platform: 'timesafari', - fallback: true, - message: 'Unable to fetch real-time updates. Tap to refresh.' - } - } - ]; - - return fallbackNotifications; - } - - /** - * Cache notifications for future use - */ - private cacheNotifications( - notifications: TimeSafariNotificationType[], - timestamp: number - ): void { - if (!this.user) { - throw new Error('User not initialized'); - } - const cacheKey = `notifications_${this.user.activeDid}`; - this.cache.set(cacheKey, { - data: notifications, - timestamp - }); - } - - /** - * Get cached notifications if fresh enough - */ - private getCachedNotifications(): TimeSafariNotificationType[] | null { - if (!this.user) { - throw new Error('User not initialized'); - } - const cacheKey = `notifications_${this.user.activeDid}`; - const cached = this.cache.get(cacheKey); - - if (cached && (Date.now() - cached.timestamp) < 300000) { // 5 minutes - return cached.data; - } - - return null; - } - - /** - * Update user preferences - */ - async updatePreferences(preferences: Partial): Promise { - try { - if (!this.user) { - return false; - } - - this.user.preferences = { ...this.user.preferences, ...preferences }; - - // Clear cache to force refresh with new preferences - this.clearCache(); - - // User preferences updated - return true; - - } catch (error) { - console.error('Error updating preferences:', error); - return false; - } - } - - /** - * Update active DID (for identity changes) - */ - async updateActiveDid(newActiveDid: string): Promise { - try { - // Updating active DID - - // Update security manager - const securityUpdated = await this.securityManager.updateActiveDid(newActiveDid); - if (!securityUpdated) { - console.error('Failed to update security manager'); - return false; - } - - // Generate new JWT token - const token = await this.securityManager.generateJWT({ - scope: 'notifications' - }); - - if (token) { - this.apiClient.setAuthToken(token); - } - - // Clear cache for new identity - this.clearCache(); - - // Update user record - if (this.user) { - this.user.activeDid = newActiveDid; - } - - // Active DID updated successfully - return true; - - } catch (error) { - console.error('Error updating active DID:', error); - return false; - } - } - - /** - * Clear cache - */ - clearCache(): void { - this.cache.clear(); - this.apiClient.clearCache(); - // TimeSafari notification cache cleared - } - - /** - * Get current user configuration - */ - getUser(): TimeSafariUser | undefined { - return this.user; - } - - /** - * Get security manager instance - */ - getSecurityManager(): SecurityManager { - return this.securityManager; - } - - /** - * Get API client instance - */ - getAPIClient(): EndorserAPIClient { - return this.apiClient; - } - - /** - * Check if manager is initialized - */ - isInitialized(): boolean { - return !!this.user && this.securityManager.isInitialized(); - } - - /** - * Reset manager (for user logout/changes) - */ - async reset(): Promise { - try { - await this.securityManager.reset(); - this.clearCache(); - this.user = undefined; - // TimeSafariNotificationManager reset completed - - } catch (error) { - console.error('Error resetting TimeSafariNotificationManager:', error); - } - } - - /** - * Get notification statistics - */ - getStatistics(): { - totalGenerated: number; - cacheSize: number; - activeGenerations: number; - securityOperations: number; - } { - const cacheSize = this.cache.size; - const activeGenerations = this.activeGeneration.size; - const securityOperations = this.securityManager.getOperationHistory().length; - - return { - totalGenerated: 0, // Would track this in real implementation - cacheSize, - activeGenerations, - securityOperations - }; - } -} diff --git a/test-apps/test-api/.gitignore b/test-apps/test-api/.gitignore deleted file mode 100644 index 66cf9ba..0000000 --- a/test-apps/test-api/.gitignore +++ /dev/null @@ -1,152 +0,0 @@ -# Dependencies -node_modules/ -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Coverage directory used by tools like istanbul -coverage/ -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage -.grunt - -# Bower dependency directory -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons -build/Release - -# Dependency directories -jspm_packages/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test -.env.local -.env.production - -# parcel-bundler cache -.cache -.parcel-cache - -# Next.js build output -.next - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -public - -# Storybook build outputs -.out -.storybook-out - -# Temporary folders -tmp/ -temp/ - -# Logs -logs -*.log - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# Grunt intermediate storage -.grunt - -# Bower dependency directory -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env - -# IDE files -.vscode/ -.idea/ -*.swp -*.swo -*~ - -# OS generated files -.DS_Store -.DS_Store? -._* -.Spotlight-V100 -.Trashes -ehthumbs.db -Thumbs.db diff --git a/test-apps/test-api/README.md b/test-apps/test-api/README.md deleted file mode 100644 index 80f666a..0000000 --- a/test-apps/test-api/README.md +++ /dev/null @@ -1,282 +0,0 @@ -# Test API Server - -A mock REST API server for testing the Daily Notification Plugin's network functionality, ETag support, and error handling capabilities. - -## Features - -- **Content Endpoints**: Generate mock notification content for different time slots -- **ETag Support**: Full HTTP caching with conditional requests (304 Not Modified) -- **Error Simulation**: Test various error scenarios (timeout, server error, rate limiting) -- **Metrics**: Monitor API usage and performance -- **CORS Enabled**: Cross-origin requests supported for web testing - -## Quick Start - -```bash -# Install dependencies -npm install - -# Start server -npm start - -# Development mode with auto-restart -npm run dev -``` - -## API Endpoints - -### Health Check -```http -GET /health -``` - -**Response:** -```json -{ - "status": "healthy", - "timestamp": 1703123456789, - "version": "1.0.0", - "endpoints": { - "content": "/api/content/:slotId", - "health": "/health", - "metrics": "/api/metrics", - "error": "/api/error/:type" - } -} -``` - -### Get Notification Content -```http -GET /api/content/:slotId -``` - -**Parameters:** -- `slotId`: Slot identifier in format `slot-HH:MM` (e.g., `slot-08:00`) - -**Headers:** -- `If-None-Match`: ETag for conditional requests - -**Response (200 OK):** -```json -{ - "id": "abc12345", - "slotId": "slot-08:00", - "title": "Daily Update - 08:00", - "body": "Your personalized content for 08:00. Content ID: abc12345", - "timestamp": 1703123456789, - "priority": "high", - "category": "daily", - "actions": [ - { "id": "view", "title": "View Details" }, - { "id": "dismiss", "title": "Dismiss" } - ], - "metadata": { - "source": "test-api", - "version": "1.0.0", - "generated": "2023-12-21T08:00:00.000Z" - } -} -``` - -**Response (304 Not Modified):** -When `If-None-Match` header matches current ETag. - -### Update Content -```http -PUT /api/content/:slotId -``` - -**Body:** -```json -{ - "content": { - "title": "Custom Title", - "body": "Custom body content" - } -} -``` - -### Clear All Content -```http -DELETE /api/content -``` - -### Simulate Errors -```http -GET /api/error/:type -``` - -**Error Types:** -- `timeout` - Simulates request timeout (15 seconds) -- `server-error` - Returns 500 Internal Server Error -- `not-found` - Returns 404 Not Found -- `rate-limit` - Returns 429 Rate Limit Exceeded -- `unauthorized` - Returns 401 Unauthorized - -### API Metrics -```http -GET /api/metrics -``` - -**Response:** -```json -{ - "timestamp": 1703123456789, - "contentStore": { - "size": 5, - "slots": ["slot-08:00", "slot-12:00", "slot-18:00"] - }, - "etagStore": { - "size": 5, - "etags": [["slot-08:00", "\"abc123\""]] - }, - "uptime": 3600, - "memory": { - "rss": 50331648, - "heapTotal": 20971520, - "heapUsed": 15728640, - "external": 1048576 - } -} -``` - -## Usage Examples - -### Basic Content Fetch -```bash -curl http://localhost:3001/api/content/slot-08:00 -``` - -### ETag Conditional Request -```bash -# First request -curl -v http://localhost:3001/api/content/slot-08:00 - -# Second request with ETag (should return 304) -curl -v -H "If-None-Match: \"abc123\"" http://localhost:3001/api/content/slot-08:00 -``` - -### Error Testing -```bash -# Test timeout -curl http://localhost:3001/api/error/timeout - -# Test server error -curl http://localhost:3001/api/error/server-error - -# Test rate limiting -curl http://localhost:3001/api/error/rate-limit -``` - -## Integration with Test Apps - -### Android Test App -```typescript -// In your Android test app -const API_BASE_URL = 'http://10.0.2.2:3001'; // Android emulator localhost - -const fetchContent = async (slotId: string) => { - const response = await fetch(`${API_BASE_URL}/api/content/${slotId}`); - return response.json(); -}; -``` - -### iOS Test App -```typescript -// In your iOS test app -const API_BASE_URL = 'http://localhost:3001'; // iOS simulator localhost - -const fetchContent = async (slotId: string) => { - const response = await fetch(`${API_BASE_URL}/api/content/${slotId}`); - return response.json(); -}; -``` - -### Electron Test App -```typescript -// In your Electron test app -const API_BASE_URL = 'http://localhost:3001'; - -const fetchContent = async (slotId: string) => { - const response = await fetch(`${API_BASE_URL}/api/content/${slotId}`); - return response.json(); -}; -``` - -## Configuration - -### Environment Variables -- `PORT`: Server port (default: 3001) -- `NODE_ENV`: Environment mode (development/production) - -### CORS Configuration -The server is configured to allow cross-origin requests from any origin for testing purposes. - -## Testing Scenarios - -### 1. Basic Content Fetching -- Test successful content retrieval -- Verify content structure and format -- Check timestamp accuracy - -### 2. ETag Caching -- Test conditional requests with `If-None-Match` -- Verify 304 Not Modified responses -- Test cache invalidation - -### 3. Error Handling -- Test timeout scenarios -- Test server error responses -- Test rate limiting behavior -- Test network failure simulation - -### 4. Performance Testing -- Test concurrent requests -- Monitor memory usage -- Test long-running scenarios - -## Development - -### Running in Development Mode -```bash -npm run dev -``` - -This uses `nodemon` for automatic server restart on file changes. - -### Adding New Endpoints -1. Add route handler in `server.js` -2. Update health check endpoint list -3. Add documentation to this README -4. Add test cases if applicable - -### Testing -```bash -npm test -``` - -## Troubleshooting - -### Common Issues - -1. **Port Already in Use** - ```bash - # Kill process using port 3001 - lsof -ti:3001 | xargs kill -9 - ``` - -2. **CORS Issues** - - Server is configured to allow all origins - - Check browser console for CORS errors - -3. **Network Connectivity** - - Android emulator: Use `10.0.2.2` instead of `localhost` - - iOS simulator: Use `localhost` or `127.0.0.1` - - Physical devices: Use your computer's IP address - -### Logs -The server logs all requests with timestamps and response codes for debugging. - -## License - -MIT License - See LICENSE file for details. diff --git a/test-apps/test-api/SETUP.md b/test-apps/test-api/SETUP.md deleted file mode 100644 index 06a6b85..0000000 --- a/test-apps/test-api/SETUP.md +++ /dev/null @@ -1,76 +0,0 @@ -# Test API Server Setup - -## Overview - -The Test API Server provides mock endpoints for testing the Daily Notification Plugin's network functionality, including ETag support, error handling, and content fetching. - -## Quick Setup - -```bash -# Navigate to test-api directory -cd test-apps/test-api - -# Install dependencies -npm install - -# Start server -npm start -``` - -## Integration with Test Apps - -### Update Test App Configuration - -Add the API base URL to your test app configuration: - -```typescript -// In your test app's config -const API_CONFIG = { - baseUrl: 'http://localhost:3001', // Adjust for platform - endpoints: { - content: '/api/content', - health: '/health', - error: '/api/error', - metrics: '/api/metrics' - } -}; -``` - -### Platform-Specific URLs - -- **Web/Electron**: `http://localhost:3001` -- **Android Emulator**: `http://10.0.2.2:3001` -- **iOS Simulator**: `http://localhost:3001` -- **Physical Devices**: `http://[YOUR_IP]:3001` - -## Testing Workflow - -1. **Start API Server**: `npm start` in `test-apps/test-api/` -2. **Start Test App**: Run your platform-specific test app -3. **Test Scenarios**: Use the test app to validate plugin functionality -4. **Monitor API**: Check `/api/metrics` for usage statistics - -## Available Test Scenarios - -### Content Fetching -- Basic content retrieval -- ETag conditional requests -- Content updates and caching - -### Error Handling -- Network timeouts -- Server errors -- Rate limiting -- Authentication failures - -### Performance Testing -- Concurrent requests -- Memory usage monitoring -- Long-running scenarios - -## Next Steps - -1. Start the API server -2. Configure your test apps to use the API -3. Run through the test scenarios -4. Validate plugin functionality across platforms diff --git a/test-apps/test-api/client.ts b/test-apps/test-api/client.ts deleted file mode 100644 index 8842844..0000000 --- a/test-apps/test-api/client.ts +++ /dev/null @@ -1,305 +0,0 @@ -/** - * Test API Client for Daily Notification Plugin - * - * Demonstrates how to integrate with the test API server - * for validating plugin functionality. - * - * @author Matthew Raymer - * @version 1.0.0 - */ - -export interface TestAPIConfig { - baseUrl: string; - timeout: number; -} - -export interface NotificationContent { - id: string; - slotId: string; - title: string; - body: string; - timestamp: number; - priority: string; - category: string; - actions: Array<{ id: string; title: string }>; - metadata: { - source: string; - version: string; - generated: string; - }; -} - -export interface APIResponse { - data?: T; - error?: string; - status: number; - etag?: string; - fromCache: boolean; -} - -export class TestAPIClient { - private config: TestAPIConfig; - private etagCache = new Map(); - - constructor(config: TestAPIConfig) { - this.config = config; - } - - /** - * Fetch notification content for a specific slot - * @param slotId - Slot identifier (e.g., 'slot-08:00') - * @returns Promise> - */ - async fetchContent(slotId: string): Promise> { - const url = `${this.config.baseUrl}/api/content/${slotId}`; - const headers: Record = {}; - - // Add ETag for conditional request if we have cached content - const cachedETag = this.etagCache.get(slotId); - if (cachedETag) { - headers['If-None-Match'] = cachedETag; - } - - try { - const response = await fetch(url, { - method: 'GET', - headers, - signal: AbortSignal.timeout(this.config.timeout) - }); - - const etag = response.headers.get('ETag'); - const fromCache = response.status === 304; - - if (fromCache) { - return { - status: response.status, - fromCache: true, - etag: cachedETag - }; - } - - if (!response.ok) { - throw new Error(`HTTP ${response.status}: ${response.statusText}`); - } - - const data = await response.json(); - - // Cache ETag for future conditional requests - if (etag) { - this.etagCache.set(slotId, etag); - } - - return { - data, - status: response.status, - etag, - fromCache: false - }; - - } catch (error) { - return { - error: error instanceof Error ? error.message : 'Unknown error', - status: 0, - fromCache: false - }; - } - } - - /** - * Test error scenarios - * @param errorType - Type of error to simulate - * @returns Promise> - */ - async testError(errorType: string): Promise> { - const url = `${this.config.baseUrl}/api/error/${errorType}`; - - try { - const response = await fetch(url, { - method: 'GET', - signal: AbortSignal.timeout(this.config.timeout) - }); - - const data = await response.json(); - - return { - data, - status: response.status, - fromCache: false - }; - - } catch (error) { - return { - error: error instanceof Error ? error.message : 'Unknown error', - status: 0, - fromCache: false - }; - } - } - - /** - * Get API health status - * @returns Promise> - */ - async getHealth(): Promise> { - const url = `${this.config.baseUrl}/health`; - - try { - const response = await fetch(url, { - method: 'GET', - signal: AbortSignal.timeout(this.config.timeout) - }); - - const data = await response.json(); - - return { - data, - status: response.status, - fromCache: false - }; - - } catch (error) { - return { - error: error instanceof Error ? error.message : 'Unknown error', - status: 0, - fromCache: false - }; - } - } - - /** - * Get API metrics - * @returns Promise> - */ - async getMetrics(): Promise> { - const url = `${this.config.baseUrl}/api/metrics`; - - try { - const response = await fetch(url, { - method: 'GET', - signal: AbortSignal.timeout(this.config.timeout) - }); - - const data = await response.json(); - - return { - data, - status: response.status, - fromCache: false - }; - - } catch (error) { - return { - error: error instanceof Error ? error.message : 'Unknown error', - status: 0, - fromCache: false - }; - } - } - - /** - * Clear ETag cache - */ - clearCache(): void { - this.etagCache.clear(); - } - - /** - * Get cached ETags - * @returns Map of slotId to ETag - */ - getCachedETags(): Map { - return new Map(this.etagCache); - } -} - -/** - * Platform-specific API configuration - */ -export const getAPIConfig = (): TestAPIConfig => { - // Detect platform and set appropriate base URL - if (typeof window !== 'undefined') { - // Web/Electron - return { - baseUrl: 'http://localhost:3001', - timeout: 12000 // 12 seconds - }; - } - - // Default configuration - return { - baseUrl: 'http://localhost:3001', - timeout: 12000 - }; -}; - -/** - * Usage examples for test apps - */ -export const TestAPIExamples = { - /** - * Basic content fetching example - */ - async basicFetch(): Promise { - const client = new TestAPIClient(getAPIConfig()); - - // console.log('Testing basic content fetch...'); - const result = await client.fetchContent('slot-08:00'); - - if (result.error) { - // console.error('Error:', result.error); - } else { - // console.log('Success:', result.data); - // console.log('ETag:', result.etag); - // console.log('From cache:', result.fromCache); - } - }, - - /** - * ETag caching example - */ - async etagCaching(): Promise { - // const client = new TestAPIClient(getAPIConfig()); - - // console.log('Testing ETag caching...'); - - // First request - // const result1 = await client.fetchContent('slot-08:00'); - // console.log('First request:', result1.fromCache ? 'From cache' : 'Fresh content'); - - // Second request (should be from cache) - // const result2 = await client.fetchContent('slot-08:00'); - // console.log('Second request:', result2.fromCache ? 'From cache' : 'Fresh content'); - }, - - /** - * Error handling example - */ - async errorHandling(): Promise { - // const client = new TestAPIClient(getAPIConfig()); - - // console.log('Testing error handling...'); - - // const errorTypes = ['timeout', 'server-error', 'not-found', 'rate-limit']; - - // for (const errorType of errorTypes) { - // const result = await client.testError(errorType); - // console.log(`${errorType}:`, result.status, result.error || 'Success'); - // } - }, - - /** - * Health check example - */ - async healthCheck(): Promise { - const client = new TestAPIClient(getAPIConfig()); - - // console.log('Testing health check...'); - const result = await client.getHealth(); - - if (result.error) { - // console.error('Health check failed:', result.error); - } else { - // console.log('API is healthy:', result.data); - } - } -}; diff --git a/test-apps/test-api/package-lock.json b/test-apps/test-api/package-lock.json deleted file mode 100644 index 1d0b166..0000000 --- a/test-apps/test-api/package-lock.json +++ /dev/null @@ -1,4799 +0,0 @@ -{ - "name": "daily-notification-test-api", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "daily-notification-test-api", - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "cors": "^2.8.5", - "express": "^4.18.2" - }, - "devDependencies": { - "jest": "^29.7.0", - "node-fetch": "^2.7.0", - "nodemon": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "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/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/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/@babel/core/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/@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-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-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-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-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-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==", - "dev": true, - "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==", - "dev": true, - "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/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==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.4" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "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-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", - "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-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", - "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/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/traverse/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/@babel/traverse/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/@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==", - "dev": true, - "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/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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/console": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", - "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", - "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", - "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "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/@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", - "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "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/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "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/@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/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/node": { - "version": "24.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", - "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.10.0" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.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/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" - }, - "node_modules/babel-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", - "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", - "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5" - }, - "peerDependencies": { - "@babel/core": "^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", - "dev": true, - "license": "MIT", - "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.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/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/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "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/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/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "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/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "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==", - "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/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "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/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/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "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/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", - "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true, - "license": "MIT" - }, - "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/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/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "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/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "license": "MIT" - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "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/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/dedent": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", - "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "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/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "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/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/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "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/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "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/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "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-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/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-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "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/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" - } - }, - "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/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "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/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-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "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-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "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": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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/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/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/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-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/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/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/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true, - "license": "ISC" - }, - "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "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/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==", - "license": "ISC" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "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-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-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-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-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-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "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-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-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/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/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-instrument": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", - "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-instrument/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/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-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps/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/istanbul-lib-source-maps/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/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/jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", - "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/types": "^29.6.3", - "import-local": "^3.0.2", - "jest-cli": "^29.7.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", - "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "execa": "^5.0.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", - "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^1.0.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.7.0", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.7.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", - "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-jest": "^29.7.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", - "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", - "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "jest-util": "^29.7.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", - "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", - "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", - "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", - "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", - "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", - "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", - "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", - "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", - "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/environment": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-leak-detector": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-resolve": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-util": "^29.7.0", - "jest-watcher": "^29.7.0", - "jest-worker": "^29.7.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", - "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/globals": "^29.7.0", - "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", - "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.7.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/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/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", - "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.7.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/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/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/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "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-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/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/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "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/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/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "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/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/make-dir/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/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tmpl": "1.0.5" - } - }, - "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/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "license": "MIT", - "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/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "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": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "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/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/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "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/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true, - "license": "MIT" - }, - "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/nodemon": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", - "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^4", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^7.5.3", - "simple-update-notifier": "^2.0.0", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/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/nodemon/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/nodemon/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/nodemon/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/nodemon/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "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-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "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/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": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "license": "MIT", - "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/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "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-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "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==", - "dev": true, - "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/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true, - "license": "MIT" - }, - "node_modules/pure-rand": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "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": "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/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "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-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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/resolve.exports": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", - "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "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==", - "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/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "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/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/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==", - "license": "MIT" - }, - "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "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==", - "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==", - "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==", - "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==", - "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/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/simple-update-notifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", - "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/simple-update-notifier/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/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "license": "MIT" - }, - "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/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/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "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/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-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "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/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/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/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "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/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/touch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", - "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", - "dev": true, - "license": "ISC", - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true, - "license": "MIT" - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "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/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true, - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", - "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "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/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/v8-to-istanbul": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", - "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "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/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/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": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "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/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "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" - } - } - } -} diff --git a/test-apps/test-api/package.json b/test-apps/test-api/package.json deleted file mode 100644 index 3b08a53..0000000 --- a/test-apps/test-api/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "daily-notification-test-api", - "version": "1.0.0", - "description": "Test API server for Daily Notification Plugin validation", - "main": "server.js", - "scripts": { - "start": "node server.js", - "dev": "nodemon server.js", - "test": "jest", - "demo": "node test-demo.js" - }, - "keywords": [ - "test", - "api", - "notification", - "capacitor", - "plugin" - ], - "author": "Matthew Raymer", - "license": "MIT", - "dependencies": { - "express": "^4.18.2", - "cors": "^2.8.5" - }, - "devDependencies": { - "nodemon": "^3.0.1", - "jest": "^29.7.0", - "node-fetch": "^2.7.0" - }, - "engines": { - "node": ">=18.0.0" - } -} diff --git a/test-apps/test-api/server.js b/test-apps/test-api/server.js deleted file mode 100644 index b6ec268..0000000 --- a/test-apps/test-api/server.js +++ /dev/null @@ -1,535 +0,0 @@ -#!/usr/bin/env node - -/** - * Test API Server for TimeSafari Daily Notification Plugin - * - * Simulates Endorser.ch API endpoints for testing the plugin's - * network fetching, pagination, and TimeSafari-specific functionality. - * - * @author Matthew Raymer - * @version 2.0.0 - */ - -const express = require('express'); -const cors = require('cors'); -const crypto = require('crypto'); - -const app = express(); -const PORT = process.env.PORT || 3001; - -// Phase 4: JWT authentication middleware for testing SecurityManager -function verifyJWT(req, res, next) { - const authHeader = req.headers.authorization; - - if (!authHeader || !authHeader.startsWith('Bearer ')) { - return res.status(401).json({ - error: 'Missing or invalid Authorization header', - expected: 'Bearer ' - }); - } - - const token = authHeader.substring(7); // Remove 'Bearer ' prefix - - // Simple JWT validation for testing (in production, use proper JWT library) - try { - const parts = token.split('.'); - if (parts.length !== 3) { - throw new Error('Invalid JWT format'); - } - - // Decode payload (base64url) - const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString()); - - // Check expiration - if (payload.exp && payload.exp < Math.floor(Date.now() / 1000)) { - return res.status(401).json({ - error: 'JWT token expired', - expiredAt: new Date(payload.exp * 1000).toISOString() - }); - } - - // Add decoded claims to request for use in endpoints - req.jwtClaims = payload; - req.activeDid = payload.iss; // Assuming 'iss' contains the active DID - - console.log(`✅ JWT verified for DID: ${req.activeDid}`); - next(); - - } catch (error) { - console.log(`❌ JWT verification failed: ${error.message}`); - return res.status(401).json({ - error: 'Invalid JWT token', - details: error.message - }); - } -} - -// Middleware -app.use(cors()); -app.use(express.json()); - -// In-memory storage for testing -let contentStore = new Map(); -let etagStore = new Map(); -let offersStore = new Map(); -let projectsStore = new Map(); - -/** - * Generate mock offer data for TimeSafari testing - * @param {string} recipientDid - DID of the recipient - * @param {string} afterId - JWT ID for pagination - * @returns {Object} Mock offer data - */ -function generateMockOffers(recipientDid, afterId) { - const offers = []; - const offerCount = Math.floor(Math.random() * 5) + 1; // 1-5 offers - - for (let i = 0; i < offerCount; i++) { - const jwtId = `01HSE3R9MAC0FT3P3KZ382TWV${7 + i}`; - const handleId = `offer-${crypto.randomUUID().substring(0, 8)}`; - - offers.push({ - jwtId: jwtId, - handleId: handleId, - issuedAt: new Date().toISOString(), - offeredByDid: `did:example:offerer${i + 1}`, - recipientDid: recipientDid, - unit: 'USD', - amount: Math.floor(Math.random() * 5000) + 500, - amountGiven: Math.floor(Math.random() * 2000) + 200, - amountGivenConfirmed: Math.floor(Math.random() * 1000) + 100, - objectDescription: `Community service offer ${i + 1}`, - validThrough: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(), - fullClaim: { - type: 'Offer', - issuer: `did:example:offerer${i + 1}`, - recipient: recipientDid, - object: { - description: `Community service offer ${i + 1}`, - amount: Math.floor(Math.random() * 5000) + 500, - unit: 'USD' - } - } - }); - } - - return { - data: offers, - hitLimit: offers.length >= 3 // Simulate hit limit - }; -} - -/** - * Generate mock project data for TimeSafari testing - * @param {Array} planIds - Array of plan IDs - * @param {string} afterId - JWT ID for pagination - * @returns {Object} Mock project data - */ -function generateMockProjects(planIds, afterId) { - const projects = []; - - planIds.forEach((planId, index) => { - const jwtId = `01HSE3R9MAC0FT3P3KZ382TWV${8 + index}`; - - projects.push({ - plan: { - jwtId: jwtId, - handleId: planId, - name: `Community Project ${index + 1}`, - description: `Description for ${planId}`, - issuerDid: `did:example:issuer${index + 1}`, - agentDid: `did:example:agent${index + 1}`, - startTime: new Date().toISOString(), - endTime: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toISOString(), - locLat: 40.7128 + (Math.random() - 0.5) * 0.1, - locLon: -74.0060 + (Math.random() - 0.5) * 0.1, - url: `https://timesafari.com/projects/${planId}`, - category: 'community', - status: 'active' - }, - wrappedClaimBefore: null // Simulate no previous claim - }); - }); - - return { - data: projects, - hitLimit: projects.length >= 2 // Simulate hit limit - }; -} - -/** - * Generate mock notification bundle for TimeSafari - * @param {Object} params - Request parameters - * @returns {Object} Mock notification bundle - */ -function generateNotificationBundle(params) { - const { userDid, starredPlanIds, lastKnownOfferId, lastKnownPlanId } = params; - - return { - offersToPerson: generateMockOffers(userDid, lastKnownOfferId), - offersToProjects: { - data: [], - hitLimit: false - }, - starredChanges: generateMockProjects(starredPlanIds, lastKnownPlanId), - timestamp: new Date().toISOString(), - bundleId: crypto.randomUUID() - }; -} - -// Routes - -/** - * Health check endpoint - */ -app.get('/health', (req, res) => { - res.json({ - status: 'healthy', - timestamp: Date.now(), - version: '2.0.0', - service: 'TimeSafari Test API', - endpoints: { - health: '/health', - offers: '/api/v2/report/offers', - offersToPlans: '/api/v2/report/offersToPlansOwnedByMe', - plansLastUpdated: '/api/v2/report/plansLastUpdatedBetween', - notificationsBundle: '/api/v2/report/notifications/bundle', - analytics: '/api/analytics/community-events', - metrics: '/api/metrics' - } - }); -}); - -/** - * Endorser.ch API: Get offers to person - * Phase 4: Requires JWT authentication - */ -app.get('/api/v2/report/offers', verifyJWT, (req, res) => { - const { recipientId, afterId } = req.query; - - console.log(`[${new Date().toISOString()}] GET /api/v2/report/offers`); - console.log(` JWT DID: ${req.activeDid}, recipientId: ${recipientId}, afterId: ${afterId || 'none'}`); - - if (!recipientId) { - return res.status(400).json({ - error: 'recipientId parameter is required' - }); - } - - // Phase 4: Validate that JWT DID matches recipientId for security - if (req.activeDid !== recipientId) { - console.log(` ❌ JWT DID mismatch: ${req.activeDid} != ${recipientId}`); - return res.status(403).json({ - error: 'JWT DID does not match recipientId', - jwtDid: req.activeDid, - requestedRecipientId: recipientId - }); - } - - const offers = generateMockOffers(recipientId, afterId); - - console.log(` → 200 OK (${offers.data.length} offers, hitLimit: ${offers.hitLimit})`); - res.json(offers); -}); - -/** - * Endorser.ch API: Get offers to user's projects - * Phase 4: Requires JWT authentication - */ -app.get('/api/v2/report/offersToPlansOwnedByMe', verifyJWT, (req, res) => { - const { afterId } = req.query; - - console.log(`[${new Date().toISOString()}] GET /api/v2/report/offersToPlansOwnedByMe`); - console.log(` JWT DID: ${req.activeDid}, afterId: ${afterId || 'none'}`); - - const offers = { - data: [], // Simulate no offers to user's projects - hitLimit: false - }; - - console.log(` → 200 OK (${offers.data.length} offers, hitLimit: ${offers.hitLimit})`); - res.json(offers); -}); - -/** - * Endorser.ch API: Get changes to starred projects - * Phase 4: Requires JWT authentication - */ -app.post('/api/v2/report/plansLastUpdatedBetween', verifyJWT, (req, res) => { - const { planIds, afterId } = req.body; - - console.log(`[${new Date().toISOString()}] POST /api/v2/report/plansLastUpdatedBetween`); - console.log(` JWT DID: ${req.activeDid}, planIds: ${JSON.stringify(planIds)}, afterId: ${afterId || 'none'}`); - - if (!planIds || !Array.isArray(planIds)) { - return res.status(400).json({ - error: 'planIds array is required' - }); - } - - const projects = generateMockProjects(planIds, afterId); - - console.log(` → 200 OK (${projects.data.length} projects, hitLimit: ${projects.hitLimit})`); - res.json(projects); -}); - -/** - * TimeSafari API: Get notification bundle - */ -app.get('/api/v2/report/notifications/bundle', (req, res) => { - const { userDid, starredPlanIds, lastKnownOfferId, lastKnownPlanId } = req.query; - - console.log(`[${new Date().toISOString()}] GET /api/v2/report/notifications/bundle`); - console.log(` userDid: ${userDid}, starredPlanIds: ${starredPlanIds}`); - - if (!userDid) { - return res.status(400).json({ - error: 'userDid parameter is required' - }); - } - - const bundle = generateNotificationBundle({ - userDid, - starredPlanIds: starredPlanIds ? JSON.parse(starredPlanIds) : [], - lastKnownOfferId, - lastKnownPlanId - }); - - console.log(` → 200 OK (bundle generated)`); - res.json(bundle); -}); - -/** - * TimeSafari Analytics: Community events - */ -app.post('/api/analytics/community-events', (req, res) => { - const { client_id, events } = req.body; - - console.log(`[${new Date().toISOString()}] POST /api/analytics/community-events`); - console.log(` client_id: ${client_id}, events: ${events?.length || 0}`); - - // Simulate analytics processing - res.json({ - status: 'success', - processed: events?.length || 0, - timestamp: new Date().toISOString() - }); -}); - -/** - * Legacy content endpoint (for backward compatibility) - */ -app.get('/api/content/:slotId', (req, res) => { - const { slotId } = req.params; - const ifNoneMatch = req.headers['if-none-match']; - const timestamp = Date.now(); - - console.log(`[${new Date().toISOString()}] GET /api/content/${slotId}`); - console.log(` If-None-Match: ${ifNoneMatch || 'none'}`); - - // Validate slotId format - if (!slotId || !slotId.match(/^slot-\d{2}:\d{2}$/)) { - return res.status(400).json({ - error: 'Invalid slotId format. Expected: slot-HH:MM', - provided: slotId - }); - } - - // Check if we have stored content - const stored = contentStore.get(slotId); - const etag = etagStore.get(slotId); - - if (stored && etag && ifNoneMatch === etag) { - // Content hasn't changed, return 304 Not Modified - console.log(` → 304 Not Modified (ETag match)`); - return res.status(304).end(); - } - - // Generate new content - const content = { - id: crypto.randomUUID().substring(0, 8), - slotId: slotId, - title: `TimeSafari Community Update - ${slotId.split('-')[1]}`, - body: `Your personalized TimeSafari content for ${slotId.split('-')[1]}`, - timestamp: timestamp, - priority: 'high', - category: 'community', - actions: [ - { id: 'view_offers', title: 'View Offers' }, - { id: 'view_projects', title: 'See Projects' }, - { id: 'view_people', title: 'Check People' }, - { id: 'view_items', title: 'Browse Items' }, - { id: 'dismiss', title: 'Dismiss' } - ], - metadata: { - source: 'timesafari-test-api', - version: '2.0.0', - generated: new Date(timestamp).toISOString() - } - }; - - const newEtag = `"${crypto.createHash('md5').update(JSON.stringify(content)).digest('hex')}"`; - - // Store for future ETag checks - contentStore.set(slotId, content); - etagStore.set(slotId, newEtag); - - // Set ETag header - res.set('ETag', newEtag); - res.set('Cache-Control', 'no-cache'); - res.set('Last-Modified', new Date(timestamp).toUTCString()); - - console.log(` → 200 OK (new content, ETag: ${newEtag})`); - res.json(content); -}); - -/** - * API metrics endpoint - */ -app.get('/api/metrics', (req, res) => { - const metrics = { - timestamp: Date.now(), - service: 'TimeSafari Test API', - version: '2.0.0', - contentStore: { - size: contentStore.size, - slots: Array.from(contentStore.keys()) - }, - etagStore: { - size: etagStore.size, - etags: Array.from(etagStore.entries()) - }, - uptime: process.uptime(), - memory: process.memoryUsage(), - endpoints: { - total: 8, - active: 8, - health: '/health', - endorser: { - offers: '/api/v2/report/offers', - offersToPlans: '/api/v2/report/offersToPlansOwnedByMe', - plansLastUpdated: '/api/v2/report/plansLastUpdatedBetween' - }, - timesafari: { - notificationsBundle: '/api/v2/report/notifications/bundle', - analytics: '/api/analytics/community-events' - } - } - }; - - res.json(metrics); -}); - -/** - * Clear stored content (for testing) - */ -app.delete('/api/content', (req, res) => { - contentStore.clear(); - etagStore.clear(); - - res.json({ - message: 'All stored content cleared', - timestamp: Date.now() - }); -}); - -// Error handling middleware -app.use((err, req, res, next) => { - console.error(`[${new Date().toISOString()}] Error:`, err); - res.status(500).json({ - error: 'Internal server error', - message: err.message, - timestamp: Date.now() - }); -}); - -// 404 handler -app.use((req, res) => { - res.status(404).json({ - error: 'Endpoint not found', - path: req.path, - method: req.method, - timestamp: Date.now() - }); -}); - -/** - * Phase 4: JWT validation test endpoint - * Allows testing SecurityManager JWT generation and verification - */ -app.get('/api/v2/test/jwt-validation', verifyJWT, (req, res) => { - console.log(`[${new Date().toISOString()}] GET /api/v2/test/jwt-validation`); - console.log(` JWT DID: ${req.activeDid}`); - - res.json({ - success: true, - message: 'JWT validation successful', - jwtClaims: req.jwtClaims, - activeDid: req.activeDid, - timestamp: new Date().toISOString() - }); -}); - -/** - * Phase 4: Security test endpoint (no auth required) - * For testing SecurityManager initialization - */ -app.get('/api/v2/test/security-info', (req, res) => { - console.log(`[${new Date().toISOString()}] GET /api/v2/test/security-info`); - - res.json({ - securityInfo: { - jwtRequired: true, - supportedAlgorithms: ['HS256', 'ES256K'], - tokenExpiration: '60 minutes', - audience: 'endorser-api', - scope: 'notifications' - }, - testEndpoints: { - jwtValidation: '/api/v2/test/jwt-validation', - offers: '/api/v2/report/offers', - offersToProjects: '/api/v2/report/offersToPlansOwnedByMe', - projectUpdates: '/api/v2/report/plansLastUpdatedBetween' - }, - timestamp: new Date().toISOString() - }); -}); - -// Start server -app.listen(PORT, () => { - console.log(`🚀 TimeSafari Test API Server running on port ${PORT}`); - console.log(`📋 Available endpoints:`); - console.log(` GET /health - Health check`); - console.log(` GET /api/v2/report/offers - Get offers to person (JWT required)`); - console.log(` GET /api/v2/report/offersToPlansOwnedByMe - Get offers to user's projects (JWT required)`); - console.log(` POST /api/v2/report/plansLastUpdatedBetween - Get changes to starred projects (JWT required)`); - console.log(` GET /api/v2/report/notifications/bundle - Get TimeSafari notification bundle`); - console.log(` GET /api/v2/test/jwt-validation - Test JWT validation (JWT required)`); - console.log(` GET /api/v2/test/security-info - Get security configuration info`); - console.log(` POST /api/analytics/community-events - Send community analytics`); - console.log(` GET /api/content/:slotId - Legacy content endpoint`); - console.log(` GET /api/metrics - API metrics`); - console.log(``); - console.log(`🔧 Environment:`); - console.log(` NODE_ENV: ${process.env.NODE_ENV || 'development'}`); - console.log(` PORT: ${PORT}`); - console.log(``); - console.log(`📝 Usage examples:`); - console.log(` curl http://localhost:${PORT}/health`); - console.log(` curl http://localhost:${PORT}/api/v2/test/security-info`); - console.log(` curl -H "Authorization: Bearer " "http://localhost:${PORT}/api/v2/test/jwt-validation"`); - console.log(` curl -H "Authorization: Bearer " "http://localhost:${PORT}/api/v2/report/offers?recipientId=did:example:testuser123&afterId=01HSE3R9MAC0FT3P3KZ382TWV7"`); - console.log(` curl -H "Authorization: Bearer " -X POST http://localhost:${PORT}/api/v2/report/plansLastUpdatedBetween -H "Content-Type: application/json" -d '{"planIds":["plan-123","plan-456"],"afterId":"01HSE3R9MAC0FT3P3KZ382TWV8"}'`); - console.log(` curl "http://localhost:${PORT}/api/v2/report/notifications/bundle?userDid=did:example:testuser123&starredPlanIds=[\"plan-123\",\"plan-456\"]"`); -}); - -// Graceful shutdown -process.on('SIGINT', () => { - console.log('\n🛑 Shutting down TimeSafari Test API Server...'); - process.exit(0); -}); - -process.on('SIGTERM', () => { - console.log('\n🛑 Shutting down TimeSafari Test API Server...'); - process.exit(0); -}); diff --git a/test-apps/test-api/test-demo.js b/test-apps/test-api/test-demo.js deleted file mode 100644 index 2f5fbb4..0000000 --- a/test-apps/test-api/test-demo.js +++ /dev/null @@ -1,294 +0,0 @@ -#!/usr/bin/env node - -/** - * Test API Demo Script - * - * Demonstrates the Test API Server functionality - * and validates all endpoints work correctly. - * - * @author Matthew Raymer - * @version 1.0.0 - */ - -const fetch = require('node-fetch'); - -const API_BASE_URL = 'http://localhost:3001'; - -/** - * Make HTTP request with timeout - * @param {string} url - Request URL - * @param {Object} options - Fetch options - * @returns {Promise} Response data - */ -async function makeRequest(url, options = {}) { - try { - const response = await fetch(url, { - timeout: 10000, - ...options - }); - - const data = await response.json(); - - return { - status: response.status, - data, - headers: Object.fromEntries(response.headers.entries()) - }; - } catch (error) { - return { - status: 0, - error: error.message - }; - } -} - -/** - * Test health endpoint - */ -async function testHealth() { - console.log('🔍 Testing health endpoint...'); - - const result = await makeRequest(`${API_BASE_URL}/health`); - - if (result.error) { - console.error('❌ Health check failed:', result.error); - return false; - } - - console.log('✅ Health check passed'); - console.log(' Status:', result.status); - console.log(' Version:', result.data.version); - console.log(' Endpoints:', Object.keys(result.data.endpoints).length); - - return true; -} - -/** - * Test content fetching - */ -async function testContentFetching() { - console.log('\n📱 Testing content fetching...'); - - const slotId = 'slot-08:00'; - const result = await makeRequest(`${API_BASE_URL}/api/content/${slotId}`); - - if (result.error) { - console.error('❌ Content fetch failed:', result.error); - return false; - } - - console.log('✅ Content fetch passed'); - console.log(' Status:', result.status); - console.log(' Slot ID:', result.data.slotId); - console.log(' Title:', result.data.title); - console.log(' ETag:', result.headers.etag); - - return result.headers.etag; -} - -/** - * Test ETag caching - */ -async function testETagCaching(etag) { - console.log('\n🔄 Testing ETag caching...'); - - const slotId = 'slot-08:00'; - const result = await makeRequest(`${API_BASE_URL}/api/content/${slotId}`, { - headers: { - 'If-None-Match': etag - } - }); - - if (result.error) { - console.error('❌ ETag test failed:', result.error); - return false; - } - - if (result.status === 304) { - console.log('✅ ETag caching works (304 Not Modified)'); - return true; - } else { - console.log('⚠️ ETag caching unexpected response:', result.status); - return false; - } -} - -/** - * Test error scenarios - */ -async function testErrorScenarios() { - console.log('\n🚨 Testing error scenarios...'); - - const errorTypes = ['server-error', 'not-found', 'rate-limit', 'unauthorized']; - let passed = 0; - - for (const errorType of errorTypes) { - const result = await makeRequest(`${API_BASE_URL}/api/error/${errorType}`); - - if (result.error) { - console.log(`❌ ${errorType}: ${result.error}`); - } else { - console.log(`✅ ${errorType}: ${result.status}`); - passed++; - } - } - - console.log(` Passed: ${passed}/${errorTypes.length}`); - return passed === errorTypes.length; -} - -/** - * Test metrics endpoint - */ -async function testMetrics() { - console.log('\n📊 Testing metrics endpoint...'); - - const result = await makeRequest(`${API_BASE_URL}/api/metrics`); - - if (result.error) { - console.error('❌ Metrics test failed:', result.error); - return false; - } - - console.log('✅ Metrics endpoint works'); - console.log(' Content store size:', result.data.contentStore.size); - console.log(' ETag store size:', result.data.etagStore.size); - console.log(' Uptime:', Math.round(result.data.uptime), 'seconds'); - - return true; -} - -/** - * Test content update - */ -async function testContentUpdate() { - console.log('\n✏️ Testing content update...'); - - const slotId = 'slot-08:00'; - const newContent = { - content: { - title: 'Updated Test Title', - body: 'This is updated test content', - timestamp: Date.now() - } - }; - - const result = await makeRequest(`${API_BASE_URL}/api/content/${slotId}`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(newContent) - }); - - if (result.error) { - console.error('❌ Content update failed:', result.error); - return false; - } - - console.log('✅ Content update works'); - console.log(' Status:', result.status); - console.log(' New ETag:', result.data.etag); - - return true; -} - -/** - * Test content clearing - */ -async function testContentClearing() { - console.log('\n🗑️ Testing content clearing...'); - - const result = await makeRequest(`${API_BASE_URL}/api/content`, { - method: 'DELETE' - }); - - if (result.error) { - console.error('❌ Content clearing failed:', result.error); - return false; - } - - console.log('✅ Content clearing works'); - console.log(' Status:', result.status); - - return true; -} - -/** - * Main test runner - */ -async function runTests() { - console.log('🚀 Starting Test API validation...\n'); - - const tests = [ - { name: 'Health Check', fn: testHealth }, - { name: 'Content Fetching', fn: testContentFetching }, - { name: 'ETag Caching', fn: testETagCaching }, - { name: 'Error Scenarios', fn: testErrorScenarios }, - { name: 'Metrics', fn: testMetrics }, - { name: 'Content Update', fn: testContentUpdate }, - { name: 'Content Clearing', fn: testContentClearing } - ]; - - let passed = 0; - let etag = null; - - for (const test of tests) { - try { - if (test.name === 'ETag Caching' && etag) { - const result = await test.fn(etag); - if (result) passed++; - } else { - const result = await test.fn(); - if (result) { - passed++; - if (test.name === 'Content Fetching' && typeof result === 'string') { - etag = result; - } - } - } - } catch (error) { - console.error(`❌ ${test.name} failed with error:`, error.message); - } - } - - console.log(`\n📋 Test Results: ${passed}/${tests.length} passed`); - - if (passed === tests.length) { - console.log('🎉 All tests passed! Test API is working correctly.'); - } else { - console.log('⚠️ Some tests failed. Check the output above for details.'); - } - - console.log('\n💡 Next steps:'); - console.log(' 1. Start your test app'); - console.log(' 2. Configure it to use this API'); - console.log(' 3. Test plugin functionality'); - console.log(' 4. Monitor API metrics at /api/metrics'); -} - -// Check if API server is running -async function checkServer() { - try { - const result = await makeRequest(`${API_BASE_URL}/health`); - if (result.error) { - console.error('❌ Cannot connect to Test API Server'); - console.error(' Make sure the server is running: npm start'); - console.error(' Server should be available at:', API_BASE_URL); - process.exit(1); - } - } catch (error) { - console.error('❌ Cannot connect to Test API Server'); - console.error(' Make sure the server is running: npm start'); - console.error(' Server should be available at:', API_BASE_URL); - process.exit(1); - } -} - -// Run tests -checkServer().then(() => { - runTests().catch(error => { - console.error('❌ Test runner failed:', error.message); - process.exit(1); - }); -}); diff --git a/test-apps/verify-emulator-network.sh b/test-apps/verify-emulator-network.sh deleted file mode 100755 index e2751fd..0000000 --- a/test-apps/verify-emulator-network.sh +++ /dev/null @@ -1,107 +0,0 @@ -#!/bin/bash - -# Android Emulator Network Verification Script -# Diagnoses network connectivity issues that cause ANRs and Play Services failures -# Author: Matthew Raymer - -echo "🔍 Android Emulator Network Verification" -echo "========================================" -echo "" - -# Check if emulator is running -if ! adb devices | grep -q "emulator.*device"; then - echo "❌ Error: No emulator detected!" - echo "Please start an emulator first" - exit 1 -fi - -echo "✅ Emulator detected" -echo "" - -echo "📋 Network Diagnostics:" -echo "" - -echo "1. 🔧 ADB Connection Status:" -adb devices -echo "" - -echo "2. ✈️ Airplane Mode Status:" -AIRPLANE_MODE=$(adb -e shell settings get global airplane_mode_on 2>/dev/null) -if [ "$AIRPLANE_MODE" = "1" ]; then - echo " ❌ Airplane mode is ON - this will block network access" - echo " 💡 Fix: adb -e shell settings put global airplane_mode_on 0" -else - echo " ✅ Airplane mode is OFF" -fi -echo "" - -echo "3. 🌐 Network Interfaces:" -echo " Network interfaces:" -adb -e shell ip addr | grep -E "(inet |UP|DOWN)" | head -10 -echo "" -echo " Routing table:" -adb -e shell ip route | head -5 -echo "" - -echo "4. 🏓 DNS Resolution Tests:" -echo " Testing Google DNS (8.8.8.8):" -if adb -e shell ping -c1 8.8.8.8 >/dev/null 2>&1; then - echo " ✅ Google DNS reachable" -else - echo " ❌ Google DNS unreachable - host/VPN/firewall blocking" -fi - -echo " Testing connectivity check (connectivitycheck.gstatic.com):" -if adb -e shell ping -c1 connectivitycheck.gstatic.com >/dev/null 2>&1; then - echo " ✅ Hostname resolution working" -else - echo " ❌ Hostname resolution failed - DNS issue" -fi -echo "" - -echo "5. 🔍 Play Services Status:" -echo " Google Play Services:" -adb -e shell dumpsys package com.google.android.gms | grep -E "(versionName|enabled)" | head -2 -echo "" - -echo "6. 📊 Network Monitor Logs:" -echo " Recent network errors (last 10 lines):" -adb -e logcat -d | grep -E "(NetworkMonitor|ECONNREFUSED|UnknownHostException)" | tail -5 -echo "" - -echo "🎯 Diagnosis Summary:" -echo "" - -# Determine issue type -if [ "$AIRPLANE_MODE" = "1" ]; then - echo "❌ PRIMARY ISSUE: Airplane mode is ON" - echo " Solution: Turn off airplane mode" -elif ! adb -e shell ping -c1 8.8.8.8 >/dev/null 2>&1; then - echo "❌ PRIMARY ISSUE: No internet connectivity" - echo " Solutions:" - echo " - Check host VPN/killswitch settings" - echo " - Verify firewall rules allow emulator traffic" - echo " - Try: ./launch-emulator-network-fix.sh" -elif ! adb -e shell ping -c1 connectivitycheck.gstatic.com >/dev/null 2>&1; then - echo "❌ PRIMARY ISSUE: DNS resolution failure" - echo " Solutions:" - echo " - Use explicit DNS: -dns-server 8.8.8.8,1.1.1.1" - echo " - Check corporate proxy settings" - echo " - Try: ./launch-emulator-network-fix.sh" -else - echo "✅ Network connectivity appears normal" - echo " If still experiencing ANRs, check Play Services cache:" - echo " adb -e shell pm clear com.google.android.gms" -fi - -echo "" -echo "🔧 Quick Fixes:" -echo " # Clear Play Services cache" -echo " adb -e shell pm clear com.google.android.gms" -echo " adb -e shell pm clear com.android.vending" -echo "" -echo " # Restart ADB" -echo " adb kill-server && adb start-server" -echo "" -echo " # Launch with network fixes" -echo " ./launch-emulator-network-fix.sh"