Skip to content

Commit 9ed1245

Browse files
committed
fix: add typed AuthError throws to AuthMFA and AuthAdmin methods
- Update AuthMFA methods to use throws(AuthError) for consistent error handling - Update AuthAdmin methods to use throws(AuthError) for consistent error handling - Wrap API calls with wrappingError to ensure proper error type conversion - Add explicit self references in closures where required - Update Types.swift with any necessary type changes for error handling This extends the typed error handling improvements to the MFA and Admin authentication modules, ensuring all authentication-related methods have consistent AuthError typing.
1 parent 3ec7719 commit 9ed1245

File tree

3 files changed

+190
-157
lines changed

3 files changed

+190
-157
lines changed

Sources/Auth/AuthAdmin.swift

Lines changed: 93 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,33 @@ public struct AuthAdmin: Sendable {
1818
/// Get user by id.
1919
/// - Parameter uid: The user's unique identifier.
2020
/// - Note: This function should only be called on a server. Never expose your `service_role` key in the browser.
21-
public func getUserById(_ uid: UUID) async throws -> User {
22-
try await api.execute(
23-
configuration.url.appendingPathComponent("admin/users/\(uid)")
24-
)
25-
.serializingDecodable(User.self, decoder: configuration.decoder)
26-
.value
21+
public func getUserById(_ uid: UUID) async throws(AuthError) -> User {
22+
try await wrappingError {
23+
try await self.api.execute(
24+
self.configuration.url.appendingPathComponent("admin/users/\(uid)")
25+
)
26+
.serializingDecodable(User.self, decoder: self.configuration.decoder)
27+
.value
28+
}
2729
}
2830

2931
/// Updates the user data.
3032
/// - Parameters:
3133
/// - uid: The user id you want to update.
3234
/// - attributes: The data you want to update.
3335
@discardableResult
34-
public func updateUserById(_ uid: UUID, attributes: AdminUserAttributes) async throws -> User {
35-
try await api.execute(
36-
configuration.url.appendingPathComponent("admin/users/\(uid)"),
37-
method: .put,
38-
body: attributes
39-
)
40-
.serializingDecodable(User.self, decoder: configuration.decoder)
41-
.value
36+
public func updateUserById(_ uid: UUID, attributes: AdminUserAttributes) async throws(AuthError)
37+
-> User
38+
{
39+
try await wrappingError {
40+
try await self.api.execute(
41+
self.configuration.url.appendingPathComponent("admin/users/\(uid)"),
42+
method: .put,
43+
body: attributes
44+
)
45+
.serializingDecodable(User.self, decoder: self.configuration.decoder)
46+
.value
47+
}
4248
}
4349

4450
/// Creates a new user.
@@ -48,14 +54,16 @@ public struct AuthAdmin: Sendable {
4854
/// - If you are sure that the created user's email or phone number is legitimate and verified, you can set the ``AdminUserAttributes/emailConfirm`` or ``AdminUserAttributes/phoneConfirm`` param to true.
4955
/// - Warning: Never expose your `service_role` key on the client.
5056
@discardableResult
51-
public func createUser(attributes: AdminUserAttributes) async throws -> User {
52-
try await api.execute(
53-
configuration.url.appendingPathComponent("admin/users"),
54-
method: .post,
55-
body: attributes
56-
)
57-
.serializingDecodable(User.self, decoder: configuration.decoder)
58-
.value
57+
public func createUser(attributes: AdminUserAttributes) async throws(AuthError) -> User {
58+
try await wrappingError {
59+
try await self.api.execute(
60+
self.configuration.url.appendingPathComponent("admin/users"),
61+
method: .post,
62+
body: attributes
63+
)
64+
.serializingDecodable(User.self, decoder: self.configuration.decoder)
65+
.value
66+
}
5967
}
6068

6169
/// Sends an invite link to an email address.
@@ -72,20 +80,22 @@ public struct AuthAdmin: Sendable {
7280
_ email: String,
7381
data: [String: AnyJSON]? = nil,
7482
redirectTo: URL? = nil
75-
) async throws -> User {
76-
try await api.execute(
77-
configuration.url.appendingPathComponent("admin/invite"),
78-
method: .post,
79-
query: (redirectTo ?? configuration.redirectToURL).map {
80-
["redirect_to": $0.absoluteString]
81-
},
82-
body: [
83-
"email": .string(email),
84-
"data": data.map({ AnyJSON.object($0) }) ?? .null,
85-
]
86-
)
87-
.serializingDecodable(User.self, decoder: configuration.decoder)
88-
.value
83+
) async throws(AuthError) -> User {
84+
try await wrappingError {
85+
try await self.api.execute(
86+
self.configuration.url.appendingPathComponent("admin/invite"),
87+
method: .post,
88+
query: (redirectTo ?? self.configuration.redirectToURL).map {
89+
["redirect_to": $0.absoluteString]
90+
},
91+
body: [
92+
"email": .string(email),
93+
"data": data.map({ AnyJSON.object($0) }) ?? .null,
94+
]
95+
)
96+
.serializingDecodable(User.self, decoder: self.configuration.decoder)
97+
.value
98+
}
8999
}
90100

91101
/// Delete a user. Requires `service_role` key.
@@ -95,62 +105,68 @@ public struct AuthAdmin: Sendable {
95105
/// from the auth schema.
96106
///
97107
/// - Warning: Never expose your `service_role` key on the client.
98-
public func deleteUser(id: UUID, shouldSoftDelete: Bool = false) async throws {
99-
_ = try await api.execute(
100-
configuration.url.appendingPathComponent("admin/users/\(id)"),
101-
method: .delete,
102-
body: DeleteUserRequest(shouldSoftDelete: shouldSoftDelete)
103-
).serializingData().value
108+
public func deleteUser(id: UUID, shouldSoftDelete: Bool = false) async throws(AuthError) {
109+
_ = try await wrappingError {
110+
try await self.api.execute(
111+
self.configuration.url.appendingPathComponent("admin/users/\(id)"),
112+
method: .delete,
113+
body: DeleteUserRequest(shouldSoftDelete: shouldSoftDelete)
114+
).serializingData().value
115+
}
104116
}
105117

106118
/// Get a list of users.
107119
///
108120
/// This function should only be called on a server.
109121
///
110122
/// - Warning: Never expose your `service_role` key in the client.
111-
public func listUsers(params: PageParams? = nil) async throws -> ListUsersPaginatedResponse {
123+
public func listUsers(
124+
params: PageParams? = nil
125+
) async throws(AuthError) -> ListUsersPaginatedResponse {
112126
struct Response: Decodable {
113127
let users: [User]
114128
let aud: String
115129
}
116130

117-
let httpResponse = try await api.execute(
118-
configuration.url.appendingPathComponent("admin/users"),
119-
query: [
120-
"page": params?.page?.description ?? "",
121-
"per_page": params?.perPage?.description ?? "",
122-
]
123-
)
124-
.serializingDecodable(Response.self, decoder: configuration.decoder)
125-
.response
126-
127-
let response = try httpResponse.result.get()
128-
129-
var pagination = ListUsersPaginatedResponse(
130-
users: response.users,
131-
aud: response.aud,
132-
lastPage: 0,
133-
total: httpResponse.response?.headers["X-Total-Count"].flatMap(Int.init) ?? 0
134-
)
135-
136-
let links =
137-
httpResponse.response?.headers["Link"].flatMap { $0.components(separatedBy: ",") } ?? []
138-
if !links.isEmpty {
139-
for link in links {
140-
let page = link.components(separatedBy: ";")[0].components(separatedBy: "=")[1].prefix(
141-
while: \.isNumber
142-
)
143-
let rel = link.components(separatedBy: ";")[1].components(separatedBy: "=")[1]
144-
145-
if rel == "\"last\"", let lastPage = Int(page) {
146-
pagination.lastPage = lastPage
147-
} else if rel == "\"next\"", let nextPage = Int(page) {
148-
pagination.nextPage = nextPage
131+
return try await wrappingError {
132+
let httpResponse = try await self.api.execute(
133+
self.configuration.url.appendingPathComponent("admin/users"),
134+
query: [
135+
"page": params?.page?.description ?? "",
136+
"per_page": params?.perPage?.description ?? "",
137+
]
138+
)
139+
.serializingDecodable(Response.self, decoder: self.configuration.decoder)
140+
.response
141+
142+
let response = try httpResponse.result.get()
143+
144+
var pagination = ListUsersPaginatedResponse(
145+
users: response.users,
146+
aud: response.aud,
147+
lastPage: 0,
148+
total: httpResponse.response?.headers["X-Total-Count"].flatMap(Int.init) ?? 0
149+
)
150+
151+
let links =
152+
httpResponse.response?.headers["Link"].flatMap { $0.components(separatedBy: ",") } ?? []
153+
if !links.isEmpty {
154+
for link in links {
155+
let page = link.components(separatedBy: ";")[0].components(separatedBy: "=")[1].prefix(
156+
while: \.isNumber
157+
)
158+
let rel = link.components(separatedBy: ";")[1].components(separatedBy: "=")[1]
159+
160+
if rel == "\"last\"", let lastPage = Int(page) {
161+
pagination.lastPage = lastPage
162+
} else if rel == "\"next\"", let nextPage = Int(page) {
163+
pagination.nextPage = nextPage
164+
}
149165
}
150166
}
151-
}
152167

153-
return pagination
168+
return pagination
169+
}
154170
}
155171

156172
/*

0 commit comments

Comments
 (0)