react-native-oauth-essentials 1.0.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 (41) hide show
  1. package/LICENSE +20 -0
  2. package/OauthEssentials.podspec +22 -0
  3. package/README.md +30 -0
  4. package/android/build.gradle +74 -0
  5. package/android/src/main/AndroidManifest.xml +22 -0
  6. package/android/src/main/java/com/oauthessentials/CredentialError.kt +7 -0
  7. package/android/src/main/java/com/oauthessentials/CredentialFactory.kt +114 -0
  8. package/android/src/main/java/com/oauthessentials/CustomTabsActivity.kt +133 -0
  9. package/android/src/main/java/com/oauthessentials/OauthEssentialsModule.kt +603 -0
  10. package/android/src/main/java/com/oauthessentials/OauthEssentialsPackage.kt +33 -0
  11. package/android/src/main/java/com/oauthessentials/RCTPromiseSettler.kt +60 -0
  12. package/ios/AppleIdRetriever.swift +61 -0
  13. package/ios/CredentialError.swift +6 -0
  14. package/ios/CredentialFactory.swift +133 -0
  15. package/ios/CredentialsType.swift +7 -0
  16. package/ios/GoogleIdRetriever.swift +83 -0
  17. package/ios/HybridRetriever.swift +64 -0
  18. package/ios/OauthEssentials.h +8 -0
  19. package/ios/OauthEssentials.mm +104 -0
  20. package/ios/OauthEssentialsModule.swift +210 -0
  21. package/ios/PasskeyRetriever.swift +226 -0
  22. package/ios/PasswordRetriever.swift +72 -0
  23. package/ios/RCTPromiseSettler.swift +28 -0
  24. package/lib/module/NativeOauthEssentials.js +5 -0
  25. package/lib/module/NativeOauthEssentials.js.map +1 -0
  26. package/lib/module/index.js +148 -0
  27. package/lib/module/index.js.map +1 -0
  28. package/lib/module/package.json +1 -0
  29. package/lib/module/types.js +23 -0
  30. package/lib/module/types.js.map +1 -0
  31. package/lib/typescript/package.json +1 -0
  32. package/lib/typescript/src/NativeOauthEssentials.d.ts +60 -0
  33. package/lib/typescript/src/NativeOauthEssentials.d.ts.map +1 -0
  34. package/lib/typescript/src/index.d.ts +78 -0
  35. package/lib/typescript/src/index.d.ts.map +1 -0
  36. package/lib/typescript/src/types.d.ts +71 -0
  37. package/lib/typescript/src/types.d.ts.map +1 -0
  38. package/package.json +156 -0
  39. package/src/NativeOauthEssentials.ts +75 -0
  40. package/src/index.tsx +199 -0
  41. package/src/types.ts +79 -0
@@ -0,0 +1,61 @@
1
+ import AuthenticationServices
2
+ import React
3
+
4
+ public class AppleIdRetriever: RCTPromiseSettler,
5
+ ASAuthorizationControllerDelegate,
6
+ ASAuthorizationControllerPresentationContextProviding {
7
+
8
+ override init(
9
+ resolve: @escaping RCTPromiseResolveBlock,
10
+ reject: @escaping RCTPromiseRejectBlock,
11
+ emitEvent: ((String, NSDictionary) -> Void)?
12
+ ) {
13
+ super.init(resolve: resolve, reject: reject, emitEvent: emitEvent)
14
+
15
+ let controller = ASAuthorizationController(authorizationRequests: [
16
+ ASAuthorizationAppleIDProvider().createRequest(),
17
+ ])
18
+
19
+ controller.delegate = self
20
+ controller.presentationContextProvider = self
21
+
22
+ if #available(iOS 16.0, *) {
23
+ controller.performRequests(options: .preferImmediatelyAvailableCredentials)
24
+ } else {
25
+ controller.performRequests()
26
+ }
27
+ }
28
+
29
+ public func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
30
+ return UIWindow()
31
+ }
32
+
33
+ public func authorizationController(
34
+ controller: ASAuthorizationController,
35
+ didCompleteWithAuthorization authorization: ASAuthorization
36
+ ) {
37
+ if let appleIdCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
38
+ let result = CredentialFactory.fromAppleId(appleIdCredential: appleIdCredential)
39
+ self.resolve?(result)
40
+ self.emitEvent?("onCredentialSuccess", result as NSDictionary)
41
+ cleanup()
42
+ }
43
+ }
44
+
45
+ public func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
46
+ let nsError = error as NSError
47
+ if nsError.domain == ASAuthorizationError.errorDomain,
48
+ nsError.code == ASAuthorizationError.canceled.rawValue {
49
+
50
+ let result = CredentialFactory.fromCancelled()
51
+ self.resolve?(result)
52
+ self.emitEvent?("onCredentialSuccess", result as NSDictionary)
53
+ } else {
54
+ self.emitEvent?("onCredentialFailure", [
55
+ "code": CredentialError.invalidResult.rawValue,
56
+ "message": error.localizedDescription
57
+ ])
58
+ }
59
+ cleanup()
60
+ }
61
+ }
@@ -0,0 +1,6 @@
1
+ public enum CredentialError: String {
2
+ case noSignInAvailable = "NO_SIGN_IN_AVAILABLE"
3
+ case invalidResult = "INVALID_RESULT_ERROR"
4
+ case simultaneousCallError = "SIMULTANEOUS_CALL_ERROR"
5
+ case notSupportedError = "NOT_SUPPORTED_ERROR"
6
+ }
@@ -0,0 +1,133 @@
1
+ import AuthenticationServices
2
+ import GoogleSignIn
3
+
4
+ class CredentialFactory {
5
+
6
+ public static func fromCancelled() -> [String: Any] {
7
+ return [
8
+ "type": CredentialsType.cancelled.rawValue,
9
+ "data": NSNull()
10
+ ]
11
+ }
12
+
13
+ public static func fromAppleId(appleIdCredential: ASAuthorizationAppleIDCredential) -> [String: Any] {
14
+ let idToken: Any =
15
+ appleIdCredential.identityToken
16
+ .flatMap { String(data: $0, encoding: .utf8) } ?? NSNull()
17
+
18
+ let authorizationCode: Any =
19
+ appleIdCredential.authorizationCode
20
+ .flatMap { String(data: $0, encoding: .utf8) } ?? NSNull()
21
+
22
+ let fullName =
23
+ appleIdCredential.fullName
24
+ .flatMap { PersonNameComponentsFormatter().string(from: $0) } ?? ""
25
+
26
+ let data: [String: Any] = [
27
+ "idToken": idToken,
28
+ "authorizationCode": authorizationCode,
29
+ "user": appleIdCredential.user,
30
+ "email": appleIdCredential.email ?? "",
31
+ "fullName": fullName,
32
+ "likelyReal": appleIdCredential.realUserStatus == .likelyReal
33
+ ]
34
+
35
+ let result: [String: Any] = [
36
+ "type": CredentialsType.appleId.rawValue,
37
+ "data": data
38
+ ]
39
+
40
+ return result
41
+ }
42
+
43
+ public static func fromPassword(credential: ASPasswordCredential) -> [String: Any] {
44
+ let data: [String: Any] = [
45
+ "username": credential.user, "password": credential.password
46
+ ]
47
+ let result: [String: Any] = [
48
+ "type": CredentialsType.password.rawValue,
49
+ "data": data
50
+ ]
51
+ return result
52
+ }
53
+
54
+ @available(iOS 16.0, *)
55
+ public static func fromPasskeyRegistration(credential: ASAuthorizationPlatformPublicKeyCredentialRegistration) -> [String: Any] {
56
+ let responseJson: [String: Any] = [
57
+ "id": base64URLEncode(credential.credentialID),
58
+ "rawId": base64URLEncode(credential.credentialID),
59
+ "type": "public-key",
60
+ "response": [
61
+ "clientDataJSON": base64URLEncode(credential.rawClientDataJSON),
62
+ "attestationObject": base64URLEncode(credential.rawAttestationObject ?? Data())
63
+ ]
64
+ ]
65
+
66
+ guard let jsonData = try? JSONSerialization.data(withJSONObject: responseJson),
67
+ let jsonString = String(data: jsonData, encoding: .utf8) else {
68
+ return [
69
+ "type": CredentialsType.passkey.rawValue,
70
+ "data": "{}"
71
+ ]
72
+ }
73
+
74
+ return [
75
+ "type": CredentialsType.passkey.rawValue,
76
+ "data": jsonString
77
+ ]
78
+ }
79
+
80
+ @available(iOS 16.0, *)
81
+ public static func fromPasskeyAssertion(credential: ASAuthorizationPlatformPublicKeyCredentialAssertion) -> [String: Any] {
82
+ let responseJson: [String: Any] = [
83
+ "id": base64URLEncode(credential.credentialID),
84
+ "rawId": base64URLEncode(credential.credentialID),
85
+ "type": "public-key",
86
+ "response": [
87
+ "clientDataJSON": base64URLEncode(credential.rawClientDataJSON),
88
+ "authenticatorData": base64URLEncode(credential.rawAuthenticatorData),
89
+ "signature": base64URLEncode(credential.signature),
90
+ "userHandle": base64URLEncode(credential.userID)
91
+ ]
92
+ ]
93
+
94
+ guard let jsonData = try? JSONSerialization.data(withJSONObject: responseJson),
95
+ let jsonString = String(data: jsonData, encoding: .utf8) else {
96
+ return [
97
+ "type": CredentialsType.passkey.rawValue,
98
+ "data": "{}"
99
+ ]
100
+ }
101
+
102
+ return [
103
+ "type": CredentialsType.passkey.rawValue,
104
+ "data": jsonString
105
+ ]
106
+ }
107
+
108
+ private static func base64URLEncode(_ data: Data) -> String {
109
+ return data.base64EncodedString()
110
+ .replacingOccurrences(of: "+", with: "-")
111
+ .replacingOccurrences(of: "/", with: "_")
112
+ .replacingOccurrences(of: "=", with: "")
113
+ }
114
+
115
+ public static func fromGoogleId(user: GIDGoogleUser) -> [String: Any] {
116
+ let profile = user.profile
117
+ let data: [String: Any] = [
118
+ "idToken": user.idToken?.tokenString ?? "",
119
+ "id": user.userID ?? "",
120
+ "displayName": profile?.name ?? "",
121
+ "givenName": profile?.givenName ?? "",
122
+ "familyName": profile?.familyName ?? "",
123
+ "profilePictureUri": profile?.imageURL(withDimension: 200)?.absoluteString ?? "",
124
+ "email": profile?.email ?? ""
125
+ ]
126
+
127
+ let result: [String: Any] = [
128
+ "type": CredentialsType.googleId.rawValue,
129
+ "data": data
130
+ ]
131
+ return result
132
+ }
133
+ }
@@ -0,0 +1,7 @@
1
+ public enum CredentialsType: String {
2
+ case googleId = "GOOGLE_ID"
3
+ case password = "PASSWORD"
4
+ case appleId = "APPLE_ID"
5
+ case cancelled = "CANCELLED"
6
+ case passkey = "PASSKEY"
7
+ }
@@ -0,0 +1,83 @@
1
+ import GoogleSignIn
2
+ import React
3
+
4
+ public class GoogleIdRetriever: RCTPromiseSettler {
5
+
6
+ init(
7
+ clientId: String,
8
+ options: NSDictionary,
9
+ resolve: @escaping RCTPromiseResolveBlock,
10
+ reject: @escaping RCTPromiseRejectBlock,
11
+ emitEvent: ((String, NSDictionary) -> Void)?
12
+ ) {
13
+ super.init(resolve: resolve, reject: reject, emitEvent: emitEvent)
14
+ performGoogleSignIn(clientId:clientId, options: options)
15
+ }
16
+
17
+ private func performGoogleSignIn(clientId: String, options: NSDictionary) {
18
+ var rootVC: UIViewController?
19
+ DispatchQueue.main.sync {
20
+ if #available(iOS 13.0, *) {
21
+ rootVC = UIApplication.shared.connectedScenes
22
+ .compactMap { $0 as? UIWindowScene }
23
+ .flatMap { $0.windows }
24
+ .first { $0.isKeyWindow }?
25
+ .rootViewController
26
+ } else {
27
+ rootVC = UIApplication.shared.keyWindow?.rootViewController
28
+ }
29
+ }
30
+
31
+ guard let rootVC = rootVC else {
32
+ self.reject?(
33
+ CredentialError.noSignInAvailable.rawValue,
34
+ "No root view controller available",
35
+ nil
36
+ )
37
+ self.emitEvent?("onCredentialFailure", [
38
+ "code": CredentialError.noSignInAvailable.rawValue,
39
+ "message": "No root view controller available"
40
+ ])
41
+
42
+ self.cleanup()
43
+ return
44
+ }
45
+
46
+ GIDSignIn.sharedInstance.configuration = GIDConfiguration(clientID: clientId)
47
+ GIDSignIn.sharedInstance.signIn(withPresenting: rootVC) { result, error in
48
+
49
+ if let error = error {
50
+ let nsError = error as NSError
51
+ if nsError.code == GIDSignInError.canceled.rawValue {
52
+ let result = CredentialFactory.fromCancelled()
53
+ self.resolve?(result)
54
+ self.emitEvent?("onCredentialSuccess", result as NSDictionary)
55
+ } else {
56
+ self.reject?(CredentialError.invalidResult.rawValue, error.localizedDescription, error)
57
+ self.emitEvent?("onCredentialFailure", [
58
+ "code": CredentialError.invalidResult.rawValue,
59
+ "message": error.localizedDescription
60
+ ])
61
+ }
62
+ self.cleanup()
63
+ return
64
+ }
65
+
66
+ guard let user = result?.user else {
67
+ self.reject?(CredentialError.invalidResult.rawValue, "No user returned", nil)
68
+ self.emitEvent?("onCredentialFailure", [
69
+ "code": CredentialError.invalidResult.rawValue,
70
+ "message": "No user returned"
71
+ ])
72
+
73
+ self.cleanup()
74
+ return
75
+ }
76
+
77
+ let result = CredentialFactory.fromGoogleId(user: user)
78
+ self.resolve?(result)
79
+ self.emitEvent?("onCredentialSuccess", result as NSDictionary)
80
+ self.cleanup()
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,64 @@
1
+ import AuthenticationServices
2
+ import React
3
+
4
+ public class HybridRetriever: RCTPromiseSettler,
5
+ ASAuthorizationControllerDelegate,
6
+ ASAuthorizationControllerPresentationContextProviding {
7
+
8
+ init(
9
+ clientId: String,
10
+ options: NSDictionary,
11
+ resolve: @escaping RCTPromiseResolveBlock,
12
+ reject: @escaping RCTPromiseRejectBlock,
13
+ emitEvent: ((String, NSDictionary) -> Void)?
14
+ ) {
15
+ super.init(resolve: resolve, reject: reject, emitEvent: emitEvent)
16
+
17
+ let controller = ASAuthorizationController(authorizationRequests: [
18
+ ASAuthorizationAppleIDProvider().createRequest(),
19
+ ASAuthorizationPasswordProvider().createRequest()
20
+ ])
21
+
22
+ controller.delegate = self
23
+ controller.presentationContextProvider = self
24
+
25
+ if #available(iOS 16.0, *) {
26
+ controller.performRequests(options: .preferImmediatelyAvailableCredentials)
27
+ } else {
28
+ controller.performRequests()
29
+ }
30
+ }
31
+
32
+ public func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
33
+ return UIWindow()
34
+ }
35
+
36
+ public func authorizationController(
37
+ controller: ASAuthorizationController,
38
+ didCompleteWithAuthorization authorization: ASAuthorization
39
+ ) {
40
+ if let appleIdCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
41
+ let result = CredentialFactory.fromAppleId(appleIdCredential: appleIdCredential)
42
+ self.resolve?(result)
43
+ self.emitEvent?("onCredentialSuccess", result as NSDictionary)
44
+ }
45
+ else if let credential = authorization.credential as? ASPasswordCredential {
46
+ let result = CredentialFactory.fromPassword(credential: credential)
47
+ self.resolve?(result)
48
+ self.emitEvent?("onCredentialSuccess", result as NSDictionary)
49
+ }
50
+ cleanup()
51
+ }
52
+
53
+ public func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
54
+ self.reject?(
55
+ CredentialError.invalidResult.rawValue,
56
+ error.localizedDescription,
57
+ error
58
+ )
59
+ self.emitEvent?("onCredentialFailure", [
60
+ "code": CredentialError.invalidResult.rawValue,
61
+ "message": error.localizedDescription
62
+ ])
63
+ }
64
+ }
@@ -0,0 +1,8 @@
1
+ #import <OauthEssentialsSpec/OauthEssentialsSpec.h>
2
+
3
+ @interface OauthEssentials : NativeOauthEssentialsSpecBase <NativeOauthEssentialsSpec>
4
+
5
+ - (void)emitOnCredentialSuccess:(NSDictionary *)value;
6
+ - (void)emitOnCredentialFailure:(NSDictionary *)value;
7
+
8
+ @end
@@ -0,0 +1,104 @@
1
+ #import "OauthEssentials.h"
2
+ #import <AuthenticationServices/AuthenticationServices.h>
3
+ #import "OauthEssentials-Swift.h"
4
+
5
+
6
+ @implementation OauthEssentials {
7
+ OauthEssentialsModule *_sModule;
8
+ }
9
+
10
+ - (instancetype)init
11
+ {
12
+ self = [super init];
13
+ if (self) {
14
+ __weak OauthEssentials *weakSelf = self;
15
+
16
+ _sModule = [[OauthEssentialsModule alloc]
17
+ initOnCredentialSuccess:^(NSDictionary * _Nonnull value) {
18
+ [weakSelf emitOnCredentialSuccess:value];
19
+ } onCredentialFailure:^(NSDictionary * _Nonnull value) {
20
+ [weakSelf emitOnCredentialSuccess:value];
21
+ }];
22
+ }
23
+ return self;
24
+ }
25
+
26
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
27
+ (const facebook::react::ObjCTurboModule::InitParams &)params
28
+ {
29
+ return std::make_shared<facebook::react::NativeOauthEssentialsSpecJSI>(params);
30
+ }
31
+
32
+ + (NSString *)moduleName
33
+ {
34
+ return @"OauthEssentials";
35
+ }
36
+
37
+ // Constants
38
+ - (NSDictionary *)getConstants
39
+ {
40
+ return [_sModule getConstants];
41
+ }
42
+
43
+ // Methods
44
+ - (void)googleSignIn:(NSString *)clientId
45
+ options:(NSDictionary *)options
46
+ resolve:(RCTPromiseResolveBlock)resolve
47
+ reject:(RCTPromiseRejectBlock)reject
48
+ {
49
+ [_sModule googleSignIn:clientId
50
+ options:options
51
+ resolver:resolve
52
+ rejecter:reject];
53
+ }
54
+
55
+ - (void)passwordSignIn:(NSString *)username
56
+ password:(NSString *)password
57
+ resolve:(RCTPromiseResolveBlock)resolve
58
+ reject:(RCTPromiseRejectBlock)reject
59
+ {
60
+ [_sModule passwordSignIn:username
61
+ password:password
62
+ resolver:resolve
63
+ rejecter:reject];
64
+ }
65
+
66
+ - (void)getPassword:(RCTPromiseResolveBlock)resolve
67
+ reject:(RCTPromiseRejectBlock)reject
68
+ {
69
+ [_sModule getPassword:resolve
70
+ rejecter:reject];
71
+ }
72
+
73
+
74
+ - (void)hybridSignIn:(NSString *)clientId
75
+ options:(NSDictionary *)options
76
+ resolve:(RCTPromiseResolveBlock)resolve
77
+ reject:(RCTPromiseRejectBlock)reject
78
+ {
79
+ [_sModule hybridSignIn:clientId options:options resolver:resolve rejecter:reject];
80
+ }
81
+
82
+ - (void)appleSignIn:(NSString *)webAndroidUrl
83
+ resolve:(RCTPromiseResolveBlock)resolve
84
+ reject:(RCTPromiseRejectBlock)reject {
85
+ [_sModule appleSignIn:webAndroidUrl resolver:resolve rejecter:reject];
86
+ }
87
+
88
+ - (void)createPassKey:(NSDictionary *)options
89
+ resolve:(RCTPromiseResolveBlock)resolve
90
+ reject:(RCTPromiseRejectBlock)reject {
91
+ [_sModule createPassKey:options resolver:resolve rejecter:reject];
92
+ }
93
+
94
+ - (void)getPassKey:(NSDictionary *)options
95
+ resolve:(RCTPromiseResolveBlock)resolve
96
+ reject:(RCTPromiseRejectBlock)reject {
97
+ [_sModule getPassKey:options resolver:resolve rejecter:reject];
98
+ }
99
+
100
+ - (facebook::react::ModuleConstants<JS::NativeOauthEssentials::Constants>) constantsToExport {
101
+ return (facebook::react::ModuleConstants<JS::NativeOauthEssentials::Constants>)[_sModule getConstants];
102
+ }
103
+
104
+ @end
@@ -0,0 +1,210 @@
1
+ import Foundation
2
+ import React
3
+ import GoogleSignIn
4
+ import AuthenticationServices
5
+ import Security
6
+ import UIKit
7
+
8
+ public class OauthEssentialsModule: NSObject {
9
+
10
+ public var onCredentialSuccess: ((NSDictionary) -> Void)?
11
+ public var onCredentialFailure: ((NSDictionary) -> Void)?
12
+
13
+ private var _password_retriever: PasswordRetriever? = nil
14
+ private var _google_id_retriever: GoogleIdRetriever? = nil
15
+ private var _apple_id_retriever: AppleIdRetriever? = nil
16
+ private var _hybrid_retriever: HybridRetriever? = nil
17
+ private var _passkey_retriever: RCTPromiseSettler? = nil
18
+
19
+ @objc
20
+ public init(
21
+ onCredentialSuccess: @escaping ((NSDictionary) -> Void),
22
+ onCredentialFailure: @escaping ((NSDictionary) -> Void)
23
+ ) {
24
+ super.init()
25
+
26
+ self.onCredentialSuccess = onCredentialSuccess
27
+ self.onCredentialFailure = onCredentialFailure
28
+ }
29
+
30
+ private func ensurePreviousPromiseSettled(settler: RCTPromiseSettler?, reject: RCTPromiseRejectBlock) -> Bool {
31
+ if settler == nil || (settler != nil && ((settler?.settled()) != nil)) {
32
+ return true
33
+ }
34
+
35
+ reject(
36
+ CredentialError.simultaneousCallError.rawValue,
37
+ "Another operation is in progress",
38
+ nil
39
+ )
40
+ return false
41
+ }
42
+
43
+ @objc(requiresMainQueueSetup)
44
+ static func requiresMainQueueSetup() -> Bool { true }
45
+
46
+ @objc
47
+ public func getConstants() -> [String: Any] {
48
+ var googleIdSupported: Bool = false
49
+ var appleIdSupported: Bool = false
50
+ var passwordSupported: Bool = false
51
+ var passkeySupported = false
52
+ if #available(iOS 13.0, *) {
53
+ // Modern GoogleSignIn works on iOS 13+
54
+ googleIdSupported = true
55
+ appleIdSupported = true
56
+ passwordSupported = true
57
+ }
58
+ if #available(iOS 16.0, *) {
59
+ passkeySupported = true
60
+ }
61
+
62
+ return [
63
+ "GOOGLE_ID_SUPPORTED": googleIdSupported,
64
+ "PASSWORD_SUPPORTED": passwordSupported,
65
+ "GOOGLE_PLAY_SERVICES_SUPPORTED": false, // Not applicable on iOS, it does not have Google Play Services
66
+ "APPLE_ID_SUPPORTED": appleIdSupported,
67
+ "HYBRID_SUPPORTED": true,
68
+ "PASSKEY_SUPPORTED": passkeySupported
69
+ ]
70
+ }
71
+
72
+ @objc
73
+ public func googleSignIn(
74
+ _ clientId: String,
75
+ options: NSDictionary,
76
+ resolver resolve: @escaping RCTPromiseResolveBlock,
77
+ rejecter reject: @escaping RCTPromiseRejectBlock
78
+ ) {
79
+ if (ensurePreviousPromiseSettled(settler: self._google_id_retriever,reject: reject)) {
80
+ self._google_id_retriever = GoogleIdRetriever(clientId: clientId, options: options,resolve: resolve,reject: reject, emitEvent: emitEvent)
81
+ }
82
+ }
83
+
84
+ @objc
85
+ public func passwordSignIn(
86
+ _ username: String,
87
+ password: String,
88
+ resolver resolve: @escaping RCTPromiseResolveBlock,
89
+ rejecter reject: @escaping RCTPromiseRejectBlock
90
+ ) {
91
+ if (ensurePreviousPromiseSettled(settler: self._apple_id_retriever, reject: reject)) {
92
+ self._apple_id_retriever = AppleIdRetriever(resolve: resolve, reject: reject, emitEvent: self.emitEvent)
93
+ }
94
+ }
95
+
96
+ @objc
97
+ public func getPassword(
98
+ _ resolve: @escaping RCTPromiseResolveBlock,
99
+ rejecter reject: @escaping RCTPromiseRejectBlock
100
+ ) {
101
+ if (ensurePreviousPromiseSettled(settler: self._password_retriever,reject: reject)) {
102
+ self._password_retriever = PasswordRetriever(resolve: resolve,reject: reject, emitEvent: self.emitEvent)
103
+ }
104
+ }
105
+
106
+ @objc
107
+ public func hybridSignIn(
108
+ _ clientId: String,
109
+ options: NSDictionary,
110
+ resolver resolve: @escaping RCTPromiseResolveBlock,
111
+ rejecter reject: @escaping RCTPromiseRejectBlock) {
112
+ if (ensurePreviousPromiseSettled(settler: self._hybrid_retriever,reject: reject)) {
113
+ self._hybrid_retriever = HybridRetriever(clientId: clientId, options: options, resolve: resolve, reject: reject, emitEvent: emitEvent)
114
+ }
115
+ }
116
+
117
+ @objc(createPassKey:resolver:rejecter:)
118
+ public func createPassKey(
119
+ _ options: NSDictionary,
120
+ resolver resolve: @escaping RCTPromiseResolveBlock,
121
+ rejecter reject: @escaping RCTPromiseRejectBlock
122
+ ) {
123
+ guard #available(iOS 16.0, *) else {
124
+ reject(
125
+ CredentialError.notSupportedError.rawValue,
126
+ "Passkeys require iOS 16.0 or later",
127
+ nil
128
+ )
129
+ return
130
+ }
131
+
132
+ if ensurePreviousPromiseSettled(settler: self._passkey_retriever, reject: reject) {
133
+ guard let requestJson = options["requestJson"] as? String else {
134
+ reject(
135
+ CredentialError.invalidResult.rawValue,
136
+ "\"requestJson\" field is required",
137
+ nil
138
+ )
139
+ return
140
+ }
141
+
142
+ self._passkey_retriever = PasskeyRetriever(
143
+ requestJson: requestJson,
144
+ mode: .registration,
145
+ resolve: resolve,
146
+ reject: reject,
147
+ emitEvent: emitEvent
148
+ )
149
+ }
150
+ }
151
+
152
+ @objc(getPassKey:resolver:rejecter:)
153
+ public func getPassKey(
154
+ _ options: NSDictionary,
155
+ resolver resolve: @escaping RCTPromiseResolveBlock,
156
+ rejecter reject: @escaping RCTPromiseRejectBlock
157
+ ) {
158
+ guard #available(iOS 16.0, *) else {
159
+ reject(
160
+ CredentialError.notSupportedError.rawValue,
161
+ "Passkeys require iOS 16.0 or later",
162
+ nil
163
+ )
164
+ return
165
+ }
166
+
167
+ if ensurePreviousPromiseSettled(settler: self._passkey_retriever, reject: reject) {
168
+ guard let requestJson = options["requestJson"] as? String else {
169
+ reject(
170
+ CredentialError.invalidResult.rawValue,
171
+ "\"requestJson\" field is required",
172
+ nil
173
+ )
174
+ return
175
+ }
176
+
177
+ self._passkey_retriever = PasskeyRetriever(
178
+ requestJson: requestJson,
179
+ mode: .assertion,
180
+ resolve: resolve,
181
+ reject: reject,
182
+ emitEvent: emitEvent
183
+ )
184
+ }
185
+ }
186
+
187
+ @objc(appleSignIn:resolver:rejecter:)
188
+ public func appleSignIn(
189
+ _ webAndroidUrl: String,
190
+ resolver resolve: @escaping RCTPromiseResolveBlock,
191
+ rejecter reject: @escaping RCTPromiseRejectBlock
192
+ ) {
193
+ if (ensurePreviousPromiseSettled(settler: self._apple_id_retriever,reject: reject)) {
194
+ self._apple_id_retriever = AppleIdRetriever(resolve: resolve,reject: reject, emitEvent: emitEvent)
195
+ }
196
+ }
197
+
198
+ private func emitEvent(eventName: String, body: NSDictionary) {
199
+ switch eventName {
200
+ case "onCredentialSuccess":
201
+ onCredentialSuccess?(body)
202
+
203
+ case "onCredentialFailure":
204
+ onCredentialFailure?(body)
205
+
206
+ default:
207
+ print("Unhandled event found: \(eventName)")
208
+ }
209
+ }
210
+ }