@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.
Files changed (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -2
  3. package/android/build.gradle +152 -0
  4. package/android/src/main/AndroidManifest.xml +4 -0
  5. package/android/src/main/java/expo/modules/clerk/ClerkAuthViewModule.kt +241 -0
  6. package/android/src/main/java/expo/modules/clerk/ClerkComposeNativeViewHost.kt +148 -0
  7. package/android/src/main/java/expo/modules/clerk/ClerkExpoModule.kt +1077 -0
  8. package/android/src/main/java/expo/modules/clerk/ClerkUserButtonViewModule.kt +156 -0
  9. package/android/src/main/java/expo/modules/clerk/ClerkUserProfileCustomPageState.kt +120 -0
  10. package/android/src/main/java/expo/modules/clerk/ClerkUserProfileViewModule.kt +315 -0
  11. package/android/src/test/java/expo/modules/clerk/BiometricCredentialBridgeTest.kt +326 -0
  12. package/android/src/test/java/expo/modules/clerk/ClerkUserProfileCustomPageStateTest.kt +163 -0
  13. package/app.plugin.d.ts +5 -0
  14. package/app.plugin.js +333 -0
  15. package/dist/AuthView.d.ts +35 -0
  16. package/dist/AuthView.d.ts.map +1 -0
  17. package/dist/AuthView.js +79 -0
  18. package/dist/AuthView.js.map +1 -0
  19. package/dist/AuthView.types.d.ts +62 -0
  20. package/dist/AuthView.types.d.ts.map +1 -0
  21. package/dist/AuthView.types.js +0 -0
  22. package/dist/EmbeddedNavigation.types.d.ts +24 -0
  23. package/dist/EmbeddedNavigation.types.d.ts.map +1 -0
  24. package/dist/EmbeddedNavigation.types.js +0 -0
  25. package/dist/UserButton.d.ts +38 -0
  26. package/dist/UserButton.d.ts.map +1 -0
  27. package/dist/UserButton.js +68 -0
  28. package/dist/UserButton.js.map +1 -0
  29. package/dist/UserProfileCustomPages.d.ts +81 -0
  30. package/dist/UserProfileCustomPages.d.ts.map +1 -0
  31. package/dist/UserProfileCustomPages.js +140 -0
  32. package/dist/UserProfileCustomPages.js.map +1 -0
  33. package/dist/UserProfileView.d.ts +76 -0
  34. package/dist/UserProfileView.d.ts.map +1 -0
  35. package/dist/UserProfileView.js +101 -0
  36. package/dist/UserProfileView.js.map +1 -0
  37. package/dist/_virtual/_rolldown/runtime.js +29 -0
  38. package/dist/index.d.ts +41 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +37 -0
  41. package/dist/specs/NativeClerkAuthView.android.d.ts +15 -0
  42. package/dist/specs/NativeClerkAuthView.android.d.ts.map +1 -0
  43. package/dist/specs/NativeClerkAuthView.android.js +8 -0
  44. package/dist/specs/NativeClerkAuthView.android.js.map +1 -0
  45. package/dist/specs/NativeClerkAuthView.d.ts +15 -0
  46. package/dist/specs/NativeClerkAuthView.d.ts.map +1 -0
  47. package/dist/specs/NativeClerkAuthView.js +9 -0
  48. package/dist/specs/NativeClerkAuthView.js.map +1 -0
  49. package/dist/specs/NativeClerkModule.d.ts +4 -0
  50. package/dist/specs/NativeClerkModule.d.ts.map +1 -0
  51. package/dist/specs/NativeClerkModule.js +8 -0
  52. package/dist/specs/NativeClerkModule.js.map +1 -0
  53. package/dist/specs/NativeClerkModule.types.d.ts +11 -0
  54. package/dist/specs/NativeClerkModule.types.d.ts.map +1 -0
  55. package/dist/specs/NativeClerkModule.types.js +0 -0
  56. package/dist/specs/NativeClerkModule.web.d.ts +4 -0
  57. package/dist/specs/NativeClerkModule.web.d.ts.map +1 -0
  58. package/dist/specs/NativeClerkModule.web.js +7 -0
  59. package/dist/specs/NativeClerkModule.web.js.map +1 -0
  60. package/dist/specs/NativeClerkUserButtonView.android.d.ts +6 -0
  61. package/dist/specs/NativeClerkUserButtonView.android.d.ts.map +1 -0
  62. package/dist/specs/NativeClerkUserButtonView.android.js +8 -0
  63. package/dist/specs/NativeClerkUserButtonView.android.js.map +1 -0
  64. package/dist/specs/NativeClerkUserButtonView.d.ts +6 -0
  65. package/dist/specs/NativeClerkUserButtonView.d.ts.map +1 -0
  66. package/dist/specs/NativeClerkUserButtonView.js +9 -0
  67. package/dist/specs/NativeClerkUserButtonView.js.map +1 -0
  68. package/dist/specs/NativeClerkUserProfileView.android.d.ts +13 -0
  69. package/dist/specs/NativeClerkUserProfileView.android.d.ts.map +1 -0
  70. package/dist/specs/NativeClerkUserProfileView.android.js +8 -0
  71. package/dist/specs/NativeClerkUserProfileView.android.js.map +1 -0
  72. package/dist/specs/NativeClerkUserProfileView.d.ts +13 -0
  73. package/dist/specs/NativeClerkUserProfileView.d.ts.map +1 -0
  74. package/dist/specs/NativeClerkUserProfileView.js +9 -0
  75. package/dist/specs/NativeClerkUserProfileView.js.map +1 -0
  76. package/dist/useAuthViewState.d.ts +12 -0
  77. package/dist/useAuthViewState.d.ts.map +1 -0
  78. package/dist/useAuthViewState.js +76 -0
  79. package/dist/useAuthViewState.js.map +1 -0
  80. package/dist/utils/native-module.d.ts +3 -0
  81. package/dist/utils/native-module.d.ts.map +1 -0
  82. package/dist/utils/native-module.js +14 -0
  83. package/dist/utils/native-module.js.map +1 -0
  84. package/expo-module.config.json +15 -0
  85. package/ios/ClerkAppDelegateSubscriber.swift +16 -0
  86. package/ios/ClerkAuthNativeView.swift +157 -0
  87. package/ios/ClerkExpo.podspec +67 -0
  88. package/ios/ClerkExpoModule.swift +315 -0
  89. package/ios/ClerkNativeBridge.swift +1575 -0
  90. package/ios/ClerkNativeViewHost.swift +204 -0
  91. package/ios/ClerkUserButtonNativeView.swift +34 -0
  92. package/ios/ClerkUserProfileNativeView.swift +92 -0
  93. package/ios/Tests/ClerkAuthNativeViewPaperTests.swift +30 -0
  94. package/ios/Tests/ClerkNativeBridgeTests.swift +185 -0
  95. package/ios/Tests/ClerkNativeViewHostTests.swift +66 -0
  96. package/ios/Tests/ClerkUserProfileCustomPageStateTests.swift +311 -0
  97. package/package.json +79 -3
  98. package/react-native.config.js +8 -0
  99. package/src/specs/NativeClerkAuthView.android.ts +15 -0
  100. package/src/specs/NativeClerkAuthView.ts +19 -0
  101. package/src/specs/NativeClerkModule.ts +6 -0
  102. package/src/specs/NativeClerkModule.types.ts +9 -0
  103. package/src/specs/NativeClerkModule.web.ts +3 -0
  104. package/src/specs/NativeClerkUserButtonView.android.ts +9 -0
  105. package/src/specs/NativeClerkUserButtonView.ts +11 -0
  106. package/src/specs/NativeClerkUserProfileView.android.ts +13 -0
  107. package/src/specs/NativeClerkUserProfileView.ts +17 -0
  108. 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
+ }