@react-native-firebase/app 26.3.3 → 27.0.0

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 (283) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/README.md +10 -27
  3. package/RNFBApp.podspec +13 -5
  4. package/android/build.gradle +3 -0
  5. package/android/src/main/java/io/invertase/firebase/common/RNFBHandleCollisionException.kt +29 -0
  6. package/android/src/main/java/io/invertase/firebase/common/RNFBHandleMap.kt +146 -0
  7. package/android/src/main/java/io/invertase/firebase/common/TaskExecutorService.kt +156 -0
  8. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebaseModule.kt +44 -0
  9. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebasePreferences.kt +100 -0
  10. package/android/src/reactnative/java/io/invertase/firebase/app/NativeRNFBTurboApp.kt +250 -0
  11. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseApp.kt +64 -0
  12. package/android/src/reactnative/java/io/invertase/firebase/app/{ReactNativeFirebaseAppInitProvider.java → ReactNativeFirebaseAppInitProvider.kt} +3 -4
  13. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackage.kt +47 -0
  14. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppRegistrar.kt +33 -0
  15. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseVersion.java +1 -1
  16. package/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.kt +185 -0
  17. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEvent.kt +35 -0
  18. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitter.kt +662 -0
  19. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseJSON.kt +103 -0
  20. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseMeta.kt +96 -0
  21. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseModule.kt +140 -0
  22. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebasePreferences.kt +109 -0
  23. package/android/src/reactnative/java/io/invertase/firebase/common/SharedUtils.kt +451 -0
  24. package/android/src/reactnative/java/io/invertase/firebase/interfaces/{ContextProvider.java → ContextProvider.kt} +8 -8
  25. package/android/src/reactnative/java/io/invertase/firebase/interfaces/{NativeError.java → NativeError.kt} +8 -8
  26. package/android/src/reactnative/java/io/invertase/firebase/interfaces/{NativeEvent.java → NativeEvent.kt} +6 -6
  27. package/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.kt +219 -0
  28. package/android/src/test/java/expo/core/ModuleRegistry.java +9 -0
  29. package/android/src/test/java/io/invertase/firebase/app/NativeRNFBTurboAppTest.java +208 -60
  30. package/android/src/test/java/io/invertase/firebase/app/ReactNativeFirebaseAppComponentsJavaCompatibilityTest.java +70 -0
  31. package/android/src/test/java/io/invertase/firebase/app/ReactNativeFirebaseAppJavaCompatibilityTest.java +60 -0
  32. package/android/src/test/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackageTest.java +165 -0
  33. package/android/src/test/java/io/invertase/firebase/app/ReactNativeFirebaseAppTest.kt +167 -0
  34. package/android/src/test/java/io/invertase/firebase/common/RCTConvertFirebaseJavaCompatibilityTest.java +112 -0
  35. package/android/src/test/java/io/invertase/firebase/common/RCTConvertFirebaseTest.kt +317 -0
  36. package/android/src/test/java/io/invertase/firebase/common/RNFBHandleMapTest.kt +309 -0
  37. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitterJavaCompatibilityTest.java +176 -0
  38. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitterTest.java +144 -13
  39. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseEventTest.kt +61 -0
  40. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseJSONJavaCompatibilityTest.java +85 -0
  41. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseJSONTest.kt +296 -0
  42. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseMetaJavaCompatibilityTest.java +67 -0
  43. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseMetaTest.kt +246 -0
  44. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseModuleTest.kt +254 -0
  45. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebasePreferencesJavaCompatibilityTest.java +87 -0
  46. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebasePreferencesTest.kt +260 -0
  47. package/android/src/test/java/io/invertase/firebase/common/SharedUtilsJavaCompatibilityTest.java +255 -0
  48. package/android/src/test/java/io/invertase/firebase/common/SharedUtilsTest.kt +674 -0
  49. package/android/src/test/java/io/invertase/firebase/common/TaskExecutorServiceTest.kt +290 -0
  50. package/android/src/test/java/io/invertase/firebase/common/UniversalFirebaseModuleJavaCompatibilityTest.java +178 -0
  51. package/android/src/test/java/io/invertase/firebase/common/UniversalFirebasePreferencesJavaCompatibilityTest.java +99 -0
  52. package/android/src/test/java/io/invertase/firebase/common/UniversalFirebasePreferencesTest.kt +217 -0
  53. package/android/src/test/java/io/invertase/firebase/commoncompat/ReactNativeFirebaseModuleJavaCompatibilityTest.java +176 -0
  54. package/android/src/test/java/io/invertase/firebase/commoncompat/ReactNativeFirebaseModuleKotlinCompatibilityTest.kt +52 -0
  55. package/android/src/test/java/io/invertase/firebase/interfaces/InterfacesJavaCompatibilityTest.java +144 -0
  56. package/android/src/test/java/io/invertase/firebase/interfaces/NativeEventTest.kt +56 -0
  57. package/android/src/test/java/io/invertase/firebase/utils/NativeRNFBTurboUtilsTest.java +517 -23
  58. package/dist/module/FirebaseApp.js +10 -0
  59. package/dist/module/FirebaseApp.js.map +1 -1
  60. package/dist/module/common/Base64.js +13 -21
  61. package/dist/module/common/Base64.js.map +1 -1
  62. package/dist/module/common/deeps.js +3 -0
  63. package/dist/module/common/deeps.js.map +1 -1
  64. package/dist/module/common/index.js +17 -9
  65. package/dist/module/common/index.js.map +1 -1
  66. package/dist/module/internal/FirebaseModule.js.map +1 -1
  67. package/dist/module/internal/RNFBNativeEventEmitter.js +12 -1
  68. package/dist/module/internal/RNFBNativeEventEmitter.js.map +1 -1
  69. package/dist/module/internal/SharedEventEmitter.js +3 -1
  70. package/dist/module/internal/SharedEventEmitter.js.map +1 -1
  71. package/dist/module/internal/asyncStorage.js +7 -11
  72. package/dist/module/internal/asyncStorage.js.map +1 -1
  73. package/dist/module/internal/index.js +1 -0
  74. package/dist/module/internal/index.js.map +1 -1
  75. package/dist/module/internal/logger.js +44 -40
  76. package/dist/module/internal/logger.js.map +1 -1
  77. package/dist/module/internal/nativeModuleAndroidIos.js +2 -29
  78. package/dist/module/internal/nativeModuleAndroidIos.js.map +1 -1
  79. package/dist/module/internal/nativeModuleDebug.js +74 -0
  80. package/dist/module/internal/nativeModuleDebug.js.map +1 -0
  81. package/dist/module/internal/nativeModuleWeb.js +9 -29
  82. package/dist/module/internal/nativeModuleWeb.js.map +1 -1
  83. package/dist/module/internal/registry/app.js +8 -2
  84. package/dist/module/internal/registry/app.js.map +1 -1
  85. package/dist/module/internal/registry/modular.js +2 -2
  86. package/dist/module/internal/registry/modular.js.map +1 -1
  87. package/dist/module/internal/registry/nativeModule.js +3 -3
  88. package/dist/module/internal/registry/nativeModule.js.map +1 -1
  89. package/dist/module/internal/web/RNFBAppModule.js +16 -15
  90. package/dist/module/internal/web/RNFBAppModule.js.map +1 -1
  91. package/dist/module/internal/web/memidb/lib/FakeEventTarget.js +3 -1
  92. package/dist/module/internal/web/memidb/lib/FakeEventTarget.js.map +1 -1
  93. package/dist/module/types/app.js.map +1 -1
  94. package/dist/module/types/internal.js +2 -0
  95. package/dist/module/version.js +1 -1
  96. package/dist/typescript/lib/FirebaseApp.d.ts +7 -0
  97. package/dist/typescript/lib/FirebaseApp.d.ts.map +1 -1
  98. package/dist/typescript/lib/common/Base64.d.ts.map +1 -1
  99. package/dist/typescript/lib/common/deeps.d.ts.map +1 -1
  100. package/dist/typescript/lib/common/index.d.ts.map +1 -1
  101. package/dist/typescript/lib/internal/FirebaseModule.d.ts +2 -3
  102. package/dist/typescript/lib/internal/FirebaseModule.d.ts.map +1 -1
  103. package/dist/typescript/lib/internal/NativeModules.d.ts +4 -1
  104. package/dist/typescript/lib/internal/NativeModules.d.ts.map +1 -1
  105. package/dist/typescript/lib/internal/RNFBNativeEventEmitter.d.ts +2 -2
  106. package/dist/typescript/lib/internal/RNFBNativeEventEmitter.d.ts.map +1 -1
  107. package/dist/typescript/lib/internal/SharedEventEmitter.d.ts +3 -3
  108. package/dist/typescript/lib/internal/SharedEventEmitter.d.ts.map +1 -1
  109. package/dist/typescript/lib/internal/asyncStorage.d.ts.map +1 -1
  110. package/dist/typescript/lib/internal/index.d.ts +1 -0
  111. package/dist/typescript/lib/internal/index.d.ts.map +1 -1
  112. package/dist/typescript/lib/internal/logger.d.ts.map +1 -1
  113. package/dist/typescript/lib/internal/nativeModuleAndroidIos.d.ts.map +1 -1
  114. package/dist/typescript/lib/internal/nativeModuleDebug.d.ts +2 -0
  115. package/dist/typescript/lib/internal/nativeModuleDebug.d.ts.map +1 -0
  116. package/dist/typescript/lib/internal/nativeModuleWeb.d.ts.map +1 -1
  117. package/dist/typescript/lib/internal/registry/app.d.ts.map +1 -1
  118. package/dist/typescript/lib/internal/web/RNFBAppModule.d.ts +7 -7
  119. package/dist/typescript/lib/internal/web/RNFBAppModule.d.ts.map +1 -1
  120. package/dist/typescript/lib/types/app.d.ts +10 -3
  121. package/dist/typescript/lib/types/app.d.ts.map +1 -1
  122. package/dist/typescript/lib/types/internal.d.ts +12 -0
  123. package/dist/typescript/lib/types/internal.d.ts.map +1 -1
  124. package/dist/typescript/lib/version.d.ts +1 -1
  125. package/firebase-schema.json +5 -1
  126. package/firebase_spm.rb +552 -96
  127. package/ios/RNFBApp/RCTConvert+FIRApp.h +2 -5
  128. package/ios/RNFBApp/RCTConvert+FIRApp.m +11 -6
  129. package/ios/RNFBApp/RCTConvert+FIROptions.h +2 -5
  130. package/ios/RNFBApp/RCTConvert+FIROptions.m +11 -10
  131. package/ios/RNFBApp/RCTConvertFIRApp.swift +86 -0
  132. package/ios/RNFBApp/RCTConvertFIROptions.swift +259 -0
  133. package/ios/RNFBApp/RNFBAppCustomAuthDomains.swift +63 -0
  134. package/ios/RNFBApp/RNFBAppInitializeOptionsMapper.swift +113 -0
  135. package/ios/RNFBApp/RNFBAppLogLevelMapper.swift +53 -0
  136. package/ios/RNFBApp/RNFBAppModule+CustomAuthDomain.m +35 -0
  137. package/ios/RNFBApp/RNFBAppModule.h +6 -2
  138. package/ios/RNFBApp/RNFBAppModule.mm +67 -204
  139. package/ios/RNFBApp/RNFBAppModuleFirebase.swift +439 -0
  140. package/ios/RNFBApp/RNFBAppModuleImplementation.h +68 -0
  141. package/ios/RNFBApp/RNFBAppModuleImplementation.m +195 -0
  142. package/ios/RNFBApp/RNFBHandleMap.h +73 -0
  143. package/ios/RNFBApp/RNFBHandleMap.m +87 -0
  144. package/ios/RNFBApp/RNFBHandleMapStorage.swift +90 -0
  145. package/ios/RNFBApp/RNFBInitializeAppArguments.swift +82 -0
  146. package/ios/RNFBApp/RNFBJSON.m +22 -38
  147. package/ios/RNFBApp/RNFBJSONImplementation.swift +71 -0
  148. package/ios/RNFBApp/RNFBMeta.m +24 -26
  149. package/ios/RNFBApp/RNFBMetaStorage.swift +76 -0
  150. package/ios/RNFBApp/RNFBNullSentinelDecoding.swift +135 -0
  151. package/ios/RNFBApp/RNFBNullSentinelInterceptor.h +30 -3
  152. package/ios/RNFBApp/RNFBNullSentinelInterceptor.m +28 -5
  153. package/ios/RNFBApp/RNFBPreferences.m +22 -20
  154. package/ios/RNFBApp/RNFBPreferencesStorage.swift +101 -0
  155. package/ios/RNFBApp/RNFBRCTEventEmitter.m +36 -93
  156. package/ios/RNFBApp/RNFBRCTEventEmitterCore.swift +161 -0
  157. package/ios/RNFBApp/RNFBSharedUtils.h +2 -5
  158. package/ios/RNFBApp/RNFBSharedUtils.m +109 -197
  159. package/ios/RNFBApp/RNFBSharedUtilsConfig.swift +72 -0
  160. package/ios/RNFBApp/RNFBSharedUtilsFIRApp.swift +271 -0
  161. package/ios/RNFBApp/RNFBSharedUtilsFormatting.swift +59 -0
  162. package/ios/RNFBApp/RNFBSharedUtilsPromiseRejection.swift +88 -0
  163. package/ios/RNFBApp/RNFBUtilsHelpers.swift +116 -0
  164. package/ios/RNFBApp/RNFBUtilsModule+Foundation.m +44 -0
  165. package/ios/RNFBApp/RNFBUtilsModule+PhotoAssets.m +47 -0
  166. package/ios/RNFBApp/RNFBUtilsModule.h +11 -1
  167. package/ios/RNFBApp/RNFBUtilsModule.mm +10 -85
  168. package/ios/RNFBApp/RNFBUtilsModuleImplementation.h +32 -0
  169. package/ios/RNFBApp/RNFBUtilsModuleImplementation.m +56 -0
  170. package/ios/RNFBApp/RNFBVersion.m +1 -1
  171. package/ios/RNFBApp.xcodeproj/project.pbxproj +106 -0
  172. package/ios/RNFBAppUnitTests/HostStubs/FirebaseCore/FIRApp.m +171 -0
  173. package/ios/RNFBAppUnitTests/HostStubs/FirebaseCore/FirebaseCore.h +78 -0
  174. package/ios/RNFBAppUnitTests/HostStubs/FirebaseInstallations/FIRInstallations.m +7 -0
  175. package/ios/RNFBAppUnitTests/HostStubs/FirebaseInstallations/FirebaseInstallations.h +8 -0
  176. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppModuleHostStub.m +55 -0
  177. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppTurboModules.h +89 -0
  178. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppTurboModules.mm +30 -0
  179. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridge.h +19 -0
  180. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridge.m +32 -0
  181. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridgeModule.h +19 -0
  182. package/ios/RNFBAppUnitTests/HostStubs/React/RCTConvert.h +28 -0
  183. package/ios/RNFBAppUnitTests/HostStubs/React/RCTConvert.m +23 -0
  184. package/ios/RNFBAppUnitTests/HostStubs/React/RCTEventEmitter.h +9 -0
  185. package/ios/RNFBAppUnitTests/HostStubs/React/RCTInvalidating.h +24 -0
  186. package/ios/RNFBAppUnitTests/HostStubs/React/RCTUtils.h +9 -0
  187. package/ios/RNFBAppUnitTests/HostStubs/module.modulemap +13 -0
  188. package/ios/RNFBAppUnitTests/RCTConvertFIRAppFacadeTests.m +61 -0
  189. package/ios/RNFBAppUnitTests/RCTConvertFIRAppTests.swift +73 -0
  190. package/ios/RNFBAppUnitTests/RCTConvertFIROptionsFacadeTests.m +57 -0
  191. package/ios/RNFBAppUnitTests/RCTConvertFIROptionsTests.swift +243 -0
  192. package/ios/RNFBAppUnitTests/RNFBAppCustomAuthDomainsFacadeTests.m +73 -0
  193. package/ios/RNFBAppUnitTests/RNFBAppCustomAuthDomainsTests.swift +70 -0
  194. package/ios/RNFBAppUnitTests/RNFBAppInitializeOptionsMapperTests.swift +190 -0
  195. package/ios/RNFBAppUnitTests/RNFBAppLogLevelFacadeTests.m +76 -0
  196. package/ios/RNFBAppUnitTests/RNFBAppLogLevelMapperTests.swift +59 -0
  197. package/ios/RNFBAppUnitTests/RNFBAppModuleFirebaseFacadeTests.m +215 -0
  198. package/ios/RNFBAppUnitTests/RNFBAppModuleFirebaseTests.swift +430 -0
  199. package/ios/RNFBAppUnitTests/RNFBAppModuleLifecycleTests.m +206 -0
  200. package/ios/RNFBAppUnitTests/RNFBAppModuleShellTests.mm +367 -0
  201. package/ios/RNFBAppUnitTests/RNFBAppUnitTests.xcodeproj/project.pbxproj +590 -0
  202. package/ios/RNFBAppUnitTests/RNFBAppUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBAppUnitTests.xcscheme +69 -0
  203. package/ios/RNFBAppUnitTests/RNFBFirebaseAppClientTests.swift +165 -0
  204. package/ios/RNFBAppUnitTests/RNFBHandleMapStorageTests.swift +121 -0
  205. package/ios/RNFBAppUnitTests/RNFBHandleMapTests.m +238 -0
  206. package/ios/RNFBAppUnitTests/RNFBInitializeAppArgumentsTests.swift +256 -0
  207. package/ios/RNFBAppUnitTests/RNFBJSONImplementationTests.swift +126 -0
  208. package/ios/RNFBAppUnitTests/RNFBJSONTests.m +172 -0
  209. package/ios/RNFBAppUnitTests/RNFBMetaStorageTests.swift +106 -0
  210. package/ios/RNFBAppUnitTests/RNFBMetaTests.m +65 -0
  211. package/ios/RNFBAppUnitTests/RNFBNullSentinelDecodingTests.swift +286 -0
  212. package/ios/RNFBAppUnitTests/RNFBNullSentinelInterceptorTests.m +312 -0
  213. package/ios/RNFBAppUnitTests/RNFBPreferencesStorageTests.swift +105 -0
  214. package/ios/RNFBAppUnitTests/RNFBPreferencesTests.m +110 -0
  215. package/ios/RNFBAppUnitTests/RNFBRCTEventEmitterCoreTests.swift +163 -0
  216. package/ios/RNFBAppUnitTests/RNFBRCTEventEmitterFacadeTests.m +141 -0
  217. package/ios/RNFBAppUnitTests/RNFBSharedUtilsConfigFacadeTests.m +100 -0
  218. package/ios/RNFBAppUnitTests/RNFBSharedUtilsConfigTests.swift +234 -0
  219. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFIRAppFacadeTests.m +145 -0
  220. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFIRAppTests.swift +173 -0
  221. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFormattingFacadeTests.m +38 -0
  222. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFormattingTests.swift +82 -0
  223. package/ios/RNFBAppUnitTests/RNFBSharedUtilsNullSentinelTests.m +35 -0
  224. package/ios/RNFBAppUnitTests/RNFBSharedUtilsPromiseRejectionFacadeTests.m +107 -0
  225. package/ios/RNFBAppUnitTests/RNFBSharedUtilsPromiseRejectionTests.swift +133 -0
  226. package/ios/RNFBAppUnitTests/RNFBUtilsHelpersTests.swift +144 -0
  227. package/ios/RNFBAppUnitTests/RNFBUtilsModuleFacadeTests.m +72 -0
  228. package/ios/RNFBAppUnitTests/RNFBUtilsModuleShellTests.mm +282 -0
  229. package/ios/RNFBFirebase/Package.swift +53 -0
  230. package/ios/RNFBFirebase/Sources/RNFBFirebase/RNFBFirebase.swift +285 -0
  231. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/Public/.gitkeep +0 -0
  232. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/RNFBFirebaseBridge.m +169 -0
  233. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/include/RNFBFirebaseBridge.h +52 -0
  234. package/ios/RNFBFirebaseUnitTests/RNFBAppDynamicFacadeTests.swift +240 -0
  235. package/{android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppRegistrar.java → ios/RNFBFirebaseUnitTests/RNFBFirebaseClientImport.swift} +22 -17
  236. package/ios/RNFBFirebaseUnitTests/RNFBFirebaseUnitTests.xcodeproj/project.pbxproj +588 -0
  237. package/ios/RNFBFirebaseUnitTests/RNFBFirebaseUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBFirebaseUnitTests.xcscheme +83 -0
  238. package/ios_config.sh +50 -22
  239. package/lib/FirebaseApp.ts +10 -0
  240. package/lib/common/Base64.ts +10 -16
  241. package/lib/common/deeps.ts +3 -0
  242. package/lib/common/index.ts +20 -9
  243. package/lib/internal/FirebaseModule.ts +6 -3
  244. package/lib/internal/NativeModules.ts +4 -1
  245. package/lib/internal/RNFBNativeEventEmitter.ts +14 -5
  246. package/lib/internal/SharedEventEmitter.ts +5 -1
  247. package/lib/internal/asyncStorage.ts +7 -11
  248. package/lib/internal/index.ts +1 -0
  249. package/lib/internal/logger.ts +53 -43
  250. package/lib/internal/nativeModuleAndroidIos.ts +2 -40
  251. package/lib/internal/nativeModuleDebug.ts +97 -0
  252. package/lib/internal/nativeModuleWeb.ts +10 -40
  253. package/lib/internal/react-native-vendor-emitter.d.ts +11 -0
  254. package/lib/internal/registry/app.ts +8 -2
  255. package/lib/internal/registry/modular.ts +2 -2
  256. package/lib/internal/registry/nativeModule.ts +3 -3
  257. package/lib/internal/web/RNFBAppModule.ts +16 -15
  258. package/lib/internal/web/memidb/lib/FakeEventTarget.js +3 -1
  259. package/lib/types/app.ts +10 -3
  260. package/lib/types/internal.ts +19 -0
  261. package/lib/version.ts +1 -1
  262. package/package.json +9 -8
  263. package/plugin/build/ios/appDelegate.js +19 -9
  264. package/plugin/build/ios/podfile.js +16 -16
  265. package/plugin/build/pluginConfig.d.ts +4 -2
  266. package/plugin/src/ios/appDelegate.ts +45 -15
  267. package/plugin/src/ios/podfile.ts +20 -23
  268. package/plugin/src/pluginConfig.ts +4 -2
  269. package/android/src/main/java/io/invertase/firebase/common/TaskExecutorService.java +0 -124
  270. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebaseModule.java +0 -62
  271. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebasePreferences.java +0 -91
  272. package/android/src/reactnative/java/io/invertase/firebase/app/NativeRNFBTurboApp.java +0 -222
  273. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseApp.java +0 -46
  274. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackage.java +0 -49
  275. package/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.java +0 -191
  276. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEvent.java +0 -53
  277. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitter.java +0 -606
  278. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseJSON.java +0 -107
  279. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseMeta.java +0 -101
  280. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseModule.java +0 -146
  281. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebasePreferences.java +0 -96
  282. package/android/src/reactnative/java/io/invertase/firebase/common/SharedUtils.java +0 -441
  283. package/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.java +0 -223
@@ -0,0 +1,219 @@
1
+ package io.invertase.firebase.utils
2
+
3
+ /*
4
+ * Copyright (c) 2016-present Invertase Limited & Contributors
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this library except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ import android.app.Activity
21
+ import android.app.Dialog
22
+ import android.content.Context
23
+ import android.content.IntentSender
24
+ import android.os.Build
25
+ import android.os.Environment
26
+ import android.provider.Settings
27
+ import android.util.Log
28
+ import com.facebook.fbreact.specs.NativeRNFBTurboUtilsSpec
29
+ import com.facebook.react.bridge.Arguments
30
+ import com.facebook.react.bridge.Promise
31
+ import com.facebook.react.bridge.ReactApplicationContext
32
+ import com.facebook.react.bridge.UiThreadUtil
33
+ import com.facebook.react.bridge.WritableMap
34
+ import com.google.android.gms.common.ConnectionResult
35
+ import com.google.android.gms.common.GoogleApiAvailability
36
+ import io.invertase.firebase.app.ReactNativeFirebaseApp
37
+ import java.util.HashMap
38
+
39
+ open class NativeRNFBTurboUtils(
40
+ reactContext: ReactApplicationContext?,
41
+ ) : NativeRNFBTurboUtilsSpec(reactContext) {
42
+ override fun androidGetPlayServicesStatus(promise: Promise?) {
43
+ nullableAsPlatformType<Promise>(promise).resolve(playServicesStatusMap)
44
+ }
45
+
46
+ override fun androidPromptForPlayServices(promise: Promise?) {
47
+ val status = isGooglePlayServicesAvailable()
48
+ val gapi = GoogleApiAvailability.getInstance()
49
+
50
+ if (status != ConnectionResult.SUCCESS && gapi.isUserResolvableError(status)) {
51
+ val activity: Activity? = getCurrentActivity()
52
+ if (activity != null) {
53
+ nullableAsPlatformType<Dialog>(gapi.getErrorDialog(activity, status, status)).show()
54
+ }
55
+ }
56
+ nullableAsPlatformType<Promise>(promise).resolve(null)
57
+ }
58
+
59
+ override fun androidResolutionForPlayServices(promise: Promise?) {
60
+ val status = isGooglePlayServicesAvailable()
61
+ val connectionResult = ConnectionResult(status)
62
+
63
+ if (!connectionResult.isSuccess && connectionResult.hasResolution()) {
64
+ val activity: Activity? = getCurrentActivity()
65
+ if (activity != null) {
66
+ try {
67
+ connectionResult.startResolutionForResult(activity, status)
68
+ } catch (error: IntentSender.SendIntentException) {
69
+ Log.d(TAG, "resolutionForPlayServices", error)
70
+ }
71
+ }
72
+ }
73
+ nullableAsPlatformType<Promise>(promise).resolve(null)
74
+ }
75
+
76
+ override fun androidMakePlayServicesAvailable(promise: Promise?) {
77
+ val status = isGooglePlayServicesAvailable()
78
+
79
+ if (status != ConnectionResult.SUCCESS) {
80
+ UiThreadUtil.runOnUiThread {
81
+ val activity: Activity? = getCurrentActivity()
82
+ if (activity != null) {
83
+ GoogleApiAvailability
84
+ .getInstance()
85
+ .makeGooglePlayServicesAvailable(activity)
86
+ .addOnCompleteListener { task ->
87
+ if (task.isSuccessful) {
88
+ nullableAsPlatformType<Promise>(promise).resolve(null)
89
+ } else if (task.isCanceled) {
90
+ nullableAsPlatformType<Promise>(promise).reject(
91
+ "play-services-update-canceled",
92
+ "Play Services update was canceled by the user",
93
+ )
94
+ } else {
95
+ val error = task.exception
96
+ nullableAsPlatformType<Promise>(promise).reject(
97
+ "play-services-update-failed",
98
+ if (error != null) error.message else "Unknown error",
99
+ error,
100
+ )
101
+ }
102
+ }
103
+ } else {
104
+ nullableAsPlatformType<Promise>(promise).resolve(null)
105
+ }
106
+ }
107
+ } else {
108
+ nullableAsPlatformType<Promise>(promise).resolve(null)
109
+ }
110
+ }
111
+
112
+ protected override fun getTypedExportedConstants(): MutableMap<String, Any> {
113
+ val constants: MutableMap<String, Any> = HashMap()
114
+
115
+ constants["isRunningInTestLab"] = isRunningInTestLab()
116
+
117
+ val context = reactApplicationContext
118
+ val appVersion = getAppVersionName(context)
119
+ if (appVersion != null && appVersion.isNotEmpty()) {
120
+ constants["appVersion"] = appVersion
121
+ }
122
+
123
+ constants[KEY_MAIN_BUNDLE] = ""
124
+ constants[KEY_LIBRARY_DIRECTORY] = context.filesDir.absolutePath
125
+ constants[KEY_TEMP_DIRECTORY] = context.cacheDir.absolutePath
126
+ constants[KEY_CACHE_DIRECTORY] = context.cacheDir.absolutePath
127
+
128
+ val externalDirectory = context.getExternalFilesDir(null)
129
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && externalDirectory != null) {
130
+ constants[KEY_DOCUMENT_DIRECTORY] = externalDirectory.absolutePath
131
+ }
132
+
133
+ if (!constants.containsKey(KEY_DOCUMENT_DIRECTORY)) {
134
+ constants[KEY_DOCUMENT_DIRECTORY] = context.filesDir.absolutePath
135
+ }
136
+
137
+ val picturesDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
138
+ constants[KEY_PICS_DIRECTORY] =
139
+ if (picturesDirectory != null) picturesDirectory.absolutePath else ""
140
+
141
+ val moviesDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
142
+ constants[KEY_MOVIES_DIRECTORY] =
143
+ if (moviesDirectory != null) moviesDirectory.absolutePath else ""
144
+
145
+ val externalStorageDirectory = Environment.getExternalStorageDirectory()
146
+ if (externalStorageDirectory != null) {
147
+ constants[KEY_EXT_STORAGE_DIRECTORY] = externalStorageDirectory.absolutePath
148
+ }
149
+
150
+ if (externalDirectory != null) {
151
+ constants[KEY_EXTERNAL_DIRECTORY] = externalDirectory.absolutePath
152
+ }
153
+
154
+ return constants
155
+ }
156
+
157
+ private fun isGooglePlayServicesAvailable(): Int {
158
+ val gapi = GoogleApiAvailability.getInstance()
159
+ return gapi.isGooglePlayServicesAvailable(reactApplicationContext)
160
+ }
161
+
162
+ private val playServicesStatusMap: WritableMap
163
+ get() {
164
+ val result = Arguments.createMap()
165
+ val gapi = GoogleApiAvailability.getInstance()
166
+
167
+ val status = gapi.isGooglePlayServicesAvailable(reactApplicationContext)
168
+ result.putInt("status", status)
169
+
170
+ if (status == ConnectionResult.SUCCESS) {
171
+ result.putBoolean("isAvailable", true)
172
+ } else {
173
+ result.putBoolean("isAvailable", false)
174
+ result.putString("error", gapi.getErrorString(status))
175
+ result.putBoolean("isUserResolvableError", gapi.isUserResolvableError(status))
176
+ result.putBoolean("hasResolution", ConnectionResult(status).hasResolution())
177
+ }
178
+
179
+ return result
180
+ }
181
+
182
+ companion object {
183
+ private const val TAG = "Utils"
184
+ private const val KEY_MAIN_BUNDLE = "MAIN_BUNDLE"
185
+ private const val KEY_DOCUMENT_DIRECTORY = "DOCUMENT_DIRECTORY"
186
+ private const val KEY_LIBRARY_DIRECTORY = "LIBRARY_DIRECTORY"
187
+ private const val KEY_EXTERNAL_DIRECTORY = "EXTERNAL_DIRECTORY"
188
+ private const val KEY_EXT_STORAGE_DIRECTORY = "EXTERNAL_STORAGE_DIRECTORY"
189
+ private const val KEY_PICS_DIRECTORY = "PICTURES_DIRECTORY"
190
+ private const val KEY_MOVIES_DIRECTORY = "MOVIES_DIRECTORY"
191
+ private const val KEY_TEMP_DIRECTORY = "TEMP_DIRECTORY"
192
+ private const val KEY_CACHE_DIRECTORY = "CACHES_DIRECTORY"
193
+ private const val FIREBASE_TEST_LAB = "firebase.test.lab"
194
+
195
+ private fun isRunningInTestLab(): Boolean {
196
+ val testLabSetting =
197
+ Settings.System.getString(
198
+ ReactNativeFirebaseApp.getApplicationContext().contentResolver,
199
+ FIREBASE_TEST_LAB,
200
+ )
201
+
202
+ return "true" == testLabSetting
203
+ }
204
+
205
+ private fun getAppVersionName(context: Context): String? =
206
+ try {
207
+ @Suppress("DEPRECATION")
208
+ val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
209
+ packageInfo.versionName
210
+ } catch (error: Exception) {
211
+ // Optional metadata: prefer omit over crashing on null context / unexpected PM failures.
212
+ Log.d(TAG, "getAppVersionName", error)
213
+ null
214
+ }
215
+
216
+ @Suppress("UNCHECKED_CAST")
217
+ private fun <T> nullableAsPlatformType(value: T?): T = value as T
218
+ }
219
+ }
@@ -0,0 +1,9 @@
1
+ package expo.core;
2
+
3
+ /**
4
+ * Test-source-only classpath marker that makes the default SharedUtils detector see Expo. Isolated
5
+ * class loaders in SharedUtilsJavaCompatibilityTest explicitly hide it for non-Expo cases.
6
+ */
7
+ public final class ModuleRegistry {
8
+ private ModuleRegistry() {}
9
+ }
@@ -20,10 +20,16 @@ package io.invertase.firebase.app;
20
20
  import static org.junit.Assert.assertEquals;
21
21
  import static org.junit.Assert.assertFalse;
22
22
  import static org.junit.Assert.assertNull;
23
+ import static org.junit.Assert.assertSame;
24
+ import static org.junit.Assert.assertThrows;
23
25
  import static org.junit.Assert.assertTrue;
26
+ import static org.mockito.ArgumentMatchers.any;
27
+ import static org.mockito.ArgumentMatchers.anyMap;
28
+ import static org.mockito.ArgumentMatchers.eq;
24
29
  import static org.mockito.Mockito.mock;
25
30
  import static org.mockito.Mockito.mockStatic;
26
31
  import static org.mockito.Mockito.verify;
32
+ import static org.mockito.Mockito.verifyNoInteractions;
27
33
  import static org.mockito.Mockito.when;
28
34
 
29
35
  import android.app.Application;
@@ -37,19 +43,22 @@ import com.facebook.react.bridge.ReactContext;
37
43
  import com.facebook.react.bridge.ReadableMap;
38
44
  import com.facebook.react.bridge.WritableMap;
39
45
  import com.google.firebase.FirebaseApp;
46
+ import com.google.firebase.FirebaseOptions;
40
47
  import io.invertase.firebase.common.RCTConvertFirebase;
41
48
  import io.invertase.firebase.common.ReactNativeFirebaseEventEmitter;
42
49
  import io.invertase.firebase.common.ReactNativeFirebaseJSON;
43
- import io.invertase.firebase.common.ReactNativeFirebaseMeta;
44
50
  import io.invertase.firebase.common.ReactNativeFirebasePreferences;
51
+ import io.invertase.firebase.interfaces.NativeEvent;
45
52
  import java.lang.ref.WeakReference;
46
53
  import java.lang.reflect.Constructor;
47
54
  import java.lang.reflect.Field;
48
55
  import java.lang.reflect.Method;
56
+ import java.lang.reflect.Modifier;
57
+ import java.lang.reflect.ParameterizedType;
49
58
  import java.util.Collections;
50
- import java.util.HashMap;
51
59
  import java.util.List;
52
60
  import java.util.Map;
61
+ import java.util.concurrent.ConcurrentHashMap;
53
62
  import org.junit.Before;
54
63
  import org.junit.Test;
55
64
  import org.junit.runner.RunWith;
@@ -63,7 +72,7 @@ import org.robolectric.shadows.ShadowLooper;
63
72
  * preferences bridges.
64
73
  */
65
74
  @RunWith(RobolectricTestRunner.class)
66
- @Config(sdk = 34, application = NativeRNFBTurboAppTest.HostApplication.class)
75
+ @Config(application = NativeRNFBTurboAppTest.HostApplication.class)
67
76
  public class NativeRNFBTurboAppTest {
68
77
 
69
78
  public static class HostApplication extends Application implements ReactApplication {
@@ -95,10 +104,57 @@ public class NativeRNFBTurboAppTest {
95
104
  when(reactContext.hasActiveReactInstance()).thenReturn(true);
96
105
  when(reactHost.getCurrentReactContext()).thenReturn(reactContext);
97
106
 
107
+ ReactNativeFirebaseApp.setApplicationContext(application);
98
108
  NativeRNFBTurboApp.authDomains.clear();
109
+ ReactNativeFirebasePreferences.getSharedInstance().clearAll();
99
110
  resetEmitterSharedInstance();
100
111
  }
101
112
 
113
+ @Test
114
+ public void javaAbi_preservesClassConstructorAndStaticAuthDomainSurface() throws Exception {
115
+ assertTrue(Modifier.isPublic(NativeRNFBTurboApp.class.getModifiers()));
116
+ assertFalse(Modifier.isFinal(NativeRNFBTurboApp.class.getModifiers()));
117
+ assertEquals(
118
+ com.facebook.fbreact.specs.NativeRNFBTurboAppSpec.class,
119
+ NativeRNFBTurboApp.class.getSuperclass());
120
+ assertTrue(
121
+ com.facebook.react.bridge.LifecycleEventListener.class.isAssignableFrom(
122
+ NativeRNFBTurboApp.class));
123
+
124
+ Constructor<NativeRNFBTurboApp> constructor =
125
+ NativeRNFBTurboApp.class.getDeclaredConstructor(ReactApplicationContext.class);
126
+ // Kotlin cannot emit package-private. Protected is the closest JVM visibility: it preserves
127
+ // construction from same-package Java (as every `new` in this class proves) without making the
128
+ // constructor public; the internal companion invoke serves same-module Kotlin registration.
129
+ assertTrue(Modifier.isProtected(constructor.getModifiers()));
130
+ assertFalse(Modifier.isPublic(constructor.getModifiers()));
131
+
132
+ Field field = NativeRNFBTurboApp.class.getDeclaredField("authDomains");
133
+ assertTrue(Modifier.isPublic(field.getModifiers()));
134
+ assertTrue(Modifier.isStatic(field.getModifiers()));
135
+ assertTrue(Modifier.isFinal(field.getModifiers()));
136
+ assertEquals(Map.class, field.getType());
137
+ ParameterizedType fieldType = (ParameterizedType) field.getGenericType();
138
+ assertEquals(String.class, fieldType.getActualTypeArguments()[0]);
139
+ assertEquals(String.class, fieldType.getActualTypeArguments()[1]);
140
+ assertTrue(field.get(null) instanceof ConcurrentHashMap);
141
+ assertSame(NativeRNFBTurboApp.authDomains, field.get(null));
142
+
143
+ Method configure =
144
+ NativeRNFBTurboApp.class.getDeclaredMethod(
145
+ "configureAuthDomain", String.class, String.class);
146
+ assertTrue(Modifier.isPublic(configure.getModifiers()));
147
+ assertTrue(Modifier.isStatic(configure.getModifiers()));
148
+ assertEquals(void.class, configure.getReturnType());
149
+ }
150
+
151
+ @Test
152
+ public void javaNullCalls_doNotGainKotlinBoundaryChecks() {
153
+ NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
154
+ module.addListener(null);
155
+ module.setLogLevel(null);
156
+ }
157
+
102
158
  @Test
103
159
  public void initialize_registersLifecycleListenerAndAttachesEmitter() throws Exception {
104
160
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
@@ -140,21 +196,14 @@ public class NativeRNFBTurboAppTest {
140
196
  @Test
141
197
  public void getTypedExportedConstants_includesAppsAndRawJson() throws Exception {
142
198
  FirebaseApp firebaseApp = mock(FirebaseApp.class);
143
- Map<String, Object> appMap = new HashMap<>();
144
- appMap.put("name", "[DEFAULT]");
199
+ FirebaseOptions options = mock(FirebaseOptions.class);
200
+ when(firebaseApp.getName()).thenReturn("[DEFAULT]");
201
+ when(firebaseApp.getOptions()).thenReturn(options);
145
202
 
146
- try (MockedStatic<FirebaseApp> firebaseApps = mockStatic(FirebaseApp.class);
147
- MockedStatic<RCTConvertFirebase> convert = mockStatic(RCTConvertFirebase.class);
148
- MockedStatic<ReactNativeFirebaseJSON> jsonStatic =
149
- mockStatic(ReactNativeFirebaseJSON.class)) {
203
+ try (MockedStatic<FirebaseApp> firebaseApps = mockStatic(FirebaseApp.class)) {
150
204
  firebaseApps
151
205
  .when(() -> FirebaseApp.getApps(reactContext))
152
206
  .thenReturn(Collections.singletonList(firebaseApp));
153
- convert.when(() -> RCTConvertFirebase.firebaseAppToMap(firebaseApp)).thenReturn(appMap);
154
-
155
- ReactNativeFirebaseJSON json = mock(ReactNativeFirebaseJSON.class);
156
- jsonStatic.when(ReactNativeFirebaseJSON::getSharedInstance).thenReturn(json);
157
- when(json.getRawJSON()).thenReturn("{}");
158
207
 
159
208
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
160
209
  Method method = NativeRNFBTurboApp.class.getDeclaredMethod("getTypedExportedConstants");
@@ -162,12 +211,16 @@ public class NativeRNFBTurboAppTest {
162
211
  @SuppressWarnings("unchecked")
163
212
  Map<String, Object> constants = (Map<String, Object>) method.invoke(module);
164
213
 
165
- assertEquals("{}", constants.get("FIREBASE_RAW_JSON"));
214
+ assertEquals(
215
+ ReactNativeFirebaseJSON.getSharedInstance().getRawJSON(),
216
+ constants.get("FIREBASE_RAW_JSON"));
166
217
  @SuppressWarnings("unchecked")
167
218
  List<Map<String, Object>> apps =
168
219
  (List<Map<String, Object>>) constants.get("NATIVE_FIREBASE_APPS");
169
220
  assertEquals(1, apps.size());
170
- assertEquals("[DEFAULT]", apps.get(0).get("name"));
221
+ @SuppressWarnings("unchecked")
222
+ Map<String, Object> appConfig = (Map<String, Object>) apps.get(0).get("appConfig");
223
+ assertEquals("[DEFAULT]", appConfig.get("name"));
171
224
  }
172
225
  }
173
226
 
@@ -177,24 +230,33 @@ public class NativeRNFBTurboAppTest {
177
230
  ReadableMap appConfig = mock(ReadableMap.class);
178
231
  Promise promise = mock(Promise.class);
179
232
  FirebaseApp firebaseApp = mock(FirebaseApp.class);
180
- WritableMap writableMap = mock(WritableMap.class);
233
+ FirebaseOptions firebaseOptions = mock(FirebaseOptions.class);
181
234
 
182
235
  when(appConfig.getString("name")).thenReturn("secondary");
236
+ when(options.getString("apiKey")).thenReturn("api-key");
237
+ when(options.getString("appId")).thenReturn("app-id");
183
238
  when(options.getString("authDomain")).thenReturn("example.firebaseapp.com");
239
+ when(firebaseApp.getName()).thenReturn("secondary");
240
+ when(firebaseApp.getOptions()).thenReturn(firebaseOptions);
184
241
 
185
- try (MockedStatic<RCTConvertFirebase> convert = mockStatic(RCTConvertFirebase.class)) {
186
- convert
187
- .when(() -> RCTConvertFirebase.readableMapToFirebaseApp(options, appConfig, reactContext))
242
+ try (MockedStatic<FirebaseApp> firebaseApps = mockStatic(FirebaseApp.class);
243
+ MockedStatic<Arguments> arguments = mockStatic(Arguments.class)) {
244
+ firebaseApps
245
+ .when(
246
+ () ->
247
+ FirebaseApp.initializeApp(
248
+ eq(reactContext), any(FirebaseOptions.class), eq("secondary")))
188
249
  .thenReturn(firebaseApp);
189
- convert
190
- .when(() -> RCTConvertFirebase.firebaseAppToWritableMap(firebaseApp))
191
- .thenReturn(writableMap);
192
-
193
250
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
194
251
  module.initializeApp(options, appConfig, promise);
195
252
 
196
253
  assertEquals("example.firebaseapp.com", NativeRNFBTurboApp.authDomains.get("secondary"));
197
- verify(promise).resolve(writableMap);
254
+ firebaseApps.verify(
255
+ () ->
256
+ FirebaseApp.initializeApp(
257
+ eq(reactContext), any(FirebaseOptions.class), eq("secondary")));
258
+ arguments.verify(() -> Arguments.makeNativeMap(anyMap()));
259
+ verify(promise).resolve(null);
198
260
  }
199
261
  }
200
262
 
@@ -206,15 +268,53 @@ public class NativeRNFBTurboAppTest {
206
268
  assertFalse(NativeRNFBTurboApp.authDomains.containsKey("secondary"));
207
269
  }
208
270
 
271
+ @Test
272
+ public void configureAuthDomain_preservesConcurrentHashMapNullKeyFailures() {
273
+ assertThrows(
274
+ NullPointerException.class,
275
+ () -> NativeRNFBTurboApp.configureAuthDomain(null, "example.firebaseapp.com"));
276
+ assertThrows(
277
+ NullPointerException.class, () -> NativeRNFBTurboApp.configureAuthDomain(null, null));
278
+ }
279
+
280
+ @Test
281
+ public void firebaseAppToMap_includesOnlyConfiguredAuthDomain() {
282
+ FirebaseApp firebaseApp = mock(FirebaseApp.class);
283
+ FirebaseOptions options = mock(FirebaseOptions.class);
284
+ when(firebaseApp.getName()).thenReturn("secondary");
285
+ when(firebaseApp.getOptions()).thenReturn(options);
286
+
287
+ NativeRNFBTurboApp.configureAuthDomain("secondary", "example.firebaseapp.com");
288
+ Map<String, Object> appWithAuthDomain = RCTConvertFirebase.firebaseAppToMap(firebaseApp);
289
+ @SuppressWarnings("unchecked")
290
+ Map<String, Object> optionsWithAuthDomain =
291
+ (Map<String, Object>) appWithAuthDomain.get("options");
292
+ assertEquals("example.firebaseapp.com", optionsWithAuthDomain.get("authDomain"));
293
+
294
+ NativeRNFBTurboApp.configureAuthDomain("secondary", null);
295
+ Map<String, Object> appWithoutAuthDomain = RCTConvertFirebase.firebaseAppToMap(firebaseApp);
296
+ @SuppressWarnings("unchecked")
297
+ Map<String, Object> optionsWithoutAuthDomain =
298
+ (Map<String, Object>) appWithoutAuthDomain.get("options");
299
+ assertFalse(optionsWithoutAuthDomain.containsKey("authDomain"));
300
+ }
301
+
209
302
  @Test
210
303
  public void setAutomaticDataCollectionEnabled_delegatesToFirebaseApp() {
211
304
  FirebaseApp firebaseApp = mock(FirebaseApp.class);
212
305
  try (MockedStatic<FirebaseApp> firebaseApps = mockStatic(FirebaseApp.class)) {
213
- firebaseApps.when(() -> FirebaseApp.getInstance("secondary")).thenReturn(firebaseApp);
306
+ firebaseApps
307
+ .when(() -> FirebaseApp.getInstance((String) null))
308
+ .thenAnswer(
309
+ invocation -> {
310
+ assertNull(invocation.getArgument(0));
311
+ return firebaseApp;
312
+ });
214
313
 
215
314
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
216
- module.setAutomaticDataCollectionEnabled("secondary", true);
315
+ module.setAutomaticDataCollectionEnabled(null, true);
217
316
 
317
+ firebaseApps.verify(() -> FirebaseApp.getInstance((String) null));
218
318
  verify(firebaseApp).setDataCollectionDefaultEnabled(true);
219
319
  }
220
320
  }
@@ -223,6 +323,7 @@ public class NativeRNFBTurboAppTest {
223
323
  public void deleteApp_deletesWhenInstancePresent() {
224
324
  FirebaseApp firebaseApp = mock(FirebaseApp.class);
225
325
  Promise promise = mock(Promise.class);
326
+ NativeRNFBTurboApp.configureAuthDomain("secondary", "example.firebaseapp.com");
226
327
  try (MockedStatic<FirebaseApp> firebaseApps = mockStatic(FirebaseApp.class)) {
227
328
  firebaseApps.when(() -> FirebaseApp.getInstance("secondary")).thenReturn(firebaseApp);
228
329
 
@@ -230,6 +331,7 @@ public class NativeRNFBTurboAppTest {
230
331
  module.deleteApp("secondary", promise);
231
332
 
232
333
  verify(firebaseApp).delete();
334
+ assertFalse(NativeRNFBTurboApp.authDomains.containsKey("secondary"));
233
335
  verify(promise).resolve(null);
234
336
  }
235
337
  }
@@ -244,6 +346,22 @@ public class NativeRNFBTurboAppTest {
244
346
  module.deleteApp("missing", promise);
245
347
 
246
348
  verify(promise).resolve(null);
349
+
350
+ RuntimeException fromFirebase = new RuntimeException("from FirebaseApp.getInstance");
351
+ firebaseApps
352
+ .when(() -> FirebaseApp.getInstance((String) null))
353
+ .thenAnswer(
354
+ invocation -> {
355
+ assertNull(invocation.getArgument(0));
356
+ throw fromFirebase;
357
+ });
358
+ Promise nullNamePromise = mock(Promise.class);
359
+
360
+ assertSame(
361
+ fromFirebase,
362
+ assertThrows(RuntimeException.class, () -> module.deleteApp(null, nullNamePromise)));
363
+ firebaseApps.verify(() -> FirebaseApp.getInstance((String) null));
364
+ verifyNoInteractions(nullNamePromise);
247
365
  }
248
366
  }
249
367
 
@@ -273,18 +391,39 @@ public class NativeRNFBTurboAppTest {
273
391
  }
274
392
 
275
393
  @Test
276
- public void eventsPing_sendsEventAndResolvesBody() {
394
+ public void eventsPing_sendsEventAndResolvesBody() throws Exception {
277
395
  ReadableMap body = mock(ReadableMap.class);
278
- WritableMap writable = mock(WritableMap.class);
396
+ WritableMap eventWritable = mock(WritableMap.class);
397
+ WritableMap resolvedWritable = mock(WritableMap.class);
398
+ WritableMap nullNameWritable = mock(WritableMap.class);
279
399
  Promise promise = mock(Promise.class);
280
400
 
281
- try (MockedStatic<RCTConvertFirebase> convert = mockStatic(RCTConvertFirebase.class)) {
282
- convert.when(() -> RCTConvertFirebase.readableMapToWritableMap(body)).thenReturn(writable);
401
+ try (MockedStatic<Arguments> arguments = mockStatic(Arguments.class)) {
402
+ arguments
403
+ .when(Arguments::createMap)
404
+ .thenReturn(eventWritable, resolvedWritable, nullNameWritable);
283
405
 
284
406
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
285
407
  module.eventsPing("ping_event", body, promise);
408
+ ShadowLooper.idleMainLooper();
286
409
 
287
- verify(promise).resolve(writable);
410
+ verify(eventWritable).merge(body);
411
+ verify(resolvedWritable).merge(body);
412
+ verify(promise).resolve(resolvedWritable);
413
+ @SuppressWarnings("unchecked")
414
+ List<NativeEvent> queuedEvents =
415
+ (List<NativeEvent>)
416
+ getEmitterField("queuedEvents")
417
+ .get(ReactNativeFirebaseEventEmitter.getSharedInstance());
418
+ assertEquals(1, queuedEvents.size());
419
+ assertEquals("ping_event", queuedEvents.get(0).getEventName());
420
+ assertSame(eventWritable, queuedEvents.get(0).getEventBody());
421
+
422
+ Promise nullNamePromise = mock(Promise.class);
423
+ assertThrows(
424
+ NullPointerException.class, () -> module.eventsPing(null, body, nullNamePromise));
425
+ verify(nullNameWritable).merge(body);
426
+ verifyNoInteractions(nullNamePromise);
288
427
  }
289
428
  }
290
429
 
@@ -316,12 +455,9 @@ public class NativeRNFBTurboAppTest {
316
455
  public void metaGetAll_resolvesMetaSingleton() {
317
456
  Promise promise = mock(Promise.class);
318
457
  WritableMap all = mock(WritableMap.class);
319
- ReactNativeFirebaseMeta meta = mock(ReactNativeFirebaseMeta.class);
320
- when(meta.getAll()).thenReturn(all);
321
458
 
322
- try (MockedStatic<ReactNativeFirebaseMeta> metaStatic =
323
- mockStatic(ReactNativeFirebaseMeta.class)) {
324
- metaStatic.when(ReactNativeFirebaseMeta::getSharedInstance).thenReturn(meta);
459
+ try (MockedStatic<Arguments> arguments = mockStatic(Arguments.class)) {
460
+ arguments.when(Arguments::createMap).thenReturn(all);
325
461
 
326
462
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
327
463
  module.metaGetAll(promise);
@@ -333,12 +469,9 @@ public class NativeRNFBTurboAppTest {
333
469
  public void jsonGetAll_resolvesJsonSingleton() {
334
470
  Promise promise = mock(Promise.class);
335
471
  WritableMap all = mock(WritableMap.class);
336
- ReactNativeFirebaseJSON json = mock(ReactNativeFirebaseJSON.class);
337
- when(json.getAll()).thenReturn(all);
338
472
 
339
- try (MockedStatic<ReactNativeFirebaseJSON> jsonStatic =
340
- mockStatic(ReactNativeFirebaseJSON.class)) {
341
- jsonStatic.when(ReactNativeFirebaseJSON::getSharedInstance).thenReturn(json);
473
+ try (MockedStatic<Arguments> arguments = mockStatic(Arguments.class)) {
474
+ arguments.when(Arguments::createMap).thenReturn(all);
342
475
 
343
476
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
344
477
  module.jsonGetAll(promise);
@@ -348,28 +481,37 @@ public class NativeRNFBTurboAppTest {
348
481
 
349
482
  @Test
350
483
  public void preferencesSettersAndGetters_delegateToPreferencesSingleton() {
351
- Promise promise = mock(Promise.class);
484
+ Promise boolPromise = mock(Promise.class);
485
+ Promise stringPromise = mock(Promise.class);
486
+ Promise getPromise = mock(Promise.class);
487
+ Promise clearPromise = mock(Promise.class);
352
488
  WritableMap all = mock(WritableMap.class);
353
- ReactNativeFirebasePreferences prefs = mock(ReactNativeFirebasePreferences.class);
354
- when(prefs.getAll()).thenReturn(all);
355
489
 
356
- try (MockedStatic<ReactNativeFirebasePreferences> prefsStatic =
357
- mockStatic(ReactNativeFirebasePreferences.class)) {
358
- prefsStatic.when(ReactNativeFirebasePreferences::getSharedInstance).thenReturn(prefs);
490
+ try (MockedStatic<Arguments> arguments = mockStatic(Arguments.class)) {
491
+ arguments.when(Arguments::createMap).thenReturn(all);
359
492
 
360
493
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
361
- module.preferencesSetBool("k", true, promise);
362
- verify(prefs).setBooleanValue("k", true);
363
- verify(promise).resolve(null);
364
-
365
- module.preferencesSetString("k", "v", promise);
366
- verify(prefs).setStringValue("k", "v");
367
-
368
- module.preferencesGetAll(promise);
369
- verify(promise).resolve(all);
370
-
371
- module.preferencesClearAll(promise);
372
- verify(prefs).clearAll();
494
+ module.preferencesSetBool("bool", true, boolPromise);
495
+ assertTrue(ReactNativeFirebasePreferences.getSharedInstance().getBooleanValue("bool", false));
496
+ verify(boolPromise).resolve(null);
497
+
498
+ assertThrows(
499
+ NullPointerException.class, () -> module.preferencesSetBool("nullPromise", true, null));
500
+ assertTrue(
501
+ ReactNativeFirebasePreferences.getSharedInstance().getBooleanValue("nullPromise", false));
502
+
503
+ module.preferencesSetString("string", "v", stringPromise);
504
+ assertEquals(
505
+ "v", ReactNativeFirebasePreferences.getSharedInstance().getStringValue("string", null));
506
+ verify(stringPromise).resolve(null);
507
+
508
+ module.preferencesGetAll(getPromise);
509
+ verify(getPromise).resolve(all);
510
+
511
+ module.preferencesClearAll(clearPromise);
512
+ assertFalse(ReactNativeFirebasePreferences.getSharedInstance().contains("bool"));
513
+ assertFalse(ReactNativeFirebasePreferences.getSharedInstance().contains("string"));
514
+ verify(clearPromise).resolve(null);
373
515
  }
374
516
  }
375
517
 
@@ -389,6 +531,12 @@ public class NativeRNFBTurboAppTest {
389
531
  shared.set(null, fresh);
390
532
  }
391
533
 
534
+ private static Field getEmitterField(String name) throws Exception {
535
+ Field field = ReactNativeFirebaseEventEmitter.class.getDeclaredField(name);
536
+ field.setAccessible(true);
537
+ return field;
538
+ }
539
+
392
540
  @SuppressWarnings("unchecked")
393
541
  private static ReactContext attachedContext() throws Exception {
394
542
  ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance();