diff --git a/Package.swift b/Package.swift index be3c9330..07c87fa5 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.5 +// swift-tools-version:5.7 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -19,14 +19,11 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/supabase-community/gotrue-swift", from: "0.0.7"), + .package(url: "https://github.com/supabase-community/gotrue-swift", from: "0.1.0"), .package(url: "https://github.com/supabase-community/storage-swift.git", branch: "main"), .package(url: "https://github.com/supabase-community/realtime-swift.git", from: "0.0.1"), - .package( - url: "https://github.com/supabase-community/postgrest-swift", - branch: "master" - ), - .package(url: "https://github.com/supabase-community/functions-swift", branch: "main"), + .package(url: "https://github.com/supabase-community/postgrest-swift", from: "1.0.0"), + .package(url: "https://github.com/supabase-community/functions-swift", from: "0.2.0"), ], targets: [ .target( @@ -37,6 +34,14 @@ let package = Package( .product(name: "Realtime", package: "realtime-swift"), .product(name: "PostgREST", package: "postgrest-swift"), .product(name: "Functions", package: "functions-swift"), + ], + swiftSettings: [ + .unsafeFlags( + [ + "-warn-concurrency", + "-enable-actor-data-race-checks", + ] + ) ] ), ] diff --git a/Sources/Supabase/SupabaseClient.swift b/Sources/Supabase/SupabaseClient.swift index 537b1aeb..6b362010 100644 --- a/Sources/Supabase/SupabaseClient.swift +++ b/Sources/Supabase/SupabaseClient.swift @@ -1,5 +1,6 @@ import Foundation import Functions +import Get import GoTrue import PostgREST import Realtime @@ -10,11 +11,6 @@ public class SupabaseClient { private let supabaseURL: URL private let supabaseKey: String private let schema: String - private let restURL: URL - private let realtimeURL: URL - private let authURL: URL - private let storageURL: URL - private let functionsURL: URL /// Supabase Auth allows you to create and manage user sessions for access to data that is secured /// by access policies. @@ -22,34 +18,37 @@ public class SupabaseClient { /// Supabase Storage allows you to manage user-generated content, such as photos or videos. public var storage: SupabaseStorageClient { - var headers: [String: String] = defaultHeaders - headers["Authorization"] = "Bearer \(auth.session?.accessToken ?? supabaseKey)" - return SupabaseStorageClient(url: storageURL.absoluteString, headers: headers, http: self) + SupabaseStorageClient( + url: supabaseURL.appendingPathComponent("/storage/v1").absoluteString, + headers: defaultHeaders, + http: self + ) } /// Database client for Supabase. public var database: PostgrestClient { - var headers: [String: String] = defaultHeaders - headers["Authorization"] = "Bearer \(auth.session?.accessToken ?? supabaseKey)" - return PostgrestClient( - url: restURL.absoluteString, - headers: headers, + PostgrestClient( + url: supabaseURL.appendingPathComponent("/rest/v1"), + headers: defaultHeaders, schema: schema, - http: self + apiClientDelegate: self ) } /// Realtime client for Supabase - public var realtime: RealtimeClient + public var realtime: RealtimeClient { + RealtimeClient( + endPoint: supabaseURL.appendingPathComponent("/realtime/v1").absoluteString, + params: defaultHeaders + ) + } /// Supabase Functions allows you to deploy and invoke edge functions. public var functions: FunctionsClient { - var headers: [String: String] = defaultHeaders - headers["Authorization"] = "Bearer \(auth.session?.accessToken ?? supabaseKey)" - return FunctionsClient( - url: functionsURL, - headers: headers, - http: self + FunctionsClient( + url: supabaseURL.appendingPathComponent("/functions/v1"), + headers: defaultHeaders, + apiClientDelegate: self ) } @@ -60,8 +59,6 @@ public class SupabaseClient { /// - supabaseURL: Unique Supabase project url /// - supabaseKey: Supabase anonymous API Key /// - schema: Database schema name, defaults to `public` - /// - autoRefreshToken: Toggles whether `Supabase.auth` automatically refreshes auth tokens. - /// Defaults to `true` public init( supabaseURL: URL, supabaseKey: String, @@ -72,11 +69,6 @@ public class SupabaseClient { self.supabaseKey = supabaseKey self.schema = schema self.httpClient = httpClient - restURL = supabaseURL.appendingPathComponent("/rest/v1") - realtimeURL = supabaseURL.appendingPathComponent("/realtime/v1") - authURL = supabaseURL.appendingPathComponent("/auth/v1") - storageURL = supabaseURL.appendingPathComponent("/storage/v1") - functionsURL = supabaseURL.appendingPathComponent("/functions/v1") defaultHeaders = [ "X-Client-Info": "supabase-swift/\(version)", @@ -84,53 +76,48 @@ public class SupabaseClient { ] auth = GoTrueClient( - url: authURL, + url: supabaseURL.appendingPathComponent("/auth/v1"), headers: defaultHeaders ) - realtime = RealtimeClient(endPoint: realtimeURL.absoluteString, params: defaultHeaders) } public struct HTTPClient { let storage: StorageHTTPClient - let postgrest: PostgrestHTTPClient - let functions: FunctionsHTTPClient public init( - storage: StorageHTTPClient? = nil, - postgrest: PostgrestHTTPClient? = nil, - functions: FunctionsHTTPClient? = nil + storage: StorageHTTPClient? = nil ) { self.storage = storage ?? DefaultStorageHTTPClient() - self.postgrest = postgrest ?? DefaultPostgrestHTTPClient() - self.functions = functions ?? DefaultFunctionsHTTPClient() } } private let httpClient: HTTPClient } -extension SupabaseClient { - func adapt(request: URLRequest) async throws -> URLRequest { - try? await auth.refreshCurrentSessionIfNeeded() +extension SupabaseClient: APIClientDelegate { + public func client(_: APIClient, willSendRequest request: inout URLRequest) async throws { + if let session = try? await auth.session { + request.setValue( + "\(session.tokenType) \(session.accessToken)", + forHTTPHeaderField: "Authorization" + ) + } + } +} +extension SupabaseClient { + func adapt(request: URLRequest) async -> URLRequest { var request = request - if let accessToken = auth.session?.accessToken { + if let accessToken = try? await auth.session.accessToken { request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") } return request } } -extension SupabaseClient: PostgrestHTTPClient { - public func execute(_ request: URLRequest) async throws -> (Data, HTTPURLResponse) { - let request = try await adapt(request: request) - return try await httpClient.postgrest.execute(request) - } -} - extension SupabaseClient: StorageHTTPClient { public func fetch(_ request: URLRequest) async throws -> (Data, HTTPURLResponse) { - let request = try await adapt(request: request) + let request = await adapt(request: request) return try await httpClient.storage.fetch(request) } @@ -138,17 +125,7 @@ extension SupabaseClient: StorageHTTPClient { _ request: URLRequest, from data: Data ) async throws -> (Data, HTTPURLResponse) { - let request = try await adapt(request: request) + let request = await adapt(request: request) return try await httpClient.storage.upload(request, from: data) } } - -extension SupabaseClient: FunctionsHTTPClient { - public func execute( - _ request: URLRequest, - client: FunctionsClient - ) async throws -> (Data, HTTPURLResponse) { - let request = try await adapt(request: request) - return try await httpClient.functions.execute(request, client: client) - } -}