@react-native-firebase/auth 26.4.0 → 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 (47) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/RNFBAuth.podspec +8 -2
  3. package/android/build.gradle +3 -0
  4. package/android/src/main/java/io/invertase/firebase/auth/NativeRNFBTurboAuth.java +1 -3
  5. package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthCacheRegistry.kt +77 -0
  6. package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthListenerRegistry.kt +76 -0
  7. package/android/src/test/java/io/invertase/firebase/auth/RNFBAuthCacheRegistryTest.java +12 -0
  8. package/dist/module/index.js +1 -2
  9. package/dist/module/index.js.map +1 -1
  10. package/dist/module/version.js +1 -1
  11. package/dist/typescript/lib/types/internal.d.ts +2 -3
  12. package/dist/typescript/lib/types/internal.d.ts.map +1 -1
  13. package/dist/typescript/lib/version.d.ts +1 -1
  14. package/ios/RNFBAuth/RNFBAuthCacheRegistry.m +27 -8
  15. package/ios/RNFBAuth/RNFBAuthCacheRegistryStorage.swift +53 -0
  16. package/ios/RNFBAuth/RNFBAuthErrorCodeMapper.swift +333 -0
  17. package/ios/RNFBAuth/RNFBAuthHelper.m +24 -154
  18. package/ios/RNFBAuth/RNFBAuthListenerRegistry.m +26 -26
  19. package/ios/RNFBAuth/RNFBAuthListenerRegistryStorage.swift +76 -0
  20. package/ios/RNFBAuth/RNFBAuthNullSentinelDecoder.h +40 -0
  21. package/ios/RNFBAuth/RNFBAuthNullSentinelDecoder.m +49 -0
  22. package/ios/RNFBAuth.xcodeproj/project.pbxproj +22 -0
  23. package/ios/RNFBAuthUnitTests/RNFBAuthCacheRegistryStorageTests.swift +72 -0
  24. package/ios/RNFBAuthUnitTests/RNFBAuthErrorCodeMapperTests.swift +250 -0
  25. package/ios/RNFBAuthUnitTests/RNFBAuthListenerRegistryStorageTests.swift +122 -0
  26. package/ios/RNFBAuthUnitTests/RNFBAuthNullSentinelDecodeTests.m +78 -0
  27. package/ios/RNFBAuthUnitTests/RNFBAuthUnitTests.xcodeproj/project.pbxproj +50 -0
  28. package/lib/index.ts +1 -1
  29. package/lib/types/internal.ts +2 -2
  30. package/lib/version.ts +1 -1
  31. package/package.json +4 -4
  32. package/plugin/build/index.js +4 -0
  33. package/plugin/build/ios/index.d.ts +2 -1
  34. package/plugin/build/ios/index.js +3 -1
  35. package/plugin/build/ios/openUrlFix.js +12 -0
  36. package/plugin/build/ios/sceneDelegate.d.ts +34 -0
  37. package/plugin/build/ios/sceneDelegate.js +127 -0
  38. package/plugin/build/ios/sceneLifecycle.d.ts +32 -0
  39. package/plugin/build/ios/sceneLifecycle.js +115 -0
  40. package/plugin/src/index.ts +9 -1
  41. package/plugin/src/ios/index.ts +2 -1
  42. package/plugin/src/ios/openUrlFix.ts +15 -0
  43. package/plugin/src/ios/sceneDelegate.ts +159 -0
  44. package/plugin/src/ios/sceneLifecycle.ts +134 -0
  45. package/plugin/tsconfig.tsbuildinfo +1 -1
  46. package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthCacheRegistry.java +0 -66
  47. package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthListenerRegistry.java +0 -76
@@ -0,0 +1,72 @@
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
+ import XCTest
18
+
19
+ final class RNFBAuthCacheRegistryStorageTests: XCTestCase {
20
+ private var storage: RNFBAuthCacheRegistryStorage!
21
+
22
+ override func setUp() {
23
+ super.setUp()
24
+ storage = RNFBAuthCacheRegistryStorage()
25
+ }
26
+
27
+ func testPutOrDiscard_storesWhenFree() {
28
+ XCTAssertTrue(storage.putOrDiscard("k1" as NSString, value: "payload" as NSString))
29
+ XCTAssertEqual(storage.get("k1" as NSString) as? NSString, "payload")
30
+ }
31
+
32
+ func testPutOrDiscard_collision_keepsExisting() {
33
+ XCTAssertTrue(storage.putOrDiscard("k1" as NSString, value: "first" as NSString))
34
+ XCTAssertFalse(storage.putOrDiscard("k1" as NSString, value: "second" as NSString))
35
+ XCTAssertEqual(storage.get("k1" as NSString) as? NSString, "first")
36
+ }
37
+
38
+ func testPutReplacing_whenFree_returnsNil() {
39
+ XCTAssertNil(storage.putReplacing("k1" as NSString, value: "payload" as NSString))
40
+ XCTAssertEqual(storage.get("k1" as NSString) as? NSString, "payload")
41
+ }
42
+
43
+ func testPutReplacing_whenOccupied_returnsDisplaced() {
44
+ XCTAssertTrue(storage.putOrDiscard("k1" as NSString, value: "first" as NSString))
45
+ let displaced = storage.putReplacing("k1" as NSString, value: "second" as NSString)
46
+ XCTAssertEqual(displaced as? NSString, "first")
47
+ XCTAssertEqual(storage.get("k1" as NSString) as? NSString, "second")
48
+ }
49
+
50
+ func testGet_whenFree_isNil() {
51
+ XCTAssertNil(storage.get("missing" as NSString))
52
+ }
53
+
54
+ func testTake_removesAndReturns() {
55
+ XCTAssertTrue(storage.putOrDiscard("k1" as NSString, value: "payload" as NSString))
56
+ XCTAssertEqual(storage.take("k1" as NSString) as? NSString, "payload")
57
+ XCTAssertNil(storage.get("k1" as NSString))
58
+ }
59
+
60
+ func testTake_whenFree_isNil() {
61
+ XCTAssertNil(storage.take("missing" as NSString))
62
+ }
63
+
64
+ func testTakeAll_returnsSnapshotAndLeavesEmpty() {
65
+ XCTAssertTrue(storage.putOrDiscard("a" as NSString, value: "1" as NSString))
66
+ XCTAssertTrue(storage.putOrDiscard("b" as NSString, value: "2" as NSString))
67
+ let remaining = storage.takeAll()
68
+ XCTAssertEqual(remaining.count, 2)
69
+ XCTAssertNil(storage.get("a" as NSString))
70
+ XCTAssertNil(storage.get("b" as NSString))
71
+ }
72
+ }
@@ -0,0 +1,250 @@
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
+ import XCTest
18
+
19
+ final class RNFBAuthErrorCodeMapperTests: XCTestCase {
20
+ /// Sample of known FIRAuthErrorCode raw values → JS codes.
21
+ func testSampleKnownCodes() {
22
+ XCTAssertEqual(
23
+ RNFBAuthErrorCodeMapper.jsErrorCode(forAuthErrorCode: 17000),
24
+ "invalid-custom-token"
25
+ )
26
+ XCTAssertEqual(
27
+ RNFBAuthErrorCodeMapper.jsErrorCode(forAuthErrorCode: 17008),
28
+ "invalid-email"
29
+ )
30
+ XCTAssertEqual(
31
+ RNFBAuthErrorCodeMapper.jsErrorCode(forAuthErrorCode: 17020),
32
+ "network-request-failed"
33
+ )
34
+ XCTAssertEqual(
35
+ RNFBAuthErrorCodeMapper.jsErrorCode(forAuthErrorCode: 17057),
36
+ "cancelled-popup-request"
37
+ )
38
+ XCTAssertEqual(
39
+ RNFBAuthErrorCodeMapper.jsErrorCode(forAuthErrorCode: 17078),
40
+ "multi-factor-auth-required"
41
+ )
42
+ XCTAssertEqual(
43
+ RNFBAuthErrorCodeMapper.jsErrorCode(forAuthErrorCode: 17999),
44
+ "internal-error"
45
+ )
46
+ }
47
+
48
+ /// Pre-port quirk: MissingEmail (17034) maps to invalid-email, not missing-email.
49
+ func testMissingEmailMapsToInvalidEmail() {
50
+ XCTAssertEqual(
51
+ RNFBAuthErrorCodeMapper.jsErrorCode(forAuthErrorCode: 17034),
52
+ "invalid-email"
53
+ )
54
+ XCTAssertEqual(
55
+ RNFBAuthErrorCodeMapper.jsErrorCode(forAuthErrorCode: 17008),
56
+ "invalid-email"
57
+ )
58
+ }
59
+
60
+ func testUnknownCodeReturnsNil() {
61
+ XCTAssertNil(RNFBAuthErrorCodeMapper.jsErrorCode(forAuthErrorCode: 0))
62
+ XCTAssertNil(RNFBAuthErrorCodeMapper.jsErrorCode(forAuthErrorCode: 17001))
63
+ XCTAssertNil(RNFBAuthErrorCodeMapper.jsErrorCode(forAuthErrorCode: 99999))
64
+ XCTAssertNil(RNFBAuthErrorCodeMapper.jsErrorCode(forAuthErrorCode: -1))
65
+ }
66
+
67
+ /// Sample of known FIRAuthErrorCode raw values → JS message overrides.
68
+ func testSampleKnownMessageOverrides() {
69
+ XCTAssertEqual(
70
+ RNFBAuthErrorCodeMapper.jsErrorMessage(forAuthErrorCode: 17000),
71
+ "The custom token format is incorrect. Please check the documentation."
72
+ )
73
+ XCTAssertEqual(
74
+ RNFBAuthErrorCodeMapper.jsErrorMessage(forAuthErrorCode: 17008),
75
+ "The email address is badly formatted."
76
+ )
77
+ XCTAssertEqual(
78
+ RNFBAuthErrorCodeMapper.jsErrorMessage(forAuthErrorCode: 17020),
79
+ "A network error has occurred, please try again."
80
+ )
81
+ XCTAssertEqual(
82
+ RNFBAuthErrorCodeMapper.jsErrorMessage(forAuthErrorCode: 17078),
83
+ "Please complete a second factor challenge to finish signing into this account."
84
+ )
85
+ XCTAssertEqual(
86
+ RNFBAuthErrorCodeMapper.jsErrorMessage(forAuthErrorCode: 17999),
87
+ "An internal error has occurred, please try again."
88
+ )
89
+ XCTAssertEqual(
90
+ RNFBAuthErrorCodeMapper.jsErrorMessage(forAuthErrorCode: 17042),
91
+ "The format of the phone number provided is incorrect. "
92
+ + "Please enter the phone number in a format that can be parsed into E.164 format. "
93
+ + "E.164 phone numbers are written in the format [+][country code][subscriber "
94
+ + "number including area code]."
95
+ )
96
+ }
97
+
98
+ func testUnknownMessageOverrideReturnsNil() {
99
+ XCTAssertNil(RNFBAuthErrorCodeMapper.jsErrorMessage(forAuthErrorCode: 0))
100
+ XCTAssertNil(RNFBAuthErrorCodeMapper.jsErrorMessage(forAuthErrorCode: 17001))
101
+ XCTAssertNil(RNFBAuthErrorCodeMapper.jsErrorMessage(forAuthErrorCode: 17034))
102
+ XCTAssertNil(RNFBAuthErrorCodeMapper.jsErrorMessage(forAuthErrorCode: 99999))
103
+ XCTAssertNil(RNFBAuthErrorCodeMapper.jsErrorMessage(forAuthErrorCode: -1))
104
+ }
105
+
106
+ /// Full table — every pre-port `getJSError:` message override (coverage of switch DA).
107
+ func testAllPrePortMessageOverrides() {
108
+ let expected: [(Int, String)] = [
109
+ (
110
+ 17000,
111
+ "The custom token format is incorrect. Please check the documentation."
112
+ ),
113
+ (17002, "The custom token corresponds to a different audience."),
114
+ (17004, "The supplied auth credential is malformed or has expired."),
115
+ (17008, "The email address is badly formatted."),
116
+ (17009, "The password is invalid or the user does not have a password."),
117
+ (
118
+ 17024,
119
+ "The supplied credentials do not correspond to the previously signed in user."
120
+ ),
121
+ (
122
+ 17014,
123
+ "This operation is sensitive and requires recent authentication. Log in again "
124
+ + "before retrying this request."
125
+ ),
126
+ (
127
+ 17078,
128
+ "Please complete a second factor challenge to finish signing into this account."
129
+ ),
130
+ (
131
+ 17012,
132
+ "An account already exists with the same email address but different sign-in "
133
+ + "credentials. Sign in using a provider associated with this email address."
134
+ ),
135
+ (17007, "The email address is already in use by another account."),
136
+ (
137
+ 17025,
138
+ "This credential is already associated with a different user account."
139
+ ),
140
+ (17005, "The user account has been disabled by an administrator."),
141
+ (
142
+ 17021,
143
+ "The user's credential is no longer valid. The user must sign in again."
144
+ ),
145
+ (
146
+ 17011,
147
+ "There is no user record corresponding to this identifier. The user may have been "
148
+ + "deleted."
149
+ ),
150
+ (
151
+ 17017,
152
+ "The user's credential is no longer valid. The user must sign in again."
153
+ ),
154
+ (17026, "The given password is invalid."),
155
+ (
156
+ 17006,
157
+ "This operation is not allowed. You must enable this service in the console."
158
+ ),
159
+ (17020, "A network error has occurred, please try again."),
160
+ (17999, "An internal error has occurred, please try again."),
161
+ (
162
+ 17042,
163
+ "The format of the phone number provided is incorrect. "
164
+ + "Please enter the phone number in a format that can be parsed into E.164 format. "
165
+ + "E.164 phone numbers are written in the format [+][country code][subscriber "
166
+ + "number including area code]."
167
+ ),
168
+ ]
169
+
170
+ for (code, message) in expected {
171
+ XCTAssertEqual(
172
+ RNFBAuthErrorCodeMapper.jsErrorMessage(forAuthErrorCode: code),
173
+ message,
174
+ "FIRAuthErrorCode raw \(code) message override"
175
+ )
176
+ }
177
+ }
178
+
179
+ /// Full table — preserves every pre-port sparse-array entry (coverage of switch DA).
180
+ func testAllPrePortMappings() {
181
+ let expected: [(Int, String)] = [
182
+ (17000, "invalid-custom-token"),
183
+ (17002, "custom-token-mismatch"),
184
+ (17004, "invalid-credential"),
185
+ (17005, "user-disabled"),
186
+ (17006, "operation-not-allowed"),
187
+ (17007, "email-already-in-use"),
188
+ (17008, "invalid-email"),
189
+ (17009, "wrong-password"),
190
+ (17010, "too-many-requests"),
191
+ (17011, "user-not-found"),
192
+ (17012, "account-exists-with-different-credential"),
193
+ (17014, "requires-recent-login"),
194
+ (17015, "provider-already-linked"),
195
+ (17016, "no-such-provider"),
196
+ (17017, "invalid-user-token"),
197
+ (17020, "network-request-failed"),
198
+ (17021, "user-token-expired"),
199
+ (17023, "invalid-api-key"),
200
+ (17024, "user-mismatch"),
201
+ (17025, "credential-already-in-use"),
202
+ (17026, "weak-password"),
203
+ (17028, "app-not-authorized"),
204
+ (17029, "expired-action-code"),
205
+ (17030, "invalid-action-code"),
206
+ (17031, "invalid-message-payload"),
207
+ (17032, "invalid-sender"),
208
+ (17033, "invalid-recipient-email"),
209
+ (17034, "invalid-email"),
210
+ (17036, "missing-ios-bundle-id"),
211
+ (17037, "missing-android-pkg-name"),
212
+ (17038, "unauthorized-domain"),
213
+ (17039, "invalid-continue-uri"),
214
+ (17040, "missing-continue-uri"),
215
+ (17041, "missing-phone-number"),
216
+ (17042, "invalid-phone-number"),
217
+ (17043, "missing-verification-code"),
218
+ (17044, "invalid-verification-code"),
219
+ (17045, "missing-verification-id"),
220
+ (17046, "invalid-verification-id"),
221
+ (17047, "missing-app-credential"),
222
+ (17048, "invalid-app-credential"),
223
+ (17051, "code-expired"),
224
+ (17052, "quota-exceeded"),
225
+ (17053, "missing-apns-token"),
226
+ (17054, "notification-not-forwarded"),
227
+ (17055, "app-not-verified"),
228
+ (17056, "captcha-check-failed"),
229
+ (17057, "cancelled-popup-request"),
230
+ (17058, "popup-closed-by-user"),
231
+ (17059, "app-verification-user-interaction-failure"),
232
+ (17060, "invalid-oauth-client-id"),
233
+ (17061, "network-request-failed"),
234
+ (17062, "internal-error"),
235
+ (17067, "null-user"),
236
+ (17995, "keychain-error"),
237
+ (17999, "internal-error"),
238
+ (18000, "malformed-jwt"),
239
+ (17078, "multi-factor-auth-required"),
240
+ ]
241
+
242
+ for (code, js) in expected {
243
+ XCTAssertEqual(
244
+ RNFBAuthErrorCodeMapper.jsErrorCode(forAuthErrorCode: code),
245
+ js,
246
+ "FIRAuthErrorCode raw \(code)"
247
+ )
248
+ }
249
+ }
250
+ }
@@ -0,0 +1,122 @@
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
+ import XCTest
18
+
19
+ private final class FakeRemovableHandle: NSObject {
20
+ private(set) var removeCount = 0
21
+
22
+ @objc func remove() {
23
+ removeCount += 1
24
+ }
25
+ }
26
+
27
+ final class RNFBAuthListenerRegistryStorageTests: XCTestCase {
28
+ private var storage: RNFBAuthListenerRegistryStorage!
29
+
30
+ override func setUp() {
31
+ super.setUp()
32
+ storage = RNFBAuthListenerRegistryStorage()
33
+ }
34
+
35
+ func testPutIfAbsent_storesWhenFree() {
36
+ let handle = FakeRemovableHandle()
37
+ XCTAssertTrue(storage.putIfAbsent("k1" as NSString, value: handle))
38
+ XCTAssertTrue(storage.get("k1" as NSString) === handle)
39
+ XCTAssertEqual(handle.removeCount, 0)
40
+ }
41
+
42
+ func testPutIfAbsent_collision_keepsExistingWithoutRemove() {
43
+ let first = FakeRemovableHandle()
44
+ let second = FakeRemovableHandle()
45
+ XCTAssertTrue(storage.putIfAbsent("k1" as NSString, value: first))
46
+ XCTAssertFalse(storage.putIfAbsent("k1" as NSString, value: second))
47
+ XCTAssertTrue(storage.get("k1" as NSString) === first)
48
+ XCTAssertEqual(first.removeCount, 0)
49
+ XCTAssertEqual(second.removeCount, 0)
50
+ }
51
+
52
+ func testPutOrDiscard_storesWhenFree() {
53
+ let handle = FakeRemovableHandle()
54
+ XCTAssertTrue(storage.putOrDiscard("k1" as NSString, value: handle))
55
+ XCTAssertTrue(storage.get("k1" as NSString) === handle)
56
+ XCTAssertEqual(handle.removeCount, 0)
57
+ }
58
+
59
+ func testPutOrDiscard_collision_removesIncoming() {
60
+ let first = FakeRemovableHandle()
61
+ let duplicate = FakeRemovableHandle()
62
+ XCTAssertTrue(storage.putOrDiscard("k1" as NSString, value: first))
63
+ XCTAssertFalse(storage.putOrDiscard("k1" as NSString, value: duplicate))
64
+ XCTAssertEqual(duplicate.removeCount, 1)
65
+ XCTAssertEqual(first.removeCount, 0)
66
+ XCTAssertTrue(storage.get("k1" as NSString) === first)
67
+ }
68
+
69
+ func testGet_whenFree_isNil() {
70
+ XCTAssertNil(storage.get("missing" as NSString))
71
+ }
72
+
73
+ func testTake_removesAndReturnsWithoutCallingRemove() {
74
+ let handle = FakeRemovableHandle()
75
+ XCTAssertTrue(storage.putIfAbsent("k1" as NSString, value: handle))
76
+ XCTAssertTrue(storage.take("k1" as NSString) === handle)
77
+ XCTAssertNil(storage.get("k1" as NSString))
78
+ XCTAssertEqual(handle.removeCount, 0)
79
+ }
80
+
81
+ func testTake_whenFree_isNil() {
82
+ XCTAssertNil(storage.take("missing" as NSString))
83
+ }
84
+
85
+ func testTakeAndRemove_removesAfterTake() {
86
+ let handle = FakeRemovableHandle()
87
+ XCTAssertTrue(storage.putIfAbsent("k1" as NSString, value: handle))
88
+ storage.takeAndRemove("k1" as NSString)
89
+ XCTAssertEqual(handle.removeCount, 1)
90
+ XCTAssertNil(storage.get("k1" as NSString))
91
+ }
92
+
93
+ func testTakeAndRemove_missingKey_isNoOp() {
94
+ storage.takeAndRemove("missing" as NSString)
95
+ }
96
+
97
+ func testTakeAndRemove_objectWithoutRemove_doesNotCrash() {
98
+ let plain = NSObject()
99
+ XCTAssertTrue(storage.putIfAbsent("plain" as NSString, value: plain))
100
+ storage.takeAndRemove("plain" as NSString)
101
+ XCTAssertNil(storage.get("plain" as NSString))
102
+ }
103
+
104
+ func testRemoveAll_removesSnapshotAndLeavesEmpty() {
105
+ let a = FakeRemovableHandle()
106
+ let b = FakeRemovableHandle()
107
+ XCTAssertTrue(storage.putIfAbsent("a" as NSString, value: a))
108
+ XCTAssertTrue(storage.putIfAbsent("b" as NSString, value: b))
109
+ storage.removeAll()
110
+ XCTAssertEqual(a.removeCount, 1)
111
+ XCTAssertEqual(b.removeCount, 1)
112
+ XCTAssertNil(storage.get("a" as NSString))
113
+ XCTAssertNil(storage.get("b" as NSString))
114
+ }
115
+
116
+ func testRemoveAll_objectWithoutRemove_doesNotCrash() {
117
+ let plain = NSObject()
118
+ XCTAssertTrue(storage.putIfAbsent("plain" as NSString, value: plain))
119
+ storage.removeAll()
120
+ XCTAssertNil(storage.get("plain" as NSString))
121
+ }
122
+ }
@@ -0,0 +1,78 @@
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 <XCTest/XCTest.h>
19
+
20
+ #import "RNFBAuthNullSentinelDecoder.h"
21
+
22
+ @interface RNFBAuthNullSentinelDecodeTests : XCTestCase
23
+ @end
24
+
25
+ @implementation RNFBAuthNullSentinelDecodeTests
26
+
27
+ - (NSDictionary *)nullSentinel {
28
+ return @{@"__rnfbNull" : @YES};
29
+ }
30
+
31
+ - (NSDictionary *)unrelatedOneKeyDictionary {
32
+ return @{@".sv" : @"timestamp"};
33
+ }
34
+
35
+ - (void)testUpdateProfile_displayNameNullSentinel_becomesNil {
36
+ NSDictionary *props = @{@"displayName" : [self nullSentinel]};
37
+ NSDictionary *decoded = [RNFBAuthNullSentinelDecoder decodedProfileProps:props];
38
+ XCTAssertNil(decoded[@"displayName"]);
39
+ XCTAssertFalse([decoded[@"displayName"] isKindOfClass:[NSDictionary class]]);
40
+ }
41
+
42
+ - (void)testUpdateProfile_photoURLNullSentinel_becomesNil {
43
+ NSDictionary *props = @{@"photoURL" : [self nullSentinel]};
44
+ NSDictionary *decoded = [RNFBAuthNullSentinelDecoder decodedProfileProps:props];
45
+ XCTAssertNil(decoded[@"photoURL"]);
46
+ XCTAssertFalse([decoded[@"photoURL"] isKindOfClass:[NSDictionary class]]);
47
+ // Same path updateProfile uses: seam omit → subscript nil → clear arm (nil, not URLWithString:).
48
+ XCTAssertNil([RNFBAuthNullSentinelDecoder photoURLFromDecodedValue:decoded[@"photoURL"]]);
49
+ }
50
+
51
+ - (void)testUpdateProfile_photoURLFromDecodedValue_nilClearsWithoutURLWithString {
52
+ XCTAssertNil([RNFBAuthNullSentinelDecoder photoURLFromDecodedValue:nil]);
53
+ }
54
+
55
+ - (void)testUpdateProfile_photoURLFromDecodedValue_stringBecomesNSURL {
56
+ NSURL *url = [RNFBAuthNullSentinelDecoder photoURLFromDecodedValue:@"https://example.com/a.jpg"];
57
+ XCTAssertEqualObjects(url.absoluteString, @"https://example.com/a.jpg");
58
+ }
59
+
60
+ - (void)testUpdateProfile_displayNameNSNull_becomesNil {
61
+ NSDictionary *props = @{@"displayName" : [NSNull null]};
62
+ NSDictionary *decoded = [RNFBAuthNullSentinelDecoder decodedProfileProps:props];
63
+ XCTAssertNil(decoded[@"displayName"]);
64
+ }
65
+
66
+ - (void)testUpdateProfile_photoURLNSNull_becomesNil {
67
+ NSDictionary *props = @{@"photoURL" : [NSNull null]};
68
+ NSDictionary *decoded = [RNFBAuthNullSentinelDecoder decodedProfileProps:props];
69
+ XCTAssertNil(decoded[@"photoURL"]);
70
+ }
71
+
72
+ - (void)testUpdateProfile_unrelatedOneKeyDictionary_unchanged {
73
+ NSDictionary *props = @{@"displayName" : [self unrelatedOneKeyDictionary]};
74
+ NSDictionary *decoded = [RNFBAuthNullSentinelDecoder decodedProfileProps:props];
75
+ XCTAssertEqualObjects(decoded[@"displayName"], [self unrelatedOneKeyDictionary]);
76
+ }
77
+
78
+ @end
@@ -12,7 +12,17 @@
12
12
  A9000000000000000000000C /* RNFBAuthListenerRegistryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A90000000000000000000009 /* RNFBAuthListenerRegistryTests.m */; };
13
13
  A9000000000000000000001E /* RNFBAuthCacheRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = A9000000000000000000001C /* RNFBAuthCacheRegistry.m */; };
14
14
  A9000000000000000000001F /* RNFBAuthCacheRegistryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A9000000000000000000001D /* RNFBAuthCacheRegistryTests.m */; };
15
+ A90000000000000000000030 /* RNFBNullSentinelDecoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90000000000000000000031 /* RNFBNullSentinelDecoding.swift */; };
16
+ A90000000000000000000032 /* RNFBAuthNullSentinelDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = A90000000000000000000033 /* RNFBAuthNullSentinelDecoder.m */; };
17
+ A90000000000000000000038 /* RNFBAuthNullSentinelDecodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A90000000000000000000039 /* RNFBAuthNullSentinelDecodeTests.m */; };
15
18
  A90000000000000000000015 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A90000000000000000000014 /* XCTest.framework */; };
19
+ A90000000000000000000020 /* RNFBHandleMapStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90000000000000000000021 /* RNFBHandleMapStorage.swift */; };
20
+ A90000000000000000000022 /* RNFBAuthCacheRegistryStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90000000000000000000023 /* RNFBAuthCacheRegistryStorage.swift */; };
21
+ A90000000000000000000024 /* RNFBAuthCacheRegistryStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90000000000000000000025 /* RNFBAuthCacheRegistryStorageTests.swift */; };
22
+ A90000000000000000000026 /* RNFBAuthListenerRegistryStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90000000000000000000027 /* RNFBAuthListenerRegistryStorage.swift */; };
23
+ A90000000000000000000028 /* RNFBAuthListenerRegistryStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90000000000000000000029 /* RNFBAuthListenerRegistryStorageTests.swift */; };
24
+ A9000000000000000000002A /* RNFBAuthErrorCodeMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9000000000000000000002B /* RNFBAuthErrorCodeMapper.swift */; };
25
+ A9000000000000000000002C /* RNFBAuthErrorCodeMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9000000000000000000002D /* RNFBAuthErrorCodeMapperTests.swift */; };
16
26
  /* End PBXBuildFile section */
17
27
 
18
28
  /* Begin PBXFileReference section */
@@ -25,7 +35,18 @@
25
35
  A90000000000000000000019 /* RNFBAuthCacheRegistry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBAuthCacheRegistry.h; path = ../RNFBAuth/RNFBAuthCacheRegistry.h; sourceTree = SOURCE_ROOT; };
26
36
  A9000000000000000000001C /* RNFBAuthCacheRegistry.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBAuthCacheRegistry.m; path = ../RNFBAuth/RNFBAuthCacheRegistry.m; sourceTree = SOURCE_ROOT; };
27
37
  A9000000000000000000001D /* RNFBAuthCacheRegistryTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBAuthCacheRegistryTests.m; sourceTree = "<group>"; };
38
+ A90000000000000000000031 /* RNFBNullSentinelDecoding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBNullSentinelDecoding.swift; path = ../../../app/ios/RNFBApp/RNFBNullSentinelDecoding.swift; sourceTree = SOURCE_ROOT; };
39
+ A90000000000000000000033 /* RNFBAuthNullSentinelDecoder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBAuthNullSentinelDecoder.m; path = ../RNFBAuth/RNFBAuthNullSentinelDecoder.m; sourceTree = SOURCE_ROOT; };
40
+ A9000000000000000000003B /* RNFBAuthNullSentinelDecoder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBAuthNullSentinelDecoder.h; path = ../RNFBAuth/RNFBAuthNullSentinelDecoder.h; sourceTree = SOURCE_ROOT; };
41
+ A90000000000000000000039 /* RNFBAuthNullSentinelDecodeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBAuthNullSentinelDecodeTests.m; sourceTree = "<group>"; };
28
42
  A90000000000000000000014 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/MacOSX.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
43
+ A90000000000000000000021 /* RNFBHandleMapStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBHandleMapStorage.swift; path = ../../../app/ios/RNFBApp/RNFBHandleMapStorage.swift; sourceTree = SOURCE_ROOT; };
44
+ A90000000000000000000023 /* RNFBAuthCacheRegistryStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBAuthCacheRegistryStorage.swift; path = ../RNFBAuth/RNFBAuthCacheRegistryStorage.swift; sourceTree = SOURCE_ROOT; };
45
+ A90000000000000000000025 /* RNFBAuthCacheRegistryStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNFBAuthCacheRegistryStorageTests.swift; sourceTree = "<group>"; };
46
+ A90000000000000000000027 /* RNFBAuthListenerRegistryStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBAuthListenerRegistryStorage.swift; path = ../RNFBAuth/RNFBAuthListenerRegistryStorage.swift; sourceTree = SOURCE_ROOT; };
47
+ A90000000000000000000029 /* RNFBAuthListenerRegistryStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNFBAuthListenerRegistryStorageTests.swift; sourceTree = "<group>"; };
48
+ A9000000000000000000002B /* RNFBAuthErrorCodeMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBAuthErrorCodeMapper.swift; path = ../RNFBAuth/RNFBAuthErrorCodeMapper.swift; sourceTree = SOURCE_ROOT; };
49
+ A9000000000000000000002D /* RNFBAuthErrorCodeMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNFBAuthErrorCodeMapperTests.swift; sourceTree = "<group>"; };
29
50
  /* End PBXFileReference section */
30
51
 
31
52
  /* Begin PBXFrameworksBuildPhase section */
@@ -61,12 +82,23 @@
61
82
  children = (
62
83
  A90000000000000000000007 /* RNFBHandleMap.h */,
63
84
  A90000000000000000000008 /* RNFBHandleMap.m */,
85
+ A90000000000000000000021 /* RNFBHandleMapStorage.swift */,
64
86
  A90000000000000000000016 /* RNFBAuthListenerRegistry.h */,
65
87
  A90000000000000000000018 /* RNFBAuthListenerRegistry.m */,
88
+ A90000000000000000000027 /* RNFBAuthListenerRegistryStorage.swift */,
66
89
  A90000000000000000000009 /* RNFBAuthListenerRegistryTests.m */,
90
+ A90000000000000000000029 /* RNFBAuthListenerRegistryStorageTests.swift */,
67
91
  A90000000000000000000019 /* RNFBAuthCacheRegistry.h */,
68
92
  A9000000000000000000001C /* RNFBAuthCacheRegistry.m */,
93
+ A90000000000000000000023 /* RNFBAuthCacheRegistryStorage.swift */,
69
94
  A9000000000000000000001D /* RNFBAuthCacheRegistryTests.m */,
95
+ A90000000000000000000031 /* RNFBNullSentinelDecoding.swift */,
96
+ A9000000000000000000003B /* RNFBAuthNullSentinelDecoder.h */,
97
+ A90000000000000000000033 /* RNFBAuthNullSentinelDecoder.m */,
98
+ A90000000000000000000039 /* RNFBAuthNullSentinelDecodeTests.m */,
99
+ A90000000000000000000025 /* RNFBAuthCacheRegistryStorageTests.swift */,
100
+ A9000000000000000000002B /* RNFBAuthErrorCodeMapper.swift */,
101
+ A9000000000000000000002D /* RNFBAuthErrorCodeMapperTests.swift */,
70
102
  );
71
103
  name = Sources;
72
104
  sourceTree = "<group>";
@@ -129,10 +161,20 @@
129
161
  buildActionMask = 2147483647;
130
162
  files = (
131
163
  A9000000000000000000000A /* RNFBHandleMap.m in Sources */,
164
+ A90000000000000000000020 /* RNFBHandleMapStorage.swift in Sources */,
132
165
  A9000000000000000000000B /* RNFBAuthListenerRegistry.m in Sources */,
166
+ A90000000000000000000026 /* RNFBAuthListenerRegistryStorage.swift in Sources */,
133
167
  A9000000000000000000000C /* RNFBAuthListenerRegistryTests.m in Sources */,
168
+ A90000000000000000000028 /* RNFBAuthListenerRegistryStorageTests.swift in Sources */,
134
169
  A9000000000000000000001E /* RNFBAuthCacheRegistry.m in Sources */,
170
+ A90000000000000000000022 /* RNFBAuthCacheRegistryStorage.swift in Sources */,
135
171
  A9000000000000000000001F /* RNFBAuthCacheRegistryTests.m in Sources */,
172
+ A90000000000000000000030 /* RNFBNullSentinelDecoding.swift in Sources */,
173
+ A90000000000000000000032 /* RNFBAuthNullSentinelDecoder.m in Sources */,
174
+ A90000000000000000000038 /* RNFBAuthNullSentinelDecodeTests.m in Sources */,
175
+ A90000000000000000000024 /* RNFBAuthCacheRegistryStorageTests.swift in Sources */,
176
+ A9000000000000000000002A /* RNFBAuthErrorCodeMapper.swift in Sources */,
177
+ A9000000000000000000002C /* RNFBAuthErrorCodeMapperTests.swift in Sources */,
136
178
  );
137
179
  runOnlyForDeploymentPostprocessing = 0;
138
180
  };
@@ -181,8 +223,10 @@
181
223
  CODE_SIGNING_REQUIRED = NO;
182
224
  CODE_SIGN_IDENTITY = "-";
183
225
  COMBINE_HIDPI_IMAGES = YES;
226
+ DEFINES_MODULE = YES;
184
227
  GENERATE_INFOPLIST_FILE = YES;
185
228
  HEADER_SEARCH_PATHS = (
229
+ "$(SRCROOT)",
186
230
  "$(SRCROOT)/../../../app/ios",
187
231
  "$(SRCROOT)/../../../app/ios/RNFBApp",
188
232
  "$(SRCROOT)/../RNFBAuth",
@@ -204,6 +248,8 @@
204
248
  PRODUCT_NAME = "$(TARGET_NAME)";
205
249
  SDKROOT = macosx;
206
250
  SUPPORTED_PLATFORMS = macosx;
251
+ SWIFT_OBJC_INTERFACE_HEADER_NAME = "RNFBHandleMapStorage-Swift.inc";
252
+ SWIFT_VERSION = 5.10;
207
253
  };
208
254
  name = Debug;
209
255
  };
@@ -215,8 +261,10 @@
215
261
  CODE_SIGNING_REQUIRED = NO;
216
262
  CODE_SIGN_IDENTITY = "-";
217
263
  COMBINE_HIDPI_IMAGES = YES;
264
+ DEFINES_MODULE = YES;
218
265
  GENERATE_INFOPLIST_FILE = YES;
219
266
  HEADER_SEARCH_PATHS = (
267
+ "$(SRCROOT)",
220
268
  "$(SRCROOT)/../../../app/ios",
221
269
  "$(SRCROOT)/../../../app/ios/RNFBApp",
222
270
  "$(SRCROOT)/../RNFBAuth",
@@ -231,6 +279,8 @@
231
279
  PRODUCT_NAME = "$(TARGET_NAME)";
232
280
  SDKROOT = macosx;
233
281
  SUPPORTED_PLATFORMS = macosx;
282
+ SWIFT_OBJC_INTERFACE_HEADER_NAME = "RNFBHandleMapStorage-Swift.inc";
283
+ SWIFT_VERSION = 5.10;
234
284
  };
235
285
  name = Release;
236
286
  };
package/lib/index.ts CHANGED
@@ -47,11 +47,11 @@ import {
47
47
  parseListenerOrObserver,
48
48
  } from '@react-native-firebase/app/dist/module/common';
49
49
  import type { ReactNativeFirebase } from '@react-native-firebase/app';
50
- import { setReactNativeModule } from '@react-native-firebase/app/dist/module/internal/nativeModule';
51
50
  import {
52
51
  FirebaseModule,
53
52
  getOrCreateModularInstance,
54
53
  type ModuleConfig,
54
+ setReactNativeModule,
55
55
  } from '@react-native-firebase/app/dist/module/internal';
56
56
  import ConfirmationResultClass from './ConfirmationResult';
57
57
  import { ActionCodeURL } from './ActionCodeURL';
@@ -20,8 +20,8 @@ import type {} from '@react-native-firebase/app/dist/module/internal/NativeModul
20
20
  import type {
21
21
  ModuleConfig,
22
22
  NativeErrorUserInfo,
23
+ ReactNativeFirebaseEventEmitter,
23
24
  } from '@react-native-firebase/app/dist/module/types/internal';
24
- import type EventEmitter from 'react-native/Libraries/vendor/emitter/EventEmitter';
25
25
  import type {
26
26
  ActionCodeInfo,
27
27
  ActionCodeSettings,
@@ -411,7 +411,7 @@ export type AuthInternal = Auth & {
411
411
  verifyPasswordResetCode(code: string): Promise<string>;
412
412
  revokeToken(authorizationCode: string): Promise<void>;
413
413
  native: RNFBAuthModule;
414
- emitter: EventEmitter;
414
+ emitter: ReactNativeFirebaseEventEmitter;
415
415
  eventNameForApp(...args: Array<string | number>): string;
416
416
  _config: ModuleConfig;
417
417
  _tenantId: string | null;