@trainon-inc/capacitor-clerk-native 1.10.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.
- package/LICENSE +22 -0
- package/README.md +416 -0
- package/TrainonIncCapacitorClerkNative.podspec +18 -0
- package/android/src/main/java/com/trainon/capacitor/clerk/.gitkeep +0 -0
- package/android/src/main/java/com/trainon/capacitor/clerk/ClerkNativePlugin.java +66 -0
- package/dist/definitions.d.ts +93 -0
- package/dist/definitions.d.ts.map +1 -0
- package/dist/definitions.js +2 -0
- package/dist/definitions.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/react.d.ts +65 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +142 -0
- package/dist/react.js.map +1 -0
- package/dist/web.d.ts +54 -0
- package/dist/web.d.ts.map +1 -0
- package/dist/web.js +37 -0
- package/dist/web.js.map +1 -0
- package/ios/Plugin/ClerkNativePlugin.m +17 -0
- package/ios/Plugin/ClerkNativePlugin.swift +171 -0
- package/package.json +81 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 TrainOn Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
# capacitor-clerk-native
|
|
2
|
+
|
|
3
|
+
A Capacitor plugin for native Clerk authentication on iOS and Android using the bridge pattern to seamlessly integrate Clerk's native SDKs with CocoaPods/Gradle-based Capacitor plugins.
|
|
4
|
+
|
|
5
|
+
## The Problem This Solves
|
|
6
|
+
|
|
7
|
+
When using Clerk authentication in Capacitor iOS apps, WebView cookie limitations cause authentication failures with the error:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Browser unauthenticated (dev_browser_unauthenticated)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Additionally, Clerk's iOS SDK is only available via Swift Package Manager (SPM), but Capacitor plugins use CocoaPods, creating a dependency conflict.
|
|
14
|
+
|
|
15
|
+
## The Solution
|
|
16
|
+
|
|
17
|
+
This plugin uses a **bridge pattern** to resolve the CocoaPods ↔ SPM conflict:
|
|
18
|
+
|
|
19
|
+
1. **Plugin (CocoaPods)**: Defines a protocol interface without depending on Clerk
|
|
20
|
+
2. **App Target (SPM)**: Implements the bridge using Clerk's native SDK
|
|
21
|
+
3. **AppDelegate**: Connects them at runtime
|
|
22
|
+
|
|
23
|
+
This allows your Capacitor app to use Clerk's native iOS/Android SDKs (following the official [Clerk iOS Quickstart](https://clerk.com/docs/ios/getting-started/quickstart)), avoiding WebView cookie issues entirely.
|
|
24
|
+
|
|
25
|
+
### Why This Approach?
|
|
26
|
+
|
|
27
|
+
- ✅ Uses **official Clerk iOS SDK** - same as native Swift apps
|
|
28
|
+
- ✅ Follows **Clerk's best practices** for iOS integration
|
|
29
|
+
- ✅ **No WebView limitations** - native authentication flows
|
|
30
|
+
- ✅ **CocoaPods compatible** - works with Capacitor's build system
|
|
31
|
+
- ✅ **Reusable** - bridge pattern can be adapted for other native SDKs
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
### From GitHub Packages (Recommended)
|
|
36
|
+
|
|
37
|
+
1. Create a `.npmrc` file in your project root:
|
|
38
|
+
```
|
|
39
|
+
@trainon-inc:registry=https://npm.pkg.github.com
|
|
40
|
+
//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
2. Install the package:
|
|
44
|
+
```bash
|
|
45
|
+
npm install @trainon-inc/capacitor-clerk-native
|
|
46
|
+
# or
|
|
47
|
+
pnpm add @trainon-inc/capacitor-clerk-native
|
|
48
|
+
# or
|
|
49
|
+
yarn add @trainon-inc/capacitor-clerk-native
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
> **Note**: You'll need a GitHub Personal Access Token with `read:packages` permission. [Create one here](https://github.com/settings/tokens/new?scopes=read:packages)
|
|
53
|
+
|
|
54
|
+
### From NPM (Future)
|
|
55
|
+
|
|
56
|
+
Once published to npm:
|
|
57
|
+
```bash
|
|
58
|
+
npm install capacitor-clerk-native
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## iOS Setup
|
|
62
|
+
|
|
63
|
+
### Prerequisites
|
|
64
|
+
|
|
65
|
+
Before starting, ensure you have:
|
|
66
|
+
- ✅ A [Clerk account](https://dashboard.clerk.com/sign-up)
|
|
67
|
+
- ✅ A Clerk application set up in the dashboard
|
|
68
|
+
- ✅ **Native API enabled** in Clerk Dashboard → Settings → Native Applications
|
|
69
|
+
|
|
70
|
+
> **Important**: You must enable the Native API in your Clerk Dashboard before proceeding. This is required for native iOS integration.
|
|
71
|
+
|
|
72
|
+
### 1. Register Your iOS App with Clerk
|
|
73
|
+
|
|
74
|
+
1. Go to the [**Native Applications**](https://dashboard.clerk.com/last-active?path=native-applications) page in Clerk Dashboard
|
|
75
|
+
2. Click **"Add Application"**
|
|
76
|
+
3. Enter your iOS app details:
|
|
77
|
+
- **App ID Prefix**: Found in your Apple Developer account or Xcode (Team ID)
|
|
78
|
+
- **Bundle ID**: Your app's bundle identifier (e.g., `com.trainon.member`)
|
|
79
|
+
4. Note down your **Frontend API URL** (you'll need this for associated domains)
|
|
80
|
+
|
|
81
|
+
### 2. Add Associated Domain Capability
|
|
82
|
+
|
|
83
|
+
This is required for seamless authentication flows:
|
|
84
|
+
|
|
85
|
+
1. In Xcode, select your project → Select your **App** target
|
|
86
|
+
2. Go to **"Signing & Capabilities"** tab
|
|
87
|
+
3. Click **"+ Capability"** → Add **"Associated Domains"**
|
|
88
|
+
4. Under Associated Domains, add: `webcredentials:{YOUR_FRONTEND_API_URL}`
|
|
89
|
+
- Example: `webcredentials:guiding-serval-42.clerk.accounts.dev`
|
|
90
|
+
- Get your Frontend API URL from the Native Applications page in Clerk Dashboard
|
|
91
|
+
|
|
92
|
+
### 3. Add Clerk iOS SDK to Your App Target
|
|
93
|
+
|
|
94
|
+
1. Open your iOS project in Xcode
|
|
95
|
+
2. Select your **App** target
|
|
96
|
+
3. Go to **"Package Dependencies"** tab
|
|
97
|
+
4. Click **"+"** → **"Add Package Dependency"**
|
|
98
|
+
5. Enter: `https://github.com/clerk/clerk-ios`
|
|
99
|
+
6. Select version `0.69.0` or later
|
|
100
|
+
7. Link to your **App** target
|
|
101
|
+
|
|
102
|
+
### 4. Create the Bridge Implementation
|
|
103
|
+
|
|
104
|
+
Create a file `ClerkBridgeImpl.swift` in your app's directory:
|
|
105
|
+
|
|
106
|
+
```swift
|
|
107
|
+
import Foundation
|
|
108
|
+
import Clerk
|
|
109
|
+
import capacitor_clerk_native
|
|
110
|
+
|
|
111
|
+
@MainActor
|
|
112
|
+
class ClerkBridgeImpl: NSObject, ClerkBridge {
|
|
113
|
+
private let clerk = Clerk.shared
|
|
114
|
+
|
|
115
|
+
func signIn(withEmail email: String, password: String, completion: @escaping (String?, Error?) -> Void) {
|
|
116
|
+
Task { @MainActor in
|
|
117
|
+
do {
|
|
118
|
+
let signIn = try await SignIn.create(strategy: .identifier(email))
|
|
119
|
+
let result = try await signIn.attemptFirstFactor(strategy: .password(password: password))
|
|
120
|
+
|
|
121
|
+
if result.status == .complete {
|
|
122
|
+
if let user = clerk.user {
|
|
123
|
+
completion(user.id, nil)
|
|
124
|
+
} else {
|
|
125
|
+
completion(nil, NSError(domain: "ClerkBridge", code: -1, userInfo: [NSLocalizedDescriptionKey: "Sign in completed but no user found"]))
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
completion(nil, NSError(domain: "ClerkBridge", code: -1, userInfo: [NSLocalizedDescriptionKey: "Sign in not complete"]))
|
|
129
|
+
}
|
|
130
|
+
} catch {
|
|
131
|
+
completion(nil, error)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
func signUp(withEmail email: String, password: String, completion: @escaping (String?, Error?) -> Void) {
|
|
137
|
+
Task { @MainActor in
|
|
138
|
+
do {
|
|
139
|
+
let signUp = try await SignUp.create(
|
|
140
|
+
strategy: .standard(emailAddress: email, password: password)
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
if let user = clerk.user {
|
|
144
|
+
completion(user.id, nil)
|
|
145
|
+
} else {
|
|
146
|
+
completion(nil, NSError(domain: "ClerkBridge", code: -1, userInfo: [NSLocalizedDescriptionKey: "Sign up completed but no user found"]))
|
|
147
|
+
}
|
|
148
|
+
} catch {
|
|
149
|
+
completion(nil, error)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
func signOut(completion: @escaping (Error?) -> Void) {
|
|
155
|
+
Task { @MainActor in
|
|
156
|
+
do {
|
|
157
|
+
try await clerk.signOut()
|
|
158
|
+
completion(nil)
|
|
159
|
+
} catch {
|
|
160
|
+
completion(error)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
func getToken(completion: @escaping (String?, Error?) -> Void) {
|
|
166
|
+
Task { @MainActor in
|
|
167
|
+
do {
|
|
168
|
+
if let session = clerk.session {
|
|
169
|
+
if let token = try await session.getToken() {
|
|
170
|
+
completion(token.jwt, nil)
|
|
171
|
+
} else {
|
|
172
|
+
completion(nil, NSError(domain: "ClerkBridge", code: -1, userInfo: [NSLocalizedDescriptionKey: "No token available"]))
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
completion(nil, NSError(domain: "ClerkBridge", code: -1, userInfo: [NSLocalizedDescriptionKey: "No active session"]))
|
|
176
|
+
}
|
|
177
|
+
} catch {
|
|
178
|
+
completion(nil, error)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
func getUser(completion: @escaping ([String: Any]?, Error?) -> Void) {
|
|
184
|
+
Task { @MainActor in
|
|
185
|
+
if let user = clerk.user {
|
|
186
|
+
let userDict: [String: Any] = [
|
|
187
|
+
"id": user.id,
|
|
188
|
+
"firstName": user.firstName ?? NSNull(),
|
|
189
|
+
"lastName": user.lastName ?? NSNull(),
|
|
190
|
+
"emailAddress": user.primaryEmailAddress?.emailAddress ?? NSNull(),
|
|
191
|
+
"imageUrl": user.imageUrl ?? NSNull(),
|
|
192
|
+
"username": user.username ?? NSNull()
|
|
193
|
+
]
|
|
194
|
+
completion(userDict, nil)
|
|
195
|
+
} else {
|
|
196
|
+
completion(nil, nil)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
func isSignedIn(completion: @escaping (Bool, Error?) -> Void) {
|
|
202
|
+
Task { @MainActor in
|
|
203
|
+
completion(clerk.user != nil, nil)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### 5. Update AppDelegate
|
|
210
|
+
|
|
211
|
+
> **Note**: Your AppDelegate should configure Clerk when the app launches, just like in the [Clerk iOS Quickstart](https://clerk.com/docs/ios/getting-started/quickstart).
|
|
212
|
+
|
|
213
|
+
```swift
|
|
214
|
+
import UIKit
|
|
215
|
+
import Capacitor
|
|
216
|
+
import Clerk
|
|
217
|
+
import capacitor_clerk_native
|
|
218
|
+
|
|
219
|
+
@UIApplicationMain
|
|
220
|
+
class AppDelegate: UIResponder, UIApplicationDelegate {
|
|
221
|
+
|
|
222
|
+
var window: UIWindow?
|
|
223
|
+
private let clerkBridge = ClerkBridgeImpl()
|
|
224
|
+
|
|
225
|
+
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
|
226
|
+
// Configure Clerk
|
|
227
|
+
if let publishableKey = ProcessInfo.processInfo.environment["CLERK_PUBLISHABLE_KEY"] ?? Bundle.main.infoDictionary?["ClerkPublishableKey"] as? String {
|
|
228
|
+
Clerk.shared.configure(publishableKey: publishableKey)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Set up the Clerk bridge for the Capacitor plugin
|
|
232
|
+
ClerkNativePlugin.setClerkBridge(clerkBridge)
|
|
233
|
+
|
|
234
|
+
return true
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ... rest of AppDelegate methods
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### 6. Add ClerkBridgeImpl.swift to Xcode Project
|
|
242
|
+
|
|
243
|
+
1. In Xcode, right-click your **"App"** folder
|
|
244
|
+
2. Select **"Add Files to 'App'..."**
|
|
245
|
+
3. Select `ClerkBridgeImpl.swift`
|
|
246
|
+
4. **Uncheck** "Copy items if needed"
|
|
247
|
+
5. **Check** the "App" target
|
|
248
|
+
6. Click **"Add"**
|
|
249
|
+
|
|
250
|
+
### 7. Configure Clerk Publishable Key
|
|
251
|
+
|
|
252
|
+
> **Important**: Get your Publishable Key from the [**API Keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in Clerk Dashboard.
|
|
253
|
+
|
|
254
|
+
**Option A: Build Settings**
|
|
255
|
+
1. Select the **App** target → **Build Settings**
|
|
256
|
+
2. Click **"+"** → **"Add User-Defined Setting"**
|
|
257
|
+
3. Name: `CLERK_PUBLISHABLE_KEY`
|
|
258
|
+
4. Value: Your Clerk publishable key
|
|
259
|
+
|
|
260
|
+
**Option B: xcconfig File** (Recommended)
|
|
261
|
+
1. Create `Config.xcconfig` in your App folder:
|
|
262
|
+
```
|
|
263
|
+
CLERK_PUBLISHABLE_KEY = pk_test_your_clerk_key_here
|
|
264
|
+
```
|
|
265
|
+
2. Add it to Xcode project
|
|
266
|
+
3. Set it for both Debug and Release configurations in Project Info
|
|
267
|
+
|
|
268
|
+
### 8. Update Info.plist
|
|
269
|
+
|
|
270
|
+
Add your Clerk publishable key:
|
|
271
|
+
|
|
272
|
+
```xml
|
|
273
|
+
<key>ClerkPublishableKey</key>
|
|
274
|
+
<string>$(CLERK_PUBLISHABLE_KEY)</string>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## React/JavaScript Usage
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
import { ClerkProvider, useAuth, useUser, useSignIn, useSignUp } from '@trainon-inc/capacitor-clerk-native';
|
|
281
|
+
|
|
282
|
+
// Wrap your app
|
|
283
|
+
function App() {
|
|
284
|
+
return (
|
|
285
|
+
<ClerkProvider publishableKey="pk_test_...">
|
|
286
|
+
<YourApp />
|
|
287
|
+
</ClerkProvider>
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Use in components
|
|
292
|
+
function LoginPage() {
|
|
293
|
+
const { signIn } = useSignIn();
|
|
294
|
+
|
|
295
|
+
const handleLogin = async () => {
|
|
296
|
+
const result = await signIn.create({
|
|
297
|
+
identifier: email,
|
|
298
|
+
password: password
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
if (result.status === 'complete') {
|
|
302
|
+
// Navigate to app
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Get auth state
|
|
308
|
+
function Profile() {
|
|
309
|
+
const { user } = useUser();
|
|
310
|
+
const { getToken } = useAuth();
|
|
311
|
+
|
|
312
|
+
const token = await getToken();
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Architecture
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
┌─────────────────────────────────────────────────┐
|
|
320
|
+
│ JavaScript/React (Capacitor WebView) │
|
|
321
|
+
│ - Uses capacitor-clerk-native hooks │
|
|
322
|
+
└─────────────────┬───────────────────────────────┘
|
|
323
|
+
│ Capacitor Bridge
|
|
324
|
+
┌─────────────────▼───────────────────────────────┐
|
|
325
|
+
│ ClerkNativePlugin (CocoaPods Pod) │
|
|
326
|
+
│ - Defines ClerkBridge protocol │
|
|
327
|
+
│ - Receives calls from JavaScript │
|
|
328
|
+
│ - Delegates to bridge implementation │
|
|
329
|
+
└─────────────────┬───────────────────────────────┘
|
|
330
|
+
│ Protocol/Delegate
|
|
331
|
+
┌─────────────────▼───────────────────────────────┐
|
|
332
|
+
│ ClerkBridgeImpl (App Target, SPM) │
|
|
333
|
+
│ - Implements ClerkBridge protocol │
|
|
334
|
+
│ - Uses Clerk iOS SDK directly │
|
|
335
|
+
│ - Handles all Clerk authentication │
|
|
336
|
+
└─────────────────────────────────────────────────┘
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## API
|
|
340
|
+
|
|
341
|
+
### Methods
|
|
342
|
+
|
|
343
|
+
- `signInWithPassword(email: string, password: string)` - Sign in with email/password
|
|
344
|
+
- `signUp(email: string, password: string)` - Create a new account
|
|
345
|
+
- `signOut()` - Sign out current user
|
|
346
|
+
- `getToken()` - Get the authentication token
|
|
347
|
+
- `getUser()` - Get current user data
|
|
348
|
+
- `isSignedIn()` - Check if user is signed in
|
|
349
|
+
|
|
350
|
+
### React Hooks
|
|
351
|
+
|
|
352
|
+
- `useAuth()` - Authentication state and methods
|
|
353
|
+
- `useUser()` - Current user data
|
|
354
|
+
- `useSignIn()` - Sign in methods
|
|
355
|
+
- `useSignUp()` - Sign up methods
|
|
356
|
+
- `useClerk()` - Full Clerk context
|
|
357
|
+
|
|
358
|
+
## Troubleshooting
|
|
359
|
+
|
|
360
|
+
### Common Issues
|
|
361
|
+
|
|
362
|
+
#### "Browser unauthenticated" error in WebView
|
|
363
|
+
✅ **Solved!** This plugin uses native SDKs instead of WebView, eliminating this issue entirely.
|
|
364
|
+
|
|
365
|
+
#### "Native API not enabled"
|
|
366
|
+
- Go to Clerk Dashboard → Settings → Native Applications
|
|
367
|
+
- Enable the Native API toggle
|
|
368
|
+
- Refresh your app
|
|
369
|
+
|
|
370
|
+
#### Associated Domain not working
|
|
371
|
+
- Verify you added `webcredentials:{YOUR_FRONTEND_API_URL}` correctly
|
|
372
|
+
- Get the exact URL from Clerk Dashboard → Native Applications
|
|
373
|
+
- Clean build folder and rebuild (Shift+Cmd+K in Xcode)
|
|
374
|
+
|
|
375
|
+
#### "No such module 'Clerk'" in ClerkBridgeImpl
|
|
376
|
+
- Ensure Clerk iOS SDK is added to your App target (not just the project)
|
|
377
|
+
- Check Package Dependencies tab shows Clerk linked to your target
|
|
378
|
+
- Clean and rebuild
|
|
379
|
+
|
|
380
|
+
#### Plugin not found or not responding
|
|
381
|
+
- Run `npx cap sync` to sync the plugin
|
|
382
|
+
- Verify plugin is in node_modules: `@trainon-inc/capacitor-clerk-native`
|
|
383
|
+
- Check Podfile includes the plugin after running cap sync
|
|
384
|
+
|
|
385
|
+
#### Authentication not persisting
|
|
386
|
+
- Clerk handles session persistence automatically
|
|
387
|
+
- Verify `clerk.load()` is called in AppDelegate
|
|
388
|
+
- Check Clerk SDK is properly configured with your publishable key
|
|
389
|
+
|
|
390
|
+
### Getting Help
|
|
391
|
+
|
|
392
|
+
- 📖 [Clerk iOS Documentation](https://clerk.com/docs/ios)
|
|
393
|
+
- 💬 [Clerk Discord Community](https://clerk.com/discord)
|
|
394
|
+
- 🐛 [Report Issues](https://github.com/TrainOn-Inc/capacitor-clerk-native/issues)
|
|
395
|
+
|
|
396
|
+
## Android Support
|
|
397
|
+
|
|
398
|
+
Android support is planned. The bridge pattern will work similarly with Gradle and the Clerk Android SDK.
|
|
399
|
+
|
|
400
|
+
## Contributing
|
|
401
|
+
|
|
402
|
+
Contributions are welcome! This plugin was created to solve a real problem we encountered, and we'd love to make it better.
|
|
403
|
+
|
|
404
|
+
## License
|
|
405
|
+
|
|
406
|
+
MIT
|
|
407
|
+
|
|
408
|
+
## Credits
|
|
409
|
+
|
|
410
|
+
Created by the TrainOn Team to solve CocoaPods ↔ SPM conflicts when integrating Clerk authentication in Capacitor iOS apps.
|
|
411
|
+
|
|
412
|
+
## Support
|
|
413
|
+
|
|
414
|
+
- [GitHub Issues](https://github.com/Trainon-Inc/capacitor-clerk-native/issues)
|
|
415
|
+
- [Clerk Documentation](https://clerk.com/docs)
|
|
416
|
+
- [Capacitor Documentation](https://capacitorjs.com/docs)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'TrainonIncCapacitorClerkNative'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.license = package['license']
|
|
10
|
+
s.homepage = package['repository']['url']
|
|
11
|
+
s.author = package['author']
|
|
12
|
+
s.source = { :git => package['repository']['url'], :tag => "v#{s.version}" }
|
|
13
|
+
s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
|
|
14
|
+
s.ios.deployment_target = '13.0'
|
|
15
|
+
s.dependency 'Capacitor'
|
|
16
|
+
s.swift_version = '5.1'
|
|
17
|
+
end
|
|
18
|
+
|
|
File without changes
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
package com.trainon.capacitor.clerk;
|
|
2
|
+
|
|
3
|
+
import com.getcapacitor.Plugin;
|
|
4
|
+
import com.getcapacitor.PluginCall;
|
|
5
|
+
import com.getcapacitor.PluginMethod;
|
|
6
|
+
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
7
|
+
|
|
8
|
+
@CapacitorPlugin(name = "ClerkNative")
|
|
9
|
+
public class ClerkNativePlugin extends Plugin {
|
|
10
|
+
|
|
11
|
+
@PluginMethod
|
|
12
|
+
public void configure(PluginCall call) {
|
|
13
|
+
call.reject("Android not yet implemented");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@PluginMethod
|
|
17
|
+
public void load(PluginCall call) {
|
|
18
|
+
call.reject("Android not yet implemented");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@PluginMethod
|
|
22
|
+
public void signInWithEmail(PluginCall call) {
|
|
23
|
+
call.reject("Android not yet implemented");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@PluginMethod
|
|
27
|
+
public void verifyEmailCode(PluginCall call) {
|
|
28
|
+
call.reject("Android not yet implemented");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@PluginMethod
|
|
32
|
+
public void signInWithPassword(PluginCall call) {
|
|
33
|
+
call.reject("Android not yet implemented");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@PluginMethod
|
|
37
|
+
public void signUp(PluginCall call) {
|
|
38
|
+
call.reject("Android not yet implemented");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@PluginMethod
|
|
42
|
+
public void verifySignUpEmail(PluginCall call) {
|
|
43
|
+
call.reject("Android not yet implemented");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@PluginMethod
|
|
47
|
+
public void getUser(PluginCall call) {
|
|
48
|
+
call.reject("Android not yet implemented");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@PluginMethod
|
|
52
|
+
public void getToken(PluginCall call) {
|
|
53
|
+
call.reject("Android not yet implemented");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@PluginMethod
|
|
57
|
+
public void signOut(PluginCall call) {
|
|
58
|
+
call.reject("Android not yet implemented");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@PluginMethod
|
|
62
|
+
public void updateUser(PluginCall call) {
|
|
63
|
+
call.reject("Android not yet implemented");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export interface ClerkNativePlugin {
|
|
2
|
+
/**
|
|
3
|
+
* Configure Clerk with publishable key
|
|
4
|
+
*/
|
|
5
|
+
configure(options: {
|
|
6
|
+
publishableKey: string;
|
|
7
|
+
}): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Load Clerk and check for existing session
|
|
10
|
+
*/
|
|
11
|
+
load(): Promise<{
|
|
12
|
+
user: ClerkUser | null;
|
|
13
|
+
}>;
|
|
14
|
+
/**
|
|
15
|
+
* Sign in with email code
|
|
16
|
+
*/
|
|
17
|
+
signInWithEmail(options: {
|
|
18
|
+
email: string;
|
|
19
|
+
}): Promise<{
|
|
20
|
+
requiresCode: boolean;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Verify email code
|
|
24
|
+
*/
|
|
25
|
+
verifyEmailCode(options: {
|
|
26
|
+
code: string;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
user: ClerkUser;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* Sign in with email and password
|
|
32
|
+
*/
|
|
33
|
+
signInWithPassword(options: {
|
|
34
|
+
email: string;
|
|
35
|
+
password: string;
|
|
36
|
+
}): Promise<{
|
|
37
|
+
user: ClerkUser;
|
|
38
|
+
}>;
|
|
39
|
+
/**
|
|
40
|
+
* Sign up with email and password
|
|
41
|
+
*/
|
|
42
|
+
signUp(options: {
|
|
43
|
+
emailAddress: string;
|
|
44
|
+
password: string;
|
|
45
|
+
firstName?: string;
|
|
46
|
+
lastName?: string;
|
|
47
|
+
}): Promise<{
|
|
48
|
+
user: ClerkUser;
|
|
49
|
+
requiresVerification: boolean;
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* Verify email for sign up
|
|
53
|
+
*/
|
|
54
|
+
verifySignUpEmail(options: {
|
|
55
|
+
code: string;
|
|
56
|
+
}): Promise<{
|
|
57
|
+
user: ClerkUser;
|
|
58
|
+
}>;
|
|
59
|
+
/**
|
|
60
|
+
* Get current user
|
|
61
|
+
*/
|
|
62
|
+
getUser(): Promise<{
|
|
63
|
+
user: ClerkUser | null;
|
|
64
|
+
}>;
|
|
65
|
+
/**
|
|
66
|
+
* Get authentication token
|
|
67
|
+
*/
|
|
68
|
+
getToken(): Promise<{
|
|
69
|
+
token: string | null;
|
|
70
|
+
}>;
|
|
71
|
+
/**
|
|
72
|
+
* Sign out current user
|
|
73
|
+
*/
|
|
74
|
+
signOut(): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Update user profile
|
|
77
|
+
*/
|
|
78
|
+
updateUser(options: {
|
|
79
|
+
firstName?: string;
|
|
80
|
+
lastName?: string;
|
|
81
|
+
}): Promise<{
|
|
82
|
+
user: ClerkUser;
|
|
83
|
+
}>;
|
|
84
|
+
}
|
|
85
|
+
export interface ClerkUser {
|
|
86
|
+
id: string;
|
|
87
|
+
firstName: string | null;
|
|
88
|
+
lastName: string | null;
|
|
89
|
+
emailAddress: string | null;
|
|
90
|
+
imageUrl: string | null;
|
|
91
|
+
username: string | null;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=definitions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../src/definitions.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE;QAAE,cAAc,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9D;;OAEG;IACH,IAAI,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAE5C;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,YAAY,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAEhF;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAEzE;;OAEG;IACH,kBAAkB,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAE/F;;OAEG;IACH,MAAM,CAAC,OAAO,EAAE;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,oBAAoB,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAEhE;;OAEG;IACH,iBAAiB,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAE3E;;OAEG;IACH,OAAO,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAE/C;;OAEG;IACH,QAAQ,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAE9C;;OAEG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../src/definitions.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD,QAAA,MAAM,WAAW,mBAEf,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { registerPlugin } from '@capacitor/core';
|
|
2
|
+
const ClerkNative = registerPlugin('ClerkNative', {
|
|
3
|
+
web: () => import('./web').then(m => new m.ClerkNativeWeb()),
|
|
4
|
+
});
|
|
5
|
+
export * from './definitions';
|
|
6
|
+
export * from './react';
|
|
7
|
+
export { ClerkNative };
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,WAAW,GAAG,cAAc,CAAoB,aAAa,EAAE;IACnE,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE,CAAC;CAC7D,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface ClerkProviderProps {
|
|
3
|
+
publishableKey: string;
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
}
|
|
6
|
+
export declare function ClerkProvider({ publishableKey, children }: ClerkProviderProps): any;
|
|
7
|
+
export declare function useClerk(): any;
|
|
8
|
+
export declare function useUser(): {
|
|
9
|
+
user: any;
|
|
10
|
+
isLoaded: any;
|
|
11
|
+
isSignedIn: any;
|
|
12
|
+
};
|
|
13
|
+
export declare function useAuth(): {
|
|
14
|
+
isSignedIn: any;
|
|
15
|
+
isLoaded: any;
|
|
16
|
+
signOut: any;
|
|
17
|
+
getToken: any;
|
|
18
|
+
};
|
|
19
|
+
export declare function useSignIn(): {
|
|
20
|
+
isLoaded: any;
|
|
21
|
+
signIn: {
|
|
22
|
+
create: ({ identifier, password }: {
|
|
23
|
+
identifier: string;
|
|
24
|
+
password?: string;
|
|
25
|
+
}) => Promise<any>;
|
|
26
|
+
prepareFirstFactor: () => Promise<void>;
|
|
27
|
+
attemptFirstFactor: ({ strategy, code }: {
|
|
28
|
+
strategy: string;
|
|
29
|
+
code?: string;
|
|
30
|
+
}) => Promise<{
|
|
31
|
+
status: string;
|
|
32
|
+
createdSessionId: string;
|
|
33
|
+
} | {
|
|
34
|
+
status: string;
|
|
35
|
+
createdSessionId?: undefined;
|
|
36
|
+
}>;
|
|
37
|
+
};
|
|
38
|
+
setActive: () => Promise<void>;
|
|
39
|
+
};
|
|
40
|
+
export declare function useSignUp(): {
|
|
41
|
+
isLoaded: any;
|
|
42
|
+
signUp: {
|
|
43
|
+
create: (options: {
|
|
44
|
+
emailAddress: string;
|
|
45
|
+
password: string;
|
|
46
|
+
firstName?: string;
|
|
47
|
+
lastName?: string;
|
|
48
|
+
}) => Promise<{
|
|
49
|
+
status: string;
|
|
50
|
+
}>;
|
|
51
|
+
prepareVerification: () => Promise<void>;
|
|
52
|
+
attemptVerification: ({ strategy, code }: {
|
|
53
|
+
strategy: string;
|
|
54
|
+
code: string;
|
|
55
|
+
}) => Promise<{
|
|
56
|
+
status: string;
|
|
57
|
+
createdSessionId: string;
|
|
58
|
+
} | {
|
|
59
|
+
status: string;
|
|
60
|
+
createdSessionId?: undefined;
|
|
61
|
+
}>;
|
|
62
|
+
};
|
|
63
|
+
setActive: () => Promise<void>;
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsE,MAAM,OAAO,CAAC;AAyB3F,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,wBAAgB,aAAa,CAAC,EAAE,cAAc,EAAE,QAAQ,EAAE,EAAE,kBAAkB,OAyF7E;AAED,wBAAgB,QAAQ,QAMvB;AAED,wBAAgB,OAAO;;;;EAGtB;AAED,wBAAgB,OAAO;;;;;EAGtB;AAED,wBAAgB,SAAS;;;2CAKsB;YAAE,UAAU,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE;;iDAYnC;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE;;;;;;;;;EAYvF;AAED,wBAAgB,SAAS;;;0BAKK;YACtB,YAAY,EAAE,MAAM,CAAC;YACrB,QAAQ,EAAE,MAAM,CAAC;YACjB,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;SACnB;;;;kDAO+C;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE;;;;;;;;;EAYvF"}
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import React, { createContext, useContext, useEffect, useState, useCallback } from 'react';
|
|
2
|
+
import { ClerkNative } from './index';
|
|
3
|
+
const ClerkContext = createContext(null);
|
|
4
|
+
export function ClerkProvider({ publishableKey, children }) {
|
|
5
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
6
|
+
const [user, setUser] = useState(null);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
const initClerk = async () => {
|
|
9
|
+
try {
|
|
10
|
+
await ClerkNative.configure({ publishableKey });
|
|
11
|
+
const result = await ClerkNative.load();
|
|
12
|
+
setUser(result.user);
|
|
13
|
+
setIsLoaded(true);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
console.error('Failed to initialize Clerk:', error);
|
|
17
|
+
setIsLoaded(true);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
initClerk();
|
|
21
|
+
}, [publishableKey]);
|
|
22
|
+
const signInWithEmail = useCallback(async (email) => {
|
|
23
|
+
const result = await ClerkNative.signInWithEmail({ email });
|
|
24
|
+
return result;
|
|
25
|
+
}, []);
|
|
26
|
+
const verifyEmailCode = useCallback(async (code) => {
|
|
27
|
+
const result = await ClerkNative.verifyEmailCode({ code });
|
|
28
|
+
setUser(result.user);
|
|
29
|
+
}, []);
|
|
30
|
+
const signInWithPassword = useCallback(async (email, password) => {
|
|
31
|
+
const result = await ClerkNative.signInWithPassword({ email, password });
|
|
32
|
+
setUser(result.user);
|
|
33
|
+
}, []);
|
|
34
|
+
const signUp = useCallback(async (options) => {
|
|
35
|
+
const result = await ClerkNative.signUp(options);
|
|
36
|
+
if (!result.requiresVerification) {
|
|
37
|
+
setUser(result.user);
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
}, []);
|
|
41
|
+
const verifySignUpEmail = useCallback(async (code) => {
|
|
42
|
+
const result = await ClerkNative.verifySignUpEmail({ code });
|
|
43
|
+
setUser(result.user);
|
|
44
|
+
}, []);
|
|
45
|
+
const signOut = useCallback(async () => {
|
|
46
|
+
await ClerkNative.signOut();
|
|
47
|
+
setUser(null);
|
|
48
|
+
}, []);
|
|
49
|
+
const getToken = useCallback(async () => {
|
|
50
|
+
const result = await ClerkNative.getToken();
|
|
51
|
+
return result.token;
|
|
52
|
+
}, []);
|
|
53
|
+
const updateUser = useCallback(async (options) => {
|
|
54
|
+
const result = await ClerkNative.updateUser(options);
|
|
55
|
+
setUser(result.user);
|
|
56
|
+
}, []);
|
|
57
|
+
const value = {
|
|
58
|
+
isLoaded,
|
|
59
|
+
isSignedIn: user !== null,
|
|
60
|
+
user,
|
|
61
|
+
signInWithEmail,
|
|
62
|
+
verifyEmailCode,
|
|
63
|
+
signInWithPassword,
|
|
64
|
+
signUp,
|
|
65
|
+
verifySignUpEmail,
|
|
66
|
+
signOut,
|
|
67
|
+
getToken,
|
|
68
|
+
updateUser,
|
|
69
|
+
};
|
|
70
|
+
return React.createElement(ClerkContext.Provider, { value: value }, children);
|
|
71
|
+
}
|
|
72
|
+
export function useClerk() {
|
|
73
|
+
const context = useContext(ClerkContext);
|
|
74
|
+
if (!context) {
|
|
75
|
+
throw new Error('useClerk must be used within a ClerkProvider');
|
|
76
|
+
}
|
|
77
|
+
return context;
|
|
78
|
+
}
|
|
79
|
+
export function useUser() {
|
|
80
|
+
const { user, isLoaded, isSignedIn } = useClerk();
|
|
81
|
+
return { user, isLoaded, isSignedIn };
|
|
82
|
+
}
|
|
83
|
+
export function useAuth() {
|
|
84
|
+
const { isSignedIn, isLoaded, signOut, getToken } = useClerk();
|
|
85
|
+
return { isSignedIn, isLoaded, signOut, getToken };
|
|
86
|
+
}
|
|
87
|
+
export function useSignIn() {
|
|
88
|
+
const { signInWithEmail, verifyEmailCode, signInWithPassword, isLoaded } = useClerk();
|
|
89
|
+
return {
|
|
90
|
+
isLoaded,
|
|
91
|
+
signIn: {
|
|
92
|
+
create: async ({ identifier, password }) => {
|
|
93
|
+
// If password is provided, sign in directly with password
|
|
94
|
+
if (password) {
|
|
95
|
+
await signInWithPassword(identifier, password);
|
|
96
|
+
return { status: 'complete', createdSessionId: 'session' };
|
|
97
|
+
}
|
|
98
|
+
// Otherwise, use email code flow
|
|
99
|
+
return signInWithEmail(identifier);
|
|
100
|
+
},
|
|
101
|
+
prepareFirstFactor: async () => {
|
|
102
|
+
// Already handled in signInWithEmail
|
|
103
|
+
},
|
|
104
|
+
attemptFirstFactor: async ({ strategy, code }) => {
|
|
105
|
+
if (strategy === 'email_code' && code) {
|
|
106
|
+
await verifyEmailCode(code);
|
|
107
|
+
return { status: 'complete', createdSessionId: 'session' };
|
|
108
|
+
}
|
|
109
|
+
return { status: 'needs_verification' };
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
setActive: async () => {
|
|
113
|
+
// Session is automatically set in native plugin
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
export function useSignUp() {
|
|
118
|
+
const { signUp, verifySignUpEmail, isLoaded } = useClerk();
|
|
119
|
+
return {
|
|
120
|
+
isLoaded,
|
|
121
|
+
signUp: {
|
|
122
|
+
create: async (options) => {
|
|
123
|
+
await signUp(options);
|
|
124
|
+
return { status: 'needs_verification' };
|
|
125
|
+
},
|
|
126
|
+
prepareVerification: async () => {
|
|
127
|
+
// Already handled in signUp
|
|
128
|
+
},
|
|
129
|
+
attemptVerification: async ({ strategy, code }) => {
|
|
130
|
+
if (strategy === 'email_code') {
|
|
131
|
+
await verifySignUpEmail(code);
|
|
132
|
+
return { status: 'complete', createdSessionId: 'session' };
|
|
133
|
+
}
|
|
134
|
+
return { status: 'needs_verification' };
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
setActive: async () => {
|
|
138
|
+
// Session is automatically set in native plugin
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"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"}
|
package/dist/web.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
import type { ClerkNativePlugin, ClerkUser } from './definitions';
|
|
3
|
+
export declare class ClerkNativeWeb extends WebPlugin implements ClerkNativePlugin {
|
|
4
|
+
configure(_options: {
|
|
5
|
+
publishableKey: string;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
load(): Promise<{
|
|
8
|
+
user: ClerkUser | null;
|
|
9
|
+
}>;
|
|
10
|
+
signInWithEmail(_options: {
|
|
11
|
+
email: string;
|
|
12
|
+
}): Promise<{
|
|
13
|
+
requiresCode: boolean;
|
|
14
|
+
}>;
|
|
15
|
+
verifyEmailCode(_options: {
|
|
16
|
+
code: string;
|
|
17
|
+
}): Promise<{
|
|
18
|
+
user: ClerkUser;
|
|
19
|
+
}>;
|
|
20
|
+
signInWithPassword(_options: {
|
|
21
|
+
email: string;
|
|
22
|
+
password: string;
|
|
23
|
+
}): Promise<{
|
|
24
|
+
user: ClerkUser;
|
|
25
|
+
}>;
|
|
26
|
+
signUp(_options: {
|
|
27
|
+
emailAddress: string;
|
|
28
|
+
password: string;
|
|
29
|
+
firstName?: string;
|
|
30
|
+
lastName?: string;
|
|
31
|
+
}): Promise<{
|
|
32
|
+
user: ClerkUser;
|
|
33
|
+
requiresVerification: boolean;
|
|
34
|
+
}>;
|
|
35
|
+
verifySignUpEmail(_options: {
|
|
36
|
+
code: string;
|
|
37
|
+
}): Promise<{
|
|
38
|
+
user: ClerkUser;
|
|
39
|
+
}>;
|
|
40
|
+
getUser(): Promise<{
|
|
41
|
+
user: ClerkUser | null;
|
|
42
|
+
}>;
|
|
43
|
+
getToken(): Promise<{
|
|
44
|
+
token: string | null;
|
|
45
|
+
}>;
|
|
46
|
+
signOut(): Promise<void>;
|
|
47
|
+
updateUser(_options: {
|
|
48
|
+
firstName?: string;
|
|
49
|
+
lastName?: string;
|
|
50
|
+
}): Promise<{
|
|
51
|
+
user: ClerkUser;
|
|
52
|
+
}>;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=web.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAElE,qBAAa,cAAe,SAAQ,SAAU,YAAW,iBAAiB;IAClE,SAAS,CAAC,QAAQ,EAAE;QAAE,cAAc,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9D,IAAI,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAAA;KAAE,CAAC;IAI3C,eAAe,CAAC,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,YAAY,EAAE,OAAO,CAAA;KAAE,CAAC;IAIhF,eAAe,CAAC,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC;IAIzE,kBAAkB,CAAC,QAAQ,EAAE;QACjC,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC;IAI1B,MAAM,CAAC,QAAQ,EAAE;QACrB,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,oBAAoB,EAAE,OAAO,CAAA;KAAE,CAAC;IAIzD,iBAAiB,CAAC,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC;IAI3E,OAAO,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAAA;KAAE,CAAC;IAI9C,QAAQ,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAI7C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,UAAU,CAAC,QAAQ,EAAE;QACzB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC;CAGjC"}
|
package/dist/web.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
export class ClerkNativeWeb extends WebPlugin {
|
|
3
|
+
async configure(_options) {
|
|
4
|
+
throw this.unimplemented('Clerk Native is only available on iOS and Android');
|
|
5
|
+
}
|
|
6
|
+
async load() {
|
|
7
|
+
throw this.unimplemented('Clerk Native is only available on iOS and Android');
|
|
8
|
+
}
|
|
9
|
+
async signInWithEmail(_options) {
|
|
10
|
+
throw this.unimplemented('Clerk Native is only available on iOS and Android');
|
|
11
|
+
}
|
|
12
|
+
async verifyEmailCode(_options) {
|
|
13
|
+
throw this.unimplemented('Clerk Native is only available on iOS and Android');
|
|
14
|
+
}
|
|
15
|
+
async signInWithPassword(_options) {
|
|
16
|
+
throw this.unimplemented('Clerk Native is only available on iOS and Android');
|
|
17
|
+
}
|
|
18
|
+
async signUp(_options) {
|
|
19
|
+
throw this.unimplemented('Clerk Native is only available on iOS and Android');
|
|
20
|
+
}
|
|
21
|
+
async verifySignUpEmail(_options) {
|
|
22
|
+
throw this.unimplemented('Clerk Native is only available on iOS and Android');
|
|
23
|
+
}
|
|
24
|
+
async getUser() {
|
|
25
|
+
throw this.unimplemented('Clerk Native is only available on iOS and Android');
|
|
26
|
+
}
|
|
27
|
+
async getToken() {
|
|
28
|
+
throw this.unimplemented('Clerk Native is only available on iOS and Android');
|
|
29
|
+
}
|
|
30
|
+
async signOut() {
|
|
31
|
+
throw this.unimplemented('Clerk Native is only available on iOS and Android');
|
|
32
|
+
}
|
|
33
|
+
async updateUser(_options) {
|
|
34
|
+
throw this.unimplemented('Clerk Native is only available on iOS and Android');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=web.js.map
|
package/dist/web.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,OAAO,cAAe,SAAQ,SAAS;IAC3C,KAAK,CAAC,SAAS,CAAC,QAAoC;QAClD,MAAM,IAAI,CAAC,aAAa,CAAC,mDAAmD,CAAC,CAAC;IAChF,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,IAAI,CAAC,aAAa,CAAC,mDAAmD,CAAC,CAAC;IAChF,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,QAA2B;QAC/C,MAAM,IAAI,CAAC,aAAa,CAAC,mDAAmD,CAAC,CAAC;IAChF,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,QAA0B;QAC9C,MAAM,IAAI,CAAC,aAAa,CAAC,mDAAmD,CAAC,CAAC;IAChF,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,QAGxB;QACC,MAAM,IAAI,CAAC,aAAa,CAAC,mDAAmD,CAAC,CAAC;IAChF,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,QAKZ;QACC,MAAM,IAAI,CAAC,aAAa,CAAC,mDAAmD,CAAC,CAAC;IAChF,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,QAA0B;QAChD,MAAM,IAAI,CAAC,aAAa,CAAC,mDAAmD,CAAC,CAAC;IAChF,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,CAAC,aAAa,CAAC,mDAAmD,CAAC,CAAC;IAChF,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,IAAI,CAAC,aAAa,CAAC,mDAAmD,CAAC,CAAC;IAChF,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,CAAC,aAAa,CAAC,mDAAmD,CAAC,CAAC;IAChF,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,QAGhB;QACC,MAAM,IAAI,CAAC,aAAa,CAAC,mDAAmD,CAAC,CAAC;IAChF,CAAC;CACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
#import <Capacitor/Capacitor.h>
|
|
3
|
+
|
|
4
|
+
CAP_PLUGIN(ClerkNativePlugin, "ClerkNative",
|
|
5
|
+
CAP_PLUGIN_METHOD(configure, CAPPluginReturnPromise);
|
|
6
|
+
CAP_PLUGIN_METHOD(load, CAPPluginReturnPromise);
|
|
7
|
+
CAP_PLUGIN_METHOD(signInWithEmail, CAPPluginReturnPromise);
|
|
8
|
+
CAP_PLUGIN_METHOD(verifyEmailCode, CAPPluginReturnPromise);
|
|
9
|
+
CAP_PLUGIN_METHOD(signInWithPassword, CAPPluginReturnPromise);
|
|
10
|
+
CAP_PLUGIN_METHOD(signUp, CAPPluginReturnPromise);
|
|
11
|
+
CAP_PLUGIN_METHOD(verifySignUpEmail, CAPPluginReturnPromise);
|
|
12
|
+
CAP_PLUGIN_METHOD(getUser, CAPPluginReturnPromise);
|
|
13
|
+
CAP_PLUGIN_METHOD(getToken, CAPPluginReturnPromise);
|
|
14
|
+
CAP_PLUGIN_METHOD(signOut, CAPPluginReturnPromise);
|
|
15
|
+
CAP_PLUGIN_METHOD(updateUser, CAPPluginReturnPromise);
|
|
16
|
+
)
|
|
17
|
+
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
|
|
4
|
+
// Protocol for Clerk bridge - the App target will implement this
|
|
5
|
+
@objc public protocol ClerkBridge: AnyObject {
|
|
6
|
+
func signIn(withEmail email: String, password: String, completion: @escaping (String?, Error?) -> Void)
|
|
7
|
+
func signUp(withEmail email: String, password: String, completion: @escaping (String?, Error?) -> Void)
|
|
8
|
+
func signOut(completion: @escaping (Error?) -> Void)
|
|
9
|
+
func getToken(completion: @escaping (String?, Error?) -> Void)
|
|
10
|
+
func getUser(completion: @escaping ([String: Any]?, Error?) -> Void)
|
|
11
|
+
func isSignedIn(completion: @escaping (Bool, Error?) -> Void)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@objc(ClerkNativePlugin)
|
|
15
|
+
public class ClerkNativePlugin: CAPPlugin {
|
|
16
|
+
private weak var clerkBridge: ClerkBridge?
|
|
17
|
+
|
|
18
|
+
@objc public static func setClerkBridge(_ bridge: ClerkBridge) {
|
|
19
|
+
// Store bridge in a static property accessible to all plugin instances
|
|
20
|
+
ClerkNativePlugin.sharedBridge = bridge
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private static var sharedBridge: ClerkBridge?
|
|
24
|
+
|
|
25
|
+
public override func load() {
|
|
26
|
+
super.load()
|
|
27
|
+
clerkBridge = ClerkNativePlugin.sharedBridge
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@objc func configure(_ call: CAPPluginCall) {
|
|
31
|
+
// Configuration is now handled by the bridge in AppDelegate
|
|
32
|
+
call.resolve()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@objc func load(_ call: CAPPluginCall) {
|
|
36
|
+
guard let bridge = clerkBridge else {
|
|
37
|
+
call.reject("Clerk bridge not configured")
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
bridge.getUser { user, error in
|
|
42
|
+
if let error = error {
|
|
43
|
+
call.reject("Failed to load Clerk: \(error.localizedDescription)")
|
|
44
|
+
} else {
|
|
45
|
+
call.resolve(["user": user ?? NSNull()])
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@objc func signInWithPassword(_ call: CAPPluginCall) {
|
|
51
|
+
guard let bridge = clerkBridge else {
|
|
52
|
+
call.reject("Clerk bridge not configured")
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
guard let email = call.getString("email"),
|
|
57
|
+
let password = call.getString("password") else {
|
|
58
|
+
call.reject("Must provide email and password")
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
bridge.signIn(withEmail: email, password: password) { userId, error in
|
|
63
|
+
if let error = error {
|
|
64
|
+
call.reject("Sign in failed: \(error.localizedDescription)")
|
|
65
|
+
} else {
|
|
66
|
+
// Get the full user after sign in
|
|
67
|
+
bridge.getUser { user, getUserError in
|
|
68
|
+
if let getUserError = getUserError {
|
|
69
|
+
call.reject("Sign in succeeded but failed to get user: \(getUserError.localizedDescription)")
|
|
70
|
+
} else {
|
|
71
|
+
call.resolve(["user": user ?? NSNull()])
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@objc func signUp(_ call: CAPPluginCall) {
|
|
79
|
+
guard let bridge = clerkBridge else {
|
|
80
|
+
call.reject("Clerk bridge not configured")
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
guard let email = call.getString("emailAddress"),
|
|
85
|
+
let password = call.getString("password") else {
|
|
86
|
+
call.reject("Must provide emailAddress and password")
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
bridge.signUp(withEmail: email, password: password) { userId, error in
|
|
91
|
+
if let error = error {
|
|
92
|
+
call.reject("Sign up failed: \(error.localizedDescription)")
|
|
93
|
+
} else {
|
|
94
|
+
// Get the full user after sign up
|
|
95
|
+
bridge.getUser { user, getUserError in
|
|
96
|
+
if let getUserError = getUserError {
|
|
97
|
+
call.reject("Sign up succeeded but failed to get user: \(getUserError.localizedDescription)")
|
|
98
|
+
} else {
|
|
99
|
+
call.resolve(["user": user ?? NSNull(), "requiresVerification": false])
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@objc func getUser(_ call: CAPPluginCall) {
|
|
107
|
+
guard let bridge = clerkBridge else {
|
|
108
|
+
call.reject("Clerk bridge not configured")
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
bridge.getUser { user, error in
|
|
113
|
+
if let error = error {
|
|
114
|
+
call.reject("Failed to get user: \(error.localizedDescription)")
|
|
115
|
+
} else {
|
|
116
|
+
call.resolve(["user": user ?? NSNull()])
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@objc func getToken(_ call: CAPPluginCall) {
|
|
122
|
+
guard let bridge = clerkBridge else {
|
|
123
|
+
call.reject("Clerk bridge not configured")
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
bridge.getToken { token, error in
|
|
128
|
+
if let error = error {
|
|
129
|
+
call.reject("Failed to get token: \(error.localizedDescription)")
|
|
130
|
+
} else {
|
|
131
|
+
call.resolve(["token": token ?? NSNull()])
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
@objc func signOut(_ call: CAPPluginCall) {
|
|
137
|
+
guard let bridge = clerkBridge else {
|
|
138
|
+
call.reject("Clerk bridge not configured")
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
bridge.signOut { error in
|
|
143
|
+
if let error = error {
|
|
144
|
+
call.reject("Sign out failed: \(error.localizedDescription)")
|
|
145
|
+
} else {
|
|
146
|
+
call.resolve()
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
@objc func signInWithEmail(_ call: CAPPluginCall) {
|
|
152
|
+
// For now, this just indicates that email code is required
|
|
153
|
+
// The actual sign-in happens with signInWithPassword
|
|
154
|
+
call.resolve(["requiresCode": false])
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
@objc func verifyEmailCode(_ call: CAPPluginCall) {
|
|
158
|
+
// Email code verification - not implemented in simplified bridge
|
|
159
|
+
call.reject("Email code verification not implemented")
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
@objc func verifySignUpEmail(_ call: CAPPluginCall) {
|
|
163
|
+
// Sign up email verification - not implemented in simplified bridge
|
|
164
|
+
call.reject("Sign up email verification not implemented")
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
@objc func updateUser(_ call: CAPPluginCall) {
|
|
168
|
+
// User update - not implemented in simplified bridge
|
|
169
|
+
call.reject("Update user not implemented")
|
|
170
|
+
}
|
|
171
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@trainon-inc/capacitor-clerk-native",
|
|
3
|
+
"version": "1.10.0",
|
|
4
|
+
"description": "Capacitor plugin for Clerk native authentication using bridge pattern to integrate Clerk iOS/Android SDKs with CocoaPods/Gradle",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"android/src/main/",
|
|
20
|
+
"android/build.gradle",
|
|
21
|
+
"dist/",
|
|
22
|
+
"ios/Plugin/",
|
|
23
|
+
"TrainonIncCapacitorClerkNative.podspec",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE"
|
|
26
|
+
],
|
|
27
|
+
"author": "TrainOn Team",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/TrainOn-Inc/capacitor-clerk-native.git"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/TrainOn-Inc/capacitor-clerk-native/issues"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/TrainOn-Inc/capacitor-clerk-native#readme",
|
|
37
|
+
"keywords": [
|
|
38
|
+
"capacitor",
|
|
39
|
+
"capacitor-plugin",
|
|
40
|
+
"plugin",
|
|
41
|
+
"native",
|
|
42
|
+
"clerk",
|
|
43
|
+
"clerk-auth",
|
|
44
|
+
"authentication",
|
|
45
|
+
"ios",
|
|
46
|
+
"android",
|
|
47
|
+
"cocoapods",
|
|
48
|
+
"swift-package-manager",
|
|
49
|
+
"bridge-pattern"
|
|
50
|
+
],
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsc",
|
|
53
|
+
"clean": "rm -rf ./dist",
|
|
54
|
+
"watch": "tsc --watch",
|
|
55
|
+
"prepublishOnly": "npm run clean && npm run build",
|
|
56
|
+
"version": "npm run build",
|
|
57
|
+
"postversion": "git push && git push --tags"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@capacitor/android": "^6.0.0",
|
|
61
|
+
"@capacitor/core": "^6.0.0",
|
|
62
|
+
"@capacitor/ios": "^6.0.0",
|
|
63
|
+
"react": "^19.0.0",
|
|
64
|
+
"typescript": "5.9.3"
|
|
65
|
+
},
|
|
66
|
+
"peerDependencies": {
|
|
67
|
+
"@capacitor/core": "^6.0.0 || ^7.0.0"
|
|
68
|
+
},
|
|
69
|
+
"prettier": "@ionic/prettier-config",
|
|
70
|
+
"eslintConfig": {
|
|
71
|
+
"extends": "@ionic/eslint-config/recommended"
|
|
72
|
+
},
|
|
73
|
+
"capacitor": {
|
|
74
|
+
"ios": {
|
|
75
|
+
"src": "ios"
|
|
76
|
+
},
|
|
77
|
+
"android": {
|
|
78
|
+
"src": "android"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|