Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ let package = Package(
],
dependencies: [
.package(url: "https://github.com/apple/swift-crypto.git", "1.0.0" ..< "4.0.0"),
.package(url: "https://github.com/apple/swift-log", from: "1.6.1"),
.package(url: "https://github.com/pointfreeco/swift-concurrency-extras", from: "1.1.0"),
.package(url: "https://github.com/pointfreeco/swift-custom-dump", from: "1.3.2"),
.package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.17.2"),
Expand All @@ -32,6 +33,7 @@ let package = Package(
.target(
name: "Helpers",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "ConcurrencyExtras", package: "swift-concurrency-extras"),
]
),
Expand All @@ -47,6 +49,7 @@ let package = Package(
dependencies: [
.product(name: "ConcurrencyExtras", package: "swift-concurrency-extras"),
.product(name: "Crypto", package: "swift-crypto"),
.product(name: "Logging", package: "swift-log"),
"Helpers",
]
),
Expand All @@ -66,7 +69,13 @@ let package = Package(
],
resources: [.process("Resources")]
),
.target(name: "Functions", dependencies: ["Helpers"]),
.target(
name: "Functions",
dependencies: [
"Helpers",
.product(name: "Logging", package: "swift-log"),
]
),
.testTarget(
name: "FunctionsTests",
dependencies: [
Expand Down Expand Up @@ -97,6 +106,7 @@ let package = Package(
name: "PostgREST",
dependencies: [
.product(name: "ConcurrencyExtras", package: "swift-concurrency-extras"),
.product(name: "Logging", package: "swift-log"),
"Helpers",
]
),
Expand All @@ -113,6 +123,7 @@ let package = Package(
name: "Realtime",
dependencies: [
.product(name: "ConcurrencyExtras", package: "swift-concurrency-extras"),
.product(name: "Logging", package: "swift-log"),
"Helpers",
]
),
Expand All @@ -130,6 +141,7 @@ let package = Package(
.target(
name: "Storage",
dependencies: [
.product(name: "Logging", package: "swift-log"),
"Helpers",
]
),
Expand All @@ -146,6 +158,7 @@ let package = Package(
dependencies: [
.product(name: "ConcurrencyExtras", package: "swift-concurrency-extras"),
.product(name: "IssueReporting", package: "xctest-dynamic-overlay"),
.product(name: "Logging", package: "swift-log"),
"Auth",
"Functions",
"PostgREST",
Expand Down
6 changes: 6 additions & 0 deletions Sources/Auth/AuthClient.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import ConcurrencyExtras
import Foundation
import Helpers
import Logging

#if canImport(AuthenticationServices)
import AuthenticationServices
Expand All @@ -12,6 +13,8 @@ import Helpers

typealias AuthClientID = UUID

let log = Logger(label: "supabase.auth")

public final class AuthClient: Sendable {
let clientID = AuthClientID()

Expand Down Expand Up @@ -452,6 +455,7 @@ public final class AuthClient: Sendable {
let codeVerifier = codeVerifierStorage.get()

if codeVerifier == nil {
log.error("code verifier not found, a code verifier should exist when calling this method.")
logger?.error("code verifier not found, a code verifier should exist when calling this method.")
}

Expand Down Expand Up @@ -662,6 +666,7 @@ public final class AuthClient: Sendable {
do {
try await session(from: url)
} catch {
log.error("Failure loading session from url '\(url)' error: \(error)")
logger?.error("Failure loading session from url '\(url)' error: \(error)")
}
}
Expand All @@ -670,6 +675,7 @@ public final class AuthClient: Sendable {
/// Gets the session data from a OAuth2 callback URL.
@discardableResult
public func session(from url: URL) async throws -> Session {
log.debug("received \(url)")
logger?.debug("received \(url)")

let params = extractParams(from: url)
Expand Down
1 change: 1 addition & 0 deletions Sources/Auth/AuthClientConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ extension AuthClient {
/// Optional key name used for storing tokens in local storage.
public var storageKey: String?
public let localStorage: any AuthLocalStorage
@available(*, deprecated, message: "SupabaseLogger is deprecated in favor of Logging from apple/swift-log")
public let logger: (any SupabaseLogger)?
public let encoder: JSONEncoder
public let decoder: JSONDecoder
Expand Down
10 changes: 5 additions & 5 deletions Sources/Auth/Internal/APIClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ extension HTTPClient {
init(configuration: AuthClient.Configuration) {
var interceptors: [any HTTPClientInterceptor] = []
if let logger = configuration.logger {
interceptors.append(LoggerInterceptor(logger: logger))
interceptors.append(LoggerInterceptor(logger: logger, log: log))
}

interceptors.append(
Expand Down Expand Up @@ -35,8 +35,8 @@ struct APIClient: Sendable {
var request = request
request.headers = HTTPHeaders(configuration.headers).merged(with: request.headers)

if request.headers[API_VERSION_HEADER_NAME] == nil {
request.headers[API_VERSION_HEADER_NAME] = API_VERSIONS[._20240101]!.name.rawValue
if request.headers[apiVersionHeaderName] == nil {
request.headers[apiVersionHeaderName] = apiVersions[._20240101]!.name.rawValue
}

let response = try await http.send(request)
Expand Down Expand Up @@ -77,7 +77,7 @@ struct APIClient: Sendable {

let responseAPIVersion = parseResponseAPIVersion(response)

let errorCode: ErrorCode? = if let responseAPIVersion, responseAPIVersion >= API_VERSIONS[._20240101]!.timestamp, let code = error.code {
let errorCode: ErrorCode? = if let responseAPIVersion, responseAPIVersion >= apiVersions[._20240101]!.timestamp, let code = error.code {
ErrorCode(code)
} else {
error.errorCode
Expand Down Expand Up @@ -106,7 +106,7 @@ struct APIClient: Sendable {
}

private func parseResponseAPIVersion(_ response: HTTPResponse) -> Date? {
guard let apiVersion = response.headers[API_VERSION_HEADER_NAME] else { return nil }
guard let apiVersion = response.headers[apiVersionHeaderName] else { return nil }

let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
Expand Down
6 changes: 5 additions & 1 deletion Sources/Auth/Internal/CodeVerifierStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,19 @@ struct CodeVerifierStorage: Sendable {
extension CodeVerifierStorage {
static func live(clientID: AuthClientID) -> Self {
var configuration: AuthClient.Configuration { Dependencies[clientID].configuration }
var key: String { "\(configuration.storageKey ?? STORAGE_KEY)-code-verifier" }
var key: String { "\(configuration.storageKey ?? defaultStorageKey)-code-verifier" }

return Self(
get: {
do {
guard let data = try configuration.localStorage.retrieve(key: key) else {
log.debug("Code verifier not found.")
configuration.logger?.debug("Code verifier not found.")
return nil
}
return String(decoding: data, as: UTF8.self)
} catch {
log.error("Failure loading code verifier: \(error.localizedDescription)")
configuration.logger?.error("Failure loading code verifier: \(error.localizedDescription)")
return nil
}
Expand All @@ -32,9 +34,11 @@ extension CodeVerifierStorage {
} else if code == nil {
try configuration.localStorage.remove(key: key)
} else {
log.error("Code verifier is not a valid UTF8 string.")
configuration.logger?.error("Code verifier is not a valid UTF8 string.")
}
} catch {
log.error("Failure storing code verifier: \(error.localizedDescription)")
configuration.logger?.error("Failure storing code verifier: \(error.localizedDescription)")
}
}
Expand Down
8 changes: 4 additions & 4 deletions Sources/Auth/Internal/Contants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

import Foundation

let EXPIRY_MARGIN: TimeInterval = 30
let STORAGE_KEY = "supabase.auth.token"
let defaultExpiryMargin: TimeInterval = 30
let defaultStorageKey = "supabase.auth.token"

let API_VERSION_HEADER_NAME = "X-Supabase-Api-Version"
let API_VERSIONS: [APIVersion.Name: APIVersion] = [
let apiVersionHeaderName = "X-Supabase-Api-Version"
let apiVersions: [APIVersion.Name: APIVersion] = [
._20240101: ._20240101,
]

Expand Down
1 change: 1 addition & 0 deletions Sources/Auth/Internal/EventEmitter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ struct AuthStateChangeEventEmitter {
guard let event else { return }
listener(event.0, event.1)

log.debug("Auth state changed: \(event)")
logger?.verbose("Auth state changed: \(event)")
}
}
Expand Down
8 changes: 8 additions & 0 deletions Sources/Auth/Internal/SessionManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,18 @@ private actor LiveSessionManager {
) {
try await trace(using: logger) {
if let inFlightRefreshTask {
log.debug("refresh already in flight")
logger?.debug("refresh already in flight")
return try await inFlightRefreshTask.value
}

inFlightRefreshTask = Task {
log.debug("refresh task started")
logger?.debug("refresh task started")

defer {
inFlightRefreshTask = nil
log.debug("refresh task ended")
logger?.debug("refresh task ended")
}

Expand Down Expand Up @@ -100,6 +103,7 @@ private actor LiveSessionManager {
do {
try sessionStorage.store(session)
} catch {
log.error("Failed to store session: \(error)")
logger?.error("Failed to store session: \(error)")
}
}
Expand All @@ -108,6 +112,7 @@ private actor LiveSessionManager {
do {
try sessionStorage.delete()
} catch {
log.error("Failed to remove session: \(error)")
logger?.error("Failed to remove session: \(error)")
}
}
Expand All @@ -117,11 +122,13 @@ private actor LiveSessionManager {
merging: ["caller": .string("\(caller)")]
) {
guard configuration.autoRefreshToken else {
log.debug("auto refresh token disabled")
logger?.debug("auto refresh token disabled")
return
}

guard scheduledNextRefreshTask == nil else {
log.debug("refresh task already scheduled")
logger?.debug("refresh task already scheduled")
return
}
Expand All @@ -136,6 +143,7 @@ private actor LiveSessionManager {
// if expiresIn < 0, it will refresh right away.
let timeToRefresh = max(expiresIn * 0.9, 0)

log.debug("scheduled next token refresh in: \(timeToRefresh)s")
logger?.debug("scheduled next token refresh in: \(timeToRefresh)s")

try? await Task.sleep(nanoseconds: NSEC_PER_SEC * UInt64(timeToRefresh))
Expand Down
2 changes: 1 addition & 1 deletion Sources/Auth/Internal/SessionStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ extension SessionStorage {
///
/// It uses value from ``AuthClient/Configuration/storageKey`` or default to `supabase.auth.token` if not provided.
static func key(_ clientID: AuthClientID) -> String {
Dependencies[clientID].configuration.storageKey ?? STORAGE_KEY
Dependencies[clientID].configuration.storageKey ?? defaultStorageKey
}

static func live(clientID: AuthClientID) -> SessionStorage {
Expand Down
2 changes: 1 addition & 1 deletion Sources/Auth/Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public struct Session: Codable, Hashable, Sendable {
/// The 30 second buffer is to account for latency issues.
public var isExpired: Bool {
let expiresAt = Date(timeIntervalSince1970: expiresAt)
return expiresAt.timeIntervalSinceNow < EXPIRY_MARGIN
return expiresAt.timeIntervalSinceNow < defaultExpiryMargin
}
}

Expand Down
5 changes: 4 additions & 1 deletion Sources/Functions/FunctionsClient.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import ConcurrencyExtras
import Foundation
import Helpers
import Logging

#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

let version = Helpers.version

let log = Logger(label: "supabase.functions")

/// An actor representing a client for invoking functions.
public final class FunctionsClient: Sendable {
/// Fetch handler used to make requests.
Expand Down Expand Up @@ -52,7 +55,7 @@ public final class FunctionsClient: Sendable {
) {
var interceptors: [any HTTPClientInterceptor] = []
if let logger {
interceptors.append(LoggerInterceptor(logger: logger))
interceptors.append(LoggerInterceptor(logger: logger, log: log))
}

let http = HTTPClient(fetch: fetch, interceptors: interceptors)
Expand Down
1 change: 1 addition & 0 deletions Sources/Helpers/HTTP/HTTPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import Foundation
import Logging

#if canImport(FoundationNetworking)
import FoundationNetworking
Expand Down
5 changes: 4 additions & 1 deletion Sources/Helpers/HTTP/HTTPResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ package struct HTTPResponse: Sendable {
}

extension HTTPResponse {
package func decoded<T: Decodable>(as _: T.Type = T.self, decoder: JSONDecoder = JSONDecoder()) throws -> T {
package func decoded<T: Decodable>(
as _: T.Type = T.self,
decoder: JSONDecoder = JSONDecoder()
) throws -> T {
try decoder.decode(T.self, from: data)
}
}
20 changes: 19 additions & 1 deletion Sources/Helpers/HTTP/LoggerInterceptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
//

import Foundation
import Logging

package struct LoggerInterceptor: HTTPClientInterceptor {
let logger: any SupabaseLogger
let log: Logger

package init(logger: any SupabaseLogger) {
package init(logger: any SupabaseLogger, log: Logger) {
self.logger = logger
self.log = log
}

package func intercept(
Expand All @@ -28,9 +31,23 @@ package struct LoggerInterceptor: HTTPClientInterceptor {
Body: \(stringfy(request.body))
"""
)
log.trace(
"""
Request: \(urlRequest.httpMethod ?? "") \(urlRequest.url?.absoluteString.removingPercentEncoding ?? "")
Body: \(stringfy(request.body))
"""
)

do {
let response = try await next(request)
log.trace(
"""
Response: Status code: \(response.statusCode) Content-Length: \(
response.underlyingResponse.expectedContentLength
)
Body: \(stringfy(response.data))
"""
)
logger.verbose(
"""
Response: Status code: \(response.statusCode) Content-Length: \(
Expand All @@ -41,6 +58,7 @@ package struct LoggerInterceptor: HTTPClientInterceptor {
)
return response
} catch {
log.error("Response: Failure \(error)")
logger.error("Response: Failure \(error)")
throw error
}
Expand Down
Loading
Loading