@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,53 @@
1
+ import { Pressable, StyleSheet, Text, View } from 'react-native';
2
+ import type { ReactElement } from 'react';
3
+ import type { UpdateInfo } from '../../domain/models/UpdateInfo';
4
+
5
+ export interface OptionalUpdateBannerProps {
6
+ updateInfo: UpdateInfo;
7
+ onUpdatePress: () => void;
8
+ onDismissPress: () => void;
9
+ message?: string;
10
+ updateButtonLabel?: string;
11
+ }
12
+
13
+ /** Low-intrusion in-app banner (Prompt 1 §5.3; UI copy detail is Prompt 19). */
14
+ export function OptionalUpdateBanner({
15
+ updateInfo,
16
+ onUpdatePress,
17
+ onDismissPress,
18
+ message = `Version ${updateInfo.latestVersion} is available.`,
19
+ updateButtonLabel = 'Update',
20
+ }: OptionalUpdateBannerProps): ReactElement {
21
+ return (
22
+ <View style={styles.banner}>
23
+ <Text style={styles.message}>{message}</Text>
24
+ <View style={styles.actions}>
25
+ <Pressable onPress={onUpdatePress} accessibilityRole="button">
26
+ <Text style={styles.updateLabel}>{updateButtonLabel}</Text>
27
+ </Pressable>
28
+ <Pressable
29
+ onPress={onDismissPress}
30
+ accessibilityRole="button"
31
+ accessibilityLabel="Dismiss"
32
+ >
33
+ <Text style={styles.dismissLabel}>✕</Text>
34
+ </Pressable>
35
+ </View>
36
+ </View>
37
+ );
38
+ }
39
+
40
+ const styles = StyleSheet.create({
41
+ banner: {
42
+ flexDirection: 'row',
43
+ alignItems: 'center',
44
+ justifyContent: 'space-between',
45
+ paddingVertical: 10,
46
+ paddingHorizontal: 16,
47
+ backgroundColor: '#111827',
48
+ },
49
+ message: { color: '#ffffff', fontSize: 13, flexShrink: 1, marginRight: 12 },
50
+ actions: { flexDirection: 'row', alignItems: 'center', gap: 16 },
51
+ updateLabel: { color: '#60a5fa', fontSize: 13, fontWeight: '700' },
52
+ dismissLabel: { color: '#9ca3af', fontSize: 13 },
53
+ });
@@ -0,0 +1,84 @@
1
+ import { Modal, Pressable, StyleSheet, Text, View } from 'react-native';
2
+ import type { ReactElement } from 'react';
3
+ import type { UpdateInfo } from '../../domain/models/UpdateInfo';
4
+
5
+ export interface SoftUpdateDialogProps {
6
+ updateInfo: UpdateInfo;
7
+ onUpdatePress: () => void;
8
+ onLaterPress: () => void;
9
+ title?: string;
10
+ message?: string;
11
+ updateButtonLabel?: string;
12
+ laterButtonLabel?: string;
13
+ }
14
+
15
+ /** Dismissible modal dialog (Prompt 1 §5.3; UI copy detail is Prompt 19). */
16
+ export function SoftUpdateDialog({
17
+ updateInfo,
18
+ onUpdatePress,
19
+ onLaterPress,
20
+ title = 'Update Available',
21
+ message = `Version ${updateInfo.latestVersion} is available.${updateInfo.releaseNotes ? ` ${updateInfo.releaseNotes}` : ''}`,
22
+ updateButtonLabel = 'Update',
23
+ laterButtonLabel = 'Later',
24
+ }: SoftUpdateDialogProps): ReactElement {
25
+ return (
26
+ <Modal
27
+ visible
28
+ animationType="slide"
29
+ transparent
30
+ onRequestClose={onLaterPress}
31
+ >
32
+ <View style={styles.backdrop}>
33
+ <View style={styles.card}>
34
+ <Text style={styles.title}>{title}</Text>
35
+ <Text style={styles.message}>{message}</Text>
36
+ <View style={styles.actions}>
37
+ <Pressable
38
+ style={styles.secondaryButton}
39
+ onPress={onLaterPress}
40
+ accessibilityRole="button"
41
+ >
42
+ <Text style={styles.secondaryButtonLabel}>
43
+ {laterButtonLabel}
44
+ </Text>
45
+ </Pressable>
46
+ <Pressable
47
+ style={styles.primaryButton}
48
+ onPress={onUpdatePress}
49
+ accessibilityRole="button"
50
+ >
51
+ <Text style={styles.primaryButtonLabel}>{updateButtonLabel}</Text>
52
+ </Pressable>
53
+ </View>
54
+ </View>
55
+ </View>
56
+ </Modal>
57
+ );
58
+ }
59
+
60
+ const styles = StyleSheet.create({
61
+ backdrop: {
62
+ flex: 1,
63
+ backgroundColor: 'rgba(0,0,0,0.4)',
64
+ justifyContent: 'flex-end',
65
+ },
66
+ card: {
67
+ backgroundColor: '#ffffff',
68
+ borderTopLeftRadius: 16,
69
+ borderTopRightRadius: 16,
70
+ padding: 24,
71
+ },
72
+ title: { fontSize: 18, fontWeight: '700', marginBottom: 8 },
73
+ message: { fontSize: 14, marginBottom: 20 },
74
+ actions: { flexDirection: 'row', justifyContent: 'flex-end', gap: 12 },
75
+ secondaryButton: { paddingVertical: 10, paddingHorizontal: 16 },
76
+ secondaryButtonLabel: { color: '#6b7280', fontSize: 15, fontWeight: '600' },
77
+ primaryButton: {
78
+ paddingVertical: 10,
79
+ paddingHorizontal: 16,
80
+ borderRadius: 8,
81
+ backgroundColor: '#2563eb',
82
+ },
83
+ primaryButtonLabel: { color: '#ffffff', fontSize: 15, fontWeight: '600' },
84
+ });
@@ -0,0 +1,23 @@
1
+ import { useMemo } from 'react';
2
+ import type { ReactElement, ReactNode } from 'react';
3
+ import { VersionManager } from '../../publicApi';
4
+ import type { VersionManagerOptions } from '../../domain/models/VersionManagerOptions';
5
+ import { VersionManagerContext } from './context';
6
+
7
+ export interface VersionManagerProviderProps {
8
+ options: VersionManagerOptions;
9
+ children: ReactNode;
10
+ }
11
+
12
+ /** Optional top-level configuration provider (Prompt 2 §6) — an alternative to passing options to every useVersionManager() call. */
13
+ export function VersionManagerProvider({
14
+ options,
15
+ children,
16
+ }: VersionManagerProviderProps): ReactElement {
17
+ const manager = useMemo(() => VersionManager.configure(options), [options]);
18
+ return (
19
+ <VersionManagerContext.Provider value={manager}>
20
+ {children}
21
+ </VersionManagerContext.Provider>
22
+ );
23
+ }
@@ -0,0 +1,6 @@
1
+ import { createContext } from 'react';
2
+ import type { IVersionManagerCore } from '../../domain/IVersionManagerCore';
3
+
4
+ export const VersionManagerContext = createContext<IVersionManagerCore | null>(
5
+ null
6
+ );
@@ -0,0 +1,50 @@
1
+ import {
2
+ useCallback,
3
+ useContext,
4
+ useEffect,
5
+ useMemo,
6
+ useSyncExternalStore,
7
+ } from 'react';
8
+ import type { ActionPlan } from '../../domain/models/ActionPlan';
9
+ import type { LifecycleState } from '../../domain/models/LifecycleState';
10
+ import type { UpdateInfo } from '../../domain/models/UpdateInfo';
11
+ import { VersionManager } from '../../publicApi';
12
+ import { VersionManagerStore } from '../state/VersionManagerStore';
13
+ import { VersionManagerContext } from './context';
14
+
15
+ export interface UseUpdateStateResult {
16
+ readonly state: LifecycleState;
17
+ readonly updateInfo: UpdateInfo | null;
18
+ readonly isUpdateAvailable: boolean;
19
+ readonly actionPlan: ActionPlan | null;
20
+ }
21
+
22
+ /**
23
+ * Reactive state only, for components that don't need to trigger checks (Prompt 2 §6).
24
+ * Must be used beneath a tree where useVersionManager() or VersionManagerProvider has
25
+ * already run at least once — otherwise this falls back to VersionManager.getInstance(),
26
+ * which throws NotInitializedException if configure() was never called.
27
+ */
28
+ export function useUpdateState(): UseUpdateStateResult {
29
+ const contextManager = useContext(VersionManagerContext);
30
+ const manager = useMemo(
31
+ () => contextManager ?? VersionManager.getInstance(),
32
+ [contextManager]
33
+ );
34
+
35
+ const store = useMemo(() => new VersionManagerStore(manager), [manager]);
36
+ useEffect(() => () => store.dispose(), [store]);
37
+
38
+ const uiState = useSyncExternalStore(
39
+ useCallback((listener) => store.subscribe(listener), [store]),
40
+ () => store.getState(),
41
+ () => store.getState()
42
+ );
43
+
44
+ return {
45
+ state: uiState.lifecycleState,
46
+ updateInfo: uiState.updateInfo,
47
+ isUpdateAvailable: uiState.isUpdateAvailable,
48
+ actionPlan: uiState.actionPlan,
49
+ };
50
+ }
@@ -0,0 +1,68 @@
1
+ import {
2
+ useCallback,
3
+ useContext,
4
+ useEffect,
5
+ useMemo,
6
+ useSyncExternalStore,
7
+ } from 'react';
8
+ import type { IVersionManagerCore } from '../../domain/IVersionManagerCore';
9
+ import type { LifecycleState } from '../../domain/models/LifecycleState';
10
+ import type { ActionPlan } from '../../domain/models/ActionPlan';
11
+ import type { CheckForUpdatesOptions } from '../../domain/models/PublicApiOptions';
12
+ import type { UpdateInfo } from '../../domain/models/UpdateInfo';
13
+ import type { VersionManagerOptions } from '../../domain/models/VersionManagerOptions';
14
+ import { VersionManager } from '../../publicApi';
15
+ import { VersionManagerStore } from '../state/VersionManagerStore';
16
+ import { VersionManagerContext } from './context';
17
+
18
+ export interface UseVersionManagerResult {
19
+ readonly manager: IVersionManagerCore;
20
+ readonly state: LifecycleState;
21
+ readonly updateInfo: UpdateInfo | null;
22
+ readonly isUpdateAvailable: boolean;
23
+ readonly checkForUpdates: (
24
+ options?: CheckForUpdatesOptions
25
+ ) => Promise<ActionPlan>;
26
+ }
27
+
28
+ /**
29
+ * Bootstraps (or attaches to) the singleton and returns the imperative handle plus
30
+ * reactive state in one call (Prompt 2 §6). For a stable manager reference across
31
+ * re-renders, pass a memoized `options` object — VersionManager.configure() is
32
+ * idempotent for equal options, but this hook still re-invokes it whenever the
33
+ * `options` reference changes.
34
+ */
35
+ export function useVersionManager(
36
+ options?: VersionManagerOptions
37
+ ): UseVersionManagerResult {
38
+ const contextManager = useContext(VersionManagerContext);
39
+
40
+ const manager = useMemo<IVersionManagerCore>(() => {
41
+ if (contextManager) return contextManager;
42
+ if (options) return VersionManager.configure(options);
43
+ return VersionManager.getInstance();
44
+ }, [contextManager, options]);
45
+
46
+ const store = useMemo(() => new VersionManagerStore(manager), [manager]);
47
+ useEffect(() => () => store.dispose(), [store]);
48
+
49
+ const uiState = useSyncExternalStore(
50
+ useCallback((listener) => store.subscribe(listener), [store]),
51
+ () => store.getState(),
52
+ () => store.getState()
53
+ );
54
+
55
+ const checkForUpdates = useCallback(
56
+ (checkOptions?: CheckForUpdatesOptions) =>
57
+ manager.checkForUpdates(checkOptions),
58
+ [manager]
59
+ );
60
+
61
+ return {
62
+ manager,
63
+ state: uiState.lifecycleState,
64
+ updateInfo: uiState.updateInfo,
65
+ isUpdateAvailable: uiState.isUpdateAvailable,
66
+ checkForUpdates,
67
+ };
68
+ }
@@ -0,0 +1,72 @@
1
+ import type { ActionPlan } from '../../domain/models/ActionPlan';
2
+ import type { LifecycleState } from '../../domain/models/LifecycleState';
3
+ import type { UpdateInfo } from '../../domain/models/UpdateInfo';
4
+ import type { Unsubscribe } from '../../domain/models/Unsubscribe';
5
+ import type { IVersionManagerCore } from '../../domain/IVersionManagerCore';
6
+
7
+ export interface VersionManagerUiState {
8
+ readonly lifecycleState: LifecycleState;
9
+ readonly updateInfo: UpdateInfo | null;
10
+ readonly actionPlan: ActionPlan | null;
11
+ readonly isUpdateAvailable: boolean;
12
+ }
13
+
14
+ function snapshotFrom(core: IVersionManagerCore): VersionManagerUiState {
15
+ return {
16
+ lifecycleState: core.getCurrentState(),
17
+ updateInfo: core.getUpdateInfo(),
18
+ actionPlan: core.getActionPlan(),
19
+ isUpdateAvailable: core.isUpdateAvailable(),
20
+ };
21
+ }
22
+
23
+ /**
24
+ * The single reactive source of truth the Hooks adapter renders from (Prompt 1 §6) —
25
+ * components subscribe to this store, never to the core's event bus directly. Kept in
26
+ * sync by re-snapshotting the core on every event it emits.
27
+ */
28
+ export class VersionManagerStore {
29
+ private state: VersionManagerUiState;
30
+ private readonly listeners = new Set<
31
+ (state: Readonly<VersionManagerUiState>) => void
32
+ >();
33
+ private readonly detach: Unsubscribe;
34
+
35
+ constructor(private readonly core: IVersionManagerCore) {
36
+ this.state = snapshotFrom(core);
37
+
38
+ const unsubscribers = [
39
+ core.onStateChanged(() => this.sync()),
40
+ core.onUpdateDetected(() => this.sync()),
41
+ core.on('updateNotAvailable', () => this.sync()),
42
+ ];
43
+ this.detach = () => {
44
+ for (const unsubscribe of unsubscribers) unsubscribe();
45
+ };
46
+ }
47
+
48
+ getState(): Readonly<VersionManagerUiState> {
49
+ return this.state;
50
+ }
51
+
52
+ subscribe(
53
+ listener: (state: Readonly<VersionManagerUiState>) => void
54
+ ): Unsubscribe {
55
+ this.listeners.add(listener);
56
+ return () => {
57
+ this.listeners.delete(listener);
58
+ };
59
+ }
60
+
61
+ dispose(): void {
62
+ this.detach();
63
+ this.listeners.clear();
64
+ }
65
+
66
+ private sync(): void {
67
+ this.state = snapshotFrom(this.core);
68
+ for (const listener of Array.from(this.listeners)) {
69
+ listener(this.state);
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,126 @@
1
+ import { createVersionManagerCore } from './di/container';
2
+ import {
3
+ InvalidConfigException,
4
+ NotInitializedException,
5
+ } from './domain/errors/VersionManagerException';
6
+ import type { IVersionManagerCore } from './domain/IVersionManagerCore';
7
+ import type {
8
+ CacheOptions,
9
+ FallbackOptions,
10
+ LoggingOptions,
11
+ PolicyOptions,
12
+ StoreLinksOptions,
13
+ VersionManagerOptions,
14
+ } from './domain/models/VersionManagerOptions';
15
+ import type { IPlatformBridge } from './domain/ports/IPlatformBridge';
16
+
17
+ let instance: IVersionManagerCore | null = null;
18
+ let instanceOptions: VersionManagerOptions | null = null;
19
+
20
+ /**
21
+ * Structural equality via JSON serialization — good enough to detect "the same
22
+ * configure() call happening twice" (e.g. duplicate provider mounts in React) without
23
+ * requiring callers to memoize their options object. `platformBridge` (a live object
24
+ * of functions) is excluded; DI overrides are expected to be stable references from
25
+ * advanced/testing callers, not something this check needs to compare deeply.
26
+ */
27
+ function withoutPlatformBridge(
28
+ options: VersionManagerOptions
29
+ ): Omit<VersionManagerOptions, 'platformBridge'> {
30
+ const clone: VersionManagerOptions = { ...options };
31
+ delete clone.platformBridge;
32
+ return clone;
33
+ }
34
+
35
+ function optionsEqual(
36
+ a: VersionManagerOptions,
37
+ b: VersionManagerOptions
38
+ ): boolean {
39
+ return (
40
+ JSON.stringify(withoutPlatformBridge(a)) ===
41
+ JSON.stringify(withoutPlatformBridge(b))
42
+ );
43
+ }
44
+
45
+ export const VersionManager = {
46
+ configure(options: VersionManagerOptions): IVersionManagerCore {
47
+ if (instance && instanceOptions) {
48
+ if (optionsEqual(instanceOptions, options)) {
49
+ return instance;
50
+ }
51
+ throw new InvalidConfigException({
52
+ message:
53
+ 'VersionManager.configure() was already called with different options. Call VersionManager.reset() first if this is intentional (e.g. in tests).',
54
+ });
55
+ }
56
+ const core = createVersionManagerCore(options);
57
+ instance = core;
58
+ instanceOptions = options;
59
+ return core;
60
+ },
61
+
62
+ getInstance(): IVersionManagerCore {
63
+ if (!instance) {
64
+ throw new NotInitializedException({
65
+ message: 'VersionManager.getInstance() called before configure()',
66
+ });
67
+ }
68
+ return instance;
69
+ },
70
+
71
+ isConfigured(): boolean {
72
+ return instance !== null;
73
+ },
74
+
75
+ /** Testing/HMR only — tears down the singleton (Prompt 2 §1.1). */
76
+ reset(): void {
77
+ instance?.dispose();
78
+ instance = null;
79
+ instanceOptions = null;
80
+ },
81
+ };
82
+
83
+ export class VersionManagerBuilder {
84
+ private options: VersionManagerOptions = { stores: {} };
85
+
86
+ private constructor() {}
87
+
88
+ static create(): VersionManagerBuilder {
89
+ return new VersionManagerBuilder();
90
+ }
91
+
92
+ withLogging(options: LoggingOptions): this {
93
+ this.options = { ...this.options, logging: options };
94
+ return this;
95
+ }
96
+
97
+ withCache(options: CacheOptions): this {
98
+ this.options = { ...this.options, cache: options };
99
+ return this;
100
+ }
101
+
102
+ withFallback(options: FallbackOptions): this {
103
+ this.options = { ...this.options, fallback: options };
104
+ return this;
105
+ }
106
+
107
+ withStoreLinks(options: StoreLinksOptions): this {
108
+ this.options = { ...this.options, stores: options };
109
+ return this;
110
+ }
111
+
112
+ withPolicy(options: PolicyOptions): this {
113
+ this.options = { ...this.options, policy: options };
114
+ return this;
115
+ }
116
+
117
+ /** Advanced/testing: DI override (Prompt 2 §1.1). */
118
+ withPlatformBridge(bridge: IPlatformBridge): this {
119
+ this.options = { ...this.options, platformBridge: bridge };
120
+ return this;
121
+ }
122
+
123
+ build(): IVersionManagerCore {
124
+ return VersionManager.configure(this.options);
125
+ }
126
+ }
@@ -0,0 +1,56 @@
1
+ import type { Unsubscribe } from '../../domain/models/Unsubscribe';
2
+
3
+ export type { Unsubscribe };
4
+
5
+ export interface IEventBus<TMap extends object> {
6
+ publish<K extends keyof TMap>(type: K, payload: TMap[K]): void;
7
+ subscribe<K extends keyof TMap>(
8
+ type: K,
9
+ handler: (payload: TMap[K]) => void
10
+ ): Unsubscribe;
11
+ /** Removes a handler registered via subscribe() by reference (Prompt 2 §4.2's off()). */
12
+ off<K extends keyof TMap>(type: K, handler: (payload: TMap[K]) => void): void;
13
+ }
14
+
15
+ type AnyHandler = (payload: unknown) => void;
16
+
17
+ /**
18
+ * Generic typed pub/sub used for both the internal domain event flow (Prompt 1 §6)
19
+ * and the public IVersionManagerEvents surface (Prompt 2 §4). Copy-on-write listener
20
+ * snapshots on dispatch (Prompt 1 §9.2) — publishing during a concurrent
21
+ * subscribe/unsubscribe never races or throws.
22
+ */
23
+ export class EventBus<TMap extends object> implements IEventBus<TMap> {
24
+ private readonly listeners = new Map<keyof TMap, Set<AnyHandler>>();
25
+
26
+ publish<K extends keyof TMap>(type: K, payload: TMap[K]): void {
27
+ const set = this.listeners.get(type);
28
+ if (!set) return;
29
+ for (const handler of Array.from(set)) {
30
+ handler(payload);
31
+ }
32
+ }
33
+
34
+ subscribe<K extends keyof TMap>(
35
+ type: K,
36
+ handler: (payload: TMap[K]) => void
37
+ ): Unsubscribe {
38
+ let set = this.listeners.get(type);
39
+ if (!set) {
40
+ set = new Set();
41
+ this.listeners.set(type, set);
42
+ }
43
+ const wrapped = handler as AnyHandler;
44
+ set.add(wrapped);
45
+ return () => {
46
+ set?.delete(wrapped);
47
+ };
48
+ }
49
+
50
+ off<K extends keyof TMap>(
51
+ type: K,
52
+ handler: (payload: TMap[K]) => void
53
+ ): void {
54
+ this.listeners.get(type)?.delete(handler as AnyHandler);
55
+ }
56
+ }
@@ -0,0 +1,70 @@
1
+ import type {
2
+ ILogSink,
3
+ LogEntry,
4
+ LogLevel,
5
+ } from '../../domain/models/VersionManagerOptions';
6
+
7
+ const LEVEL_ORDER: Record<LogLevel, number> = {
8
+ silent: 0,
9
+ error: 1,
10
+ warn: 2,
11
+ info: 3,
12
+ debug: 4,
13
+ verbose: 5,
14
+ };
15
+
16
+ export class ConsoleLogSink implements ILogSink {
17
+ write(entry: LogEntry): void {
18
+ const line = `[VersionManager] ${entry.message}`;
19
+ if (entry.level === 'error') {
20
+ console.error(line, entry.metadata ?? {});
21
+ } else if (entry.level === 'warn') {
22
+ console.warn(line, entry.metadata ?? {});
23
+ } else {
24
+ console.info(line, entry.metadata ?? {});
25
+ }
26
+ }
27
+ }
28
+
29
+ export class Logger {
30
+ private level: LogLevel;
31
+ private readonly sink: ILogSink;
32
+
33
+ constructor(level: LogLevel, sink: ILogSink) {
34
+ this.level = level;
35
+ this.sink = sink;
36
+ }
37
+
38
+ setLevel(level: LogLevel): void {
39
+ this.level = level;
40
+ }
41
+
42
+ error(message: string, metadata?: Record<string, unknown>): void {
43
+ this.log('error', message, metadata);
44
+ }
45
+
46
+ warn(message: string, metadata?: Record<string, unknown>): void {
47
+ this.log('warn', message, metadata);
48
+ }
49
+
50
+ info(message: string, metadata?: Record<string, unknown>): void {
51
+ this.log('info', message, metadata);
52
+ }
53
+
54
+ debug(message: string, metadata?: Record<string, unknown>): void {
55
+ this.log('debug', message, metadata);
56
+ }
57
+
58
+ verbose(message: string, metadata?: Record<string, unknown>): void {
59
+ this.log('verbose', message, metadata);
60
+ }
61
+
62
+ private log(
63
+ level: LogLevel,
64
+ message: string,
65
+ metadata?: Record<string, unknown>
66
+ ): void {
67
+ if (LEVEL_ORDER[level] > LEVEL_ORDER[this.level]) return;
68
+ this.sink.write({ level, message, timestamp: Date.now(), metadata });
69
+ }
70
+ }
package/src/ui.tsx ADDED
@@ -0,0 +1,19 @@
1
+ // Presentation entry point (Prompt 1 §8) — importing only 'src/index.tsx' never pulls
2
+ // in anything below; this subpath is where React/RN UI code lives.
3
+
4
+ export { useVersionManager } from './presentation/hooks/useVersionManager';
5
+ export type { UseVersionManagerResult } from './presentation/hooks/useVersionManager';
6
+ export { useUpdateState } from './presentation/hooks/useUpdateState';
7
+ export type { UseUpdateStateResult } from './presentation/hooks/useUpdateState';
8
+ export { VersionManagerProvider } from './presentation/hooks/VersionManagerProvider';
9
+ export type { VersionManagerProviderProps } from './presentation/hooks/VersionManagerProvider';
10
+
11
+ export { ForceUpdateScreen } from './presentation/components/ForceUpdateScreen';
12
+ export type { ForceUpdateScreenProps } from './presentation/components/ForceUpdateScreen';
13
+ export { SoftUpdateDialog } from './presentation/components/SoftUpdateDialog';
14
+ export type { SoftUpdateDialogProps } from './presentation/components/SoftUpdateDialog';
15
+ export { OptionalUpdateBanner } from './presentation/components/OptionalUpdateBanner';
16
+ export type { OptionalUpdateBannerProps } from './presentation/components/OptionalUpdateBanner';
17
+
18
+ export type { VersionManagerUiState } from './presentation/state/VersionManagerStore';
19
+ export { VersionManagerStore } from './presentation/state/VersionManagerStore';