@rs-native-kit/version-check 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +256 -0
- package/VersionCheck.podspec +20 -0
- package/android/build.gradle +56 -0
- package/android/src/main/AndroidManifest.xml +9 -0
- package/android/src/main/java/com/rsnativekit/versioncheck/SecureStorageCipher.kt +57 -0
- package/android/src/main/java/com/rsnativekit/versioncheck/VersionCheckHeadlessTaskService.kt +31 -0
- package/android/src/main/java/com/rsnativekit/versioncheck/VersionCheckModule.kt +215 -0
- package/android/src/main/java/com/rsnativekit/versioncheck/VersionCheckPackage.kt +31 -0
- package/android/src/main/java/com/rsnativekit/versioncheck/VersionCheckWorker.kt +29 -0
- package/ios/PlatformBridge/Ed25519Verifier.swift +19 -0
- package/ios/VersionCheck.h +5 -0
- package/ios/VersionCheck.mm +278 -0
- package/lib/module/data/cache/MemoryCacheStore.js +30 -0
- package/lib/module/data/cache/MemoryCacheStore.js.map +1 -0
- package/lib/module/data/cache/PersistentCacheStore.js +56 -0
- package/lib/module/data/cache/PersistentCacheStore.js.map +1 -0
- package/lib/module/data/config/ConfigCache.js +29 -0
- package/lib/module/data/config/ConfigCache.js.map +1 -0
- package/lib/module/data/config/ConfigDocumentValidator.js +185 -0
- package/lib/module/data/config/ConfigDocumentValidator.js.map +1 -0
- package/lib/module/data/config/ConfigLoader.js +82 -0
- package/lib/module/data/config/ConfigLoader.js.map +1 -0
- package/lib/module/data/config/ConfigProvider.js +58 -0
- package/lib/module/data/config/ConfigProvider.js.map +1 -0
- package/lib/module/data/config/ConfigResolutionPipeline.js +268 -0
- package/lib/module/data/config/ConfigResolutionPipeline.js.map +1 -0
- package/lib/module/data/config/ConfigValidator.js +69 -0
- package/lib/module/data/config/ConfigValidator.js.map +1 -0
- package/lib/module/data/config/SignatureVerifier.js +80 -0
- package/lib/module/data/config/SignatureVerifier.js.map +1 -0
- package/lib/module/data/config/canonicalize.js +88 -0
- package/lib/module/data/config/canonicalize.js.map +1 -0
- package/lib/module/data/config/sources/EnvironmentOverrideSource.js +20 -0
- package/lib/module/data/config/sources/EnvironmentOverrideSource.js.map +1 -0
- package/lib/module/data/config/sources/LocalConfigSource.js +22 -0
- package/lib/module/data/config/sources/LocalConfigSource.js.map +1 -0
- package/lib/module/data/config/sources/RemoteConfigSource.js +38 -0
- package/lib/module/data/config/sources/RemoteConfigSource.js.map +1 -0
- package/lib/module/data/providers/amazon/AmazonAppstoreProvider.js +13 -0
- package/lib/module/data/providers/amazon/AmazonAppstoreProvider.js.map +1 -0
- package/lib/module/data/providers/apple/AppleStoreProvider.js +67 -0
- package/lib/module/data/providers/apple/AppleStoreProvider.js.map +1 -0
- package/lib/module/data/providers/custom-api/CustomApiProvider.js +51 -0
- package/lib/module/data/providers/custom-api/CustomApiProvider.js.map +1 -0
- package/lib/module/data/providers/firebase-remote-config/FirebaseRemoteConfigProvider.js +13 -0
- package/lib/module/data/providers/firebase-remote-config/FirebaseRemoteConfigProvider.js.map +1 -0
- package/lib/module/data/providers/google-play/GooglePlayProvider.js +62 -0
- package/lib/module/data/providers/google-play/GooglePlayProvider.js.map +1 -0
- package/lib/module/data/providers/huawei/HuaweiAppGalleryProvider.js +18 -0
- package/lib/module/data/providers/huawei/HuaweiAppGalleryProvider.js.map +1 -0
- package/lib/module/data/repositories/VersionRepositoryImpl.js +69 -0
- package/lib/module/data/repositories/VersionRepositoryImpl.js.map +1 -0
- package/lib/module/di/container.js +80 -0
- package/lib/module/di/container.js.map +1 -0
- package/lib/module/domain/IVersionManagerCore.js +4 -0
- package/lib/module/domain/IVersionManagerCore.js.map +1 -0
- package/lib/module/domain/VersionManagerCore.js +276 -0
- package/lib/module/domain/VersionManagerCore.js.map +1 -0
- package/lib/module/domain/engines/decision/DecisionEngine.js +40 -0
- package/lib/module/domain/engines/decision/DecisionEngine.js.map +1 -0
- package/lib/module/domain/engines/policy/IUpdatePolicyEngine.js +4 -0
- package/lib/module/domain/engines/policy/IUpdatePolicyEngine.js.map +1 -0
- package/lib/module/domain/engines/policy/PolicyEngine.js +42 -0
- package/lib/module/domain/engines/policy/PolicyEngine.js.map +1 -0
- package/lib/module/domain/engines/semver/IVersionComparator.js +4 -0
- package/lib/module/domain/engines/semver/IVersionComparator.js.map +1 -0
- package/lib/module/domain/engines/semver/SemVerEngine.js +176 -0
- package/lib/module/domain/engines/semver/SemVerEngine.js.map +1 -0
- package/lib/module/domain/errors/VersionManagerException.js +104 -0
- package/lib/module/domain/errors/VersionManagerException.js.map +1 -0
- package/lib/module/domain/models/ActionPlan.js +9 -0
- package/lib/module/domain/models/ActionPlan.js.map +1 -0
- package/lib/module/domain/models/ConfigDocument.js +4 -0
- package/lib/module/domain/models/ConfigDocument.js.map +1 -0
- package/lib/module/domain/models/Events.js +4 -0
- package/lib/module/domain/models/Events.js.map +1 -0
- package/lib/module/domain/models/LifecycleState.js +29 -0
- package/lib/module/domain/models/LifecycleState.js.map +1 -0
- package/lib/module/domain/models/ParsedVersion.js +2 -0
- package/lib/module/domain/models/ParsedVersion.js.map +1 -0
- package/lib/module/domain/models/PlatformId.js +2 -0
- package/lib/module/domain/models/PlatformId.js.map +1 -0
- package/lib/module/domain/models/PublicApiOptions.js +2 -0
- package/lib/module/domain/models/PublicApiOptions.js.map +1 -0
- package/lib/module/domain/models/RemoteVersionInfo.js +4 -0
- package/lib/module/domain/models/RemoteVersionInfo.js.map +1 -0
- package/lib/module/domain/models/StoreLookup.js +2 -0
- package/lib/module/domain/models/StoreLookup.js.map +1 -0
- package/lib/module/domain/models/Unsubscribe.js +2 -0
- package/lib/module/domain/models/Unsubscribe.js.map +1 -0
- package/lib/module/domain/models/UpdateInfo.js +4 -0
- package/lib/module/domain/models/UpdateInfo.js.map +1 -0
- package/lib/module/domain/models/VersionManagerOptions.js +4 -0
- package/lib/module/domain/models/VersionManagerOptions.js.map +1 -0
- package/lib/module/domain/ports/ICacheStore.js +2 -0
- package/lib/module/domain/ports/ICacheStore.js.map +1 -0
- package/lib/module/domain/ports/IClock.js +2 -0
- package/lib/module/domain/ports/IClock.js.map +1 -0
- package/lib/module/domain/ports/IConfigProvider.js +4 -0
- package/lib/module/domain/ports/IConfigProvider.js.map +1 -0
- package/lib/module/domain/ports/IConfigSources.js +4 -0
- package/lib/module/domain/ports/IConfigSources.js.map +1 -0
- package/lib/module/domain/ports/IPlatformBridge.js +4 -0
- package/lib/module/domain/ports/IPlatformBridge.js.map +1 -0
- package/lib/module/domain/ports/IStoreProvider.js +4 -0
- package/lib/module/domain/ports/IStoreProvider.js.map +1 -0
- package/lib/module/domain/ports/IVersionRepository.js +4 -0
- package/lib/module/domain/ports/IVersionRepository.js.map +1 -0
- package/lib/module/domain/statemachine/LifecycleStateMachine.js +55 -0
- package/lib/module/domain/statemachine/LifecycleStateMachine.js.map +1 -0
- package/lib/module/domain/usecases/CheckForUpdatesUseCase.js +31 -0
- package/lib/module/domain/usecases/CheckForUpdatesUseCase.js.map +1 -0
- package/lib/module/domain/usecases/ForceTriggerUpdateUseCase.js +20 -0
- package/lib/module/domain/usecases/ForceTriggerUpdateUseCase.js.map +1 -0
- package/lib/module/domain/usecases/ResetIgnoredVersionsUseCase.js +24 -0
- package/lib/module/domain/usecases/ResetIgnoredVersionsUseCase.js.map +1 -0
- package/lib/module/index.js +10 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/platform/contracts/IPlatformBridge.js +2 -0
- package/lib/module/platform/contracts/IPlatformBridge.js.map +1 -0
- package/lib/module/platform/createPlatformBridge.js +17 -0
- package/lib/module/platform/createPlatformBridge.js.map +1 -0
- package/lib/module/platform/createPlatformBridge.native.js +9 -0
- package/lib/module/platform/createPlatformBridge.native.js.map +1 -0
- package/lib/module/platform/native/NativePlatformBridge.js +143 -0
- package/lib/module/platform/native/NativePlatformBridge.js.map +1 -0
- package/lib/module/platform/native/NativeVersionCheck.js +33 -0
- package/lib/module/platform/native/NativeVersionCheck.js.map +1 -0
- package/lib/module/platform/web/WebPlatformBridge.js +228 -0
- package/lib/module/platform/web/WebPlatformBridge.js.map +1 -0
- package/lib/module/presentation/components/ForceUpdateScreen.js +68 -0
- package/lib/module/presentation/components/ForceUpdateScreen.js.map +1 -0
- package/lib/module/presentation/components/OptionalUpdateBanner.js +69 -0
- package/lib/module/presentation/components/OptionalUpdateBanner.js.map +1 -0
- package/lib/module/presentation/components/SoftUpdateDialog.js +101 -0
- package/lib/module/presentation/components/SoftUpdateDialog.js.map +1 -0
- package/lib/module/presentation/hooks/VersionManagerProvider.js +18 -0
- package/lib/module/presentation/hooks/VersionManagerProvider.js.map +1 -0
- package/lib/module/presentation/hooks/context.js +5 -0
- package/lib/module/presentation/hooks/context.js.map +1 -0
- package/lib/module/presentation/hooks/useUpdateState.js +26 -0
- package/lib/module/presentation/hooks/useUpdateState.js.map +1 -0
- package/lib/module/presentation/hooks/useVersionManager.js +33 -0
- package/lib/module/presentation/hooks/useVersionManager.js.map +1 -0
- package/lib/module/presentation/state/VersionManagerStore.js +47 -0
- package/lib/module/presentation/state/VersionManagerStore.js.map +1 -0
- package/lib/module/publicApi.js +114 -0
- package/lib/module/publicApi.js.map +1 -0
- package/lib/module/shared/eventbus/EventBus.js +34 -0
- package/lib/module/shared/eventbus/EventBus.js.map +1 -0
- package/lib/module/shared/logging/Logger.js +56 -0
- package/lib/module/shared/logging/Logger.js.map +1 -0
- package/lib/module/ui.js +13 -0
- package/lib/module/ui.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/data/cache/MemoryCacheStore.d.ts +12 -0
- package/lib/typescript/src/data/cache/MemoryCacheStore.d.ts.map +1 -0
- package/lib/typescript/src/data/cache/PersistentCacheStore.d.ts +14 -0
- package/lib/typescript/src/data/cache/PersistentCacheStore.d.ts.map +1 -0
- package/lib/typescript/src/data/config/ConfigCache.d.ts +15 -0
- package/lib/typescript/src/data/config/ConfigCache.d.ts.map +1 -0
- package/lib/typescript/src/data/config/ConfigDocumentValidator.d.ts +20 -0
- package/lib/typescript/src/data/config/ConfigDocumentValidator.d.ts.map +1 -0
- package/lib/typescript/src/data/config/ConfigLoader.d.ts +28 -0
- package/lib/typescript/src/data/config/ConfigLoader.d.ts.map +1 -0
- package/lib/typescript/src/data/config/ConfigProvider.d.ts +30 -0
- package/lib/typescript/src/data/config/ConfigProvider.d.ts.map +1 -0
- package/lib/typescript/src/data/config/ConfigResolutionPipeline.d.ts +49 -0
- package/lib/typescript/src/data/config/ConfigResolutionPipeline.d.ts.map +1 -0
- package/lib/typescript/src/data/config/ConfigValidator.d.ts +10 -0
- package/lib/typescript/src/data/config/ConfigValidator.d.ts.map +1 -0
- package/lib/typescript/src/data/config/SignatureVerifier.d.ts +16 -0
- package/lib/typescript/src/data/config/SignatureVerifier.d.ts.map +1 -0
- package/lib/typescript/src/data/config/canonicalize.d.ts +13 -0
- package/lib/typescript/src/data/config/canonicalize.d.ts.map +1 -0
- package/lib/typescript/src/data/config/sources/EnvironmentOverrideSource.d.ts +17 -0
- package/lib/typescript/src/data/config/sources/EnvironmentOverrideSource.d.ts.map +1 -0
- package/lib/typescript/src/data/config/sources/LocalConfigSource.d.ts +19 -0
- package/lib/typescript/src/data/config/sources/LocalConfigSource.d.ts.map +1 -0
- package/lib/typescript/src/data/config/sources/RemoteConfigSource.d.ts +10 -0
- package/lib/typescript/src/data/config/sources/RemoteConfigSource.d.ts.map +1 -0
- package/lib/typescript/src/data/providers/amazon/AmazonAppstoreProvider.d.ts +9 -0
- package/lib/typescript/src/data/providers/amazon/AmazonAppstoreProvider.d.ts.map +1 -0
- package/lib/typescript/src/data/providers/apple/AppleStoreProvider.d.ts +19 -0
- package/lib/typescript/src/data/providers/apple/AppleStoreProvider.d.ts.map +1 -0
- package/lib/typescript/src/data/providers/custom-api/CustomApiProvider.d.ts +14 -0
- package/lib/typescript/src/data/providers/custom-api/CustomApiProvider.d.ts.map +1 -0
- package/lib/typescript/src/data/providers/firebase-remote-config/FirebaseRemoteConfigProvider.d.ts +9 -0
- package/lib/typescript/src/data/providers/firebase-remote-config/FirebaseRemoteConfigProvider.d.ts.map +1 -0
- package/lib/typescript/src/data/providers/google-play/GooglePlayProvider.d.ts +22 -0
- package/lib/typescript/src/data/providers/google-play/GooglePlayProvider.d.ts.map +1 -0
- package/lib/typescript/src/data/providers/huawei/HuaweiAppGalleryProvider.d.ts +14 -0
- package/lib/typescript/src/data/providers/huawei/HuaweiAppGalleryProvider.d.ts.map +1 -0
- package/lib/typescript/src/data/repositories/VersionRepositoryImpl.d.ts +23 -0
- package/lib/typescript/src/data/repositories/VersionRepositoryImpl.d.ts.map +1 -0
- package/lib/typescript/src/di/container.d.ts +12 -0
- package/lib/typescript/src/di/container.d.ts.map +1 -0
- package/lib/typescript/src/domain/IVersionManagerCore.d.ts +30 -0
- package/lib/typescript/src/domain/IVersionManagerCore.d.ts.map +1 -0
- package/lib/typescript/src/domain/VersionManagerCore.d.ts +94 -0
- package/lib/typescript/src/domain/VersionManagerCore.d.ts.map +1 -0
- package/lib/typescript/src/domain/engines/decision/DecisionEngine.d.ts +16 -0
- package/lib/typescript/src/domain/engines/decision/DecisionEngine.d.ts.map +1 -0
- package/lib/typescript/src/domain/engines/policy/IUpdatePolicyEngine.d.ts +17 -0
- package/lib/typescript/src/domain/engines/policy/IUpdatePolicyEngine.d.ts.map +1 -0
- package/lib/typescript/src/domain/engines/policy/PolicyEngine.d.ts +16 -0
- package/lib/typescript/src/domain/engines/policy/PolicyEngine.d.ts.map +1 -0
- package/lib/typescript/src/domain/engines/semver/IVersionComparator.d.ts +7 -0
- package/lib/typescript/src/domain/engines/semver/IVersionComparator.d.ts.map +1 -0
- package/lib/typescript/src/domain/engines/semver/SemVerEngine.d.ts +11 -0
- package/lib/typescript/src/domain/engines/semver/SemVerEngine.d.ts.map +1 -0
- package/lib/typescript/src/domain/errors/VersionManagerException.d.ts +97 -0
- package/lib/typescript/src/domain/errors/VersionManagerException.d.ts.map +1 -0
- package/lib/typescript/src/domain/models/ActionPlan.d.ts +15 -0
- package/lib/typescript/src/domain/models/ActionPlan.d.ts.map +1 -0
- package/lib/typescript/src/domain/models/ConfigDocument.d.ts +86 -0
- package/lib/typescript/src/domain/models/ConfigDocument.d.ts.map +1 -0
- package/lib/typescript/src/domain/models/Events.d.ts +39 -0
- package/lib/typescript/src/domain/models/Events.d.ts.map +1 -0
- package/lib/typescript/src/domain/models/LifecycleState.d.ts +18 -0
- package/lib/typescript/src/domain/models/LifecycleState.d.ts.map +1 -0
- package/lib/typescript/src/domain/models/ParsedVersion.d.ts +9 -0
- package/lib/typescript/src/domain/models/ParsedVersion.d.ts.map +1 -0
- package/lib/typescript/src/domain/models/PlatformId.d.ts +3 -0
- package/lib/typescript/src/domain/models/PlatformId.d.ts.map +1 -0
- package/lib/typescript/src/domain/models/PublicApiOptions.d.ts +13 -0
- package/lib/typescript/src/domain/models/PublicApiOptions.d.ts.map +1 -0
- package/lib/typescript/src/domain/models/RemoteVersionInfo.d.ts +21 -0
- package/lib/typescript/src/domain/models/RemoteVersionInfo.d.ts.map +1 -0
- package/lib/typescript/src/domain/models/StoreLookup.d.ts +12 -0
- package/lib/typescript/src/domain/models/StoreLookup.d.ts.map +1 -0
- package/lib/typescript/src/domain/models/Unsubscribe.d.ts +2 -0
- package/lib/typescript/src/domain/models/Unsubscribe.d.ts.map +1 -0
- package/lib/typescript/src/domain/models/UpdateInfo.d.ts +11 -0
- package/lib/typescript/src/domain/models/UpdateInfo.d.ts.map +1 -0
- package/lib/typescript/src/domain/models/VersionManagerOptions.d.ts +149 -0
- package/lib/typescript/src/domain/models/VersionManagerOptions.d.ts.map +1 -0
- package/lib/typescript/src/domain/ports/ICacheStore.d.ts +6 -0
- package/lib/typescript/src/domain/ports/ICacheStore.d.ts.map +1 -0
- package/lib/typescript/src/domain/ports/IClock.d.ts +4 -0
- package/lib/typescript/src/domain/ports/IClock.d.ts.map +1 -0
- package/lib/typescript/src/domain/ports/IConfigProvider.d.ts +11 -0
- package/lib/typescript/src/domain/ports/IConfigProvider.d.ts.map +1 -0
- package/lib/typescript/src/domain/ports/IConfigSources.d.ts +25 -0
- package/lib/typescript/src/domain/ports/IConfigSources.d.ts.map +1 -0
- package/lib/typescript/src/domain/ports/IPlatformBridge.d.ts +77 -0
- package/lib/typescript/src/domain/ports/IPlatformBridge.d.ts.map +1 -0
- package/lib/typescript/src/domain/ports/IStoreProvider.d.ts +7 -0
- package/lib/typescript/src/domain/ports/IStoreProvider.d.ts.map +1 -0
- package/lib/typescript/src/domain/ports/IVersionRepository.d.ts +8 -0
- package/lib/typescript/src/domain/ports/IVersionRepository.d.ts.map +1 -0
- package/lib/typescript/src/domain/statemachine/LifecycleStateMachine.d.ts +25 -0
- package/lib/typescript/src/domain/statemachine/LifecycleStateMachine.d.ts.map +1 -0
- package/lib/typescript/src/domain/usecases/CheckForUpdatesUseCase.d.ts +30 -0
- package/lib/typescript/src/domain/usecases/CheckForUpdatesUseCase.d.ts.map +1 -0
- package/lib/typescript/src/domain/usecases/ForceTriggerUpdateUseCase.d.ts +17 -0
- package/lib/typescript/src/domain/usecases/ForceTriggerUpdateUseCase.d.ts.map +1 -0
- package/lib/typescript/src/domain/usecases/ResetIgnoredVersionsUseCase.d.ts +7 -0
- package/lib/typescript/src/domain/usecases/ResetIgnoredVersionsUseCase.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +17 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/platform/contracts/IPlatformBridge.d.ts +2 -0
- package/lib/typescript/src/platform/contracts/IPlatformBridge.d.ts.map +1 -0
- package/lib/typescript/src/platform/createPlatformBridge.d.ts +12 -0
- package/lib/typescript/src/platform/createPlatformBridge.d.ts.map +1 -0
- package/lib/typescript/src/platform/createPlatformBridge.native.d.ts +4 -0
- package/lib/typescript/src/platform/createPlatformBridge.native.d.ts.map +1 -0
- package/lib/typescript/src/platform/native/NativePlatformBridge.d.ts +17 -0
- package/lib/typescript/src/platform/native/NativePlatformBridge.d.ts.map +1 -0
- package/lib/typescript/src/platform/native/NativeVersionCheck.d.ts +45 -0
- package/lib/typescript/src/platform/native/NativeVersionCheck.d.ts.map +1 -0
- package/lib/typescript/src/platform/web/WebPlatformBridge.d.ts +17 -0
- package/lib/typescript/src/platform/web/WebPlatformBridge.d.ts.map +1 -0
- package/lib/typescript/src/presentation/components/ForceUpdateScreen.d.ts +12 -0
- package/lib/typescript/src/presentation/components/ForceUpdateScreen.d.ts.map +1 -0
- package/lib/typescript/src/presentation/components/OptionalUpdateBanner.d.ts +12 -0
- package/lib/typescript/src/presentation/components/OptionalUpdateBanner.d.ts.map +1 -0
- package/lib/typescript/src/presentation/components/SoftUpdateDialog.d.ts +14 -0
- package/lib/typescript/src/presentation/components/SoftUpdateDialog.d.ts.map +1 -0
- package/lib/typescript/src/presentation/hooks/VersionManagerProvider.d.ts +9 -0
- package/lib/typescript/src/presentation/hooks/VersionManagerProvider.d.ts.map +1 -0
- package/lib/typescript/src/presentation/hooks/context.d.ts +3 -0
- package/lib/typescript/src/presentation/hooks/context.d.ts.map +1 -0
- package/lib/typescript/src/presentation/hooks/useUpdateState.d.ts +17 -0
- package/lib/typescript/src/presentation/hooks/useUpdateState.d.ts.map +1 -0
- package/lib/typescript/src/presentation/hooks/useVersionManager.d.ts +22 -0
- package/lib/typescript/src/presentation/hooks/useVersionManager.d.ts.map +1 -0
- package/lib/typescript/src/presentation/state/VersionManagerStore.d.ts +28 -0
- package/lib/typescript/src/presentation/state/VersionManagerStore.d.ts.map +1 -0
- package/lib/typescript/src/publicApi.d.ts +24 -0
- package/lib/typescript/src/publicApi.d.ts.map +1 -0
- package/lib/typescript/src/shared/eventbus/EventBus.d.ts +21 -0
- package/lib/typescript/src/shared/eventbus/EventBus.d.ts.map +1 -0
- package/lib/typescript/src/shared/logging/Logger.d.ts +17 -0
- package/lib/typescript/src/shared/logging/Logger.d.ts.map +1 -0
- package/lib/typescript/src/ui.d.ts +15 -0
- package/lib/typescript/src/ui.d.ts.map +1 -0
- package/package.json +192 -0
- package/src/data/cache/MemoryCacheStore.ts +36 -0
- package/src/data/cache/PersistentCacheStore.ts +63 -0
- package/src/data/config/ConfigCache.ts +30 -0
- package/src/data/config/ConfigDocumentValidator.ts +309 -0
- package/src/data/config/ConfigLoader.ts +105 -0
- package/src/data/config/ConfigProvider.ts +84 -0
- package/src/data/config/ConfigResolutionPipeline.ts +424 -0
- package/src/data/config/ConfigValidator.ts +79 -0
- package/src/data/config/SignatureVerifier.ts +90 -0
- package/src/data/config/canonicalize.ts +111 -0
- package/src/data/config/sources/EnvironmentOverrideSource.ts +22 -0
- package/src/data/config/sources/LocalConfigSource.ts +24 -0
- package/src/data/config/sources/RemoteConfigSource.ts +41 -0
- package/src/data/providers/amazon/AmazonAppstoreProvider.ts +16 -0
- package/src/data/providers/apple/AppleStoreProvider.ts +94 -0
- package/src/data/providers/custom-api/CustomApiProvider.ts +75 -0
- package/src/data/providers/firebase-remote-config/FirebaseRemoteConfigProvider.ts +16 -0
- package/src/data/providers/google-play/GooglePlayProvider.ts +75 -0
- package/src/data/providers/huawei/HuaweiAppGalleryProvider.ts +21 -0
- package/src/data/repositories/VersionRepositoryImpl.ts +90 -0
- package/src/di/container.ts +128 -0
- package/src/domain/IVersionManagerCore.ts +54 -0
- package/src/domain/VersionManagerCore.ts +425 -0
- package/src/domain/engines/decision/DecisionEngine.ts +47 -0
- package/src/domain/engines/policy/IUpdatePolicyEngine.ts +18 -0
- package/src/domain/engines/policy/PolicyEngine.ts +60 -0
- package/src/domain/engines/semver/IVersionComparator.ts +7 -0
- package/src/domain/engines/semver/SemVerEngine.ts +200 -0
- package/src/domain/errors/VersionManagerException.ts +166 -0
- package/src/domain/models/ActionPlan.ts +17 -0
- package/src/domain/models/ConfigDocument.ts +97 -0
- package/src/domain/models/Events.ts +48 -0
- package/src/domain/models/LifecycleState.ts +50 -0
- package/src/domain/models/ParsedVersion.ts +8 -0
- package/src/domain/models/PlatformId.ts +9 -0
- package/src/domain/models/PublicApiOptions.ts +14 -0
- package/src/domain/models/RemoteVersionInfo.ts +23 -0
- package/src/domain/models/StoreLookup.ts +12 -0
- package/src/domain/models/Unsubscribe.ts +1 -0
- package/src/domain/models/UpdateInfo.ts +11 -0
- package/src/domain/models/VersionManagerOptions.ts +150 -0
- package/src/domain/ports/ICacheStore.ts +5 -0
- package/src/domain/ports/IClock.ts +3 -0
- package/src/domain/ports/IConfigProvider.ts +18 -0
- package/src/domain/ports/IConfigSources.ts +44 -0
- package/src/domain/ports/IPlatformBridge.ts +97 -0
- package/src/domain/ports/IStoreProvider.ts +12 -0
- package/src/domain/ports/IVersionRepository.ts +14 -0
- package/src/domain/statemachine/LifecycleStateMachine.ts +76 -0
- package/src/domain/usecases/CheckForUpdatesUseCase.ts +63 -0
- package/src/domain/usecases/ForceTriggerUpdateUseCase.ts +35 -0
- package/src/domain/usecases/ResetIgnoredVersionsUseCase.ts +26 -0
- package/src/index.tsx +84 -0
- package/src/platform/contracts/IPlatformBridge.ts +14 -0
- package/src/platform/createPlatformBridge.native.ts +7 -0
- package/src/platform/createPlatformBridge.ts +15 -0
- package/src/platform/native/NativePlatformBridge.ts +179 -0
- package/src/platform/native/NativeVersionCheck.ts +64 -0
- package/src/platform/web/WebPlatformBridge.ts +347 -0
- package/src/presentation/components/ForceUpdateScreen.tsx +64 -0
- package/src/presentation/components/OptionalUpdateBanner.tsx +53 -0
- package/src/presentation/components/SoftUpdateDialog.tsx +84 -0
- package/src/presentation/hooks/VersionManagerProvider.tsx +23 -0
- package/src/presentation/hooks/context.ts +6 -0
- package/src/presentation/hooks/useUpdateState.ts +50 -0
- package/src/presentation/hooks/useVersionManager.ts +68 -0
- package/src/presentation/state/VersionManagerStore.ts +72 -0
- package/src/publicApi.ts +126 -0
- package/src/shared/eventbus/EventBus.ts +56 -0
- package/src/shared/logging/Logger.ts +70 -0
- package/src/ui.tsx +19 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { InvalidVersionFormatException } from '../../errors/VersionManagerException';
|
|
2
|
+
import type { ParsedVersion } from '../../models/ParsedVersion';
|
|
3
|
+
import type { IVersionComparator } from './IVersionComparator';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Zero-dependency SemVer 2.0.0 parser/comparator (Prompt 1 §9.3 — no `semver` package).
|
|
7
|
+
* Supports the full strict grammar plus a small set of common looseness (leading "v",
|
|
8
|
+
* 1 or 2 part versions). Range support covers "^", "~", the comparison operators, and
|
|
9
|
+
* whitespace-separated AND clauses — OR ("||") ranges and prerelease-scoped range
|
|
10
|
+
* matching are intentionally out of scope for this pass; see Prompt 5 in the design
|
|
11
|
+
* series for the full BNF grammar and edge-case matrix this should eventually match.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const STRICT_SEMVER_REGEX =
|
|
15
|
+
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
|
|
16
|
+
|
|
17
|
+
const LOOSE_VERSION_REGEX = /^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\..*)?$/;
|
|
18
|
+
|
|
19
|
+
function toIdentifiers(segment: string | undefined): (string | number)[] {
|
|
20
|
+
if (!segment) return [];
|
|
21
|
+
return segment.split('.').map((part) => {
|
|
22
|
+
return /^\d+$/.test(part) ? Number(part) : part;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function parseVersion(raw: string): ParsedVersion {
|
|
27
|
+
if (typeof raw !== 'string' || raw.trim().length === 0) {
|
|
28
|
+
throw new InvalidVersionFormatException({
|
|
29
|
+
message: `Cannot parse version: expected a non-empty string, received "${String(raw)}"`,
|
|
30
|
+
metadata: { raw },
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const trimmed = raw.trim().replace(/^[vV]/, '');
|
|
35
|
+
const strict = STRICT_SEMVER_REGEX.exec(trimmed);
|
|
36
|
+
if (strict) {
|
|
37
|
+
const [, majorStr, minorStr, patchStr, prerelease, build] = strict;
|
|
38
|
+
return {
|
|
39
|
+
raw,
|
|
40
|
+
major: Number(majorStr),
|
|
41
|
+
minor: Number(minorStr),
|
|
42
|
+
patch: Number(patchStr),
|
|
43
|
+
prerelease: toIdentifiers(prerelease),
|
|
44
|
+
build: build ? build.split('.') : [],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const loose = LOOSE_VERSION_REGEX.exec(trimmed);
|
|
49
|
+
if (loose) {
|
|
50
|
+
const [, majorStr, minorStr, patchStr] = loose;
|
|
51
|
+
return {
|
|
52
|
+
raw,
|
|
53
|
+
major: Number(majorStr),
|
|
54
|
+
minor: minorStr !== undefined ? Number(minorStr) : 0,
|
|
55
|
+
patch: patchStr !== undefined ? Number(patchStr) : 0,
|
|
56
|
+
prerelease: [],
|
|
57
|
+
build: [],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
throw new InvalidVersionFormatException({
|
|
62
|
+
message: `Cannot parse version: "${raw}" does not match a recognized SemVer format`,
|
|
63
|
+
metadata: { raw },
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function comparePrerelease(
|
|
68
|
+
a: readonly (string | number)[],
|
|
69
|
+
b: readonly (string | number)[]
|
|
70
|
+
): -1 | 0 | 1 {
|
|
71
|
+
if (a.length === 0 && b.length === 0) return 0;
|
|
72
|
+
if (a.length === 0) return 1; // no prerelease outranks any prerelease
|
|
73
|
+
if (b.length === 0) return -1;
|
|
74
|
+
|
|
75
|
+
const len = Math.max(a.length, b.length);
|
|
76
|
+
for (let i = 0; i < len; i++) {
|
|
77
|
+
const ai = a[i];
|
|
78
|
+
const bi = b[i];
|
|
79
|
+
if (ai === undefined) return -1; // shorter set of identifiers = lower precedence
|
|
80
|
+
if (bi === undefined) return 1;
|
|
81
|
+
if (ai === bi) continue;
|
|
82
|
+
|
|
83
|
+
const aIsNumber = typeof ai === 'number';
|
|
84
|
+
const bIsNumber = typeof bi === 'number';
|
|
85
|
+
if (aIsNumber && bIsNumber) return ai < bi ? -1 : 1;
|
|
86
|
+
if (aIsNumber && !bIsNumber) return -1; // numeric identifiers always have lower precedence
|
|
87
|
+
if (!aIsNumber && bIsNumber) return 1;
|
|
88
|
+
return String(ai) < String(bi) ? -1 : 1;
|
|
89
|
+
}
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function compareVersions(
|
|
94
|
+
a: ParsedVersion,
|
|
95
|
+
b: ParsedVersion
|
|
96
|
+
): -1 | 0 | 1 {
|
|
97
|
+
if (a.major !== b.major) return a.major < b.major ? -1 : 1;
|
|
98
|
+
if (a.minor !== b.minor) return a.minor < b.minor ? -1 : 1;
|
|
99
|
+
if (a.patch !== b.patch) return a.patch < b.patch ? -1 : 1;
|
|
100
|
+
return comparePrerelease(a.prerelease, b.prerelease);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function bumpUpperBound(
|
|
104
|
+
base: ParsedVersion,
|
|
105
|
+
kind: 'caret' | 'tilde'
|
|
106
|
+
): ParsedVersion {
|
|
107
|
+
if (kind === 'tilde') {
|
|
108
|
+
return {
|
|
109
|
+
...base,
|
|
110
|
+
minor: base.minor + 1,
|
|
111
|
+
patch: 0,
|
|
112
|
+
prerelease: [],
|
|
113
|
+
build: [],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
if (base.major > 0) {
|
|
117
|
+
return {
|
|
118
|
+
...base,
|
|
119
|
+
major: base.major + 1,
|
|
120
|
+
minor: 0,
|
|
121
|
+
patch: 0,
|
|
122
|
+
prerelease: [],
|
|
123
|
+
build: [],
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (base.minor > 0) {
|
|
127
|
+
return {
|
|
128
|
+
...base,
|
|
129
|
+
minor: base.minor + 1,
|
|
130
|
+
patch: 0,
|
|
131
|
+
prerelease: [],
|
|
132
|
+
build: [],
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return { ...base, patch: base.patch + 1, prerelease: [], build: [] };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function satisfiesClause(version: ParsedVersion, clause: string): boolean {
|
|
139
|
+
const caretMatch = /^\^(.+)$/.exec(clause);
|
|
140
|
+
const caretArg = caretMatch?.[1];
|
|
141
|
+
if (caretArg) {
|
|
142
|
+
const base = parseVersion(caretArg);
|
|
143
|
+
const upper = bumpUpperBound(base, 'caret');
|
|
144
|
+
return (
|
|
145
|
+
compareVersions(version, base) >= 0 && compareVersions(version, upper) < 0
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const tildeMatch = /^~(.+)$/.exec(clause);
|
|
150
|
+
const tildeArg = tildeMatch?.[1];
|
|
151
|
+
if (tildeArg) {
|
|
152
|
+
const base = parseVersion(tildeArg);
|
|
153
|
+
const upper = bumpUpperBound(base, 'tilde');
|
|
154
|
+
return (
|
|
155
|
+
compareVersions(version, base) >= 0 && compareVersions(version, upper) < 0
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const opMatch = /^(>=|<=|>|<|=)?(.+)$/.exec(clause);
|
|
160
|
+
const opArg = opMatch?.[2];
|
|
161
|
+
if (opArg) {
|
|
162
|
+
const operator = opMatch?.[1] ?? '=';
|
|
163
|
+
const target = parseVersion(opArg);
|
|
164
|
+
const cmp = compareVersions(version, target);
|
|
165
|
+
switch (operator) {
|
|
166
|
+
case '>=':
|
|
167
|
+
return cmp >= 0;
|
|
168
|
+
case '<=':
|
|
169
|
+
return cmp <= 0;
|
|
170
|
+
case '>':
|
|
171
|
+
return cmp > 0;
|
|
172
|
+
case '<':
|
|
173
|
+
return cmp < 0;
|
|
174
|
+
default:
|
|
175
|
+
return cmp === 0;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function satisfiesRange(version: ParsedVersion, range: string): boolean {
|
|
183
|
+
const clauses = range.trim().split(/\s+/).filter(Boolean);
|
|
184
|
+
if (clauses.length === 0) return false;
|
|
185
|
+
return clauses.every((clause) => satisfiesClause(version, clause));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export class SemVerEngine implements IVersionComparator {
|
|
189
|
+
parse(raw: string): ParsedVersion {
|
|
190
|
+
return parseVersion(raw);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
compare(a: ParsedVersion, b: ParsedVersion): -1 | 0 | 1 {
|
|
194
|
+
return compareVersions(a, b);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
satisfies(version: ParsedVersion, range: string): boolean {
|
|
198
|
+
return satisfiesRange(version, range);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
export type VersionManagerErrorCode =
|
|
2
|
+
| 'VM-1001' // InvalidConfigException
|
|
3
|
+
| 'VM-1002' // NotInitializedException
|
|
4
|
+
| 'VM-1003' // NotReadyException
|
|
5
|
+
| 'VM-1004' // SchemaValidationException
|
|
6
|
+
| 'VM-1005' // BoundaryValidationException
|
|
7
|
+
| 'VM-1006' // SignatureVerificationException
|
|
8
|
+
| 'VM-1007' // ConfigSizeLimitExceededException
|
|
9
|
+
| 'VM-1008' // UntrustedKeyIdException
|
|
10
|
+
| 'VM-1009' // EnvironmentOverrideConflictException
|
|
11
|
+
| 'VM-2001' // RequestTimeoutException
|
|
12
|
+
| 'VM-2002' // RateLimitException
|
|
13
|
+
| 'VM-2003' // OfflineException
|
|
14
|
+
| 'VM-2004' // TlsHandshakeException
|
|
15
|
+
| 'VM-3001' // AppNotFoundException
|
|
16
|
+
| 'VM-3002' // StorePermissionException
|
|
17
|
+
| 'VM-3003' // UnsupportedStoreException
|
|
18
|
+
| 'VM-3004' // StoreResponseParseException
|
|
19
|
+
| 'VM-4001' // InvalidVersionFormatException
|
|
20
|
+
| 'VM-5001' // PolicyEvaluationException
|
|
21
|
+
| 'VM-6001' // CacheCorruptionException
|
|
22
|
+
| 'VM-6002' // CacheWriteException
|
|
23
|
+
| 'VM-7001' // PlatformBridgeException
|
|
24
|
+
| 'VM-9999'; // UnknownVersionManagerException
|
|
25
|
+
|
|
26
|
+
export interface VersionManagerExceptionInit {
|
|
27
|
+
message: string;
|
|
28
|
+
cause?: unknown;
|
|
29
|
+
metadata?: Record<string, unknown>;
|
|
30
|
+
retryable?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export abstract class VersionManagerException extends Error {
|
|
34
|
+
abstract readonly code: VersionManagerErrorCode;
|
|
35
|
+
readonly cause: unknown;
|
|
36
|
+
readonly metadata: Readonly<Record<string, unknown>>;
|
|
37
|
+
readonly retryable: boolean;
|
|
38
|
+
readonly timestamp: number;
|
|
39
|
+
|
|
40
|
+
constructor(init: VersionManagerExceptionInit) {
|
|
41
|
+
super(init.message);
|
|
42
|
+
this.name = new.target.name;
|
|
43
|
+
this.cause = init.cause;
|
|
44
|
+
this.metadata = Object.freeze({ ...init.metadata });
|
|
45
|
+
this.retryable = init.retryable ?? false;
|
|
46
|
+
this.timestamp = Date.now();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export class InvalidConfigException extends VersionManagerException {
|
|
51
|
+
readonly code = 'VM-1001' as const;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export class NotInitializedException extends VersionManagerException {
|
|
55
|
+
readonly code = 'VM-1002' as const;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class NotReadyException extends VersionManagerException {
|
|
59
|
+
readonly code = 'VM-1003' as const;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export class SchemaValidationException extends VersionManagerException {
|
|
63
|
+
readonly code = 'VM-1004' as const;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export class BoundaryValidationException extends VersionManagerException {
|
|
67
|
+
readonly code = 'VM-1005' as const;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export class SignatureVerificationException extends VersionManagerException {
|
|
71
|
+
readonly code = 'VM-1006' as const;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export class ConfigSizeLimitExceededException extends VersionManagerException {
|
|
75
|
+
readonly code = 'VM-1007' as const;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export class UntrustedKeyIdException extends VersionManagerException {
|
|
79
|
+
readonly code = 'VM-1008' as const;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export class EnvironmentOverrideConflictException extends VersionManagerException {
|
|
83
|
+
readonly code = 'VM-1009' as const;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export abstract class NetworkException extends VersionManagerException {}
|
|
87
|
+
|
|
88
|
+
export class RequestTimeoutException extends NetworkException {
|
|
89
|
+
readonly code = 'VM-2001' as const;
|
|
90
|
+
override readonly retryable = true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export class RateLimitException extends NetworkException {
|
|
94
|
+
readonly code = 'VM-2002' as const;
|
|
95
|
+
override readonly retryable = true;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export class OfflineException extends NetworkException {
|
|
99
|
+
readonly code = 'VM-2003' as const;
|
|
100
|
+
override readonly retryable = true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export class TlsHandshakeException extends NetworkException {
|
|
104
|
+
readonly code = 'VM-2004' as const;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export abstract class StoreProviderException extends VersionManagerException {}
|
|
108
|
+
|
|
109
|
+
export class AppNotFoundException extends StoreProviderException {
|
|
110
|
+
readonly code = 'VM-3001' as const;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export class StorePermissionException extends StoreProviderException {
|
|
114
|
+
readonly code = 'VM-3002' as const;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export class UnsupportedStoreException extends StoreProviderException {
|
|
118
|
+
readonly code = 'VM-3003' as const;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export class StoreResponseParseException extends StoreProviderException {
|
|
122
|
+
readonly code = 'VM-3004' as const;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export class InvalidVersionFormatException extends VersionManagerException {
|
|
126
|
+
readonly code = 'VM-4001' as const;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export class PolicyEvaluationException extends VersionManagerException {
|
|
130
|
+
readonly code = 'VM-5001' as const;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export abstract class CacheException extends VersionManagerException {}
|
|
134
|
+
|
|
135
|
+
export class CacheCorruptionException extends CacheException {
|
|
136
|
+
readonly code = 'VM-6001' as const;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export class CacheWriteException extends CacheException {
|
|
140
|
+
readonly code = 'VM-6002' as const;
|
|
141
|
+
override readonly retryable = true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export class PlatformBridgeException extends VersionManagerException {
|
|
145
|
+
readonly code = 'VM-7001' as const;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export class UnknownVersionManagerException extends VersionManagerException {
|
|
149
|
+
readonly code = 'VM-9999' as const;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function toVersionManagerException(
|
|
153
|
+
error: unknown
|
|
154
|
+
): VersionManagerException {
|
|
155
|
+
if (error instanceof VersionManagerException) return error;
|
|
156
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
157
|
+
return new UnknownVersionManagerException({ message, cause: error });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function isConfigTierException(
|
|
161
|
+
error: unknown
|
|
162
|
+
): error is VersionManagerException {
|
|
163
|
+
return (
|
|
164
|
+
error instanceof VersionManagerException && error.code.startsWith('VM-1')
|
|
165
|
+
);
|
|
166
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { UpdateInfo } from './UpdateInfo';
|
|
2
|
+
|
|
3
|
+
export const ActionType = {
|
|
4
|
+
NO_ACTION: 'NO_ACTION',
|
|
5
|
+
FORCE_UPDATE: 'FORCE_UPDATE',
|
|
6
|
+
SOFT_UPDATE: 'SOFT_UPDATE',
|
|
7
|
+
OPTIONAL_REMINDER: 'OPTIONAL_REMINDER',
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
export type ActionType = (typeof ActionType)[keyof typeof ActionType];
|
|
11
|
+
|
|
12
|
+
export interface ActionPlan {
|
|
13
|
+
readonly type: ActionType;
|
|
14
|
+
readonly updateInfo: UpdateInfo | null;
|
|
15
|
+
readonly reason: string;
|
|
16
|
+
readonly decidedAt: number;
|
|
17
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { StoreLinksOptions } from './VersionManagerOptions';
|
|
2
|
+
|
|
3
|
+
/** Doc 03 §1.1 — the loadable configuration document (payload of a SignedConfigEnvelope). */
|
|
4
|
+
export interface VersionManagerConfigDocument {
|
|
5
|
+
readonly localVersionIdentifier?: string;
|
|
6
|
+
readonly remoteConfigUrl?: string;
|
|
7
|
+
readonly cache?: {
|
|
8
|
+
readonly ttlMs?: number;
|
|
9
|
+
readonly storage?: 'memory' | 'persistent';
|
|
10
|
+
};
|
|
11
|
+
readonly network?: {
|
|
12
|
+
readonly requestTimeoutMs?: number;
|
|
13
|
+
readonly retry?: {
|
|
14
|
+
readonly maxAttempts?: number;
|
|
15
|
+
readonly backoff?: 'fixed' | 'exponential-jitter';
|
|
16
|
+
readonly baseDelayMs?: number;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
readonly alerts?: {
|
|
20
|
+
readonly forceUpdateBelow?: string;
|
|
21
|
+
readonly reminderDelayMs?: number;
|
|
22
|
+
readonly customUiHookIds?: readonly string[];
|
|
23
|
+
};
|
|
24
|
+
readonly stores?: StoreLinksOptions;
|
|
25
|
+
/**
|
|
26
|
+
* Only ever read from tier 4 (configure()) per §4.2 — a document cannot alter the
|
|
27
|
+
* rules used to verify documents. Present in the type for schema-shape completeness
|
|
28
|
+
* (an incoming document that includes it is structurally valid but this field is
|
|
29
|
+
* always ignored by the precedence merge — see ConfigResolutionPipeline).
|
|
30
|
+
*/
|
|
31
|
+
readonly security?: {
|
|
32
|
+
readonly signatureAlgorithm?: 'ed25519' | 'hmac-sha256' | 'none';
|
|
33
|
+
readonly trustedKeyIds?: readonly string[];
|
|
34
|
+
};
|
|
35
|
+
readonly schemaVersion?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type SignatureAlgorithm = 'ed25519' | 'hmac-sha256' | 'none';
|
|
39
|
+
|
|
40
|
+
/** Doc 03 §3.1 — envelope wrapping every local/remote config document. */
|
|
41
|
+
export interface SignedConfigEnvelope {
|
|
42
|
+
readonly schemaVersion: string;
|
|
43
|
+
readonly payload: VersionManagerConfigDocument;
|
|
44
|
+
readonly signature: {
|
|
45
|
+
readonly algorithm: SignatureAlgorithm;
|
|
46
|
+
readonly keyId: string;
|
|
47
|
+
readonly value: string; // base64
|
|
48
|
+
readonly signedAt: string; // ISO 8601
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Opaque raw bytes/JSON before schema validation has proven its shape. */
|
|
53
|
+
export type RawConfigDocument = unknown;
|
|
54
|
+
|
|
55
|
+
export interface ConfigLoadRequest {
|
|
56
|
+
readonly defaults: import('./VersionManagerOptions').VersionManagerOptions;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface FetchOptions {
|
|
60
|
+
readonly timeoutMs: number;
|
|
61
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface TrustedKeySet {
|
|
65
|
+
readonly algorithm: SignatureAlgorithm;
|
|
66
|
+
/**
|
|
67
|
+
* Trusted keyIds only — per doc 03 §3.4, actual key material (public keys / HMAC
|
|
68
|
+
* secrets) is embedded at build time on the native side (Info.plist/BuildConfig), not
|
|
69
|
+
* shipped through JS. JS only needs to confirm the envelope's keyId is one this app
|
|
70
|
+
* trusts, then hand the keyId to ICryptoProvider, which resolves it to key material
|
|
71
|
+
* natively.
|
|
72
|
+
*/
|
|
73
|
+
readonly keys: ReadonlySet<string>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export type ConfigTier = 'env' | 'remote' | 'local' | 'default';
|
|
77
|
+
|
|
78
|
+
export interface SchemaValidationResult {
|
|
79
|
+
readonly valid: boolean;
|
|
80
|
+
readonly errors: readonly string[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface BoundaryValidationResult {
|
|
84
|
+
readonly valid: boolean;
|
|
85
|
+
/** Field-path -> reason, so the pipeline can drop only the offending fields (§7.3). */
|
|
86
|
+
readonly fieldErrors: ReadonlyMap<string, string>;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface SignatureVerificationResult {
|
|
90
|
+
readonly valid: boolean;
|
|
91
|
+
readonly reason?: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface ResolvedConfigWithProvenance {
|
|
95
|
+
readonly config: import('./VersionManagerOptions').ResolvedVersionManagerConfig;
|
|
96
|
+
readonly tier: ConfigTier;
|
|
97
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { VersionManagerException } from '../errors/VersionManagerException';
|
|
2
|
+
import type { ActionPlan } from './ActionPlan';
|
|
3
|
+
import type { LifecycleState } from './LifecycleState';
|
|
4
|
+
import type { UpdateInfo } from './UpdateInfo';
|
|
5
|
+
|
|
6
|
+
export interface StateChangedEvent {
|
|
7
|
+
readonly from: LifecycleState;
|
|
8
|
+
readonly to: LifecycleState;
|
|
9
|
+
readonly timestamp: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface UpdateDetectedEvent {
|
|
13
|
+
readonly updateInfo: UpdateInfo;
|
|
14
|
+
readonly actionPlan: ActionPlan;
|
|
15
|
+
readonly timestamp: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface UpdateNotAvailableEvent {
|
|
19
|
+
readonly currentVersion: string;
|
|
20
|
+
readonly checkedAt: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type UserActionType =
|
|
24
|
+
'update_clicked' | 'later_clicked' | 'ignore_clicked' | 'dismiss_clicked';
|
|
25
|
+
|
|
26
|
+
export interface UserActionEvent {
|
|
27
|
+
readonly action: UserActionType;
|
|
28
|
+
readonly updateInfo: UpdateInfo;
|
|
29
|
+
readonly timestamp: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type ErrorPhase = 'config' | 'check' | 'policy' | 'presentation';
|
|
33
|
+
|
|
34
|
+
export interface VersionManagerErrorEvent {
|
|
35
|
+
readonly error: VersionManagerException;
|
|
36
|
+
readonly phase: ErrorPhase;
|
|
37
|
+
readonly timestamp: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface VersionManagerEventMap {
|
|
41
|
+
stateChanged: StateChangedEvent;
|
|
42
|
+
updateDetected: UpdateDetectedEvent;
|
|
43
|
+
updateNotAvailable: UpdateNotAvailableEvent;
|
|
44
|
+
userAction: UserActionEvent;
|
|
45
|
+
error: VersionManagerErrorEvent;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type VersionManagerEventType = keyof VersionManagerEventMap;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export const LifecycleState = {
|
|
2
|
+
UNINITIALIZED: 'UNINITIALIZED',
|
|
3
|
+
CONFIG_LOADING: 'CONFIG_LOADING',
|
|
4
|
+
IDLE: 'IDLE',
|
|
5
|
+
VERSION_CHECKING: 'VERSION_CHECKING',
|
|
6
|
+
DECIDING: 'DECIDING',
|
|
7
|
+
FORCE_UPDATE_DISPLAYED: 'FORCE_UPDATE_DISPLAYED',
|
|
8
|
+
SOFT_UPDATE_DISPLAYED: 'SOFT_UPDATE_DISPLAYED',
|
|
9
|
+
REJECTED_WAITING_REMINDER: 'REJECTED_WAITING_REMINDER',
|
|
10
|
+
TERMINATED: 'TERMINATED',
|
|
11
|
+
} as const;
|
|
12
|
+
|
|
13
|
+
export type LifecycleState =
|
|
14
|
+
(typeof LifecycleState)[keyof typeof LifecycleState];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Allowed transitions. Anything not listed here is invalid and
|
|
18
|
+
* ILifecycleStateMachine.transition() must reject it.
|
|
19
|
+
*/
|
|
20
|
+
export const LIFECYCLE_TRANSITIONS: Readonly<
|
|
21
|
+
Record<LifecycleState, readonly LifecycleState[]>
|
|
22
|
+
> = {
|
|
23
|
+
UNINITIALIZED: [LifecycleState.CONFIG_LOADING],
|
|
24
|
+
CONFIG_LOADING: [LifecycleState.IDLE, LifecycleState.TERMINATED],
|
|
25
|
+
IDLE: [LifecycleState.VERSION_CHECKING, LifecycleState.TERMINATED],
|
|
26
|
+
VERSION_CHECKING: [
|
|
27
|
+
LifecycleState.DECIDING,
|
|
28
|
+
LifecycleState.IDLE,
|
|
29
|
+
LifecycleState.TERMINATED,
|
|
30
|
+
],
|
|
31
|
+
DECIDING: [
|
|
32
|
+
LifecycleState.FORCE_UPDATE_DISPLAYED,
|
|
33
|
+
LifecycleState.SOFT_UPDATE_DISPLAYED,
|
|
34
|
+
LifecycleState.REJECTED_WAITING_REMINDER,
|
|
35
|
+
LifecycleState.IDLE,
|
|
36
|
+
LifecycleState.TERMINATED,
|
|
37
|
+
],
|
|
38
|
+
FORCE_UPDATE_DISPLAYED: [LifecycleState.TERMINATED],
|
|
39
|
+
SOFT_UPDATE_DISPLAYED: [
|
|
40
|
+
LifecycleState.IDLE,
|
|
41
|
+
LifecycleState.REJECTED_WAITING_REMINDER,
|
|
42
|
+
LifecycleState.TERMINATED,
|
|
43
|
+
],
|
|
44
|
+
REJECTED_WAITING_REMINDER: [
|
|
45
|
+
LifecycleState.IDLE,
|
|
46
|
+
LifecycleState.VERSION_CHECKING,
|
|
47
|
+
LifecycleState.TERMINATED,
|
|
48
|
+
],
|
|
49
|
+
TERMINATED: [],
|
|
50
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface CheckForUpdatesOptions {
|
|
2
|
+
bypassCache?: boolean;
|
|
3
|
+
silent?: boolean;
|
|
4
|
+
timeoutMs?: number;
|
|
5
|
+
context?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ForceTriggerOptions {
|
|
9
|
+
reason?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ResetIgnoredVersionsOptions {
|
|
13
|
+
versions?: string[];
|
|
14
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { PlatformId, StoreProviderId } from './PlatformId';
|
|
2
|
+
|
|
3
|
+
export interface RemoteVersionInfo {
|
|
4
|
+
readonly latestVersion: string;
|
|
5
|
+
readonly storeUrl: string;
|
|
6
|
+
readonly releaseNotes: string | null;
|
|
7
|
+
readonly minimumOsVersion: string | null;
|
|
8
|
+
readonly fetchedAt: number;
|
|
9
|
+
readonly provider: StoreProviderId;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface VersionCheckRequest {
|
|
13
|
+
readonly currentVersion: string;
|
|
14
|
+
readonly bundleId: string;
|
|
15
|
+
readonly platform: PlatformId;
|
|
16
|
+
readonly bypassCache: boolean;
|
|
17
|
+
readonly timeoutMs: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface UserVersionDecision {
|
|
21
|
+
readonly ignoredVersions: readonly string[];
|
|
22
|
+
readonly remindMeLaterUntil: number | null;
|
|
23
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface StoreLookupRequest {
|
|
2
|
+
readonly bundleId: string;
|
|
3
|
+
readonly region: string | null;
|
|
4
|
+
readonly timeoutMs: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface StoreLookupResult {
|
|
8
|
+
readonly latestVersion: string;
|
|
9
|
+
readonly storeUrl: string;
|
|
10
|
+
readonly releaseNotes: string | null;
|
|
11
|
+
readonly minimumOsVersion: string | null;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Unsubscribe = () => void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { StoreProviderId } from './PlatformId';
|
|
2
|
+
|
|
3
|
+
export interface UpdateInfo {
|
|
4
|
+
readonly currentVersion: string;
|
|
5
|
+
readonly latestVersion: string;
|
|
6
|
+
readonly storeUrl: string;
|
|
7
|
+
readonly releaseNotes: string | null;
|
|
8
|
+
readonly isForceUpdate: boolean;
|
|
9
|
+
readonly provider: StoreProviderId;
|
|
10
|
+
readonly fetchedAt: number;
|
|
11
|
+
}
|