Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add SupabaseLogger #219

Merged
merged 8 commits into from
Jan 16, 2024
Merged
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
23 changes: 19 additions & 4 deletions Examples/UserManagement/Supabase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,28 @@
//

import Foundation
import OSLog
import Supabase

let supabase = SupabaseClient(
supabaseURL: URL(string: "https://PROJECT_ID.supabase.co")!,
supabaseKey: "YOUR_SUPABASE_ANON_KEY",
options: .init(auth: .init(storage: KeychainLocalStorage(
service: "supabase.gotrue.swift",
accessGroup: nil
)))
options: .init(
global: .init(logger: AppLogger())
)
)

struct AppLogger: SupabaseLogger {
let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "supabase")

func log(message: SupabaseLogMessage) {
switch message.level {
case .verbose:
logger.log(level: .info, "\(message.description)")
case .debug:
logger.log(level: .debug, "\(message.description)")
case .warning, .error:
logger.log(level: .error, "\(message.description)")
}
}
}
11 changes: 10 additions & 1 deletion Package.resolved
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
{
"pins" : [
{
"identity" : "keychainaccess",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kishikawakatsumi/KeychainAccess",
"state" : {
"revision" : "84e546727d66f1adc5439debad16270d0fdd04e7",
"version" : "4.2.2"
}
},
{
"identity" : "swift-concurrency-extras",
"kind" : "remoteSourceControl",
Expand Down Expand Up @@ -47,4 +56,4 @@
}
],
"version" : 2
}
}
27 changes: 23 additions & 4 deletions Sources/Auth/AuthClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public actor AuthClient {
public var headers: [String: String]
public let flowType: AuthFlowType
public let localStorage: AuthLocalStorage
public let logger: SupabaseLogger?
public let encoder: JSONEncoder
public let decoder: JSONDecoder
public let fetch: FetchHandler
Expand All @@ -27,6 +28,7 @@ public actor AuthClient {
/// - headers: Custom headers to be included in requests.
/// - flowType: The authentication flow type.
/// - localStorage: The storage mechanism for local data.
/// - logger: The logger to use.
/// - encoder: The JSON encoder to use for encoding requests.
/// - decoder: The JSON decoder to use for decoding responses.
/// - fetch: The asynchronous fetch handler for network requests.
Expand All @@ -35,6 +37,7 @@ public actor AuthClient {
headers: [String: String] = [:],
flowType: AuthFlowType = Configuration.defaultFlowType,
localStorage: AuthLocalStorage,
logger: SupabaseLogger? = nil,
encoder: JSONEncoder = AuthClient.Configuration.jsonEncoder,
decoder: JSONDecoder = AuthClient.Configuration.jsonDecoder,
fetch: @escaping FetchHandler = { try await URLSession.shared.data(for: $0) }
Expand All @@ -45,6 +48,7 @@ public actor AuthClient {
self.headers = headers
self.flowType = flowType
self.localStorage = localStorage
self.logger = logger
self.encoder = encoder
self.decoder = decoder
self.fetch = fetch
Expand Down Expand Up @@ -75,6 +79,10 @@ public actor AuthClient {
Dependencies.current.value!.currentDate
}

private var logger: SupabaseLogger? {
Dependencies.current.value!.logger
}

/// Returns the session, refreshing it if necessary.
///
/// If no session can be found, a ``AuthError/sessionNotFound`` error is thrown.
Expand All @@ -94,6 +102,7 @@ public actor AuthClient {
/// - headers: Custom headers to be included in requests.
/// - flowType: The authentication flow type..
/// - localStorage: The storage mechanism for local data..
/// - logger: The logger to use.
/// - encoder: The JSON encoder to use for encoding requests.
/// - decoder: The JSON decoder to use for decoding responses.
/// - fetch: The asynchronous fetch handler for network requests.
Expand All @@ -102,6 +111,7 @@ public actor AuthClient {
headers: [String: String] = [:],
flowType: AuthFlowType = AuthClient.Configuration.defaultFlowType,
localStorage: AuthLocalStorage,
logger: SupabaseLogger? = nil,
encoder: JSONEncoder = AuthClient.Configuration.jsonEncoder,
decoder: JSONDecoder = AuthClient.Configuration.jsonDecoder,
fetch: @escaping FetchHandler = { try await URLSession.shared.data(for: $0) }
Expand All @@ -112,6 +122,7 @@ public actor AuthClient {
headers: headers,
flowType: flowType,
localStorage: localStorage,
logger: logger,
encoder: encoder,
decoder: decoder,
fetch: fetch
Expand All @@ -124,15 +135,19 @@ public actor AuthClient {
/// - Parameters:
/// - configuration: The client configuration.
public init(configuration: Configuration) {
let api = APIClient.live(http: HTTPClient(fetchHandler: configuration.fetch))
let api = APIClient.live(http: HTTPClient(
logger: configuration.logger,
fetchHandler: configuration.fetch
))

self.init(
configuration: configuration,
sessionManager: .live,
codeVerifierStorage: .live,
api: api,
eventEmitter: .live,
sessionStorage: .live
sessionStorage: .live,
logger: configuration.logger
)
}

Expand All @@ -143,7 +158,8 @@ public actor AuthClient {
codeVerifierStorage: CodeVerifierStorage,
api: APIClient,
eventEmitter: EventEmitter,
sessionStorage: SessionStorage
sessionStorage: SessionStorage,
logger: SupabaseLogger?
) {
mfa = AuthMFA()

Expand All @@ -159,7 +175,8 @@ public actor AuthClient {
try await self?.refreshSession(refreshToken: $0) ?? .empty
}
),
codeVerifierStorage: codeVerifierStorage
codeVerifierStorage: codeVerifierStorage,
logger: logger
)
)
}
Expand All @@ -172,9 +189,11 @@ public actor AuthClient {
session: Session?
)> {
let (id, stream) = eventEmitter.attachListener()
logger?.debug("auth state change listener with id '\(id.uuidString)' attached.")

Task { [id] in
await emitInitialSession(forStreamWithID: id)
logger?.debug("initial session for listener with id '\(id.uuidString)' emitted.")
}

return stream
Expand Down
81 changes: 81 additions & 0 deletions Sources/Auth/Deprecated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@
// Created by Guilherme Souza on 14/12/23.
//

import _Helpers
import Foundation

#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

@available(*, deprecated, renamed: "AuthClient")
public typealias GoTrueClient = AuthClient

Expand Down Expand Up @@ -45,3 +50,79 @@ extension JSONDecoder {
AuthClient.Configuration.jsonDecoder
}
}

extension AuthClient.Configuration {
/// Initializes a AuthClient Configuration with optional parameters.
///
/// - Parameters:
/// - url: The base URL of the Auth server.
/// - headers: Custom headers to be included in requests.
/// - flowType: The authentication flow type.
/// - localStorage: The storage mechanism for local data.
/// - encoder: The JSON encoder to use for encoding requests.
/// - decoder: The JSON decoder to use for decoding responses.
/// - fetch: The asynchronous fetch handler for network requests.
@available(
*,
deprecated,
message: "Replace usages of this initializer with new init(url:headers:flowType:localStorage:logger:encoder:decoder:fetch)"
)
public init(
url: URL,
headers: [String: String] = [:],
flowType: AuthFlowType = Self.defaultFlowType,
localStorage: AuthLocalStorage,
encoder: JSONEncoder = AuthClient.Configuration.jsonEncoder,
decoder: JSONDecoder = AuthClient.Configuration.jsonDecoder,
fetch: @escaping AuthClient.FetchHandler = { try await URLSession.shared.data(for: $0) }
) {
self.init(
url: url,
headers: headers,
flowType: flowType,
localStorage: localStorage,
logger: nil,
encoder: encoder,
decoder: decoder,
fetch: fetch
)
}
}

extension AuthClient {
/// Initializes a AuthClient Configuration with optional parameters.
///
/// - Parameters:
/// - url: The base URL of the Auth server.
/// - headers: Custom headers to be included in requests.
/// - flowType: The authentication flow type.
/// - localStorage: The storage mechanism for local data.
/// - encoder: The JSON encoder to use for encoding requests.
/// - decoder: The JSON decoder to use for decoding responses.
/// - fetch: The asynchronous fetch handler for network requests.
@available(
*,
deprecated,
message: "Replace usages of this initializer with new init(url:headers:flowType:localStorage:logger:encoder:decoder:fetch)"
)
public init(
url: URL,
headers: [String: String] = [:],
flowType: AuthFlowType = Configuration.defaultFlowType,
localStorage: AuthLocalStorage,
encoder: JSONEncoder = AuthClient.Configuration.jsonEncoder,
decoder: JSONDecoder = AuthClient.Configuration.jsonDecoder,
fetch: @escaping AuthClient.FetchHandler = { try await URLSession.shared.data(for: $0) }
) {
self.init(
url: url,
headers: headers,
flowType: flowType,
localStorage: localStorage,
logger: nil,
encoder: encoder,
decoder: decoder,
fetch: fetch
)
}
}
2 changes: 2 additions & 0 deletions Sources/Auth/Internal/Dependencies.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@_spi(Internal) import _Helpers
import ConcurrencyExtras
import Foundation

Expand All @@ -12,4 +13,5 @@ struct Dependencies: Sendable {
var sessionRefresher: SessionRefresher
var codeVerifierStorage: CodeVerifierStorage
var currentDate: @Sendable () -> Date = { Date() }
var logger: SupabaseLogger?
}
12 changes: 12 additions & 0 deletions Sources/Auth/Storage/AuthLocalStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,15 @@ public protocol AuthLocalStorage: Sendable {
func retrieve(key: String) throws -> Data?
func remove(key: String) throws
}

extension AuthClient.Configuration {
#if os(iOS) || os(macOS) || os(watchOS) || os(tvOS)
public static let defaultLocalStorage: AuthLocalStorage = KeychainLocalStorage(
service: "supabase.gotrue.swift",
accessGroup: nil
)
#elseif os(Windows)
public static let defaultLocalStorage: AuthLocalStorage =
WinCredLocalStorage(service: "supabase.gotrue.swift")
#endif
}
80 changes: 80 additions & 0 deletions Sources/PostgREST/Deprecated.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//
// Deprecated.swift
//
//
// Created by Guilherme Souza on 16/01/24.
//

import Foundation

#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

extension PostgrestClient.Configuration {
/// Initializes a new configuration for the PostgREST client.
/// - Parameters:
/// - url: The URL of the PostgREST server.
/// - schema: The schema to use.
/// - headers: The headers to include in requests.
/// - fetch: The fetch handler to use for requests.
/// - encoder: The JSONEncoder to use for encoding.
/// - decoder: The JSONDecoder to use for decoding.
@available(
*,
deprecated,
message: "Replace usages of this initializer with new init(url:schema:headers:logger:fetch:encoder:decoder:)"
)
public init(
url: URL,
schema: String? = nil,
headers: [String: String] = [:],
fetch: @escaping PostgrestClient.FetchHandler = { try await URLSession.shared.data(for: $0) },
encoder: JSONEncoder = PostgrestClient.Configuration.jsonEncoder,
decoder: JSONDecoder = PostgrestClient.Configuration.jsonDecoder
) {
self.init(
url: url,
schema: schema,
headers: headers,
logger: nil,
fetch: fetch,
encoder: encoder,
decoder: decoder
)
}
}

extension PostgrestClient {
/// Creates a PostgREST client with the specified parameters.
/// - Parameters:
/// - url: The URL of the PostgREST server.
/// - schema: The schema to use.
/// - headers: The headers to include in requests.
/// - session: The URLSession to use for requests.
/// - encoder: The JSONEncoder to use for encoding.
/// - decoder: The JSONDecoder to use for decoding.
@available(
*,
deprecated,
message: "Replace usages of this initializer with new init(url:schema:headers:logger:fetch:encoder:decoder:)"
)
public init(
url: URL,
schema: String? = nil,
headers: [String: String] = [:],
fetch: @escaping FetchHandler = { try await URLSession.shared.data(for: $0) },
encoder: JSONEncoder = PostgrestClient.Configuration.jsonEncoder,
decoder: JSONDecoder = PostgrestClient.Configuration.jsonDecoder
) {
self.init(
url: url,
schema: schema,
headers: headers,
logger: nil,
fetch: fetch,
encoder: encoder,
decoder: decoder
)
}
}
4 changes: 2 additions & 2 deletions Sources/PostgREST/PostgrestBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class PostgrestBuilder: @unchecked Sendable {
request: Request
) {
self.configuration = configuration
http = HTTPClient(fetchHandler: configuration.fetch)
http = HTTPClient(logger: configuration.logger, fetchHandler: configuration.fetch)

mutableState = LockIsolated(
MutableState(
Expand Down Expand Up @@ -74,7 +74,7 @@ public class PostgrestBuilder: @unchecked Sendable {
do {
return try configuration.decoder.decode(T.self, from: data)
} catch {
debug("Fail to decode type '\(T.self) with error: \(error)")
configuration.logger?.error("Fail to decode type '\(T.self) with error: \(error)")
throw error
}
}
Expand Down
Loading