@clerk/expo-native-components 0.0.0-stage → 0.0.1
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.
- package/LICENSE +21 -0
- package/README.md +106 -2
- package/android/build.gradle +152 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/java/expo/modules/clerk/ClerkAuthViewModule.kt +241 -0
- package/android/src/main/java/expo/modules/clerk/ClerkComposeNativeViewHost.kt +148 -0
- package/android/src/main/java/expo/modules/clerk/ClerkExpoModule.kt +1077 -0
- package/android/src/main/java/expo/modules/clerk/ClerkUserButtonViewModule.kt +156 -0
- package/android/src/main/java/expo/modules/clerk/ClerkUserProfileCustomPageState.kt +120 -0
- package/android/src/main/java/expo/modules/clerk/ClerkUserProfileViewModule.kt +315 -0
- package/android/src/test/java/expo/modules/clerk/BiometricCredentialBridgeTest.kt +326 -0
- package/android/src/test/java/expo/modules/clerk/ClerkUserProfileCustomPageStateTest.kt +163 -0
- package/app.plugin.d.ts +5 -0
- package/app.plugin.js +333 -0
- package/dist/AuthView.d.ts +35 -0
- package/dist/AuthView.d.ts.map +1 -0
- package/dist/AuthView.js +79 -0
- package/dist/AuthView.js.map +1 -0
- package/dist/AuthView.types.d.ts +62 -0
- package/dist/AuthView.types.d.ts.map +1 -0
- package/dist/AuthView.types.js +0 -0
- package/dist/EmbeddedNavigation.types.d.ts +24 -0
- package/dist/EmbeddedNavigation.types.d.ts.map +1 -0
- package/dist/EmbeddedNavigation.types.js +0 -0
- package/dist/UserButton.d.ts +38 -0
- package/dist/UserButton.d.ts.map +1 -0
- package/dist/UserButton.js +68 -0
- package/dist/UserButton.js.map +1 -0
- package/dist/UserProfileCustomPages.d.ts +81 -0
- package/dist/UserProfileCustomPages.d.ts.map +1 -0
- package/dist/UserProfileCustomPages.js +140 -0
- package/dist/UserProfileCustomPages.js.map +1 -0
- package/dist/UserProfileView.d.ts +76 -0
- package/dist/UserProfileView.d.ts.map +1 -0
- package/dist/UserProfileView.js +101 -0
- package/dist/UserProfileView.js.map +1 -0
- package/dist/_virtual/_rolldown/runtime.js +29 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/specs/NativeClerkAuthView.android.d.ts +15 -0
- package/dist/specs/NativeClerkAuthView.android.d.ts.map +1 -0
- package/dist/specs/NativeClerkAuthView.android.js +8 -0
- package/dist/specs/NativeClerkAuthView.android.js.map +1 -0
- package/dist/specs/NativeClerkAuthView.d.ts +15 -0
- package/dist/specs/NativeClerkAuthView.d.ts.map +1 -0
- package/dist/specs/NativeClerkAuthView.js +9 -0
- package/dist/specs/NativeClerkAuthView.js.map +1 -0
- package/dist/specs/NativeClerkModule.d.ts +4 -0
- package/dist/specs/NativeClerkModule.d.ts.map +1 -0
- package/dist/specs/NativeClerkModule.js +8 -0
- package/dist/specs/NativeClerkModule.js.map +1 -0
- package/dist/specs/NativeClerkModule.types.d.ts +11 -0
- package/dist/specs/NativeClerkModule.types.d.ts.map +1 -0
- package/dist/specs/NativeClerkModule.types.js +0 -0
- package/dist/specs/NativeClerkModule.web.d.ts +4 -0
- package/dist/specs/NativeClerkModule.web.d.ts.map +1 -0
- package/dist/specs/NativeClerkModule.web.js +7 -0
- package/dist/specs/NativeClerkModule.web.js.map +1 -0
- package/dist/specs/NativeClerkUserButtonView.android.d.ts +6 -0
- package/dist/specs/NativeClerkUserButtonView.android.d.ts.map +1 -0
- package/dist/specs/NativeClerkUserButtonView.android.js +8 -0
- package/dist/specs/NativeClerkUserButtonView.android.js.map +1 -0
- package/dist/specs/NativeClerkUserButtonView.d.ts +6 -0
- package/dist/specs/NativeClerkUserButtonView.d.ts.map +1 -0
- package/dist/specs/NativeClerkUserButtonView.js +9 -0
- package/dist/specs/NativeClerkUserButtonView.js.map +1 -0
- package/dist/specs/NativeClerkUserProfileView.android.d.ts +13 -0
- package/dist/specs/NativeClerkUserProfileView.android.d.ts.map +1 -0
- package/dist/specs/NativeClerkUserProfileView.android.js +8 -0
- package/dist/specs/NativeClerkUserProfileView.android.js.map +1 -0
- package/dist/specs/NativeClerkUserProfileView.d.ts +13 -0
- package/dist/specs/NativeClerkUserProfileView.d.ts.map +1 -0
- package/dist/specs/NativeClerkUserProfileView.js +9 -0
- package/dist/specs/NativeClerkUserProfileView.js.map +1 -0
- package/dist/useAuthViewState.d.ts +12 -0
- package/dist/useAuthViewState.d.ts.map +1 -0
- package/dist/useAuthViewState.js +76 -0
- package/dist/useAuthViewState.js.map +1 -0
- package/dist/utils/native-module.d.ts +3 -0
- package/dist/utils/native-module.d.ts.map +1 -0
- package/dist/utils/native-module.js +14 -0
- package/dist/utils/native-module.js.map +1 -0
- package/expo-module.config.json +15 -0
- package/ios/ClerkAppDelegateSubscriber.swift +16 -0
- package/ios/ClerkAuthNativeView.swift +157 -0
- package/ios/ClerkExpo.podspec +67 -0
- package/ios/ClerkExpoModule.swift +315 -0
- package/ios/ClerkNativeBridge.swift +1575 -0
- package/ios/ClerkNativeViewHost.swift +204 -0
- package/ios/ClerkUserButtonNativeView.swift +34 -0
- package/ios/ClerkUserProfileNativeView.swift +92 -0
- package/ios/Tests/ClerkAuthNativeViewPaperTests.swift +30 -0
- package/ios/Tests/ClerkNativeBridgeTests.swift +185 -0
- package/ios/Tests/ClerkNativeViewHostTests.swift +66 -0
- package/ios/Tests/ClerkUserProfileCustomPageStateTests.swift +311 -0
- package/package.json +79 -3
- package/react-native.config.js +8 -0
- package/src/specs/NativeClerkAuthView.android.ts +15 -0
- package/src/specs/NativeClerkAuthView.ts +19 -0
- package/src/specs/NativeClerkModule.ts +6 -0
- package/src/specs/NativeClerkModule.types.ts +9 -0
- package/src/specs/NativeClerkModule.web.ts +3 -0
- package/src/specs/NativeClerkUserButtonView.android.ts +9 -0
- package/src/specs/NativeClerkUserButtonView.ts +11 -0
- package/src/specs/NativeClerkUserProfileView.android.ts +13 -0
- package/src/specs/NativeClerkUserProfileView.ts +17 -0
- package/src/specs/__tests__/native-view.web.test.ts +43 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
// ClerkExpoModule - Native module for Clerk integration
|
|
2
|
+
// This module provides the configure function, client sync, and native view bridges.
|
|
3
|
+
// SwiftUI Clerk views are created by ClerkNativeBridge through the Clerk iOS SPM dependency.
|
|
4
|
+
|
|
5
|
+
import ExpoModulesCore
|
|
6
|
+
import Foundation
|
|
7
|
+
|
|
8
|
+
// MARK: - Module
|
|
9
|
+
|
|
10
|
+
public class ClerkExpoModule: Module {
|
|
11
|
+
private static let nativeAuthFlowChangedEvent = "clerkNativeAuthFlowChanged"
|
|
12
|
+
private static let nativeClientChangedEvent = "clerkNativeClientChanged"
|
|
13
|
+
|
|
14
|
+
private static weak var sharedInstance: ClerkExpoModule?
|
|
15
|
+
|
|
16
|
+
public func definition() -> ModuleDefinition {
|
|
17
|
+
Name("ClerkExpo")
|
|
18
|
+
|
|
19
|
+
Events(Self.nativeAuthFlowChangedEvent, Self.nativeClientChangedEvent)
|
|
20
|
+
|
|
21
|
+
OnCreate {
|
|
22
|
+
Self.sharedInstance = self
|
|
23
|
+
ClerkNativeBridge.setAuthFlowChangedEmitter { body in
|
|
24
|
+
Self.emitAuthFlowChanged(body)
|
|
25
|
+
}
|
|
26
|
+
ClerkNativeBridge.setClientChangedEmitter { body in
|
|
27
|
+
Self.emitClientChanged(body)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
OnDestroy {
|
|
32
|
+
if Self.sharedInstance === self {
|
|
33
|
+
Self.sharedInstance = nil
|
|
34
|
+
ClerkNativeBridge.setAuthFlowChangedEmitter(nil)
|
|
35
|
+
ClerkNativeBridge.setClientChangedEmitter(nil)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
AsyncFunction("configure") { (publishableKey: String, bearerToken: String?, promise: Promise) in
|
|
40
|
+
self.configure(publishableKey, bearerToken: bearerToken, promise: promise)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
AsyncFunction("getClientToken") { (promise: Promise) in
|
|
44
|
+
self.getClientToken(promise: promise)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
AsyncFunction("getAuthFlowState") { (promise: Promise) in
|
|
48
|
+
self.getAuthFlowState(promise: promise)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
AsyncFunction("syncClientStateFromJs") {
|
|
52
|
+
(deviceToken: String?,
|
|
53
|
+
sourceId: String?,
|
|
54
|
+
didChangeClient: Bool,
|
|
55
|
+
didChangeDeviceToken: Bool,
|
|
56
|
+
promise: Promise) in
|
|
57
|
+
self.syncClientStateFromJs(
|
|
58
|
+
deviceToken,
|
|
59
|
+
sourceId: sourceId,
|
|
60
|
+
didChangeClient: didChangeClient,
|
|
61
|
+
didChangeDeviceToken: didChangeDeviceToken,
|
|
62
|
+
promise: promise
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
AsyncFunction("getTrustedDeviceAvailability") {
|
|
67
|
+
(id: String?, identifierHint: String?, promise: Promise) in
|
|
68
|
+
self.getBiometricCredentialAvailability(id: id, identifierHint: identifierHint, promise: promise)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
AsyncFunction("listTrustedDevices") { (promise: Promise) in
|
|
72
|
+
self.listBiometricCredentials(promise: promise)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
AsyncFunction("enrollTrustedDevice") {
|
|
76
|
+
(deviceName: String?,
|
|
77
|
+
identifierHint: String?,
|
|
78
|
+
reason: String?,
|
|
79
|
+
policy: String,
|
|
80
|
+
promise: Promise) in
|
|
81
|
+
self.enrollBiometricCredential(
|
|
82
|
+
deviceName: deviceName,
|
|
83
|
+
identifierHint: identifierHint,
|
|
84
|
+
reason: reason,
|
|
85
|
+
policy: policy,
|
|
86
|
+
promise: promise
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
AsyncFunction("revokeTrustedDevice") { (id: String, promise: Promise) in
|
|
91
|
+
self.revokeBiometricCredential(id: id, promise: promise)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
AsyncFunction("signInWithTrustedDevice") {
|
|
95
|
+
(id: String?, identifierHint: String?, reason: String?, promise: Promise) in
|
|
96
|
+
self.signInWithBiometrics(
|
|
97
|
+
id: id,
|
|
98
|
+
identifierHint: identifierHint,
|
|
99
|
+
reason: reason,
|
|
100
|
+
promise: promise
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
AsyncFunction("reverifyWithBiometrics") {
|
|
105
|
+
(sessionId: String, level: String, reason: String?, promise: Promise) in
|
|
106
|
+
Task { @MainActor in
|
|
107
|
+
do {
|
|
108
|
+
let verification = try await ClerkNativeBridge.shared.reverifyWithBiometrics(
|
|
109
|
+
sessionId: sessionId,
|
|
110
|
+
level: level,
|
|
111
|
+
reason: reason
|
|
112
|
+
)
|
|
113
|
+
promise.resolve(verification)
|
|
114
|
+
} catch {
|
|
115
|
+
self.rejectBiometricCredentialError(
|
|
116
|
+
error,
|
|
117
|
+
fallbackCode: "E_BIOMETRIC_REVERIFICATION_FAILED",
|
|
118
|
+
promise: promise
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// MARK: - configure
|
|
126
|
+
|
|
127
|
+
private func configure(_ publishableKey: String, bearerToken: String?, promise: Promise) {
|
|
128
|
+
Task {
|
|
129
|
+
do {
|
|
130
|
+
try await ClerkNativeBridge.shared.configure(publishableKey: publishableKey, bearerToken: bearerToken)
|
|
131
|
+
promise.resolve()
|
|
132
|
+
} catch {
|
|
133
|
+
promise.reject("E_CONFIGURE_FAILED", error.localizedDescription)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// MARK: - getClientToken
|
|
139
|
+
|
|
140
|
+
private func getClientToken(promise: Promise) {
|
|
141
|
+
Task {
|
|
142
|
+
let token = await ClerkNativeBridge.shared.getClientToken()
|
|
143
|
+
promise.resolve(token)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// MARK: - getAuthFlowState
|
|
148
|
+
|
|
149
|
+
private func getAuthFlowState(promise: Promise) {
|
|
150
|
+
Task { @MainActor in
|
|
151
|
+
let state = ClerkNativeBridge.shared.getAuthFlowState()
|
|
152
|
+
promise.resolve(state)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// MARK: - syncClientStateFromJs
|
|
157
|
+
|
|
158
|
+
private func syncClientStateFromJs(_ deviceToken: String?,
|
|
159
|
+
sourceId: String?,
|
|
160
|
+
didChangeClient: Bool,
|
|
161
|
+
didChangeDeviceToken: Bool,
|
|
162
|
+
promise: Promise) {
|
|
163
|
+
Task {
|
|
164
|
+
do {
|
|
165
|
+
try await ClerkNativeBridge.shared.syncClientStateFromJs(
|
|
166
|
+
deviceToken: deviceToken,
|
|
167
|
+
sourceId: sourceId,
|
|
168
|
+
didChangeClient: didChangeClient,
|
|
169
|
+
didChangeDeviceToken: didChangeDeviceToken
|
|
170
|
+
)
|
|
171
|
+
promise.resolve()
|
|
172
|
+
} catch {
|
|
173
|
+
promise.reject("E_SYNC_FROM_JS_FAILED", error.localizedDescription)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// MARK: - Biometric credentials
|
|
179
|
+
|
|
180
|
+
private func getBiometricCredentialAvailability(id: String?, identifierHint: String?, promise: Promise) {
|
|
181
|
+
Task { @MainActor in
|
|
182
|
+
do {
|
|
183
|
+
let availability = try await ClerkNativeBridge.shared.getBiometricCredentialAvailability(
|
|
184
|
+
id: id,
|
|
185
|
+
identifierHint: identifierHint
|
|
186
|
+
)
|
|
187
|
+
promise.resolve(availability)
|
|
188
|
+
} catch {
|
|
189
|
+
rejectBiometricCredentialError(
|
|
190
|
+
error,
|
|
191
|
+
fallbackCode: "E_TRUSTED_DEVICE_AVAILABILITY_FAILED",
|
|
192
|
+
promise: promise
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private func listBiometricCredentials(promise: Promise) {
|
|
199
|
+
Task { @MainActor in
|
|
200
|
+
do {
|
|
201
|
+
let biometricCredentials = try await ClerkNativeBridge.shared.listBiometricCredentials()
|
|
202
|
+
promise.resolve(biometricCredentials)
|
|
203
|
+
} catch {
|
|
204
|
+
rejectBiometricCredentialError(
|
|
205
|
+
error,
|
|
206
|
+
fallbackCode: "E_TRUSTED_DEVICE_LIST_FAILED",
|
|
207
|
+
promise: promise
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private func enrollBiometricCredential(
|
|
214
|
+
deviceName: String?,
|
|
215
|
+
identifierHint: String?,
|
|
216
|
+
reason: String?,
|
|
217
|
+
policy: String,
|
|
218
|
+
promise: Promise
|
|
219
|
+
) {
|
|
220
|
+
Task { @MainActor in
|
|
221
|
+
do {
|
|
222
|
+
let biometricCredential = try await ClerkNativeBridge.shared.enrollBiometricCredential(
|
|
223
|
+
deviceName: deviceName,
|
|
224
|
+
identifierHint: identifierHint,
|
|
225
|
+
reason: reason,
|
|
226
|
+
policy: policy
|
|
227
|
+
)
|
|
228
|
+
promise.resolve(biometricCredential)
|
|
229
|
+
} catch {
|
|
230
|
+
rejectBiometricCredentialError(
|
|
231
|
+
error,
|
|
232
|
+
fallbackCode: "E_TRUSTED_DEVICE_ENROLLMENT_FAILED",
|
|
233
|
+
promise: promise
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
private func revokeBiometricCredential(id: String, promise: Promise) {
|
|
240
|
+
Task { @MainActor in
|
|
241
|
+
do {
|
|
242
|
+
let biometricCredential = try await ClerkNativeBridge.shared.revokeBiometricCredential(id: id)
|
|
243
|
+
promise.resolve(biometricCredential)
|
|
244
|
+
} catch {
|
|
245
|
+
rejectBiometricCredentialError(
|
|
246
|
+
error,
|
|
247
|
+
fallbackCode: "E_TRUSTED_DEVICE_REVOCATION_FAILED",
|
|
248
|
+
promise: promise
|
|
249
|
+
)
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
private func signInWithBiometrics(
|
|
255
|
+
id: String?,
|
|
256
|
+
identifierHint: String?,
|
|
257
|
+
reason: String?,
|
|
258
|
+
promise: Promise
|
|
259
|
+
) {
|
|
260
|
+
Task { @MainActor in
|
|
261
|
+
do {
|
|
262
|
+
let signIn = try await ClerkNativeBridge.shared.signInWithBiometrics(
|
|
263
|
+
id: id,
|
|
264
|
+
identifierHint: identifierHint,
|
|
265
|
+
reason: reason
|
|
266
|
+
)
|
|
267
|
+
promise.resolve(signIn)
|
|
268
|
+
} catch {
|
|
269
|
+
rejectBiometricCredentialError(
|
|
270
|
+
error,
|
|
271
|
+
fallbackCode: "E_TRUSTED_DEVICE_SIGN_IN_FAILED",
|
|
272
|
+
promise: promise
|
|
273
|
+
)
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private func rejectBiometricCredentialError(
|
|
279
|
+
_ error: Error,
|
|
280
|
+
fallbackCode: String,
|
|
281
|
+
promise: Promise
|
|
282
|
+
) {
|
|
283
|
+
let descriptor = ClerkNativeBridge.biometricCredentialErrorDescriptor(
|
|
284
|
+
error,
|
|
285
|
+
fallbackCode: fallbackCode
|
|
286
|
+
)
|
|
287
|
+
promise.reject(descriptor.code, descriptor.message)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/// Emits a native client change event to JS from anywhere in the native layer.
|
|
291
|
+
/// Used by native views to ask ClerkProvider to reload JS client state.
|
|
292
|
+
static func emitClientChanged(_ body: [String: Any]? = nil) {
|
|
293
|
+
let eventBody = body ?? [:]
|
|
294
|
+
|
|
295
|
+
guard let instance = sharedInstance else {
|
|
296
|
+
return
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
DispatchQueue.main.async { [weak instance] in
|
|
300
|
+
instance?.sendEvent(Self.nativeClientChangedEvent, eventBody)
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
static func emitAuthFlowChanged(_ body: [String: Any]? = nil) {
|
|
305
|
+
let eventBody = body ?? [:]
|
|
306
|
+
|
|
307
|
+
guard let instance = sharedInstance else {
|
|
308
|
+
return
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
DispatchQueue.main.async { [weak instance] in
|
|
312
|
+
instance?.sendEvent(Self.nativeAuthFlowChangedEvent, eventBody)
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|