@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.
Files changed (371) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +256 -0
  3. package/VersionCheck.podspec +20 -0
  4. package/android/build.gradle +56 -0
  5. package/android/src/main/AndroidManifest.xml +9 -0
  6. package/android/src/main/java/com/rsnativekit/versioncheck/SecureStorageCipher.kt +57 -0
  7. package/android/src/main/java/com/rsnativekit/versioncheck/VersionCheckHeadlessTaskService.kt +31 -0
  8. package/android/src/main/java/com/rsnativekit/versioncheck/VersionCheckModule.kt +215 -0
  9. package/android/src/main/java/com/rsnativekit/versioncheck/VersionCheckPackage.kt +31 -0
  10. package/android/src/main/java/com/rsnativekit/versioncheck/VersionCheckWorker.kt +29 -0
  11. package/ios/PlatformBridge/Ed25519Verifier.swift +19 -0
  12. package/ios/VersionCheck.h +5 -0
  13. package/ios/VersionCheck.mm +278 -0
  14. package/lib/module/data/cache/MemoryCacheStore.js +30 -0
  15. package/lib/module/data/cache/MemoryCacheStore.js.map +1 -0
  16. package/lib/module/data/cache/PersistentCacheStore.js +56 -0
  17. package/lib/module/data/cache/PersistentCacheStore.js.map +1 -0
  18. package/lib/module/data/config/ConfigCache.js +29 -0
  19. package/lib/module/data/config/ConfigCache.js.map +1 -0
  20. package/lib/module/data/config/ConfigDocumentValidator.js +185 -0
  21. package/lib/module/data/config/ConfigDocumentValidator.js.map +1 -0
  22. package/lib/module/data/config/ConfigLoader.js +82 -0
  23. package/lib/module/data/config/ConfigLoader.js.map +1 -0
  24. package/lib/module/data/config/ConfigProvider.js +58 -0
  25. package/lib/module/data/config/ConfigProvider.js.map +1 -0
  26. package/lib/module/data/config/ConfigResolutionPipeline.js +268 -0
  27. package/lib/module/data/config/ConfigResolutionPipeline.js.map +1 -0
  28. package/lib/module/data/config/ConfigValidator.js +69 -0
  29. package/lib/module/data/config/ConfigValidator.js.map +1 -0
  30. package/lib/module/data/config/SignatureVerifier.js +80 -0
  31. package/lib/module/data/config/SignatureVerifier.js.map +1 -0
  32. package/lib/module/data/config/canonicalize.js +88 -0
  33. package/lib/module/data/config/canonicalize.js.map +1 -0
  34. package/lib/module/data/config/sources/EnvironmentOverrideSource.js +20 -0
  35. package/lib/module/data/config/sources/EnvironmentOverrideSource.js.map +1 -0
  36. package/lib/module/data/config/sources/LocalConfigSource.js +22 -0
  37. package/lib/module/data/config/sources/LocalConfigSource.js.map +1 -0
  38. package/lib/module/data/config/sources/RemoteConfigSource.js +38 -0
  39. package/lib/module/data/config/sources/RemoteConfigSource.js.map +1 -0
  40. package/lib/module/data/providers/amazon/AmazonAppstoreProvider.js +13 -0
  41. package/lib/module/data/providers/amazon/AmazonAppstoreProvider.js.map +1 -0
  42. package/lib/module/data/providers/apple/AppleStoreProvider.js +67 -0
  43. package/lib/module/data/providers/apple/AppleStoreProvider.js.map +1 -0
  44. package/lib/module/data/providers/custom-api/CustomApiProvider.js +51 -0
  45. package/lib/module/data/providers/custom-api/CustomApiProvider.js.map +1 -0
  46. package/lib/module/data/providers/firebase-remote-config/FirebaseRemoteConfigProvider.js +13 -0
  47. package/lib/module/data/providers/firebase-remote-config/FirebaseRemoteConfigProvider.js.map +1 -0
  48. package/lib/module/data/providers/google-play/GooglePlayProvider.js +62 -0
  49. package/lib/module/data/providers/google-play/GooglePlayProvider.js.map +1 -0
  50. package/lib/module/data/providers/huawei/HuaweiAppGalleryProvider.js +18 -0
  51. package/lib/module/data/providers/huawei/HuaweiAppGalleryProvider.js.map +1 -0
  52. package/lib/module/data/repositories/VersionRepositoryImpl.js +69 -0
  53. package/lib/module/data/repositories/VersionRepositoryImpl.js.map +1 -0
  54. package/lib/module/di/container.js +80 -0
  55. package/lib/module/di/container.js.map +1 -0
  56. package/lib/module/domain/IVersionManagerCore.js +4 -0
  57. package/lib/module/domain/IVersionManagerCore.js.map +1 -0
  58. package/lib/module/domain/VersionManagerCore.js +276 -0
  59. package/lib/module/domain/VersionManagerCore.js.map +1 -0
  60. package/lib/module/domain/engines/decision/DecisionEngine.js +40 -0
  61. package/lib/module/domain/engines/decision/DecisionEngine.js.map +1 -0
  62. package/lib/module/domain/engines/policy/IUpdatePolicyEngine.js +4 -0
  63. package/lib/module/domain/engines/policy/IUpdatePolicyEngine.js.map +1 -0
  64. package/lib/module/domain/engines/policy/PolicyEngine.js +42 -0
  65. package/lib/module/domain/engines/policy/PolicyEngine.js.map +1 -0
  66. package/lib/module/domain/engines/semver/IVersionComparator.js +4 -0
  67. package/lib/module/domain/engines/semver/IVersionComparator.js.map +1 -0
  68. package/lib/module/domain/engines/semver/SemVerEngine.js +176 -0
  69. package/lib/module/domain/engines/semver/SemVerEngine.js.map +1 -0
  70. package/lib/module/domain/errors/VersionManagerException.js +104 -0
  71. package/lib/module/domain/errors/VersionManagerException.js.map +1 -0
  72. package/lib/module/domain/models/ActionPlan.js +9 -0
  73. package/lib/module/domain/models/ActionPlan.js.map +1 -0
  74. package/lib/module/domain/models/ConfigDocument.js +4 -0
  75. package/lib/module/domain/models/ConfigDocument.js.map +1 -0
  76. package/lib/module/domain/models/Events.js +4 -0
  77. package/lib/module/domain/models/Events.js.map +1 -0
  78. package/lib/module/domain/models/LifecycleState.js +29 -0
  79. package/lib/module/domain/models/LifecycleState.js.map +1 -0
  80. package/lib/module/domain/models/ParsedVersion.js +2 -0
  81. package/lib/module/domain/models/ParsedVersion.js.map +1 -0
  82. package/lib/module/domain/models/PlatformId.js +2 -0
  83. package/lib/module/domain/models/PlatformId.js.map +1 -0
  84. package/lib/module/domain/models/PublicApiOptions.js +2 -0
  85. package/lib/module/domain/models/PublicApiOptions.js.map +1 -0
  86. package/lib/module/domain/models/RemoteVersionInfo.js +4 -0
  87. package/lib/module/domain/models/RemoteVersionInfo.js.map +1 -0
  88. package/lib/module/domain/models/StoreLookup.js +2 -0
  89. package/lib/module/domain/models/StoreLookup.js.map +1 -0
  90. package/lib/module/domain/models/Unsubscribe.js +2 -0
  91. package/lib/module/domain/models/Unsubscribe.js.map +1 -0
  92. package/lib/module/domain/models/UpdateInfo.js +4 -0
  93. package/lib/module/domain/models/UpdateInfo.js.map +1 -0
  94. package/lib/module/domain/models/VersionManagerOptions.js +4 -0
  95. package/lib/module/domain/models/VersionManagerOptions.js.map +1 -0
  96. package/lib/module/domain/ports/ICacheStore.js +2 -0
  97. package/lib/module/domain/ports/ICacheStore.js.map +1 -0
  98. package/lib/module/domain/ports/IClock.js +2 -0
  99. package/lib/module/domain/ports/IClock.js.map +1 -0
  100. package/lib/module/domain/ports/IConfigProvider.js +4 -0
  101. package/lib/module/domain/ports/IConfigProvider.js.map +1 -0
  102. package/lib/module/domain/ports/IConfigSources.js +4 -0
  103. package/lib/module/domain/ports/IConfigSources.js.map +1 -0
  104. package/lib/module/domain/ports/IPlatformBridge.js +4 -0
  105. package/lib/module/domain/ports/IPlatformBridge.js.map +1 -0
  106. package/lib/module/domain/ports/IStoreProvider.js +4 -0
  107. package/lib/module/domain/ports/IStoreProvider.js.map +1 -0
  108. package/lib/module/domain/ports/IVersionRepository.js +4 -0
  109. package/lib/module/domain/ports/IVersionRepository.js.map +1 -0
  110. package/lib/module/domain/statemachine/LifecycleStateMachine.js +55 -0
  111. package/lib/module/domain/statemachine/LifecycleStateMachine.js.map +1 -0
  112. package/lib/module/domain/usecases/CheckForUpdatesUseCase.js +31 -0
  113. package/lib/module/domain/usecases/CheckForUpdatesUseCase.js.map +1 -0
  114. package/lib/module/domain/usecases/ForceTriggerUpdateUseCase.js +20 -0
  115. package/lib/module/domain/usecases/ForceTriggerUpdateUseCase.js.map +1 -0
  116. package/lib/module/domain/usecases/ResetIgnoredVersionsUseCase.js +24 -0
  117. package/lib/module/domain/usecases/ResetIgnoredVersionsUseCase.js.map +1 -0
  118. package/lib/module/index.js +10 -0
  119. package/lib/module/index.js.map +1 -0
  120. package/lib/module/package.json +1 -0
  121. package/lib/module/platform/contracts/IPlatformBridge.js +2 -0
  122. package/lib/module/platform/contracts/IPlatformBridge.js.map +1 -0
  123. package/lib/module/platform/createPlatformBridge.js +17 -0
  124. package/lib/module/platform/createPlatformBridge.js.map +1 -0
  125. package/lib/module/platform/createPlatformBridge.native.js +9 -0
  126. package/lib/module/platform/createPlatformBridge.native.js.map +1 -0
  127. package/lib/module/platform/native/NativePlatformBridge.js +143 -0
  128. package/lib/module/platform/native/NativePlatformBridge.js.map +1 -0
  129. package/lib/module/platform/native/NativeVersionCheck.js +33 -0
  130. package/lib/module/platform/native/NativeVersionCheck.js.map +1 -0
  131. package/lib/module/platform/web/WebPlatformBridge.js +228 -0
  132. package/lib/module/platform/web/WebPlatformBridge.js.map +1 -0
  133. package/lib/module/presentation/components/ForceUpdateScreen.js +68 -0
  134. package/lib/module/presentation/components/ForceUpdateScreen.js.map +1 -0
  135. package/lib/module/presentation/components/OptionalUpdateBanner.js +69 -0
  136. package/lib/module/presentation/components/OptionalUpdateBanner.js.map +1 -0
  137. package/lib/module/presentation/components/SoftUpdateDialog.js +101 -0
  138. package/lib/module/presentation/components/SoftUpdateDialog.js.map +1 -0
  139. package/lib/module/presentation/hooks/VersionManagerProvider.js +18 -0
  140. package/lib/module/presentation/hooks/VersionManagerProvider.js.map +1 -0
  141. package/lib/module/presentation/hooks/context.js +5 -0
  142. package/lib/module/presentation/hooks/context.js.map +1 -0
  143. package/lib/module/presentation/hooks/useUpdateState.js +26 -0
  144. package/lib/module/presentation/hooks/useUpdateState.js.map +1 -0
  145. package/lib/module/presentation/hooks/useVersionManager.js +33 -0
  146. package/lib/module/presentation/hooks/useVersionManager.js.map +1 -0
  147. package/lib/module/presentation/state/VersionManagerStore.js +47 -0
  148. package/lib/module/presentation/state/VersionManagerStore.js.map +1 -0
  149. package/lib/module/publicApi.js +114 -0
  150. package/lib/module/publicApi.js.map +1 -0
  151. package/lib/module/shared/eventbus/EventBus.js +34 -0
  152. package/lib/module/shared/eventbus/EventBus.js.map +1 -0
  153. package/lib/module/shared/logging/Logger.js +56 -0
  154. package/lib/module/shared/logging/Logger.js.map +1 -0
  155. package/lib/module/ui.js +13 -0
  156. package/lib/module/ui.js.map +1 -0
  157. package/lib/typescript/package.json +1 -0
  158. package/lib/typescript/src/data/cache/MemoryCacheStore.d.ts +12 -0
  159. package/lib/typescript/src/data/cache/MemoryCacheStore.d.ts.map +1 -0
  160. package/lib/typescript/src/data/cache/PersistentCacheStore.d.ts +14 -0
  161. package/lib/typescript/src/data/cache/PersistentCacheStore.d.ts.map +1 -0
  162. package/lib/typescript/src/data/config/ConfigCache.d.ts +15 -0
  163. package/lib/typescript/src/data/config/ConfigCache.d.ts.map +1 -0
  164. package/lib/typescript/src/data/config/ConfigDocumentValidator.d.ts +20 -0
  165. package/lib/typescript/src/data/config/ConfigDocumentValidator.d.ts.map +1 -0
  166. package/lib/typescript/src/data/config/ConfigLoader.d.ts +28 -0
  167. package/lib/typescript/src/data/config/ConfigLoader.d.ts.map +1 -0
  168. package/lib/typescript/src/data/config/ConfigProvider.d.ts +30 -0
  169. package/lib/typescript/src/data/config/ConfigProvider.d.ts.map +1 -0
  170. package/lib/typescript/src/data/config/ConfigResolutionPipeline.d.ts +49 -0
  171. package/lib/typescript/src/data/config/ConfigResolutionPipeline.d.ts.map +1 -0
  172. package/lib/typescript/src/data/config/ConfigValidator.d.ts +10 -0
  173. package/lib/typescript/src/data/config/ConfigValidator.d.ts.map +1 -0
  174. package/lib/typescript/src/data/config/SignatureVerifier.d.ts +16 -0
  175. package/lib/typescript/src/data/config/SignatureVerifier.d.ts.map +1 -0
  176. package/lib/typescript/src/data/config/canonicalize.d.ts +13 -0
  177. package/lib/typescript/src/data/config/canonicalize.d.ts.map +1 -0
  178. package/lib/typescript/src/data/config/sources/EnvironmentOverrideSource.d.ts +17 -0
  179. package/lib/typescript/src/data/config/sources/EnvironmentOverrideSource.d.ts.map +1 -0
  180. package/lib/typescript/src/data/config/sources/LocalConfigSource.d.ts +19 -0
  181. package/lib/typescript/src/data/config/sources/LocalConfigSource.d.ts.map +1 -0
  182. package/lib/typescript/src/data/config/sources/RemoteConfigSource.d.ts +10 -0
  183. package/lib/typescript/src/data/config/sources/RemoteConfigSource.d.ts.map +1 -0
  184. package/lib/typescript/src/data/providers/amazon/AmazonAppstoreProvider.d.ts +9 -0
  185. package/lib/typescript/src/data/providers/amazon/AmazonAppstoreProvider.d.ts.map +1 -0
  186. package/lib/typescript/src/data/providers/apple/AppleStoreProvider.d.ts +19 -0
  187. package/lib/typescript/src/data/providers/apple/AppleStoreProvider.d.ts.map +1 -0
  188. package/lib/typescript/src/data/providers/custom-api/CustomApiProvider.d.ts +14 -0
  189. package/lib/typescript/src/data/providers/custom-api/CustomApiProvider.d.ts.map +1 -0
  190. package/lib/typescript/src/data/providers/firebase-remote-config/FirebaseRemoteConfigProvider.d.ts +9 -0
  191. package/lib/typescript/src/data/providers/firebase-remote-config/FirebaseRemoteConfigProvider.d.ts.map +1 -0
  192. package/lib/typescript/src/data/providers/google-play/GooglePlayProvider.d.ts +22 -0
  193. package/lib/typescript/src/data/providers/google-play/GooglePlayProvider.d.ts.map +1 -0
  194. package/lib/typescript/src/data/providers/huawei/HuaweiAppGalleryProvider.d.ts +14 -0
  195. package/lib/typescript/src/data/providers/huawei/HuaweiAppGalleryProvider.d.ts.map +1 -0
  196. package/lib/typescript/src/data/repositories/VersionRepositoryImpl.d.ts +23 -0
  197. package/lib/typescript/src/data/repositories/VersionRepositoryImpl.d.ts.map +1 -0
  198. package/lib/typescript/src/di/container.d.ts +12 -0
  199. package/lib/typescript/src/di/container.d.ts.map +1 -0
  200. package/lib/typescript/src/domain/IVersionManagerCore.d.ts +30 -0
  201. package/lib/typescript/src/domain/IVersionManagerCore.d.ts.map +1 -0
  202. package/lib/typescript/src/domain/VersionManagerCore.d.ts +94 -0
  203. package/lib/typescript/src/domain/VersionManagerCore.d.ts.map +1 -0
  204. package/lib/typescript/src/domain/engines/decision/DecisionEngine.d.ts +16 -0
  205. package/lib/typescript/src/domain/engines/decision/DecisionEngine.d.ts.map +1 -0
  206. package/lib/typescript/src/domain/engines/policy/IUpdatePolicyEngine.d.ts +17 -0
  207. package/lib/typescript/src/domain/engines/policy/IUpdatePolicyEngine.d.ts.map +1 -0
  208. package/lib/typescript/src/domain/engines/policy/PolicyEngine.d.ts +16 -0
  209. package/lib/typescript/src/domain/engines/policy/PolicyEngine.d.ts.map +1 -0
  210. package/lib/typescript/src/domain/engines/semver/IVersionComparator.d.ts +7 -0
  211. package/lib/typescript/src/domain/engines/semver/IVersionComparator.d.ts.map +1 -0
  212. package/lib/typescript/src/domain/engines/semver/SemVerEngine.d.ts +11 -0
  213. package/lib/typescript/src/domain/engines/semver/SemVerEngine.d.ts.map +1 -0
  214. package/lib/typescript/src/domain/errors/VersionManagerException.d.ts +97 -0
  215. package/lib/typescript/src/domain/errors/VersionManagerException.d.ts.map +1 -0
  216. package/lib/typescript/src/domain/models/ActionPlan.d.ts +15 -0
  217. package/lib/typescript/src/domain/models/ActionPlan.d.ts.map +1 -0
  218. package/lib/typescript/src/domain/models/ConfigDocument.d.ts +86 -0
  219. package/lib/typescript/src/domain/models/ConfigDocument.d.ts.map +1 -0
  220. package/lib/typescript/src/domain/models/Events.d.ts +39 -0
  221. package/lib/typescript/src/domain/models/Events.d.ts.map +1 -0
  222. package/lib/typescript/src/domain/models/LifecycleState.d.ts +18 -0
  223. package/lib/typescript/src/domain/models/LifecycleState.d.ts.map +1 -0
  224. package/lib/typescript/src/domain/models/ParsedVersion.d.ts +9 -0
  225. package/lib/typescript/src/domain/models/ParsedVersion.d.ts.map +1 -0
  226. package/lib/typescript/src/domain/models/PlatformId.d.ts +3 -0
  227. package/lib/typescript/src/domain/models/PlatformId.d.ts.map +1 -0
  228. package/lib/typescript/src/domain/models/PublicApiOptions.d.ts +13 -0
  229. package/lib/typescript/src/domain/models/PublicApiOptions.d.ts.map +1 -0
  230. package/lib/typescript/src/domain/models/RemoteVersionInfo.d.ts +21 -0
  231. package/lib/typescript/src/domain/models/RemoteVersionInfo.d.ts.map +1 -0
  232. package/lib/typescript/src/domain/models/StoreLookup.d.ts +12 -0
  233. package/lib/typescript/src/domain/models/StoreLookup.d.ts.map +1 -0
  234. package/lib/typescript/src/domain/models/Unsubscribe.d.ts +2 -0
  235. package/lib/typescript/src/domain/models/Unsubscribe.d.ts.map +1 -0
  236. package/lib/typescript/src/domain/models/UpdateInfo.d.ts +11 -0
  237. package/lib/typescript/src/domain/models/UpdateInfo.d.ts.map +1 -0
  238. package/lib/typescript/src/domain/models/VersionManagerOptions.d.ts +149 -0
  239. package/lib/typescript/src/domain/models/VersionManagerOptions.d.ts.map +1 -0
  240. package/lib/typescript/src/domain/ports/ICacheStore.d.ts +6 -0
  241. package/lib/typescript/src/domain/ports/ICacheStore.d.ts.map +1 -0
  242. package/lib/typescript/src/domain/ports/IClock.d.ts +4 -0
  243. package/lib/typescript/src/domain/ports/IClock.d.ts.map +1 -0
  244. package/lib/typescript/src/domain/ports/IConfigProvider.d.ts +11 -0
  245. package/lib/typescript/src/domain/ports/IConfigProvider.d.ts.map +1 -0
  246. package/lib/typescript/src/domain/ports/IConfigSources.d.ts +25 -0
  247. package/lib/typescript/src/domain/ports/IConfigSources.d.ts.map +1 -0
  248. package/lib/typescript/src/domain/ports/IPlatformBridge.d.ts +77 -0
  249. package/lib/typescript/src/domain/ports/IPlatformBridge.d.ts.map +1 -0
  250. package/lib/typescript/src/domain/ports/IStoreProvider.d.ts +7 -0
  251. package/lib/typescript/src/domain/ports/IStoreProvider.d.ts.map +1 -0
  252. package/lib/typescript/src/domain/ports/IVersionRepository.d.ts +8 -0
  253. package/lib/typescript/src/domain/ports/IVersionRepository.d.ts.map +1 -0
  254. package/lib/typescript/src/domain/statemachine/LifecycleStateMachine.d.ts +25 -0
  255. package/lib/typescript/src/domain/statemachine/LifecycleStateMachine.d.ts.map +1 -0
  256. package/lib/typescript/src/domain/usecases/CheckForUpdatesUseCase.d.ts +30 -0
  257. package/lib/typescript/src/domain/usecases/CheckForUpdatesUseCase.d.ts.map +1 -0
  258. package/lib/typescript/src/domain/usecases/ForceTriggerUpdateUseCase.d.ts +17 -0
  259. package/lib/typescript/src/domain/usecases/ForceTriggerUpdateUseCase.d.ts.map +1 -0
  260. package/lib/typescript/src/domain/usecases/ResetIgnoredVersionsUseCase.d.ts +7 -0
  261. package/lib/typescript/src/domain/usecases/ResetIgnoredVersionsUseCase.d.ts.map +1 -0
  262. package/lib/typescript/src/index.d.ts +17 -0
  263. package/lib/typescript/src/index.d.ts.map +1 -0
  264. package/lib/typescript/src/platform/contracts/IPlatformBridge.d.ts +2 -0
  265. package/lib/typescript/src/platform/contracts/IPlatformBridge.d.ts.map +1 -0
  266. package/lib/typescript/src/platform/createPlatformBridge.d.ts +12 -0
  267. package/lib/typescript/src/platform/createPlatformBridge.d.ts.map +1 -0
  268. package/lib/typescript/src/platform/createPlatformBridge.native.d.ts +4 -0
  269. package/lib/typescript/src/platform/createPlatformBridge.native.d.ts.map +1 -0
  270. package/lib/typescript/src/platform/native/NativePlatformBridge.d.ts +17 -0
  271. package/lib/typescript/src/platform/native/NativePlatformBridge.d.ts.map +1 -0
  272. package/lib/typescript/src/platform/native/NativeVersionCheck.d.ts +45 -0
  273. package/lib/typescript/src/platform/native/NativeVersionCheck.d.ts.map +1 -0
  274. package/lib/typescript/src/platform/web/WebPlatformBridge.d.ts +17 -0
  275. package/lib/typescript/src/platform/web/WebPlatformBridge.d.ts.map +1 -0
  276. package/lib/typescript/src/presentation/components/ForceUpdateScreen.d.ts +12 -0
  277. package/lib/typescript/src/presentation/components/ForceUpdateScreen.d.ts.map +1 -0
  278. package/lib/typescript/src/presentation/components/OptionalUpdateBanner.d.ts +12 -0
  279. package/lib/typescript/src/presentation/components/OptionalUpdateBanner.d.ts.map +1 -0
  280. package/lib/typescript/src/presentation/components/SoftUpdateDialog.d.ts +14 -0
  281. package/lib/typescript/src/presentation/components/SoftUpdateDialog.d.ts.map +1 -0
  282. package/lib/typescript/src/presentation/hooks/VersionManagerProvider.d.ts +9 -0
  283. package/lib/typescript/src/presentation/hooks/VersionManagerProvider.d.ts.map +1 -0
  284. package/lib/typescript/src/presentation/hooks/context.d.ts +3 -0
  285. package/lib/typescript/src/presentation/hooks/context.d.ts.map +1 -0
  286. package/lib/typescript/src/presentation/hooks/useUpdateState.d.ts +17 -0
  287. package/lib/typescript/src/presentation/hooks/useUpdateState.d.ts.map +1 -0
  288. package/lib/typescript/src/presentation/hooks/useVersionManager.d.ts +22 -0
  289. package/lib/typescript/src/presentation/hooks/useVersionManager.d.ts.map +1 -0
  290. package/lib/typescript/src/presentation/state/VersionManagerStore.d.ts +28 -0
  291. package/lib/typescript/src/presentation/state/VersionManagerStore.d.ts.map +1 -0
  292. package/lib/typescript/src/publicApi.d.ts +24 -0
  293. package/lib/typescript/src/publicApi.d.ts.map +1 -0
  294. package/lib/typescript/src/shared/eventbus/EventBus.d.ts +21 -0
  295. package/lib/typescript/src/shared/eventbus/EventBus.d.ts.map +1 -0
  296. package/lib/typescript/src/shared/logging/Logger.d.ts +17 -0
  297. package/lib/typescript/src/shared/logging/Logger.d.ts.map +1 -0
  298. package/lib/typescript/src/ui.d.ts +15 -0
  299. package/lib/typescript/src/ui.d.ts.map +1 -0
  300. package/package.json +192 -0
  301. package/src/data/cache/MemoryCacheStore.ts +36 -0
  302. package/src/data/cache/PersistentCacheStore.ts +63 -0
  303. package/src/data/config/ConfigCache.ts +30 -0
  304. package/src/data/config/ConfigDocumentValidator.ts +309 -0
  305. package/src/data/config/ConfigLoader.ts +105 -0
  306. package/src/data/config/ConfigProvider.ts +84 -0
  307. package/src/data/config/ConfigResolutionPipeline.ts +424 -0
  308. package/src/data/config/ConfigValidator.ts +79 -0
  309. package/src/data/config/SignatureVerifier.ts +90 -0
  310. package/src/data/config/canonicalize.ts +111 -0
  311. package/src/data/config/sources/EnvironmentOverrideSource.ts +22 -0
  312. package/src/data/config/sources/LocalConfigSource.ts +24 -0
  313. package/src/data/config/sources/RemoteConfigSource.ts +41 -0
  314. package/src/data/providers/amazon/AmazonAppstoreProvider.ts +16 -0
  315. package/src/data/providers/apple/AppleStoreProvider.ts +94 -0
  316. package/src/data/providers/custom-api/CustomApiProvider.ts +75 -0
  317. package/src/data/providers/firebase-remote-config/FirebaseRemoteConfigProvider.ts +16 -0
  318. package/src/data/providers/google-play/GooglePlayProvider.ts +75 -0
  319. package/src/data/providers/huawei/HuaweiAppGalleryProvider.ts +21 -0
  320. package/src/data/repositories/VersionRepositoryImpl.ts +90 -0
  321. package/src/di/container.ts +128 -0
  322. package/src/domain/IVersionManagerCore.ts +54 -0
  323. package/src/domain/VersionManagerCore.ts +425 -0
  324. package/src/domain/engines/decision/DecisionEngine.ts +47 -0
  325. package/src/domain/engines/policy/IUpdatePolicyEngine.ts +18 -0
  326. package/src/domain/engines/policy/PolicyEngine.ts +60 -0
  327. package/src/domain/engines/semver/IVersionComparator.ts +7 -0
  328. package/src/domain/engines/semver/SemVerEngine.ts +200 -0
  329. package/src/domain/errors/VersionManagerException.ts +166 -0
  330. package/src/domain/models/ActionPlan.ts +17 -0
  331. package/src/domain/models/ConfigDocument.ts +97 -0
  332. package/src/domain/models/Events.ts +48 -0
  333. package/src/domain/models/LifecycleState.ts +50 -0
  334. package/src/domain/models/ParsedVersion.ts +8 -0
  335. package/src/domain/models/PlatformId.ts +9 -0
  336. package/src/domain/models/PublicApiOptions.ts +14 -0
  337. package/src/domain/models/RemoteVersionInfo.ts +23 -0
  338. package/src/domain/models/StoreLookup.ts +12 -0
  339. package/src/domain/models/Unsubscribe.ts +1 -0
  340. package/src/domain/models/UpdateInfo.ts +11 -0
  341. package/src/domain/models/VersionManagerOptions.ts +150 -0
  342. package/src/domain/ports/ICacheStore.ts +5 -0
  343. package/src/domain/ports/IClock.ts +3 -0
  344. package/src/domain/ports/IConfigProvider.ts +18 -0
  345. package/src/domain/ports/IConfigSources.ts +44 -0
  346. package/src/domain/ports/IPlatformBridge.ts +97 -0
  347. package/src/domain/ports/IStoreProvider.ts +12 -0
  348. package/src/domain/ports/IVersionRepository.ts +14 -0
  349. package/src/domain/statemachine/LifecycleStateMachine.ts +76 -0
  350. package/src/domain/usecases/CheckForUpdatesUseCase.ts +63 -0
  351. package/src/domain/usecases/ForceTriggerUpdateUseCase.ts +35 -0
  352. package/src/domain/usecases/ResetIgnoredVersionsUseCase.ts +26 -0
  353. package/src/index.tsx +84 -0
  354. package/src/platform/contracts/IPlatformBridge.ts +14 -0
  355. package/src/platform/createPlatformBridge.native.ts +7 -0
  356. package/src/platform/createPlatformBridge.ts +15 -0
  357. package/src/platform/native/NativePlatformBridge.ts +179 -0
  358. package/src/platform/native/NativeVersionCheck.ts +64 -0
  359. package/src/platform/web/WebPlatformBridge.ts +347 -0
  360. package/src/presentation/components/ForceUpdateScreen.tsx +64 -0
  361. package/src/presentation/components/OptionalUpdateBanner.tsx +53 -0
  362. package/src/presentation/components/SoftUpdateDialog.tsx +84 -0
  363. package/src/presentation/hooks/VersionManagerProvider.tsx +23 -0
  364. package/src/presentation/hooks/context.ts +6 -0
  365. package/src/presentation/hooks/useUpdateState.ts +50 -0
  366. package/src/presentation/hooks/useVersionManager.ts +68 -0
  367. package/src/presentation/state/VersionManagerStore.ts +72 -0
  368. package/src/publicApi.ts +126 -0
  369. package/src/shared/eventbus/EventBus.ts +56 -0
  370. package/src/shared/logging/Logger.ts +70 -0
  371. package/src/ui.tsx +19 -0
@@ -0,0 +1,22 @@
1
+ import type { VersionManagerConfigDocument } from '../../../domain/models/ConfigDocument';
2
+ import type { IEnvironmentOverrideSource } from '../../../domain/ports/IConfigSources';
3
+
4
+ /**
5
+ * Doc 03 §4 — "there is no OS process environment on a device"; this tier maps to
6
+ * build-time-injected constants and explicit runtime overrides, not `process.env` on a
7
+ * server. Build-time constants (Info.plist / BuildConfig fields) are app-specific and
8
+ * have no generic cross-platform read path from JS, so this implementation covers the
9
+ * "explicit configure({ configSources: { envOverrides } })" half of §4.1 tier 1 — the
10
+ * build-time-constant half is a per-app integration concern (documented, not a gap in
11
+ * this port's contract, which only promises "read whatever overrides are available").
12
+ */
13
+ export class EnvironmentOverrideSource implements IEnvironmentOverrideSource {
14
+ constructor(
15
+ private readonly overrides:
16
+ Partial<VersionManagerConfigDocument> | undefined
17
+ ) {}
18
+
19
+ async read(): Promise<Partial<VersionManagerConfigDocument>> {
20
+ return this.overrides ?? {};
21
+ }
22
+ }
@@ -0,0 +1,24 @@
1
+ import type {
2
+ RawConfigDocument,
3
+ SignedConfigEnvelope,
4
+ } from '../../../domain/models/ConfigDocument';
5
+ import type { ILocalConfigSource } from '../../../domain/ports/IConfigSources';
6
+
7
+ /**
8
+ * Doc 03 §5.1 — the design calls for a native mmap reader (iOS Data(alwaysMapped),
9
+ * Android FileChannel.map) to avoid a double-copy when reading a bundled config asset.
10
+ * This implementation takes a documented, lower-risk equivalent instead: the host app
11
+ * imports its bundled config JSON via Metro/webpack's native JSON module support
12
+ * (`import localConfig from './vm-config.json'`) and passes the parsed envelope through
13
+ * `VersionManagerOptions.configSources.local`. Metro's JSON loader already avoids the
14
+ * page-cache -> native-heap -> JS-heap double copy for typical bundle sizes (the asset
15
+ * is compiled into the JS bundle itself), which satisfies §5.1's actual goal (avoid GC
16
+ * churn against the 5MB budget for a <=64KB document) without a dedicated native reader.
17
+ */
18
+ export class LocalConfigSource implements ILocalConfigSource {
19
+ constructor(private readonly envelope: SignedConfigEnvelope | undefined) {}
20
+
21
+ async read(): Promise<RawConfigDocument | null> {
22
+ return this.envelope ?? null;
23
+ }
24
+ }
@@ -0,0 +1,41 @@
1
+ import {
2
+ OfflineException,
3
+ StoreResponseParseException,
4
+ } from '../../../domain/errors/VersionManagerException';
5
+ import type {
6
+ FetchOptions,
7
+ RawConfigDocument,
8
+ } from '../../../domain/models/ConfigDocument';
9
+ import type { IRemoteConfigSource } from '../../../domain/ports/IConfigSources';
10
+ import type { IHttpClient } from '../../../domain/ports/IPlatformBridge';
11
+
12
+ /** Doc 03 §4.3 — the remote-fetch tier, reached through the same IHttpClient port every other network call in this SDK uses. */
13
+ export class RemoteConfigSource implements IRemoteConfigSource {
14
+ constructor(private readonly http: IHttpClient) {}
15
+
16
+ async fetch(url: string, options: FetchOptions): Promise<RawConfigDocument> {
17
+ const response = await this.http.request({
18
+ url,
19
+ method: 'GET',
20
+ headers: options.headers,
21
+ timeoutMs: options.timeoutMs,
22
+ });
23
+
24
+ if (response.status !== 200) {
25
+ throw new OfflineException({
26
+ message: `Remote config fetch returned HTTP ${response.status}`,
27
+ metadata: { url, status: response.status },
28
+ });
29
+ }
30
+
31
+ try {
32
+ return JSON.parse(response.body);
33
+ } catch (error) {
34
+ throw new StoreResponseParseException({
35
+ message: 'Remote config endpoint returned malformed JSON',
36
+ cause: error,
37
+ metadata: { url },
38
+ });
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,16 @@
1
+ import { UnsupportedStoreException } from '../../../domain/errors/VersionManagerException';
2
+ import type { StoreProviderId } from '../../../domain/models/PlatformId';
3
+ import type { StoreLookupResult } from '../../../domain/models/StoreLookup';
4
+ import type { IStoreProvider } from '../../../domain/ports/IStoreProvider';
5
+
6
+ /** Not yet implemented — see Prompt 11 in the design series. */
7
+ export class AmazonAppstoreProvider implements IStoreProvider {
8
+ readonly id: StoreProviderId = 'amazon';
9
+
10
+ async fetchLatestVersionInfo(): Promise<StoreLookupResult> {
11
+ throw new UnsupportedStoreException({
12
+ message:
13
+ 'Amazon Appstore provider is not yet implemented — see Prompt 11 in the design series',
14
+ });
15
+ }
16
+ }
@@ -0,0 +1,94 @@
1
+ import {
2
+ AppNotFoundException,
3
+ RateLimitException,
4
+ StoreResponseParseException,
5
+ } from '../../../domain/errors/VersionManagerException';
6
+ import type { StoreProviderId } from '../../../domain/models/PlatformId';
7
+ import type {
8
+ StoreLookupRequest,
9
+ StoreLookupResult,
10
+ } from '../../../domain/models/StoreLookup';
11
+ import type { IHttpClient } from '../../../domain/ports/IPlatformBridge';
12
+ import type { IStoreProvider } from '../../../domain/ports/IStoreProvider';
13
+
14
+ interface AppleLookupResult {
15
+ version: string;
16
+ trackViewUrl: string;
17
+ releaseNotes?: string;
18
+ minimumOsVersion?: string;
19
+ }
20
+
21
+ interface AppleLookupResponse {
22
+ resultCount: number;
23
+ results: AppleLookupResult[];
24
+ }
25
+
26
+ /**
27
+ * Real implementation against the public iTunes Lookup API (Prompt 10). Accepts either
28
+ * the numeric App Store Connect id (`id=`) or, when the app developer doesn't want to
29
+ * hardcode one, falls back to looking the app up by its own bundle id (`bundleId=`) —
30
+ * the iTunes Lookup API supports both query params equivalently.
31
+ */
32
+ export class AppleStoreProvider implements IStoreProvider {
33
+ readonly id: StoreProviderId = 'apple';
34
+
35
+ constructor(
36
+ private readonly http: IHttpClient,
37
+ private readonly appStoreId?: string,
38
+ private readonly region: string = 'us'
39
+ ) {}
40
+
41
+ async fetchLatestVersionInfo(
42
+ request: StoreLookupRequest
43
+ ): Promise<StoreLookupResult> {
44
+ const country = request.region ?? this.region;
45
+ const identifierParam = this.appStoreId
46
+ ? `id=${encodeURIComponent(this.appStoreId)}`
47
+ : `bundleId=${encodeURIComponent(request.bundleId)}`;
48
+ const url = `https://itunes.apple.com/lookup?${identifierParam}&country=${encodeURIComponent(country)}`;
49
+ const response = await this.http.request({
50
+ url,
51
+ method: 'GET',
52
+ timeoutMs: request.timeoutMs,
53
+ });
54
+
55
+ const identifier = this.appStoreId ?? request.bundleId;
56
+
57
+ if (response.status === 429) {
58
+ throw new RateLimitException({
59
+ message: 'Apple iTunes Lookup API rate limit exceeded (HTTP 429)',
60
+ });
61
+ }
62
+ if (response.status !== 200) {
63
+ throw new AppNotFoundException({
64
+ message: `Apple iTunes Lookup API returned HTTP ${response.status}`,
65
+ metadata: { identifier, status: response.status },
66
+ });
67
+ }
68
+
69
+ let payload: AppleLookupResponse;
70
+ try {
71
+ payload = JSON.parse(response.body) as AppleLookupResponse;
72
+ } catch (error) {
73
+ throw new StoreResponseParseException({
74
+ message: 'Apple iTunes Lookup API returned malformed JSON',
75
+ cause: error,
76
+ });
77
+ }
78
+
79
+ const result = payload.results[0];
80
+ if (!result) {
81
+ throw new AppNotFoundException({
82
+ message: `No app found in the App Store for "${identifier}"`,
83
+ metadata: { identifier },
84
+ });
85
+ }
86
+
87
+ return {
88
+ latestVersion: result.version,
89
+ storeUrl: result.trackViewUrl,
90
+ releaseNotes: result.releaseNotes ?? null,
91
+ minimumOsVersion: result.minimumOsVersion ?? null,
92
+ };
93
+ }
94
+ }
@@ -0,0 +1,75 @@
1
+ import {
2
+ StorePermissionException,
3
+ StoreResponseParseException,
4
+ } from '../../../domain/errors/VersionManagerException';
5
+ import type { StoreProviderId } from '../../../domain/models/PlatformId';
6
+ import type {
7
+ StoreLookupRequest,
8
+ StoreLookupResult,
9
+ } from '../../../domain/models/StoreLookup';
10
+ import type { IHttpClient } from '../../../domain/ports/IPlatformBridge';
11
+ import type { IStoreProvider } from '../../../domain/ports/IStoreProvider';
12
+
13
+ interface CustomApiResponsePayload {
14
+ latestVersion?: string;
15
+ storeUrl?: string;
16
+ releaseNotes?: string;
17
+ minimumOsVersion?: string;
18
+ }
19
+
20
+ /** Generic enterprise/private-distribution provider (Prompt 12). */
21
+ export class CustomApiProvider implements IStoreProvider {
22
+ readonly id: StoreProviderId = 'custom';
23
+
24
+ constructor(
25
+ private readonly http: IHttpClient,
26
+ private readonly url: string,
27
+ private readonly headers: Readonly<Record<string, string>> = {}
28
+ ) {}
29
+
30
+ async fetchLatestVersionInfo(
31
+ request: StoreLookupRequest
32
+ ): Promise<StoreLookupResult> {
33
+ const response = await this.http.request({
34
+ url: this.url,
35
+ method: 'GET',
36
+ headers: this.headers,
37
+ timeoutMs: request.timeoutMs,
38
+ });
39
+
40
+ if (response.status === 401 || response.status === 403) {
41
+ throw new StorePermissionException({
42
+ message: `Custom API rejected the request (HTTP ${response.status})`,
43
+ });
44
+ }
45
+ if (response.status !== 200) {
46
+ throw new StoreResponseParseException({
47
+ message: `Custom API returned HTTP ${response.status}`,
48
+ });
49
+ }
50
+
51
+ let payload: CustomApiResponsePayload;
52
+ try {
53
+ payload = JSON.parse(response.body) as CustomApiResponsePayload;
54
+ } catch (error) {
55
+ throw new StoreResponseParseException({
56
+ message: 'Custom API returned malformed JSON',
57
+ cause: error,
58
+ });
59
+ }
60
+
61
+ if (!payload.latestVersion || !payload.storeUrl) {
62
+ throw new StoreResponseParseException({
63
+ message:
64
+ 'Custom API response is missing required fields "latestVersion"/"storeUrl"',
65
+ });
66
+ }
67
+
68
+ return {
69
+ latestVersion: payload.latestVersion,
70
+ storeUrl: payload.storeUrl,
71
+ releaseNotes: payload.releaseNotes ?? null,
72
+ minimumOsVersion: payload.minimumOsVersion ?? null,
73
+ };
74
+ }
75
+ }
@@ -0,0 +1,16 @@
1
+ import { UnsupportedStoreException } from '../../../domain/errors/VersionManagerException';
2
+ import type { StoreProviderId } from '../../../domain/models/PlatformId';
3
+ import type { StoreLookupResult } from '../../../domain/models/StoreLookup';
4
+ import type { IStoreProvider } from '../../../domain/ports/IStoreProvider';
5
+
6
+ /** Not yet implemented — see Prompt 13 in the design series. */
7
+ export class FirebaseRemoteConfigProvider implements IStoreProvider {
8
+ readonly id: StoreProviderId = 'firebase-remote-config';
9
+
10
+ async fetchLatestVersionInfo(): Promise<StoreLookupResult> {
11
+ throw new UnsupportedStoreException({
12
+ message:
13
+ 'Firebase Remote Config provider is not yet implemented — see Prompt 13 in the design series',
14
+ });
15
+ }
16
+ }
@@ -0,0 +1,75 @@
1
+ import {
2
+ AppNotFoundException,
3
+ StoreResponseParseException,
4
+ } from '../../../domain/errors/VersionManagerException';
5
+ import type { StoreProviderId } from '../../../domain/models/PlatformId';
6
+ import type {
7
+ StoreLookupRequest,
8
+ StoreLookupResult,
9
+ } from '../../../domain/models/StoreLookup';
10
+ import type { IHttpClient } from '../../../domain/ports/IPlatformBridge';
11
+ import type { IStoreProvider } from '../../../domain/ports/IStoreProvider';
12
+
13
+ /**
14
+ * Google Play has no public, unauthenticated lookup API (Prompt 10). This provider is a
15
+ * best-effort parser of the public store listing page's inline JSON blob. It is
16
+ * inherently fragile — Play Store markup can change without notice — and is offered as
17
+ * a pragmatic default; production deployments with a Google Play Developer API service
18
+ * account should prefer a IStoreProvider backed by that authenticated API instead.
19
+ *
20
+ * packageName is optional — on Android the app's own bundle id *is* its package name,
21
+ * so when it's not supplied explicitly this falls back to request.bundleId.
22
+ */
23
+ export class GooglePlayProvider implements IStoreProvider {
24
+ readonly id: StoreProviderId = 'google-play';
25
+
26
+ constructor(
27
+ private readonly http: IHttpClient,
28
+ private readonly packageName?: string
29
+ ) {}
30
+
31
+ async fetchLatestVersionInfo(
32
+ request: StoreLookupRequest
33
+ ): Promise<StoreLookupResult> {
34
+ const packageName = this.packageName ?? request.bundleId;
35
+ const storeUrl = `https://play.google.com/store/apps/details?id=${encodeURIComponent(packageName)}&hl=en`;
36
+ const response = await this.http.request({
37
+ url: storeUrl,
38
+ method: 'GET',
39
+ timeoutMs: request.timeoutMs,
40
+ });
41
+
42
+ if (response.status === 404) {
43
+ throw new AppNotFoundException({
44
+ message: `No app found on Google Play for package "${packageName}"`,
45
+ metadata: { packageName },
46
+ });
47
+ }
48
+ if (response.status !== 200) {
49
+ throw new StoreResponseParseException({
50
+ message: `Google Play returned HTTP ${response.status}`,
51
+ });
52
+ }
53
+
54
+ const version = extractPlayStoreVersion(response.body);
55
+ if (!version) {
56
+ throw new StoreResponseParseException({
57
+ message:
58
+ 'Could not extract a version string from the Google Play store page',
59
+ metadata: { packageName },
60
+ });
61
+ }
62
+
63
+ return {
64
+ latestVersion: version,
65
+ storeUrl: `https://play.google.com/store/apps/details?id=${packageName}`,
66
+ releaseNotes: null,
67
+ minimumOsVersion: null,
68
+ };
69
+ }
70
+ }
71
+
72
+ function extractPlayStoreVersion(html: string): string | null {
73
+ const match = /\[\[\["(\d+(?:\.\d+){1,3})"\]\]/.exec(html);
74
+ return match?.[1] ?? null;
75
+ }
@@ -0,0 +1,21 @@
1
+ import { UnsupportedStoreException } from '../../../domain/errors/VersionManagerException';
2
+ import type { StoreProviderId } from '../../../domain/models/PlatformId';
3
+ import type { StoreLookupResult } from '../../../domain/models/StoreLookup';
4
+ import type { IStoreProvider } from '../../../domain/ports/IStoreProvider';
5
+
6
+ /**
7
+ * Not yet implemented — Huawei AppGallery integration is designed in Prompt 11 of this
8
+ * series (AG Connect API parameters, error-code mapping) but not built in this pass.
9
+ * The file exists so the provider is independently importable/tree-shakeable
10
+ * (Prompt 1 §8) without pulling in Apple/Google/Custom code.
11
+ */
12
+ export class HuaweiAppGalleryProvider implements IStoreProvider {
13
+ readonly id: StoreProviderId = 'huawei';
14
+
15
+ async fetchLatestVersionInfo(): Promise<StoreLookupResult> {
16
+ throw new UnsupportedStoreException({
17
+ message:
18
+ 'Huawei AppGallery provider is not yet implemented — see Prompt 11 in the design series',
19
+ });
20
+ }
21
+ }
@@ -0,0 +1,90 @@
1
+ import {
2
+ toVersionManagerException,
3
+ UnsupportedStoreException,
4
+ } from '../../domain/errors/VersionManagerException';
5
+ import type {
6
+ RemoteVersionInfo,
7
+ UserVersionDecision,
8
+ VersionCheckRequest,
9
+ } from '../../domain/models/RemoteVersionInfo';
10
+ import type { ICacheStore } from '../../domain/ports/ICacheStore';
11
+ import type { IClock } from '../../domain/ports/IClock';
12
+ import type { IKeyValueStorage } from '../../domain/ports/IPlatformBridge';
13
+ import type { IStoreProvider } from '../../domain/ports/IStoreProvider';
14
+ import type { IVersionRepository } from '../../domain/ports/IVersionRepository';
15
+
16
+ const REMOTE_INFO_CACHE_KEY = 'remote-version-info';
17
+ const USER_DECISION_STORAGE_KEY = 'vm_user_decision';
18
+
19
+ /**
20
+ * Sequential fallback across registered providers (Prompt 14's simpler tier): the first
21
+ * provider to succeed wins. Only providers the host app actually registers via DI
22
+ * reach this list — nothing here imports a provider it doesn't need (Prompt 1 §8).
23
+ */
24
+ export class VersionRepositoryImpl implements IVersionRepository {
25
+ constructor(
26
+ private readonly providers: readonly IStoreProvider[],
27
+ private readonly cache: ICacheStore<RemoteVersionInfo>,
28
+ private readonly storage: IKeyValueStorage,
29
+ private readonly clock: IClock
30
+ ) {}
31
+
32
+ async getRemoteVersionInfo(
33
+ request: VersionCheckRequest
34
+ ): Promise<RemoteVersionInfo> {
35
+ if (!request.bypassCache) {
36
+ const cached = await this.cache.get(REMOTE_INFO_CACHE_KEY);
37
+ if (cached) return cached;
38
+ }
39
+
40
+ if (this.providers.length === 0) {
41
+ throw new UnsupportedStoreException({
42
+ message:
43
+ 'No store providers are registered — configure() must include at least one of stores.ios/.android/.custom/etc',
44
+ });
45
+ }
46
+
47
+ let lastError: unknown = null;
48
+ for (const provider of this.providers) {
49
+ try {
50
+ const result = await provider.fetchLatestVersionInfo({
51
+ bundleId: request.bundleId,
52
+ region: null,
53
+ timeoutMs: request.timeoutMs,
54
+ });
55
+ const info: RemoteVersionInfo = {
56
+ latestVersion: result.latestVersion,
57
+ storeUrl: result.storeUrl,
58
+ releaseNotes: result.releaseNotes,
59
+ minimumOsVersion: result.minimumOsVersion,
60
+ fetchedAt: this.clock.now(),
61
+ provider: provider.id,
62
+ };
63
+ await this.cache.set(REMOTE_INFO_CACHE_KEY, info);
64
+ return info;
65
+ } catch (error) {
66
+ lastError = error;
67
+ }
68
+ }
69
+
70
+ throw toVersionManagerException(lastError);
71
+ }
72
+
73
+ async getCachedVersionInfo(): Promise<RemoteVersionInfo | null> {
74
+ return this.cache.get(REMOTE_INFO_CACHE_KEY);
75
+ }
76
+
77
+ async persistUserDecision(decision: UserVersionDecision): Promise<void> {
78
+ await this.storage.set(USER_DECISION_STORAGE_KEY, JSON.stringify(decision));
79
+ }
80
+
81
+ async getUserDecision(): Promise<UserVersionDecision | null> {
82
+ const raw = await this.storage.get(USER_DECISION_STORAGE_KEY);
83
+ if (!raw) return null;
84
+ try {
85
+ return JSON.parse(raw) as UserVersionDecision;
86
+ } catch {
87
+ return null;
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,128 @@
1
+ import { PersistentCacheStore } from '../data/cache/PersistentCacheStore';
2
+ import { MemoryCacheStore } from '../data/cache/MemoryCacheStore';
3
+ import { ConfigCache } from '../data/config/ConfigCache';
4
+ import { ConfigDocumentValidator } from '../data/config/ConfigDocumentValidator';
5
+ import { resolveConfigSync } from '../data/config/ConfigLoader';
6
+ import { ConfigProvider } from '../data/config/ConfigProvider';
7
+ import { SignatureVerifier } from '../data/config/SignatureVerifier';
8
+ import { EnvironmentOverrideSource } from '../data/config/sources/EnvironmentOverrideSource';
9
+ import { LocalConfigSource } from '../data/config/sources/LocalConfigSource';
10
+ import { RemoteConfigSource } from '../data/config/sources/RemoteConfigSource';
11
+ import { AppleStoreProvider } from '../data/providers/apple/AppleStoreProvider';
12
+ import { CustomApiProvider } from '../data/providers/custom-api/CustomApiProvider';
13
+ import { GooglePlayProvider } from '../data/providers/google-play/GooglePlayProvider';
14
+ import { VersionRepositoryImpl } from '../data/repositories/VersionRepositoryImpl';
15
+ import { DecisionEngine } from '../domain/engines/decision/DecisionEngine';
16
+ import { PolicyEngine } from '../domain/engines/policy/PolicyEngine';
17
+ import { SemVerEngine } from '../domain/engines/semver/SemVerEngine';
18
+ import type { VersionManagerEventMap } from '../domain/models/Events';
19
+ import type { RemoteVersionInfo } from '../domain/models/RemoteVersionInfo';
20
+ import type {
21
+ ResolvedVersionManagerConfig,
22
+ VersionManagerOptions,
23
+ } from '../domain/models/VersionManagerOptions';
24
+ import type { IPlatformBridge } from '../domain/ports/IPlatformBridge';
25
+ import type { IStoreProvider } from '../domain/ports/IStoreProvider';
26
+ import { VersionManagerCore } from '../domain/VersionManagerCore';
27
+ import type { IVersionManagerCore } from '../domain/IVersionManagerCore';
28
+ import { createPlatformBridge } from '../platform/createPlatformBridge';
29
+ import { EventBus } from '../shared/eventbus/EventBus';
30
+
31
+ /**
32
+ * Composition root (Prompt 1 §1.3) — the only file in the codebase that imports both a
33
+ * port and its concrete adapter simultaneously. Only Apple/Google Play/Custom API
34
+ * providers are wired here; Huawei/Amazon/Firebase Remote Config providers exist as
35
+ * independently importable files (Prompt 1 §8) but are intentionally not referenced
36
+ * from this file yet since their implementations are still stubs (see those files'
37
+ * doc comments) — wiring them here would defeat tree-shaking for no behavioral benefit.
38
+ */
39
+ export function createVersionManagerCore(
40
+ options: VersionManagerOptions
41
+ ): IVersionManagerCore {
42
+ // Synchronous — throws InvalidConfigException immediately for a bad options bag
43
+ // (Prompt 2 §1.3's fail-fast requirement), before any adapter is constructed.
44
+ const config: ResolvedVersionManagerConfig = resolveConfigSync(options);
45
+
46
+ const platformBridge: IPlatformBridge =
47
+ options.platformBridge ?? createPlatformBridge();
48
+ const clock = platformBridge.clock;
49
+ const comparator = new SemVerEngine();
50
+ const policyEngine = new PolicyEngine(comparator);
51
+ const decisionEngine = new DecisionEngine(clock);
52
+ const eventBus = new EventBus<VersionManagerEventMap>();
53
+
54
+ const providers = buildProviders(config, platformBridge);
55
+ const remoteInfoCache =
56
+ config.cache.storage === 'memory'
57
+ ? new MemoryCacheStore<RemoteVersionInfo>(clock, config.cache.ttlMs)
58
+ : new PersistentCacheStore<RemoteVersionInfo>(
59
+ platformBridge.storage,
60
+ clock,
61
+ config.cache.ttlMs
62
+ );
63
+
64
+ const repository = new VersionRepositoryImpl(
65
+ providers,
66
+ remoteInfoCache,
67
+ platformBridge.storage,
68
+ clock
69
+ );
70
+
71
+ const configProvider = new ConfigProvider({
72
+ local: new LocalConfigSource(options.configSources?.local),
73
+ remote: new RemoteConfigSource(platformBridge.http),
74
+ envOverrides: new EnvironmentOverrideSource(
75
+ options.configSources?.envOverrides
76
+ ),
77
+ cache: new ConfigCache(platformBridge.storage),
78
+ validator: new ConfigDocumentValidator(),
79
+ signatureVerifier: new SignatureVerifier(platformBridge.crypto),
80
+ clock,
81
+ });
82
+
83
+ return new VersionManagerCore({
84
+ config,
85
+ rawOptions: options,
86
+ platformBridge,
87
+ repository,
88
+ comparator,
89
+ policyEngine,
90
+ decisionEngine,
91
+ eventBus,
92
+ clock,
93
+ configProvider,
94
+ });
95
+ }
96
+
97
+ function buildProviders(
98
+ config: ResolvedVersionManagerConfig,
99
+ bridge: IPlatformBridge
100
+ ): IStoreProvider[] {
101
+ const providers: IStoreProvider[] = [];
102
+
103
+ if (bridge.platform === 'ios' && config.stores.ios) {
104
+ providers.push(
105
+ new AppleStoreProvider(
106
+ bridge.http,
107
+ config.stores.ios.appStoreId,
108
+ config.stores.ios.region
109
+ )
110
+ );
111
+ }
112
+ if (bridge.platform === 'android' && config.stores.android) {
113
+ providers.push(
114
+ new GooglePlayProvider(bridge.http, config.stores.android.packageName)
115
+ );
116
+ }
117
+ if (config.stores.custom) {
118
+ providers.push(
119
+ new CustomApiProvider(
120
+ bridge.http,
121
+ config.stores.custom.url,
122
+ config.stores.custom.headers
123
+ )
124
+ );
125
+ }
126
+
127
+ return providers;
128
+ }
@@ -0,0 +1,54 @@
1
+ import type { ActionPlan } from './models/ActionPlan';
2
+ import type {
3
+ StateChangedEvent,
4
+ UpdateDetectedEvent,
5
+ UserActionEvent,
6
+ VersionManagerErrorEvent,
7
+ VersionManagerEventMap,
8
+ } from './models/Events';
9
+ import type { LifecycleState } from './models/LifecycleState';
10
+ import type {
11
+ CheckForUpdatesOptions,
12
+ ForceTriggerOptions,
13
+ ResetIgnoredVersionsOptions,
14
+ } from './models/PublicApiOptions';
15
+ import type { UpdateInfo } from './models/UpdateInfo';
16
+ import type { Unsubscribe } from './models/Unsubscribe';
17
+
18
+ /** Public event subscription surface (Prompt 2 §4.2). */
19
+ export interface IVersionManagerEvents {
20
+ on<K extends keyof VersionManagerEventMap>(
21
+ event: K,
22
+ handler: (payload: VersionManagerEventMap[K]) => void
23
+ ): Unsubscribe;
24
+ once<K extends keyof VersionManagerEventMap>(
25
+ event: K,
26
+ handler: (payload: VersionManagerEventMap[K]) => void
27
+ ): Unsubscribe;
28
+ off<K extends keyof VersionManagerEventMap>(
29
+ event: K,
30
+ handler: (payload: VersionManagerEventMap[K]) => void
31
+ ): void;
32
+
33
+ onUpdateDetected(handler: (e: UpdateDetectedEvent) => void): Unsubscribe;
34
+ onUserAction(handler: (e: UserActionEvent) => void): Unsubscribe;
35
+ onError(handler: (e: VersionManagerErrorEvent) => void): Unsubscribe;
36
+ onStateChanged(handler: (e: StateChangedEvent) => void): Unsubscribe;
37
+ }
38
+
39
+ /** The single class Domain exposes outward (Prompt 1 §3; full spec in Prompt 2). */
40
+ export interface IVersionManagerCore extends IVersionManagerEvents {
41
+ ready(): Promise<void>;
42
+
43
+ checkForUpdates(options?: CheckForUpdatesOptions): Promise<ActionPlan>;
44
+ forceTriggerUpdate(options?: ForceTriggerOptions): Promise<void>;
45
+ resetIgnoredVersions(options?: ResetIgnoredVersionsOptions): Promise<void>;
46
+
47
+ getCurrentState(): LifecycleState;
48
+ getUpdateInfo(): UpdateInfo | null;
49
+ isUpdateAvailable(): boolean;
50
+ getActionPlan(): ActionPlan | null;
51
+ getLastCheckedAt(): number | null;
52
+
53
+ dispose(): void;
54
+ }