@react-native-firebase/app 26.4.0 → 27.1.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 (242) hide show
  1. package/CHANGELOG.md +62 -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 +182 -59
  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 +143 -12
  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 -21
  58. package/dist/module/FirebaseApp.js +10 -0
  59. package/dist/module/FirebaseApp.js.map +1 -1
  60. package/dist/module/common/deeps.js +3 -0
  61. package/dist/module/common/deeps.js.map +1 -1
  62. package/dist/module/internal/FirebaseModule.js.map +1 -1
  63. package/dist/module/internal/RNFBNativeEventEmitter.js +12 -1
  64. package/dist/module/internal/RNFBNativeEventEmitter.js.map +1 -1
  65. package/dist/module/internal/SharedEventEmitter.js +3 -1
  66. package/dist/module/internal/SharedEventEmitter.js.map +1 -1
  67. package/dist/module/internal/index.js +1 -0
  68. package/dist/module/internal/index.js.map +1 -1
  69. package/dist/module/internal/registry/app.js +7 -1
  70. package/dist/module/internal/registry/app.js.map +1 -1
  71. package/dist/module/types/app.js.map +1 -1
  72. package/dist/module/types/internal.js +2 -0
  73. package/dist/module/version.js +1 -1
  74. package/dist/typescript/lib/FirebaseApp.d.ts +7 -0
  75. package/dist/typescript/lib/FirebaseApp.d.ts.map +1 -1
  76. package/dist/typescript/lib/common/deeps.d.ts.map +1 -1
  77. package/dist/typescript/lib/internal/FirebaseModule.d.ts +2 -3
  78. package/dist/typescript/lib/internal/FirebaseModule.d.ts.map +1 -1
  79. package/dist/typescript/lib/internal/NativeModules.d.ts +4 -1
  80. package/dist/typescript/lib/internal/NativeModules.d.ts.map +1 -1
  81. package/dist/typescript/lib/internal/RNFBNativeEventEmitter.d.ts +2 -2
  82. package/dist/typescript/lib/internal/RNFBNativeEventEmitter.d.ts.map +1 -1
  83. package/dist/typescript/lib/internal/SharedEventEmitter.d.ts +3 -3
  84. package/dist/typescript/lib/internal/SharedEventEmitter.d.ts.map +1 -1
  85. package/dist/typescript/lib/internal/index.d.ts +1 -0
  86. package/dist/typescript/lib/internal/index.d.ts.map +1 -1
  87. package/dist/typescript/lib/internal/registry/app.d.ts.map +1 -1
  88. package/dist/typescript/lib/types/app.d.ts +10 -3
  89. package/dist/typescript/lib/types/app.d.ts.map +1 -1
  90. package/dist/typescript/lib/types/internal.d.ts +12 -0
  91. package/dist/typescript/lib/types/internal.d.ts.map +1 -1
  92. package/dist/typescript/lib/version.d.ts +1 -1
  93. package/firebase-schema.json +4 -0
  94. package/firebase_spm.rb +552 -96
  95. package/ios/RNFBApp/RCTConvert+FIRApp.h +2 -5
  96. package/ios/RNFBApp/RCTConvert+FIRApp.m +11 -6
  97. package/ios/RNFBApp/RCTConvert+FIROptions.h +2 -5
  98. package/ios/RNFBApp/RCTConvert+FIROptions.m +11 -10
  99. package/ios/RNFBApp/RCTConvertFIRApp.swift +86 -0
  100. package/ios/RNFBApp/RCTConvertFIROptions.swift +259 -0
  101. package/ios/RNFBApp/RNFBAppCustomAuthDomains.swift +63 -0
  102. package/ios/RNFBApp/RNFBAppInitializeOptionsMapper.swift +113 -0
  103. package/ios/RNFBApp/RNFBAppLogLevelMapper.swift +53 -0
  104. package/ios/RNFBApp/RNFBAppModule+CustomAuthDomain.m +35 -0
  105. package/ios/RNFBApp/RNFBAppModule.h +6 -2
  106. package/ios/RNFBApp/RNFBAppModule.mm +65 -228
  107. package/ios/RNFBApp/RNFBAppModuleFirebase.swift +439 -0
  108. package/ios/RNFBApp/RNFBAppModuleImplementation.h +68 -0
  109. package/ios/RNFBApp/RNFBAppModuleImplementation.m +195 -0
  110. package/ios/RNFBApp/RNFBHandleMap.m +27 -56
  111. package/ios/RNFBApp/RNFBHandleMapStorage.swift +90 -0
  112. package/ios/RNFBApp/RNFBInitializeAppArguments.swift +82 -0
  113. package/ios/RNFBApp/RNFBJSON.m +22 -38
  114. package/ios/RNFBApp/RNFBJSONImplementation.swift +71 -0
  115. package/ios/RNFBApp/RNFBMeta.m +24 -26
  116. package/ios/RNFBApp/RNFBMetaStorage.swift +76 -0
  117. package/ios/RNFBApp/RNFBNullSentinelDecoding.swift +135 -0
  118. package/ios/RNFBApp/RNFBNullSentinelInterceptor.h +30 -3
  119. package/ios/RNFBApp/RNFBNullSentinelInterceptor.m +28 -5
  120. package/ios/RNFBApp/RNFBPreferences.m +22 -20
  121. package/ios/RNFBApp/RNFBPreferencesStorage.swift +101 -0
  122. package/ios/RNFBApp/RNFBRCTEventEmitter.m +36 -93
  123. package/ios/RNFBApp/RNFBRCTEventEmitterCore.swift +161 -0
  124. package/ios/RNFBApp/RNFBSharedUtils.h +2 -5
  125. package/ios/RNFBApp/RNFBSharedUtils.m +109 -198
  126. package/ios/RNFBApp/RNFBSharedUtilsConfig.swift +72 -0
  127. package/ios/RNFBApp/RNFBSharedUtilsFIRApp.swift +271 -0
  128. package/ios/RNFBApp/RNFBSharedUtilsFormatting.swift +59 -0
  129. package/ios/RNFBApp/RNFBSharedUtilsPromiseRejection.swift +88 -0
  130. package/ios/RNFBApp/RNFBUtilsHelpers.swift +116 -0
  131. package/ios/RNFBApp/RNFBUtilsModule+Foundation.m +44 -0
  132. package/ios/RNFBApp/RNFBUtilsModule+PhotoAssets.m +47 -0
  133. package/ios/RNFBApp/RNFBUtilsModule.h +11 -1
  134. package/ios/RNFBApp/RNFBUtilsModule.mm +10 -85
  135. package/ios/RNFBApp/RNFBUtilsModuleImplementation.h +32 -0
  136. package/ios/RNFBApp/RNFBUtilsModuleImplementation.m +56 -0
  137. package/ios/RNFBApp/RNFBVersion.m +1 -1
  138. package/ios/RNFBApp.xcodeproj/project.pbxproj +100 -0
  139. package/ios/RNFBAppUnitTests/HostStubs/FirebaseCore/FIRApp.m +171 -0
  140. package/ios/RNFBAppUnitTests/HostStubs/FirebaseCore/FirebaseCore.h +78 -0
  141. package/ios/RNFBAppUnitTests/HostStubs/FirebaseInstallations/FIRInstallations.m +7 -0
  142. package/ios/RNFBAppUnitTests/HostStubs/FirebaseInstallations/FirebaseInstallations.h +8 -0
  143. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppModuleHostStub.m +55 -0
  144. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppTurboModules.h +89 -0
  145. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppTurboModules.mm +30 -0
  146. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridge.h +19 -0
  147. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridge.m +32 -0
  148. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridgeModule.h +19 -0
  149. package/ios/RNFBAppUnitTests/HostStubs/React/RCTConvert.h +28 -0
  150. package/ios/RNFBAppUnitTests/HostStubs/React/RCTConvert.m +23 -0
  151. package/ios/RNFBAppUnitTests/HostStubs/React/RCTEventEmitter.h +9 -0
  152. package/ios/RNFBAppUnitTests/HostStubs/React/RCTInvalidating.h +24 -0
  153. package/ios/RNFBAppUnitTests/HostStubs/React/RCTUtils.h +9 -0
  154. package/ios/RNFBAppUnitTests/HostStubs/module.modulemap +13 -0
  155. package/ios/RNFBAppUnitTests/RCTConvertFIRAppFacadeTests.m +61 -0
  156. package/ios/RNFBAppUnitTests/RCTConvertFIRAppTests.swift +73 -0
  157. package/ios/RNFBAppUnitTests/RCTConvertFIROptionsFacadeTests.m +57 -0
  158. package/ios/RNFBAppUnitTests/RCTConvertFIROptionsTests.swift +243 -0
  159. package/ios/RNFBAppUnitTests/RNFBAppCustomAuthDomainsFacadeTests.m +73 -0
  160. package/ios/RNFBAppUnitTests/RNFBAppCustomAuthDomainsTests.swift +70 -0
  161. package/ios/RNFBAppUnitTests/RNFBAppInitializeOptionsMapperTests.swift +190 -0
  162. package/ios/RNFBAppUnitTests/RNFBAppLogLevelFacadeTests.m +76 -0
  163. package/ios/RNFBAppUnitTests/RNFBAppLogLevelMapperTests.swift +59 -0
  164. package/ios/RNFBAppUnitTests/RNFBAppModuleFirebaseFacadeTests.m +215 -0
  165. package/ios/RNFBAppUnitTests/RNFBAppModuleFirebaseTests.swift +430 -0
  166. package/ios/RNFBAppUnitTests/RNFBAppModuleLifecycleTests.m +206 -0
  167. package/ios/RNFBAppUnitTests/RNFBAppModuleShellTests.mm +367 -0
  168. package/ios/RNFBAppUnitTests/RNFBAppUnitTests.xcodeproj/project.pbxproj +355 -2
  169. package/ios/RNFBAppUnitTests/RNFBFirebaseAppClientTests.swift +165 -0
  170. package/ios/RNFBAppUnitTests/RNFBHandleMapStorageTests.swift +121 -0
  171. package/ios/RNFBAppUnitTests/RNFBInitializeAppArgumentsTests.swift +256 -0
  172. package/ios/RNFBAppUnitTests/RNFBJSONImplementationTests.swift +126 -0
  173. package/ios/RNFBAppUnitTests/RNFBJSONTests.m +172 -0
  174. package/ios/RNFBAppUnitTests/RNFBMetaStorageTests.swift +106 -0
  175. package/ios/RNFBAppUnitTests/RNFBMetaTests.m +65 -0
  176. package/ios/RNFBAppUnitTests/RNFBNullSentinelDecodingTests.swift +286 -0
  177. package/ios/RNFBAppUnitTests/RNFBNullSentinelInterceptorTests.m +312 -0
  178. package/ios/RNFBAppUnitTests/RNFBPreferencesStorageTests.swift +105 -0
  179. package/ios/RNFBAppUnitTests/RNFBPreferencesTests.m +110 -0
  180. package/ios/RNFBAppUnitTests/RNFBRCTEventEmitterCoreTests.swift +163 -0
  181. package/ios/RNFBAppUnitTests/RNFBRCTEventEmitterFacadeTests.m +141 -0
  182. package/ios/RNFBAppUnitTests/RNFBSharedUtilsConfigFacadeTests.m +100 -0
  183. package/ios/RNFBAppUnitTests/RNFBSharedUtilsConfigTests.swift +234 -0
  184. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFIRAppFacadeTests.m +145 -0
  185. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFIRAppTests.swift +173 -0
  186. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFormattingFacadeTests.m +38 -0
  187. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFormattingTests.swift +82 -0
  188. package/ios/RNFBAppUnitTests/RNFBSharedUtilsNullSentinelTests.m +35 -0
  189. package/ios/RNFBAppUnitTests/RNFBSharedUtilsPromiseRejectionFacadeTests.m +107 -0
  190. package/ios/RNFBAppUnitTests/RNFBSharedUtilsPromiseRejectionTests.swift +133 -0
  191. package/ios/RNFBAppUnitTests/RNFBUtilsHelpersTests.swift +144 -0
  192. package/ios/RNFBAppUnitTests/RNFBUtilsModuleFacadeTests.m +72 -0
  193. package/ios/RNFBAppUnitTests/RNFBUtilsModuleShellTests.mm +282 -0
  194. package/ios/RNFBFirebase/Package.swift +53 -0
  195. package/ios/RNFBFirebase/Sources/RNFBFirebase/RNFBFirebase.swift +285 -0
  196. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/Public/.gitkeep +0 -0
  197. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/RNFBFirebaseBridge.m +169 -0
  198. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/include/RNFBFirebaseBridge.h +52 -0
  199. package/ios/RNFBFirebaseUnitTests/RNFBAppDynamicFacadeTests.swift +240 -0
  200. package/{android/src/main/java/io/invertase/firebase/common/RNFBHandleCollisionException.java → ios/RNFBFirebaseUnitTests/RNFBFirebaseClientImport.swift} +23 -14
  201. package/ios/RNFBFirebaseUnitTests/RNFBFirebaseUnitTests.xcodeproj/project.pbxproj +588 -0
  202. package/ios/RNFBFirebaseUnitTests/RNFBFirebaseUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBFirebaseUnitTests.xcscheme +83 -0
  203. package/ios_config.sh +50 -22
  204. package/lib/FirebaseApp.ts +10 -0
  205. package/lib/common/deeps.ts +3 -0
  206. package/lib/internal/FirebaseModule.ts +6 -3
  207. package/lib/internal/NativeModules.ts +4 -1
  208. package/lib/internal/RNFBNativeEventEmitter.ts +14 -5
  209. package/lib/internal/SharedEventEmitter.ts +5 -1
  210. package/lib/internal/index.ts +1 -0
  211. package/lib/internal/react-native-vendor-emitter.d.ts +11 -0
  212. package/lib/internal/registry/app.ts +7 -1
  213. package/lib/types/app.ts +10 -3
  214. package/lib/types/internal.ts +19 -0
  215. package/lib/version.ts +1 -1
  216. package/package.json +8 -8
  217. package/plugin/build/ios/appDelegate.js +2 -2
  218. package/plugin/build/ios/podfile.js +16 -16
  219. package/plugin/build/pluginConfig.d.ts +4 -2
  220. package/plugin/src/ios/appDelegate.ts +2 -2
  221. package/plugin/src/ios/podfile.ts +20 -23
  222. package/plugin/src/pluginConfig.ts +4 -2
  223. package/android/src/main/java/io/invertase/firebase/common/RNFBHandleMap.java +0 -150
  224. package/android/src/main/java/io/invertase/firebase/common/TaskExecutorService.java +0 -148
  225. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebaseModule.java +0 -62
  226. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebasePreferences.java +0 -91
  227. package/android/src/reactnative/java/io/invertase/firebase/app/NativeRNFBTurboApp.java +0 -224
  228. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseApp.java +0 -46
  229. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackage.java +0 -49
  230. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppRegistrar.java +0 -35
  231. package/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.java +0 -192
  232. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEvent.java +0 -53
  233. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitter.java +0 -606
  234. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseJSON.java +0 -109
  235. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseMeta.java +0 -101
  236. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseModule.java +0 -146
  237. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebasePreferences.java +0 -96
  238. package/android/src/reactnative/java/io/invertase/firebase/common/SharedUtils.java +0 -441
  239. package/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.java +0 -223
  240. package/android/src/test/java/io/invertase/firebase/common/RNFBHandleMapTest.java +0 -275
  241. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseJSONTest.java +0 -108
  242. package/android/src/test/java/io/invertase/firebase/common/TaskExecutorServiceTest.java +0 -97
@@ -0,0 +1,176 @@
1
+ package io.invertase.firebase.common;
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
+ import static org.junit.Assert.assertEquals;
20
+ import static org.junit.Assert.assertFalse;
21
+ import static org.junit.Assert.assertNotNull;
22
+ import static org.junit.Assert.assertSame;
23
+ import static org.junit.Assert.assertTrue;
24
+ import static org.junit.Assert.fail;
25
+
26
+ import com.facebook.react.bridge.ReactContext;
27
+ import com.facebook.react.bridge.WritableMap;
28
+ import io.invertase.firebase.interfaces.NativeEvent;
29
+ import java.lang.reflect.Constructor;
30
+ import java.lang.reflect.Field;
31
+ import java.lang.reflect.Method;
32
+ import java.lang.reflect.Modifier;
33
+ import java.util.HashMap;
34
+ import java.util.List;
35
+ import org.junit.Test;
36
+ import org.junit.runner.RunWith;
37
+ import org.robolectric.RobolectricTestRunner;
38
+
39
+ /**
40
+ * Java ABI / nullability / descriptor checks for the Kotlin EventEmitter port.
41
+ *
42
+ * <p>Robolectric is required because companion initialization constructs a main-looper Handler.
43
+ */
44
+ @RunWith(RobolectricTestRunner.class)
45
+ public class ReactNativeFirebaseEventEmitterJavaCompatibilityTest {
46
+
47
+ @Test
48
+ public void classIsPublicOpenConstructibleWithOuterStaticSharedInstanceAccessor()
49
+ throws Exception {
50
+ Class<?> emitterClass = ReactNativeFirebaseEventEmitter.class;
51
+ assertTrue(Modifier.isPublic(emitterClass.getModifiers()));
52
+ assertFalse(Modifier.isFinal(emitterClass.getModifiers()));
53
+
54
+ Constructor<?> constructor = emitterClass.getDeclaredConstructor();
55
+ assertTrue(Modifier.isPublic(constructor.getModifiers()));
56
+ assertNotNull(constructor.newInstance());
57
+
58
+ Method getSharedInstance = emitterClass.getMethod("getSharedInstance");
59
+ assertTrue(Modifier.isPublic(getSharedInstance.getModifiers()));
60
+ assertTrue(Modifier.isStatic(getSharedInstance.getModifiers()));
61
+ assertEquals(emitterClass, getSharedInstance.getReturnType());
62
+ assertSame(
63
+ ReactNativeFirebaseEventEmitter.getSharedInstance(),
64
+ ReactNativeFirebaseEventEmitter.getSharedInstance());
65
+ }
66
+
67
+ @Test
68
+ public void publicMethodDescriptorsMatchJavaSurface() throws Exception {
69
+ Class<?> emitterClass = ReactNativeFirebaseEventEmitter.class;
70
+
71
+ assertPublicOpenInstance(
72
+ emitterClass.getMethod("attachReactContext", ReactContext.class), Void.TYPE);
73
+ assertPublicOpenInstance(
74
+ emitterClass.getMethod("detachReactContext", ReactContext.class), Void.TYPE);
75
+ assertPublicOpenInstance(emitterClass.getMethod("notifyJsReady", Boolean.class), Void.TYPE);
76
+ assertPublicOpenInstance(emitterClass.getMethod("sendEvent", NativeEvent.class), Void.TYPE);
77
+ assertPublicOpenInstance(emitterClass.getMethod("addListener", String.class), Void.TYPE);
78
+ assertPublicOpenInstance(
79
+ emitterClass.getMethod("removeListener", String.class, Boolean.class), Void.TYPE);
80
+ assertPublicOpenInstance(emitterClass.getMethod("getListenersMap"), WritableMap.class);
81
+ }
82
+
83
+ @Test
84
+ public void sharedInstanceRemainsPrivateStaticOuterField() throws Exception {
85
+ Field shared = ReactNativeFirebaseEventEmitter.class.getDeclaredField("sharedInstance");
86
+ assertTrue(Modifier.isPrivate(shared.getModifiers()));
87
+ assertTrue(Modifier.isStatic(shared.getModifiers()));
88
+ assertEquals(ReactNativeFirebaseEventEmitter.class, shared.getType());
89
+ }
90
+
91
+ @Test
92
+ public void privateFieldNamesRemainReflectable() throws Exception {
93
+ String[] names = {
94
+ "handler",
95
+ "queuedEvents",
96
+ "jsListeners",
97
+ "attachedReactContext",
98
+ "pendingReactContext",
99
+ "hostLagReactContext",
100
+ "attachedListenersSnapshot",
101
+ "attachedJsReadySnapshot",
102
+ "attachedJsListenerCountSnapshot",
103
+ "emitPrefersRestoredAttached",
104
+ "jsReady",
105
+ "jsListenerCount"
106
+ };
107
+ for (String name : names) {
108
+ Field field = ReactNativeFirebaseEventEmitter.class.getDeclaredField(name);
109
+ assertTrue(name, Modifier.isPrivate(field.getModifiers()));
110
+ }
111
+
112
+ // Java field type was List; Kotlin MutableList erases to List.
113
+ Field queued = ReactNativeFirebaseEventEmitter.class.getDeclaredField("queuedEvents");
114
+ assertEquals(List.class, queued.getType());
115
+ Field listeners = ReactNativeFirebaseEventEmitter.class.getDeclaredField("jsListeners");
116
+ assertEquals(HashMap.class, listeners.getType());
117
+ }
118
+
119
+ @Test
120
+ public void hostResolveAndEmitMethodsRetainJavaDescriptors() throws Exception {
121
+ Method resolve =
122
+ ReactNativeFirebaseEventEmitter.class.getDeclaredMethod(
123
+ "getCurrentReactContextFromHost", ReactContext.class);
124
+ assertTrue(Modifier.isStatic(resolve.getModifiers()));
125
+ assertTrue(Modifier.isPrivate(resolve.getModifiers()));
126
+ assertEquals(ReactContext.class, resolve.getReturnType());
127
+
128
+ Method emit =
129
+ ReactNativeFirebaseEventEmitter.class.getDeclaredMethod("emit", NativeEvent.class);
130
+ assertTrue(Modifier.isPrivate(emit.getModifiers()));
131
+ assertEquals(Boolean.TYPE, emit.getReturnType());
132
+
133
+ Method sendQueued = ReactNativeFirebaseEventEmitter.class.getDeclaredMethod("sendQueuedEvents");
134
+ assertTrue(Modifier.isPrivate(sendQueued.getModifiers()));
135
+ assertEquals(Void.TYPE, sendQueued.getReturnType());
136
+
137
+ // androidx @Nullable/@MainThread are CLASS retention (lint-visible, not runtime).
138
+ Field snapshot =
139
+ ReactNativeFirebaseEventEmitter.class.getDeclaredField("attachedListenersSnapshot");
140
+ assertTrue(Modifier.isPrivate(snapshot.getModifiers()));
141
+ assertEquals(HashMap.class, snapshot.getType());
142
+ }
143
+
144
+ @Test
145
+ public void notifyJsReadyNullUnboxesWithNpeAtAssignmentTiming() {
146
+ ReactNativeFirebaseEventEmitter emitter = new ReactNativeFirebaseEventEmitter();
147
+ try {
148
+ emitter.notifyJsReady(null);
149
+ fail("expected NullPointerException from Boolean unboxing");
150
+ } catch (NullPointerException expected) {
151
+ // Java assigned Boolean into primitive boolean inside the monitor.
152
+ }
153
+ }
154
+
155
+ @Test
156
+ public void removeListenerNullAllUnboxesOnlyWhenEventRegistered() {
157
+ ReactNativeFirebaseEventEmitter emitter = new ReactNativeFirebaseEventEmitter();
158
+ // No registration: null `all` must not unbox.
159
+ emitter.removeListener("missing", null);
160
+
161
+ emitter.addListener("present");
162
+ try {
163
+ emitter.removeListener("present", null);
164
+ fail("expected NullPointerException from Boolean unboxing");
165
+ } catch (NullPointerException expected) {
166
+ // With count == 1, `|| all` short-circuits; `all ? … : 1` then unboxes.
167
+ }
168
+ }
169
+
170
+ private static void assertPublicOpenInstance(Method method, Class<?> returnType) {
171
+ assertTrue(method.toString(), Modifier.isPublic(method.getModifiers()));
172
+ assertFalse(method.toString(), Modifier.isStatic(method.getModifiers()));
173
+ assertFalse(method.toString(), Modifier.isFinal(method.getModifiers()));
174
+ assertEquals(returnType, method.getReturnType());
175
+ }
176
+ }
@@ -1418,21 +1418,28 @@ public class ReactNativeFirebaseEventEmitterTest {
1418
1418
  public void emit_returnsFalse_whenEmitContextNull() throws Exception {
1419
1419
  when(reactHost.getCurrentReactContext()).thenReturn(null);
1420
1420
  ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance();
1421
- emitter.notifyJsReady(true);
1422
- emitter.addListener(EVENT);
1423
- ShadowLooper.idleMainLooper();
1421
+ Context previous = ReactNativeFirebaseApp.getApplicationContext();
1422
+ try {
1423
+ // Force brownfield null host resolution: no ReactApplication fallback.
1424
+ ReactNativeFirebaseApp.setApplicationContext(null);
1425
+ emitter.notifyJsReady(true);
1426
+ emitter.addListener(EVENT);
1427
+ ShadowLooper.idleMainLooper();
1424
1428
 
1425
- emitter.sendEvent(event(EVENT, eventBody));
1426
- ShadowLooper.idleMainLooper();
1429
+ emitter.sendEvent(event(EVENT, eventBody));
1430
+ ShadowLooper.idleMainLooper();
1427
1431
 
1428
- verify(liveJsEmitter, never()).emit(anyString(), eq(eventBody));
1429
- verify(staleJsEmitter, never()).emit(anyString(), eq(eventBody));
1432
+ verify(liveJsEmitter, never()).emit(anyString(), eq(eventBody));
1433
+ verify(staleJsEmitter, never()).emit(anyString(), eq(eventBody));
1430
1434
 
1431
- Field queued = ReactNativeFirebaseEventEmitter.class.getDeclaredField("queuedEvents");
1432
- queued.setAccessible(true);
1433
- @SuppressWarnings("unchecked")
1434
- java.util.List<NativeEvent> remaining = (java.util.List<NativeEvent>) queued.get(emitter);
1435
- assertEquals(1, remaining.size());
1435
+ Field queued = ReactNativeFirebaseEventEmitter.class.getDeclaredField("queuedEvents");
1436
+ queued.setAccessible(true);
1437
+ @SuppressWarnings("unchecked")
1438
+ java.util.List<NativeEvent> remaining = (java.util.List<NativeEvent>) queued.get(emitter);
1439
+ assertEquals(1, remaining.size());
1440
+ } finally {
1441
+ ReactNativeFirebaseApp.setApplicationContext(previous);
1442
+ }
1436
1443
  }
1437
1444
 
1438
1445
  /** With no pending and a null attached pointer, emit prefers the non-null host current. */
@@ -1711,6 +1718,130 @@ public class ReactNativeFirebaseEventEmitterTest {
1711
1718
  }
1712
1719
  }
1713
1720
 
1721
+ /** getListenersMap reports currentContextHash 0 when the host cannot name a current context. */
1722
+ @Test
1723
+ public void getListenersMap_reportsZeroCurrentHash_whenHostCurrentNull() {
1724
+ when(reactHost.getCurrentReactContext()).thenReturn(liveContext);
1725
+ ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance();
1726
+ emitter.attachReactContext(liveContext);
1727
+ ShadowLooper.idleMainLooper();
1728
+ emitter.notifyJsReady(true);
1729
+ emitter.addListener(EVENT);
1730
+ ShadowLooper.idleMainLooper();
1731
+
1732
+ when(reactHost.getCurrentReactContext()).thenReturn(null);
1733
+
1734
+ WritableMap writableMap = mock(WritableMap.class);
1735
+ WritableMap eventsMap = mock(WritableMap.class);
1736
+ try (MockedStatic<Arguments> arguments = mockStatic(Arguments.class)) {
1737
+ arguments.when(Arguments::createMap).thenReturn(writableMap, eventsMap);
1738
+ emitter.getListenersMap();
1739
+ verify(writableMap).putInt("currentContextHash", 0);
1740
+ verify(writableMap).putInt("attachedContextHash", System.identityHashCode(liveContext));
1741
+ }
1742
+ }
1743
+
1744
+ /** The first NativeEvent dereference must occur while holding the exact jsListeners monitor. */
1745
+ @Test
1746
+ public void sendEvent_readsEventNameFirstInsideJsListenersMonitor() throws Exception {
1747
+ ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance();
1748
+ Field field = ReactNativeFirebaseEventEmitter.class.getDeclaredField("jsListeners");
1749
+ field.setAccessible(true);
1750
+ Object monitor = field.get(emitter);
1751
+
1752
+ NativeEvent nativeEvent = mock(NativeEvent.class);
1753
+ when(nativeEvent.getEventName())
1754
+ .thenAnswer(
1755
+ invocation -> {
1756
+ assertTrue("getEventName must execute under jsListeners", Thread.holdsLock(monitor));
1757
+ return EVENT;
1758
+ });
1759
+
1760
+ emitter.sendEvent(nativeEvent);
1761
+ ShadowLooper.idleMainLooper();
1762
+
1763
+ verify(nativeEvent).getEventName();
1764
+ assertEquals(1, queuedCount(emitter));
1765
+ }
1766
+
1767
+ /**
1768
+ * A null NativeEvent is accepted by the public call and fails only when the posted runnable first
1769
+ * dereferences it under jsListeners. The erased generic helper proves there is no parameter cast.
1770
+ */
1771
+ @Test
1772
+ public void sendEvent_nullFailsInsidePostedRunnable_withoutPreMonitorCheck() throws Exception {
1773
+ Method platformHelper =
1774
+ ReactNativeFirebaseEventEmitter.class.getDeclaredMethod(
1775
+ "nullableAsPlatformType", Object.class);
1776
+ assertEquals(Object.class, platformHelper.getReturnType());
1777
+
1778
+ ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance();
1779
+ emitter.sendEvent(null);
1780
+ try {
1781
+ ShadowLooper.idleMainLooper();
1782
+ org.junit.Assert.fail("expected posted getEventName NullPointerException");
1783
+ } catch (NullPointerException expected) {
1784
+ // The public sendEvent call returned; failure occurred in the posted runnable.
1785
+ }
1786
+ }
1787
+
1788
+ /** Nullable Java listener keys flow unchanged into WritableMap.putInt. */
1789
+ @Test
1790
+ public void getListenersMap_passesNullListenerKeyToWritableMap() {
1791
+ ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance();
1792
+ emitter.addListener(null);
1793
+ ShadowLooper.idleMainLooper();
1794
+
1795
+ WritableMap writableMap = mock(WritableMap.class);
1796
+ WritableMap eventsMap = mock(WritableMap.class);
1797
+ try (MockedStatic<Arguments> arguments = mockStatic(Arguments.class)) {
1798
+ arguments.when(Arguments::createMap).thenReturn(writableMap, eventsMap);
1799
+
1800
+ emitter.getListenersMap();
1801
+
1802
+ verify(eventsMap).putInt(eq((String) null), eq(1));
1803
+ }
1804
+ }
1805
+
1806
+ /** ReactHost LinkageError is swallowed the same as RuntimeException. */
1807
+ @Test
1808
+ public void hostResolution_swallowsReactHostLinkageError() throws Exception {
1809
+ Application reactApp =
1810
+ mock(
1811
+ Application.class,
1812
+ org.mockito.Mockito.withSettings().extraInterfaces(ReactApplication.class));
1813
+ ReactApplication asReactApplication = (ReactApplication) reactApp;
1814
+ when(reactApp.getApplicationContext()).thenReturn(reactApp);
1815
+ when(asReactApplication.getReactHost()).thenThrow(new LinkageError("reactHost linkage"));
1816
+ when(asReactApplication.getReactNativeHost())
1817
+ .thenThrow(new RuntimeException("bridgeless-only test host"));
1818
+
1819
+ ReactContext hint = mock(ReactContext.class);
1820
+ when(hint.getApplicationContext()).thenReturn(reactApp);
1821
+
1822
+ Method resolve =
1823
+ ReactNativeFirebaseEventEmitter.class.getDeclaredMethod(
1824
+ "getCurrentReactContextFromHost", ReactContext.class);
1825
+ resolve.setAccessible(true);
1826
+ assertNull(resolve.invoke(null, hint));
1827
+ }
1828
+
1829
+ /** ReactNativeHost LinkageError is swallowed when ReactHost is absent. */
1830
+ @Test
1831
+ public void hostResolution_swallowsReactNativeHostLinkageError_whenReactHostAbsent()
1832
+ throws Exception {
1833
+ application.reactHost = null;
1834
+ ReactNativeHost rnHost = mock(ReactNativeHost.class);
1835
+ application.reactNativeHost = rnHost;
1836
+ when(rnHost.hasInstance()).thenThrow(new LinkageError("native host linkage"));
1837
+
1838
+ Method resolve =
1839
+ ReactNativeFirebaseEventEmitter.class.getDeclaredMethod(
1840
+ "getCurrentReactContextFromHost", ReactContext.class);
1841
+ resolve.setAccessible(true);
1842
+ assertNull(resolve.invoke(null, liveContext));
1843
+ }
1844
+
1714
1845
  private static NativeEvent event(String name, WritableMap body) {
1715
1846
  return new NativeEvent() {
1716
1847
  @Override
@@ -0,0 +1,61 @@
1
+ package io.invertase.firebase.common
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 com.facebook.react.bridge.WritableMap
21
+ import io.invertase.firebase.interfaces.NativeEvent
22
+ import org.junit.Assert.assertEquals
23
+ import org.junit.Assert.assertNull
24
+ import org.junit.Assert.assertSame
25
+ import org.junit.Test
26
+ import org.mockito.Mockito.mock
27
+
28
+ class ReactNativeFirebaseEventTest {
29
+ @Test
30
+ fun twoArgumentConstructor_preservesValuesAndUsesNullAppName() {
31
+ val body = mock(WritableMap::class.java)
32
+
33
+ val event: NativeEvent = ReactNativeFirebaseEvent("event_name", body)
34
+
35
+ assertEquals("event_name", event.getEventName())
36
+ assertSame(body, event.getEventBody())
37
+ assertNull(event.getFirebaseAppName())
38
+ }
39
+
40
+ @Test
41
+ fun threeArgumentConstructor_preservesValues() {
42
+ val body = mock(WritableMap::class.java)
43
+
44
+ val event: NativeEvent = ReactNativeFirebaseEvent("event_name", body, "app_name")
45
+
46
+ assertEquals("event_name", event.getEventName())
47
+ assertSame(body, event.getEventBody())
48
+ assertEquals("app_name", event.getFirebaseAppName())
49
+ }
50
+
51
+ @Test
52
+ fun javaVisibleApi_hasBothConstructorShapesAndExactGetterTypes() {
53
+ val eventClass = ReactNativeFirebaseEvent::class.java
54
+
55
+ eventClass.getConstructor(String::class.java, WritableMap::class.java)
56
+ eventClass.getConstructor(String::class.java, WritableMap::class.java, String::class.java)
57
+ assertEquals(String::class.java, eventClass.getMethod("getEventName").returnType)
58
+ assertEquals(WritableMap::class.java, eventClass.getMethod("getEventBody").returnType)
59
+ assertEquals(String::class.java, eventClass.getMethod("getFirebaseAppName").returnType)
60
+ }
61
+ }
@@ -0,0 +1,85 @@
1
+ package io.invertase.firebase.common;
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
+ import static org.junit.Assert.assertEquals;
20
+ import static org.junit.Assert.assertFalse;
21
+ import static org.junit.Assert.assertNull;
22
+ import static org.junit.Assert.assertTrue;
23
+ import static org.mockito.Mockito.mock;
24
+ import static org.mockito.Mockito.when;
25
+
26
+ import java.lang.reflect.Field;
27
+ import java.util.ArrayList;
28
+ import java.util.List;
29
+ import org.json.JSONObject;
30
+ import org.junit.After;
31
+ import org.junit.Before;
32
+ import org.junit.Test;
33
+
34
+ /** Proves the Kotlin port preserves calls that Java permits with null reference arguments. */
35
+ public class ReactNativeFirebaseJSONJavaCompatibilityTest {
36
+ private ReactNativeFirebaseJSON json;
37
+ private Field jsonObjectField;
38
+ private Object originalJsonObject;
39
+
40
+ @Before
41
+ public void setUp() throws Exception {
42
+ json = ReactNativeFirebaseJSON.getSharedInstance();
43
+ jsonObjectField = ReactNativeFirebaseJSON.class.getDeclaredField("jsonObject");
44
+ jsonObjectField.setAccessible(true);
45
+ originalJsonObject = jsonObjectField.get(json);
46
+ }
47
+
48
+ @After
49
+ public void tearDown() throws Exception {
50
+ jsonObjectField.set(json, originalJsonObject);
51
+ }
52
+
53
+ @Test
54
+ public void publicAccessorsAcceptNullKeysFromJava() throws Exception {
55
+ JSONObject jsonObject = mock(JSONObject.class);
56
+ when(jsonObject.has(null)).thenReturn(true);
57
+ when(jsonObject.optBoolean(null, true)).thenReturn(false);
58
+ when(jsonObject.optInt(null, 17)).thenReturn(23);
59
+ when(jsonObject.optLong(null, 29L)).thenReturn(31L);
60
+ when(jsonObject.optString(null, "fallback")).thenReturn("value");
61
+ when(jsonObject.optJSONArray(null)).thenReturn(null);
62
+ jsonObjectField.set(json, jsonObject);
63
+
64
+ assertTrue(json.contains(null));
65
+ assertFalse(json.getBooleanValue(null, true));
66
+ assertEquals(23, json.getIntValue(null, 17));
67
+ assertEquals(31L, json.getLongValue(null, 29L));
68
+ assertEquals("value", json.getStringValue(null, "fallback"));
69
+
70
+ ArrayList<String> result = json.getArrayValue(null);
71
+ result.add("mutable");
72
+ assertEquals(List.of("mutable"), result);
73
+ }
74
+
75
+ @Test
76
+ public void getStringValueAcceptsAndReturnsNullDefaultFromJava() throws Exception {
77
+ jsonObjectField.set(json, null);
78
+ assertNull(json.getStringValue(null, null));
79
+
80
+ JSONObject jsonObject = mock(JSONObject.class);
81
+ when(jsonObject.optString(null, null)).thenReturn(null);
82
+ jsonObjectField.set(json, jsonObject);
83
+ assertNull(json.getStringValue(null, null));
84
+ }
85
+ }