Skip to content

Commit 15feaa8

Browse files
committed
refactor
1 parent bcbd1ca commit 15feaa8

File tree

9 files changed

+105
-98
lines changed

9 files changed

+105
-98
lines changed

Sources/Auth/AuthClient.swift

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -669,34 +669,24 @@ public final class AuthClient: Sendable {
669669
let params = extractParams(from: url)
670670

671671
if configuration.flowType == .implicit, !isImplicitGrantFlow(params: params) {
672-
throw SupabaseAuthImplicitGrantRedirectError(
673-
message: "Not a valid implicit grant flow url: \(url)"
674-
)
672+
throw AuthError.implicitGrantRedirect(message: "Not a valid implicit grant flow url: \(url)")
675673
}
676674

677675
if configuration.flowType == .pkce, !isPKCEFlow(params: params) {
678-
throw SupabaseAuthPKCEGrantCodeExchangeError(
679-
message: "Not a valid PKCE flow url: \(url)",
680-
error: nil,
681-
code: nil
682-
)
676+
throw AuthError.pkceGrantCodeExchange(message: "Not a valid PKCE flow url: \(url)")
683677
}
684678

685679
if isPKCEFlow(params: params) {
686680
guard let code = params["code"] else {
687-
throw SupabaseAuthPKCEGrantCodeExchangeError(
688-
message: "No code detected.",
689-
error: nil,
690-
code: nil
691-
)
681+
throw AuthError.pkceGrantCodeExchange(message: "No code detected.")
692682
}
693683

694684
let session = try await exchangeCodeForSession(authCode: code)
695685
return session
696686
}
697687

698688
if params["error"] != nil || params["error_description"] != nil || params["error_code"] != nil {
699-
throw SupabaseAuthPKCEGrantCodeExchangeError(
689+
throw AuthError.pkceGrantCodeExchange(
700690
message: params["error_description"] ?? "Error in URL with unspecified error_description.",
701691
error: params["error"] ?? "unspecified_error",
702692
code: params["error_code"] ?? "unspecified_code"
@@ -709,7 +699,7 @@ public final class AuthClient: Sendable {
709699
let refreshToken = params["refresh_token"],
710700
let tokenType = params["token_type"]
711701
else {
712-
throw SupabaseAuthImplicitGrantRedirectError(message: "No session defined in URL")
702+
throw AuthError.implicitGrantRedirect(message: "No session defined in URL")
713703
}
714704

715705
let expiresAt = params["expires_at"].flatMap(TimeInterval.init)
@@ -810,14 +800,9 @@ public final class AuthClient: Sendable {
810800
headers: [.init(name: "Authorization", value: "Bearer \(accessToken)")]
811801
)
812802
)
813-
} catch let error as SupabaseAuthAPIError {
803+
} catch let AuthError.api(_, _, _, response) where ![404, 403, 401].contains(response.statusCode) {
814804
// ignore 404s since user might not exist anymore
815805
// ignore 401s, and 403s since an invalid or expired JWT should sign out the current session.
816-
let ignoredCodes = Set([404, 403, 401])
817-
818-
if !ignoredCodes.contains(error.status) {
819-
throw error
820-
}
821806
}
822807
}
823808

@@ -1174,7 +1159,7 @@ public final class AuthClient: Sendable {
11741159
@discardableResult
11751160
public func refreshSession(refreshToken: String? = nil) async throws -> Session {
11761161
guard let refreshToken = refreshToken ?? currentSession?.refreshToken else {
1177-
throw SupabaseAuthSessionMissingError()
1162+
throw AuthError.sessionMissing
11781163
}
11791164

11801165
return try await sessionManager.refreshSession(refreshToken)

Sources/Auth/AuthError.swift

Lines changed: 37 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -100,50 +100,43 @@ extension ErrorCode {
100100
public static let InvalidCredentials = ErrorCode("invalid_credentials")
101101
}
102102

103-
/// Represents an error thrown by Auth, either by the client or the server.
104-
public protocol SupabaseAuthError: LocalizedError {
105-
var message: String { get }
106-
var errorCode: ErrorCode { get }
107-
}
108-
109-
public struct SupabaseAuthSessionMissingError: SupabaseAuthError {
110-
public let errorCode: ErrorCode = .SessionNotFound
111-
112-
public let message: String = "Auth session missing."
113-
}
114-
115-
/// Error thrown on certain methods when the password used is deemed weak.
116-
/// Inspect the reasons to identify what password strength rules are inadequate.
117-
public struct SupabaseAuthWeakPasswordError: SupabaseAuthError {
118-
public let errorCode: ErrorCode = .WeakPassword
119-
120-
public let message: String
121-
public let reasons: [String]
122-
}
123-
124-
public struct SupabaseAuthAPIError: SupabaseAuthError {
125-
public let message: String
126-
public let errorCode: ErrorCode
127-
128-
/// The Data response for the underlysing request which caused this error to be thrown.
129-
public let underlyngData: Data
130-
131-
/// The response for the underlysing request which caused this error to be thrown.
132-
public let underlyingResponse: HTTPURLResponse
133-
134-
/// The HTTP status code for the response which caused this error to be thrown.
135-
public var status: Int { underlyingResponse.statusCode }
136-
}
137-
138-
public struct SupabaseAuthPKCEGrantCodeExchangeError: SupabaseAuthError {
139-
public let errorCode: ErrorCode = .Unknown
103+
public enum AuthError: LocalizedError {
104+
case sessionMissing
105+
case weakPassword(message: String, reasons: [String])
106+
case api(
107+
message: String,
108+
errorCode: ErrorCode,
109+
underlyingData: Data,
110+
underlyingResponse: HTTPURLResponse
111+
)
112+
case pkceGrantCodeExchange(message: String, error: String? = nil, code: String? = nil)
113+
case implicitGrantRedirect(message: String)
114+
115+
public var message: String {
116+
switch self {
117+
case .sessionMissing: "Auth session missing."
118+
case let .weakPassword(message, _),
119+
let .api(message, _, _, _),
120+
let .pkceGrantCodeExchange(message, _, _),
121+
let .implicitGrantRedirect(message):
122+
message
123+
}
124+
}
140125

141-
public let message: String
142-
public let error: String?
143-
public let code: String?
144-
}
126+
public var errorCode: ErrorCode {
127+
switch self {
128+
case .sessionMissing: .SessionNotFound
129+
case .weakPassword: .WeakPassword
130+
case let .api(_, errorCode, _, _): errorCode
131+
case .pkceGrantCodeExchange, .implicitGrantRedirect: .Unknown
132+
}
133+
}
145134

146-
public struct SupabaseAuthImplicitGrantRedirectError: SupabaseAuthError {
147-
public let errorCode: ErrorCode = .Unknown
148-
public var message: String
135+
public var errorDescription: String? {
136+
if errorCode == .Unknown {
137+
message
138+
} else {
139+
"\(errorCode.rawValue): \(message)"
140+
}
141+
}
149142
}

Sources/Auth/AuthMFA.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,12 @@ public struct AuthMFA: Sendable {
151151
nextLevel: nextLevel,
152152
currentAuthenticationMethods: currentAuthenticationMethods
153153
)
154-
} catch is SupabaseAuthSessionMissingError {
154+
} catch AuthError.sessionMissing {
155155
return AuthMFAGetAuthenticatorAssuranceLevelResponse(
156156
currentLevel: nil,
157157
nextLevel: nil,
158158
currentAuthenticationMethods: []
159159
)
160-
} catch {
161-
throw error
162160
}
163161
}
164162
}

Sources/Auth/Internal/APIClient.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,15 @@ struct APIClient: Sendable {
6262
return try await execute(request)
6363
}
6464

65-
func handleError(response: HTTPResponse) -> any SupabaseAuthError {
65+
func handleError(response: HTTPResponse) -> AuthError {
6666
guard let error = try? response.decoded(
6767
as: _RawAPIErrorResponse.self,
6868
decoder: configuration.decoder
6969
) else {
70-
return SupabaseAuthAPIError(
70+
return .api(
7171
message: "Unexpected error",
7272
errorCode: .UnexpectedFailure,
73-
underlyngData: response.data,
73+
underlyingData: response.data,
7474
underlyingResponse: response.underlyingResponse
7575
)
7676
}
@@ -84,22 +84,22 @@ struct APIClient: Sendable {
8484
}
8585

8686
if errorCode == nil, let weakPassword = error.weakPassword {
87-
return SupabaseAuthWeakPasswordError(
87+
return .weakPassword(
8888
message: error._getErrorMessage(),
8989
reasons: weakPassword.reasons ?? []
9090
)
9191
} else if errorCode == .WeakPassword {
92-
return SupabaseAuthWeakPasswordError(
92+
return .weakPassword(
9393
message: error._getErrorMessage(),
9494
reasons: error.weakPassword?.reasons ?? []
9595
)
9696
} else if errorCode == .SessionNotFound {
97-
return SupabaseAuthSessionMissingError()
97+
return .sessionMissing
9898
} else {
99-
return SupabaseAuthAPIError(
99+
return .api(
100100
message: error._getErrorMessage(),
101101
errorCode: errorCode ?? .Unknown,
102-
underlyngData: response.data,
102+
underlyingData: response.data,
103103
underlyingResponse: response.underlyingResponse
104104
)
105105
}

Sources/Auth/Internal/SessionManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ private actor LiveSessionManager {
4040
func session() async throws -> Session {
4141
try await trace(using: logger) {
4242
guard let currentSession = try sessionStorage.get() else {
43-
throw SupabaseAuthSessionMissingError()
43+
throw AuthError.sessionMissing
4444
}
4545

4646
if !currentSession.isExpired {

Tests/AuthTests/AuthClientTests.swift

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,7 @@ final class AuthClientTests: XCTestCase {
9797
} catch {
9898
assertInlineSnapshot(of: error, as: .dump) {
9999
"""
100-
▿ SupabaseAuthSessionMissingError
101-
▿ errorCode: ErrorCode
102-
- rawValue: "session_not_found"
103-
- message: "Auth session missing."
100+
- AuthError.sessionMissing
104101
105102
"""
106103
}
@@ -125,10 +122,10 @@ final class AuthClientTests: XCTestCase {
125122

126123
func testSignOutShouldRemoveSessionIfUserIsNotFound() async throws {
127124
sut = makeSUT { _ in
128-
throw SupabaseAuthAPIError(
125+
throw AuthError.api(
129126
message: "",
130127
errorCode: .Unknown,
131-
underlyngData: Data(),
128+
underlyingData: Data(),
132129
underlyingResponse: HTTPURLResponse(url: URL(string: "http://localhost")!, statusCode: 404, httpVersion: nil, headerFields: nil)!
133130
)
134131
}
@@ -156,10 +153,10 @@ final class AuthClientTests: XCTestCase {
156153

157154
func testSignOutShouldRemoveSessionIfJWTIsInvalid() async throws {
158155
sut = makeSUT { _ in
159-
throw SupabaseAuthAPIError(
156+
throw AuthError.api(
160157
message: "",
161158
errorCode: .InvalidCredentials,
162-
underlyngData: Data(),
159+
underlyingData: Data(),
163160
underlyingResponse: HTTPURLResponse(url: URL(string: "http://localhost")!, statusCode: 401, httpVersion: nil, headerFields: nil)!
164161
)
165162
}
@@ -187,10 +184,10 @@ final class AuthClientTests: XCTestCase {
187184

188185
func testSignOutShouldRemoveSessionIf403Returned() async throws {
189186
sut = makeSUT { _ in
190-
throw SupabaseAuthAPIError(
187+
throw AuthError.api(
191188
message: "",
192189
errorCode: .InvalidCredentials,
193-
underlyngData: Data(),
190+
underlyingData: Data(),
194191
underlyingResponse: HTTPURLResponse(url: URL(string: "http://localhost")!, statusCode: 403, httpVersion: nil, headerFields: nil)!
195192
)
196193
}

Tests/AuthTests/AuthErrorTests.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//
2+
// AuthErrorTests.swift
3+
// Supabase
4+
//
5+
// Created by Guilherme Souza on 29/08/24.
6+
//
7+
8+
@testable import Auth
9+
import XCTest
10+
11+
final class AuthErrorTests: XCTestCase {
12+
func testErrors() {
13+
let sessionMissing = AuthError.sessionMissing
14+
XCTAssertEqual(sessionMissing.errorCode, .SessionNotFound)
15+
XCTAssertEqual(sessionMissing.message, "Auth session missing.")
16+
17+
let weakPassword = AuthError.weakPassword(message: "Weak password", reasons: [])
18+
XCTAssertEqual(weakPassword.errorCode, .WeakPassword)
19+
XCTAssertEqual(weakPassword.message, "Weak password")
20+
21+
let api = AuthError.api(
22+
message: "API Error",
23+
errorCode: .EmailConflictIdentityNotDeletable,
24+
underlyingData: Data(),
25+
underlyingResponse: HTTPURLResponse(url: URL(string: "http://localhost")!, statusCode: 400, httpVersion: nil, headerFields: nil)!
26+
)
27+
XCTAssertEqual(api.errorCode, .EmailConflictIdentityNotDeletable)
28+
XCTAssertEqual(api.message, "API Error")
29+
30+
let pkceGrantCodeExchange = AuthError.pkceGrantCodeExchange(message: "PKCE failure", error: nil, code: nil)
31+
XCTAssertEqual(pkceGrantCodeExchange.errorCode, .Unknown)
32+
XCTAssertEqual(pkceGrantCodeExchange.message, "PKCE failure")
33+
34+
let implicitGrantRedirect = AuthError.implicitGrantRedirect(message: "Implicit grant failure")
35+
XCTAssertEqual(implicitGrantRedirect.errorCode, .Unknown)
36+
XCTAssertEqual(implicitGrantRedirect.message, "Implicit grant failure")
37+
}
38+
}

Tests/AuthTests/RequestsTests.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,9 @@ final class RequestsTests: XCTestCase {
181181
} catch {
182182
assertInlineSnapshot(of: error, as: .dump) {
183183
"""
184-
▿ SupabaseAuthImplicitGrantRedirectError
185-
▿ errorCode: ErrorCode
186-
- rawValue: "unknown"
187-
- message: "No session defined in URL"
184+
▿ AuthError
185+
▿ implicitGrantRedirect: (1 element)
186+
- message: "No session defined in URL"
188187
189188
"""
190189
}

Tests/AuthTests/SessionManagerTests.swift

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
import ConcurrencyExtras
1010
import CustomDump
1111
import Helpers
12+
import InlineSnapshotTesting
1213
import TestHelpers
1314
import XCTest
1415
import XCTestDynamicOverlay
15-
import InlineSnapshotTesting
1616

1717
final class SessionManagerTests: XCTestCase {
1818
var http: HTTPClientMock!
@@ -46,14 +46,11 @@ final class SessionManagerTests: XCTestCase {
4646
func testSession_shouldFailWithSessionNotFound() async {
4747
do {
4848
_ = try await sut.session()
49-
XCTFail("Expected a \(SupabaseAuthSessionMissingError()) failure")
49+
XCTFail("Expected a \(AuthError.sessionMissing) failure")
5050
} catch {
5151
assertInlineSnapshot(of: error, as: .dump) {
5252
"""
53-
▿ SupabaseAuthSessionMissingError
54-
▿ errorCode: ErrorCode
55-
- rawValue: "session_not_found"
56-
- message: "Auth session missing."
53+
- AuthError.sessionMissing
5754
5855
"""
5956
}

0 commit comments

Comments
 (0)