Skip to content
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
26 changes: 26 additions & 0 deletions Sources/Supabase/Deprecated.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// Deprecated.swift
//
//
// Created by Guilherme Souza on 15/05/24.
//

import Foundation

extension SupabaseClient {
/// Database client for Supabase.
@available(
*,
deprecated,
message: "Direct access to database is deprecated, please use one of the available methods such as, SupabaseClient.from(_:), SupabaseClient.rpc(_:params:), or SupabaseClient.schema(_:)."
)
public var database: PostgrestClient {
rest
}

/// Realtime client for Supabase
@available(*, deprecated, message: "Use realtimeV2")
public var realtime: RealtimeClient {
_realtime.value
}
}
120 changes: 72 additions & 48 deletions Sources/Supabase/SupabaseClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public typealias SupabaseLogMessage = _Helpers.SupabaseLogMessage
let version = _Helpers.version

/// Supabase Client.
public final class SupabaseClient: @unchecked Sendable {
public final class SupabaseClient: Sendable {
let options: SupabaseClientOptions
let supabaseURL: URL
let supabaseKey: String
Expand All @@ -30,53 +30,74 @@ public final class SupabaseClient: @unchecked Sendable {
/// by access policies.
public let auth: AuthClient

/// Database client for Supabase.
@available(
*,
deprecated,
message: "Direct access to database is deprecated, please use one of the available methods such as, SupabaseClient.from(_:), SupabaseClient.rpc(_:params:), or SupabaseClient.schema(_:)."
)
public var database: PostgrestClient {
rest
}
var rest: PostgrestClient {
mutableState.withValue {
if $0.rest == nil {
$0.rest = PostgrestClient(
url: databaseURL,
schema: options.db.schema,
headers: defaultHeaders.dictionary,
logger: options.global.logger,
fetch: fetchWithAuth,
encoder: options.db.encoder,
decoder: options.db.decoder
)
}

private lazy var rest = PostgrestClient(
url: databaseURL,
schema: options.db.schema,
headers: defaultHeaders.dictionary,
logger: options.global.logger,
fetch: fetchWithAuth,
encoder: options.db.encoder,
decoder: options.db.decoder
)
return $0.rest!
}
}

/// Supabase Storage allows you to manage user-generated content, such as photos or videos.
public private(set) lazy var storage = SupabaseStorageClient(
configuration: StorageClientConfiguration(
url: storageURL,
headers: defaultHeaders.dictionary,
session: StorageHTTPSession(fetch: fetchWithAuth, upload: uploadWithAuth),
logger: options.global.logger
)
)
public var storage: SupabaseStorageClient {
mutableState.withValue {
if $0.storage == nil {
$0.storage = SupabaseStorageClient(
configuration: StorageClientConfiguration(
url: storageURL,
headers: defaultHeaders.dictionary,
session: StorageHTTPSession(fetch: fetchWithAuth, upload: uploadWithAuth),
logger: options.global.logger
)
)
}

/// Realtime client for Supabase
public let realtime: RealtimeClient
return $0.storage!
}
}

let _realtime: UncheckedSendable<RealtimeClient>

/// Realtime client for Supabase
public let realtimeV2: RealtimeClientV2

/// Supabase Functions allows you to deploy and invoke edge functions.
public private(set) lazy var functions = FunctionsClient(
url: functionsURL,
headers: defaultHeaders.dictionary,
region: options.functions.region,
logger: options.global.logger,
fetch: fetchWithAuth
)
public var functions: FunctionsClient {
mutableState.withValue {
if $0.functions == nil {
$0.functions = FunctionsClient(
url: functionsURL,
headers: defaultHeaders.dictionary,
region: options.functions.region,
logger: options.global.logger,
fetch: fetchWithAuth
)
}

return $0.functions!
}
}

let defaultHeaders: HTTPHeaders
private let listenForAuthEventsTask = LockIsolated(Task<Void, Never>?.none)

struct MutableState {
var listenForAuthEventsTask: Task<Void, Never>?
var storage: SupabaseStorageClient?
var rest: PostgrestClient?
var functions: FunctionsClient?
}

private let mutableState = LockIsolated(MutableState())

private var session: URLSession {
options.global.session
Expand Down Expand Up @@ -138,10 +159,12 @@ public final class SupabaseClient: @unchecked Sendable {
}
)

realtime = RealtimeClient(
supabaseURL.appendingPathComponent("/realtime/v1").absoluteString,
headers: defaultHeaders.dictionary,
params: defaultHeaders.dictionary
_realtime = UncheckedSendable(
RealtimeClient(
supabaseURL.appendingPathComponent("/realtime/v1").absoluteString,
headers: defaultHeaders.dictionary,
params: defaultHeaders.dictionary
)
)

var realtimeOptions = options.realtime
Expand Down Expand Up @@ -234,7 +257,7 @@ public final class SupabaseClient: @unchecked Sendable {
}

deinit {
listenForAuthEventsTask.value?.cancel()
mutableState.listenForAuthEventsTask?.cancel()
}

@Sendable
Expand All @@ -259,13 +282,14 @@ public final class SupabaseClient: @unchecked Sendable {
}

private func listenForAuthEvents() {
listenForAuthEventsTask.setValue(
Task {
for await (event, session) in auth.authStateChanges {
await handleTokenChanged(event: event, session: session)
}
let task = Task {
for await (event, session) in auth.authStateChanges {
await handleTokenChanged(event: event, session: session)
}
)
}
mutableState.withValue {
$0.listenForAuthEventsTask = task
}
}

private func handleTokenChanged(event: AuthChangeEvent, session: Session?) async {
Expand Down