@react-native-firebase/app 23.8.0 → 23.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/CHANGELOG.md +1547 -0
  2. package/RNFBApp.podspec +49 -0
  3. package/android/.editorconfig +10 -0
  4. package/android/build.gradle +129 -0
  5. package/android/firebase-json.gradle +73 -0
  6. package/android/gradle.properties +2 -0
  7. package/android/lint.xml +5 -0
  8. package/android/settings.gradle +1 -0
  9. package/android/src/main/AndroidManifest.xml +24 -0
  10. package/android/src/main/java/io/invertase/firebase/app/.gitkeep +0 -0
  11. package/android/src/main/java/io/invertase/firebase/common/TaskExecutorService.java +124 -0
  12. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebaseModule.java +62 -0
  13. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebasePreferences.java +91 -0
  14. package/android/src/main/java/io/invertase/firebase/interfaces/.gitkeep +0 -0
  15. package/android/src/reactnative/AndroidManifest.xml +2 -0
  16. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseApp.java +46 -0
  17. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppInitProvider.java +22 -0
  18. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppModule.java +186 -0
  19. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackage.java +49 -0
  20. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppRegistrar.java +35 -0
  21. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseVersion.java +22 -0
  22. package/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.java +191 -0
  23. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEvent.java +53 -0
  24. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitter.java +151 -0
  25. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseInitProvider.java +78 -0
  26. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseJSON.java +107 -0
  27. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseMeta.java +93 -0
  28. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseModule.java +146 -0
  29. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebasePreferences.java +88 -0
  30. package/android/src/reactnative/java/io/invertase/firebase/common/SharedUtils.java +440 -0
  31. package/android/src/reactnative/java/io/invertase/firebase/interfaces/ContextProvider.java +30 -0
  32. package/android/src/reactnative/java/io/invertase/firebase/interfaces/NativeError.java +32 -0
  33. package/android/src/reactnative/java/io/invertase/firebase/interfaces/NativeEvent.java +28 -0
  34. package/android/src/reactnative/java/io/invertase/firebase/utils/ReactNativeFirebaseUtilsModule.java +191 -0
  35. package/app.plugin.js +1 -0
  36. package/dist/commonjs/version.js +1 -1
  37. package/dist/module/version.js +1 -1
  38. package/dist/typescript/commonjs/lib/modular.d.ts +1 -1
  39. package/dist/typescript/commonjs/lib/version.d.ts +1 -1
  40. package/dist/typescript/module/lib/modular.d.ts +1 -1
  41. package/dist/typescript/module/lib/version.d.ts +1 -1
  42. package/firebase-schema.json +149 -0
  43. package/firebase_json.rb +72 -0
  44. package/ios/RNFBApp/RCTConvert+FIRApp.h +23 -0
  45. package/ios/RNFBApp/RCTConvert+FIRApp.m +31 -0
  46. package/ios/RNFBApp/RCTConvert+FIROptions.h +23 -0
  47. package/ios/RNFBApp/RCTConvert+FIROptions.m +36 -0
  48. package/ios/RNFBApp/RNFBAppModule.h +28 -0
  49. package/ios/RNFBApp/RNFBAppModule.m +305 -0
  50. package/ios/RNFBApp/RNFBJSON.h +36 -0
  51. package/ios/RNFBApp/RNFBJSON.m +99 -0
  52. package/ios/RNFBApp/RNFBMeta.h +30 -0
  53. package/ios/RNFBApp/RNFBMeta.m +61 -0
  54. package/ios/RNFBApp/RNFBNullSentinelInterceptor.h +47 -0
  55. package/ios/RNFBApp/RNFBNullSentinelInterceptor.m +74 -0
  56. package/ios/RNFBApp/RNFBPreferences.h +44 -0
  57. package/ios/RNFBApp/RNFBPreferences.m +94 -0
  58. package/ios/RNFBApp/RNFBRCTEventEmitter.h +73 -0
  59. package/ios/RNFBApp/RNFBRCTEventEmitter.m +151 -0
  60. package/ios/RNFBApp/RNFBSharedUtils.h +67 -0
  61. package/ios/RNFBApp/RNFBSharedUtils.m +285 -0
  62. package/ios/RNFBApp/RNFBUtilsModule.h +30 -0
  63. package/ios/RNFBApp/RNFBUtilsModule.m +100 -0
  64. package/ios/RNFBApp/RNFBVersion.h +20 -0
  65. package/ios/RNFBApp/RNFBVersion.m +21 -0
  66. package/ios/RNFBApp.xcodeproj/project.pbxproj +411 -0
  67. package/ios/RNFBApp.xcodeproj/xcshareddata/IDETemplateMacros.plist +24 -0
  68. package/ios_config.sh +269 -0
  69. package/lib/version.ts +1 -1
  70. package/package.json +4 -11
  71. package/plugin/build/android/applyPlugin.d.ts +6 -0
  72. package/plugin/build/android/applyPlugin.js +29 -0
  73. package/plugin/build/android/buildscriptDependency.d.ts +6 -0
  74. package/plugin/build/android/buildscriptDependency.js +31 -0
  75. package/plugin/build/android/constants.d.ts +4 -0
  76. package/plugin/build/android/constants.js +8 -0
  77. package/plugin/build/android/copyGoogleServices.d.ts +5 -0
  78. package/plugin/build/android/copyGoogleServices.js +33 -0
  79. package/plugin/build/android/index.d.ts +4 -0
  80. package/plugin/build/android/index.js +9 -0
  81. package/plugin/build/index.d.ts +3 -0
  82. package/plugin/build/index.js +21 -0
  83. package/plugin/build/ios/appDelegate.d.ts +6 -0
  84. package/plugin/build/ios/appDelegate.js +116 -0
  85. package/plugin/build/ios/googleServicesPlist.d.ts +7 -0
  86. package/plugin/build/ios/googleServicesPlist.js +42 -0
  87. package/plugin/build/ios/index.d.ts +3 -0
  88. package/plugin/build/ios/index.js +7 -0
  89. package/plugin/src/android/applyPlugin.ts +30 -0
  90. package/plugin/src/android/buildscriptDependency.ts +33 -0
  91. package/plugin/src/android/constants.ts +7 -0
  92. package/plugin/src/android/copyGoogleServices.ts +36 -0
  93. package/plugin/src/android/index.ts +5 -0
  94. package/plugin/src/index.ts +27 -0
  95. package/plugin/src/ios/appDelegate.ts +140 -0
  96. package/plugin/src/ios/googleServicesPlist.ts +55 -0
  97. package/plugin/src/ios/index.ts +4 -0
  98. package/plugin/tsconfig.json +9 -0
  99. package/plugin/tsconfig.tsbuildinfo +1 -0
  100. package/react-native.config.js +19 -0
  101. package/tsconfig.json +10 -0
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import "RNFBPreferences.h"
19
+
20
+ @interface RNFBPreferences ()
21
+ @property(nonatomic, strong) NSUserDefaults *userDefaults;
22
+ @end
23
+
24
+ static NSString *const RNFBDomainIdentifier = @"io.invertase.firebase";
25
+
26
+ @implementation RNFBPreferences
27
+
28
+ static RNFBPreferences *sharedInstance;
29
+
30
+ + (void)load {
31
+ sharedInstance = [[RNFBPreferences alloc] init];
32
+ }
33
+
34
+ - (instancetype)init {
35
+ self = [super init];
36
+
37
+ if (self) {
38
+ _userDefaults = [[NSUserDefaults alloc] initWithSuiteName:RNFBDomainIdentifier];
39
+ }
40
+
41
+ return self;
42
+ }
43
+
44
+ - (BOOL)contains:(NSString *)key {
45
+ return [_userDefaults objectForKey:key] != nil;
46
+ }
47
+
48
+ - (BOOL)getBooleanValue:(NSString *)key defaultValue:(BOOL)defaultValue {
49
+ if ([_userDefaults objectForKey:key] == nil) return defaultValue;
50
+ return [_userDefaults boolForKey:key];
51
+ }
52
+
53
+ - (void)setBooleanValue:(NSString *)key boolValue:(BOOL)boolValue {
54
+ [_userDefaults setBool:boolValue forKey:key];
55
+ [_userDefaults synchronize];
56
+ }
57
+
58
+ - (void)setIntegerValue:(NSString *)key integerValue:(NSInteger)integerValue {
59
+ [_userDefaults setInteger:(NSInteger)integerValue forKey:key];
60
+ [_userDefaults synchronize];
61
+ }
62
+
63
+ - (NSInteger)getIntegerValue:(NSString *)key defaultValue:(NSInteger)defaultValue {
64
+ if ([_userDefaults objectForKey:key] == nil) return defaultValue;
65
+ return [_userDefaults integerForKey:key];
66
+ }
67
+
68
+ - (NSString *)getStringValue:(NSString *)key defaultValue:(NSString *)defaultValue {
69
+ if ([_userDefaults objectForKey:key] == nil) return defaultValue;
70
+ return [_userDefaults stringForKey:key];
71
+ }
72
+
73
+ - (void)setStringValue:(NSString *)key stringValue:(NSString *)stringValue {
74
+ [_userDefaults setValue:stringValue forKey:key];
75
+ [_userDefaults synchronize];
76
+ }
77
+
78
+ - (NSDictionary *)getAll {
79
+ return [_userDefaults dictionaryRepresentation];
80
+ }
81
+
82
+ - (void)clearAll {
83
+ [_userDefaults removePersistentDomainForName:RNFBDomainIdentifier];
84
+ }
85
+
86
+ - (void)remove:(NSString *)key {
87
+ [_userDefaults removeObjectForKey:key];
88
+ }
89
+
90
+ + (RNFBPreferences *)shared {
91
+ return sharedInstance;
92
+ }
93
+
94
+ @end
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import <Foundation/Foundation.h>
19
+ #import <React/RCTEventEmitter.h>
20
+
21
+ /**
22
+ * Listeners for Firebase events and emits them to the JS layer
23
+ */
24
+ @interface RNFBRCTEventEmitter : NSObject
25
+
26
+ /**
27
+ * The RCTBridge. Assigned by `RNFBAppModule`
28
+ */
29
+ @property(nonatomic, weak) RCTBridge *bridge;
30
+
31
+ /**
32
+ * Returns the shared instance
33
+ *
34
+ * @returns RNFBRCTEventEmitter.
35
+ */
36
+ + (RNFBRCTEventEmitter *)shared;
37
+
38
+ /**
39
+ * Invalidate
40
+ */
41
+ - (void)invalidate;
42
+
43
+ /**
44
+ * Add an event listener
45
+ *
46
+ * @param eventName NSString event name.
47
+ */
48
+ - (void)addListener:(NSString *)eventName;
49
+
50
+ /**
51
+ * Removes event listeners
52
+ */
53
+ - (void)removeListeners:(NSString *)eventName all:(BOOL)all;
54
+
55
+ /**
56
+ * Send an event to JS with the specified name and body
57
+ *
58
+ */
59
+ - (void)sendEventWithName:(NSString *)eventName body:(id)body;
60
+
61
+ /**
62
+ * Notify the event emitter that JS has loaded and is ready to receive events.
63
+ *
64
+ */
65
+ - (void)notifyJsReady:(BOOL)ready;
66
+
67
+ /**
68
+ * Returns a dictionary of all registered events & counts. Mainly for testing.
69
+ *
70
+ * @return NSDictionary
71
+ */
72
+ - (NSDictionary *)getListenersDictionary;
73
+ @end
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import "RNFBRCTEventEmitter.h"
19
+
20
+ @interface RNFBRCTEventEmitter ()
21
+ @property(atomic, assign) BOOL jsReady;
22
+ @property(atomic, assign) NSInteger jsListenerCount;
23
+ @property(nonatomic, strong) NSMutableDictionary *jsListeners;
24
+ @property(nonatomic, strong) NSMutableArray *queuedEvents;
25
+ @property(readonly) BOOL isObserving;
26
+ @end
27
+
28
+ NSString *const RNFBRCTEventNameKey = @"name";
29
+ NSString *const RNFBRCTEventBodyKey = @"body";
30
+
31
+ @implementation RNFBRCTEventEmitter
32
+
33
+ - (void)invalidate {
34
+ self.jsReady = FALSE;
35
+ self.queuedEvents = [NSMutableArray array];
36
+ self.jsListeners = [NSMutableDictionary dictionary];
37
+ self.jsListenerCount = 0;
38
+ }
39
+
40
+ + (instancetype)shared {
41
+ static dispatch_once_t once;
42
+ static RNFBRCTEventEmitter *sharedInstance;
43
+ dispatch_once(&once, ^{
44
+ sharedInstance = [[RNFBRCTEventEmitter alloc] init];
45
+ });
46
+ return sharedInstance;
47
+ }
48
+
49
+ - (instancetype)init {
50
+ self = [super init];
51
+
52
+ if (self) {
53
+ self.jsReady = FALSE;
54
+ self.queuedEvents = [NSMutableArray array];
55
+ self.jsListeners = [NSMutableDictionary dictionary];
56
+ }
57
+
58
+ return self;
59
+ }
60
+
61
+ - (void)notifyJsReady:(BOOL)jsReady {
62
+ @synchronized(self.jsListeners) {
63
+ self.jsReady = jsReady;
64
+ if (jsReady) {
65
+ for (id event in [self.queuedEvents copy]) {
66
+ [self sendEventWithName:event[RNFBRCTEventNameKey] body:event[RNFBRCTEventBodyKey]];
67
+ @synchronized(self.queuedEvents) {
68
+ [self.queuedEvents removeObject:event];
69
+ }
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ - (void)sendEventWithName:(NSString *)eventName body:(id)body {
76
+ @synchronized(self.jsListeners) {
77
+ if (self.bridge && self.isObserving && self.jsListeners[eventName] != nil) {
78
+ NSString *prefixedEventName = [@"rnfb_" stringByAppendingString:eventName];
79
+ [self.bridge enqueueJSCall:@"RCTDeviceEventEmitter"
80
+ method:@"emit"
81
+ args:body ? @[ prefixedEventName, body ] : @[ prefixedEventName ]
82
+ completion:NULL];
83
+ } else {
84
+ @synchronized(self.queuedEvents) {
85
+ [self.queuedEvents
86
+ addObject:@{RNFBRCTEventNameKey : eventName, RNFBRCTEventBodyKey : body}];
87
+ }
88
+ }
89
+ }
90
+ }
91
+
92
+ - (void)addListener:(NSString *)eventName {
93
+ @synchronized(self.jsListeners) {
94
+ self.jsListenerCount++;
95
+
96
+ if (self.jsListeners[eventName] == nil) {
97
+ self.jsListeners[eventName] = @([@1 integerValue]);
98
+ } else {
99
+ self.jsListeners[eventName] =
100
+ @([self.jsListeners[eventName] integerValue] + [@1 integerValue]);
101
+ }
102
+
103
+ for (id event in [self.queuedEvents copy]) {
104
+ if ([event[RNFBRCTEventNameKey] isEqualToString:eventName]) {
105
+ [self sendEventWithName:event[RNFBRCTEventNameKey] body:event[RNFBRCTEventBodyKey]];
106
+ @synchronized(self.queuedEvents) {
107
+ [self.queuedEvents removeObject:event];
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+
114
+ - (void)removeListeners:(NSString *)eventName all:(BOOL)all {
115
+ @synchronized(self.jsListeners) {
116
+ if (self.jsListeners[eventName] != nil) {
117
+ NSInteger listenersForEvent = [self.jsListeners[eventName] integerValue];
118
+
119
+ if (listenersForEvent <= 1 || all) {
120
+ @synchronized(self.jsListeners) {
121
+ [self.jsListeners removeObjectForKey:eventName];
122
+ }
123
+ } else {
124
+ @synchronized(self.jsListeners) {
125
+ self.jsListeners[eventName] =
126
+ @([self.jsListeners[eventName] integerValue] - [@1 integerValue]);
127
+ }
128
+ }
129
+
130
+ if (all) {
131
+ self.jsListenerCount = self.jsListenerCount - listenersForEvent;
132
+ } else {
133
+ self.jsListenerCount = self.jsListenerCount - [@1 integerValue];
134
+ }
135
+ }
136
+ }
137
+ }
138
+
139
+ - (NSDictionary *)getListenersDictionary {
140
+ NSMutableDictionary *listenersDictionary = [NSMutableDictionary new];
141
+ listenersDictionary[@"listeners"] = @(self.jsListenerCount);
142
+ listenersDictionary[@"queued"] = @([self.queuedEvents count]);
143
+ listenersDictionary[@"events"] = [self.jsListeners copy];
144
+ return listenersDictionary;
145
+ }
146
+
147
+ - (BOOL)isObserving {
148
+ return self.jsReady && self.jsListenerCount > 0;
149
+ }
150
+
151
+ @end
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #ifndef RNFBSharedUtils_h
19
+ #define RNFBSharedUtils_h
20
+
21
+ #import <FirebaseCore/FirebaseCore.h>
22
+ #import <React/RCTBridgeModule.h>
23
+
24
+ #ifdef DEBUG
25
+ #define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
26
+ #else
27
+ #define DLog(...)
28
+ #endif
29
+
30
+ #define ELog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
31
+
32
+ #pragma mark -
33
+ #pragma mark Constants
34
+
35
+ extern NSString *const DEFAULT_APP_DISPLAY_NAME;
36
+ extern NSString *const DEFAULT_APP_NAME;
37
+
38
+ @interface RNFBSharedUtils : NSObject
39
+
40
+ #pragma mark -
41
+ #pragma mark Methods
42
+
43
+ + (NSString *)getAppJavaScriptName:(NSString *)appDisplayName;
44
+
45
+ + (NSDictionary *)firAppToDictionary:(FIRApp *)firApp;
46
+
47
+ + (void)sendJSEventForApp:(FIRApp *)app name:(NSString *)name body:(NSDictionary *)body;
48
+
49
+ + (void)rejectPromiseWithExceptionDict:(RCTPromiseRejectBlock)reject
50
+ exception:(NSException *)exception;
51
+
52
+ + (void)rejectPromiseWithNSError:(RCTPromiseRejectBlock)reject error:(NSError *)error;
53
+
54
+ + (void)rejectPromiseWithUserInfo:(RCTPromiseRejectBlock)reject
55
+ userInfo:(NSMutableDictionary *)userInfo;
56
+
57
+ + (NSString *)getISO8601String:(NSDate *)date;
58
+
59
+ + (BOOL)configContains:(NSString *)key;
60
+
61
+ + (BOOL)getConfigBooleanValue:(NSString *)tag key:(NSString *)key defaultValue:(BOOL)defaultValue;
62
+
63
+ + (id)decodeNullSentinels:(id)value;
64
+
65
+ @end
66
+
67
+ #endif
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import "RNFBSharedUtils.h"
19
+ #import "RNFBAppModule.h"
20
+ #import "RNFBJSON.h"
21
+ #import "RNFBMeta.h"
22
+ #import "RNFBPreferences.h"
23
+ #import "RNFBRCTEventEmitter.h"
24
+
25
+ #pragma mark -
26
+ #pragma mark Constants
27
+
28
+ NSString *const DEFAULT_APP_DISPLAY_NAME = @"[DEFAULT]";
29
+ NSString *const DEFAULT_APP_NAME = @"__FIRAPP_DEFAULT";
30
+
31
+ @implementation RNFBSharedUtils
32
+ static NSString *const RNFBErrorDomain = @"RNFBErrorDomain";
33
+
34
+ #pragma mark -
35
+ #pragma mark Methods
36
+
37
+ + (NSString *)getAppJavaScriptName:(NSString *)appDisplayName {
38
+ if ([appDisplayName isEqualToString:DEFAULT_APP_NAME]) {
39
+ return DEFAULT_APP_DISPLAY_NAME;
40
+ }
41
+ return appDisplayName;
42
+ }
43
+
44
+ + (NSDictionary *)firAppToDictionary:(FIRApp *)firApp {
45
+ FIROptions *firOptions = [firApp options];
46
+ NSMutableDictionary *firAppDictionary = [NSMutableDictionary new];
47
+ NSMutableDictionary *firAppOptions = [NSMutableDictionary new];
48
+ NSMutableDictionary *firAppConfig = [NSMutableDictionary new];
49
+
50
+ NSString *name = [firApp name];
51
+ if ([name isEqualToString:DEFAULT_APP_NAME]) {
52
+ name = DEFAULT_APP_DISPLAY_NAME;
53
+ }
54
+
55
+ firAppConfig[@"name"] = name;
56
+ firAppConfig[@"automaticDataCollectionEnabled"] = @([firApp isDataCollectionDefaultEnabled]);
57
+
58
+ firAppOptions[@"apiKey"] = firOptions.APIKey;
59
+ firAppOptions[@"appId"] = firOptions.googleAppID;
60
+ firAppOptions[@"projectId"] = firOptions.projectID;
61
+ firAppOptions[@"databaseURL"] = firOptions.databaseURL;
62
+ firAppOptions[@"storageBucket"] = firOptions.storageBucket;
63
+ firAppOptions[@"messagingSenderId"] = firOptions.GCMSenderID;
64
+ // missing from android sdk - ios only:
65
+ firAppOptions[@"clientId"] = firOptions.clientID;
66
+ // not in FIROptions API but in JS SDK and project config JSON
67
+ if ([RNFBAppModule getCustomDomain:name] != nil) {
68
+ firAppOptions[@"authDomain"] = [RNFBAppModule getCustomDomain:name];
69
+ }
70
+
71
+ firAppDictionary[@"options"] = firAppOptions;
72
+ firAppDictionary[@"appConfig"] = firAppConfig;
73
+
74
+ return firAppDictionary;
75
+ }
76
+
77
+ + (void)rejectPromiseWithExceptionDict:(RCTPromiseRejectBlock)reject
78
+ exception:(NSException *)exception {
79
+ NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
80
+
81
+ [userInfo setValue:@(YES) forKey:@"fatal"];
82
+ [userInfo setValue:@"unknown" forKey:@"code"];
83
+ [userInfo setValue:exception.reason forKey:@"message"];
84
+ [userInfo setValue:exception.name forKey:@"nativeErrorCode"];
85
+ [userInfo setValue:exception.reason forKey:@"nativeErrorMessage"];
86
+
87
+ NSError *error = [NSError errorWithDomain:RNFBErrorDomain code:666 userInfo:userInfo];
88
+
89
+ reject(exception.name, exception.reason, error);
90
+ }
91
+
92
+ + (void)rejectPromiseWithNSError:(RCTPromiseRejectBlock)reject error:(NSError *)error {
93
+ NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
94
+
95
+ [userInfo setValue:@(NO) forKey:@"fatal"];
96
+ [userInfo setValue:@"unknown" forKey:@"code"];
97
+ [userInfo setValue:error.localizedDescription forKey:@"message"];
98
+ [userInfo setValue:@(error.code) forKey:@"nativeErrorCode"];
99
+ [userInfo setValue:error.localizedDescription forKey:@"nativeErrorMessage"];
100
+
101
+ NSError *newErrorWithUserInfo = [NSError errorWithDomain:RNFBErrorDomain
102
+ code:666
103
+ userInfo:userInfo];
104
+ reject(@"unknown", error.localizedDescription, newErrorWithUserInfo);
105
+ }
106
+
107
+ + (void)rejectPromiseWithUserInfo:(RCTPromiseRejectBlock)reject
108
+ userInfo:(NSMutableDictionary *)userInfo {
109
+ NSError *error = [NSError errorWithDomain:RNFBErrorDomain code:666 userInfo:userInfo];
110
+ reject(userInfo[@"code"], userInfo[@"message"], error);
111
+ }
112
+
113
+ // for easier v5 migration
114
+ + (void)sendJSEventForApp:(FIRApp *)app name:(NSString *)name body:(NSDictionary *)body {
115
+ NSMutableDictionary *newBody = [body mutableCopy];
116
+ newBody[@"appName"] = [self getAppJavaScriptName:app.name];
117
+ [[RNFBRCTEventEmitter shared] sendEventWithName:name body:newBody];
118
+ }
119
+
120
+ + (NSString *)getISO8601String:(NSDate *)date {
121
+ static NSDateFormatter *formatter = nil;
122
+
123
+ if (!formatter) {
124
+ formatter = [[NSDateFormatter alloc] init];
125
+ [formatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
126
+ formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
127
+ [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"];
128
+ }
129
+
130
+ NSString *iso8601String = [formatter stringFromDate:date];
131
+
132
+ return [iso8601String stringByAppendingString:@"Z"];
133
+ }
134
+
135
+ + (BOOL)configContains:(NSString *)key {
136
+ return [[RNFBPreferences shared] contains:key] || [[RNFBJSON shared] contains:key] ||
137
+ [RNFBMeta contains:key];
138
+ }
139
+
140
+ + (BOOL)getConfigBooleanValue:(NSString *)tag key:(NSString *)key defaultValue:(BOOL)defaultValue {
141
+ BOOL enabled;
142
+
143
+ if ([[RNFBPreferences shared] contains:key]) {
144
+ enabled = [[RNFBPreferences shared] getBooleanValue:key defaultValue:defaultValue];
145
+ DLog(@"%@ %@ via "
146
+ @"RNFBPreferences: %d",
147
+ tag, key, enabled);
148
+ } else if ([[RNFBJSON shared] contains:key]) {
149
+ enabled = [[RNFBJSON shared] getBooleanValue:key defaultValue:defaultValue];
150
+ DLog(@"%@ %@ via "
151
+ @"RNFBJSON: %d",
152
+ tag, key, enabled);
153
+ } else {
154
+ // Note that if we're here, and the key is not set on the app's bundle, our final default is the
155
+ // one passed in
156
+ enabled = [RNFBMeta getBooleanValue:key defaultValue:defaultValue];
157
+ DLog(@"%@ %@ via "
158
+ @"RNFBMeta: %d",
159
+ tag, key, enabled);
160
+ }
161
+
162
+ DLog(@"%@ %@ final value: %d", tag, key, enabled);
163
+
164
+ return enabled;
165
+ }
166
+
167
+ /**
168
+ * Decodes null sentinel objects back to NSNull values.
169
+ * Uses iterative stack-based traversal to avoid stack overflow on deeply nested structures.
170
+ *
171
+ * This reverses the encoding done on the JavaScript side where null values in object
172
+ * properties are replaced with {__rnfbNull: true} sentinel objects to survive iOS
173
+ * TurboModule serialization.
174
+ *
175
+ * Process:
176
+ * 1. Detects sentinel objects: dictionaries with single key "__rnfbNull" set to true
177
+ * 2. Replaces sentinels with NSNull in object properties and arrays
178
+ * 3. Preserves regular NSNull values that were in arrays (never encoded as sentinels)
179
+ * 4. Deep processes all nested objects and arrays using a stack-based iteration
180
+ *
181
+ * @param value - The value to decode (dictionary, array, or primitive)
182
+ * @return The decoded value with sentinels replaced by NSNull
183
+ */
184
+ + (id)decodeNullSentinels:(id)value {
185
+ // Non-container values are returned as-is
186
+ if (![value isKindOfClass:[NSDictionary class]] && ![value isKindOfClass:[NSArray class]]) {
187
+ return value;
188
+ }
189
+
190
+ // Helper to detect the sentinel
191
+ BOOL (^isNullSentinel)(NSDictionary *) = ^BOOL(NSDictionary *dict) {
192
+ id flag = dict[@"__rnfbNull"];
193
+ return (dict.count == 1 && flag != nil && [flag boolValue]);
194
+ };
195
+
196
+ // Helper to process a child element and add it to the parent container
197
+ void (^processChild)(id, id, id, BOOL, NSMutableArray *) =
198
+ ^void(id child, id parentMutable, id keyOrNil, BOOL isParentDict, NSMutableArray *stack) {
199
+ id processedValue = nil;
200
+
201
+ if ([child isKindOfClass:[NSDictionary class]]) {
202
+ NSDictionary *childDict = (NSDictionary *)child;
203
+
204
+ if (isNullSentinel(childDict)) {
205
+ // Replace sentinel with NSNull
206
+ processedValue = [NSNull null];
207
+ } else {
208
+ // Process nested dictionary
209
+ NSMutableDictionary *childMut =
210
+ [NSMutableDictionary dictionaryWithCapacity:childDict.count];
211
+ processedValue = childMut;
212
+ [stack addObject:@{@"original" : childDict, @"mutable" : childMut}];
213
+ }
214
+ } else if ([child isKindOfClass:[NSArray class]]) {
215
+ // Process nested array
216
+ NSArray *childArray = (NSArray *)child;
217
+ NSMutableArray *childMut = [NSMutableArray arrayWithCapacity:childArray.count];
218
+ processedValue = childMut;
219
+ [stack addObject:@{@"original" : childArray, @"mutable" : childMut}];
220
+ } else {
221
+ // Preserve primitive values
222
+ processedValue = child ?: [NSNull null];
223
+ }
224
+
225
+ // Add to parent container based on type
226
+ if (isParentDict) {
227
+ NSMutableDictionary *mutDict = (NSMutableDictionary *)parentMutable;
228
+ if (processedValue) {
229
+ mutDict[keyOrNil] = processedValue;
230
+ }
231
+ // NSDictionary can't store nil, and original code wouldn't see nil values either.
232
+ } else {
233
+ NSMutableArray *mutArray = (NSMutableArray *)parentMutable;
234
+ [mutArray addObject:processedValue];
235
+ }
236
+ };
237
+
238
+ // Root-level sentinel case
239
+ if ([value isKindOfClass:[NSDictionary class]] && isNullSentinel((NSDictionary *)value)) {
240
+ return [NSNull null];
241
+ }
242
+
243
+ id rootOriginal = value;
244
+ id rootMutable = nil;
245
+
246
+ if ([value isKindOfClass:[NSDictionary class]]) {
247
+ NSDictionary *dict = (NSDictionary *)value;
248
+ rootMutable = [NSMutableDictionary dictionaryWithCapacity:dict.count];
249
+ } else {
250
+ NSArray *array = (NSArray *)value;
251
+ rootMutable = [NSMutableArray arrayWithCapacity:array.count];
252
+ }
253
+
254
+ // Stack-based iteration to process nested structures without recursion
255
+ // Stack frames: { @"original": container, @"mutable": mutableContainer }
256
+ NSMutableArray<NSDictionary *> *stack = [NSMutableArray array];
257
+ [stack addObject:@{@"original" : rootOriginal, @"mutable" : rootMutable}];
258
+
259
+ while (stack.count > 0) {
260
+ NSDictionary *frame = [stack lastObject];
261
+ [stack removeLastObject];
262
+
263
+ id original = frame[@"original"];
264
+ id mutable = frame[@"mutable"];
265
+
266
+ if ([original isKindOfClass:[NSDictionary class]]) {
267
+ NSDictionary *origDict = (NSDictionary *)original;
268
+
269
+ for (id key in origDict) {
270
+ id child = origDict[key];
271
+ processChild(child, mutable, key, YES, stack);
272
+ }
273
+ } else if ([original isKindOfClass:[NSArray class]]) {
274
+ NSArray *origArray = (NSArray *)original;
275
+
276
+ for (id child in origArray) {
277
+ processChild(child, mutable, nil, NO, stack);
278
+ }
279
+ }
280
+ }
281
+
282
+ return rootMutable;
283
+ }
284
+
285
+ @end
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import <Foundation/Foundation.h>
19
+ #import <Photos/Photos.h>
20
+
21
+ #import <React/RCTBridgeModule.h>
22
+
23
+ @interface RNFBUtilsModule : NSObject <RCTBridgeModule>
24
+
25
+ + (BOOL)isRemoteAsset:(NSString *)localFilePath;
26
+ + (BOOL)unused_isHeic:(NSString *)localFilePath;
27
+ + (NSString *)valueForKey:(NSString *)key fromQueryItems:(NSArray *)queryItems;
28
+ + (PHAsset *)fetchAssetForPath:(NSString *)localFilePath;
29
+
30
+ @end