react-native-authsignal 1.0.13 → 1.1.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 (22) hide show
  1. package/android/build.gradle +27 -87
  2. package/android/gradle/wrapper/gradle-wrapper.properties +3 -2
  3. package/android/gradle.properties +4 -3
  4. package/android/src/main/java/com/authsignal/react/AuthenticationActivity.kt +69 -0
  5. package/android/src/main/java/com/authsignal/react/AuthsignalEmailModule.kt +113 -0
  6. package/android/src/main/java/com/authsignal/react/AuthsignalModule.kt +115 -0
  7. package/android/src/main/java/com/authsignal/react/AuthsignalPackage.kt +23 -0
  8. package/android/src/main/java/com/authsignal/react/AuthsignalPasskeyModule.kt +103 -0
  9. package/android/src/main/java/com/authsignal/react/AuthsignalPushModule.kt +152 -0
  10. package/android/src/main/java/com/authsignal/react/AuthsignalSMSModule.kt +117 -0
  11. package/android/src/main/java/com/authsignal/react/AuthsignalTOTPModule.kt +95 -0
  12. package/android/src/main/java/com/authsignal/react/RedirectActivity.kt +17 -0
  13. package/package.json +1 -1
  14. package/android/src/main/java/com/authsignal/react/AuthenticationActivity.java +0 -73
  15. package/android/src/main/java/com/authsignal/react/AuthsignalEmailModule.java +0 -139
  16. package/android/src/main/java/com/authsignal/react/AuthsignalModule.java +0 -127
  17. package/android/src/main/java/com/authsignal/react/AuthsignalPackage.java +0 -29
  18. package/android/src/main/java/com/authsignal/react/AuthsignalPasskeyModule.java +0 -133
  19. package/android/src/main/java/com/authsignal/react/AuthsignalPushModule.java +0 -188
  20. package/android/src/main/java/com/authsignal/react/AuthsignalSMSModule.java +0 -139
  21. package/android/src/main/java/com/authsignal/react/AuthsignalTOTPModule.java +0 -116
  22. package/android/src/main/java/com/authsignal/react/RedirectActivity.java +0 -18
@@ -1,24 +1,19 @@
1
1
  buildscript {
2
+ def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["Authsignal_kotlinVersion"]
3
+
2
4
  repositories {
3
5
  google()
4
6
  mavenCentral()
5
7
  }
6
8
 
7
9
  dependencies {
8
- classpath 'com.android.tools.build:gradle:7.4.2'
10
+ classpath 'com.android.tools.build:gradle:8.1.4'
11
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
9
12
  }
10
13
  }
11
14
 
12
- def isNewArchitectureEnabled() {
13
- return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
14
- }
15
-
16
15
  apply plugin: 'com.android.library'
17
-
18
-
19
- if (isNewArchitectureEnabled()) {
20
- apply plugin: 'com.facebook.react'
21
- }
16
+ apply plugin: 'org.jetbrains.kotlin.android'
22
17
 
23
18
  def getExtOrDefault(name) {
24
19
  return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['Authsignal_' + name]
@@ -29,13 +24,21 @@ def getExtOrIntegerDefault(name) {
29
24
  }
30
25
 
31
26
  android {
27
+ namespace "com.authsignal"
28
+
29
+ sourceSets {
30
+ main {
31
+ manifest.srcFile "src/main/AndroidManifestNew.xml"
32
+ }
33
+ }
34
+
32
35
  compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
33
36
 
34
37
  defaultConfig {
35
38
  minSdkVersion getExtOrIntegerDefault('minSdkVersion')
36
39
  targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
37
- buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
38
40
  }
41
+
39
42
  buildTypes {
40
43
  release {
41
44
  minifyEnabled false
@@ -47,95 +50,32 @@ android {
47
50
  }
48
51
 
49
52
  compileOptions {
50
- sourceCompatibility JavaVersion.VERSION_1_8
51
- targetCompatibility JavaVersion.VERSION_1_8
53
+ sourceCompatibility JavaVersion.VERSION_17
54
+ targetCompatibility JavaVersion.VERSION_17
55
+ }
56
+
57
+ kotlinOptions {
58
+ jvmTarget = '17'
52
59
  }
53
60
 
61
+ buildFeatures {
62
+ buildConfig true
63
+ }
54
64
  }
55
65
 
56
66
  repositories {
57
67
  mavenCentral()
58
68
  google()
59
-
60
- def found = false
61
- def defaultDir = null
62
- def androidSourcesName = 'React Native sources'
63
-
64
- if (rootProject.ext.has('reactNativeAndroidRoot')) {
65
- defaultDir = rootProject.ext.get('reactNativeAndroidRoot')
66
- } else {
67
- defaultDir = new File(
68
- projectDir,
69
- '/../../../node_modules/react-native/android'
70
- )
71
- }
72
-
73
- if (defaultDir.exists()) {
74
- maven {
75
- url defaultDir.toString()
76
- name androidSourcesName
77
- }
78
-
79
- logger.info(":${project.name}:reactNativeAndroidRoot ${defaultDir.canonicalPath}")
80
- found = true
81
- } else {
82
- def parentDir = rootProject.projectDir
83
-
84
- 1.upto(5, {
85
- if (found) return true
86
- parentDir = parentDir.parentFile
87
-
88
- def androidSourcesDir = new File(
89
- parentDir,
90
- 'node_modules/react-native'
91
- )
92
-
93
- def androidPrebuiltBinaryDir = new File(
94
- parentDir,
95
- 'node_modules/react-native/android'
96
- )
97
-
98
- if (androidPrebuiltBinaryDir.exists()) {
99
- maven {
100
- url androidPrebuiltBinaryDir.toString()
101
- name androidSourcesName
102
- }
103
-
104
- logger.info(":${project.name}:reactNativeAndroidRoot ${androidPrebuiltBinaryDir.canonicalPath}")
105
- found = true
106
- } else if (androidSourcesDir.exists()) {
107
- maven {
108
- url androidSourcesDir.toString()
109
- name androidSourcesName
110
- }
111
-
112
- logger.info(":${project.name}:reactNativeAndroidRoot ${androidSourcesDir.canonicalPath}")
113
- found = true
114
- }
115
- })
116
- }
117
-
118
- if (!found) {
119
- throw new GradleException(
120
- "${project.name}: unable to locate React Native android sources. " +
121
- "Ensure you have you installed React Native as a dependency in your project and try again."
122
- )
123
- }
124
69
  }
125
70
 
71
+ def kotlin_version = getExtOrDefault("kotlinVersion")
72
+
126
73
  dependencies {
127
74
  //noinspection GradleDynamicVersion
128
75
  implementation "com.facebook.react:react-native:+"
76
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
129
77
 
130
78
  implementation "androidx.browser:browser:1.2.0"
131
79
 
132
- implementation("com.authsignal:authsignal-android:1.0.15")
133
- }
134
-
135
- if (isNewArchitectureEnabled()) {
136
- react {
137
- jsRootDir = file("../src/")
138
- libraryName = "Authsignal"
139
- codegenJavaPackageName = "com.reactnativeauthsignal"
140
- }
80
+ implementation("com.authsignal:authsignal-android:1.1.2")
141
81
  }
@@ -1,6 +1,7 @@
1
- #Fri Aug 16 14:14:32 NZST 2024
2
1
  distributionBase=GRADLE_USER_HOME
3
2
  distributionPath=wrapper/dists
4
- distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
3
+ distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip
4
+ networkTimeout=10000
5
+ validateDistributionUrl=true
5
6
  zipStoreBase=GRADLE_USER_HOME
6
7
  zipStorePath=wrapper/dists
@@ -1,5 +1,6 @@
1
+ Authsignal_kotlinVersion=1.9.24
1
2
  Authsignal_minSdkVersion=24
2
- Authsignal_targetSdkVersion=33
3
- Authsignal_compileSdkVersion=33
4
- Authsignal_ndkversion=21.4.7075529
3
+ Authsignal_targetSdkVersion=34
4
+ Authsignal_compileSdkVersion=34
5
+ Authsignal_ndkversion=26.1.10909125
5
6
  android.useAndroidX=true
@@ -0,0 +1,69 @@
1
+ package com.authsignal.react
2
+
3
+ import android.app.Activity
4
+ import android.content.Intent
5
+ import android.net.Uri
6
+ import android.os.Bundle
7
+ import androidx.browser.customtabs.CustomTabsIntent
8
+
9
+ class AuthenticationActivity : Activity() {
10
+ private var intentLaunched = false
11
+
12
+ override fun onCreate(savedInstanceState: Bundle?) {
13
+ super.onCreate(savedInstanceState)
14
+ if (savedInstanceState != null) {
15
+ intentLaunched = savedInstanceState.getBoolean(EXTRA_INTENT_LAUNCHED, false)
16
+ }
17
+ }
18
+
19
+ override fun onResume() {
20
+ super.onResume()
21
+ val authenticationIntent = intent
22
+
23
+ if (!intentLaunched && authenticationIntent.extras == null) {
24
+ finish()
25
+ return
26
+ } else if (!intentLaunched) {
27
+ intentLaunched = true
28
+ launchAuthenticationIntent()
29
+ return
30
+ }
31
+
32
+ val resultMissing = authenticationIntent.data == null
33
+ if (resultMissing) setResult(RESULT_CANCELED)
34
+ else setResult(RESULT_OK, authenticationIntent)
35
+ finish()
36
+ }
37
+
38
+ override fun onSaveInstanceState(outState: Bundle) {
39
+ super.onSaveInstanceState(outState)
40
+ outState.putBoolean(EXTRA_INTENT_LAUNCHED, intentLaunched)
41
+ }
42
+
43
+ override fun onNewIntent(intent: Intent?) {
44
+ super.onNewIntent(intent)
45
+ setIntent(intent)
46
+ }
47
+
48
+ private fun launchAuthenticationIntent() {
49
+ val extras = intent.extras
50
+ val authorizeUri = extras!!.getParcelable<Uri>(EXTRA_AUTHORIZE_URI)
51
+ val builder = CustomTabsIntent.Builder()
52
+ val customTabsIntent = builder.build()
53
+ customTabsIntent.launchUrl(this, authorizeUri!!)
54
+ }
55
+
56
+ companion object {
57
+ const val AUTHENTICATION_REQUEST: Int = 1000
58
+ const val EXTRA_AUTHORIZE_URI: String = "com.authsignal.react.EXTRA_AUTHORIZE_URI"
59
+ private const val EXTRA_INTENT_LAUNCHED = "com.authsignal.react.EXTRA_INTENT_LAUNCHED"
60
+
61
+ @JvmStatic
62
+ fun authenticateUsingBrowser(activity: Activity, authorizeUri: Uri) {
63
+ val intent = Intent(activity, AuthenticationActivity::class.java)
64
+ intent.putExtra(EXTRA_AUTHORIZE_URI, authorizeUri)
65
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
66
+ activity.startActivityForResult(intent, AUTHENTICATION_REQUEST)
67
+ }
68
+ }
69
+ }
@@ -0,0 +1,113 @@
1
+ package com.authsignal.react
2
+
3
+ import android.util.Log
4
+ import com.authsignal.email.AuthsignalEmail
5
+ import com.facebook.react.bridge.Arguments
6
+ import com.facebook.react.bridge.Promise
7
+ import com.facebook.react.bridge.ReactApplicationContext
8
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
9
+ import com.facebook.react.bridge.ReactMethod
10
+ import kotlinx.coroutines.CoroutineScope
11
+ import kotlinx.coroutines.Dispatchers
12
+ import kotlinx.coroutines.SupervisorJob
13
+ import kotlinx.coroutines.launch
14
+
15
+ class AuthsignalEmailModule(private val reactContext: ReactApplicationContext) :
16
+ ReactContextBaseJavaModule(
17
+ reactContext
18
+ ) {
19
+ private var authsignal: AuthsignalEmail? = null
20
+
21
+ private val defaultError = "unexpected_error"
22
+
23
+ private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
24
+
25
+ override fun getConstants(): Map<String, Any>? {
26
+ val constants: MutableMap<String, Any> = HashMap()
27
+ constants["bundleIdentifier"] = reactContext.applicationInfo.packageName
28
+ return constants
29
+ }
30
+
31
+ override fun getName(): String {
32
+ return "AuthsignalEmailModule"
33
+ }
34
+
35
+ @ReactMethod
36
+ fun initialize(tenantID: String, baseURL: String, promise: Promise) {
37
+ val currentActivity = reactContext.currentActivity
38
+
39
+ if (currentActivity != null) {
40
+ authsignal = AuthsignalEmail(tenantID, baseURL)
41
+ }
42
+
43
+ promise.resolve(null)
44
+ }
45
+
46
+ @ReactMethod
47
+ fun enroll(email: String, promise: Promise) {
48
+ launch(promise) {
49
+ val response = it.enroll(email)
50
+
51
+ if (response.error != null) {
52
+ val errorCode = response.errorType ?: defaultError
53
+
54
+ promise.reject(errorCode, response.error)
55
+ } else {
56
+ val enrollResponse = response.data
57
+ val map = Arguments.createMap()
58
+ map.putString("userAuthenticatorId", enrollResponse!!.userAuthenticatorId)
59
+ promise.resolve(map)
60
+ }
61
+ }
62
+ }
63
+
64
+ @ReactMethod
65
+ fun challenge(promise: Promise) {
66
+ launch(promise) {
67
+ val response = it.challenge()
68
+
69
+ if (response.error != null) {
70
+ val errorCode = response.errorType ?: defaultError
71
+
72
+ promise.reject(errorCode, response.error)
73
+ } else {
74
+ val challengeResponse = response.data
75
+ val map = Arguments.createMap()
76
+ map.putString("challengeId", challengeResponse!!.challengeId)
77
+ promise.resolve(map)
78
+ }
79
+ }
80
+ }
81
+
82
+ @ReactMethod
83
+ fun verify(code: String, promise: Promise) {
84
+ launch(promise) {
85
+ val response = it.verify(code)
86
+
87
+ if (response.error != null) {
88
+ val errorCode = response.errorType ?: defaultError
89
+
90
+ promise.reject(errorCode, response.error)
91
+ } else {
92
+ val verifyResponse = response.data
93
+ val map = Arguments.createMap()
94
+ map.putBoolean("isVerified", verifyResponse!!.isVerified)
95
+ map.putString("token", verifyResponse.token)
96
+ map.putString("failureReason", verifyResponse.failureReason)
97
+ promise.resolve(map)
98
+ }
99
+ }
100
+ }
101
+
102
+ private fun launch(promise: Promise, fn: suspend (client: AuthsignalEmail) -> Unit) {
103
+ coroutineScope.launch {
104
+ authsignal?.let {
105
+ fn(it)
106
+ } ?: run {
107
+ Log.w("init_error", "AuthsignalEmailModule is not initialized.")
108
+
109
+ promise.resolve(null)
110
+ }
111
+ }
112
+ }
113
+ }
@@ -0,0 +1,115 @@
1
+ package com.authsignal.react
2
+
3
+ import android.app.Activity
4
+ import android.content.ActivityNotFoundException
5
+ import android.content.Intent
6
+ import android.net.Uri
7
+ import com.authsignal.TokenCache.Companion.shared
8
+ import com.authsignal.react.AuthenticationActivity.Companion.authenticateUsingBrowser
9
+ import com.facebook.react.bridge.ActivityEventListener
10
+ import com.facebook.react.bridge.Arguments
11
+ import com.facebook.react.bridge.Callback
12
+ import com.facebook.react.bridge.Promise
13
+ import com.facebook.react.bridge.ReactApplicationContext
14
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
15
+ import com.facebook.react.bridge.ReactMethod
16
+ import java.net.URLDecoder
17
+
18
+ class AuthsignalModule(private val reactContext: ReactApplicationContext) :
19
+ ReactContextBaseJavaModule(
20
+ reactContext
21
+ ), ActivityEventListener {
22
+ private var callback: Callback? = null
23
+
24
+ init {
25
+ reactContext.addActivityEventListener(this)
26
+ }
27
+
28
+ override fun getConstants(): Map<String, Any>? {
29
+ val constants: MutableMap<String, Any> = HashMap()
30
+ constants["bundleIdentifier"] = reactContext.applicationInfo.packageName
31
+ return constants
32
+ }
33
+
34
+ override fun getName(): String {
35
+ return "AuthsignalModule"
36
+ }
37
+
38
+ @ReactMethod
39
+ fun setToken(token: String?, promise: Promise) {
40
+ shared.token = token
41
+
42
+ promise.resolve("token_set")
43
+ }
44
+
45
+ @ReactMethod
46
+ fun launch(url: String?, callback: Callback) {
47
+ val activity = currentActivity
48
+ val parsedUrl = Uri.parse(url)
49
+ this.callback = callback
50
+
51
+ try {
52
+ if (activity != null) {
53
+ authenticateUsingBrowser(activity, parsedUrl)
54
+ } else {
55
+ val error = Arguments.createMap()
56
+ error.putString("error", "activity_not_available")
57
+ error.putString("error_description", "Android Activity is null.")
58
+ callback.invoke(error)
59
+ }
60
+ } catch (e: ActivityNotFoundException) {
61
+ val error = Arguments.createMap()
62
+ error.putString("error", "browser_not_available")
63
+ error.putString("error_description", "No browser app is installed")
64
+ callback.invoke(error)
65
+ }
66
+ }
67
+
68
+ override fun onActivityResult(
69
+ activity: Activity,
70
+ requestCode: Int,
71
+ resultCode: Int,
72
+ data: Intent?
73
+ ) {
74
+ val cb = this@AuthsignalModule.callback ?: return
75
+
76
+ val hasResult =
77
+ resultCode == Activity.RESULT_OK && requestCode == AuthenticationActivity.AUTHENTICATION_REQUEST && data!!.data != null
78
+
79
+ if (hasResult) {
80
+ try {
81
+ val redirectUrl = data!!.data.toString()
82
+ val query = redirectUrl.split("[?]".toRegex()).dropLastWhile { it.isEmpty() }
83
+ .toTypedArray()[1]
84
+ val pairs = query.split("&".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
85
+ var token: String? = null
86
+ for (pair in pairs) {
87
+ val index = pair.indexOf("=")
88
+ val name = URLDecoder.decode(pair.substring(0, index), "UTF-8")
89
+ val value = URLDecoder.decode(pair.substring(index + 1), "UTF-8")
90
+ if (name == "token") {
91
+ token = value
92
+
93
+ shared.token = value
94
+ }
95
+ }
96
+ cb.invoke(null, token)
97
+ } catch (ex: Exception) {
98
+ val error = Arguments.createMap()
99
+ error.putString("error", "malformed_url")
100
+ error.putString("error_description", "Malformed redirect url")
101
+ cb.invoke(error)
102
+ }
103
+ } else {
104
+ val error = Arguments.createMap()
105
+ error.putString("error", "user_cancelled")
106
+ error.putString("error_description", "User cancelled")
107
+ cb.invoke(error)
108
+ }
109
+
110
+ this@AuthsignalModule.callback = null
111
+ }
112
+
113
+ override fun onNewIntent(intent: Intent) {
114
+ }
115
+ }
@@ -0,0 +1,23 @@
1
+ package com.authsignal.react
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+ class AuthsignalPackage : ReactPackage {
9
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
10
+ return listOf<NativeModule>(
11
+ AuthsignalModule(reactContext),
12
+ AuthsignalEmailModule(reactContext),
13
+ AuthsignalPasskeyModule(reactContext),
14
+ AuthsignalPushModule(reactContext),
15
+ AuthsignalSMSModule(reactContext),
16
+ AuthsignalTOTPModule(reactContext)
17
+ )
18
+ }
19
+
20
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
21
+ return emptyList()
22
+ }
23
+ }
@@ -0,0 +1,103 @@
1
+ package com.authsignal.react
2
+
3
+ import android.util.Log
4
+ import com.authsignal.passkey.AuthsignalPasskey
5
+ import com.facebook.react.bridge.Arguments
6
+ import com.facebook.react.bridge.Promise
7
+ import com.facebook.react.bridge.ReactApplicationContext
8
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
9
+ import com.facebook.react.bridge.ReactMethod
10
+ import kotlinx.coroutines.CoroutineScope
11
+ import kotlinx.coroutines.Dispatchers
12
+ import kotlinx.coroutines.SupervisorJob
13
+ import kotlinx.coroutines.launch
14
+
15
+ class AuthsignalPasskeyModule(private val reactContext: ReactApplicationContext) :
16
+ ReactContextBaseJavaModule(reactContext) {
17
+ private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
18
+ private var authsignal: AuthsignalPasskey? = null
19
+ private var defaultError = "unexpected_error"
20
+
21
+ override fun getConstants(): Map<String, Any>? {
22
+ val constants: MutableMap<String, Any> = HashMap()
23
+ constants["bundleIdentifier"] = reactContext.applicationInfo.packageName
24
+ return constants
25
+ }
26
+
27
+ override fun getName(): String {
28
+ return "AuthsignalPasskeyModule"
29
+ }
30
+
31
+ @ReactMethod
32
+ fun initialize(tenantID: String, baseURL: String, promise: Promise) {
33
+ val activity = reactContext.currentActivity
34
+
35
+ if (activity != null) {
36
+ authsignal = AuthsignalPasskey(tenantID, baseURL, activity)
37
+ }
38
+
39
+ promise.resolve(null)
40
+ }
41
+
42
+ @ReactMethod
43
+ fun signUp(token: String?, username: String?, displayName: String?, promise: Promise) {
44
+ launch(promise) {
45
+ val response = it.signUp(token, username, displayName)
46
+
47
+ if (response.error != null) {
48
+ val errorCode = response.errorType ?: defaultError
49
+
50
+ promise.reject(errorCode, response.error)
51
+ } else {
52
+ val signUpResponse = response.data
53
+ val map = Arguments.createMap()
54
+ map.putString("token", signUpResponse!!.token)
55
+ promise.resolve(map)
56
+ }
57
+ }
58
+ }
59
+
60
+ @ReactMethod
61
+ fun signIn(action: String?, token: String?, promise: Promise) {
62
+ launch(promise) {
63
+ val response = it.signIn(action, token)
64
+
65
+ if (response.error != null) {
66
+ val errorCode = response.errorType ?: defaultError
67
+
68
+ promise.reject(errorCode, response.error)
69
+ } else {
70
+ val signInResponse = response.data
71
+ val map = Arguments.createMap()
72
+ map.putBoolean("isVerified", signInResponse!!.isVerified)
73
+ map.putString("token", signInResponse.token)
74
+ map.putString("userId", signInResponse.userId)
75
+ map.putString("userAuthenticatorId", signInResponse.userAuthenticatorId)
76
+ map.putString("username", signInResponse.username)
77
+ map.putString("displayName", signInResponse.displayName)
78
+ promise.resolve(map)
79
+ }
80
+ }
81
+ }
82
+
83
+ @ReactMethod
84
+ fun isAvailableOnDevice(promise: Promise) {
85
+ launch(promise) {
86
+ val response = it.isAvailableOnDevice()
87
+
88
+ promise.resolve(response.data ?: false)
89
+ }
90
+ }
91
+
92
+ private fun launch(promise: Promise, fn: suspend (client: AuthsignalPasskey) -> Unit) {
93
+ coroutineScope.launch {
94
+ authsignal?.let {
95
+ fn(it)
96
+ } ?: run {
97
+ Log.w("init_error", "AuthsignalTOTPModule is not initialized.")
98
+
99
+ promise.resolve(null)
100
+ }
101
+ }
102
+ }
103
+ }