diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..fb081ea --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +# EditorConfig is awesome: https://EditorConfig.org +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8087038..a49b178 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,9 +2,7 @@ name: Build validation on: push: - branches: [ "main", "develop" ] pull_request: - branches: [ "main", "develop" ] jobs: build: diff --git a/.gitignore b/.gitignore index 4ac371d..5f2e400 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,5 @@ dist-ssr *.sln *.sw? -resources/android/**/* \ No newline at end of file +resources/android/**/* +resources/ios/**/* \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index d827280..b90cbe7 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "com.donetick.app" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 24 - versionName "1.2.2" + versionCode 25 + versionName "1.2.3" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle index 1e82591..739289a 100644 --- a/android/app/capacitor.build.gradle +++ b/android/app/capacitor.build.gradle @@ -13,12 +13,16 @@ dependencies { implementation project(':capacitor-app') implementation project(':capacitor-browser') implementation project(':capacitor-device') + implementation project(':capacitor-local-llm') implementation project(':capacitor-local-notifications') implementation project(':capacitor-network') implementation project(':capacitor-preferences') implementation project(':capacitor-push-notifications') implementation project(':capacitor-status-bar') + implementation project(':capgo-capacitor-document-scanner') + implementation project(':capgo-capacitor-nfc') implementation project(':capgo-capacitor-social-login') + implementation project(':jcesarmobile-capacitor-ocr') implementation project(':revenuecat-purchases-capacitor') implementation project(':revenuecat-purchases-capacitor-ui') implementation project(':capacitor-plugin-safe-area') diff --git a/android/app/release/output-metadata.json b/android/app/release/output-metadata.json new file mode 100644 index 0000000..0683b46 --- /dev/null +++ b/android/app/release/output-metadata.json @@ -0,0 +1,37 @@ +{ + "version": 3, + "artifactType": { + "type": "APK", + "kind": "Directory" + }, + "applicationId": "com.donetick.app", + "variantName": "release", + "elements": [ + { + "type": "SINGLE", + "filters": [], + "attributes": [], + "versionCode": 20, + "versionName": "1.0.20", + "outputFile": "app-release.apk" + } + ], + "elementType": "File", + "baselineProfiles": [ + { + "minApi": 28, + "maxApi": 30, + "baselineProfiles": [ + "baselineProfiles/1/app-release.dm" + ] + }, + { + "minApi": 31, + "maxApi": 2147483647, + "baselineProfiles": [ + "baselineProfiles/0/app-release.dm" + ] + } + ], + "minSdkVersionForDexing": 24 +} \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 837d403..76aa59f 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -9,7 +9,7 @@ android:theme="@style/AppTheme" android:usesCleartextTraffic="true"> - + + + + + + + + + + + + + + @@ -43,6 +60,8 @@ + + diff --git a/android/app/src/main/java/com/donetick/app/MainActivity.java b/android/app/src/main/java/com/donetick/app/MainActivity.java index 0b70e1f..283dc35 100644 --- a/android/app/src/main/java/com/donetick/app/MainActivity.java +++ b/android/app/src/main/java/com/donetick/app/MainActivity.java @@ -2,4 +2,36 @@ package com.donetick.app; import com.getcapacitor.BridgeActivity; -public class MainActivity extends BridgeActivity {} +import ee.forgr.capacitor.social.login.GoogleProvider; +import ee.forgr.capacitor.social.login.SocialLoginPlugin; +import ee.forgr.capacitor.social.login.ModifiedMainActivityForSocialLoginPlugin; +import com.getcapacitor.PluginHandle; +import com.getcapacitor.Plugin; +import android.content.Intent; +import android.util.Log; + + + public class MainActivity extends BridgeActivity implements ModifiedMainActivityForSocialLoginPlugin { + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode >= GoogleProvider.REQUEST_AUTHORIZE_GOOGLE_MIN && requestCode < GoogleProvider.REQUEST_AUTHORIZE_GOOGLE_MAX) { + PluginHandle pluginHandle = getBridge().getPlugin("SocialLogin"); + if (pluginHandle == null) { + Log.i("Google Activity Result", "SocialLogin login handle is null"); + return; + } + Plugin plugin = pluginHandle.getInstance(); + if (!(plugin instanceof SocialLoginPlugin)) { + Log.i("Google Activity Result", "SocialLogin plugin instance is not SocialLoginPlugin"); + return; + } + ((SocialLoginPlugin) plugin).handleGoogleLoginIntent(requestCode, data); + } + } + + @Override + public void IHaveModifiedTheMainActivityForTheUseWithSocialLoginPlugin() {} + } \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 85a5dda..97e6322 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -7,8 +7,8 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.2.1' - classpath 'com.google.gms:google-services:4.4.0' + classpath 'com.android.tools.build:gradle:8.10.1' + 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 diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle index 3ad1593..a50983d 100644 --- a/android/capacitor.settings.gradle +++ b/android/capacitor.settings.gradle @@ -14,6 +14,9 @@ project(':capacitor-browser').projectDir = new File('../node_modules/@capacitor/ include ':capacitor-device' project(':capacitor-device').projectDir = new File('../node_modules/@capacitor/device/android') +include ':capacitor-local-llm' +project(':capacitor-local-llm').projectDir = new File('../node_modules/@capacitor/local-llm/android') + include ':capacitor-local-notifications' project(':capacitor-local-notifications').projectDir = new File('../node_modules/@capacitor/local-notifications/android') @@ -29,9 +32,18 @@ project(':capacitor-push-notifications').projectDir = new File('../node_modules/ include ':capacitor-status-bar' project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android') +include ':capgo-capacitor-document-scanner' +project(':capgo-capacitor-document-scanner').projectDir = new File('../node_modules/@capgo/capacitor-document-scanner/android') + +include ':capgo-capacitor-nfc' +project(':capgo-capacitor-nfc').projectDir = new File('../node_modules/@capgo/capacitor-nfc/android') + include ':capgo-capacitor-social-login' project(':capgo-capacitor-social-login').projectDir = new File('../node_modules/@capgo/capacitor-social-login/android') +include ':jcesarmobile-capacitor-ocr' +project(':jcesarmobile-capacitor-ocr').projectDir = new File('../node_modules/@jcesarmobile/capacitor-ocr/android') + include ':revenuecat-purchases-capacitor' project(':revenuecat-purchases-capacitor').projectDir = new File('../node_modules/@revenuecat/purchases-capacitor/android') diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index c747538..37f853b 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/android/variables.gradle b/android/variables.gradle index 9930199..753826f 100644 --- a/android/variables.gradle +++ b/android/variables.gradle @@ -1,16 +1,17 @@ ext { - minSdkVersion = 24 - compileSdkVersion = 35 - targetSdkVersion = 35 - androidxActivityVersion = '1.9.2' - androidxAppCompatVersion = '1.7.0' - androidxCoordinatorLayoutVersion = '1.2.0' - androidxCoreVersion = '1.12.0' - androidxFragmentVersion = '1.6.2' + minSdkVersion = 28 + compileSdkVersion = 36 + targetSdkVersion = 36 + androidxActivityVersion = '1.11.0' + androidxAppCompatVersion = '1.7.1' + androidxCoordinatorLayoutVersion = '1.3.0' + androidxCoreVersion = '1.17.0' + androidxFragmentVersion = '1.8.9' coreSplashScreenVersion = '1.0.1' - androidxWebkitVersion = '1.9.0' + androidxWebkitVersion = '1.14.0' junitVersion = '4.13.2' - androidxJunitVersion = '1.1.5' - androidxEspressoCoreVersion = '3.5.1' + androidxJunitVersion = '1.3.0' + androidxEspressoCoreVersion = '3.7.0' cordovaAndroidVersion = '10.1.1' -} \ No newline at end of file + firebaseMessagingVersion = '24.1.0' +} diff --git a/capacitor.config.ts b/capacitor.config.ts index 751d712..a585c19 100644 --- a/capacitor.config.ts +++ b/capacitor.config.ts @@ -1,4 +1,4 @@ -import type { CapacitorConfig } from '@capacitor/cli'; +import type { CapacitorConfig } from '@capacitor/cli' const config: CapacitorConfig = { appId: 'com.donetick.app', @@ -12,17 +12,17 @@ const config: CapacitorConfig = { presentationOptions: ['badge', 'sound', 'alert'], }, LocalNotifications: { - smallIcon: "ic_stat_icon_config_sample", - iconColor: "#488AFF", - sound: "beep.wav", + smallIcon: 'ic_stat_icon_config_sample', + iconColor: '#488AFF', + sound: 'beep.wav', }, - GoogleAuth: { - scopes: ['profile', 'email', 'openid'], - clientId: process.env.VITE_APP_GOOGLE_CLIENT_ID, - androidClientId: process.env.VITE_APP_ANDRIOD_CLIENT_ID, - iosClientId: process.env.VITE_APP_IOS_CLIENT_ID, + // GoogleAuth: { + // scopes: ['profile', 'email', 'openid'], + // clientId: process.env.VITE_APP_GOOGLE_CLIENT_ID, + // androidClientId: process.env.VITE_APP_ANDRIOD_CLIENT_ID, + // iosClientId: process.env.VITE_APP_IOS_CLIENT_ID, + // }, }, } -}; -export default config; +export default config diff --git a/index.html b/index.html index f4fbd0e..93cec0b 100644 --- a/index.html +++ b/index.html @@ -3,8 +3,13 @@ - + + Donetick + diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index 150692e..9230fec 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; }; 504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; }; 50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; }; + 72FA9293C4A649D1BA0E5917 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 71866EB277374608AD02C137 /* PrivacyInfo.xcprivacy */; }; A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; }; D1115B492C653D60004C6043 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = D1115B482C653D60004C6043 /* GoogleService-Info.plist */; }; /* End PBXBuildFile section */ @@ -28,6 +29,7 @@ 504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = ""; }; + 71866EB277374608AD02C137 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; }; AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = ""; }; D1115B482C653D60004C6043 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; @@ -62,6 +64,7 @@ 504EC3051FED79650016851F /* Products */, 7F8756D8B27F46E3366F6CEA /* Pods */, 27E2DDA53C4D2A4D1A88CE4A /* Frameworks */, + 71866EB277374608AD02C137 /* PrivacyInfo.xcprivacy */, ); sourceTree = ""; }; @@ -127,8 +130,8 @@ 504EC2FC1FED79650016851F /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 0920; + LastSwiftUpdateCheck = 920; + LastUpgradeCheck = 920; TargetAttributes = { 504EC3031FED79650016851F = { CreatedOnToolsVersion = 9.2; @@ -169,6 +172,7 @@ 504EC30D1FED79650016851F /* Main.storyboard in Resources */, 2FAD9763203C412B000D30F8 /* config.xml in Resources */, D1115B492C653D60004C6043 /* GoogleService-Info.plist in Resources */, + 72FA9293C4A649D1BA0E5917 /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -289,7 +293,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -340,7 +344,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -355,13 +359,13 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = App/App.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 24; + CURRENT_PROJECT_VERSION = 25; DEVELOPMENT_TEAM = 6UJJ78R3BS; INFOPLIST_FILE = App/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.donetick.app; - MARKETING_VERSION = 1.2.2; + MARKETING_VERSION = 1.2.3; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -375,12 +379,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = App/App.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 24; + CURRENT_PROJECT_VERSION = 25; DEVELOPMENT_TEAM = 6UJJ78R3BS; INFOPLIST_FILE = App/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 1.2.2; + MARKETING_VERSION = 1.2.3; PRODUCT_BUNDLE_IDENTIFIER = com.donetick.app; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; diff --git a/ios/App/App/App.entitlements b/ios/App/App/App.entitlements index 80b5221..17cd619 100644 --- a/ios/App/App/App.entitlements +++ b/ios/App/App/App.entitlements @@ -2,6 +2,10 @@ + com.apple.developer.nfc.readersession.formats + + TAG + aps-environment development com.apple.developer.applesignin diff --git a/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png b/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png index adf6ba0..83c8ed6 100644 Binary files a/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png and b/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png differ diff --git a/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json index 9b7d382..b1a8483 100644 --- a/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,14 +1,14 @@ { - "images" : [ + "images": [ { - "filename" : "AppIcon-512@2x.png", - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" + "idiom": "universal", + "size": "1024x1024", + "filename": "AppIcon-512@2x.png", + "platform": "ios" } ], - "info" : { - "author" : "xcode", - "version" : 1 + "info": { + "author": "xcode", + "version": 1 } -} +} \ No newline at end of file diff --git a/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json b/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json index d7d96a6..84a416d 100644 --- a/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json +++ b/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json @@ -1,23 +1,56 @@ { - "images" : [ + "images": [ { - "idiom" : "universal", - "filename" : "splash-2732x2732-2.png", - "scale" : "1x" + "idiom": "universal", + "filename": "Default@1x~universal~anyany.png", + "scale": "1x" }, { - "idiom" : "universal", - "filename" : "splash-2732x2732-1.png", - "scale" : "2x" + "idiom": "universal", + "filename": "Default@2x~universal~anyany.png", + "scale": "2x" }, { - "idiom" : "universal", - "filename" : "splash-2732x2732.png", - "scale" : "3x" + "idiom": "universal", + "filename": "Default@3x~universal~anyany.png", + "scale": "3x" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "idiom": "universal", + "scale": "1x", + "filename": "Default@1x~universal~anyany-dark.png" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "idiom": "universal", + "scale": "2x", + "filename": "Default@2x~universal~anyany-dark.png" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "idiom": "universal", + "scale": "3x", + "filename": "Default@3x~universal~anyany-dark.png" } ], - "info" : { - "version" : 1, - "author" : "xcode" + "info": { + "version": 1, + "author": "xcode" } } \ No newline at end of file diff --git a/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany-dark.png b/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany-dark.png new file mode 100644 index 0000000..3ae9f3f Binary files /dev/null and b/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany-dark.png differ diff --git a/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany.png b/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany.png new file mode 100644 index 0000000..2f9ccb6 Binary files /dev/null and b/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany.png differ diff --git a/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany-dark.png b/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany-dark.png new file mode 100644 index 0000000..3ae9f3f Binary files /dev/null and b/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany-dark.png differ diff --git a/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany.png b/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany.png new file mode 100644 index 0000000..2f9ccb6 Binary files /dev/null and b/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany.png differ diff --git a/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany-dark.png b/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany-dark.png new file mode 100644 index 0000000..3ae9f3f Binary files /dev/null and b/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany-dark.png differ diff --git a/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany.png b/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany.png new file mode 100644 index 0000000..2f9ccb6 Binary files /dev/null and b/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany.png differ diff --git a/ios/App/App/Info.plist b/ios/App/App/Info.plist index 3d7ef1e..5a58712 100644 --- a/ios/App/App/Info.plist +++ b/ios/App/App/Info.plist @@ -2,10 +2,12 @@ + NFCReaderUsageDescription + Donetick uses NFC to read and write chore tags for quick task completion. CFBundleDevelopmentRegion en CFBundleDisplayName - DoneTick + Donetick CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -18,10 +20,27 @@ APPL CFBundleShortVersionString $(MARKETING_VERSION) + CFBundleURLTypes + + + CFBundleURLSchemes + + com.googleusercontent.apps.682262497914-5dacpk46qcc1494lood6ch8ul9c83kop + + + CFBundleVersion $(CURRENT_PROJECT_VERSION) LSRequiresIPhoneOS + NSCameraUsageDescription + This app needs access to camera to take photos to attach to task or use as profile photo + NSPhotoLibraryUsageDescription + This app needs access to photo library to select images to attach to task or use as profile photo + UIBackgroundModes + + UILaunchStoryboardName + LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities @@ -30,6 +49,7 @@ UISupportedInterfaceOrientations + UIInterfaceOrientationPortrait UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight @@ -54,9 +74,5 @@ - NSCameraUsageDescription - This app needs access to camera to take photos to attach to task or use as profile photo - NSPhotoLibraryUsageDescription - This app needs access to photo library to select images to attach to task or use as profile photo - \ No newline at end of file + diff --git a/ios/App/Podfile b/ios/App/Podfile index 9602381..e5d54c4 100644 --- a/ios/App/Podfile +++ b/ios/App/Podfile @@ -20,6 +20,7 @@ def capacitor_pods pod 'CapacitorPreferences', :path => '../../node_modules/@capacitor/preferences' pod 'CapacitorPushNotifications', :path => '../../node_modules/@capacitor/push-notifications' pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar' + pod 'CapgoCapacitorNfc', :path => '../../node_modules/@capgo/capacitor-nfc' pod 'CapgoCapacitorSocialLogin', :path => '../../node_modules/@capgo/capacitor-social-login' pod 'RevenuecatPurchasesCapacitor', :path => '../../node_modules/@revenuecat/purchases-capacitor' pod 'RevenuecatPurchasesCapacitorUi', :path => '../../node_modules/@revenuecat/purchases-capacitor-ui' diff --git a/ios/App/Podfile.lock b/ios/App/Podfile.lock index f304ddb..7ef206d 100644 --- a/ios/App/Podfile.lock +++ b/ios/App/Podfile.lock @@ -1,68 +1,76 @@ PODS: - Alamofire (5.10.2) - - AppAuth (2.0.0): - - AppAuth/Core (= 2.0.0) - - AppAuth/ExternalUserAgent (= 2.0.0) - - AppAuth/Core (2.0.0) - - AppAuth/ExternalUserAgent (2.0.0): + - AppAuth (2.1.0): + - AppAuth/Core (= 2.1.0) + - AppAuth/ExternalUserAgent (= 2.1.0) + - AppAuth/Core (2.1.0) + - AppAuth/ExternalUserAgent (2.1.0): - AppAuth/Core - - AppCheckCore (11.2.0): + - AppCheckCore (11.3.0): - GoogleUtilities/Environment (~> 8.0) - GoogleUtilities/UserDefaults (~> 8.0) - PromisesObjC (~> 2.4) - - Capacitor (7.4.3): + - PromisesSwift (~> 2.4) + - RecaptchaInterop (~> 101.0) + - Capacitor (8.4.1): - CapacitorCordova - - CapacitorApp (7.0.2): + - CapacitorApp (8.1.0): - Capacitor - - CapacitorBrowser (7.0.2): + - CapacitorBrowser (8.0.3): - Capacitor - - CapacitorCommunitySqlite (7.0.1): + - CapacitorCommunitySqlite (8.1.0): - Capacitor - SQLCipher - ZIPFoundation - - CapacitorCordova (7.4.3) - - CapacitorDevice (7.0.2): + - CapacitorCordova (8.4.1) + - CapacitorDevice (8.0.2): - Capacitor - - CapacitorLocalNotifications (7.0.2): + - CapacitorLocalLlm (1.0.0): - Capacitor - - CapacitorNetwork (7.0.2): + - CapacitorLocalNotifications (8.2.0): - Capacitor - - CapacitorPluginSafeArea (4.0.0): + - CapacitorNetwork (8.0.1): - Capacitor - - CapacitorPreferences (7.0.2): + - CapacitorPluginSafeArea (5.0.0): - Capacitor - - CapacitorPushNotifications (7.0.2): + - CapacitorPreferences (8.0.1): - Capacitor - - CapacitorStatusBar (7.0.2): + - CapacitorPushNotifications (8.1.1): - Capacitor - - CapgoCapacitorSocialLogin (7.11.2): + - CapacitorStatusBar (8.0.2): + - Capacitor + - CapgoCapacitorDocumentScanner (8.4.0): + - Capacitor + - CapgoCapacitorNfc (8.1.7): + - Capacitor + - CapgoCapacitorSocialLogin (8.3.34): - Alamofire (~> 5.10.2) - Capacitor - - FBSDKCoreKit (= 18.0.0) - - FBSDKLoginKit (= 18.0.0) + - FBSDKCoreKit (~> 18.0) + - FBSDKLoginKit (~> 18.0) - GoogleSignIn (~> 9.0.0) - - FBAEMKit (18.0.0): - - FBSDKCoreKit_Basics (= 18.0.0) - - FBSDKCoreKit (18.0.0): - - FBAEMKit (= 18.0.0) - - FBSDKCoreKit_Basics (= 18.0.0) - - FBSDKCoreKit_Basics (18.0.0) - - FBSDKLoginKit (18.0.0): - - FBSDKCoreKit (= 18.0.0) - - FirebaseCore (12.3.0): - - FirebaseCoreInternal (~> 12.3.0) + - FBAEMKit (18.1.0): + - FBSDKCoreKit_Basics (= 18.1.0) + - FBSDKCoreKit (18.1.0): + - FBAEMKit (= 18.1.0) + - FBSDKCoreKit_Basics (= 18.1.0) + - FBSDKCoreKit_Basics (18.1.0) + - FBSDKLoginKit (18.1.0): + - FBSDKCoreKit (= 18.1.0) + - FirebaseCore (12.15.0): + - FirebaseCoreInternal (~> 12.15.0) - GoogleUtilities/Environment (~> 8.1) - GoogleUtilities/Logger (~> 8.1) - - FirebaseCoreInternal (12.3.0): + - FirebaseCoreInternal (12.15.0): - "GoogleUtilities/NSData+zlib (~> 8.1)" - - FirebaseInstallations (12.3.0): - - FirebaseCore (~> 12.3.0) + - FirebaseInstallations (12.15.0): + - FirebaseCore (~> 12.15.0) - GoogleUtilities/Environment (~> 8.1) - GoogleUtilities/UserDefaults (~> 8.1) - PromisesObjC (~> 2.4) - - FirebaseMessaging (12.3.0): - - FirebaseCore (~> 12.3.0) - - FirebaseInstallations (~> 12.3.0) + - FirebaseMessaging (12.15.0): + - FirebaseCore (~> 12.15.0) + - FirebaseInstallations (~> 12.15.0) - GoogleDataTransport (~> 10.1) - GoogleUtilities/AppDelegateSwizzler (~> 8.1) - GoogleUtilities/Environment (~> 8.1) @@ -77,60 +85,65 @@ PODS: - AppCheckCore (~> 11.0) - GTMAppAuth (~> 5.0) - GTMSessionFetcher/Core (~> 3.3) - - GoogleUtilities/AppDelegateSwizzler (8.1.0): + - GoogleUtilities/AppDelegateSwizzler (8.1.2): - GoogleUtilities/Environment - GoogleUtilities/Logger - GoogleUtilities/Network - GoogleUtilities/Privacy - - GoogleUtilities/Environment (8.1.0): + - GoogleUtilities/Environment (8.1.2): - GoogleUtilities/Privacy - - GoogleUtilities/Logger (8.1.0): + - GoogleUtilities/Logger (8.1.2): - GoogleUtilities/Environment - GoogleUtilities/Privacy - - GoogleUtilities/Network (8.1.0): + - GoogleUtilities/Network (8.1.2): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" - GoogleUtilities/Privacy - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (8.1.0)": + - "GoogleUtilities/NSData+zlib (8.1.2)": - GoogleUtilities/Privacy - - GoogleUtilities/Privacy (8.1.0) - - GoogleUtilities/Reachability (8.1.0): + - GoogleUtilities/Privacy (8.1.2) + - GoogleUtilities/Reachability (8.1.2): - GoogleUtilities/Logger - GoogleUtilities/Privacy - - GoogleUtilities/UserDefaults (8.1.0): + - GoogleUtilities/UserDefaults (8.1.2): - GoogleUtilities/Logger - GoogleUtilities/Privacy - GTMAppAuth (5.0.0): - AppAuth/Core (~> 2.0) - GTMSessionFetcher/Core (< 4.0, >= 3.3) - GTMSessionFetcher/Core (3.5.0) + - JcesarmobileCapacitorOcr (0.3.0): + - Capacitor - nanopb (3.30910.0): - nanopb/decode (= 3.30910.0) - nanopb/encode (= 3.30910.0) - nanopb/decode (3.30910.0) - nanopb/encode (3.30910.0) - - PromisesObjC (2.4.0) - - PurchasesHybridCommon (17.0.0): - - RevenueCat (= 5.35.1) - - PurchasesHybridCommonUI (17.0.0): - - PurchasesHybridCommon (= 17.0.0) - - RevenueCatUI (= 5.35.1) - - RevenueCat (5.35.1) - - RevenuecatPurchasesCapacitor (11.1.2): + - PromisesObjC (2.4.1) + - PromisesSwift (2.4.1): + - PromisesObjC (= 2.4.1) + - PurchasesHybridCommon (17.55.1): + - RevenueCat (= 5.67.1) + - PurchasesHybridCommonUI (17.55.1): + - PurchasesHybridCommon (= 17.55.1) + - RevenueCatUI (= 5.67.1) + - RecaptchaInterop (101.0.0) + - RevenueCat (5.67.1) + - RevenuecatPurchasesCapacitor (12.3.2): - Capacitor - - PurchasesHybridCommon (= 17.0.0) - - RevenuecatPurchasesCapacitorUi (11.1.2): + - PurchasesHybridCommon (= 17.55.1) + - RevenuecatPurchasesCapacitorUi (12.3.2): - Capacitor - - PurchasesHybridCommonUI (= 17.0.0) - - RevenueCatUI (5.35.1): - - RevenueCat (= 5.35.1) + - PurchasesHybridCommonUI (= 17.55.1) + - RevenueCatUI (5.67.1): + - RevenueCat (= 5.67.1) - SQLCipher (4.10.0): - SQLCipher/standard (= 4.10.0) - SQLCipher/common (4.10.0) - SQLCipher/standard (4.10.0): - SQLCipher/common - - ZIPFoundation (0.9.19) + - ZIPFoundation (0.9.20) DEPENDENCIES: - "Capacitor (from `../../node_modules/@capacitor/ios`)" @@ -139,14 +152,18 @@ DEPENDENCIES: - "CapacitorCommunitySqlite (from `../../node_modules/@capacitor-community/sqlite`)" - "CapacitorCordova (from `../../node_modules/@capacitor/ios`)" - "CapacitorDevice (from `../../node_modules/@capacitor/device`)" + - "CapacitorLocalLlm (from `../../node_modules/@capacitor/local-llm`)" - "CapacitorLocalNotifications (from `../../node_modules/@capacitor/local-notifications`)" - "CapacitorNetwork (from `../../node_modules/@capacitor/network`)" - CapacitorPluginSafeArea (from `../../node_modules/capacitor-plugin-safe-area`) - "CapacitorPreferences (from `../../node_modules/@capacitor/preferences`)" - "CapacitorPushNotifications (from `../../node_modules/@capacitor/push-notifications`)" - "CapacitorStatusBar (from `../../node_modules/@capacitor/status-bar`)" + - "CapgoCapacitorDocumentScanner (from `../../node_modules/@capgo/capacitor-document-scanner`)" + - "CapgoCapacitorNfc (from `../../node_modules/@capgo/capacitor-nfc`)" - "CapgoCapacitorSocialLogin (from `../../node_modules/@capgo/capacitor-social-login`)" - FirebaseMessaging + - "JcesarmobileCapacitorOcr (from `../../node_modules/@jcesarmobile/capacitor-ocr`)" - "RevenuecatPurchasesCapacitor (from `../../node_modules/@revenuecat/purchases-capacitor`)" - "RevenuecatPurchasesCapacitorUi (from `../../node_modules/@revenuecat/purchases-capacitor-ui`)" @@ -170,8 +187,10 @@ SPEC REPOS: - GTMSessionFetcher - nanopb - PromisesObjC + - PromisesSwift - PurchasesHybridCommon - PurchasesHybridCommonUI + - RecaptchaInterop - RevenueCat - RevenueCatUI - SQLCipher @@ -190,6 +209,8 @@ EXTERNAL SOURCES: :path: "../../node_modules/@capacitor/ios" CapacitorDevice: :path: "../../node_modules/@capacitor/device" + CapacitorLocalLlm: + :path: "../../node_modules/@capacitor/local-llm" CapacitorLocalNotifications: :path: "../../node_modules/@capacitor/local-notifications" CapacitorNetwork: @@ -202,8 +223,14 @@ EXTERNAL SOURCES: :path: "../../node_modules/@capacitor/push-notifications" CapacitorStatusBar: :path: "../../node_modules/@capacitor/status-bar" + CapgoCapacitorDocumentScanner: + :path: "../../node_modules/@capgo/capacitor-document-scanner" + CapgoCapacitorNfc: + :path: "../../node_modules/@capgo/capacitor-nfc" CapgoCapacitorSocialLogin: :path: "../../node_modules/@capgo/capacitor-social-login" + JcesarmobileCapacitorOcr: + :path: "../../node_modules/@jcesarmobile/capacitor-ocr" RevenuecatPurchasesCapacitor: :path: "../../node_modules/@revenuecat/purchases-capacitor" RevenuecatPurchasesCapacitorUi: @@ -211,45 +238,51 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496 - AppAuth: 1c1a8afa7e12f2ec3a294d9882dfa5ab7d3cb063 - AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f - Capacitor: 28d6c01026a9a3f7156529498ec1f389a2a28dbc - CapacitorApp: 1f6922c9c5c8b1c538d7fbe92ebe44a81b34bed3 - CapacitorBrowser: 22541e48442de44dc629c214388290d6eecc6ae9 - CapacitorCommunitySqlite: 8b2c6bab33e3519280811d481f8bd0fa90343e1b - CapacitorCordova: 435121e81a2df4d0034f0fb11fcefab5104cfdb5 - CapacitorDevice: 81ae78d5d1942707caad79276badd458bf6ec603 - CapacitorLocalNotifications: 665188ae8accd40806129073896fb2b39322d858 - CapacitorNetwork: 695069886b3c5ed514db69aa3d026b8dc3c03a6b - CapacitorPluginSafeArea: 22031c3436269ca80fac90ec2c94bc7c1e59a81d - CapacitorPreferences: 65107ed7437d96ee72583df5763985e3c0ff2bc2 - CapacitorPushNotifications: 7c0659b349b149ee3936a682da31a9d269de9582 - CapacitorStatusBar: e04d05e121d5a5979c29eb4249186a4e4a84cacb - CapgoCapacitorSocialLogin: a320106e1d032da88576cf8b31a336e971f5acad - FBAEMKit: e34530df538b8eb8aeb53c35867715ba6c63ef0c - FBSDKCoreKit: d3f479a69127acebb1c6aad91c1a33907bcf6c2f - FBSDKCoreKit_Basics: 017b6dc2a1862024815a8229e75661e627ac1e29 - FBSDKLoginKit: 5875762d1fe09ddcb05d03365d4f5dc34413843d - FirebaseCore: ff47fe1ad3ab9ef66edd3e8bc4647b493d2067f8 - FirebaseCoreInternal: a9e1ff270f217489d9258563b693d11a312903bf - FirebaseInstallations: ca48ec60ea51b66b9f214a91847ea3720cde97f5 - FirebaseMessaging: 919ce76cb353f0c36d463f5461d8ab584e6ed765 + AppAuth: ef4da5a3fc2e10b90c09a0a94a9baeaedc0341d5 + AppCheckCore: 214137f5c378d1dec88a68425c467fe65aaff637 + Capacitor: 35242afe195b1e53c58ca1b827d1b444c5e6602b + CapacitorApp: 449ffe26375e96f8aaaee625ac6e01e5c57c8650 + CapacitorBrowser: c987c73d09d8bd3b5ec13f06338b1e14d5d2be69 + CapacitorCommunitySqlite: eac6acfb852f46e7988fc59604d7f900498d354e + CapacitorCordova: eebe6bcf807b1b06f3f48237650f96bbcd0eef09 + CapacitorDevice: 14cba6f88d1c3074cbf825fea977c8c526453ff8 + CapacitorLocalLlm: a05516151a02923a9e7dae9949d3817e85e321f0 + CapacitorLocalNotifications: 2615aa008f608b95d3921a778ee1988abf1e6148 + CapacitorNetwork: 8812ce60d11fb63d8f2e4ba51a49b2e59892ebe2 + CapacitorPluginSafeArea: 9d0682951c011bf0b36e513a89103c5fbff7ac49 + CapacitorPreferences: cca2021f386efb75947c850334447d9ff22b14f1 + CapacitorPushNotifications: ec08d589c226a2c0db7c032ec1bf5b044ec85f8e + CapacitorStatusBar: 01d5763b4ed720de5ce2edbc938de6a98f4c8f32 + CapgoCapacitorDocumentScanner: 7ad9e8ed9c054d551bfc948660d995b9545723d8 + CapgoCapacitorNfc: 5bf5a951ca231d7c40f1ac20549d2abcd1b8f939 + CapgoCapacitorSocialLogin: b0e67630b9d9b5f14fff774c825c1b8fa85eff7b + FBAEMKit: 64088ff0380f50e4a56e2ee07d984f7f1aef7595 + FBSDKCoreKit: 8390ea3a8fac186f444275f31d7512e760b47cba + FBSDKCoreKit_Basics: 3a0005c78b355388bf2df5c6dbe6381b77ea4be3 + FBSDKLoginKit: d8e2711a3a03b0026703735c8d28a2b5a0e1f4fd + FirebaseCore: 2e86a4ea1684d4381707069e4a6d89ac808e901e + FirebaseCoreInternal: 6ab6a02c94446c026d2cf35cf5383842ebaa4992 + FirebaseInstallations: eb29ccbf64eaedf86fd5b2ccc7fabde567660b52 + FirebaseMessaging: 40017d7bc8457ee295b0f41d480a80fdabc9994e GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleSignIn: c7f09cfbc85a1abf69187be091997c317cc33b77 - GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 + GoogleUtilities: 766ace00c6b10d8148408f329d10c4f051931850 GTMAppAuth: 217a876b249c3c585a54fd6f73e6b58c4f5c4238 GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6 + JcesarmobileCapacitorOcr: d3668e104d7ad8968a9d00fd4766e18fea0fe305 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 - PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 - PurchasesHybridCommon: 34d2f73712f4c02f2963fcfb62d43757a9136860 - PurchasesHybridCommonUI: 16e162423c0010f9a6f2c1d6505dcc075f49dcbe - RevenueCat: 47d52620419dcf3dce4e724eade9d390e16ab4b0 - RevenuecatPurchasesCapacitor: 51cd81cec7db693a2552b45c36261d849e1cf574 - RevenuecatPurchasesCapacitorUi: 267758d61aba42a0a3f035e6ba3c4630112357e4 - RevenueCatUI: 3c72ef61b54c3f4787afab6a3b0f00cbec192063 + PromisesObjC: 752c3227f599e3467650e47ea36f433eeb10c273 + PromisesSwift: 217dea0fd5d2ad65222a109c48698add13cc1c5b + PurchasesHybridCommon: ecd9d7c586287625f1225b8de5e24c1021502270 + PurchasesHybridCommonUI: 3056a3d261529f6adb8f74ecc3ab7f1cc0d3fab4 + RecaptchaInterop: 11e0b637842dfb48308d242afc3f448062325aba + RevenueCat: 9357239a9f0978285e68983637b8a602e65c94f0 + RevenuecatPurchasesCapacitor: c299be01b1a5c1d5eb118c30eadc84160944ecf2 + RevenuecatPurchasesCapacitorUi: dc2ec0d97638ebe4ac0078452f5c212b1525ea1c + RevenueCatUI: 6f9291da540f98baf405b5bdfc46b2d5547b704a SQLCipher: eb79c64049cb002b4e9fcb30edb7979bf4706dfc - ZIPFoundation: b8c29ea7ae353b309bc810586181fd073cb3312c + ZIPFoundation: dfd3d681c4053ff7e2f7350bc4e53b5dba3f5351 -PODFILE CHECKSUM: bb6dcef70c8edc058fe3ba311f08a223fd7dbc66 +PODFILE CHECKSUM: 21b805bdbbb6ac4b8a3527ee8ef346ba0a55ef65 COCOAPODS: 1.16.2 diff --git a/ios/App/PrivacyInfo.xcprivacy b/ios/App/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..8bc1948 --- /dev/null +++ b/ios/App/PrivacyInfo.xcprivacy @@ -0,0 +1,29 @@ + + + + + NSPrivacyTracking + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryDiskSpace + NSPrivacyAccessedAPITypeReasons + + 85F4.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + NSPrivacyCollectedDataTypes + + + \ No newline at end of file diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..e69de29 diff --git a/package-lock.json b/package-lock.json index d0703be..bc249e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "donetick", - "version": "1.2.0", + "version": "1.2.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "donetick", - "version": "1.2.0", + "version": "1.2.3", "dependencies": { "@capacitor-community/sqlite": "^7.0.0", "@capacitor/android": "^7.0.0", @@ -15,11 +15,14 @@ "@capacitor/core": "^7.0.0", "@capacitor/device": "^7.0.0", "@capacitor/ios": "^7.0.0", + "@capacitor/local-llm": "^1.0.0", "@capacitor/local-notifications": "^7.0.0", "@capacitor/network": "^7.0.1", "@capacitor/preferences": "^7.0.0", "@capacitor/push-notifications": "^7.0.0", "@capacitor/status-bar": "^7.0.0", + "@capgo/capacitor-document-scanner": "^8.4.0", + "@capgo/capacitor-nfc": "^7.2.0", "@capgo/capacitor-social-login": "^7.5.3", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", @@ -27,6 +30,7 @@ "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@hello-pangea/dnd": "^18.0.1", + "@jcesarmobile/capacitor-ocr": "^0.3.0", "@meauxt/react-swipeable-list": "^1.0.0", "@mui/icons-material": "^5.16.13", "@mui/joy": "^5.0.0-beta.20", @@ -65,6 +69,7 @@ "reactjs-social-login": "^2.6.3", "recharts": "^2.15.0", "reusify": "^1.0.4", + "tesseract.js": "^7.0.0", "vite-plugin-pwa": "^0.20.0" }, "devDependencies": { @@ -77,6 +82,7 @@ "@vitejs/plugin-react-swc": "^3.5.0", "autoprefixer": "^10.4.16", "baseline-browser-mapping": "^2.9.19", + "capacitor-set-version": "^2.2.0", "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.2", @@ -123,7 +129,7 @@ }, "node_modules/@antfu/utils": { "version": "0.7.10", - "devOptional": true, + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/antfu" @@ -150,8 +156,6 @@ }, "node_modules/@babel/core": { "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", - "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -463,8 +467,6 @@ }, "node_modules/@babel/helpers": { "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.3.tgz", - "integrity": "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==", "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", @@ -1412,8 +1414,6 @@ }, "node_modules/@babel/runtime": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", - "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1449,8 +1449,6 @@ }, "node_modules/@babel/types": { "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", - "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -1462,7 +1460,7 @@ }, "node_modules/@canvas/image-data": { "version": "1.0.0", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@capacitor-community/sqlite": { @@ -1480,8 +1478,6 @@ }, "node_modules/@capacitor-community/sqlite/node_modules/@rollup/rollup-darwin-arm64": { "version": "4.34.9", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz", - "integrity": "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==", "cpu": [ "arm64" ], @@ -1511,6 +1507,9 @@ "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1524,6 +1523,9 @@ "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1537,6 +1539,9 @@ "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1550,6 +1555,9 @@ "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1584,8 +1592,6 @@ }, "node_modules/@capacitor-community/sqlite/node_modules/@stencil/core": { "version": "4.36.3", - "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.36.3.tgz", - "integrity": "sha512-C9DOaAjm+hSYRuVoUuYWG/lrYT8+4DG0AL0m1Ea9+G5v2Y6ApVpNJLbXvFlRZIdDMGecH86s6v0Gp39uockLxg==", "license": "MIT", "bin": { "stencil": "bin/stencil" @@ -1607,8 +1613,6 @@ }, "node_modules/@capacitor-community/sqlite/node_modules/jeep-sqlite": { "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jeep-sqlite/-/jeep-sqlite-2.8.0.tgz", - "integrity": "sha512-FWNUP6OAmrUHwiW7H1xH5YUQ8tN2O4l4psT1sLd7DQtHd5PfrA1nvNdeKPNj+wQBtu7elJa8WoUibTytNTaaCg==", "license": "MIT", "dependencies": { "@stencil/core": "^4.20.0", @@ -1620,8 +1624,6 @@ }, "node_modules/@capacitor-community/sqlite/node_modules/sql.js": { "version": "1.13.0", - "resolved": "https://registry.npmjs.org/sql.js/-/sql.js-1.13.0.tgz", - "integrity": "sha512-RJbVP1HRDlUUXahJ7VMTcu9Rm1Nzw+EBpoPr94vnbD4LwR715F3CcxE2G2k45PewcaZ57pjetYa+LoSJLAASgA==", "license": "MIT" }, "node_modules/@capacitor/android": { @@ -1958,8 +1960,6 @@ }, "node_modules/@capacitor/cli/node_modules/xml2js": { "version": "0.6.2", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", - "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", "dev": true, "license": "MIT", "dependencies": { @@ -1972,8 +1972,6 @@ }, "node_modules/@capacitor/cli/node_modules/xmlbuilder": { "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": { @@ -2001,6 +1999,13 @@ "@capacitor/core": "^7.4.0" } }, + "node_modules/@capacitor/local-llm": { + "version": "1.0.0", + "license": "MIT", + "peerDependencies": { + "@capacitor/core": ">=8.0.0" + } + }, "node_modules/@capacitor/local-notifications": { "version": "7.0.2", "license": "MIT", @@ -2036,6 +2041,22 @@ "@capacitor/core": ">=7.0.0" } }, + "node_modules/@capgo/capacitor-document-scanner": { + "version": "8.4.0", + "license": "MPL-2.0", + "peerDependencies": { + "@capacitor/core": ">=8.0.0" + } + }, + "node_modules/@capgo/capacitor-nfc": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@capgo/capacitor-nfc/-/capacitor-nfc-7.2.0.tgz", + "integrity": "sha512-lYMlogAlUG3j1HmieOdFan4SNOnTbTvZ7BMYQmyhnfU9810aip9oPh6CYVXO/2ecZXW03ATTmSKtr4Ci8DpW2Q==", + "license": "MPL-2.0", + "peerDependencies": { + "@capacitor/core": ">=7.0.0" + } + }, "node_modules/@capgo/capacitor-social-login": { "version": "7.11.2", "license": "MIT", @@ -2228,6 +2249,380 @@ "version": "0.4.0", "license": "MIT" }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.8.0", "dev": true, @@ -2644,6 +3039,13 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/@jcesarmobile/capacitor-ocr": { + "version": "0.3.0", + "license": "MIT", + "peerDependencies": { + "@capacitor/core": ">=8.0.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "license": "MIT", @@ -2681,8 +3083,6 @@ }, "node_modules/@meauxt/react-swipeable-list": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@meauxt/react-swipeable-list/-/react-swipeable-list-1.0.0.tgz", - "integrity": "sha512-LhcGbX9otSfm788p0I43Q4keKNsvl/hbFhVszEpI8f4+EyyU9+Gc6Sn6HajVUCX4Enh4Wk1G1DDrmA2+HnpB/A==", "license": "MIT" }, "node_modules/@medv/finder": { @@ -2691,9 +3091,6 @@ }, "node_modules/@mui/base": { "version": "5.0.0-beta.40-1", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40-1.tgz", - "integrity": "sha512-agKXuNNy0bHUmeU7pNmoZwNFr7Hiyhojkb9+2PVyDG5+6RafYuyMgbrav8CndsB7KUc/U51JAw9vKNDLYBzaUA==", - "deprecated": "This package has been replaced by @base-ui-components/react", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", @@ -2732,8 +3129,6 @@ }, "node_modules/@mui/icons-material": { "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.18.0.tgz", - "integrity": "sha512-1s0vEZj5XFXDMmz3Arl/R7IncFqJ+WQ95LDp1roHWGDE2oCO3IS4/hmiOv1/8SD9r6B7tv9GLiqVZYHo+6PkTg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9" @@ -2758,8 +3153,6 @@ }, "node_modules/@mui/joy": { "version": "5.0.0-beta.52", - "resolved": "https://registry.npmjs.org/@mui/joy/-/joy-5.0.0-beta.52.tgz", - "integrity": "sha512-e8jQanA5M1f/X52mJrw0UIW8Er7EAHuLuigmGFw7yIsAgIluhIP4rZ7JcbVrUi6z5Gk0weC9QWUUtjLejAbO8g==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", @@ -2799,8 +3192,6 @@ }, "node_modules/@mui/material": { "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.18.0.tgz", - "integrity": "sha512-bbH/HaJZpFtXGvWg3TsBWG4eyt3gah3E7nCNU8GLyRjVoWcA91Vm/T+sjHfUcwgJSw9iLtucfHBoq+qW/T30aA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", @@ -2900,8 +3291,6 @@ }, "node_modules/@mui/system": { "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.18.0.tgz", - "integrity": "sha512-ojZGVcRWqWhu557cdO3pWHloIGJdzVtxs3rk0F9L+x55LsUjcMUVkEhiF7E4TMxZoF9MmIHGGs0ZX3FDLAf0Xw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", @@ -2952,8 +3341,6 @@ }, "node_modules/@mui/utils": { "version": "5.17.1", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.17.1.tgz", - "integrity": "sha512-jEZ8FTqInt2WzxDV8bhImWBqeQRD99c/id/fq83H0ER9tFl+sfZlaAoCdznGvbSQQ9ividMxqSV2c7cC1vBcQg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", @@ -3023,6 +3410,811 @@ "node": ">= 8" } }, + "node_modules/@oclif/color": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@oclif/color/-/color-1.0.13.tgz", + "integrity": "sha512-/2WZxKCNjeHlQogCs1VBtJWlPXjwWke/9gMrwsVsrUt00g2V6LUBvwgwrxhrXepjOmq4IZ5QeNbpDMEOUlx/JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.2.1", + "chalk": "^4.1.0", + "strip-ansi": "^6.0.1", + "supports-color": "^8.1.1", + "tslib": "^2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@oclif/color/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/@oclif/core": { + "version": "1.26.2", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-1.26.2.tgz", + "integrity": "sha512-6jYuZgXvHfOIc9GIaS4T3CIKGTjPmfAxuMcbCbMRKJJl4aq/4xeRlEz0E8/hz8HxvxZBGvN2GwAUHlrGWQVrVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oclif/linewrap": "^1.0.0", + "@oclif/screen": "^3.0.4", + "ansi-escapes": "^4.3.2", + "ansi-styles": "^4.3.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.2", + "clean-stack": "^3.0.1", + "cli-progress": "^3.10.0", + "debug": "^4.3.4", + "ejs": "^3.1.6", + "fs-extra": "^9.1.0", + "get-package-type": "^0.1.0", + "globby": "^11.1.0", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.14.1", + "natural-orderby": "^2.0.3", + "object-treeify": "^1.1.33", + "password-prompt": "^1.1.2", + "semver": "^7.3.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "supports-color": "^8.1.1", + "supports-hyperlinks": "^2.2.0", + "tslib": "^2.4.1", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oclif/core/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/@oclif/core/node_modules/clean-stack": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", + "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@oclif/core/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@oclif/core/node_modules/js-yaml": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.0.tgz", + "integrity": "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@oclif/core/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/@oclif/linewrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@oclif/linewrap/-/linewrap-1.0.0.tgz", + "integrity": "sha512-Ups2dShK52xXa8w6iBWLgcjPJWjais6KPJQq3gQ/88AY6BXoTX+MIGFPrWQO1KLMiQfoTpcLnUwloN4brrVUHw==", + "dev": true, + "license": "ISC" + }, + "node_modules/@oclif/plugin-autocomplete": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@oclif/plugin-autocomplete/-/plugin-autocomplete-1.4.6.tgz", + "integrity": "sha512-dawJk8Eb5dxsHTEttKZIOJkJ9PPKB59hL8BrqdCkr+WB4Xerm3G6rNeGWErOVYcOLe8y+nWAeYUE8OHNPn2E9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oclif/core": "^2.1.2", + "chalk": "^4.1.0", + "debug": "^4.3.4", + "fs-extra": "^9.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@oclif/plugin-autocomplete/node_modules/@oclif/core": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-2.16.0.tgz", + "integrity": "sha512-dL6atBH0zCZl1A1IXCKJgLPrM/wR7K+Wi401E/IvqsK8m2iCHW+0TEOGrans/cuN3oTW+uxIyJFHJ8Im0k4qBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cli-progress": "^3.11.0", + "ansi-escapes": "^4.3.2", + "ansi-styles": "^4.3.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.2", + "clean-stack": "^3.0.1", + "cli-progress": "^3.12.0", + "debug": "^4.3.4", + "ejs": "^3.1.8", + "get-package-type": "^0.1.0", + "globby": "^11.1.0", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.14.1", + "natural-orderby": "^2.0.3", + "object-treeify": "^1.1.33", + "password-prompt": "^1.1.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "supports-color": "^8.1.1", + "supports-hyperlinks": "^2.2.0", + "ts-node": "^10.9.1", + "tslib": "^2.5.0", + "widest-line": "^3.1.0", + "wordwrap": "^1.0.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oclif/plugin-autocomplete/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/@oclif/plugin-autocomplete/node_modules/clean-stack": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", + "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@oclif/plugin-autocomplete/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@oclif/plugin-autocomplete/node_modules/js-yaml": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.0.tgz", + "integrity": "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@oclif/plugin-autocomplete/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/@oclif/plugin-commands": { + "version": "2.2.28", + "resolved": "https://registry.npmjs.org/@oclif/plugin-commands/-/plugin-commands-2.2.28.tgz", + "integrity": "sha512-w1vQ6WGltMnyjJnnt6Vo/VVtyhz1V0O9McCy0qKIY+os7SunjnUMRNS/y8MZ7b6AjMSdbLGV9/VAYSlWyQg9SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oclif/core": "^2.15.0", + "lodash": "^4.17.11" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@oclif/plugin-commands/node_modules/@oclif/core": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-2.16.0.tgz", + "integrity": "sha512-dL6atBH0zCZl1A1IXCKJgLPrM/wR7K+Wi401E/IvqsK8m2iCHW+0TEOGrans/cuN3oTW+uxIyJFHJ8Im0k4qBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cli-progress": "^3.11.0", + "ansi-escapes": "^4.3.2", + "ansi-styles": "^4.3.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.2", + "clean-stack": "^3.0.1", + "cli-progress": "^3.12.0", + "debug": "^4.3.4", + "ejs": "^3.1.8", + "get-package-type": "^0.1.0", + "globby": "^11.1.0", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.14.1", + "natural-orderby": "^2.0.3", + "object-treeify": "^1.1.33", + "password-prompt": "^1.1.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "supports-color": "^8.1.1", + "supports-hyperlinks": "^2.2.0", + "ts-node": "^10.9.1", + "tslib": "^2.5.0", + "widest-line": "^3.1.0", + "wordwrap": "^1.0.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oclif/plugin-commands/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/@oclif/plugin-commands/node_modules/clean-stack": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", + "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@oclif/plugin-commands/node_modules/js-yaml": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.0.tgz", + "integrity": "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@oclif/plugin-commands/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/@oclif/plugin-help": { + "version": "5.2.20", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-5.2.20.tgz", + "integrity": "sha512-u+GXX/KAGL9S10LxAwNUaWdzbEBARJ92ogmM7g3gDVud2HioCmvWQCDohNRVZ9GYV9oKwZ/M8xwd6a1d95rEKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oclif/core": "^2.15.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@oclif/plugin-help/node_modules/@oclif/core": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-2.16.0.tgz", + "integrity": "sha512-dL6atBH0zCZl1A1IXCKJgLPrM/wR7K+Wi401E/IvqsK8m2iCHW+0TEOGrans/cuN3oTW+uxIyJFHJ8Im0k4qBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cli-progress": "^3.11.0", + "ansi-escapes": "^4.3.2", + "ansi-styles": "^4.3.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.2", + "clean-stack": "^3.0.1", + "cli-progress": "^3.12.0", + "debug": "^4.3.4", + "ejs": "^3.1.8", + "get-package-type": "^0.1.0", + "globby": "^11.1.0", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.14.1", + "natural-orderby": "^2.0.3", + "object-treeify": "^1.1.33", + "password-prompt": "^1.1.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "supports-color": "^8.1.1", + "supports-hyperlinks": "^2.2.0", + "ts-node": "^10.9.1", + "tslib": "^2.5.0", + "widest-line": "^3.1.0", + "wordwrap": "^1.0.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oclif/plugin-help/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/@oclif/plugin-help/node_modules/clean-stack": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", + "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@oclif/plugin-help/node_modules/js-yaml": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.0.tgz", + "integrity": "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@oclif/plugin-help/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/@oclif/plugin-plugins": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/@oclif/plugin-plugins/-/plugin-plugins-2.4.7.tgz", + "integrity": "sha512-6fzUDLWrSK7n6+EBrEekEEYrYTCneRoOF9TzojkjuFn1+ailvUlr98G90bblxKOyy8fqMe7QjvqwTgIDQ9ZIzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oclif/color": "^1.0.4", + "@oclif/core": "^2.8.2", + "chalk": "^4.1.2", + "debug": "^4.3.4", + "fs-extra": "^9.0", + "http-call": "^5.2.2", + "load-json-file": "^5.3.0", + "npm-run-path": "^4.0.1", + "semver": "^7.5.0", + "tslib": "^2.4.1", + "yarn": "^1.22.18" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@oclif/plugin-plugins/node_modules/@oclif/core": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-2.16.0.tgz", + "integrity": "sha512-dL6atBH0zCZl1A1IXCKJgLPrM/wR7K+Wi401E/IvqsK8m2iCHW+0TEOGrans/cuN3oTW+uxIyJFHJ8Im0k4qBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cli-progress": "^3.11.0", + "ansi-escapes": "^4.3.2", + "ansi-styles": "^4.3.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.2", + "clean-stack": "^3.0.1", + "cli-progress": "^3.12.0", + "debug": "^4.3.4", + "ejs": "^3.1.8", + "get-package-type": "^0.1.0", + "globby": "^11.1.0", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.14.1", + "natural-orderby": "^2.0.3", + "object-treeify": "^1.1.33", + "password-prompt": "^1.1.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "supports-color": "^8.1.1", + "supports-hyperlinks": "^2.2.0", + "ts-node": "^10.9.1", + "tslib": "^2.5.0", + "widest-line": "^3.1.0", + "wordwrap": "^1.0.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oclif/plugin-plugins/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/@oclif/plugin-plugins/node_modules/clean-stack": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", + "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@oclif/plugin-plugins/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@oclif/plugin-plugins/node_modules/js-yaml": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.0.tgz", + "integrity": "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@oclif/plugin-plugins/node_modules/load-json-file": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", + "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.15", + "parse-json": "^4.0.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@oclif/plugin-plugins/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@oclif/plugin-plugins/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@oclif/plugin-plugins/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/@oclif/plugin-plugins/node_modules/type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=6" + } + }, + "node_modules/@oclif/plugin-version": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/@oclif/plugin-version/-/plugin-version-1.3.10.tgz", + "integrity": "sha512-TiRZALUcv4hwGTPoTyA3nOWtRew9DT4Ge1FeYx16xnuAsWryvJe3IHXmCm6b1VYhzTJhV2XH5U1DqllrQB2YaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oclif/core": "^2.15.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oclif/plugin-version/node_modules/@oclif/core": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-2.16.0.tgz", + "integrity": "sha512-dL6atBH0zCZl1A1IXCKJgLPrM/wR7K+Wi401E/IvqsK8m2iCHW+0TEOGrans/cuN3oTW+uxIyJFHJ8Im0k4qBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cli-progress": "^3.11.0", + "ansi-escapes": "^4.3.2", + "ansi-styles": "^4.3.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.2", + "clean-stack": "^3.0.1", + "cli-progress": "^3.12.0", + "debug": "^4.3.4", + "ejs": "^3.1.8", + "get-package-type": "^0.1.0", + "globby": "^11.1.0", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.14.1", + "natural-orderby": "^2.0.3", + "object-treeify": "^1.1.33", + "password-prompt": "^1.1.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "supports-color": "^8.1.1", + "supports-hyperlinks": "^2.2.0", + "ts-node": "^10.9.1", + "tslib": "^2.5.0", + "widest-line": "^3.1.0", + "wordwrap": "^1.0.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oclif/plugin-version/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/@oclif/plugin-version/node_modules/clean-stack": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", + "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@oclif/plugin-version/node_modules/js-yaml": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.0.tgz", + "integrity": "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@oclif/plugin-version/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/@oclif/screen": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@oclif/screen/-/screen-3.0.8.tgz", + "integrity": "sha512-yx6KAqlt3TAHBduS2fMQtJDL2ufIHnDRArrJEOoTTuizxqmjLT+psGYOHpmMl3gvQpFJ11Hs76guUUktzAF9Bg==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@openreplay/network-proxy": { "version": "1.2.0", "license": "MIT" @@ -3194,19 +4386,241 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@rollup/rollup-darwin-arm64": { + "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.0.tgz", - "integrity": "sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg==", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.0.tgz", + "integrity": "sha512-lVgpeQyy4fWN5QYebtW4buT/4kn4p4IJ+kDNB4uYNT5b8c8DLJDg6titg20NIg7E8RWwdWZORW6vUFfrLyG3KQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.0.tgz", + "integrity": "sha512-2O73dR4Dc9bp+wSYhviP6sDziurB5/HCym7xILKifWdE9UsOe2FtNcM+I4xZjKrfLJnq5UR8k9riB87gauiQtw==", "cpu": [ "arm64" ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.50.0", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ] }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.0.tgz", + "integrity": "sha512-cQp/WG8HE7BCGyFVuzUg0FNmupxC+EPZEwWu2FCGGw5WDT1o2/YlENbm5e9SMvfDFR6FRhVCBePLqj0o8MN7Vw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.0.tgz", + "integrity": "sha512-UR1uTJFU/p801DvvBbtDD7z9mQL8J80xB0bR7DqW7UGQHRm/OaKzp4is7sQSdbt2pjjSS72eAtRh43hNduTnnQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.0.tgz", + "integrity": "sha512-G/DKyS6PK0dD0+VEzH/6n/hWDNPDZSMBmqsElWnCRGrYOb2jC0VSupp7UAHHQ4+QILwkxSMaYIbQ72dktp8pKA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.0.tgz", + "integrity": "sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.0.tgz", + "integrity": "sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.0.tgz", + "integrity": "sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.0.tgz", + "integrity": "sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.0.tgz", + "integrity": "sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.0.tgz", + "integrity": "sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.0.tgz", + "integrity": "sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.0.tgz", + "integrity": "sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.0.tgz", + "integrity": "sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.50.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.0.tgz", @@ -3214,12 +4628,89 @@ "cpu": [ "x64" ], + "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" ] }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.0.tgz", + "integrity": "sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.0.tgz", + "integrity": "sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.0.tgz", + "integrity": "sha512-q7cIIdFvWQoaCbLDUyUc8YfR3Jh2xx3unO8Dn6/TTogKjfwrax9SyfmGGK6cQhKtjePI7jRfd7iRYcxYs93esg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.0.tgz", + "integrity": "sha512-XzNOVg/YnDOmFdDKcxxK410PrcbcqZkBmz+0FicpW5jtjKQxcW1BZJEQOF0NJa6JO7CZhett8GEtRN/wYLYJuw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.0.tgz", + "integrity": "sha512-xMmiWRR8sp72Zqwjgtf3QbZfF1wdh8X2ABu3EaozvZcyHJeU0r+XAnXdKgs4cCAp6ORoYoCygipYP1mjmbjrsg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@swc/core": { "version": "1.13.5", "hasInstallScript": true, @@ -3258,8 +4749,6 @@ }, "node_modules/@swc/core-darwin-arm64": { "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.13.5.tgz", - "integrity": "sha512-lKNv7SujeXvKn16gvQqUQI5DdyY8v7xcoO3k06/FJbHJS90zEwZdQiMNRiqpYw/orU543tPaWgz7cIYWhbopiQ==", "cpu": [ "arm64" ], @@ -3272,23 +4761,7 @@ "node": ">=10" } }, - "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.13.5.tgz", - "integrity": "sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core/node_modules/@swc/core-darwin-x64": { + "node_modules/@swc/core-darwin-x64": { "version": "1.13.5", "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.13.5.tgz", "integrity": "sha512-ILd38Fg/w23vHb0yVjlWvQBoE37ZJTdlLHa8LRCFDdX4WKfnVBiblsCU9ar4QTMNdeTBEX9iUF4IrbNWhaF1Ng==", @@ -3304,7 +4777,7 @@ "node": ">=10" } }, - "node_modules/@swc/core/node_modules/@swc/core-linux-arm-gnueabihf": { + "node_modules/@swc/core-linux-arm-gnueabihf": { "version": "1.13.5", "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.13.5.tgz", "integrity": "sha512-Q6eS3Pt8GLkXxqz9TAw+AUk9HpVJt8Uzm54MvPsqp2yuGmY0/sNaPPNVqctCX9fu/Nu8eaWUen0si6iEiCsazQ==", @@ -3320,13 +4793,16 @@ "node": ">=10" } }, - "node_modules/@swc/core/node_modules/@swc/core-linux-arm64-gnu": { + "node_modules/@swc/core-linux-arm64-gnu": { "version": "1.13.5", "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.13.5.tgz", "integrity": "sha512-aNDfeN+9af+y+M2MYfxCzCy/VDq7Z5YIbMqRI739o8Ganz6ST+27kjQFd8Y/57JN/hcnUEa9xqdS3XY7WaVtSw==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -3336,13 +4812,16 @@ "node": ">=10" } }, - "node_modules/@swc/core/node_modules/@swc/core-linux-arm64-musl": { + "node_modules/@swc/core-linux-arm64-musl": { "version": "1.13.5", "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.13.5.tgz", "integrity": "sha512-9+ZxFN5GJag4CnYnq6apKTnnezpfJhCumyz0504/JbHLo+Ue+ZtJnf3RhyA9W9TINtLE0bC4hKpWi8ZKoETyOQ==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -3352,13 +4831,35 @@ "node": ">=10" } }, - "node_modules/@swc/core/node_modules/@swc/core-linux-x64-musl": { + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.13.5.tgz", + "integrity": "sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { "version": "1.13.5", "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.13.5.tgz", "integrity": "sha512-Luj8y4OFYx4DHNQTWjdIuKTq2f5k6uSXICqx+FSabnXptaOBAbJHNbHT/06JZh6NRUouaf0mYXN0mcsqvkhd7Q==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -3368,7 +4869,7 @@ "node": ">=10" } }, - "node_modules/@swc/core/node_modules/@swc/core-win32-arm64-msvc": { + "node_modules/@swc/core-win32-arm64-msvc": { "version": "1.13.5", "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.13.5.tgz", "integrity": "sha512-cZ6UpumhF9SDJvv4DA2fo9WIzlNFuKSkZpZmPG1c+4PFSEMy5DFOjBSllCvnqihCabzXzpn6ykCwBmHpy31vQw==", @@ -3384,7 +4885,7 @@ "node": ">=10" } }, - "node_modules/@swc/core/node_modules/@swc/core-win32-ia32-msvc": { + "node_modules/@swc/core-win32-ia32-msvc": { "version": "1.13.5", "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.13.5.tgz", "integrity": "sha512-C5Yi/xIikrFUzZcyGj9L3RpKljFvKiDMtyDzPKzlsDrKIw2EYY+bF88gB6oGY5RGmv4DAX8dbnpRAqgFD0FMEw==", @@ -3400,7 +4901,7 @@ "node": ">=10" } }, - "node_modules/@swc/core/node_modules/@swc/core-win32-x64-msvc": { + "node_modules/@swc/core-win32-x64-msvc": { "version": "1.13.5", "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.13.5.tgz", "integrity": "sha512-YrKdMVxbYmlfybCSbRtrilc6UA8GF5aPmGKBdPvjrarvsmf4i7ZHGCEnLtfOMd3Lwbs2WUZq3WdMbozYeLU93Q==", @@ -3444,8 +4945,6 @@ }, "node_modules/@tanstack/query-core": { "version": "5.85.9", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.85.9.tgz", - "integrity": "sha512-5fxb9vwyftYE6KFLhhhDyLr8NO75+Wpu7pmTo+TkwKmMX2oxZDoLwcqGP8ItKSpUMwk3urWgQDZfyWr5Jm9LsQ==", "license": "MIT", "funding": { "type": "github", @@ -3454,8 +4953,6 @@ }, "node_modules/@tanstack/react-query": { "version": "5.85.9", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.85.9.tgz", - "integrity": "sha512-2T5zgSpcOZXGkH/UObIbIkGmUPQqZqn7esVQFXLOze622h4spgWf5jmvrqAo9dnI13/hyMcNsF1jsoDcb59nJQ==", "license": "MIT", "dependencies": { "@tanstack/query-core": "5.85.9" @@ -3567,8 +5064,6 @@ }, "node_modules/@trapezedev/project/node_modules/@trapezedev/gradle-parse": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@trapezedev/gradle-parse/-/gradle-parse-7.1.3.tgz", - "integrity": "sha512-WQVF5pEJ5o/mUyvfGTG9nBKx9Te/ilKM3r2IT69GlbaooItT5ao7RyF1MUTBNjHLPk/xpGUY3c6PyVnjDlz0Vw==", "dev": true, "license": "SEE LICENSE" }, @@ -3585,8 +5080,6 @@ }, "node_modules/@trapezedev/project/node_modules/prettier": { "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, "license": "MIT", "bin": { @@ -3619,6 +5112,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/cli-progress": { + "version": "3.11.6", + "resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.6.tgz", + "integrity": "sha512-cE3+jb9WRlu+uOSAugewNpITJDt1VF8dHOopPO4IABFc3SXYL5WE/+PTz/FCdZRRfIujiWW3n3aMbv1eIGVRWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/d3-array": { "version": "3.2.1", "license": "MIT" @@ -3683,7 +5186,7 @@ }, "node_modules/@types/node": { "version": "24.3.0", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~7.10.0" @@ -3704,6 +5207,7 @@ }, "node_modules/@types/react": { "version": "18.3.24", + "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -3840,8 +5344,6 @@ }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.42.0.tgz", - "integrity": "sha512-51+x9o78NBAVgQzOPd17DkNTnIzJ8T/O2dmMBLoK9qbY0Gm52XJcdJcCl18ExBMiHo6jPMErUQWUv5RLE51zJw==", "dev": true, "license": "MIT", "dependencies": { @@ -3890,7 +5392,7 @@ }, "node_modules/@vite-pwa/assets-generator": { "version": "0.2.6", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "cac": "^6.7.14", @@ -3939,8 +5441,6 @@ }, "node_modules/@xml-tools/parser/node_modules/chevrotain": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-7.1.1.tgz", - "integrity": "sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4016,6 +5516,35 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "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-escapes/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/ansi-regex": { "version": "5.0.1", "license": "MIT", @@ -4036,6 +5565,13 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==", + "dev": true, + "license": "MIT" + }, "node_modules/any-promise": { "version": "1.3.0", "dev": true, @@ -4074,8 +5610,6 @@ }, "node_modules/array-buffer-byte-length": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -4116,8 +5650,6 @@ }, "node_modules/array-includes/node_modules/es-abstract": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "dev": true, "license": "MIT", "dependencies": { @@ -4212,8 +5744,6 @@ }, "node_modules/array.prototype.findlast/node_modules/es-abstract": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "dev": true, "license": "MIT", "dependencies": { @@ -4298,8 +5828,6 @@ }, "node_modules/array.prototype.flat/node_modules/es-abstract": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "dev": true, "license": "MIT", "dependencies": { @@ -4384,8 +5912,6 @@ }, "node_modules/array.prototype.flatmap/node_modules/es-abstract": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "dev": true, "license": "MIT", "dependencies": { @@ -4468,8 +5994,6 @@ }, "node_modules/array.prototype.tosorted/node_modules/es-abstract": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "dev": true, "license": "MIT", "dependencies": { @@ -4537,8 +6061,6 @@ }, "node_modules/arraybuffer.prototype.slice": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", @@ -4558,8 +6080,6 @@ }, "node_modules/arraybuffer.prototype.slice/node_modules/es-abstract": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.2", @@ -4651,8 +6171,6 @@ }, "node_modules/async-function": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -4703,8 +6221,6 @@ }, "node_modules/available-typed-arrays": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -4718,7 +6234,7 @@ }, "node_modules/b4a": { "version": "1.6.7", - "devOptional": true, + "dev": true, "license": "Apache-2.0" }, "node_modules/babel-plugin-macros": { @@ -4780,7 +6296,7 @@ }, "node_modules/base64-js": { "version": "1.5.1", - "devOptional": true, + "dev": true, "funding": [ { "type": "github", @@ -4799,8 +6315,6 @@ }, "node_modules/baseline-browser-mapping": { "version": "2.9.19", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", - "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4828,7 +6342,7 @@ }, "node_modules/bl": { "version": "4.1.0", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "buffer": "^5.5.0", @@ -4838,7 +6352,7 @@ }, "node_modules/bl/node_modules/readable-stream": { "version": "3.6.2", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -4849,6 +6363,10 @@ "node": ">= 6" } }, + "node_modules/bmp-js": { + "version": "0.1.0", + "license": "MIT" + }, "node_modules/boolbase": { "version": "1.0.0", "dev": true, @@ -4934,7 +6452,7 @@ }, "node_modules/buffer": { "version": "5.7.1", - "devOptional": true, + "dev": true, "funding": [ { "type": "github", @@ -4969,7 +6487,7 @@ }, "node_modules/cac": { "version": "6.7.14", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5056,8 +6574,6 @@ }, "node_modules/caniuse-lite": { "version": "1.0.30001769", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", - "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", "funding": [ { "type": "opencollective", @@ -5081,6 +6597,44 @@ "@capacitor/core": ">=7.0.0" } }, + "node_modules/capacitor-set-version": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/capacitor-set-version/-/capacitor-set-version-2.2.0.tgz", + "integrity": "sha512-CMWFFA8BxSRQDOCmSjqpZenxdMpRDvLRZLQfpO3958JTjE9+4G9o97Okmqpu2t26KVs8MHoDWjDy5hxD8EigSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oclif/core": "^1", + "@oclif/plugin-autocomplete": "^1.3.6", + "@oclif/plugin-commands": "^2.2.1", + "@oclif/plugin-help": "^5", + "@oclif/plugin-plugins": "^2.1.7", + "@oclif/plugin-version": "^1.1.3", + "plist": "^3.0.6", + "semver": "^7.3.8", + "tslib": "^2.4.0" + }, + "bin": { + "capacitor-set-version": "bin/run" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/cardinal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", + "integrity": "sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" + }, + "bin": { + "cdl": "bin/cdl.js" + } + }, "node_modules/chalk": { "version": "4.1.2", "dev": true, @@ -5140,8 +6694,6 @@ }, "node_modules/chrono-node": { "version": "2.8.4", - "resolved": "https://registry.npmjs.org/chrono-node/-/chrono-node-2.8.4.tgz", - "integrity": "sha512-F+Rq88qF3H2dwjnFrl3TZrn5v4ZO57XxeQ+AhuL1C685So1hdUV/hT/q8Ja5UbmPYEZfx8VrxFDa72Dgldcxpg==", "license": "MIT", "dependencies": { "dayjs": "^1.10.0" @@ -5162,6 +6714,19 @@ "node": ">=6" } }, + "node_modules/cli-progress": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", + "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.3" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/cliui": { "version": "8.0.1", "dev": true, @@ -5184,7 +6749,7 @@ }, "node_modules/color": { "version": "4.2.3", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1", @@ -5210,7 +6775,7 @@ }, "node_modules/color-string": { "version": "1.9.1", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "color-name": "^1.0.0", @@ -5219,7 +6784,7 @@ }, "node_modules/colorette": { "version": "2.0.20", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/commander": { @@ -5245,12 +6810,22 @@ }, "node_modules/consola": { "version": "3.4.2", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": "^14.18.0 || >=16.10.0" } }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/conventional-changelog": { "version": "3.1.25", "dev": true, @@ -5431,8 +7006,6 @@ }, "node_modules/conventional-changelog-writer/node_modules/handlebars": { "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5461,8 +7034,6 @@ }, "node_modules/conventional-changelog-writer/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": { @@ -5471,8 +7042,6 @@ }, "node_modules/conventional-changelog-writer/node_modules/uglify-js": { "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "dev": true, "license": "BSD-2-Clause", "optional": true, @@ -5554,8 +7123,6 @@ }, "node_modules/cross-fetch": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", "license": "MIT", "dependencies": { "node-fetch": "^2.6.12" @@ -5738,8 +7305,6 @@ }, "node_modules/data-view-buffer": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -5755,8 +7320,6 @@ }, "node_modules/data-view-byte-length": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -5772,8 +7335,6 @@ }, "node_modules/data-view-byte-offset": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -5797,8 +7358,6 @@ }, "node_modules/dayjs": { "version": "1.11.18", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz", - "integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==", "license": "MIT" }, "node_modules/debug": { @@ -5852,7 +7411,7 @@ }, "node_modules/decode-bmp": { "version": "0.2.1", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@canvas/image-data": "^1.0.0", @@ -5864,7 +7423,7 @@ }, "node_modules/decode-ico": { "version": "0.4.1", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@canvas/image-data": "^1.0.0", @@ -5877,7 +7436,7 @@ }, "node_modules/decompress-response": { "version": "6.0.0", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "mimic-response": "^3.1.0" @@ -5891,7 +7450,7 @@ }, "node_modules/deep-extend": { "version": "0.6.0", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=4.0.0" @@ -5949,7 +7508,7 @@ }, "node_modules/defu": { "version": "6.1.4", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/del": { @@ -6028,7 +7587,7 @@ }, "node_modules/detect-libc": { "version": "2.0.4", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -6218,7 +7777,7 @@ }, "node_modules/end-of-stream": { "version": "1.4.5", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "once": "^1.4.0" @@ -6303,8 +7862,6 @@ }, "node_modules/es-iterator-helpers/node_modules/es-abstract": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "dev": true, "license": "MIT", "dependencies": { @@ -6406,8 +7963,6 @@ }, "node_modules/es-to-primitive": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "license": "MIT", "dependencies": { "is-callable": "^1.2.7", @@ -6423,6 +7978,7 @@ }, "node_modules/esbuild": { "version": "0.21.5", + "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -6457,77 +8013,12 @@ "@esbuild/win32-x64": "0.21.5" } }, - "node_modules/esbuild/node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/esbuild/node_modules/@esbuild/darwin-arm64": { "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6537,294 +8028,6 @@ "node": ">=12" } }, - "node_modules/esbuild/node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild/node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/escalade": { "version": "3.2.0", "license": "MIT", @@ -6844,9 +8047,6 @@ }, "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.", "dev": true, "license": "MIT", "dependencies": { @@ -6941,8 +8141,6 @@ }, "node_modules/eslint-plugin-react": { "version": "7.37.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", - "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", "dev": true, "license": "MIT", "dependencies": { @@ -7024,8 +8222,6 @@ }, "node_modules/eslint-plugin-react/node_modules/resolve": { "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dev": true, "license": "MIT", "dependencies": { @@ -7200,6 +8396,20 @@ "url": "https://opencollective.com/eslint" } }, + "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/esquery": { "version": "1.6.0", "dev": true, @@ -7251,7 +8461,7 @@ }, "node_modules/expand-template": { "version": "2.0.3", - "devOptional": true, + "dev": true, "license": "(MIT OR WTFPL)", "engines": { "node": ">=6" @@ -7274,7 +8484,7 @@ }, "node_modules/fast-fifo": { "version": "1.3.2", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/fast-glob": { @@ -7477,8 +8687,6 @@ }, "node_modules/for-each": { "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "license": "MIT", "dependencies": { "is-callable": "^1.2.7" @@ -7546,7 +8754,7 @@ }, "node_modules/fs-constants": { "version": "1.0.0", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/fs-extra": { @@ -7590,9 +8798,6 @@ }, "node_modules/fsevents": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, "license": "MIT", "optional": true, "os": [ @@ -7611,8 +8816,6 @@ }, "node_modules/function.prototype.name": { "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -7683,6 +8886,16 @@ "version": "3.0.2", "license": "ISC" }, + "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-pkg-repo": { "version": "4.2.1", "dev": true, @@ -7749,8 +8962,6 @@ }, "node_modules/get-symbol-description": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -7842,7 +9053,7 @@ }, "node_modules/github-from-package": { "version": "0.0.0", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/glob": { @@ -7979,8 +9190,6 @@ }, "node_modules/has-bigints": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -8085,13 +9294,43 @@ }, "node_modules/html-parse-stringify": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", - "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", "license": "MIT", "dependencies": { "void-elements": "3.1.0" } }, + "node_modules/http-call": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/http-call/-/http-call-5.3.0.tgz", + "integrity": "sha512-ahwimsC23ICE4kPl9xTBjKB4inbRaeLyZeRunC/1Jy/Z6X8tv22MEAjK+KBOMSVLaqXPTTmd8638waVIKLGx2w==", + "dev": true, + "license": "ISC", + "dependencies": { + "content-type": "^1.0.4", + "debug": "^4.1.1", + "is-retry-allowed": "^1.1.0", + "is-stream": "^2.0.0", + "parse-json": "^4.0.0", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-call/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/husky": { "version": "8.0.3", "dev": true, @@ -8106,10 +9345,18 @@ "url": "https://github.com/sponsors/typicode" } }, + "node_modules/hyperlinker": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hyperlinker/-/hyperlinker-1.0.0.tgz", + "integrity": "sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/i18next": { "version": "25.8.14", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.14.tgz", - "integrity": "sha512-paMUYkfWJMsWPeE/Hejcw+XLhHrQPehem+4wMo+uELnvIwvCG019L9sAIljwjCmEMtFQQO3YeitJY8Kctei3iA==", "funding": [ { "type": "individual", @@ -8139,8 +9386,6 @@ }, "node_modules/i18next-browser-languagedetector": { "version": "8.2.1", - "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.1.tgz", - "integrity": "sha512-bZg8+4bdmaOiApD7N7BPT9W8MLZG+nPTOFlLiJiT8uzKXFjhxw4v2ierCXOwB5sFDMtuA5G4kgYZ0AznZxQ/cw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.2" @@ -8148,8 +9393,6 @@ }, "node_modules/i18next-http-backend": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-3.0.2.tgz", - "integrity": "sha512-PdlvPnvIp4E1sYi46Ik4tBYh/v/NbYfFFgTjkwFl0is8A18s7/bx9aXqsrOax9WUbeNS6mD2oix7Z0yGGf6m5g==", "license": "MIT", "dependencies": { "cross-fetch": "4.0.0" @@ -8157,16 +9400,20 @@ }, "node_modules/ico-endec": { "version": "0.1.6", - "devOptional": true, + "dev": true, "license": "MPL-2.0" }, "node_modules/idb": { "version": "7.1.1", "license": "ISC" }, + "node_modules/idb-keyval": { + "version": "6.2.6", + "license": "Apache-2.0" + }, "node_modules/ieee754": { "version": "1.2.1", - "devOptional": true, + "dev": true, "funding": [ { "type": "github", @@ -8266,8 +9513,6 @@ }, "node_modules/is-array-buffer": { "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -8287,8 +9532,6 @@ }, "node_modules/is-async-function": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "license": "MIT", "dependencies": { "async-function": "^1.0.0", @@ -8306,8 +9549,6 @@ }, "node_modules/is-bigint": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "license": "MIT", "dependencies": { "has-bigints": "^1.0.2" @@ -8332,8 +9573,6 @@ }, "node_modules/is-boolean-object": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -8348,8 +9587,6 @@ }, "node_modules/is-callable": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -8373,8 +9610,6 @@ }, "node_modules/is-data-view": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8390,8 +9625,6 @@ }, "node_modules/is-date-object": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8428,8 +9661,6 @@ }, "node_modules/is-finalizationregistry": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -8450,8 +9681,6 @@ }, "node_modules/is-generator-function": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", - "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -8479,8 +9708,6 @@ }, "node_modules/is-map": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -8495,8 +9722,6 @@ }, "node_modules/is-negative-zero": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -8515,8 +9740,6 @@ }, "node_modules/is-number-object": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -8563,8 +9786,6 @@ }, "node_modules/is-regex": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8586,10 +9807,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-set": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -8600,8 +9829,6 @@ }, "node_modules/is-shared-array-buffer": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -8639,8 +9866,6 @@ }, "node_modules/is-symbol": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8667,8 +9892,6 @@ }, "node_modules/is-typed-array": { "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "license": "MIT", "dependencies": { "which-typed-array": "^1.1.16" @@ -8680,10 +9903,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-url": { + "version": "1.2.4", + "license": "MIT" + }, "node_modules/is-weakmap": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -8694,8 +9919,6 @@ }, "node_modules/is-weakref": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -8709,8 +9932,6 @@ }, "node_modules/is-weakset": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -8790,7 +10011,7 @@ }, "node_modules/jiti": { "version": "1.21.7", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "jiti": "bin/jiti.js" @@ -9064,8 +10285,6 @@ }, "node_modules/lodash": { "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, "node_modules/lodash.clonedeep": { @@ -9373,7 +10592,7 @@ }, "node_modules/mimic-response": { "version": "3.1.0", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -9406,7 +10625,7 @@ }, "node_modules/minimist": { "version": "1.2.8", - "devOptional": true, + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9469,7 +10688,7 @@ }, "node_modules/mkdirp-classic": { "version": "0.5.3", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/modify-values": { @@ -9482,8 +10701,6 @@ }, "node_modules/moment": { "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", "license": "MIT", "engines": { "node": "*" @@ -9509,6 +10726,7 @@ }, "node_modules/nanoid": { "version": "3.3.11", + "dev": true, "funding": [ { "type": "github", @@ -9525,7 +10743,7 @@ }, "node_modules/napi-build-utils": { "version": "2.0.0", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/native-run": { @@ -9578,6 +10796,16 @@ "dev": true, "license": "MIT" }, + "node_modules/natural-orderby": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-2.0.3.tgz", + "integrity": "sha512-p7KTHxU0CUrcOXe62Zfrb5Z13nLvPhSWR/so3kFulUQU0sgUll2Z0LwpsLN351eOOD+hRGu/F1g+6xDfPeD++Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/neo-async": { "version": "2.6.2", "dev": true, @@ -9585,7 +10813,7 @@ }, "node_modules/node-abi": { "version": "3.77.0", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "semver": "^7.3.5" @@ -9596,7 +10824,7 @@ }, "node_modules/node-addon-api": { "version": "6.1.0", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/node-fetch": { @@ -9664,6 +10892,19 @@ "version": "1.0.1", "license": "BSD-3-Clause" }, + "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/nth-check": { "version": "2.1.1", "dev": true, @@ -9707,6 +10948,16 @@ "node": ">= 0.4" } }, + "node_modules/object-treeify": { + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz", + "integrity": "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, "node_modules/object.assign": { "version": "4.1.7", "license": "MIT", @@ -9758,8 +11009,6 @@ }, "node_modules/object.fromentries/node_modules/es-abstract": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "dev": true, "license": "MIT", "dependencies": { @@ -9865,6 +11114,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/opencollective-postinstall": { + "version": "2.0.3", + "license": "MIT", + "bin": { + "opencollective-postinstall": "index.js" + } + }, "node_modules/optionator": { "version": "0.9.4", "dev": true, @@ -9883,8 +11139,6 @@ }, "node_modules/own-keys": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.6", @@ -9993,6 +11247,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/password-prompt": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.3.tgz", + "integrity": "sha512-HkrjG2aJlvF0t2BMH0e2LB/EHf3Lcq3fNMzy4GYHcQblAvOl+QQji1Lx7WRBMqpVK8p+KR7bCg7oqAMXtdgqyw==", + "dev": true, + "license": "0BSD", + "dependencies": { + "ansi-escapes": "^4.3.2", + "cross-spawn": "^7.0.3" + } + }, "node_modules/path-exists": { "version": "4.0.0", "license": "MIT", @@ -10114,8 +11379,6 @@ }, "node_modules/possible-typed-array-names": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -10123,6 +11386,7 @@ }, "node_modules/postcss": { "version": "8.5.6", + "dev": true, "funding": [ { "type": "opencollective", @@ -10217,8 +11481,6 @@ }, "node_modules/postcss-load-config/node_modules/yaml": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", "dev": true, "license": "ISC", "bin": { @@ -10271,7 +11533,7 @@ }, "node_modules/prebuild-install": { "version": "7.1.3", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "detect-libc": "^2.0.0", @@ -10296,12 +11558,12 @@ }, "node_modules/prebuild-install/node_modules/chownr": { "version": "1.1.4", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/prebuild-install/node_modules/readable-stream": { "version": "3.6.2", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -10314,7 +11576,7 @@ }, "node_modules/prebuild-install/node_modules/tar-fs": { "version": "2.1.3", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "chownr": "^1.1.1", @@ -10325,7 +11587,7 @@ }, "node_modules/prebuild-install/node_modules/tar-stream": { "version": "2.2.0", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "bl": "^4.0.3", @@ -10348,8 +11610,6 @@ }, "node_modules/prettier": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", "bin": { @@ -10495,7 +11755,7 @@ }, "node_modules/pump": { "version": "3.0.3", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -10687,8 +11947,6 @@ }, "node_modules/quill/node_modules/lodash-es": { "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "license": "MIT" }, "node_modules/quilljs-markdown": { @@ -10701,8 +11959,6 @@ }, "node_modules/quilljs-markdown/node_modules/core-js": { "version": "3.45.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.1.tgz", - "integrity": "sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -10723,7 +11979,7 @@ }, "node_modules/rc": { "version": "1.2.8", - "devOptional": true, + "dev": true, "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "dependencies": { "deep-extend": "^0.6.0", @@ -10737,12 +11993,12 @@ }, "node_modules/rc/node_modules/ini": { "version": "1.3.8", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10783,8 +12039,6 @@ }, "node_modules/react-dom": { "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", @@ -10808,8 +12062,6 @@ }, "node_modules/react-i18next": { "version": "16.5.6", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-16.5.6.tgz", - "integrity": "sha512-Ua7V2/efA88ido7KyK51fb8Ki8M/sRfW8LR/rZ/9ZKr2luhuTI7kwYZN5agT1rWG7aYm5G0RYE/6JR8KJoCMDw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", @@ -10888,8 +12140,6 @@ }, "node_modules/react-router-dom/node_modules/@remix-run/router": { "version": "1.23.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz", - "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==", "license": "MIT", "engines": { "node": ">=14.0.0" @@ -10897,8 +12147,6 @@ }, "node_modules/react-router/node_modules/@remix-run/router": { "version": "1.23.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz", - "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==", "license": "MIT", "engines": { "node": ">=14.0.0" @@ -11105,8 +12353,6 @@ }, "node_modules/recharts": { "version": "2.15.4", - "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz", - "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==", "license": "MIT", "dependencies": { "clsx": "^2.0.0", @@ -11153,14 +12399,22 @@ "node": ">=8" } }, + "node_modules/redeyed": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", + "integrity": "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esprima": "~4.0.0" + } + }, "node_modules/redux": { "version": "5.0.1", "license": "MIT" }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -11181,8 +12435,6 @@ }, "node_modules/reflect.getprototypeof/node_modules/es-abstract": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.2", @@ -11295,8 +12547,6 @@ }, "node_modules/regexpu-core/node_modules/regenerate-unicode-properties": { "version": "10.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", - "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "license": "MIT", "dependencies": { "regenerate": "^1.4.2" @@ -11648,8 +12898,7 @@ }, "node_modules/rollup": { "version": "4.50.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.0.tgz", - "integrity": "sha512-/Zl4D8zPifNmyGzJS+3kVoyXeDeT/GrsJM94sACNg9RtUE0hrHa1bNPtRSrfHTMH5HjRzce6K7rlTh3Khiw+pw==", + "dev": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.8" @@ -11686,253 +12935,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/rollup/node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.0.tgz", - "integrity": "sha512-lVgpeQyy4fWN5QYebtW4buT/4kn4p4IJ+kDNB4uYNT5b8c8DLJDg6titg20NIg7E8RWwdWZORW6vUFfrLyG3KQ==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-android-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.0.tgz", - "integrity": "sha512-2O73dR4Dc9bp+wSYhviP6sDziurB5/HCym7xILKifWdE9UsOe2FtNcM+I4xZjKrfLJnq5UR8k9riB87gauiQtw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-darwin-x64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.0.tgz", - "integrity": "sha512-cQp/WG8HE7BCGyFVuzUg0FNmupxC+EPZEwWu2FCGGw5WDT1o2/YlENbm5e9SMvfDFR6FRhVCBePLqj0o8MN7Vw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.0.tgz", - "integrity": "sha512-UR1uTJFU/p801DvvBbtDD7z9mQL8J80xB0bR7DqW7UGQHRm/OaKzp4is7sQSdbt2pjjSS72eAtRh43hNduTnnQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.0.tgz", - "integrity": "sha512-G/DKyS6PK0dD0+VEzH/6n/hWDNPDZSMBmqsElWnCRGrYOb2jC0VSupp7UAHHQ4+QILwkxSMaYIbQ72dktp8pKA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.0.tgz", - "integrity": "sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.0.tgz", - "integrity": "sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.0.tgz", - "integrity": "sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.0.tgz", - "integrity": "sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.0.tgz", - "integrity": "sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.0.tgz", - "integrity": "sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.0.tgz", - "integrity": "sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.0.tgz", - "integrity": "sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.0.tgz", - "integrity": "sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.0.tgz", - "integrity": "sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.0.tgz", - "integrity": "sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.0.tgz", - "integrity": "sha512-q7cIIdFvWQoaCbLDUyUc8YfR3Jh2xx3unO8Dn6/TTogKjfwrax9SyfmGGK6cQhKtjePI7jRfd7iRYcxYs93esg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.0.tgz", - "integrity": "sha512-XzNOVg/YnDOmFdDKcxxK410PrcbcqZkBmz+0FicpW5jtjKQxcW1BZJEQOF0NJa6JO7CZhett8GEtRN/wYLYJuw==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/rollup/node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.0.tgz", - "integrity": "sha512-xMmiWRR8sp72Zqwjgtf3QbZfF1wdh8X2ABu3EaozvZcyHJeU0r+XAnXdKgs4cCAp6ORoYoCygipYP1mjmbjrsg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/run-parallel": { "version": "1.2.0", "dev": true, @@ -11982,8 +12984,6 @@ }, "node_modules/safe-push-apply": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -11998,14 +12998,10 @@ }, "node_modules/safe-push-apply/node_modules/isarray": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "license": "MIT" }, "node_modules/safe-regex-test": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -12033,7 +13029,7 @@ }, "node_modules/semver": { "version": "7.7.2", - "devOptional": true, + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -12083,8 +13079,6 @@ }, "node_modules/set-proto": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -12101,7 +13095,7 @@ }, "node_modules/sharp": { "version": "0.32.6", - "devOptional": true, + "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -12123,7 +13117,7 @@ }, "node_modules/sharp-ico": { "version": "0.1.5", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "decode-ico": "*", @@ -12221,7 +13215,7 @@ }, "node_modules/simple-concat": { "version": "1.0.1", - "devOptional": true, + "dev": true, "funding": [ { "type": "github", @@ -12240,7 +13234,7 @@ }, "node_modules/simple-get": { "version": "4.0.1", - "devOptional": true, + "dev": true, "funding": [ { "type": "github", @@ -12285,7 +13279,7 @@ }, "node_modules/simple-swizzle": { "version": "0.2.2", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "is-arrayish": "^0.3.1" @@ -12293,7 +13287,7 @@ }, "node_modules/simple-swizzle/node_modules/is-arrayish": { "version": "0.3.2", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/sisteransi": { @@ -12338,6 +13332,7 @@ }, "node_modules/source-map-js": { "version": "1.2.1", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -12422,14 +13417,19 @@ "node": ">= 6" } }, + "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/stackframe": { "version": "1.3.4", "license": "MIT" }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -12449,7 +13449,7 @@ }, "node_modules/streamx": { "version": "2.22.1", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "fast-fifo": "^1.3.2", @@ -12461,8 +13461,6 @@ }, "node_modules/streamx/node_modules/bare-events": { "version": "2.6.1", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.6.1.tgz", - "integrity": "sha512-AuTJkq9XmE6Vk0FJVNq5QxETrSA/vKHarWVBG5l/JbdCL1prJemiyJqUS0jrlXO0MftuPq4m3YVYhoNc5+aE/g==", "dev": true, "license": "Apache-2.0", "optional": true @@ -12527,8 +13525,6 @@ }, "node_modules/string.prototype.matchall/node_modules/es-abstract": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.2", @@ -12604,8 +13600,6 @@ }, "node_modules/string.prototype.repeat/node_modules/es-abstract": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "dev": true, "license": "MIT", "dependencies": { @@ -12673,8 +13667,6 @@ }, "node_modules/string.prototype.trim": { "version": "1.2.10", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -12694,8 +13686,6 @@ }, "node_modules/string.prototype.trim/node_modules/es-abstract": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.2", @@ -12762,8 +13752,6 @@ }, "node_modules/string.prototype.trimend": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -12780,8 +13768,6 @@ }, "node_modules/string.prototype.trimstart": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -12879,8 +13865,6 @@ }, "node_modules/sucrase": { "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", "dev": true, "license": "MIT", "dependencies": { @@ -12902,8 +13886,6 @@ }, "node_modules/sucrase/node_modules/@pkgjs/parseargs": { "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, "license": "MIT", "optional": true, @@ -12913,8 +13895,6 @@ }, "node_modules/sucrase/node_modules/commander": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true, "license": "MIT", "engines": { @@ -12923,8 +13903,6 @@ }, "node_modules/sucrase/node_modules/glob": { "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "license": "ISC", "dependencies": { @@ -12944,8 +13922,6 @@ }, "node_modules/sucrase/node_modules/jackspeak": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -12960,15 +13936,11 @@ }, "node_modules/sucrase/node_modules/lru-cache": { "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, "license": "ISC" }, "node_modules/sucrase/node_modules/path-scurry": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -12993,6 +13965,20 @@ "node": ">=8" } }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "license": "MIT", @@ -13019,8 +14005,6 @@ }, "node_modules/tailwindcss": { "version": "3.4.17", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", - "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "dev": true, "license": "MIT", "dependencies": { @@ -13073,7 +14057,7 @@ }, "node_modules/tar-fs": { "version": "3.1.0", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "pump": "^3.0.0", @@ -13086,16 +14070,12 @@ }, "node_modules/tar-fs/node_modules/bare-events": { "version": "2.6.1", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.6.1.tgz", - "integrity": "sha512-AuTJkq9XmE6Vk0FJVNq5QxETrSA/vKHarWVBG5l/JbdCL1prJemiyJqUS0jrlXO0MftuPq4m3YVYhoNc5+aE/g==", "dev": true, "license": "Apache-2.0", "optional": true }, "node_modules/tar-fs/node_modules/bare-fs": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.2.3.tgz", - "integrity": "sha512-1aGs5pRVLToMQ79elP+7cc0u0s/wXAzfBv/7hDloT7WFggLqECCas5qqPky7WHCFdsBH5WDq6sD4fAoz5sJbtA==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -13118,8 +14098,6 @@ }, "node_modules/tar-fs/node_modules/bare-os": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.2.tgz", - "integrity": "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -13129,8 +14107,6 @@ }, "node_modules/tar-fs/node_modules/bare-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", - "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -13140,8 +14116,6 @@ }, "node_modules/tar-fs/node_modules/bare-stream": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.7.0.tgz", - "integrity": "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -13163,7 +14137,7 @@ }, "node_modules/tar-stream": { "version": "3.1.7", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "b4a": "^1.6.4", @@ -13217,8 +14191,6 @@ }, "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==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -13235,13 +14207,31 @@ }, "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==", "license": "MIT" }, + "node_modules/tesseract.js": { + "version": "7.0.0", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "bmp-js": "^0.1.0", + "idb-keyval": "^6.2.0", + "is-url": "^1.2.4", + "node-fetch": "^2.6.9", + "opencollective-postinstall": "^2.0.3", + "regenerator-runtime": "^0.13.3", + "tesseract.js-core": "^7.0.0", + "wasm-feature-detect": "^1.8.0", + "zlibjs": "^0.3.1" + } + }, + "node_modules/tesseract.js-core": { + "version": "7.0.0", + "license": "Apache-2.0" + }, "node_modules/text-decoder": { "version": "1.2.3", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "b4a": "^1.6.4" @@ -13358,7 +14348,7 @@ }, "node_modules/to-data-view": { "version": "1.1.0", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/to-regex-range": { @@ -13469,7 +14459,7 @@ }, "node_modules/tunnel-agent": { "version": "0.6.0", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" @@ -13502,8 +14492,6 @@ }, "node_modules/typed-array-buffer": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -13516,8 +14504,6 @@ }, "node_modules/typed-array-byte-length": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -13535,8 +14521,6 @@ }, "node_modules/typed-array-byte-offset": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", - "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -13556,8 +14540,6 @@ }, "node_modules/typed-array-length": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -13574,25 +14556,8 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", - "devOptional": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/unbox-primitive": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -13609,7 +14574,7 @@ }, "node_modules/unconfig": { "version": "0.3.13", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@antfu/utils": "^0.7.7", @@ -13622,7 +14587,7 @@ }, "node_modules/undici-types": { "version": "7.10.0", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -13728,8 +14693,6 @@ }, "node_modules/use-sync-external-store": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -13767,8 +14730,6 @@ }, "node_modules/victory-vendor": { "version": "36.9.2", - "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", - "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", "license": "MIT AND ISC", "dependencies": { "@types/d3-array": "^3.0.3", @@ -13789,8 +14750,7 @@ }, "node_modules/vite": { "version": "5.4.19", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", - "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", + "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.21.3", @@ -13895,8 +14855,6 @@ }, "node_modules/void-elements": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", - "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -13909,6 +14867,10 @@ "loose-envify": "^1.0.0" } }, + "node_modules/wasm-feature-detect": { + "version": "1.8.0", + "license": "Apache-2.0" + }, "node_modules/webidl-conversions": { "version": "3.0.1", "license": "BSD-2-Clause" @@ -13937,8 +14899,6 @@ }, "node_modules/which-boxed-primitive": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", - "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", "license": "MIT", "dependencies": { "is-bigint": "^1.1.0", @@ -13956,8 +14916,6 @@ }, "node_modules/which-builtin-type": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", - "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -13983,14 +14941,10 @@ }, "node_modules/which-builtin-type/node_modules/isarray": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "license": "MIT" }, "node_modules/which-collection": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "license": "MIT", "dependencies": { "is-map": "^2.0.3", @@ -14011,8 +14965,6 @@ }, "node_modules/which-typed-array": { "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -14030,6 +14982,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "dev": true, @@ -14168,8 +15133,6 @@ }, "node_modules/workbox-build/node_modules/@surma/rollup-plugin-off-main-thread": { "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", - "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", "license": "Apache-2.0", "dependencies": { "ejs": "^3.1.6", @@ -14184,8 +15147,6 @@ }, "node_modules/workbox-build/node_modules/ajv": { "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -14208,8 +15169,6 @@ }, "node_modules/workbox-build/node_modules/common-tags": { "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", "license": "MIT", "engines": { "node": ">=4.0.0" @@ -14276,8 +15235,6 @@ }, "node_modules/workbox-build/node_modules/rollup": { "version": "2.79.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", - "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "license": "MIT", "bin": { "rollup": "dist/bin/rollup" @@ -14585,6 +15542,21 @@ "node": ">=12" } }, + "node_modules/yarn": { + "version": "1.22.22", + "resolved": "https://registry.npmjs.org/yarn/-/yarn-1.22.22.tgz", + "integrity": "sha512-prL3kGtyG7o9Z9Sv8IPfBNrWTDmXB4Qbes8A9rEzt6wkJV8mUvoirjU0Mp3GGAU06Y0XQyA3/2/RQFVuK7MTfg==", + "dev": true, + "hasInstallScript": true, + "license": "BSD-2-Clause", + "bin": { + "yarn": "bin/yarn.js", + "yarnpkg": "bin/yarn.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/yauzl": { "version": "2.10.0", "dev": true, @@ -14612,6 +15584,13 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zlibjs": { + "version": "0.3.1", + "license": "MIT", + "engines": { + "node": "*" + } } } } diff --git a/package.json b/package.json index 305b4a0..2410be7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "donetick", "private": true, - "version": "1.2.2", + "version": "1.2.3", "type": "module", "engines": { "node": ">=20.0.0", @@ -30,43 +30,49 @@ "ionic:build": "npm run build", "ionic:serve": "npm run start", "android": "npm run build && npx cap sync android", + "cap": "npm run build && npx cap sync", "bump": "node bump-version.js", "bump:minor": "node bump-version.js minor", - "bump:major": "node bump-version.js major" + "bump:major": "node bump-version.js major", + "bump:patch": "node bump-version.js patch" }, "dependencies": { - "@capacitor-community/sqlite": "^7.0.0", - "@capacitor/android": "^7.0.0", - "@capacitor/app": "^7.0.0", - "@capacitor/browser": "^7.0.2", - "@capacitor/core": "^7.0.0", - "@capacitor/device": "^7.0.0", - "@capacitor/ios": "^7.0.0", - "@capacitor/local-notifications": "^7.0.0", - "@capacitor/network": "^7.0.1", - "@capacitor/preferences": "^7.0.0", - "@capacitor/push-notifications": "^7.0.0", - "@capacitor/status-bar": "^7.0.0", - "@capgo/capacitor-social-login": "^7.5.3", + "@capacitor-community/sqlite": "^8.0.0", + "@capacitor/android": "^8.0.0", + "@capacitor/app": "^8.0.0", + "@capacitor/browser": "^8.0.0", + "@capacitor/core": "^8.0.0", + "@capacitor/device": "^8.0.0", + "@capacitor/ios": "^8.0.0", + "@capacitor/local-llm": "^1.0.0", + "@capacitor/local-notifications": "^8.0.0", + "@capacitor/network": "^8.0.0", + "@capacitor/preferences": "^8.0.0", + "@capacitor/push-notifications": "^8.0.0", + "@capacitor/status-bar": "^8.0.0", + "@capgo/capacitor-document-scanner": "^8.4.0", + "@capgo/capacitor-nfc": "^8.0.0", + "@capgo/capacitor-social-login": "^8.0.0", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@hello-pangea/dnd": "^18.0.1", + "@jcesarmobile/capacitor-ocr": "^0.3.0", "@meauxt/react-swipeable-list": "^1.0.0", "@mui/icons-material": "^5.16.13", "@mui/joy": "^5.0.0-beta.20", "@mui/material": "^5.15.2", "@openreplay/tracker": "^14.0.4", - "@revenuecat/purchases-capacitor": "^11.1.0", - "@revenuecat/purchases-capacitor-ui": "^11.1.0", + "@revenuecat/purchases-capacitor": "^12.0.0", + "@revenuecat/purchases-capacitor-ui": "^12.0.0", "@swc/core": "^1.12.5", "@tanstack/react-query": "^5.17.0", "aos": "^2.3.4", "browser-image-compression": "^2.0.2", "caniuse-lite": "^1.0.30001769", - "capacitor-plugin-safe-area": "^4.0.0", + "capacitor-plugin-safe-area": "^5.0.0", "chrono-node": "^2.7.7", "dotenv": "^16.4.5", "esm": "^3.2.25", @@ -92,11 +98,12 @@ "reactjs-social-login": "^2.6.3", "recharts": "^2.15.0", "reusify": "^1.0.4", + "tesseract.js": "^7.0.0", "vite-plugin-pwa": "^0.20.0" }, "devDependencies": { "@capacitor/assets": "^3.0.5", - "@capacitor/cli": "^7.0.0", + "@capacitor/cli": "^8.0.0", "@tanstack/eslint-plugin-query": "^5.14.6", "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", @@ -104,6 +111,7 @@ "@vitejs/plugin-react-swc": "^3.5.0", "autoprefixer": "^10.4.16", "baseline-browser-mapping": "^2.9.19", + "capacitor-set-version": "^2.2.0", "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.2", @@ -119,6 +127,10 @@ "prettier": "^3.1.1", "prettier-plugin-tailwindcss": "^0.5.10", "tailwindcss": "^3.4.0", + "typescript": "^5.8.0", "vite": "^5.2.13" + }, + "allowScripts": { + "tesseract.js@7.0.0": true } } diff --git a/public/locales/de/chores.json b/public/locales/de/chores.json new file mode 100644 index 0000000..a8e283a --- /dev/null +++ b/public/locales/de/chores.json @@ -0,0 +1,75 @@ +{ + "title": "Aufgaben", + "myChores": "Meine Aufgaben", + "allChores": "Alle Aufgaben", + "addChore": "Aufgabe hinzufügen", + "editChore": "Aufgabe bearbeiten", + "deleteChore": "Aufgabe löschen", + "completeChore": "Aufgabe abschließen", + "dueDate": "Fälligkeitsdatum", + "assignedTo": "Zugewiesen an", + "priority": "Priorität", + "status": "Status", + "description": "Beschreibung", + "choreView": { + "assignment": "Zuweisung", + "assigned": "Zugewiesen", + "last": "Letzte", + "schedule": "Zeitplan", + "due": "Fällig", + "statistics": "Statistiken", + "completed": "Abgeschlossen", + "times": "mal", + "details": "Details", + "createdBy": "Erstellt von", + "na": "Nicht verfügbar", + "taskCompleted": "Aufgabe abgeschlossen", + "taskCompletedMessage": "Deine Aufgabe wurde als abgeschlossen markiert", + "taskCompletionUndone": "Aufgabenabschluss wurde rückgängig gemacht.", + "taskSkipUndone": "Aufgabe überspringen wurde rückgängig gemacht.", + "undoSuccessful": "Rückgängig erfolgreich", + "undoFailed": "Rückgängig fehlgeschlagen", + "undoFailedMessage": "Die Aktion konnte nicht rückgängig gemacht werden. Bitte versuche es erneut.", + "resetTimer": "Timer zurücksetzen", + "resetTimerConfirmation": "Bist du sicher, dass du den Timer zurücksetzen möchtest? Dies löscht alle Zeitaufzeichnungen seit du die Aufgabe gestartet hast.", + "clearAllTimeRecords": "Alle Zeitaufzeichnungen löschen", + "clearAllTimeConfirmation": "Dies löscht dauerhaft alle Timer für diese Aufgabe und setzt sie zurück auf \"nicht gestartet\".", + "descriptionTitle": "Beschreibung", + "description": "Beschreibung:", + "previousNote": "Vorherige Notiz", + "previousNoteLabel": "Vorherige Notiz:", + "subtasksLabel": "Unteraufgaben:", + "taskActions": "Aufgabenaktionen", + "addNote": "Notiz hinzufügen", + "additionalNotes": "Zusätzliche Notizen:", + "notePlaceholder": "Notiz zur Fertigstellung hinzufügen...", + "setCustomCompletionTime": "Benutzerdefinierte Abschlusszeit festlegen", + "skipTask": "Aufgabe überspringen", + "skipTaskConfirmation": "Bist du sicher, dass du diese Aufgabe überspringen möchtest?", + "markComplete": "Als abgeschlossen markieren", + "markAsDone": "Als erledigt markieren", + "edit": "Bearbeiten", + "archive": "Archivieren", + "unarchive": "Archivierung aufheben", + "viewHistory": "Verlauf anzeigen", + "history": "Verlauf", + "startTimer": "Timer starten", + "start": "Starten", + "pauseTimer": "Timer pausieren", + "approve": "Genehmigen", + "reject": "Ablehnen", + "pendingApproval": "Genehmigung ausstehend", + "undo": "Rückgängig", + "skip": "Überspringen", + "cancel": "Abbrechen", + "noPriority": "Keine Priorität", + "subtasks": "Unteraufgaben", + "noDescription": "Keine Beschreibung verfügbar", + "timer": { + "active": "Timer aktiv", + "paused": "Timer pausiert", + "reset": "Timer zurücksetzen", + "delete": "Sitzung löschen" + } + } +} diff --git a/public/locales/de/common.json b/public/locales/de/common.json new file mode 100644 index 0000000..50a53d0 --- /dev/null +++ b/public/locales/de/common.json @@ -0,0 +1,33 @@ +{ + "save": "Speichern", + "cancel": "Abbrechen", + "delete": "Löschen", + "edit": "Bearbeiten", + "close": "Schließen", + "confirm": "Bestätigen", + "loading": "Laden...", + "error": "Fehler", + "success": "Erfolg", + "warning": "Warnung", + "refresh": "Aktualisieren", + "copy": "Kopieren", + "copied": "Kopiert!", + "settings": "Einstellungen", + "yes": "Ja", + "no": "Nein", + "back": "Zurück", + "backToCalendar": "Zurück zum Kalender", + "logout": "Abmelden", + "version": "Version", + "navigation": { + "allTasks": "Alle Aufgaben", + "archived": "Archiviert", + "things": "Things", + "labels": "Beschriftungen", + "projects": "Projekte", + "filters": "Filter", + "activities": "Aktivitäten", + "points": "Punkte", + "settings": "Einstellungen" + } +} diff --git a/public/locales/de/settings.json b/public/locales/de/settings.json new file mode 100644 index 0000000..372a1fc --- /dev/null +++ b/public/locales/de/settings.json @@ -0,0 +1,174 @@ +{ + "title": "Einstellungen", + "circleSettings": { + "title": "Kreis-Einstellungen", + "description": "Dein Account wird automatisch mit einem Kreis verbunden, wenn du einen erstellst oder beitrittst. Lade einfach Freunde ein, indem du den einzigartigen Kreis-Code oder Link unten teilst. Du erhältst eine Benachrichtigung, wenn jemand deinem Kreis beitreten möchte. Wenn du gehen möchtest, klicke einfach auf 'Kreis verlassen'.", + "circleCode": "Kreis-Code", + "copyCode": "Code kopieren", + "copyLink": "Link kopieren", + "codeCopied": "Kreis-Code kopiert!", + "linkCopied": "Kreis-Link kopiert!", + "joinCircle": "Einem Kreis beitreten", + "joinCirclePlaceholder": "Kreis-Code eingeben", + "join": "Beitreten", + "leave": "Kreis verlassen", + "leaveConfirmTitle": "Kreis verlassen", + "leaveConfirmMessage": "Bist du sicher, dass du diesen Kreis verlassen möchtest?", + "circleMembers": "Kreis-Mitglieder", + "circleMemberRequests": "Kreis-Beitrittsanfragen", + "admin": "Administrator", + "member": "Mitglied", + "pending": "Ausstehend", + "accept": "Akzeptieren", + "reject": "Ablehnen", + "makeAdmin": "Zum Administrator machen", + "makeMember": "Zum Mitglied machen", + "remove": "Entfernen", + "webhookURL": "Webhook-URL", + "webhookDescription": "Gib eine Webhook-URL ein, um Benachrichtigungen für Kreis-Ereignisse zu erhalten", + "webhookPlaceholder": "https://deine-webhook-url.com" + }, + "accountSettings": { + "title": "Account-Einstellungen", + "subscription": "Abonnement", + "subscriptionStatus": "Aktueller Plan", + "free": "Kostenlos", + "plus": "Plus", + "upgrade": "Upgraden", + "cancel": "Kündigen", + "changePassword": "Passwort ändern", + "password": "Passwort", + "dangerZone": "Gefahrenbereich", + "dangerZoneDescription": "Sobald du dein Konto löschst, gibt es kein Zurück mehr. Bitte sei dir sicher.", + "deleteAccount": "Account löschen" + }, + "localization": { + "title": "Sprach- und Formateinstellungen", + "description": "Passe Sprache, Datumsformat und regionale Einstellungen für dein Konto an.", + "language": "Sprache", + "languageDescription": "Wähle deine bevorzugte Sprache", + "dateFormat": "Datumsformat", + "dateFormatDescription": "Wähle, wie Daten in der gesamten Anwendung angezeigt werden sollen", + "timeFormat": "Zeitformat", + "timeFormatDescription": "Wähle 12-Stunden- oder 24-Stunden-Zeitformat", + "12hour": "12-Stunden (AM/PM)", + "24hour": "24-Stunden", + "firstDayOfWeek": "Erster Tag der Woche", + "firstDayOfWeekDescription": "Wähle, welcher Tag deine Woche beginnt", + "sunday": "Sonntag", + "monday": "Montag", + "saturday": "Samstag", + "formats": { + "mdy": "MM/TT/JJJJ (USA)", + "dmy": "TT/MM/JJJJ (Europa)", + "ymd": "JJJJ-MM-TT (ISO)", + "long": "Langes Format (z.B. 1. Januar 2024)", + "short": "Kurzes Format (z.B. 1. Jan 2024)" + } + }, + "sidepanel": { + "title": "Seitenleisten-Anpassung", + "description": "Passe das Layout und die Sichtbarkeit von Karten in der Seitenleiste an. Dieser Bereich ist nur auf großen Bildschirmgeräten wie Tablets und Desktops verfügbar." + }, + "theme": { + "title": "Theme-Einstellungen", + "description": "Wähle, wie die Seite für dich aussieht. Wähle ein einzelnes Theme oder synchronisiere mit deinem System und wechsle automatisch zwischen Tag- und Nacht-Themes.", + "themeMode": "Theme-Modus", + "light": "Hell", + "dark": "Dunkel", + "system": "System" + }, + "notifications": { + "settingsSaved": "Einstellungen erfolgreich gespeichert", + "settingsSaveFailed": "Speichern der Einstellungen fehlgeschlagen", + "invalidWebhook": "Ungültige Webhook-URL" + }, + "profile": { + "title": "Profil-Einstellungen", + "description": "Aktualisiere deinen Anzeigenamen und dein Profilbild.", + "photoUpdated": "Foto aktualisiert", + "photoUpdatedMessage": "Dein Profilbild wurde erfolgreich aktualisiert!", + "uploadFailed": "Upload fehlgeschlagen", + "uploadFailedMessage": "Das Hochladen deines Fotos ist fehlgeschlagen. Bitte versuche es erneut.", + "profileUpdated": "Profil aktualisiert", + "profileUpdatedMessage": "Deine Profilinformationen wurden erfolgreich gespeichert!", + "updateFailed": "Update fehlgeschlagen", + "updateFailedMessage": "Dein Profil konnte nicht aktualisiert werden. Bitte überprüfe deine Verbindung und versuche es erneut.", + "changePhoto": "Foto ändern", + "displayName": "Anzeigename", + "displayNamePlaceholder": "Gib deinen Anzeigenamen ein", + "timezone": "Zeitzone", + "timezonePlaceholder": "Wähle deine Zeitzone", + "save": "Speichern", + "cancel": "Abbrechen" + }, + "overview": { + "title": "Einstellungen", + "subtitle": "Passe deine Erfahrung an und verwalte deine Account-Einstellungen", + "upgrade": { + "title": "Auf Plus upgraden", + "description": "Schalte mächtige Funktionen frei, um deine Produktivität zu steigern", + "button": "Jetzt upgraden", + "features": { + "richText": "Rich-Text-Beschreibungen", + "notifications": "Aufgaben-Benachrichtigungen", + "apiIntegrations": "API-Integrationen", + "advancedAutomation": "Erweiterte Automatisierung" + } + }, + "sections": { + "profile": { + "title": "Profil-Einstellungen", + "description": "Aktualisiere deine Profilinformationen, Foto, Anzeigenamen und Zeitzonen-Einstellungen." + }, + "circle": { + "title": "Kreis-Einstellungen", + "description": "Verwalte deinen Kreis, lade Mitglieder ein und bearbeite Beitrittsanfragen." + }, + "account": { + "title": "Account-Einstellungen", + "description": "Verwalte dein Abonnement, ändere dein Passwort und Account-Löschoptionen." + }, + "subaccounts": { + "title": "Verwaltete Accounts", + "description": "Erstelle und verwalte Unter-Accounts zum Anmelden und Erledigen zugewiesener Aufgaben." + }, + "notifications": { + "title": "Benachrichtigungen", + "description": "Konfiguriere Push-Benachrichtigungen, E-Mail-Benachrichtigungen und Benachrichtigungsziele für Aufgaben." + }, + "mfa": { + "title": "Multi-Faktor-Authentifizierung", + "description": "Füge eine zusätzliche Sicherheitsebene mit MFA über Authenticator-Apps hinzu." + }, + "apitokens": { + "title": "API-Token", + "description": "Generiere und verwalte Zugriffstoken für Drittanbieter-Integrationen und API-Zugang." + }, + "storage": { + "title": "Speicher-Einstellungen", + "description": "Sichere und stelle deine Daten wieder her, verwalte lokalen Speicher und Synchronisierungseinstellungen." + }, + "sidepanel": { + "title": "Seitenleisten-Anpassung", + "description": "Passe das Layout und die Sichtbarkeit von Karten in der Seitenleisten-Oberfläche an." + }, + "theme": { + "title": "Theme-Einstellungen", + "description": "Wähle dein bevorzugtes Theme und konfiguriere Dunkel-/Hell-Modus-Einstellungen." + }, + "localization": { + "title": "Sprach- und Formateinstellungen", + "description": "Passe Sprache, Datumsformat, Zeitformat und regionale Einstellungen an." + }, + "advanced": { + "title": "Erweiterte Einstellungen", + "description": "Konfiguriere Webhooks, Echtzeit-Updates und andere erweiterte Funktionen für erhöhte Produktivität." + }, + "developer": { + "title": "Entwickler-Einstellungen", + "description": "Zeige technische Informationen über Authentifizierungs-Token, SSE-Verbindungen und Debug-Daten an." + } + } + } +} \ No newline at end of file diff --git a/public/locales/pt/chores.json b/public/locales/pt/chores.json new file mode 100644 index 0000000..7e4df50 --- /dev/null +++ b/public/locales/pt/chores.json @@ -0,0 +1,75 @@ +{ + "title": "Tarefas", + "myChores": "Minhas tarefas", + "allChores": "Todas as tarefas", + "addChore": "Adicionar tarefa", + "editChore": "Editar tarefa", + "deleteChore": "Excluir tarefa", + "completeChore": "Concluir tarefa", + "dueDate": "Data de vencimento", + "assignedTo": "Atribuída a", + "priority": "Prioridade", + "status": "Status", + "description": "Descrição", + "choreView": { + "assignment": "Atribuição", + "assigned": "Atribuída", + "last": "Última", + "schedule": "Agendamento", + "due": "Vence em", + "statistics": "Estatísticas", + "completed": "Concluída", + "times": "vezes", + "details": "Detalhes", + "createdBy": "Criada por", + "na": "N/D", + "taskCompleted": "Tarefa concluída", + "taskCompletedMessage": "Sua tarefa foi marcada como concluída", + "taskCompletionUndone": "A conclusão da tarefa foi desfeita.", + "taskSkipUndone": "O pulo da tarefa foi desfeito.", + "undoSuccessful": "Desfeito com sucesso", + "undoFailed": "Falha ao desfazer", + "undoFailedMessage": "Não foi possível desfazer a ação. Tente novamente.", + "resetTimer": "Reiniciar cronômetro", + "resetTimerConfirmation": "Tem certeza de que deseja reiniciar o cronômetro? Isso apagará todos os registros de tempo desde o início da tarefa.", + "clearAllTimeRecords": "Apagar todos os registros de tempo", + "clearAllTimeConfirmation": "Isso apagará permanentemente todos os cronômetros desta tarefa e a marcará como \"não iniciada\".", + "descriptionTitle": "Descrição", + "description": "Descrição :", + "previousNote": "Nota anterior", + "previousNoteLabel": "Nota anterior:", + "subtasksLabel": "Subtarefas :", + "taskActions": "Ações da tarefa", + "addNote": "Adicionar uma nota", + "additionalNotes": "Notas adicionais:", + "notePlaceholder": "Adicione uma nota sobre a conclusão...", + "setCustomCompletionTime": "Definir horário de conclusão personalizado", + "skipTask": "Pular tarefa", + "skipTaskConfirmation": "Tem certeza de que deseja pular esta tarefa?", + "markComplete": "Marcar como concluída", + "markAsDone": "Marcar como concluída", + "edit": "Editar", + "archive": "Arquivar", + "unarchive": "Desarquivar", + "viewHistory": "Ver histórico", + "history": "Histórico", + "startTimer": "Iniciar cronômetro", + "start": "Iniciar", + "pauseTimer": "Pausar cronômetro", + "approve": "Aprovar", + "reject": "Rejeitar", + "pendingApproval": "Aguardando aprovação", + "undo": "Desfazer", + "skip": "Pular", + "cancel": "Cancelar", + "noPriority": "Sem prioridade", + "subtasks": "Subtarefas", + "noDescription": "Nenhuma descrição disponível", + "timer": { + "active": "Cronômetro ativo", + "paused": "Cronômetro pausado", + "reset": "Reiniciar cronômetro", + "delete": "Excluir sessão" + } + } +} diff --git a/public/locales/pt/common.json b/public/locales/pt/common.json new file mode 100644 index 0000000..b7e0901 --- /dev/null +++ b/public/locales/pt/common.json @@ -0,0 +1,33 @@ +{ + "save": "Salvar", + "cancel": "Cancelar", + "delete": "Excluir", + "edit": "Editar", + "close": "Fechar", + "confirm": "Confirmar", + "loading": "Carregando...", + "error": "Erro", + "success": "Sucesso", + "warning": "Aviso", + "refresh": "Atualizar", + "copy": "Copiar", + "copied": "Copiado!", + "settings": "Configurações", + "yes": "Sim", + "no": "Não", + "back": "Voltar", + "backToCalendar": "Voltar ao calendário", + "logout": "Sair", + "version": "Versão", + "navigation": { + "allTasks": "Todas as tarefas", + "archived": "Arquivadas", + "things": "Itens", + "labels": "Etiquetas", + "projects": "Projetos", + "filters": "Filtros", + "activities": "Atividades", + "points": "Pontos", + "settings": "Configurações" + } +} diff --git a/public/locales/pt/settings.json b/public/locales/pt/settings.json new file mode 100644 index 0000000..fa7787f --- /dev/null +++ b/public/locales/pt/settings.json @@ -0,0 +1,174 @@ +{ + "title": "Configurações", + "circleSettings": { + "title": "Configurações do círculo", + "description": "Sua conta é conectada automaticamente a um círculo quando você cria ou entra em um. Convide amigos facilmente compartilhando o código ou link exclusivo do círculo abaixo. Você receberá uma notificação abaixo quando alguém solicitar entrar no seu círculo. Se quiser sair, basta clicar no botão \"Sair do círculo\".", + "circleCode": "Código do círculo", + "copyCode": "Copiar código", + "copyLink": "Copiar link", + "codeCopied": "Código do círculo copiado!", + "linkCopied": "Link do círculo copiado!", + "joinCircle": "Entrar em um círculo", + "joinCirclePlaceholder": "Digite o código do círculo", + "join": "Entrar", + "leave": "Sair do círculo", + "leaveConfirmTitle": "Sair do círculo", + "leaveConfirmMessage": "Tem certeza de que deseja sair deste círculo?", + "circleMembers": "Membros do círculo", + "circleMemberRequests": "Solicitações de entrada no círculo", + "admin": "Administrador", + "member": "Membro", + "pending": "Pendente", + "accept": "Aceitar", + "reject": "Rejeitar", + "makeAdmin": "Tornar administrador", + "makeMember": "Tornar membro", + "remove": "Remover", + "webhookURL": "URL do webhook", + "webhookDescription": "Digite uma URL de webhook para receber notificações de eventos do círculo", + "webhookPlaceholder": "https://sua-url-de-webhook.com" + }, + "accountSettings": { + "title": "Configurações da conta", + "subscription": "Assinatura", + "subscriptionStatus": "Plano atual", + "free": "Gratuito", + "plus": "Plus", + "upgrade": "Fazer upgrade", + "cancel": "Cancelar", + "changePassword": "Alterar senha", + "password": "Senha", + "dangerZone": "Zona de perigo", + "dangerZoneDescription": "Após excluir sua conta, não há como voltar atrás. Tenha certeza antes de confirmar.", + "deleteAccount": "Excluir conta" + }, + "localization": { + "title": "Localização", + "description": "Personalize idioma, formato de data e preferências regionais da sua conta.", + "language": "Idioma", + "languageDescription": "Selecione seu idioma preferido", + "dateFormat": "Formato de data", + "dateFormatDescription": "Escolha como as datas devem ser exibidas no aplicativo", + "timeFormat": "Formato de hora", + "timeFormatDescription": "Selecione o formato de 12 ou 24 horas", + "12hour": "12 horas (AM/PM)", + "24hour": "24 horas", + "firstDayOfWeek": "Primeiro dia da semana", + "firstDayOfWeekDescription": "Selecione com qual dia sua semana começa", + "sunday": "Domingo", + "monday": "Segunda-feira", + "saturday": "Sábado", + "formats": { + "mdy": "MM/DD/AAAA (EUA)", + "dmy": "DD/MM/AAAA (Europa)", + "ymd": "AAAA-MM-DD (ISO)", + "long": "Formato longo (ex.: 1 de janeiro de 2024)", + "short": "Formato curto (ex.: 1 de jan de 2024)" + } + }, + "sidepanel": { + "title": "Personalização do painel lateral", + "description": "Personalize o layout e a visibilidade dos cartões no painel lateral. Esta seção está disponível apenas em dispositivos com telas grandes, como tablets e computadores." + }, + "theme": { + "title": "Preferências de tema", + "description": "Escolha a aparência do site. Selecione um único tema ou sincronize com o sistema para alternar automaticamente entre os temas claro e escuro.", + "themeMode": "Modo do tema", + "light": "Claro", + "dark": "Escuro", + "system": "Sistema" + }, + "notifications": { + "settingsSaved": "Configurações salvas com sucesso", + "settingsSaveFailed": "Falha ao salvar as configurações", + "invalidWebhook": "URL de webhook inválida" + }, + "profile": { + "title": "Configurações do perfil", + "description": "Atualize seu nome de exibição e foto de perfil.", + "photoUpdated": "Foto atualizada", + "photoUpdatedMessage": "Sua foto de perfil foi atualizada com sucesso!", + "uploadFailed": "Falha no envio", + "uploadFailedMessage": "Falha ao enviar sua foto. Tente novamente.", + "profileUpdated": "Perfil atualizado", + "profileUpdatedMessage": "As informações do seu perfil foram salvas com sucesso!", + "updateFailed": "Falha na atualização", + "updateFailedMessage": "Não foi possível atualizar seu perfil. Verifique sua conexão e tente novamente.", + "changePhoto": "Alterar foto", + "displayName": "Nome de exibição", + "displayNamePlaceholder": "Digite seu nome de exibição", + "timezone": "Fuso horário", + "timezonePlaceholder": "Selecione seu fuso horário", + "save": "Salvar", + "cancel": "Cancelar" + }, + "overview": { + "title": "Configurações", + "subtitle": "Personalize sua experiência e gerencie as preferências da sua conta", + "upgrade": { + "title": "Faça upgrade para o Plus", + "description": "Desbloqueie recursos poderosos para aumentar sua produtividade", + "button": "Fazer upgrade agora", + "features": { + "richText": "Descrições com texto formatado", + "notifications": "Notificações de tarefas", + "apiIntegrations": "Integrações de API", + "advancedAutomation": "Automação avançada" + } + }, + "sections": { + "profile": { + "title": "Configurações do perfil", + "description": "Atualize as informações do seu perfil, foto, nome de exibição e preferências de fuso horário." + }, + "circle": { + "title": "Configurações do círculo", + "description": "Gerencie seu círculo, convide membros e cuide das solicitações de entrada." + }, + "account": { + "title": "Configurações da conta", + "description": "Gerencie sua assinatura, altere a senha e as opções de exclusão de conta." + }, + "subaccounts": { + "title": "Contas gerenciadas", + "description": "Crie e gerencie subcontas para fazer login e concluir tarefas atribuídas." + }, + "notifications": { + "title": "Notificações", + "description": "Configure notificações push, alertas por e-mail e destinos de notificação para tarefas." + }, + "mfa": { + "title": "Autenticação multifator", + "description": "Adicione uma camada extra de segurança com MFA usando aplicativos autenticadores." + }, + "apitokens": { + "title": "Tokens de API", + "description": "Gere e gerencie tokens de acesso para integrações de terceiros e acesso à API." + }, + "storage": { + "title": "Configurações de armazenamento", + "description": "Faça backup e restauração dos seus dados, gerencie o armazenamento local e as preferências de sincronização." + }, + "sidepanel": { + "title": "Personalização do painel lateral", + "description": "Personalize o layout e a visibilidade dos cartões na interface do painel lateral." + }, + "theme": { + "title": "Preferências de tema", + "description": "Escolha seu tema preferido e configure o modo claro/escuro." + }, + "localization": { + "title": "Localização", + "description": "Personalize idioma, formato de data, formato de hora e preferências regionais." + }, + "advanced": { + "title": "Configurações avançadas", + "description": "Configure webhooks, atualizações em tempo real e outros recursos avançados para mais produtividade." + }, + "developer": { + "title": "Configurações de desenvolvedor", + "description": "Veja informações técnicas sobre tokens de autenticação, conexões SSE e dados de depuração." + } + } + } +} diff --git a/src/App.jsx b/src/App.jsx index 7eeb5c6..d8ef454 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,14 +1,18 @@ import NavBar from '@/views/components/NavBar' import { Button, Typography, useColorScheme } from '@mui/joy' -import Tracker from '@openreplay/tracker' import { useCallback, useEffect } from 'react' import { Outlet } from 'react-router-dom' import { useRegisterSW } from 'virtual:pwa-register/react' import { registerCapacitorListeners } from './CapacitorListener' import PageTransition from './components/animations/PageTransition' import { ImpersonateUserProvider } from './contexts/ImpersonateUserContext' -import SSEProvider from './contexts/SSEContext' import { AuthProvider } from './hooks/useAuth.jsx' + +import useStatusBar from './hooks/useStatusBar' +import { useResource } from './queries/ResourceQueries' +import './styles/safe-area.css' + +import SSEProvider from './contexts/SSEContext' import { useNotification } from './service/NotificationProvider' import { useSyncOnReconnect } from './hooks/useSyncOnReconnect' @@ -25,19 +29,16 @@ const remove = className => { // TODO: Update the interval to at 60 minutes const intervalMS = 5 * 60 * 1000 // 5 minutes -const startOpenReplay = () => { - if (!import.meta.env.VITE_OPENREPLAY_PROJECT_KEY) return - const tracker = new Tracker({ - projectKey: import.meta.env.VITE_OPENREPLAY_PROJECT_KEY, - }) - tracker.start() -} - const AppContent = () => { const { showNotification } = useNotification() useSyncOnReconnect() + // Initialize status bar with theme-aware configuration + useStatusBar() + + const { + offlineReady: [offlineReady, setOfflineReady], // eslint-disable-line no-unused-vars needRefresh: [needRefresh, setNeedRefresh], updateServiceWorker, } = useRegisterSW({ @@ -96,10 +97,11 @@ const AppContent = () => { } function App() { - // startOpenReplay() - + const resource = useResource() // eslint-disable-line no-unused-vars const { mode, systemMode } = useColorScheme() + // startOpenReplay() + const setThemeClass = useCallback(() => { const value = JSON.parse(localStorage.getItem('themeMode')) || mode @@ -126,7 +128,7 @@ function App() { }, []) return ( - <> +
@@ -134,7 +136,7 @@ function App() { - +
) } diff --git a/src/CapacitorListener.js b/src/CapacitorListener.js index 32bd343..c8fdf21 100644 --- a/src/CapacitorListener.js +++ b/src/CapacitorListener.js @@ -8,6 +8,35 @@ import { PushNotifications } from '@capacitor/push-notifications' import { focusManager } from '@tanstack/react-query' import { RegisterDeviceToken } from './utils/Fetcher' +// NFC chore deep link: donetick://chores/123?auto_complete=true +const handleNFCChoreDeepLink = url => { + try { + const urlObj = new URL(url) + // donetick://chores/123 → host='chores', pathname='/123' + const choreId = urlObj.pathname.slice(1) + const autoComplete = urlObj.searchParams.get('auto_complete') + const path = `/chores/${choreId}${autoComplete ? '?auto_complete=' + autoComplete : ''}` + + // getLaunchUrl() persists across every WebView reload caused by window.location.href. + // If we're already on the target page, skip to avoid an infinite reload loop. + if (window.location.pathname + window.location.search === path) return + + console.log('[NFC] navigating to', path) + window.location.href = path + } catch (error) { + console.error('[NFC] Error handling chore deep link:', error) + } +} + +const handleUrlOpen = url => { + console.log('[NFC] handleUrlOpen:', url) + if (url.startsWith('donetick://chores/')) { + handleNFCChoreDeepLink(url) + } else if (url.startsWith('donetick://auth/')) { + handleOAuthDeepLink(url) + } +} + // OAuth callback handler for deep links const handleOAuthDeepLink = async url => { console.log('OAuth deep link received:', url) @@ -215,16 +244,20 @@ const registerCapacitorListeners = () => { return } localNotificationListenerRegistration() - - // Register deep link handler for OAuth and other deep links - mobileApp.addListener('appUrlOpen', event => { - console.log('App URL opened:', event.url) - - // Handle OAuth callback - if (event.url.startsWith('donetick://auth/')) { - handleOAuthDeepLink(event.url) + + // Cold-start: app was launched by tapping an NFC tag (or other deep link) + mobileApp.getLaunchUrl().then(result => { + if (result?.url) { + console.log('[NFC] getLaunchUrl:', result.url) + handleUrlOpen(result.url) } }) + + // Foreground / singleTask resume: app was already running when the tag was tapped + mobileApp.addListener('appUrlOpen', event => { + console.log('[NFC] appUrlOpen:', event.url) + handleUrlOpen(event.url) + }) mobileApp.addListener('appStateChange', ({ isActive }) => { focusManager.setFocused(isActive) @@ -233,6 +266,9 @@ const registerCapacitorListeners = () => { mobileApp.addListener('backButton', ({ canGoBack }) => { if (canGoBack) { window.history.back() + } else if (window.location.pathname !== '/') { + // No history (e.g. app launched directly to a chore via NFC) — go home + window.location.href = '/' } else { mobileApp.exitApp() } diff --git a/src/components/NotificationTemplate.jsx b/src/components/NotificationTemplate.jsx index 734fd0b..9f468fa 100644 --- a/src/components/NotificationTemplate.jsx +++ b/src/components/NotificationTemplate.jsx @@ -12,7 +12,7 @@ import Input from '@mui/joy/Input' import Option from '@mui/joy/Option' import Select from '@mui/joy/Select' import Typography from '@mui/joy/Typography' -import { useCallback, useEffect, useState, useRef } from 'react' +import { useCallback, useEffect, useRef, useState } from 'react' import { NOTIFICATION_TYPE, TASK_COLOR } from '../utils/Colors' import { TIME_UNITS } from '../utils/DurationUtils' @@ -512,6 +512,7 @@ const NotificationTemplate = ({ '--Badge-fontSize': '0.7rem', '--Badge-paddingX': '5px', top: 10, + left: 10, '& .MuiBadge-badge': { background: colors.bgColor, color: 'white', diff --git a/src/components/UserProfileAvatar.jsx b/src/components/UserProfileAvatar.jsx index 0cfd165..e306c99 100644 --- a/src/components/UserProfileAvatar.jsx +++ b/src/components/UserProfileAvatar.jsx @@ -32,7 +32,7 @@ import { useImpersonateUser } from '../contexts/ImpersonateUserContext' import useStickyState from '../hooks/useStickyState' import { useCircleMembers, useUserProfile } from '../queries/UserQueries' import { apiClient } from '../utils/ApiClient' -import { isPlusAccount } from '../utils/Helpers' +import { isPlusAccount, resolvePhotoURL } from '../utils/Helpers' import UserModal from '../views/Modals/Inputs/UserModal' import SubscriptionModal from './SubscriptionModal' @@ -116,7 +116,7 @@ const UserProfileAvatar = () => { {isImpersonating ? ( { }} /> { ) : ( { + {title && ( {title} diff --git a/src/components/common/FilterBar.jsx b/src/components/common/FilterBar.jsx new file mode 100644 index 0000000..6f221e1 --- /dev/null +++ b/src/components/common/FilterBar.jsx @@ -0,0 +1,506 @@ +import { Check, FilterList, Tune } from '@mui/icons-material' +import { + Avatar, + Badge, + Box, + Button, + Chip, + Divider, + Input, + Typography, +} from '@mui/joy' +import { useState } from 'react' +import BottomSheetModal from './BottomSheetModal' +import ActiveFilterChips from './filter/ActiveFilterChips' + +/** + * Reusable filter bar component. + * + * Props: + * filterDefs - array of filter definitions: + * { id, label, type ('multi-select'|'single-select'|'boolean'|'date-range'), + * icon, options?, defaultValue?, filterFn } + * options item: { value, label, color?, icon?, avatar? } + * defaultValue: if the active value equals this, no chip is shown + * date-range value shape: { preset?, from?: ISO string, to?: ISO string } + * activeFilters - current filter state object { [id]: value } + * onSetFilter - (filterId, value | null) => void + * onClearAll - () => void + * resultCount - optional number shown in "Show N results" button + * totalCount - optional total for "N of M" label + */ + +// ── Date range presets (no moment dependency — pure Date) ──────────────────── + +const d = (date, h = 0, m = 0, s = 0, ms = 0) => + new Date(date.getFullYear(), date.getMonth(), date.getDate(), h, m, s, ms) + +const DATE_RANGE_PRESETS = [ + { + value: 'today', + label: 'Today', + getRange: () => { + const t = d(new Date()) + return { from: t.toISOString(), to: d(new Date(), 23, 59, 59, 999).toISOString() } + }, + }, + { + value: 'yesterday', + label: 'Yesterday', + getRange: () => { + const t = d(new Date()) + const y = new Date(t); y.setDate(t.getDate() - 1) + return { from: d(y).toISOString(), to: d(y, 23, 59, 59, 999).toISOString() } + }, + }, + { + value: 'this-week', + label: 'This Week', + getRange: () => { + const t = d(new Date()) + const start = new Date(t); start.setDate(t.getDate() - t.getDay()) + const end = new Date(start); end.setDate(start.getDate() + 6) + return { from: d(start).toISOString(), to: d(end, 23, 59, 59, 999).toISOString() } + }, + }, + { + value: 'last-7-days', + label: 'Last 7 Days', + getRange: () => { + const t = d(new Date()) + const start = new Date(t); start.setDate(t.getDate() - 6) + return { from: d(start).toISOString(), to: d(new Date(), 23, 59, 59, 999).toISOString() } + }, + }, + { + value: 'this-month', + label: 'This Month', + getRange: () => { + const n = new Date() + const start = new Date(n.getFullYear(), n.getMonth(), 1) + const end = new Date(n.getFullYear(), n.getMonth() + 1, 0) + return { from: start.toISOString(), to: d(end, 23, 59, 59, 999).toISOString() } + }, + }, + { + value: 'last-30-days', + label: 'Last 30 Days', + getRange: () => { + const t = d(new Date()) + const start = new Date(t); start.setDate(t.getDate() - 29) + return { from: d(start).toISOString(), to: d(new Date(), 23, 59, 59, 999).toISOString() } + }, + }, + { + value: 'last-3-months', + label: 'Last 3 Months', + getRange: () => { + const t = d(new Date()) + const start = new Date(t); start.setMonth(t.getMonth() - 3) + return { from: d(start).toISOString(), to: d(new Date(), 23, 59, 59, 999).toISOString() } + }, + }, +] + +const toInputDate = iso => (iso ? iso.split('T')[0] : '') + +const fmtDisplayDate = iso => { + if (!iso) return null + const dt = new Date(iso) + return dt.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) +} + +// ── Component ──────────────────────────────────────────────────────────────── + +const FilterBar = ({ + filterDefs, + activeFilters, + onSetFilter, + onClearAll, + resultCount, + totalCount, +}) => { + const [isOpen, setIsOpen] = useState(false) + + // ── Active count ─────────────────────────────────────────────────────────── + + const activeFilterCount = filterDefs.filter(def => { + const value = activeFilters[def.id] + if (value === undefined || value === null) return false + if (def.defaultValue !== undefined && value === def.defaultValue) return false + if (Array.isArray(value) && value.length === 0) return false + if (def.type === 'date-range') return !!(value?.from || value?.to) + return true + }).length + + const hasActive = activeFilterCount > 0 + + const selectableChipSx = { + cursor: 'pointer', + transition: 'all 0.15s ease', + userSelect: 'none', + alignItems: 'center', + '& .MuiChip-startDecorator': { + display: 'flex', + alignItems: 'center', + mr: 0.5, + }, + '& .MuiChip-label': { + lineHeight: 1.2, + }, + '&:hover': { opacity: 0.85 }, + } + + const sectionBadgeChipSx = { + ml: 'auto', + fontSize: '0.7rem', + minHeight: 22, + py: 0.25, + px: 0.75, + alignItems: 'center', + '& .MuiChip-label': { + lineHeight: 1.2, + px: 0, + }, + } + + const modalCountChipSx = { + ml: 0.5, + minHeight: 22, + py: 0.25, + px: 0.75, + alignItems: 'center', + '& .MuiChip-label': { + lineHeight: 1.2, + px: 0, + }, + } + + // ── Chip labels for inline bar ───────────────────────────────────────────── + + const getActiveChipLabel = def => { + const value = activeFilters[def.id] + if (value === undefined || value === null) return null + + if (def.type === 'single-select') { + if (def.defaultValue !== undefined && value === def.defaultValue) return null + return def.options?.find(o => o.value === value)?.label ?? def.label + } + + if (def.type === 'boolean') return def.label + + if (def.type === 'multi-select' && Array.isArray(value) && value.length > 0) { + if (value.length === 1) { + return def.options?.find(o => o.value === value[0])?.label ?? def.label + } + return `${def.label} (${value.length})` + } + + if (def.type === 'date-range') { + if (!value?.from && !value?.to) return null + if (value.preset) { + return DATE_RANGE_PRESETS.find(p => p.value === value.preset)?.label ?? 'Date Range' + } + const from = fmtDisplayDate(value.from) + const to = fmtDisplayDate(value.to) + if (from && to) return `${from} – ${to}` + if (from) return `From ${from}` + if (to) return `Until ${to}` + return null + } + + return null + } + + // ── Handlers ─────────────────────────────────────────────────────────────── + + const handleMultiToggle = (defId, optValue) => { + const current = activeFilters[defId] || [] + const next = current.includes(optValue) + ? current.filter(v => v !== optValue) + : [...current, optValue] + onSetFilter(defId, next.length > 0 ? next : null) + } + + const handleSingleToggle = (defId, optValue) => { + onSetFilter(defId, activeFilters[defId] === optValue ? null : optValue) + } + + const handleBoolToggle = defId => { + onSetFilter(defId, activeFilters[defId] ? null : true) + } + + const handleDateRangePreset = (defId, presetValue) => { + const current = activeFilters[defId] || {} + if (current.preset === presetValue) { + onSetFilter(defId, null) + return + } + const preset = DATE_RANGE_PRESETS.find(p => p.value === presetValue) + onSetFilter(defId, { preset: presetValue, ...preset.getRange() }) + } + + const handleDateRangeInput = (defId, field, dateStr) => { + const current = activeFilters[defId] || {} + if (!dateStr) { + const next = { ...current, preset: null, [field]: null } + onSetFilter(defId, next.from || next.to ? next : null) + } else { + const iso = + field === 'to' + ? new Date(dateStr + 'T23:59:59').toISOString() + : new Date(dateStr + 'T00:00:00').toISOString() + onSetFilter(defId, { ...current, preset: null, [field]: iso }) + } + } + + // ── Render ───────────────────────────────────────────────────────────────── + + return ( + <> + {/* ── Inline bar ─────────────────────────────────────── */} + + + + + + ({ def, label: getActiveChipLabel(def) })) + .filter(({ label }) => !!label) + .map(({ def, label }) => ({ + key: def.id, + label, + onClear: () => onSetFilter(def.id, null), + }))} + onOpen={() => setIsOpen(true)} + onClearAll={hasActive ? onClearAll : undefined} + resultCount={hasActive ? resultCount : undefined} + totalCount={hasActive ? totalCount : undefined} + maxVisible={2} + chipSize='md' + /> + + + {/* ── Bottom sheet ────────────────────────────────────── */} + setIsOpen(false)} + title={ + + + Filters + {hasActive && ( + + {activeFilterCount} + + )} + + } + footer={ + + + + + } + > + + {filterDefs.map((def, idx) => ( + + {idx > 0 && } + + {/* Section header */} + + {def.icon && ( + + {def.icon} + + )} + + {def.label} + + + {/* active badge in header */} + {def.type === 'multi-select' && (activeFilters[def.id]?.length ?? 0) > 0 && ( + + {activeFilters[def.id].length} selected + + )} + {def.type === 'single-select' && activeFilters[def.id] != null && (() => { + const opt = def.options?.find(o => o.value === activeFilters[def.id]) + return opt ? ( + + {opt.label} + + ) : null + })()} + {def.type === 'date-range' && getActiveChipLabel(def) && ( + + {getActiveChipLabel(def)} + + )} + + + {/* multi-select */} + {def.type === 'multi-select' && ( + + {def.options?.map(opt => { + const isSelected = (activeFilters[def.id] || []).includes(opt.value) + return ( + + ) : isSelected ? ( + + ) : (opt.icon ?? null) + } + onClick={() => handleMultiToggle(def.id, opt.value)} + sx={selectableChipSx} + > + {opt.label} + + ) + })} + + )} + + {/* single-select */} + {def.type === 'single-select' && ( + + {def.options?.map(opt => { + const isSelected = activeFilters[def.id] === opt.value + return ( + + ) : isSelected ? ( + + ) : (opt.icon ?? null) + } + onClick={() => handleSingleToggle(def.id, opt.value)} + sx={selectableChipSx} + > + {opt.label} + + ) + })} + + )} + + {/* boolean */} + {def.type === 'boolean' && ( + : null} + onClick={() => handleBoolToggle(def.id)} + sx={selectableChipSx} + > + {def.label} + + )} + + {/* date-range */} + {def.type === 'date-range' && (() => { + const val = activeFilters[def.id] || {} + return ( + + {/* Preset chips */} + + {DATE_RANGE_PRESETS.map(preset => { + const isSelected = val.preset === preset.value + return ( + : null} + onClick={() => handleDateRangePreset(def.id, preset.value)} + sx={selectableChipSx} + > + {preset.label} + + ) + })} + + + {/* Custom date inputs */} + + handleDateRangeInput(def.id, 'from', e.target.value)} + slotProps={{ input: { max: toInputDate(val.to) || undefined } }} + sx={{ flex: 1, fontSize: '0.8rem' }} + /> + + – + + handleDateRangeInput(def.id, 'to', e.target.value)} + slotProps={{ input: { min: toInputDate(val.from) || undefined } }} + sx={{ flex: 1, fontSize: '0.8rem' }} + /> + + + ) + })()} + + ))} + + + + ) +} + +export default FilterBar diff --git a/src/components/common/filter/ActiveFilterChips.jsx b/src/components/common/filter/ActiveFilterChips.jsx new file mode 100644 index 0000000..4e06220 --- /dev/null +++ b/src/components/common/filter/ActiveFilterChips.jsx @@ -0,0 +1,131 @@ +import { Close } from '@mui/icons-material' +import { Box, Button, Chip, Typography } from '@mui/joy' + +const ActiveFilterChips = ({ + chips = [], + onOpen, + onClearAll, + resultCount, + totalCount, + maxVisible = 2, + chipSize = 'md', + clearButtonSize = 'sm', + clearButtonSx, + containerSx, + chipSx, + overflowChipSx, + resultSx, +}) => { + if (!chips.length) { + return null + } + + const visible = chips.slice(0, maxVisible) + const overflow = chips.length - maxVisible + + return ( + + {visible.map(({ key, label, onClear, color = 'primary' }) => ( + { + e.stopPropagation() + onClear?.() + }} + /> + } + onClick={onOpen} + sx={{ + cursor: 'pointer', + flexShrink: 0, + transition: 'all 0.15s ease', + alignItems: 'center', + '& .MuiChip-endDecorator': { + display: 'flex', + alignItems: 'center', + ml: 0.5, + }, + '& .MuiChip-label': { + lineHeight: 1.2, + }, + '&:hover': { opacity: 0.85 }, + ...chipSx, + }} + > + {label} + + ))} + + {overflow > 0 && ( + + +{overflow} more + + )} + + {resultCount != null && totalCount != null && ( + + {resultCount} / {totalCount} + + )} + + {onClearAll && ( + + )} + + ) +} + +export default ActiveFilterChips diff --git a/src/contexts/LocalizationContext.jsx b/src/contexts/LocalizationContext.jsx index 3172400..c993b85 100644 --- a/src/contexts/LocalizationContext.jsx +++ b/src/contexts/LocalizationContext.jsx @@ -21,11 +21,13 @@ export const TIME_FORMATS = { export const RTL_LANGUAGES = ['ar', 'he', 'fa', 'ur'] export const AVAILABLE_LANGUAGES = [ + { code: 'de', name: 'German', nativeName: 'Deutsch' }, { code: 'en', name: 'English', nativeName: 'English' }, { code: 'es', name: 'Spanish', nativeName: 'Español' }, { code: 'fr', name: 'French', nativeName: 'Français' }, { code: 'nl', name: 'Dutch', nativeName: 'Nederlands' }, { code: 'ja', name: 'Japanese', nativeName: '日本語' }, + { code: 'pt', name: 'Portuguese (Brazil)', nativeName: 'Português (Brasil)' }, ] export const LocalizationProvider = ({ children }) => { diff --git a/src/hooks/NetworkManager.jsx b/src/hooks/NetworkManager.jsx index 65aafa8..3a5894c 100644 --- a/src/hooks/NetworkManager.jsx +++ b/src/hooks/NetworkManager.jsx @@ -1,47 +1,83 @@ import { Network } from '@capacitor/network' +import { isOfflineFeatureEnabled } from '../utils/OfflineFeatureToggle' class NetworkManager { constructor() { - this.isOnline = true - this.isNetworkOn = null - this.init() + this.deviceOnline = true + this.serverReachable = true + this.offlineReason = null // 'device' | 'server' | null this.connectionStatusListeners = [] this.queueSyncListeners = [] this.lastChecked = null this.offlineSince = null + this.init() } + + // Effective online status: both device network AND server must be reachable + get isOnline() { + return this.deviceOnline && this.serverReachable + } + + // Alias for backward compatibility (DeveloperSettings uses this) + get isNetworkOn() { + return this.deviceOnline + } + async init() { const status = await Network.getStatus() - this.isNetworkOn = status.connected + this.deviceOnline = status.connected this.lastChecked = Date.now() + if (!status.connected) { + this.offlineReason = 'device' + this.offlineSince = Date.now() + } Network.addListener('networkStatusChange', status => { - if (this.isNetworkOn !== status.connected) { - this.isNetworkOn = status.connected + if (this.deviceOnline !== status.connected) { + this.deviceOnline = status.connected this.lastChecked = Date.now() - this.isOnline = status.connected + if (!status.connected) { + this.offlineReason = 'device' this.offlineSince = Date.now() + } else { + // Device came back online — update reason based on server state + this.offlineReason = this.serverReachable ? null : 'server' } this.notifyConnectionStatus() } }) } - setOffline() { - if (this.isOnline === true) { - this.isOnline = false + // Called when a fetch() response is received (any HTTP status = server is up) + setServerReachable() { + if (!this.serverReachable) { + this.serverReachable = true + this.offlineReason = this.deviceOnline ? null : 'device' this.notifyConnectionStatus() - this.offlineSince = Date.now() // Record the time when we went offline } } - setOnline() { - if (this.isOnline === false) { - this.isOnline = true + + // Called when fetch() throws a network error (server unreachable) + // Only takes effect when offline mode is enabled + setServerUnreachable() { + if (!isOfflineFeatureEnabled()) return + if (this.serverReachable) { + this.serverReachable = false + this.offlineReason = 'server' + this.offlineSince = Date.now() this.notifyConnectionStatus() } } + // Legacy methods kept for compatibility + setOffline() { + this.setServerUnreachable() + } + setOnline() { + this.setServerReachable() + } + notifyConnectionStatus() { this.connectionStatusListeners.forEach(callback => { callback(this.isOnline) @@ -63,7 +99,6 @@ class NetworkManager { ) } registerBackendSyncListener(callback) { - // if callback is not in the list already, add it if (!this.queueSyncListeners.includes(callback)) { this.queueSyncListeners.push(callback) } diff --git a/src/hooks/useAuth.jsx b/src/hooks/useAuth.jsx index 4154abb..6fcc744 100644 --- a/src/hooks/useAuth.jsx +++ b/src/hooks/useAuth.jsx @@ -39,7 +39,7 @@ export const AuthProvider = ({ children }) => { // Ensure apiClient is initialized with the correct URL await apiClient.init() const currentBaseURL = apiClient.getApiURL() - + const isNative = typeof window !== 'undefined' && window.Capacitor?.isNativePlatform?.() @@ -57,8 +57,8 @@ export const AuthProvider = ({ children }) => { const response = await fetch(`${currentBaseURL}/auth/login`, config) if (!response.ok) { - const error = await response.json() - return { success: false, error: error.message || 'Login failed' } + const res = await response.json() + return { success: false, error: res?.error || 'Login failed' } } const data = await response.json() diff --git a/src/hooks/useDocumentScanner.js b/src/hooks/useDocumentScanner.js new file mode 100644 index 0000000..ff66e9b --- /dev/null +++ b/src/hooks/useDocumentScanner.js @@ -0,0 +1,50 @@ +import { Capacitor } from '@capacitor/core' + +/** + * Normalizes a raw image string from the native document scanner into a + * format that can be used as an src and passed to Tesseract.js. + * + * Android returns file:// or absolute paths → convert via Capacitor.convertFileSrc + * iOS returns raw base64 (no data: prefix) → prepend the data URI scheme + */ +function normalizeScannedImage(raw) { + if (!raw) return null + if (raw.startsWith('data:')) return raw + if (raw.startsWith('http://') || raw.startsWith('https://') || raw.startsWith('content://')) return raw + if (raw.startsWith('/') || raw.startsWith('file://')) return Capacitor.convertFileSrc(raw) + // iOS base64 without prefix + return `data:image/jpeg;base64,${raw}` +} + +/** + * Hook for native document scanning via @capgo/capacitor-document-scanner. + * + * On native: opens the OS document scanner (edge detection, perspective correction). + * On web: `scanDocument` returns null — callers should fall back to their own camera UI. + */ +export function useDocumentScanner() { + const isNativeScanner = Capacitor.isNativePlatform() + + const scanDocument = async ({ maxDocuments = 1, quality = 90, letUserAdjustCrop = true } = {}) => { + if (!isNativeScanner) return { image: null, cancelled: false } + + try { + const { DocumentScanner } = await import('@capgo/capacitor-document-scanner') + const { scannedImages } = await DocumentScanner.scanDocument({ + croppedImageQuality: quality, + maxNumDocuments: maxDocuments, + letUserAdjustCrop, + }) + + if (!scannedImages?.length) return { image: null, cancelled: true } + + const normalized = normalizeScannedImage(scannedImages[0]) + return { image: normalized, cancelled: false } + } catch (e) { + console.error('[DocumentScanner] scan failed:', e) + return { image: null, cancelled: false, error: e.message } + } + } + + return { isNativeScanner, scanDocument } +} diff --git a/src/hooks/useFileUpload.js b/src/hooks/useFileUpload.js new file mode 100644 index 0000000..e44329e --- /dev/null +++ b/src/hooks/useFileUpload.js @@ -0,0 +1,92 @@ +import imageCompression from 'browser-image-compression' +import { useCallback } from 'react' +import { useUserProfile } from '../queries/UserQueries' +import { useNotification } from '../service/NotificationProvider' +import { apiClient } from '../utils/ApiClient' +import { isPlusAccount, resolvePhotoURL } from '../utils/Helpers' + +export const useFileUpload = ({ entityType = 'chore_attachment', entityId, draftId } = {}) => { + const { showError } = useNotification() + const { data: userProfile } = useUserProfile() + + const uploadFile = useCallback( + async file => { + if (!isPlusAccount(userProfile)) { + showError({ + title: 'Plus Feature', + message: + 'Image uploads are not available in the Basic plan. Upgrade to Plus to add images to your content.', + }) + return null + } + + try { + const compressionOptions = { + maxSizeMB: entityType === 'profile' ? 0.5 : 1, + maxWidthOrHeight: entityType === 'profile' ? 320 : 1200, + useWebWorker: true, + fileType: 'image/jpeg', + } + + const compressedFile = await imageCompression(file, compressionOptions) + const compressedJpegFile = new File( + [compressedFile], + `${file.name.split('.')[0]}.jpg`, + { type: 'image/jpeg' }, + ) + + const formData = new FormData() + formData.append('file', compressedJpegFile) + formData.append('entityType', entityType) + if (entityId) formData.append('entityId', String(entityId)) + if (draftId) formData.append('draftId', draftId) + + const response = await apiClient.upload('/assets/chore', formData) + + if (response.status === 507) { + showError({ + title: 'Storage Quota Exceeded', + message: 'You have exceeded your quota for uploading files.', + }) + return null + } else if (response.status === 413) { + showError({ + title: 'File Too Large', + message: 'The file you are trying to upload is too large.', + }) + return null + } else if (response.status === 403 && !isPlusAccount(userProfile)) { + showError({ + title: 'Upgrade Required', + message: 'Image uploads are only available for Plus accounts.', + }) + return null + } else if (response.status === 403) { + showError({ + title: 'Permission Denied', + message: 'You do not have permission to upload files.', + }) + return null + } else if (!response.ok) { + showError({ + title: 'Upload Failed', + message: 'Failed to upload image.', + }) + return null + } + + const data = await response.json() + return resolvePhotoURL(data.url || data.sign) + } catch { + showError({ + title: 'Upload Failed', + message: 'An error occurred while processing the image.', + }) + return null + } + }, + [entityType, entityId, draftId, showError, userProfile], + ) + + return { uploadFile, isPlus: isPlusAccount(userProfile) } +} diff --git a/src/hooks/useFilter.js b/src/hooks/useFilter.js new file mode 100644 index 0000000..18527de --- /dev/null +++ b/src/hooks/useFilter.js @@ -0,0 +1,59 @@ +import { useMemo, useState } from 'react' + +/** + * Generic client-side filter hook. + * + * @param {Array} data - the full list to filter + * @param {Array} filterDefs - array of filter definitions (see FilterBar) + * @returns {{ filteredData, activeFilters, setFilter, clearAll, activeFilterCount, hasActiveFilters }} + * + * Each filterDef must include: + * id - unique string key + * type - 'multi-select' | 'boolean' + * filterFn - (item, filterValue) => boolean + */ +export const useFilter = (data, filterDefs) => { + const [activeFilters, setActiveFilters] = useState({}) + + const setFilter = (filterId, value) => { + setActiveFilters(prev => { + const isEmpty = + value === null || + value === undefined || + (Array.isArray(value) && value.length === 0) + + if (isEmpty) { + const { [filterId]: _removed, ...rest } = prev + return rest + } + return { ...prev, [filterId]: value } + }) + } + + const clearAll = () => setActiveFilters({}) + + const filteredData = useMemo(() => { + if (!data) return [] + if (!Object.keys(activeFilters).length) return data + + return data.filter(item => + filterDefs.every(def => { + const value = activeFilters[def.id] + if (value === undefined || value === null) return true + if (Array.isArray(value) && value.length === 0) return true + return def.filterFn(item, value) + }), + ) + }, [data, activeFilters, filterDefs]) + + const activeFilterCount = Object.keys(activeFilters).length + + return { + filteredData, + activeFilters, + setFilter, + clearAll, + activeFilterCount, + hasActiveFilters: activeFilterCount > 0, + } +} diff --git a/src/hooks/useStatusBar.js b/src/hooks/useStatusBar.js new file mode 100644 index 0000000..9075adc --- /dev/null +++ b/src/hooks/useStatusBar.js @@ -0,0 +1,56 @@ +import { useColorScheme } from '@mui/joy' +import { useEffect } from 'react' +import statusBarManager from '../utils/StatusBarManager' + +/** + * Custom hook to manage status bar integration with Joy UI themes + * This hook automatically syncs the status bar style with the current theme + */ +export const useStatusBar = () => { + const { mode, systemMode } = useColorScheme() + + useEffect(() => { + // Initialize status bar on mount + const initializeStatusBar = async () => { + await statusBarManager.initialize(mode) + } + + initializeStatusBar() + + // Cleanup on unmount + return () => { + statusBarManager.cleanup() + } + }, [mode]) // Include mode dependency + + useEffect(() => { + // Update status bar when theme changes + const updateStatusBarTheme = async () => { + let resolvedTheme = mode + + // Handle system mode by using the detected system theme + if (mode === 'system') { + resolvedTheme = systemMode || 'light' + } + + // Update the status bar with the resolved theme + await statusBarManager.updateResolvedTheme(resolvedTheme) + + // Also update the base theme for future reference + await statusBarManager.setTheme(mode) + + // Notify any custom listeners + statusBarManager.notifyThemeChange(resolvedTheme) + } + + updateStatusBarTheme() + }, [mode, systemMode]) // Update when either mode or systemMode changes + + return { + statusBarManager, + currentTheme: mode, + resolvedTheme: mode === 'system' ? systemMode : mode, + } +} + +export default useStatusBar diff --git a/src/hooks/useSyncOnReconnect.js b/src/hooks/useSyncOnReconnect.js index 65272ef..0c3220e 100644 --- a/src/hooks/useSyncOnReconnect.js +++ b/src/hooks/useSyncOnReconnect.js @@ -8,7 +8,8 @@ import { isOfflineFeatureEnabled } from '../utils/OfflineFeatureToggle' import { syncEngine } from '../utils/SyncEngine' import { networkManager } from './NetworkManager' -const PENDING_POLL_MS = 30_000 // retry pending commands every 30s +export const PENDING_POLL_MS = 30_000 // retry pending commands every 30s +export const SERVER_PROBE_MS = 15_000 // probe server when marked unreachable but device has network const CACHE_REFRESH_MS = 5 * 60_000 // refresh IDB cache every 5 min while online export function useSyncOnReconnect() { @@ -18,6 +19,7 @@ export function useSyncOnReconnect() { useEffect(() => { let pendingPollInterval let cacheRefreshInterval + let serverProbeInterval let resumeListener let networkListener const handleVisibilityChange = () => { @@ -77,13 +79,27 @@ export function useSyncOnReconnect() { cacheRefreshInterval = setInterval(() => { runSync() }, CACHE_REFRESH_MS) + + // 6. Probe server every 15s when server is unreachable but device has network + serverProbeInterval = setInterval(async () => { + if (!networkManager.isOnline && networkManager.deviceOnline) { + await runSync() + } + }, SERVER_PROBE_MS) } const runSync = async () => { if (!isOfflineFeatureEnabled()) return + const wasOffline = !networkManager.isOnline const didSync = await syncEngine.sync() if (didSync) { queryClient.invalidateQueries() + // After recovery from server-unreachable, run a second pass to flush + // any commands that were skipped while offline + if (wasOffline && networkManager.isOnline) { + const didSync2 = await syncEngine.sync() + if (didSync2) queryClient.invalidateQueries() + } } } @@ -98,6 +114,10 @@ export function useSyncOnReconnect() { clearInterval(cacheRefreshInterval) } + if (serverProbeInterval) { + clearInterval(serverProbeInterval) + } + if (networkListener) { networkManager.unregisterNetworkListener(networkListener) } diff --git a/src/queries/ChoreQueries.jsx b/src/queries/ChoreQueries.jsx index 85f7daf..20186dc 100644 --- a/src/queries/ChoreQueries.jsx +++ b/src/queries/ChoreQueries.jsx @@ -8,6 +8,7 @@ import { CreateChore, DeleteChore, DeleteChoreHistory, + GetChoreAttachments, GetChoreByID, GetChoreDetailById, GetChoreHistory, @@ -58,7 +59,8 @@ const mergePendingCreates = async chores => { } const isNetworkError = error => - error instanceof TypeError && error.message === 'Failed to fetch' + (error instanceof TypeError && error.message === 'Failed to fetch') || + error?.name === 'AbortError' const buildOfflineChore = task => ({ ...task, @@ -191,13 +193,7 @@ export const useCreateChore = () => { if (!createdChore) { throw new Error('Failed to get created chore data') } - // Successfully created the chore on the server, return the created chore - // update the local chores cache with the new chore: - queryClient.setQueryData(['chores', false], oldData => { - if (!oldData) return { res: [createdChore.res] } - return { res: [...oldData.res, createdChore.res] } - }) - return createdChore.res + return { ...newTask, id: createdChore.res } } catch (error) { if (isNetworkError(error)) { return queueOfflineCreate(newTask) @@ -258,7 +254,7 @@ export const useUpdateChore = () => { ), } }) - return updatedChoreRes?.res || updatedChoreRes + return updatedChoreRes?.res || updatedChore } catch (error) { if (isNetworkError(error)) { return queueOfflineUpdate() @@ -577,7 +573,45 @@ export const useMarkChoreComplete = () => { }) return { res: { _pending: 'complete' } } } - return MarkChoreComplete(choreId, body, completedDate, performer) + + const queueOfflineComplete = async () => { + await commandQueue.enqueue(CommandType.COMPLETE_CHORE, choreId, { + id: choreId, + body, + completedDate, + performer, + }) + await offlineDB.savePendingHistory({ + id: -Date.now(), + choreId: Number(choreId), + completedBy: body?.completedBy || 0, + performedAt: completedDate || new Date().toISOString(), + notes: body?.note || null, + status: 1, + points: 0, + pending: true, + }) + queryClient.setQueryData(['chores'], oldData => { + if (!oldData) return oldData + return { + res: oldData.res.map(chore => + chore.id === choreId + ? { ...chore, _pending: 'complete' } + : chore, + ), + } + }) + return { res: { _pending: 'complete' } } + } + + try { + return await MarkChoreComplete(choreId, body, completedDate, performer) + } catch (error) { + if (isNetworkError(error)) { + return queueOfflineComplete() + } + throw error + } }, onSuccess: (_, { choreId }) => { queryClient.invalidateQueries(['chores']) @@ -608,7 +642,26 @@ export const useSkipChore = () => { }) return { res: { _pending: 'skip' } } } - return SkipChore(choreId) + + try { + return await SkipChore(choreId) + } catch (error) { + if (isNetworkError(error)) { + await commandQueue.enqueue(CommandType.SKIP_CHORE, choreId, { + id: choreId, + }) + queryClient.setQueryData(['chores'], oldData => { + if (!oldData) return oldData + return { + res: oldData.res.map(chore => + chore.id === choreId ? { ...chore, _pending: 'skip' } : chore, + ), + } + }) + return { res: { _pending: 'skip' } } + } + throw error + } }, onSuccess: (_, choreId) => { queryClient.invalidateQueries(['chores']) @@ -644,3 +697,19 @@ export const useRejectChore = () => { }, }) } + +export const useChoreAttachments = (choreId, hasAttachments = true) => { + return useQuery({ + queryKey: ['choreAttachments', choreId], + queryFn: async () => { + const response = await GetChoreAttachments(choreId) + if (response && response.ok) { + return await response.json() + } + throw new Error('Failed to fetch attachments') + }, + enabled: !!choreId && hasAttachments, + staleTime: 10 * 60 * 1000, + gcTime: 15 * 60 * 1000, + }) +} diff --git a/src/service/AIPromptCache.js b/src/service/AIPromptCache.js new file mode 100644 index 0000000..d86393e --- /dev/null +++ b/src/service/AIPromptCache.js @@ -0,0 +1,72 @@ +const ENABLED_KEY = 'ai_prompt_cache_enabled' +const ENTRY_PREFIX = 'ai_prompt_cache_' +const INDEX_KEY = 'ai_prompt_cache_index' + +function djb2(str) { + let hash = 5381 + for (let i = 0; i < str.length; i++) { + hash = ((hash << 5) + hash) ^ str.charCodeAt(i) + hash = hash >>> 0 + } + return hash.toString(36) +} + +export function isCacheEnabled() { + try { + return localStorage.getItem(ENABLED_KEY) === 'true' + } catch { + return false + } +} + +export function setCacheEnabled(enabled) { + try { + localStorage.setItem(ENABLED_KEY, String(enabled)) + } catch { /* ignore */ } +} + +export function hashContent(content) { + return djb2(typeof content === 'string' ? content : JSON.stringify(content)) +} + +function getIndex() { + try { + return JSON.parse(localStorage.getItem(INDEX_KEY) || '[]') + } catch { + return [] + } +} + +export function getCached(hash) { + if (!isCacheEnabled()) return null + try { + const raw = localStorage.getItem(ENTRY_PREFIX + hash) + return raw ? JSON.parse(raw) : null + } catch { + return null + } +} + +export function setCached(hash, value) { + if (!isCacheEnabled()) return + try { + localStorage.setItem(ENTRY_PREFIX + hash, JSON.stringify(value)) + const index = getIndex() + if (!index.includes(hash)) { + index.push(hash) + localStorage.setItem(INDEX_KEY, JSON.stringify(index)) + } + } catch { /* storage full, ignore */ } +} + +export function getCacheStats() { + return { count: getIndex().length } +} + +export function clearCache() { + const index = getIndex() + index.forEach(h => { + try { localStorage.removeItem(ENTRY_PREFIX + h) } catch { /* ignore */ } + }) + try { localStorage.removeItem(INDEX_KEY) } catch { /* ignore */ } +} diff --git a/src/service/LocalAIService.js b/src/service/LocalAIService.js new file mode 100644 index 0000000..6b3e1dd --- /dev/null +++ b/src/service/LocalAIService.js @@ -0,0 +1,141 @@ +import { Capacitor } from '@capacitor/core' +import { getCached, hashContent, setCached } from './AIPromptCache' + +// Native-only local AI service using @capacitor/local-llm. +// On web, all methods return 'unavailable' / null — no WebLLM. +class LocalAIService { + constructor() { + this._availability = null + this._sessionId = 'donetick-summary' + this._warmedUp = false + } + + get isNative() { + return Capacitor.isNativePlatform() + } + + async checkAvailability() { + if (!this.isNative) { + this._availability = 'unavailable' + return 'unavailable' + } + try { + const { LocalLLM } = await import('@capacitor/local-llm') + const { status } = await LocalLLM.systemAvailability() + this._availability = status + return status + } catch (e) { + this._availability = 'unavailable' + return 'unavailable' + } + } + + async getStatus() { + if (this._availability !== null) return this._availability + return this.checkAvailability() + } + + async isAvailable() { + return (await this.getStatus()) === 'available' + } + + resetAvailability() { + this._availability = null + } + + async download(onStatusChange) { + if (!this.isNative) return + try { + const { LocalLLM } = await import('@capacitor/local-llm') + if (onStatusChange) { + LocalLLM.addListener('systemAvailabilityChange', ({ status }) => { + this._availability = status + onStatusChange(status) + }) + } + await LocalLLM.download() + } catch { + // download not available on iOS, ignore + } + } + + async warmup() { + if (this._warmedUp || !this.isNative) return + try { + const { LocalLLM } = await import('@capacitor/local-llm') + await LocalLLM.warmup({ sessionId: this._sessionId }) + this._warmedUp = true + } catch { + // non-fatal + } + } + + async _nativePrompt(text) { + await this.warmup() + try { + const { LocalLLM } = await import('@capacitor/local-llm') + const { text: out } = await LocalLLM.prompt({ prompt: text, sessionId: this._sessionId }) + return out?.trim() || null + } finally { + try { + const { LocalLLM } = await import('@capacitor/local-llm') + await LocalLLM.endSession({ sessionId: this._sessionId }) + this._warmedUp = false + } catch { /* ignore */ } + } + } + + // Plain chat — no tools. Returns answer string or null. + async plainChat(messages) { + const available = await this.isAvailable() + if (!available) return null + + const cacheHash = hashContent(['plain', ...messages]) + const cached = getCached(cacheHash) + if (cached) return cached + + if (!this.isNative) return null + + try { + const systemMsg = messages.find(m => m.role === 'system')?.content || '' + const userMsg = messages.find(m => m.role === 'user')?.content || '' + const result = await this._nativePrompt(`${systemMsg}\n\nUser: ${userMsg}\nAssistant:`) + if (result) setCached(cacheHash, result) + return result + } catch (e) { + console.error('[LocalAI] plainChat() failed:', e) + return null + } + } + + // Returns the summary string or null if LLM is unavailable + async summarize(prompt) { + const available = await this.isAvailable() + if (!available) return null + + const cacheHash = hashContent(prompt) + const cached = getCached(cacheHash) + if (cached) return cached + + if (!this.isNative) return null + + try { + await this.warmup() + const { LocalLLM } = await import('@capacitor/local-llm') + const { text } = await LocalLLM.prompt({ prompt, sessionId: this._sessionId }) + const result = text?.trim() || null + if (result) setCached(cacheHash, result) + return result + } catch { + return null + } finally { + try { + const { LocalLLM } = await import('@capacitor/local-llm') + await LocalLLM.endSession({ sessionId: this._sessionId }) + this._warmedUp = false + } catch { /* ignore */ } + } + } +} + +export const localAIService = new LocalAIService() diff --git a/src/service/NFCWriter.jsx b/src/service/NFCWriter.jsx index 91ac978..cc6f37a 100644 --- a/src/service/NFCWriter.jsx +++ b/src/service/NFCWriter.jsx @@ -1,11 +1,136 @@ +import { CapacitorNfc } from '@capgo/capacitor-nfc' + +// Encodes a URL into an NDEF URI record (TNF=0x01, type='U') +const buildUriRecord = url => { + const encoder = new TextEncoder() + let prefixByte = 0x00 + let uriStr = url + if (url.startsWith('https://')) { + prefixByte = 0x04 + uriStr = url.slice(8) + } else if (url.startsWith('http://')) { + prefixByte = 0x03 + uriStr = url.slice(7) + } + return { + tnf: 0x01, + type: [0x55], + id: [], + payload: [prefixByte, ...Array.from(encoder.encode(uriStr))], + } +} + +// Decodes a URL from an NDEF URI record payload. Returns null if not a URI record. +export const decodeNdefUrl = record => { + if (!record || record.tnf !== 0x01) return null + if (record.type.length !== 1 || record.type[0] !== 0x55) return null + const payload = record.payload + if (!payload || payload.length === 0) return null + const prefixes = [ + '', + 'http://www.', + 'https://www.', + 'http://', + 'https://', + 'tel:', + 'mailto:', + ] + const prefix = prefixes[payload[0]] ?? '' + const uri = new TextDecoder().decode(new Uint8Array(payload.slice(1))) + return prefix + uri +} + +// Starts a native NFC write session. Calls onWaiting once scanning is active, +// then onSuccess or onError when the write completes. Returns a cancel function. +export const startNativeNFCWrite = async (url, { onWaiting, onSuccess, onError }) => { + let listener = null + let done = false + + const cleanup = async () => { + if (listener) { + await listener.remove() + listener = null + } + await CapacitorNfc.stopScanning().catch(() => {}) + } + + try { + listener = await CapacitorNfc.addListener('nfcEvent', async () => { + if (done) return + done = true + try { + await CapacitorNfc.write({ records: [buildUriRecord(url)] }) + await cleanup() + onSuccess() + } catch (err) { + await cleanup() + onError(err.message || 'Failed to write to NFC tag') + } + }) + + await CapacitorNfc.startScanning({ + alertMessage: 'Hold your device near the NFC tag to write', + invalidateAfterFirstRead: true, + // Without FLAG_READER_SKIP_NDEF_CHECK (0x80), Android enumerates + // Ndef/NdefFormatable tech so the plugin can format blank tags on write. + androidReaderModeFlags: 0x0f, // NFC_A | NFC_B | NFC_F | NFC_V + }) + onWaiting() + return cleanup + } catch (err) { + await cleanup() + onError(err.message || 'Failed to start NFC session') + return async () => {} + } +} + +// Starts a native NFC scan session for reading. Calls onTag(url) when a URL +// NDEF record is found, or onError on failure. Returns a cancel function. +export const startNativeScan = async ({ onTag, onError }) => { + let listener = null + let done = false + + const cleanup = async () => { + if (listener) { + await listener.remove() + listener = null + } + await CapacitorNfc.stopScanning().catch(() => {}) + } + + try { + listener = await CapacitorNfc.addListener('nfcEvent', async event => { + if (done) return + const records = event.tag?.ndefMessage ?? [] + for (const record of records) { + const url = decodeNdefUrl(record) + if (url) { + done = true + await cleanup() + onTag(url) + return + } + } + }) + + await CapacitorNfc.startScanning({ + alertMessage: 'Hold your device near the NFC tag', + invalidateAfterFirstRead: true, + }) + return cleanup + } catch (err) { + await cleanup() + onError(err.message || 'Failed to start NFC session') + return async () => {} + } +} + +// Legacy default export for web/PWA (NDEFReader API) const writeToNFC = async url => { if ('NDEFReader' in window) { try { const ndef = new window.NDEFReader() - await ndef.write({ - records: [{ recordType: 'url', data: url }], - }) - alert('URL written to NFC tag successfully!') + await ndef.write({ records: [{ recordType: 'url', data: url }] }) } catch (error) { console.error('Error writing to NFC tag:', error) alert('Error writing to NFC tag. Please try again.') diff --git a/src/styles/safe-area.css b/src/styles/safe-area.css new file mode 100644 index 0000000..bc3eece --- /dev/null +++ b/src/styles/safe-area.css @@ -0,0 +1,127 @@ +/* + * Safe Area CSS Utilities + * These utilities provide consistent safe area handling across the app + * using CSS custom properties set by StatusBarManager + */ + +:root { + /* Fallback values for safe area insets when not on native platforms */ + --safe-area-inset-top: 0px; + --safe-area-inset-right: 0px; + --safe-area-inset-bottom: 0px; + --safe-area-inset-left: 0px; +} + +/* Utility classes for safe area handling */ +.safe-area-top { + padding-top: var(--safe-area-inset-top); +} + +.safe-area-right { + padding-right: var(--safe-area-inset-right); +} + +.safe-area-bottom { + padding-bottom: var(--safe-area-inset-bottom); +} + +.safe-area-left { + padding-left: var(--safe-area-inset-left); +} + +.safe-area-x { + padding-left: var(--safe-area-inset-left); + padding-right: var(--safe-area-inset-right); +} + +.safe-area-y { + padding-top: var(--safe-area-inset-top); + padding-bottom: var(--safe-area-inset-bottom); +} + +.safe-area-all { + padding-top: var(--safe-area-inset-top); + padding-right: var(--safe-area-inset-right); + padding-bottom: var(--safe-area-inset-bottom); + padding-left: var(--safe-area-inset-left); +} + +/* Margin variants */ +.safe-margin-top { + margin-top: var(--safe-area-inset-top); +} + +.safe-margin-right { + margin-right: var(--safe-area-inset-right); +} + +.safe-margin-bottom { + margin-bottom: var(--safe-area-inset-bottom); +} + +.safe-margin-left { + margin-left: var(--safe-area-inset-left); +} + +.safe-margin-x { + margin-left: var(--safe-area-inset-left); + margin-right: var(--safe-area-inset-right); +} + +.safe-margin-y { + margin-top: var(--safe-area-inset-top); + margin-bottom: var(--safe-area-inset-bottom); +} + +.safe-margin-all { + margin-top: var(--safe-area-inset-top); + margin-right: var(--safe-area-inset-right); + margin-bottom: var(--safe-area-inset-bottom); + margin-left: var(--safe-area-inset-left); +} + +/* Height utilities that account for safe areas */ +.min-h-screen-safe { + min-height: calc(100vh - var(--safe-area-inset-top) - var(--safe-area-inset-bottom)); +} + +.h-screen-safe { + height: calc(100vh - var(--safe-area-inset-top) - var(--safe-area-inset-bottom)); +} + +/* Top positioning that accounts for safe area */ +.top-safe { + top: var(--safe-area-inset-top); +} + +/* Bottom positioning that accounts for safe area */ +.bottom-safe { + bottom: var(--safe-area-inset-bottom); +} + +/* Fixed positioning utilities that respect safe areas */ +.fixed-top-safe { + position: fixed; + top: var(--safe-area-inset-top); + left: 0; + right: 0; + z-index: 1030; +} + +.fixed-bottom-safe { + position: fixed; + bottom: var(--safe-area-inset-bottom); + left: 0; + right: 0; + z-index: 1030; +} + +/* Container that provides full safe area coverage */ +.container-safe { + padding-top: var(--safe-area-inset-top); + padding-right: var(--safe-area-inset-right); + padding-bottom: var(--safe-area-inset-bottom); + padding-left: var(--safe-area-inset-left); + min-height: 100vh; + box-sizing: border-box; +} diff --git a/src/utils/ApiClient.js b/src/utils/ApiClient.js index 52d926b..d517c91 100644 --- a/src/utils/ApiClient.js +++ b/src/utils/ApiClient.js @@ -1,5 +1,6 @@ import { Preferences } from '@capacitor/preferences' import { API_URL } from '../Config' +import { networkManager } from '../hooks/NetworkManager' import { logout, RefreshToken } from './Fetcher' import { clearAllTokens, @@ -17,7 +18,7 @@ class ApiClient { } async init(force = false) { - if (!force && this.initPromise) { + if (this.initPromise && !force) { return this.initPromise } @@ -25,7 +26,9 @@ class ApiClient { return Promise.resolve() } - this.initPromise = this._doInit() + this.initPromise = this._doInit().finally(() => { + this.initPromise = null + }) return this.initPromise } @@ -144,15 +147,22 @@ class ApiClient { async request(endpoint, options = {}) { await this.init() const url = `${this.customServerURL}${endpoint}` + + // Abort after 10s so a dead/unreachable server doesn't hang the UI + const controller = new AbortController() + const timeoutId = setTimeout(() => controller.abort(), 10_000) + const config = { // credentials: 'include', ...options, headers: this.getHeaders(options.headers), + signal: options.signal ?? controller.signal, } try { // 1. Initial Request let response = await fetch(url, config) + clearTimeout(timeoutId) // 2. Check for 401 (Unauthorized) if (response.status === 401) { @@ -220,6 +230,9 @@ class ApiClient { return response } catch (error) { + clearTimeout(timeoutId) + // fetch() threw = network-level failure or timeout — mark server unreachable + networkManager.setServerUnreachable() console.error('Request failed', error) throw error } diff --git a/src/utils/Chores.jsx b/src/utils/Chores.jsx index cde9fe7..bd225ab 100644 --- a/src/utils/Chores.jsx +++ b/src/utils/Chores.jsx @@ -25,6 +25,67 @@ export const ChoreStatus = Object.freeze({ PAUSED: 2, PENDING_APPROVAL: 3, }) + +const getDateGroupKey = dueDate => + moment(dueDate).startOf('day').format('YYYY-MM-DD') + +const getDateGroupName = dateKey => + moment(dateKey, 'YYYY-MM-DD').format('dddd, MMM D') + +const getDateGroupColor = dateKey => { + const today = moment().startOf('day') + const tomorrow = moment().add(1, 'day').startOf('day') + const groupDate = moment(dateKey, 'YYYY-MM-DD') + + if (groupDate.isBefore(today)) { + return TASK_COLOR.OVERDUE + } + if (groupDate.isSame(today)) { + return TASK_COLOR.TODAY + } + if (groupDate.isSame(tomorrow)) { + return TASK_COLOR.TOMORROW + } + if (groupDate.isBefore(moment(today).add(8, 'days'))) { + return TASK_COLOR.NEXT_7_DAYS + } + if (groupDate.isSame(today, 'month')) { + return TASK_COLOR.LATER_THIS_MONTH + } + return TASK_COLOR.FUTURE +} + +const buildActualDateGroups = chores => { + const groupedByDate = {} + const anytime = [] + + chores.forEach(chore => { + if (!chore.nextDueDate) { + anytime.push(chore) + return + } + + const dateKey = getDateGroupKey(chore.nextDueDate) + if (!groupedByDate[dateKey]) { + groupedByDate[dateKey] = [] + } + groupedByDate[dateKey].push(chore) + }) + + const dateGroups = Object.keys(groupedByDate) + .sort( + (a, b) => + moment(a, 'YYYY-MM-DD').valueOf() - moment(b, 'YYYY-MM-DD').valueOf(), + ) + .map(dateKey => ({ + name: getDateGroupName(dateKey), + content: groupedByDate[dateKey], + color: getDateGroupColor(dateKey), + })) + + return { dateGroups, anytime } +} + export const ChoresGrouper = (groupBy, chores, filter) => { if (filter) { chores = chores.filter(chore => filter(chore)) @@ -34,7 +95,7 @@ export const ChoresGrouper = (groupBy, chores, filter) => { chores.sort(ChoreSorter) var groups = [] switch (groupBy) { - case 'default': + case 'default': { // same as due_date but hide empty groups: and if status is 1 or 2 have seperated catigory as Started: var groupRaw = { PendingApproval: [], @@ -147,82 +208,21 @@ export const ChoresGrouper = (groupBy, chores, filter) => { }) } break + } - case 'due_date': - var groupRaw = { - Today: [], - Tomorrow: [], - 'Next 7 Days': [], - 'Later This Month': [], - Future: [], - Overdue: [], - Anytime: [], - } - chores.forEach(chore => { - if (chore.nextDueDate === null) { - groupRaw['Anytime'].push(chore) - } else if (new Date(chore.nextDueDate) < new Date()) { - groupRaw['Overdue'].push(chore) - } else if ( - new Date(chore.nextDueDate).toDateString() === - new Date().toDateString() - ) { - groupRaw['Today'].push(chore) - } else if ( - new Date(chore.nextDueDate).toDateString() === - new Date(Date.now() + 24 * 60 * 60 * 1000).toDateString() - ) { - groupRaw['Tomorrow'].push(chore) - } else if ( - new Date(chore.nextDueDate) < - new Date(Date.now() + 8 * 24 * 60 * 60 * 1000) && - new Date(chore.nextDueDate) > - new Date(Date.now() + 24 * 60 * 60 * 1000) - ) { - groupRaw['Next 7 Days'].push(chore) - } else if ( - new Date(chore.nextDueDate).getMonth() === new Date().getMonth() && - new Date(chore.nextDueDate).getFullYear() === new Date().getFullYear() - ) { - groupRaw['Later This Month'].push(chore) - } else { - groupRaw['Future'].push(chore) - } - }) - groups = [ - { - name: 'Overdue', - content: groupRaw['Overdue'], - color: TASK_COLOR.OVERDUE, - }, - { name: 'Today', content: groupRaw['Today'], color: TASK_COLOR.TODAY }, - { - name: 'Tomorrow', - content: groupRaw['Tomorrow'], - color: TASK_COLOR.TOMORROW, - }, - { - name: 'Next 7 Days', - content: groupRaw['Next 7 Days'], - color: TASK_COLOR.NEXT_7_DAYS, - }, - { - name: 'Later This Month', - content: groupRaw['Later This Month'], - color: TASK_COLOR.LATER_THIS_MONTH, - }, - { - name: 'Future', - content: groupRaw['Future'], - color: TASK_COLOR.FUTURE, - }, - { + case 'due_date': { + var { dateGroups: dueDateGroups, anytime: dueAnytime } = + buildActualDateGroups(chores) + groups = [...dueDateGroups] + if (dueAnytime.length > 0) { + groups.push({ name: 'Anytime', - content: groupRaw['Anytime'], + content: dueAnytime, color: TASK_COLOR.ANYTIME, - }, - ] + }) + } break + } case 'priority': groupRaw = { p1: [], diff --git a/src/utils/Fetcher.jsx b/src/utils/Fetcher.jsx index 167394a..0e3caae 100644 --- a/src/utils/Fetcher.jsx +++ b/src/utils/Fetcher.jsx @@ -728,6 +728,30 @@ const DeleteUser = (password, confirmation, transferOptions = []) => { }) } +const UploadChoreAttachment = (file, entityType, { entityId, draftId } = {}) => { + const formData = new FormData() + formData.append('file', file) + formData.append('entityType', entityType) + if (entityId != null) formData.append('entityId', String(entityId)) + if (draftId != null) formData.append('draftId', draftId) + return apiClient.upload('/assets/chore', formData) +} + +const GetChoreAttachments = choreId => { + return Fetch(`/chores/${choreId}/attachments`, { + method: 'GET', + headers: HEADERS(), + }) +} + +const DeleteChoreAttachment = (choreId, filePath) => { + return Fetch(`/chores/${choreId}/attachments`, { + method: 'DELETE', + headers: HEADERS(), + body: JSON.stringify({ file_path: filePath }), + }) +} + const CreateBackup = (encryptionKey, includeAssets = true, backupName = '') => { return Fetch(`/backup/create`, { method: 'POST', @@ -933,6 +957,9 @@ const TrackFilterUsage = id => { export { AcceptCircleMemberRequest, + DeleteChoreAttachment, + GetChoreAttachments, + UploadChoreAttachment, ApproveChore, ArchiveChore, CancelSubscription, diff --git a/src/utils/Helpers.jsx b/src/utils/Helpers.jsx index fb1ef4c..b276778 100644 --- a/src/utils/Helpers.jsx +++ b/src/utils/Helpers.jsx @@ -10,9 +10,114 @@ const resolvePhotoURL = url => { if (url.startsWith('http') || url.startsWith('https')) { return url } - if (url.startsWith('assets')) { - return apiClient.getAssetURL(url) - } - return url + return apiClient.getAssetURL(url) } -export { isPlusAccount, resolvePhotoURL } + +// Detect cloud storage pre-signed URLs (S3, GCS, Azure) that carry expiry params. +const isCloudSignedUrl = url => { + if (!url) return false + try { + return ( + url.includes('X-Amz-Signature') || + url.includes('X-Amz-Expires') || + url.includes('X-Goog-Expires') || + url.includes('expires') + ) + } catch(e) { + return false + } +} + +// Extract the storage key from a cloud signed URL so we can route it through +// the backend proxy (which re-signs on every request and never expires). +// +// Handles: +// Virtual-hosted S3: https://{bucket}.s3[.region].amazonaws.com/{key}?... +// Path-style S3: https://s3[.region].amazonaws.com/{bucket}/{key}?... +// Cloudflare R2: https://{bucket}.{accountid}.r2.cloudflarestorage.com/{key}?... +// GCS: https://storage.googleapis.com/{bucket}/{key}?... +// Azure Blob: https://{account}.blob.core.windows.net/{container}/{blob}?... +// +// The app stores files under an "assets/" prefix in the bucket but the backend +// proxy already mounts at /assets/, so we strip that leading segment when present. +const extractStorageKey = url => { + try { + const u = new URL(url) + const host = u.hostname + const rawPath = u.pathname.replace(/^\//, '') + + let key + + if (host.endsWith('.r2.cloudflarestorage.com')) { + // Virtual-hosted R2: bucket is in the host, key is the full path + key = rawPath + } else if (host.endsWith('.amazonaws.com')) { + if (host.startsWith('s3') || host.includes('.s3.')) { + // Path-style S3: first segment is the bucket — strip it + key = rawPath.split('/').slice(1).join('/') + } else { + // Virtual-hosted S3: bucket is in the host, path is the key + key = rawPath + } + } else if (host === 'storage.googleapis.com') { + // First segment is the bucket + key = rawPath.split('/').slice(1).join('/') + } else if (host.endsWith('.blob.core.windows.net')) { + // First segment is the container name + key = rawPath.split('/').slice(1).join('/') + } else { + key = rawPath + } + + // The bucket stores files under an "assets/" prefix; the backend /assets/ + // endpoint already adds that prefix, so strip it to avoid duplication. + if (key.startsWith('assets/')) { + key = key.slice('assets/'.length) + } + + return key || null + } catch { + return null + } +} + +// Scan an HTML string for tags whose src is a cloud signed URL and +// replace them with backend proxy URLs (which generate fresh signed URLs on +// each request). Returns the patched HTML, or the original if nothing changed. +const refreshSignedUrlsInHtml = html => { + if (!html) return html + if ( + !html.includes('dt-data-path') && + !html.includes('X-Amz-') && + !html.includes('X-Goog-') && + !html.includes('sig') && + !html.includes('.blob.core.windows.net') + ) { + return html + } + const parser = new DOMParser() + const doc = parser.parseFromString(html, 'text/html') + const imgs = doc.querySelectorAll('img[src]') + let changed = false + + imgs.forEach(img => { + const stablePath = img.getAttribute('dt-data-path') + const src = img.getAttribute('src') + let nextSrc = src + + if (stablePath) { + nextSrc = resolvePhotoURL(stablePath) + } else if (isCloudSignedUrl(src)) { + nextSrc = resolvePhotoURL(extractStorageKey(src)) + } + + if (nextSrc && nextSrc !== src) { + img.setAttribute('src', nextSrc) + changed = true + } + }) + + return changed ? doc.body.innerHTML : html +} + +export { isPlusAccount, refreshSignedUrlsInHtml, resolvePhotoURL } diff --git a/src/utils/OfflineDB.js b/src/utils/OfflineDB.js index 00e45ec..24b8b68 100644 --- a/src/utils/OfflineDB.js +++ b/src/utils/OfflineDB.js @@ -26,17 +26,32 @@ class SQLiteBackend { constructor() { this.db = null this.initialized = false + this._initPromise = null } async init() { if (this.initialized) return + // Return the in-flight promise if init is already underway (prevents double createConnection) + if (this._initPromise) return this._initPromise - this.db = await CapacitorSQLite.createConnection({ - database: DB_NAME, - version: DB_VERSION, - encrypted: false, - mode: 'no-encryption', + this._initPromise = this._doInit().finally(() => { + this._initPromise = null }) + return this._initPromise + } + + async _doInit() { + try { + this.db = await CapacitorSQLite.createConnection({ + database: DB_NAME, + version: DB_VERSION, + encrypted: false, + mode: 'no-encryption', + }) + } catch (err) { + // Connection already open (e.g. React StrictMode double-mount) — reuse it + if (!err?.message?.includes('already exists')) throw err + } await CapacitorSQLite.open({ database: DB_NAME }) await CapacitorSQLite.execute({ diff --git a/src/utils/StatusBarManager.js b/src/utils/StatusBarManager.js index 48cc383..ce8fc62 100644 --- a/src/utils/StatusBarManager.js +++ b/src/utils/StatusBarManager.js @@ -26,7 +26,7 @@ class StatusBarManager { } try { - // Configure basic status bar settings - use overlay: true for precise control + // Configure basic status bar settings await StatusBar.setOverlaysWebView({ overlay: false }) await StatusBar.show() diff --git a/src/utils/SyncEngine.js b/src/utils/SyncEngine.js index 6f1b5ff..2d247a1 100644 --- a/src/utils/SyncEngine.js +++ b/src/utils/SyncEngine.js @@ -55,6 +55,8 @@ class SyncEngine { // Step 3: Delta sync from server await this._deltaSync() + // Sync succeeded — server is reachable (only sync success restores online status) + networkManager.setServerReachable() this._notify({ syncing: false, lastSync: Date.now() }) return true } catch (err) { @@ -182,7 +184,7 @@ class SyncEngine { let hasMore = true let currentCursor = cursor - while (hasMore && networkManager.isOnline) { + while (hasMore && networkManager.deviceOnline) { // Use apiClient.get which handles auth and returns a fetch Response const response = await apiClient.get( `/sync/changes?since=${currentCursor}`, diff --git a/src/views/Authorization/Authenticating.jsx b/src/views/Authorization/Authenticating.jsx index 693fd4b..4420b35 100644 --- a/src/views/Authorization/Authenticating.jsx +++ b/src/views/Authorization/Authenticating.jsx @@ -9,6 +9,8 @@ import { Link, useNavigate, useParams } from 'react-router-dom' import { useUserProfile } from '../../queries/UserQueries' import { apiClient } from '../../utils/ApiClient' import { GetUserProfile } from '../../utils/Fetcher' +import { saveTokens } from '../../utils/TokenStorage' +import MFAVerificationModal from './MFAVerificationModal' const AuthenticationLoading = () => { const { data: userProfile, refetch: refetchUserProfile } = useUserProfile() @@ -17,6 +19,8 @@ const AuthenticationLoading = () => { const [message, setMessage] = useState('Authenticating') const [subMessage, setSubMessage] = useState('Please wait') const [status, setStatus] = useState('pending') + const [mfaModalOpen, setMfaModalOpen] = useState(false) + const [mfaSessionToken, setMfaSessionToken] = useState('') const { provider } = useParams() useEffect(() => { if (provider === 'oauth2' && !hasCalledHandleOAuth2.current) { @@ -43,6 +47,29 @@ const AuthenticationLoading = () => { }) }) } + + const handleMFASuccess = async data => { + await saveTokens({ + accessToken: data.token, + accessTokenExpiry: data.expire, + refreshToken: data.refresh_token, + refreshTokenExpiry: data.refresh_token_expiry, + }) + + setMfaModalOpen(false) + setMfaSessionToken('') + + getUserProfileAndNavigateToHome() + } + + const handleMFAClose = () => { + setMfaModalOpen(false) + setMfaSessionToken('') + setMessage('Authentication failed') + setSubMessage('Two-factor authentication was cancelled') + setStatus('error') + } + const handleOAuth2 = async () => { // get provider from params: const urlParams = new URLSearchParams(window.location.search) @@ -64,37 +91,71 @@ const AuthenticationLoading = () => { const redirectURI = Capacitor.isNativePlatform() ? 'donetick://auth/oauth2' : `${window.location.origin}/auth/oauth2` - fetch(`${baseURL}/auth/oauth2/callback`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - code, - state: returnedState, - redirect_uri: redirectURI, - }), - }).then(response => { - if (response.status === 200) { - return response.json().then(data => { - localStorage.setItem('token', data.token) - localStorage.setItem('token_expiry', data.expire) + try { + const response = await fetch(`${baseURL}/auth/oauth2/callback`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + code, + state: returnedState, + redirect_uri: redirectURI, + }), + }) - const redirectUrl = Cookies.get('ca_redirect') - if (redirectUrl) { - Cookies.remove('ca_redirect') - Navigate(redirectUrl) - } else { - getUserProfileAndNavigateToHome() - } - }) - } else { + if (!response.ok) { console.error('Authentication failed') setMessage('Authentication failed') setSubMessage('Please try again') setStatus('error') + return } - }) + + const data = await response.json() + + if (data.mfaRequired) { + if (!data.sessionToken) { + setMessage('Authentication failed') + setSubMessage('MFA session is missing. Please try again') + setStatus('error') + return + } + + setMfaSessionToken(data.sessionToken) + setMfaModalOpen(true) + setMessage('Two-Factor Authentication Required') + setSubMessage('Please verify your login to continue') + return + } + + if (!data.token && !data.access_token) { + setMessage('Authentication failed') + setSubMessage('No valid authentication token returned') + setStatus('error') + return + } + + await saveTokens({ + accessToken: data.token || data.access_token, + accessTokenExpiry: data.expire || data.access_token_expiry, + refreshToken: data.refresh_token, + refreshTokenExpiry: data.refresh_token_expiry, + }) + + const redirectUrl = Cookies.get('ca_redirect') + if (redirectUrl) { + Cookies.remove('ca_redirect') + Navigate(redirectUrl) + } else { + getUserProfileAndNavigateToHome() + } + } catch (error) { + console.error('Authentication request failed', error) + setMessage('Authentication failed') + setSubMessage('Please try again') + setStatus('error') + } } } @@ -138,6 +199,17 @@ const AuthenticationLoading = () => { Go back Login )} + + { + setMessage('Authentication failed') + setSubMessage('Two-factor authentication failed. Please try again') + }} + /> ) diff --git a/src/views/Authorization/LoginSettings.jsx b/src/views/Authorization/LoginSettings.jsx index 1a85de3..e8fe85e 100644 --- a/src/views/Authorization/LoginSettings.jsx +++ b/src/views/Authorization/LoginSettings.jsx @@ -1,17 +1,32 @@ import { Preferences } from '@capacitor/preferences' -import { Box, Button, Container, Input, Sheet, Typography } from '@mui/joy' +import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline' +import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline' +import WifiIcon from '@mui/icons-material/Wifi' +import { + Alert, + Box, + Button, + CircularProgress, + Container, + Input, + Sheet, + Typography, +} from '@mui/joy' import React from 'react' import { useNavigate } from 'react-router-dom' import { API_URL } from '../../Config' import Logo from '../../Logo' import { useResource } from '../../queries/ResourceQueries' -import { useNotification } from '../../service/NotificationProvider' import { apiClient } from '../../utils/ApiClient' + +const CONNECTION_TIMEOUT_MS = 8000 + const LoginSettings = () => { const Navigate = useNavigate() const { refetch: refetchResource } = useResource() const [serverURL, setServerURL] = React.useState('') - const { showError } = useNotification() + const [status, setStatus] = React.useState('idle') // 'idle' | 'testing' | 'success' | 'error' + const [errorMessage, setErrorMessage] = React.useState('') React.useEffect(() => { Preferences.get({ key: 'customServerUrl' }).then(result => { @@ -19,10 +34,95 @@ const LoginSettings = () => { }) }, []) - const isValidServerURL = () => { - return serverURL.match(/^(http|https):\/\/[^ "]+$/) + const isValidURL = url => { + return /^(http|https):\/\/[^ "]+$/.test(url.trim()) } + const testConnection = async url => { + const controller = new AbortController() + const timeoutId = setTimeout( + () => controller.abort(), + CONNECTION_TIMEOUT_MS, + ) + try { + const testURL = url.replace(/\/+$/, '') + '/api/v1/resource' + const response = await fetch(testURL, { + method: 'GET', + signal: controller.signal, + }) + clearTimeout(timeoutId) + // Any HTTP response (even 401/404) means the server is reachable + if (response.status < 500) { + return { ok: true } + } + return { + ok: false, + message: `Server responded with error ${response.status}. Please check your Donetick server.`, + } + } catch (err) { + clearTimeout(timeoutId) + if (err.name === 'AbortError') { + return { + ok: false, + message: `Connection timed out after ${CONNECTION_TIMEOUT_MS / 1000}s. Check the URL and ensure the server is running.`, + } + } + return { + ok: false, + message: + 'Unable to reach the server. Check the URL, port, and network connection.', + } + } + } + + const handleSave = async () => { + const trimmedURL = serverURL.trim() + + if (trimmedURL === '') { + await Preferences.set({ key: 'customServerUrl', value: API_URL }) + Navigate('/login') + return + } + + if (!isValidURL(trimmedURL)) { + setStatus('error') + setErrorMessage( + 'Invalid URL format. Include the protocol (http:// or https://) and port if needed.', + ) + return + } + + setStatus('testing') + setErrorMessage('') + + const result = await testConnection(trimmedURL) + + if (!result.ok) { + setStatus('error') + setErrorMessage(result.message) + return + } + + await Preferences.set({ key: 'customServerUrl', value: trimmedURL }) + await apiClient.init(true) + refetchResource() + setStatus('success') + + setTimeout(() => { + Navigate('/login') + }, 1200) + } + + const handleURLChange = e => { + setServerURL(e.target.value) + if (status !== 'idle') { + setStatus('idle') + setErrorMessage('') + } + } + + const isTesting = status === 'testing' + return ( { sx={{ mt: 1, width: '100%', - display: 'flex', flexDirection: 'column', alignItems: 'center', @@ -51,13 +150,7 @@ const LoginSettings = () => { Done - - tick - + tick @@ -71,9 +164,22 @@ const LoginSettings = () => { name='serverURL' autoFocus value={serverURL} - onChange={e => { - setServerURL(e.target.value) - }} + onChange={handleURLChange} + disabled={isTesting} + color={ + status === 'success' + ? 'success' + : status === 'error' + ? 'danger' + : 'neutral' + } + endDecorator={ + status === 'success' ? ( + + ) : status === 'error' ? ( + + ) : null + } /> @@ -81,72 +187,68 @@ const LoginSettings = () => { own self-hosted Donetick server. - Please ensure to include the protocol (http:// or https://) and the - port number if necessary (default Donetick port is 2021). + Include the protocol (http:// or https://) and port if necessary + (default Donetick port is 2021). + + {status === 'error' && ( + } + sx={{ mt: 2, width: '100%' }} + > + {errorMessage} + + )} + + {status === 'success' && ( + } + sx={{ mt: 2, width: '100%' }} + > + Connected! Redirecting to login... + + )} + + {status === 'testing' && ( + } + sx={{ mt: 2, width: '100%' }} + > + Testing connection to server... + + )} + + + {/* Section 2: Assignment & Responsibility */} @@ -941,9 +1152,9 @@ const ChoreEdit = () => { { - setAssignees([]) + setAnyone(!anyone) setIsPrivate(false) }} overlay @@ -956,19 +1167,25 @@ const ChoreEdit = () => { {performers?.map((item, index) => ( a.userId == item.userId) != null - } + checked={assignableTo.some(a => a.userId == item.userId)} + disabled={anyone} onClick={() => { + if (anyone) { + setAnyone(false) + setAssignableTo([{ userId: item.userId }]) + return + } + const assignees = assignableTo + const setAssignees = setAssignableTo if (assignees.some(a => a.userId === item.userId)) { const newAssignees = assignees.filter( a => a.userId !== item.userId, ) + setAnyone(newAssignees.length === 0) setAssignees(newAssignees) } else { setAssignees([...assignees, { userId: item.userId }]) } - setShowSaveAssigneeDefault(true) }} overlay disableIcon @@ -998,9 +1215,13 @@ const ChoreEdit = () => { }, }} onClick={() => { + localStorage.setItem( + 'defaultAnyoneSetting', + JSON.stringify(anyone), + ) localStorage.setItem( 'defaultAssigneeSetting', - JSON.stringify(assignees), + JSON.stringify(assignableTo), ) setShowSaveAssigneeDefault(false) }} @@ -1026,17 +1247,12 @@ const ChoreEdit = () => { } disabled={assignees.length === 0} value={assignedTo > -1 ? assignedTo : null} + onChange={(_, selectedUserId) => setAssignedTo(selectedUserId)} > {performers - ?.filter(p => assignees.find(a => a.userId == p.userId)) + ?.filter(p => assignees.some(a => a.userId == p.userId)) .map((item, index) => ( - ))} @@ -1707,6 +1923,7 @@ const ChoreEdit = () => { )} + {addLabelModalOpen && ( err instanceof TypeError && err.message === 'Failed to fetch' @@ -124,6 +127,7 @@ const ChoreView = () => { const [chorePriority, setChorePriority] = useState(null) const [noteViewerConfig, setNoteViewerConfig] = useState({ isOpen: false }) const [timerActionConfig, setTimerActionConfig] = useState({ isOpen: false }) + const [attachmentBrowserOpen, setAttachmentBrowserOpen] = useState(false) const { data: circleMembersData, isLoading: isCircleMembersLoading } = useCircleMembers() const { data: userProfile } = useUserProfile() @@ -132,6 +136,7 @@ const ChoreView = () => { const { data: choreData, isLoading: isChoreLoading } = useChoreDetails(choreId) const { data: choreHistoryData } = useChoreHistory(choreId) + const { data: pendingCmds } = usePendingCommands(choreId) const choreHistory = choreHistoryData?.res || [] @@ -158,8 +163,8 @@ const ChoreView = () => { document.title = 'Donetick: ' + choreData.res.name setPerformers(circleMembersData.res) - const auto_complete = searchParams.get('auto_complete') - if (auto_complete === 'true') { + if (searchParams.get('auto_complete') === 'true') { + navigate({ search: '' }, { replace: true }) handleTaskCompletion() } }, [choreData, circleMembersData]) @@ -651,16 +656,14 @@ const ChoreView = () => { justifyContent: 'center', alignItems: 'center', mb: 1, + flexWrap: 'wrap', + gap: 0.5, }} > {chore?.labelsV2?.map((label, index) => ( { {label?.name} ))} + + {chore?.attachments?.length > 0 && ( + } + size='md' + variant='soft' + color='neutral' + onClick={() => setAttachmentBrowserOpen(true)} + sx={{ cursor: 'pointer' }} + > + {chore.attachments.length}{' '} + {chore.attachments.length === 1 ? 'attachment' : 'attachments'} + + )} @@ -918,7 +935,7 @@ const ChoreView = () => { whiteSpace: 'pre-wrap', wordBreak: 'break-word', }} - dangerouslySetInnerHTML={{ __html: raw }} + dangerouslySetInnerHTML={{ __html: refreshSignedUrlsInHtml(raw) }} /> ) : ( { whiteSpace: 'pre-wrap', wordBreak: 'break-word', }} - dangerouslySetInnerHTML={{ __html: raw }} + dangerouslySetInnerHTML={{ __html: refreshSignedUrlsInHtml(raw) }} /> ) : ( { + setAttachmentBrowserOpen(false)} + /> ) diff --git a/src/views/ChoreEdit/RepeatSection.jsx b/src/views/ChoreEdit/RepeatSection.jsx index a7d3c44..4cb4fa9 100644 --- a/src/views/ChoreEdit/RepeatSection.jsx +++ b/src/views/ChoreEdit/RepeatSection.jsx @@ -108,7 +108,7 @@ const generateSchedulePreview = (metadata, formatTimeFn) => { return `Every ${dayNames} at ${timeStr}` } -const RepeatOnSections = ({ +export const RepeatOnSections = ({ frequencyType, frequency, onFrequencyUpdate, diff --git a/src/views/Chores/ArchivedTasks.jsx b/src/views/Chores/ArchivedTasks.jsx index c292ad3..cf118f3 100644 --- a/src/views/Chores/ArchivedTasks.jsx +++ b/src/views/Chores/ArchivedTasks.jsx @@ -1,13 +1,16 @@ import { - Archive, - CheckBox, - CheckBoxOutlineBlank, - Close, - Delete, - SelectAll, - Unarchive, - ViewAgenda, - ViewModule, + Archive, + CheckBox, + CheckBoxOutlineBlank, + Close, + Delete, + Label, + Person, + PriorityHigh, + SelectAll, + Unarchive, + ViewAgenda, + ViewModule, } from '@mui/icons-material' import { Box, @@ -22,15 +25,18 @@ import { } from '@mui/joy' import { useQueryClient } from '@tanstack/react-query' import Fuse from 'fuse.js' -import { useEffect, useRef, useState } from 'react' +import { useEffect, useMemo, useRef, useState } from 'react' import { useNavigate } from 'react-router-dom' +import FilterBar from '../../components/common/FilterBar' import KeyboardShortcutHint from '../../components/common/KeyboardShortcutHint' import { useImpersonateUser } from '../../contexts/ImpersonateUserContext.jsx' +import { useFilter } from '../../hooks/useFilter' import { useUnArchiveChore } from '../../queries/ChoreQueries' import { useCircleMembers, useUserProfile } from '../../queries/UserQueries' import { useNotification } from '../../service/NotificationProvider' import { commandQueue, CommandType } from '../../utils/CommandQueue' import { DeleteChore, GetArchivedChores } from '../../utils/Fetcher' +import Priorities from '../../utils/Priorities' import { offlineDB } from '../../utils/OfflineDB' import LoadingComponent from '../components/Loading' import ConfirmationModal from '../Modals/Inputs/ConfirmationModal' @@ -107,6 +113,95 @@ const ArchivedTasks = () => { const { data: membersData, isLoading: membersLoading } = useCircleMembers() + // Unique labels present across all archived chores + const availableLabels = useMemo(() => { + const seen = {} + archivedChores.forEach(c => { + c.labelsV2?.forEach(l => { seen[l.id] = l }) + }) + return Object.values(seen) + }, [archivedChores]) + + const filterDefs = useMemo( + () => [ + { + id: 'assignee', + label: 'Assignee', + type: 'multi-select', + icon: , + options: performers.map(p => ({ + value: p.userId, + label: p.displayName, + avatar: p.image, + })), + filterFn: (item, values) => values.includes(item.assignedTo), + }, + { + id: 'priority', + label: 'Priority', + type: 'multi-select', + icon: , + options: Priorities.map(p => ({ + value: p.value, + label: p.name, + color: p.color || 'neutral', + icon: p.icon, + })), + filterFn: (item, values) => values.includes(item.priority ?? 0), + }, + ...(availableLabels.length > 0 + ? [ + { + id: 'label', + label: 'Labels', + type: 'multi-select', + icon: