@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,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { parseVersion } from "../../domain/engines/semver/SemVerEngine.js";
|
|
4
|
+
import { InvalidConfigException } from "../../domain/errors/VersionManagerException.js";
|
|
5
|
+
/**
|
|
6
|
+
* Boundary validation (Prompt 3 §2.2) for the "default fallback" config tier — the
|
|
7
|
+
* VersionManagerOptions object passed to configure(). Full JSON-Schema structural
|
|
8
|
+
* validation and signature verification for local/remote config documents (Prompt 3
|
|
9
|
+
* §2.1, §3) are scoped to the not-yet-built config-document pipeline; see
|
|
10
|
+
* docs/architecture/03-configuration-system.md.
|
|
11
|
+
*/
|
|
12
|
+
export function validateOptions(options) {
|
|
13
|
+
if (!options.stores || Object.keys(options.stores).length === 0) {
|
|
14
|
+
throw new InvalidConfigException({
|
|
15
|
+
message: 'VersionManagerOptions.stores must configure at least one store (ios/android/huawei/amazon/custom)'
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
if (options.appVersion !== undefined) {
|
|
19
|
+
try {
|
|
20
|
+
parseVersion(options.appVersion);
|
|
21
|
+
} catch (error) {
|
|
22
|
+
throw new InvalidConfigException({
|
|
23
|
+
message: `options.appVersion "${options.appVersion}" is not a valid SemVer string`,
|
|
24
|
+
cause: error
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (options.policy?.forceUpdateBelow !== undefined) {
|
|
29
|
+
try {
|
|
30
|
+
parseVersion(options.policy.forceUpdateBelow);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
throw new InvalidConfigException({
|
|
33
|
+
message: `options.policy.forceUpdateBelow "${options.policy.forceUpdateBelow}" is not a valid SemVer string`,
|
|
34
|
+
cause: error
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const timeoutMs = options.fallback?.requestTimeoutMs;
|
|
39
|
+
if (timeoutMs !== undefined && timeoutMs <= 0) {
|
|
40
|
+
throw new InvalidConfigException({
|
|
41
|
+
message: 'options.fallback.requestTimeoutMs must be greater than 0'
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const ttlMs = options.cache?.ttlMs;
|
|
45
|
+
if (ttlMs !== undefined && ttlMs < 0) {
|
|
46
|
+
throw new InvalidConfigException({
|
|
47
|
+
message: 'options.cache.ttlMs must be >= 0'
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const maxAttempts = options.fallback?.retry?.maxAttempts;
|
|
51
|
+
if (maxAttempts !== undefined && (maxAttempts < 0 || maxAttempts > 10)) {
|
|
52
|
+
throw new InvalidConfigException({
|
|
53
|
+
message: 'options.fallback.retry.maxAttempts must be between 0 and 10'
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const baseDelayMs = options.fallback?.retry?.baseDelayMs;
|
|
57
|
+
if (baseDelayMs !== undefined && baseDelayMs <= 0) {
|
|
58
|
+
throw new InvalidConfigException({
|
|
59
|
+
message: 'options.fallback.retry.baseDelayMs must be greater than 0'
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
const rolloutPercentage = options.policy?.rolloutPercentage;
|
|
63
|
+
if (rolloutPercentage !== undefined && (rolloutPercentage < 0 || rolloutPercentage > 100)) {
|
|
64
|
+
throw new InvalidConfigException({
|
|
65
|
+
message: 'options.policy.rolloutPercentage must be between 0 and 100'
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=ConfigValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["parseVersion","InvalidConfigException","validateOptions","options","stores","Object","keys","length","message","appVersion","undefined","error","cause","policy","forceUpdateBelow","timeoutMs","fallback","requestTimeoutMs","ttlMs","cache","maxAttempts","retry","baseDelayMs","rolloutPercentage"],"sourceRoot":"../../../../src","sources":["data/config/ConfigValidator.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,6CAA0C;AACvE,SAASC,sBAAsB,QAAQ,gDAA6C;AAGpF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAACC,OAA8B,EAAQ;EACpE,IAAI,CAACA,OAAO,CAACC,MAAM,IAAIC,MAAM,CAACC,IAAI,CAACH,OAAO,CAACC,MAAM,CAAC,CAACG,MAAM,KAAK,CAAC,EAAE;IAC/D,MAAM,IAAIN,sBAAsB,CAAC;MAC/BO,OAAO,EACL;IACJ,CAAC,CAAC;EACJ;EAEA,IAAIL,OAAO,CAACM,UAAU,KAAKC,SAAS,EAAE;IACpC,IAAI;MACFV,YAAY,CAACG,OAAO,CAACM,UAAU,CAAC;IAClC,CAAC,CAAC,OAAOE,KAAK,EAAE;MACd,MAAM,IAAIV,sBAAsB,CAAC;QAC/BO,OAAO,EAAE,uBAAuBL,OAAO,CAACM,UAAU,gCAAgC;QAClFG,KAAK,EAAED;MACT,CAAC,CAAC;IACJ;EACF;EAEA,IAAIR,OAAO,CAACU,MAAM,EAAEC,gBAAgB,KAAKJ,SAAS,EAAE;IAClD,IAAI;MACFV,YAAY,CAACG,OAAO,CAACU,MAAM,CAACC,gBAAgB,CAAC;IAC/C,CAAC,CAAC,OAAOH,KAAK,EAAE;MACd,MAAM,IAAIV,sBAAsB,CAAC;QAC/BO,OAAO,EAAE,oCAAoCL,OAAO,CAACU,MAAM,CAACC,gBAAgB,gCAAgC;QAC5GF,KAAK,EAAED;MACT,CAAC,CAAC;IACJ;EACF;EAEA,MAAMI,SAAS,GAAGZ,OAAO,CAACa,QAAQ,EAAEC,gBAAgB;EACpD,IAAIF,SAAS,KAAKL,SAAS,IAAIK,SAAS,IAAI,CAAC,EAAE;IAC7C,MAAM,IAAId,sBAAsB,CAAC;MAC/BO,OAAO,EAAE;IACX,CAAC,CAAC;EACJ;EAEA,MAAMU,KAAK,GAAGf,OAAO,CAACgB,KAAK,EAAED,KAAK;EAClC,IAAIA,KAAK,KAAKR,SAAS,IAAIQ,KAAK,GAAG,CAAC,EAAE;IACpC,MAAM,IAAIjB,sBAAsB,CAAC;MAC/BO,OAAO,EAAE;IACX,CAAC,CAAC;EACJ;EAEA,MAAMY,WAAW,GAAGjB,OAAO,CAACa,QAAQ,EAAEK,KAAK,EAAED,WAAW;EACxD,IAAIA,WAAW,KAAKV,SAAS,KAAKU,WAAW,GAAG,CAAC,IAAIA,WAAW,GAAG,EAAE,CAAC,EAAE;IACtE,MAAM,IAAInB,sBAAsB,CAAC;MAC/BO,OAAO,EAAE;IACX,CAAC,CAAC;EACJ;EAEA,MAAMc,WAAW,GAAGnB,OAAO,CAACa,QAAQ,EAAEK,KAAK,EAAEC,WAAW;EACxD,IAAIA,WAAW,KAAKZ,SAAS,IAAIY,WAAW,IAAI,CAAC,EAAE;IACjD,MAAM,IAAIrB,sBAAsB,CAAC;MAC/BO,OAAO,EAAE;IACX,CAAC,CAAC;EACJ;EAEA,MAAMe,iBAAiB,GAAGpB,OAAO,CAACU,MAAM,EAAEU,iBAAiB;EAC3D,IACEA,iBAAiB,KAAKb,SAAS,KAC9Ba,iBAAiB,GAAG,CAAC,IAAIA,iBAAiB,GAAG,GAAG,CAAC,EAClD;IACA,MAAM,IAAItB,sBAAsB,CAAC;MAC/BO,OAAO,EAAE;IACX,CAAC,CAAC;EACJ;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { canonicalize, utf8ToBase64 } from "./canonicalize.js";
|
|
4
|
+
function isDev() {
|
|
5
|
+
return typeof __DEV__ !== 'undefined' && __DEV__ === true;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Doc 03 §3.2/§3.4 — verification calls are implemented using OS-provided cryptography
|
|
10
|
+
* exclusively (iOS CryptoKit/Security.framework, Android java.security), reached through
|
|
11
|
+
* IPlatformBridge.crypto (ICryptoProvider) so this class never itself hand-rolls
|
|
12
|
+
* cryptographic primitives (Prompt 1 §9.3's zero-external-dependency constraint extends
|
|
13
|
+
* to "don't implement crypto in JS either" — only OS APIs are trusted for this).
|
|
14
|
+
*/
|
|
15
|
+
export class SignatureVerifier {
|
|
16
|
+
constructor(crypto) {
|
|
17
|
+
this.crypto = crypto;
|
|
18
|
+
}
|
|
19
|
+
async verify(envelope, trustedKeys) {
|
|
20
|
+
const {
|
|
21
|
+
algorithm,
|
|
22
|
+
keyId,
|
|
23
|
+
value
|
|
24
|
+
} = envelope.signature;
|
|
25
|
+
|
|
26
|
+
// §3.1: algorithm "none" is permitted only for the local bundled document in
|
|
27
|
+
// development builds — rejected for any remote fetch and for release builds,
|
|
28
|
+
// enforced here regardless of what security.signatureAlgorithm claims (a
|
|
29
|
+
// compromised document cannot downgrade its own algorithm to "none" and be
|
|
30
|
+
// believed). The pipeline is responsible for only calling verify() with a "none"
|
|
31
|
+
// envelope on the local-dev path in the first place; this is a defense-in-depth
|
|
32
|
+
// second check.
|
|
33
|
+
if (algorithm === 'none') {
|
|
34
|
+
if (!isDev()) {
|
|
35
|
+
return {
|
|
36
|
+
valid: false,
|
|
37
|
+
reason: 'signature.algorithm "none" is rejected outside development builds'
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
valid: true
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (trustedKeys.algorithm !== algorithm) {
|
|
45
|
+
return {
|
|
46
|
+
valid: false,
|
|
47
|
+
reason: `Envelope algorithm "${algorithm}" does not match configured security.signatureAlgorithm "${trustedKeys.algorithm}"`
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (!trustedKeys.keys.has(keyId)) {
|
|
51
|
+
return {
|
|
52
|
+
valid: false,
|
|
53
|
+
reason: `keyId "${keyId}" is not present in security.trustedKeyIds`
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (!this.crypto) {
|
|
57
|
+
return {
|
|
58
|
+
valid: false,
|
|
59
|
+
reason: 'No ICryptoProvider available on the active IPlatformBridge — cannot verify signatures on this target'
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const canonicalPayload = canonicalize(envelope.payload);
|
|
63
|
+
const messageBase64 = utf8ToBase64(canonicalPayload);
|
|
64
|
+
try {
|
|
65
|
+
const valid = algorithm === 'ed25519' ? await this.crypto.verifyEd25519(keyId, messageBase64, value) : await this.crypto.verifyHmacSha256(keyId, messageBase64, value);
|
|
66
|
+
return valid ? {
|
|
67
|
+
valid: true
|
|
68
|
+
} : {
|
|
69
|
+
valid: false,
|
|
70
|
+
reason: 'Signature mismatch'
|
|
71
|
+
};
|
|
72
|
+
} catch (error) {
|
|
73
|
+
return {
|
|
74
|
+
valid: false,
|
|
75
|
+
reason: `Native signature verification threw: ${String(error)}`
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=SignatureVerifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["canonicalize","utf8ToBase64","isDev","__DEV__","SignatureVerifier","constructor","crypto","verify","envelope","trustedKeys","algorithm","keyId","value","signature","valid","reason","keys","has","canonicalPayload","payload","messageBase64","verifyEd25519","verifyHmacSha256","error","String"],"sourceRoot":"../../../../src","sources":["data/config/SignatureVerifier.ts"],"mappings":";;AAAA,SAASA,YAAY,EAAEC,YAAY,QAAQ,mBAAgB;AAW3D,SAASC,KAAKA,CAAA,EAAY;EACxB,OAAO,OAAOC,OAAO,KAAK,WAAW,IAAIA,OAAO,KAAK,IAAI;AAC3D;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,iBAAiB,CAA+B;EAC3DC,WAAWA,CAAkBC,MAAwB,EAAE;IAAA,KAA1BA,MAAwB,GAAxBA,MAAwB;EAAG;EAExD,MAAMC,MAAMA,CACVC,QAA8B,EAC9BC,WAA0B,EACY;IACtC,MAAM;MAAEC,SAAS;MAAEC,KAAK;MAAEC;IAAM,CAAC,GAAGJ,QAAQ,CAACK,SAAS;;IAEtD;IACA;IACA;IACA;IACA;IACA;IACA;IACA,IAAIH,SAAS,KAAK,MAAM,EAAE;MACxB,IAAI,CAACR,KAAK,CAAC,CAAC,EAAE;QACZ,OAAO;UACLY,KAAK,EAAE,KAAK;UACZC,MAAM,EACJ;QACJ,CAAC;MACH;MACA,OAAO;QAAED,KAAK,EAAE;MAAK,CAAC;IACxB;IAEA,IAAIL,WAAW,CAACC,SAAS,KAAKA,SAAS,EAAE;MACvC,OAAO;QACLI,KAAK,EAAE,KAAK;QACZC,MAAM,EAAE,uBAAuBL,SAAS,4DAA4DD,WAAW,CAACC,SAAS;MAC3H,CAAC;IACH;IAEA,IAAI,CAACD,WAAW,CAACO,IAAI,CAACC,GAAG,CAACN,KAAK,CAAC,EAAE;MAChC,OAAO;QACLG,KAAK,EAAE,KAAK;QACZC,MAAM,EAAE,UAAUJ,KAAK;MACzB,CAAC;IACH;IAEA,IAAI,CAAC,IAAI,CAACL,MAAM,EAAE;MAChB,OAAO;QACLQ,KAAK,EAAE,KAAK;QACZC,MAAM,EACJ;MACJ,CAAC;IACH;IAEA,MAAMG,gBAAgB,GAAGlB,YAAY,CAACQ,QAAQ,CAACW,OAAO,CAAC;IACvD,MAAMC,aAAa,GAAGnB,YAAY,CAACiB,gBAAgB,CAAC;IAEpD,IAAI;MACF,MAAMJ,KAAK,GACTJ,SAAS,KAAK,SAAS,GACnB,MAAM,IAAI,CAACJ,MAAM,CAACe,aAAa,CAACV,KAAK,EAAES,aAAa,EAAER,KAAK,CAAC,GAC5D,MAAM,IAAI,CAACN,MAAM,CAACgB,gBAAgB,CAACX,KAAK,EAAES,aAAa,EAAER,KAAK,CAAC;MACrE,OAAOE,KAAK,GACR;QAAEA,KAAK,EAAE;MAAK,CAAC,GACf;QAAEA,KAAK,EAAE,KAAK;QAAEC,MAAM,EAAE;MAAqB,CAAC;IACpD,CAAC,CAAC,OAAOQ,KAAK,EAAE;MACd,OAAO;QACLT,KAAK,EAAE,KAAK;QACZC,MAAM,EAAE,wCAAwCS,MAAM,CAACD,KAAK,CAAC;MAC/D,CAAC;IACH;EACF;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Hand-rolled canonicalizer (Prompt 1 §9.3 zero-dependency constraint), implementing the
|
|
5
|
+
* same principles as RFC 8785 (JSON Canonicalization Scheme) that doc 03 §3.3 calls for:
|
|
6
|
+
* recursive key sorting by UTF-16 code unit order, fixed number formatting, no
|
|
7
|
+
* insignificant whitespace. Signatures are computed/verified over this canonical byte
|
|
8
|
+
* form so that whitespace/key-order differences in transit never invalidate a
|
|
9
|
+
* legitimately signed document.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
function canonicalizeValue(value) {
|
|
13
|
+
if (value === null) return 'null';
|
|
14
|
+
if (typeof value === 'boolean') return value ? 'true' : 'false';
|
|
15
|
+
if (typeof value === 'number') return canonicalizeNumber(value);
|
|
16
|
+
if (typeof value === 'string') return JSON.stringify(value);
|
|
17
|
+
if (Array.isArray(value)) {
|
|
18
|
+
return `[${value.map(canonicalizeValue).join(',')}]`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Recursive key sorting, UTF-16 code unit order (default JS string `<` comparison).
|
|
22
|
+
const keys = Object.keys(value).sort();
|
|
23
|
+
const members = keys.map(key => `${JSON.stringify(key)}:${canonicalizeValue(value[key])}`);
|
|
24
|
+
return `{${members.join(',')}}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Fixed number formatting per RFC 8785 §3.2.2.3 (simplified): integers render without a
|
|
29
|
+
* decimal point/exponent; this codebase's config schema (doc 03 §6) only ever contains
|
|
30
|
+
* integers and no fractional/exponential numeric fields, so the full ECMA-262
|
|
31
|
+
* Number::toString algorithm RFC 8785 mandates is unnecessary here.
|
|
32
|
+
*/
|
|
33
|
+
function canonicalizeNumber(value) {
|
|
34
|
+
if (!Number.isFinite(value)) {
|
|
35
|
+
throw new Error('Cannot canonicalize a non-finite number');
|
|
36
|
+
}
|
|
37
|
+
if (Number.isInteger(value)) return String(value);
|
|
38
|
+
return String(value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Canonical byte sequence (as a UTF-8 string) for the given JSON-compatible value. */
|
|
42
|
+
export function canonicalize(value) {
|
|
43
|
+
return canonicalizeValue(value);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Base64 encoding of the UTF-8 bytes of a string, without relying on Node's Buffer. */
|
|
47
|
+
export function utf8ToBase64(input) {
|
|
48
|
+
if (typeof btoa === 'function' && typeof TextEncoder !== 'undefined') {
|
|
49
|
+
const bytes = new TextEncoder().encode(input);
|
|
50
|
+
let binary = '';
|
|
51
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
52
|
+
binary += String.fromCharCode(bytes[i]);
|
|
53
|
+
}
|
|
54
|
+
return btoa(binary);
|
|
55
|
+
}
|
|
56
|
+
// React Native's Hermes engine provides global Buffer via a polyfill in most RN
|
|
57
|
+
// setups, but not guaranteed — fall back to a minimal hand-rolled base64 encoder.
|
|
58
|
+
return manualUtf8ToBase64(input);
|
|
59
|
+
}
|
|
60
|
+
const BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
61
|
+
function manualUtf8ToBase64(input) {
|
|
62
|
+
const bytes = [];
|
|
63
|
+
for (let i = 0; i < input.length; i++) {
|
|
64
|
+
let code = input.codePointAt(i);
|
|
65
|
+
if (code > 0xffff) i++; // consumed a surrogate pair
|
|
66
|
+
if (code < 0x80) {
|
|
67
|
+
bytes.push(code);
|
|
68
|
+
} else if (code < 0x800) {
|
|
69
|
+
bytes.push(0xc0 | code >> 6, 0x80 | code & 0x3f);
|
|
70
|
+
} else if (code < 0x10000) {
|
|
71
|
+
bytes.push(0xe0 | code >> 12, 0x80 | code >> 6 & 0x3f, 0x80 | code & 0x3f);
|
|
72
|
+
} else {
|
|
73
|
+
bytes.push(0xf0 | code >> 18, 0x80 | code >> 12 & 0x3f, 0x80 | code >> 6 & 0x3f, 0x80 | code & 0x3f);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
let output = '';
|
|
77
|
+
for (let i = 0; i < bytes.length; i += 3) {
|
|
78
|
+
const b0 = bytes[i];
|
|
79
|
+
const b1 = bytes[i + 1];
|
|
80
|
+
const b2 = bytes[i + 2];
|
|
81
|
+
output += BASE64_CHARS[b0 >> 2];
|
|
82
|
+
output += BASE64_CHARS[(b0 & 0x03) << 4 | (b1 ?? 0) >> 4];
|
|
83
|
+
output += b1 === undefined ? '=' : BASE64_CHARS[(b1 & 0x0f) << 2 | (b2 ?? 0) >> 6];
|
|
84
|
+
output += b2 === undefined ? '=' : BASE64_CHARS[b2 & 0x3f];
|
|
85
|
+
}
|
|
86
|
+
return output;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=canonicalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["canonicalizeValue","value","canonicalizeNumber","JSON","stringify","Array","isArray","map","join","keys","Object","sort","members","key","Number","isFinite","Error","isInteger","String","canonicalize","utf8ToBase64","input","btoa","TextEncoder","bytes","encode","binary","i","length","fromCharCode","manualUtf8ToBase64","BASE64_CHARS","code","codePointAt","push","output","b0","b1","b2","undefined"],"sourceRoot":"../../../../src","sources":["data/config/canonicalize.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Doc 03 §4 — "there is no OS process environment on a device"; this tier maps to
|
|
5
|
+
* build-time-injected constants and explicit runtime overrides, not `process.env` on a
|
|
6
|
+
* server. Build-time constants (Info.plist / BuildConfig fields) are app-specific and
|
|
7
|
+
* have no generic cross-platform read path from JS, so this implementation covers the
|
|
8
|
+
* "explicit configure({ configSources: { envOverrides } })" half of §4.1 tier 1 — the
|
|
9
|
+
* build-time-constant half is a per-app integration concern (documented, not a gap in
|
|
10
|
+
* this port's contract, which only promises "read whatever overrides are available").
|
|
11
|
+
*/
|
|
12
|
+
export class EnvironmentOverrideSource {
|
|
13
|
+
constructor(overrides) {
|
|
14
|
+
this.overrides = overrides;
|
|
15
|
+
}
|
|
16
|
+
async read() {
|
|
17
|
+
return this.overrides ?? {};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=EnvironmentOverrideSource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["EnvironmentOverrideSource","constructor","overrides","read"],"sourceRoot":"../../../../../src","sources":["data/config/sources/EnvironmentOverrideSource.ts"],"mappings":";;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMA,yBAAyB,CAAuC;EAC3EC,WAAWA,CACQC,SACkC,EACnD;IAAA,KAFiBA,SACkC,GADlCA,SACkC;EAClD;EAEH,MAAMC,IAAIA,CAAA,EAAmD;IAC3D,OAAO,IAAI,CAACD,SAAS,IAAI,CAAC,CAAC;EAC7B;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Doc 03 §5.1 — the design calls for a native mmap reader (iOS Data(alwaysMapped),
|
|
5
|
+
* Android FileChannel.map) to avoid a double-copy when reading a bundled config asset.
|
|
6
|
+
* This implementation takes a documented, lower-risk equivalent instead: the host app
|
|
7
|
+
* imports its bundled config JSON via Metro/webpack's native JSON module support
|
|
8
|
+
* (`import localConfig from './vm-config.json'`) and passes the parsed envelope through
|
|
9
|
+
* `VersionManagerOptions.configSources.local`. Metro's JSON loader already avoids the
|
|
10
|
+
* page-cache -> native-heap -> JS-heap double copy for typical bundle sizes (the asset
|
|
11
|
+
* is compiled into the JS bundle itself), which satisfies §5.1's actual goal (avoid GC
|
|
12
|
+
* churn against the 5MB budget for a <=64KB document) without a dedicated native reader.
|
|
13
|
+
*/
|
|
14
|
+
export class LocalConfigSource {
|
|
15
|
+
constructor(envelope) {
|
|
16
|
+
this.envelope = envelope;
|
|
17
|
+
}
|
|
18
|
+
async read() {
|
|
19
|
+
return this.envelope ?? null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=LocalConfigSource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["LocalConfigSource","constructor","envelope","read"],"sourceRoot":"../../../../../src","sources":["data/config/sources/LocalConfigSource.ts"],"mappings":";;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMA,iBAAiB,CAA+B;EAC3DC,WAAWA,CAAkBC,QAA0C,EAAE;IAAA,KAA5CA,QAA0C,GAA1CA,QAA0C;EAAG;EAE1E,MAAMC,IAAIA,CAAA,EAAsC;IAC9C,OAAO,IAAI,CAACD,QAAQ,IAAI,IAAI;EAC9B;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { OfflineException, StoreResponseParseException } from "../../../domain/errors/VersionManagerException.js";
|
|
4
|
+
/** Doc 03 §4.3 — the remote-fetch tier, reached through the same IHttpClient port every other network call in this SDK uses. */
|
|
5
|
+
export class RemoteConfigSource {
|
|
6
|
+
constructor(http) {
|
|
7
|
+
this.http = http;
|
|
8
|
+
}
|
|
9
|
+
async fetch(url, options) {
|
|
10
|
+
const response = await this.http.request({
|
|
11
|
+
url,
|
|
12
|
+
method: 'GET',
|
|
13
|
+
headers: options.headers,
|
|
14
|
+
timeoutMs: options.timeoutMs
|
|
15
|
+
});
|
|
16
|
+
if (response.status !== 200) {
|
|
17
|
+
throw new OfflineException({
|
|
18
|
+
message: `Remote config fetch returned HTTP ${response.status}`,
|
|
19
|
+
metadata: {
|
|
20
|
+
url,
|
|
21
|
+
status: response.status
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(response.body);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
throw new StoreResponseParseException({
|
|
29
|
+
message: 'Remote config endpoint returned malformed JSON',
|
|
30
|
+
cause: error,
|
|
31
|
+
metadata: {
|
|
32
|
+
url
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=RemoteConfigSource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["OfflineException","StoreResponseParseException","RemoteConfigSource","constructor","http","fetch","url","options","response","request","method","headers","timeoutMs","status","message","metadata","JSON","parse","body","error","cause"],"sourceRoot":"../../../../../src","sources":["data/config/sources/RemoteConfigSource.ts"],"mappings":";;AAAA,SACEA,gBAAgB,EAChBC,2BAA2B,QACtB,mDAAgD;AAQvD;AACA,OAAO,MAAMC,kBAAkB,CAAgC;EAC7DC,WAAWA,CAAkBC,IAAiB,EAAE;IAAA,KAAnBA,IAAiB,GAAjBA,IAAiB;EAAG;EAEjD,MAAMC,KAAKA,CAACC,GAAW,EAAEC,OAAqB,EAA8B;IAC1E,MAAMC,QAAQ,GAAG,MAAM,IAAI,CAACJ,IAAI,CAACK,OAAO,CAAC;MACvCH,GAAG;MACHI,MAAM,EAAE,KAAK;MACbC,OAAO,EAAEJ,OAAO,CAACI,OAAO;MACxBC,SAAS,EAAEL,OAAO,CAACK;IACrB,CAAC,CAAC;IAEF,IAAIJ,QAAQ,CAACK,MAAM,KAAK,GAAG,EAAE;MAC3B,MAAM,IAAIb,gBAAgB,CAAC;QACzBc,OAAO,EAAE,qCAAqCN,QAAQ,CAACK,MAAM,EAAE;QAC/DE,QAAQ,EAAE;UAAET,GAAG;UAAEO,MAAM,EAAEL,QAAQ,CAACK;QAAO;MAC3C,CAAC,CAAC;IACJ;IAEA,IAAI;MACF,OAAOG,IAAI,CAACC,KAAK,CAACT,QAAQ,CAACU,IAAI,CAAC;IAClC,CAAC,CAAC,OAAOC,KAAK,EAAE;MACd,MAAM,IAAIlB,2BAA2B,CAAC;QACpCa,OAAO,EAAE,gDAAgD;QACzDM,KAAK,EAAED,KAAK;QACZJ,QAAQ,EAAE;UAAET;QAAI;MAClB,CAAC,CAAC;IACJ;EACF;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { UnsupportedStoreException } from "../../../domain/errors/VersionManagerException.js";
|
|
4
|
+
/** Not yet implemented — see Prompt 11 in the design series. */
|
|
5
|
+
export class AmazonAppstoreProvider {
|
|
6
|
+
id = 'amazon';
|
|
7
|
+
async fetchLatestVersionInfo() {
|
|
8
|
+
throw new UnsupportedStoreException({
|
|
9
|
+
message: 'Amazon Appstore provider is not yet implemented — see Prompt 11 in the design series'
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=AmazonAppstoreProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["UnsupportedStoreException","AmazonAppstoreProvider","id","fetchLatestVersionInfo","message"],"sourceRoot":"../../../../../src","sources":["data/providers/amazon/AmazonAppstoreProvider.ts"],"mappings":";;AAAA,SAASA,yBAAyB,QAAQ,mDAAgD;AAK1F;AACA,OAAO,MAAMC,sBAAsB,CAA2B;EACnDC,EAAE,GAAoB,QAAQ;EAEvC,MAAMC,sBAAsBA,CAAA,EAA+B;IACzD,MAAM,IAAIH,yBAAyB,CAAC;MAClCI,OAAO,EACL;IACJ,CAAC,CAAC;EACJ;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { AppNotFoundException, RateLimitException, StoreResponseParseException } from "../../../domain/errors/VersionManagerException.js";
|
|
4
|
+
/**
|
|
5
|
+
* Real implementation against the public iTunes Lookup API (Prompt 10). Accepts either
|
|
6
|
+
* the numeric App Store Connect id (`id=`) or, when the app developer doesn't want to
|
|
7
|
+
* hardcode one, falls back to looking the app up by its own bundle id (`bundleId=`) —
|
|
8
|
+
* the iTunes Lookup API supports both query params equivalently.
|
|
9
|
+
*/
|
|
10
|
+
export class AppleStoreProvider {
|
|
11
|
+
id = 'apple';
|
|
12
|
+
constructor(http, appStoreId, region = 'us') {
|
|
13
|
+
this.http = http;
|
|
14
|
+
this.appStoreId = appStoreId;
|
|
15
|
+
this.region = region;
|
|
16
|
+
}
|
|
17
|
+
async fetchLatestVersionInfo(request) {
|
|
18
|
+
const country = request.region ?? this.region;
|
|
19
|
+
const identifierParam = this.appStoreId ? `id=${encodeURIComponent(this.appStoreId)}` : `bundleId=${encodeURIComponent(request.bundleId)}`;
|
|
20
|
+
const url = `https://itunes.apple.com/lookup?${identifierParam}&country=${encodeURIComponent(country)}`;
|
|
21
|
+
const response = await this.http.request({
|
|
22
|
+
url,
|
|
23
|
+
method: 'GET',
|
|
24
|
+
timeoutMs: request.timeoutMs
|
|
25
|
+
});
|
|
26
|
+
const identifier = this.appStoreId ?? request.bundleId;
|
|
27
|
+
if (response.status === 429) {
|
|
28
|
+
throw new RateLimitException({
|
|
29
|
+
message: 'Apple iTunes Lookup API rate limit exceeded (HTTP 429)'
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
if (response.status !== 200) {
|
|
33
|
+
throw new AppNotFoundException({
|
|
34
|
+
message: `Apple iTunes Lookup API returned HTTP ${response.status}`,
|
|
35
|
+
metadata: {
|
|
36
|
+
identifier,
|
|
37
|
+
status: response.status
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
let payload;
|
|
42
|
+
try {
|
|
43
|
+
payload = JSON.parse(response.body);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
throw new StoreResponseParseException({
|
|
46
|
+
message: 'Apple iTunes Lookup API returned malformed JSON',
|
|
47
|
+
cause: error
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const result = payload.results[0];
|
|
51
|
+
if (!result) {
|
|
52
|
+
throw new AppNotFoundException({
|
|
53
|
+
message: `No app found in the App Store for "${identifier}"`,
|
|
54
|
+
metadata: {
|
|
55
|
+
identifier
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
latestVersion: result.version,
|
|
61
|
+
storeUrl: result.trackViewUrl,
|
|
62
|
+
releaseNotes: result.releaseNotes ?? null,
|
|
63
|
+
minimumOsVersion: result.minimumOsVersion ?? null
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=AppleStoreProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["AppNotFoundException","RateLimitException","StoreResponseParseException","AppleStoreProvider","id","constructor","http","appStoreId","region","fetchLatestVersionInfo","request","country","identifierParam","encodeURIComponent","bundleId","url","response","method","timeoutMs","identifier","status","message","metadata","payload","JSON","parse","body","error","cause","result","results","latestVersion","version","storeUrl","trackViewUrl","releaseNotes","minimumOsVersion"],"sourceRoot":"../../../../../src","sources":["data/providers/apple/AppleStoreProvider.ts"],"mappings":";;AAAA,SACEA,oBAAoB,EACpBC,kBAAkB,EAClBC,2BAA2B,QACtB,mDAAgD;AAqBvD;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,kBAAkB,CAA2B;EAC/CC,EAAE,GAAoB,OAAO;EAEtCC,WAAWA,CACQC,IAAiB,EACjBC,UAAmB,EACnBC,MAAc,GAAG,IAAI,EACtC;IAAA,KAHiBF,IAAiB,GAAjBA,IAAiB;IAAA,KACjBC,UAAmB,GAAnBA,UAAmB;IAAA,KACnBC,MAAc,GAAdA,MAAc;EAC9B;EAEH,MAAMC,sBAAsBA,CAC1BC,OAA2B,EACC;IAC5B,MAAMC,OAAO,GAAGD,OAAO,CAACF,MAAM,IAAI,IAAI,CAACA,MAAM;IAC7C,MAAMI,eAAe,GAAG,IAAI,CAACL,UAAU,GACnC,MAAMM,kBAAkB,CAAC,IAAI,CAACN,UAAU,CAAC,EAAE,GAC3C,YAAYM,kBAAkB,CAACH,OAAO,CAACI,QAAQ,CAAC,EAAE;IACtD,MAAMC,GAAG,GAAG,mCAAmCH,eAAe,YAAYC,kBAAkB,CAACF,OAAO,CAAC,EAAE;IACvG,MAAMK,QAAQ,GAAG,MAAM,IAAI,CAACV,IAAI,CAACI,OAAO,CAAC;MACvCK,GAAG;MACHE,MAAM,EAAE,KAAK;MACbC,SAAS,EAAER,OAAO,CAACQ;IACrB,CAAC,CAAC;IAEF,MAAMC,UAAU,GAAG,IAAI,CAACZ,UAAU,IAAIG,OAAO,CAACI,QAAQ;IAEtD,IAAIE,QAAQ,CAACI,MAAM,KAAK,GAAG,EAAE;MAC3B,MAAM,IAAInB,kBAAkB,CAAC;QAC3BoB,OAAO,EAAE;MACX,CAAC,CAAC;IACJ;IACA,IAAIL,QAAQ,CAACI,MAAM,KAAK,GAAG,EAAE;MAC3B,MAAM,IAAIpB,oBAAoB,CAAC;QAC7BqB,OAAO,EAAE,yCAAyCL,QAAQ,CAACI,MAAM,EAAE;QACnEE,QAAQ,EAAE;UAAEH,UAAU;UAAEC,MAAM,EAAEJ,QAAQ,CAACI;QAAO;MAClD,CAAC,CAAC;IACJ;IAEA,IAAIG,OAA4B;IAChC,IAAI;MACFA,OAAO,GAAGC,IAAI,CAACC,KAAK,CAACT,QAAQ,CAACU,IAAI,CAAwB;IAC5D,CAAC,CAAC,OAAOC,KAAK,EAAE;MACd,MAAM,IAAIzB,2BAA2B,CAAC;QACpCmB,OAAO,EAAE,iDAAiD;QAC1DO,KAAK,EAAED;MACT,CAAC,CAAC;IACJ;IAEA,MAAME,MAAM,GAAGN,OAAO,CAACO,OAAO,CAAC,CAAC,CAAC;IACjC,IAAI,CAACD,MAAM,EAAE;MACX,MAAM,IAAI7B,oBAAoB,CAAC;QAC7BqB,OAAO,EAAE,sCAAsCF,UAAU,GAAG;QAC5DG,QAAQ,EAAE;UAAEH;QAAW;MACzB,CAAC,CAAC;IACJ;IAEA,OAAO;MACLY,aAAa,EAAEF,MAAM,CAACG,OAAO;MAC7BC,QAAQ,EAAEJ,MAAM,CAACK,YAAY;MAC7BC,YAAY,EAAEN,MAAM,CAACM,YAAY,IAAI,IAAI;MACzCC,gBAAgB,EAAEP,MAAM,CAACO,gBAAgB,IAAI;IAC/C,CAAC;EACH;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { StorePermissionException, StoreResponseParseException } from "../../../domain/errors/VersionManagerException.js";
|
|
4
|
+
/** Generic enterprise/private-distribution provider (Prompt 12). */
|
|
5
|
+
export class CustomApiProvider {
|
|
6
|
+
id = 'custom';
|
|
7
|
+
constructor(http, url, headers = {}) {
|
|
8
|
+
this.http = http;
|
|
9
|
+
this.url = url;
|
|
10
|
+
this.headers = headers;
|
|
11
|
+
}
|
|
12
|
+
async fetchLatestVersionInfo(request) {
|
|
13
|
+
const response = await this.http.request({
|
|
14
|
+
url: this.url,
|
|
15
|
+
method: 'GET',
|
|
16
|
+
headers: this.headers,
|
|
17
|
+
timeoutMs: request.timeoutMs
|
|
18
|
+
});
|
|
19
|
+
if (response.status === 401 || response.status === 403) {
|
|
20
|
+
throw new StorePermissionException({
|
|
21
|
+
message: `Custom API rejected the request (HTTP ${response.status})`
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
if (response.status !== 200) {
|
|
25
|
+
throw new StoreResponseParseException({
|
|
26
|
+
message: `Custom API returned HTTP ${response.status}`
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
let payload;
|
|
30
|
+
try {
|
|
31
|
+
payload = JSON.parse(response.body);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
throw new StoreResponseParseException({
|
|
34
|
+
message: 'Custom API returned malformed JSON',
|
|
35
|
+
cause: error
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
if (!payload.latestVersion || !payload.storeUrl) {
|
|
39
|
+
throw new StoreResponseParseException({
|
|
40
|
+
message: 'Custom API response is missing required fields "latestVersion"/"storeUrl"'
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
latestVersion: payload.latestVersion,
|
|
45
|
+
storeUrl: payload.storeUrl,
|
|
46
|
+
releaseNotes: payload.releaseNotes ?? null,
|
|
47
|
+
minimumOsVersion: payload.minimumOsVersion ?? null
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=CustomApiProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["StorePermissionException","StoreResponseParseException","CustomApiProvider","id","constructor","http","url","headers","fetchLatestVersionInfo","request","response","method","timeoutMs","status","message","payload","JSON","parse","body","error","cause","latestVersion","storeUrl","releaseNotes","minimumOsVersion"],"sourceRoot":"../../../../../src","sources":["data/providers/custom-api/CustomApiProvider.ts"],"mappings":";;AAAA,SACEA,wBAAwB,EACxBC,2BAA2B,QACtB,mDAAgD;AAgBvD;AACA,OAAO,MAAMC,iBAAiB,CAA2B;EAC9CC,EAAE,GAAoB,QAAQ;EAEvCC,WAAWA,CACQC,IAAiB,EACjBC,GAAW,EACXC,OAAyC,GAAG,CAAC,CAAC,EAC/D;IAAA,KAHiBF,IAAiB,GAAjBA,IAAiB;IAAA,KACjBC,GAAW,GAAXA,GAAW;IAAA,KACXC,OAAyC,GAAzCA,OAAyC;EACzD;EAEH,MAAMC,sBAAsBA,CAC1BC,OAA2B,EACC;IAC5B,MAAMC,QAAQ,GAAG,MAAM,IAAI,CAACL,IAAI,CAACI,OAAO,CAAC;MACvCH,GAAG,EAAE,IAAI,CAACA,GAAG;MACbK,MAAM,EAAE,KAAK;MACbJ,OAAO,EAAE,IAAI,CAACA,OAAO;MACrBK,SAAS,EAAEH,OAAO,CAACG;IACrB,CAAC,CAAC;IAEF,IAAIF,QAAQ,CAACG,MAAM,KAAK,GAAG,IAAIH,QAAQ,CAACG,MAAM,KAAK,GAAG,EAAE;MACtD,MAAM,IAAIb,wBAAwB,CAAC;QACjCc,OAAO,EAAE,yCAAyCJ,QAAQ,CAACG,MAAM;MACnE,CAAC,CAAC;IACJ;IACA,IAAIH,QAAQ,CAACG,MAAM,KAAK,GAAG,EAAE;MAC3B,MAAM,IAAIZ,2BAA2B,CAAC;QACpCa,OAAO,EAAE,4BAA4BJ,QAAQ,CAACG,MAAM;MACtD,CAAC,CAAC;IACJ;IAEA,IAAIE,OAAiC;IACrC,IAAI;MACFA,OAAO,GAAGC,IAAI,CAACC,KAAK,CAACP,QAAQ,CAACQ,IAAI,CAA6B;IACjE,CAAC,CAAC,OAAOC,KAAK,EAAE;MACd,MAAM,IAAIlB,2BAA2B,CAAC;QACpCa,OAAO,EAAE,oCAAoC;QAC7CM,KAAK,EAAED;MACT,CAAC,CAAC;IACJ;IAEA,IAAI,CAACJ,OAAO,CAACM,aAAa,IAAI,CAACN,OAAO,CAACO,QAAQ,EAAE;MAC/C,MAAM,IAAIrB,2BAA2B,CAAC;QACpCa,OAAO,EACL;MACJ,CAAC,CAAC;IACJ;IAEA,OAAO;MACLO,aAAa,EAAEN,OAAO,CAACM,aAAa;MACpCC,QAAQ,EAAEP,OAAO,CAACO,QAAQ;MAC1BC,YAAY,EAAER,OAAO,CAACQ,YAAY,IAAI,IAAI;MAC1CC,gBAAgB,EAAET,OAAO,CAACS,gBAAgB,IAAI;IAChD,CAAC;EACH;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { UnsupportedStoreException } from "../../../domain/errors/VersionManagerException.js";
|
|
4
|
+
/** Not yet implemented — see Prompt 13 in the design series. */
|
|
5
|
+
export class FirebaseRemoteConfigProvider {
|
|
6
|
+
id = 'firebase-remote-config';
|
|
7
|
+
async fetchLatestVersionInfo() {
|
|
8
|
+
throw new UnsupportedStoreException({
|
|
9
|
+
message: 'Firebase Remote Config provider is not yet implemented — see Prompt 13 in the design series'
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=FirebaseRemoteConfigProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["UnsupportedStoreException","FirebaseRemoteConfigProvider","id","fetchLatestVersionInfo","message"],"sourceRoot":"../../../../../src","sources":["data/providers/firebase-remote-config/FirebaseRemoteConfigProvider.ts"],"mappings":";;AAAA,SAASA,yBAAyB,QAAQ,mDAAgD;AAK1F;AACA,OAAO,MAAMC,4BAA4B,CAA2B;EACzDC,EAAE,GAAoB,wBAAwB;EAEvD,MAAMC,sBAAsBA,CAAA,EAA+B;IACzD,MAAM,IAAIH,yBAAyB,CAAC;MAClCI,OAAO,EACL;IACJ,CAAC,CAAC;EACJ;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { AppNotFoundException, StoreResponseParseException } from "../../../domain/errors/VersionManagerException.js";
|
|
4
|
+
/**
|
|
5
|
+
* Google Play has no public, unauthenticated lookup API (Prompt 10). This provider is a
|
|
6
|
+
* best-effort parser of the public store listing page's inline JSON blob. It is
|
|
7
|
+
* inherently fragile — Play Store markup can change without notice — and is offered as
|
|
8
|
+
* a pragmatic default; production deployments with a Google Play Developer API service
|
|
9
|
+
* account should prefer a IStoreProvider backed by that authenticated API instead.
|
|
10
|
+
*
|
|
11
|
+
* packageName is optional — on Android the app's own bundle id *is* its package name,
|
|
12
|
+
* so when it's not supplied explicitly this falls back to request.bundleId.
|
|
13
|
+
*/
|
|
14
|
+
export class GooglePlayProvider {
|
|
15
|
+
id = 'google-play';
|
|
16
|
+
constructor(http, packageName) {
|
|
17
|
+
this.http = http;
|
|
18
|
+
this.packageName = packageName;
|
|
19
|
+
}
|
|
20
|
+
async fetchLatestVersionInfo(request) {
|
|
21
|
+
const packageName = this.packageName ?? request.bundleId;
|
|
22
|
+
const storeUrl = `https://play.google.com/store/apps/details?id=${encodeURIComponent(packageName)}&hl=en`;
|
|
23
|
+
const response = await this.http.request({
|
|
24
|
+
url: storeUrl,
|
|
25
|
+
method: 'GET',
|
|
26
|
+
timeoutMs: request.timeoutMs
|
|
27
|
+
});
|
|
28
|
+
if (response.status === 404) {
|
|
29
|
+
throw new AppNotFoundException({
|
|
30
|
+
message: `No app found on Google Play for package "${packageName}"`,
|
|
31
|
+
metadata: {
|
|
32
|
+
packageName
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
if (response.status !== 200) {
|
|
37
|
+
throw new StoreResponseParseException({
|
|
38
|
+
message: `Google Play returned HTTP ${response.status}`
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
const version = extractPlayStoreVersion(response.body);
|
|
42
|
+
if (!version) {
|
|
43
|
+
throw new StoreResponseParseException({
|
|
44
|
+
message: 'Could not extract a version string from the Google Play store page',
|
|
45
|
+
metadata: {
|
|
46
|
+
packageName
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
latestVersion: version,
|
|
52
|
+
storeUrl: `https://play.google.com/store/apps/details?id=${packageName}`,
|
|
53
|
+
releaseNotes: null,
|
|
54
|
+
minimumOsVersion: null
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function extractPlayStoreVersion(html) {
|
|
59
|
+
const match = /\[\[\["(\d+(?:\.\d+){1,3})"\]\]/.exec(html);
|
|
60
|
+
return match?.[1] ?? null;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=GooglePlayProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["AppNotFoundException","StoreResponseParseException","GooglePlayProvider","id","constructor","http","packageName","fetchLatestVersionInfo","request","bundleId","storeUrl","encodeURIComponent","response","url","method","timeoutMs","status","message","metadata","version","extractPlayStoreVersion","body","latestVersion","releaseNotes","minimumOsVersion","html","match","exec"],"sourceRoot":"../../../../../src","sources":["data/providers/google-play/GooglePlayProvider.ts"],"mappings":";;AAAA,SACEA,oBAAoB,EACpBC,2BAA2B,QACtB,mDAAgD;AASvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,kBAAkB,CAA2B;EAC/CC,EAAE,GAAoB,aAAa;EAE5CC,WAAWA,CACQC,IAAiB,EACjBC,WAAoB,EACrC;IAAA,KAFiBD,IAAiB,GAAjBA,IAAiB;IAAA,KACjBC,WAAoB,GAApBA,WAAoB;EACpC;EAEH,MAAMC,sBAAsBA,CAC1BC,OAA2B,EACC;IAC5B,MAAMF,WAAW,GAAG,IAAI,CAACA,WAAW,IAAIE,OAAO,CAACC,QAAQ;IACxD,MAAMC,QAAQ,GAAG,iDAAiDC,kBAAkB,CAACL,WAAW,CAAC,QAAQ;IACzG,MAAMM,QAAQ,GAAG,MAAM,IAAI,CAACP,IAAI,CAACG,OAAO,CAAC;MACvCK,GAAG,EAAEH,QAAQ;MACbI,MAAM,EAAE,KAAK;MACbC,SAAS,EAAEP,OAAO,CAACO;IACrB,CAAC,CAAC;IAEF,IAAIH,QAAQ,CAACI,MAAM,KAAK,GAAG,EAAE;MAC3B,MAAM,IAAIhB,oBAAoB,CAAC;QAC7BiB,OAAO,EAAE,4CAA4CX,WAAW,GAAG;QACnEY,QAAQ,EAAE;UAAEZ;QAAY;MAC1B,CAAC,CAAC;IACJ;IACA,IAAIM,QAAQ,CAACI,MAAM,KAAK,GAAG,EAAE;MAC3B,MAAM,IAAIf,2BAA2B,CAAC;QACpCgB,OAAO,EAAE,6BAA6BL,QAAQ,CAACI,MAAM;MACvD,CAAC,CAAC;IACJ;IAEA,MAAMG,OAAO,GAAGC,uBAAuB,CAACR,QAAQ,CAACS,IAAI,CAAC;IACtD,IAAI,CAACF,OAAO,EAAE;MACZ,MAAM,IAAIlB,2BAA2B,CAAC;QACpCgB,OAAO,EACL,oEAAoE;QACtEC,QAAQ,EAAE;UAAEZ;QAAY;MAC1B,CAAC,CAAC;IACJ;IAEA,OAAO;MACLgB,aAAa,EAAEH,OAAO;MACtBT,QAAQ,EAAE,iDAAiDJ,WAAW,EAAE;MACxEiB,YAAY,EAAE,IAAI;MAClBC,gBAAgB,EAAE;IACpB,CAAC;EACH;AACF;AAEA,SAASJ,uBAAuBA,CAACK,IAAY,EAAiB;EAC5D,MAAMC,KAAK,GAAG,iCAAiC,CAACC,IAAI,CAACF,IAAI,CAAC;EAC1D,OAAOC,KAAK,GAAG,CAAC,CAAC,IAAI,IAAI;AAC3B","ignoreList":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { UnsupportedStoreException } from "../../../domain/errors/VersionManagerException.js";
|
|
4
|
+
/**
|
|
5
|
+
* Not yet implemented — Huawei AppGallery integration is designed in Prompt 11 of this
|
|
6
|
+
* series (AG Connect API parameters, error-code mapping) but not built in this pass.
|
|
7
|
+
* The file exists so the provider is independently importable/tree-shakeable
|
|
8
|
+
* (Prompt 1 §8) without pulling in Apple/Google/Custom code.
|
|
9
|
+
*/
|
|
10
|
+
export class HuaweiAppGalleryProvider {
|
|
11
|
+
id = 'huawei';
|
|
12
|
+
async fetchLatestVersionInfo() {
|
|
13
|
+
throw new UnsupportedStoreException({
|
|
14
|
+
message: 'Huawei AppGallery provider is not yet implemented — see Prompt 11 in the design series'
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=HuaweiAppGalleryProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["UnsupportedStoreException","HuaweiAppGalleryProvider","id","fetchLatestVersionInfo","message"],"sourceRoot":"../../../../../src","sources":["data/providers/huawei/HuaweiAppGalleryProvider.ts"],"mappings":";;AAAA,SAASA,yBAAyB,QAAQ,mDAAgD;AAK1F;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,wBAAwB,CAA2B;EACrDC,EAAE,GAAoB,QAAQ;EAEvC,MAAMC,sBAAsBA,CAAA,EAA+B;IACzD,MAAM,IAAIH,yBAAyB,CAAC;MAClCI,OAAO,EACL;IACJ,CAAC,CAAC;EACJ;AACF","ignoreList":[]}
|