@capgo/capacitor-supabase 8.0.4
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/CapgoCapacitorSupabase.podspec +18 -0
- package/LICENSE +373 -0
- package/Package.swift +30 -0
- package/README.md +801 -0
- package/android/build.gradle +84 -0
- package/android/src/main/java/ee/forgr/plugin/capacitor_supabase/CapacitorSupabasePlugin.kt +751 -0
- package/dist/docs.json +1718 -0
- package/dist/esm/definitions.d.ts +754 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +33 -0
- package/dist/esm/web.js +68 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +82 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +85 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/CapacitorSupabasePlugin/CapacitorSupabasePlugin.swift +628 -0
- package/ios/Tests/CapacitorSupabasePluginTests/CapacitorSupabasePluginTests.swift +9 -0
- package/package.json +90 -0
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
import Supabase
|
|
4
|
+
|
|
5
|
+
@objc(CapacitorSupabasePlugin)
|
|
6
|
+
public class CapacitorSupabasePlugin: CAPPlugin, CAPBridgedPlugin {
|
|
7
|
+
private let pluginVersion: String = "8.0.4"
|
|
8
|
+
public let identifier = "CapacitorSupabasePlugin"
|
|
9
|
+
public let jsName = "CapacitorSupabase"
|
|
10
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
11
|
+
CAPPluginMethod(name: "initialize", returnType: CAPPluginReturnPromise),
|
|
12
|
+
CAPPluginMethod(name: "signInWithPassword", returnType: CAPPluginReturnPromise),
|
|
13
|
+
CAPPluginMethod(name: "signUp", returnType: CAPPluginReturnPromise),
|
|
14
|
+
CAPPluginMethod(name: "signInWithOAuth", returnType: CAPPluginReturnPromise),
|
|
15
|
+
CAPPluginMethod(name: "signInWithOtp", returnType: CAPPluginReturnPromise),
|
|
16
|
+
CAPPluginMethod(name: "verifyOtp", returnType: CAPPluginReturnPromise),
|
|
17
|
+
CAPPluginMethod(name: "signOut", returnType: CAPPluginReturnPromise),
|
|
18
|
+
CAPPluginMethod(name: "getSession", returnType: CAPPluginReturnPromise),
|
|
19
|
+
CAPPluginMethod(name: "refreshSession", returnType: CAPPluginReturnPromise),
|
|
20
|
+
CAPPluginMethod(name: "getUser", returnType: CAPPluginReturnPromise),
|
|
21
|
+
CAPPluginMethod(name: "setSession", returnType: CAPPluginReturnPromise),
|
|
22
|
+
CAPPluginMethod(name: "select", returnType: CAPPluginReturnPromise),
|
|
23
|
+
CAPPluginMethod(name: "insert", returnType: CAPPluginReturnPromise),
|
|
24
|
+
CAPPluginMethod(name: "update", returnType: CAPPluginReturnPromise),
|
|
25
|
+
CAPPluginMethod(name: "delete", returnType: CAPPluginReturnPromise),
|
|
26
|
+
CAPPluginMethod(name: "getPluginVersion", returnType: CAPPluginReturnPromise)
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
private var supabaseClient: SupabaseClient?
|
|
30
|
+
private var authStateTask: Task<Void, Never>?
|
|
31
|
+
|
|
32
|
+
deinit {
|
|
33
|
+
authStateTask?.cancel()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@objc func initialize(_ call: CAPPluginCall) {
|
|
37
|
+
guard let supabaseUrl = call.getString("supabaseUrl"),
|
|
38
|
+
let supabaseKey = call.getString("supabaseKey"),
|
|
39
|
+
let url = URL(string: supabaseUrl) else {
|
|
40
|
+
call.reject("Missing or invalid supabaseUrl or supabaseKey")
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
supabaseClient = SupabaseClient(
|
|
45
|
+
supabaseURL: url,
|
|
46
|
+
supabaseKey: supabaseKey
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
setupAuthStateListener()
|
|
50
|
+
call.resolve()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private func setupAuthStateListener() {
|
|
54
|
+
authStateTask?.cancel()
|
|
55
|
+
authStateTask = Task { [weak self] in
|
|
56
|
+
guard let client = self?.supabaseClient else { return }
|
|
57
|
+
for await (event, session) in client.auth.authStateChanges {
|
|
58
|
+
guard !Task.isCancelled else { break }
|
|
59
|
+
let eventName: String
|
|
60
|
+
switch event {
|
|
61
|
+
case .initialSession:
|
|
62
|
+
eventName = "INITIAL_SESSION"
|
|
63
|
+
case .signedIn:
|
|
64
|
+
eventName = "SIGNED_IN"
|
|
65
|
+
case .signedOut:
|
|
66
|
+
eventName = "SIGNED_OUT"
|
|
67
|
+
case .tokenRefreshed:
|
|
68
|
+
eventName = "TOKEN_REFRESHED"
|
|
69
|
+
case .userUpdated:
|
|
70
|
+
eventName = "USER_UPDATED"
|
|
71
|
+
case .passwordRecovery:
|
|
72
|
+
eventName = "PASSWORD_RECOVERY"
|
|
73
|
+
default:
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
var data: [String: Any] = ["event": eventName]
|
|
78
|
+
if let session = session {
|
|
79
|
+
data["session"] = self?.sessionToDict(session)
|
|
80
|
+
} else {
|
|
81
|
+
data["session"] = NSNull()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
self?.notifyListeners("authStateChange", data: data)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@objc func signInWithPassword(_ call: CAPPluginCall) {
|
|
90
|
+
guard let client = supabaseClient else {
|
|
91
|
+
call.reject("Supabase client not initialized. Call initialize() first.")
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
guard let email = call.getString("email"),
|
|
96
|
+
let password = call.getString("password") else {
|
|
97
|
+
call.reject("Missing email or password")
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
Task {
|
|
102
|
+
do {
|
|
103
|
+
let session = try await client.auth.signIn(email: email, password: password)
|
|
104
|
+
call.resolve(authResultToDict(session: session, user: session.user))
|
|
105
|
+
} catch {
|
|
106
|
+
call.reject("Sign in failed: \(error.localizedDescription)")
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@objc func signUp(_ call: CAPPluginCall) {
|
|
112
|
+
guard let client = supabaseClient else {
|
|
113
|
+
call.reject("Supabase client not initialized. Call initialize() first.")
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
guard let email = call.getString("email"),
|
|
118
|
+
let password = call.getString("password") else {
|
|
119
|
+
call.reject("Missing email or password")
|
|
120
|
+
return
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let userData = call.getObject("data")
|
|
124
|
+
|
|
125
|
+
Task {
|
|
126
|
+
do {
|
|
127
|
+
let response: AuthResponse
|
|
128
|
+
if let userData = userData {
|
|
129
|
+
let jsonData = try JSONSerialization.data(withJSONObject: userData)
|
|
130
|
+
let decodedData = try JSONDecoder().decode([String: AnyJSON].self, from: jsonData)
|
|
131
|
+
response = try await client.auth.signUp(email: email, password: password, data: decodedData)
|
|
132
|
+
} else {
|
|
133
|
+
response = try await client.auth.signUp(email: email, password: password)
|
|
134
|
+
}
|
|
135
|
+
call.resolve(authResultToDict(session: response.session, user: response.user))
|
|
136
|
+
} catch {
|
|
137
|
+
call.reject("Sign up failed: \(error.localizedDescription)")
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@objc func signInWithOAuth(_ call: CAPPluginCall) {
|
|
143
|
+
guard let client = supabaseClient else {
|
|
144
|
+
call.reject("Supabase client not initialized. Call initialize() first.")
|
|
145
|
+
return
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
guard let providerString = call.getString("provider"),
|
|
149
|
+
let provider = oauthProviderFromString(providerString) else {
|
|
150
|
+
call.reject("Missing or invalid provider")
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let redirectTo = call.getString("redirectTo")
|
|
155
|
+
let scopes = call.getString("scopes")
|
|
156
|
+
|
|
157
|
+
Task {
|
|
158
|
+
do {
|
|
159
|
+
let url = try await client.auth.getOAuthSignInURL(
|
|
160
|
+
provider: provider,
|
|
161
|
+
scopes: scopes,
|
|
162
|
+
redirectTo: redirectTo.flatMap { URL(string: $0) }
|
|
163
|
+
)
|
|
164
|
+
await MainActor.run {
|
|
165
|
+
UIApplication.shared.open(url)
|
|
166
|
+
}
|
|
167
|
+
call.resolve()
|
|
168
|
+
} catch {
|
|
169
|
+
call.reject("OAuth sign in failed: \(error.localizedDescription)")
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
@objc func signInWithOtp(_ call: CAPPluginCall) {
|
|
175
|
+
guard let client = supabaseClient else {
|
|
176
|
+
call.reject("Supabase client not initialized. Call initialize() first.")
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
let email = call.getString("email")
|
|
181
|
+
let phone = call.getString("phone")
|
|
182
|
+
|
|
183
|
+
guard email != nil || phone != nil else {
|
|
184
|
+
call.reject("Either email or phone is required")
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
Task {
|
|
189
|
+
do {
|
|
190
|
+
if let email = email {
|
|
191
|
+
try await client.auth.signInWithOTP(email: email)
|
|
192
|
+
} else if let phone = phone {
|
|
193
|
+
try await client.auth.signInWithOTP(phone: phone)
|
|
194
|
+
}
|
|
195
|
+
call.resolve()
|
|
196
|
+
} catch {
|
|
197
|
+
call.reject("OTP sign in failed: \(error.localizedDescription)")
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
@objc func verifyOtp(_ call: CAPPluginCall) {
|
|
203
|
+
guard let client = supabaseClient else {
|
|
204
|
+
call.reject("Supabase client not initialized. Call initialize() first.")
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
guard let token = call.getString("token"),
|
|
209
|
+
let typeString = call.getString("type") else {
|
|
210
|
+
call.reject("Missing token or type")
|
|
211
|
+
return
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
let email = call.getString("email")
|
|
215
|
+
let phone = call.getString("phone")
|
|
216
|
+
|
|
217
|
+
guard email != nil || phone != nil else {
|
|
218
|
+
call.reject("Either email or phone is required")
|
|
219
|
+
return
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
Task {
|
|
223
|
+
do {
|
|
224
|
+
let response: AuthResponse
|
|
225
|
+
if let email = email {
|
|
226
|
+
let type = emailOtpTypeFromString(typeString)
|
|
227
|
+
response = try await client.auth.verifyOTP(email: email, token: token, type: type)
|
|
228
|
+
} else if let phone = phone {
|
|
229
|
+
let type = phoneOtpTypeFromString(typeString)
|
|
230
|
+
response = try await client.auth.verifyOTP(phone: phone, token: token, type: type)
|
|
231
|
+
} else {
|
|
232
|
+
call.reject("Either email or phone is required")
|
|
233
|
+
return
|
|
234
|
+
}
|
|
235
|
+
call.resolve(authResultToDict(session: response.session, user: response.user))
|
|
236
|
+
} catch {
|
|
237
|
+
call.reject("OTP verification failed: \(error.localizedDescription)")
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
@objc func signOut(_ call: CAPPluginCall) {
|
|
243
|
+
guard let client = supabaseClient else {
|
|
244
|
+
call.reject("Supabase client not initialized. Call initialize() first.")
|
|
245
|
+
return
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
Task {
|
|
249
|
+
do {
|
|
250
|
+
try await client.auth.signOut()
|
|
251
|
+
call.resolve()
|
|
252
|
+
} catch {
|
|
253
|
+
call.reject("Sign out failed: \(error.localizedDescription)")
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
@objc func getSession(_ call: CAPPluginCall) {
|
|
259
|
+
guard let client = supabaseClient else {
|
|
260
|
+
call.reject("Supabase client not initialized. Call initialize() first.")
|
|
261
|
+
return
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
Task {
|
|
265
|
+
do {
|
|
266
|
+
let session = try await client.auth.session
|
|
267
|
+
call.resolve(["session": sessionToDict(session)])
|
|
268
|
+
} catch {
|
|
269
|
+
call.resolve(["session": NSNull()])
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
@objc func refreshSession(_ call: CAPPluginCall) {
|
|
275
|
+
guard let client = supabaseClient else {
|
|
276
|
+
call.reject("Supabase client not initialized. Call initialize() first.")
|
|
277
|
+
return
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
Task {
|
|
281
|
+
do {
|
|
282
|
+
let session = try await client.auth.refreshSession()
|
|
283
|
+
call.resolve(["session": sessionToDict(session)])
|
|
284
|
+
} catch {
|
|
285
|
+
call.reject("Session refresh failed: \(error.localizedDescription)")
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
@objc func getUser(_ call: CAPPluginCall) {
|
|
291
|
+
guard let client = supabaseClient else {
|
|
292
|
+
call.reject("Supabase client not initialized. Call initialize() first.")
|
|
293
|
+
return
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
Task {
|
|
297
|
+
do {
|
|
298
|
+
let user = try await client.auth.user()
|
|
299
|
+
call.resolve(["user": userToDict(user)])
|
|
300
|
+
} catch {
|
|
301
|
+
call.resolve(["user": NSNull()])
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
@objc func setSession(_ call: CAPPluginCall) {
|
|
307
|
+
guard let client = supabaseClient else {
|
|
308
|
+
call.reject("Supabase client not initialized. Call initialize() first.")
|
|
309
|
+
return
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
guard let accessToken = call.getString("accessToken"),
|
|
313
|
+
let refreshToken = call.getString("refreshToken") else {
|
|
314
|
+
call.reject("Missing accessToken or refreshToken")
|
|
315
|
+
return
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
Task {
|
|
319
|
+
do {
|
|
320
|
+
let session = try await client.auth.setSession(accessToken: accessToken, refreshToken: refreshToken)
|
|
321
|
+
call.resolve(["session": sessionToDict(session)])
|
|
322
|
+
} catch {
|
|
323
|
+
call.reject("Set session failed: \(error.localizedDescription)")
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// MARK: - Database Operations
|
|
329
|
+
|
|
330
|
+
@objc func select(_ call: CAPPluginCall) {
|
|
331
|
+
guard let client = supabaseClient else {
|
|
332
|
+
call.reject("Supabase client not initialized. Call initialize() first.")
|
|
333
|
+
return
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
guard let table = call.getString("table") else {
|
|
337
|
+
call.reject("Missing table name")
|
|
338
|
+
return
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
let columns = call.getString("columns") ?? "*"
|
|
342
|
+
let filter = call.getObject("filter")
|
|
343
|
+
let limit = call.getInt("limit")
|
|
344
|
+
let offset = call.getInt("offset")
|
|
345
|
+
let orderBy = call.getString("orderBy")
|
|
346
|
+
let ascending = call.getBool("ascending") ?? true
|
|
347
|
+
let single = call.getBool("single") ?? false
|
|
348
|
+
|
|
349
|
+
Task {
|
|
350
|
+
do {
|
|
351
|
+
var filterQuery = client.from(table).select(columns)
|
|
352
|
+
|
|
353
|
+
if let filter = filter {
|
|
354
|
+
for (key, value) in filter {
|
|
355
|
+
if let stringValue = value as? String {
|
|
356
|
+
filterQuery = filterQuery.eq(key, value: stringValue)
|
|
357
|
+
} else if let intValue = value as? Int {
|
|
358
|
+
filterQuery = filterQuery.eq(key, value: intValue)
|
|
359
|
+
} else if let doubleValue = value as? Double {
|
|
360
|
+
filterQuery = filterQuery.eq(key, value: doubleValue)
|
|
361
|
+
} else if let boolValue = value as? Bool {
|
|
362
|
+
filterQuery = filterQuery.eq(key, value: boolValue)
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
var transformQuery = filterQuery.order(orderBy ?? "id", ascending: ascending)
|
|
368
|
+
|
|
369
|
+
if let limit = limit {
|
|
370
|
+
transformQuery = transformQuery.limit(limit)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if let offset = offset {
|
|
374
|
+
transformQuery = transformQuery.range(from: offset, to: offset + (limit ?? 1000) - 1)
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if single {
|
|
378
|
+
let result: [String: AnyJSON] = try await transformQuery.single().execute().value
|
|
379
|
+
let jsonData = try JSONEncoder().encode(result)
|
|
380
|
+
let dict = try JSONSerialization.jsonObject(with: jsonData)
|
|
381
|
+
call.resolve(["data": dict, "error": NSNull()])
|
|
382
|
+
} else {
|
|
383
|
+
let result: [[String: AnyJSON]] = try await transformQuery.execute().value
|
|
384
|
+
let jsonData = try JSONEncoder().encode(result)
|
|
385
|
+
let array = try JSONSerialization.jsonObject(with: jsonData)
|
|
386
|
+
call.resolve(["data": array, "error": NSNull()])
|
|
387
|
+
}
|
|
388
|
+
} catch {
|
|
389
|
+
call.resolve(["data": NSNull(), "error": error.localizedDescription])
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
@objc func insert(_ call: CAPPluginCall) {
|
|
395
|
+
guard let client = supabaseClient else {
|
|
396
|
+
call.reject("Supabase client not initialized. Call initialize() first.")
|
|
397
|
+
return
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
guard let table = call.getString("table") else {
|
|
401
|
+
call.reject("Missing table name")
|
|
402
|
+
return
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
guard let values = call.getObject("values") else {
|
|
406
|
+
call.reject("Missing values to insert")
|
|
407
|
+
return
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
Task {
|
|
411
|
+
do {
|
|
412
|
+
let jsonData = try JSONSerialization.data(withJSONObject: values)
|
|
413
|
+
let decodedValues = try JSONDecoder().decode([String: AnyJSON].self, from: jsonData)
|
|
414
|
+
let result: [String: AnyJSON] = try await client.from(table)
|
|
415
|
+
.insert(decodedValues)
|
|
416
|
+
.select()
|
|
417
|
+
.single()
|
|
418
|
+
.execute()
|
|
419
|
+
.value
|
|
420
|
+
let resultData = try JSONEncoder().encode(result)
|
|
421
|
+
let dict = try JSONSerialization.jsonObject(with: resultData)
|
|
422
|
+
call.resolve(["data": dict, "error": NSNull()])
|
|
423
|
+
} catch {
|
|
424
|
+
call.resolve(["data": NSNull(), "error": error.localizedDescription])
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
@objc func update(_ call: CAPPluginCall) {
|
|
430
|
+
guard let client = supabaseClient else {
|
|
431
|
+
call.reject("Supabase client not initialized. Call initialize() first.")
|
|
432
|
+
return
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
guard let table = call.getString("table") else {
|
|
436
|
+
call.reject("Missing table name")
|
|
437
|
+
return
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
guard let values = call.getObject("values") else {
|
|
441
|
+
call.reject("Missing values to update")
|
|
442
|
+
return
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
guard let filter = call.getObject("filter"), !filter.isEmpty else {
|
|
446
|
+
call.reject("Missing filter for update operation")
|
|
447
|
+
return
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
Task {
|
|
451
|
+
do {
|
|
452
|
+
let jsonData = try JSONSerialization.data(withJSONObject: values)
|
|
453
|
+
let decodedValues = try JSONDecoder().decode([String: AnyJSON].self, from: jsonData)
|
|
454
|
+
var query = try client.from(table).update(decodedValues)
|
|
455
|
+
|
|
456
|
+
for (key, value) in filter {
|
|
457
|
+
if let stringValue = value as? String {
|
|
458
|
+
query = query.eq(key, value: stringValue)
|
|
459
|
+
} else if let intValue = value as? Int {
|
|
460
|
+
query = query.eq(key, value: intValue)
|
|
461
|
+
} else if let doubleValue = value as? Double {
|
|
462
|
+
query = query.eq(key, value: doubleValue)
|
|
463
|
+
} else if let boolValue = value as? Bool {
|
|
464
|
+
query = query.eq(key, value: boolValue)
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
let result: [[String: AnyJSON]] = try await query.select().execute().value
|
|
469
|
+
let resultData = try JSONEncoder().encode(result)
|
|
470
|
+
let array = try JSONSerialization.jsonObject(with: resultData)
|
|
471
|
+
call.resolve(["data": array, "error": NSNull()])
|
|
472
|
+
} catch {
|
|
473
|
+
call.resolve(["data": NSNull(), "error": error.localizedDescription])
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
@objc func delete(_ call: CAPPluginCall) {
|
|
479
|
+
guard let client = supabaseClient else {
|
|
480
|
+
call.reject("Supabase client not initialized. Call initialize() first.")
|
|
481
|
+
return
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
guard let table = call.getString("table") else {
|
|
485
|
+
call.reject("Missing table name")
|
|
486
|
+
return
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
guard let filter = call.getObject("filter"), !filter.isEmpty else {
|
|
490
|
+
call.reject("Missing filter for delete operation")
|
|
491
|
+
return
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
Task {
|
|
495
|
+
do {
|
|
496
|
+
var query = try client.from(table).delete()
|
|
497
|
+
|
|
498
|
+
for (key, value) in filter {
|
|
499
|
+
if let stringValue = value as? String {
|
|
500
|
+
query = query.eq(key, value: stringValue)
|
|
501
|
+
} else if let intValue = value as? Int {
|
|
502
|
+
query = query.eq(key, value: intValue)
|
|
503
|
+
} else if let doubleValue = value as? Double {
|
|
504
|
+
query = query.eq(key, value: doubleValue)
|
|
505
|
+
} else if let boolValue = value as? Bool {
|
|
506
|
+
query = query.eq(key, value: boolValue)
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
let result: [[String: AnyJSON]] = try await query.select().execute().value
|
|
511
|
+
let resultData = try JSONEncoder().encode(result)
|
|
512
|
+
let array = try JSONSerialization.jsonObject(with: resultData)
|
|
513
|
+
call.resolve(["data": array, "error": NSNull()])
|
|
514
|
+
} catch {
|
|
515
|
+
call.resolve(["data": NSNull(), "error": error.localizedDescription])
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
@objc func getPluginVersion(_ call: CAPPluginCall) {
|
|
521
|
+
call.resolve(["version": self.pluginVersion])
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// MARK: - Helper Methods
|
|
525
|
+
|
|
526
|
+
private func sessionToDict(_ session: Session) -> [String: Any] {
|
|
527
|
+
return [
|
|
528
|
+
"accessToken": session.accessToken,
|
|
529
|
+
"refreshToken": session.refreshToken,
|
|
530
|
+
"tokenType": session.tokenType,
|
|
531
|
+
"expiresIn": session.expiresIn,
|
|
532
|
+
"expiresAt": session.expiresAt,
|
|
533
|
+
"user": userToDict(session.user)
|
|
534
|
+
]
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
private func userToDict(_ user: User) -> [String: Any] {
|
|
538
|
+
var dict: [String: Any] = [
|
|
539
|
+
"id": user.id.uuidString,
|
|
540
|
+
"createdAt": ISO8601DateFormatter().string(from: user.createdAt)
|
|
541
|
+
]
|
|
542
|
+
|
|
543
|
+
if let email = user.email {
|
|
544
|
+
dict["email"] = email
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
if let phone = user.phone {
|
|
548
|
+
dict["phone"] = phone
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if let lastSignInAt = user.lastSignInAt {
|
|
552
|
+
dict["lastSignInAt"] = ISO8601DateFormatter().string(from: lastSignInAt)
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
let userMetadata = user.userMetadata
|
|
556
|
+
if let data = try? JSONEncoder().encode(userMetadata),
|
|
557
|
+
let dict2 = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
|
|
558
|
+
dict["userMetadata"] = dict2
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
let appMetadata = user.appMetadata
|
|
562
|
+
if let data = try? JSONEncoder().encode(appMetadata),
|
|
563
|
+
let dict2 = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
|
|
564
|
+
dict["appMetadata"] = dict2
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
return dict
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
private func authResultToDict(session: Session?, user: User?) -> [String: Any] {
|
|
571
|
+
var result: [String: Any] = [:]
|
|
572
|
+
if let session = session {
|
|
573
|
+
result["session"] = sessionToDict(session)
|
|
574
|
+
} else {
|
|
575
|
+
result["session"] = NSNull()
|
|
576
|
+
}
|
|
577
|
+
if let user = user {
|
|
578
|
+
result["user"] = userToDict(user)
|
|
579
|
+
} else {
|
|
580
|
+
result["user"] = NSNull()
|
|
581
|
+
}
|
|
582
|
+
return result
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
private func oauthProviderFromString(_ provider: String) -> Provider? {
|
|
586
|
+
switch provider.lowercased() {
|
|
587
|
+
case "apple": return .apple
|
|
588
|
+
case "azure": return .azure
|
|
589
|
+
case "bitbucket": return .bitbucket
|
|
590
|
+
case "discord": return .discord
|
|
591
|
+
case "facebook": return .facebook
|
|
592
|
+
case "figma": return .figma
|
|
593
|
+
case "github": return .github
|
|
594
|
+
case "gitlab": return .gitlab
|
|
595
|
+
case "google": return .google
|
|
596
|
+
case "kakao": return .kakao
|
|
597
|
+
case "keycloak": return .keycloak
|
|
598
|
+
case "linkedin": return .linkedin
|
|
599
|
+
case "linkedin_oidc": return .linkedinOIDC
|
|
600
|
+
case "notion": return .notion
|
|
601
|
+
case "slack": return .slack
|
|
602
|
+
case "slack_oidc": return .slackOIDC
|
|
603
|
+
case "spotify": return .spotify
|
|
604
|
+
case "twitch": return .twitch
|
|
605
|
+
case "twitter": return .twitter
|
|
606
|
+
case "workos": return .workos
|
|
607
|
+
case "zoom": return .zoom
|
|
608
|
+
default: return nil
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
private func emailOtpTypeFromString(_ type: String) -> EmailOTPType {
|
|
613
|
+
switch type.lowercased() {
|
|
614
|
+
case "signup": return .signup
|
|
615
|
+
case "magiclink": return .magiclink
|
|
616
|
+
case "recovery": return .recovery
|
|
617
|
+
case "email": return .email
|
|
618
|
+
default: return .email
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
private func phoneOtpTypeFromString(_ type: String) -> MobileOTPType {
|
|
623
|
+
switch type.lowercased() {
|
|
624
|
+
case "sms": return .sms
|
|
625
|
+
default: return .sms
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|