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
23 changes: 23 additions & 0 deletions Sources/Storage/StorageApi.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,29 @@ public class StorageApi: @unchecked Sendable {
if configuration.headers["X-Client-Info"] == nil {
configuration.headers["X-Client-Info"] = "storage-swift/\(version)"
}

// if legacy uri is used, replace with new storage host (disables request buffering to allow > 50GB uploads)
// "project-ref.supabase.co" becomes "project-ref.storage.supabase.co"
if configuration.useNewHostname == true {
guard
var components = URLComponents(url: configuration.url, resolvingAgainstBaseURL: false),
let host = components.host
else {
fatalError("Client initialized with invalid URL: \(configuration.url)")
}

let regex = try! NSRegularExpression(pattern: "supabase.(co|in|red)$")

let isSupabaseHost =
regex.firstMatch(in: host, range: NSRange(location: 0, length: host.utf16.count)) != nil

if isSupabaseHost, !host.contains("storage.supabase.") {
components.host = host.replacingOccurrences(of: "supabase.", with: "storage.supabase.")
}

configuration.url = components.url!
}

self.configuration = configuration

var interceptors: [any HTTPClientInterceptor] = []
Expand Down
7 changes: 5 additions & 2 deletions Sources/Storage/SupabaseStorage.swift
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
import Foundation

public struct StorageClientConfiguration: Sendable {
public let url: URL
public var url: URL
public var headers: [String: String]
public let encoder: JSONEncoder
public let decoder: JSONDecoder
public let session: StorageHTTPSession
public let logger: (any SupabaseLogger)?
public let useNewHostname: Bool

public init(
url: URL,
headers: [String: String],
encoder: JSONEncoder = .defaultStorageEncoder,

Check warning on line 15 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (MACOS, 15.4)

'defaultStorageEncoder' is deprecated: Access to storage encoder is going to be removed.

Check warning on line 15 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (MACOS, 15.4)

'defaultStorageEncoder' is deprecated: Access to storage encoder is going to be removed.

Check warning on line 15 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (IOS, 15.4)

'defaultStorageEncoder' is deprecated: Access to storage encoder is going to be removed.

Check warning on line 15 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (IOS, 15.4)

'defaultStorageEncoder' is deprecated: Access to storage encoder is going to be removed.

Check warning on line 15 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (test, MACOS, 16.3)

'defaultStorageEncoder' is deprecated: Access to storage encoder is going to be removed.

Check warning on line 15 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (MACOS, 16.3)

'defaultStorageEncoder' is deprecated: Access to storage encoder is going to be removed.

Check warning on line 15 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (MACOS, 16.3)

'defaultStorageEncoder' is deprecated: Access to storage encoder is going to be removed.

Check warning on line 15 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (MACOS, 16.3)

'defaultStorageEncoder' is deprecated: Access to storage encoder is going to be removed.

Check warning on line 15 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (MAC_CATALYST, 15.4)

'defaultStorageEncoder' is deprecated: Access to storage encoder is going to be removed.

Check warning on line 15 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (MAC_CATALYST, 15.4)

'defaultStorageEncoder' is deprecated: Access to storage encoder is going to be removed.

Check warning on line 15 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / Examples

'defaultStorageEncoder' is deprecated: Access to storage encoder is going to be removed.

Check warning on line 15 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (IOS, 16.3)

'defaultStorageEncoder' is deprecated: Access to storage encoder is going to be removed.

Check warning on line 15 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (IOS, 16.3)

'defaultStorageEncoder' is deprecated: Access to storage encoder is going to be removed.

Check warning on line 15 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (IOS, 16.3)

'defaultStorageEncoder' is deprecated: Access to storage encoder is going to be removed.

Check warning on line 15 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (test, IOS, 16.3)

'defaultStorageEncoder' is deprecated: Access to storage encoder is going to be removed.
decoder: JSONDecoder = .defaultStorageDecoder,

Check warning on line 16 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (MACOS, 15.4)

'defaultStorageDecoder' is deprecated: Access to storage decoder is going to be removed.

Check warning on line 16 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (MACOS, 15.4)

'defaultStorageDecoder' is deprecated: Access to storage decoder is going to be removed.

Check warning on line 16 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (IOS, 15.4)

'defaultStorageDecoder' is deprecated: Access to storage decoder is going to be removed.

Check warning on line 16 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (IOS, 15.4)

'defaultStorageDecoder' is deprecated: Access to storage decoder is going to be removed.

Check warning on line 16 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (test, MACOS, 16.3)

'defaultStorageDecoder' is deprecated: Access to storage decoder is going to be removed.

Check warning on line 16 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (MACOS, 16.3)

'defaultStorageDecoder' is deprecated: Access to storage decoder is going to be removed.

Check warning on line 16 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (MACOS, 16.3)

'defaultStorageDecoder' is deprecated: Access to storage decoder is going to be removed.

Check warning on line 16 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (MACOS, 16.3)

'defaultStorageDecoder' is deprecated: Access to storage decoder is going to be removed.

Check warning on line 16 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (MAC_CATALYST, 15.4)

'defaultStorageDecoder' is deprecated: Access to storage decoder is going to be removed.

Check warning on line 16 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (MAC_CATALYST, 15.4)

'defaultStorageDecoder' is deprecated: Access to storage decoder is going to be removed.

Check warning on line 16 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / Examples

'defaultStorageDecoder' is deprecated: Access to storage decoder is going to be removed.

Check warning on line 16 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (IOS, 16.3)

'defaultStorageDecoder' is deprecated: Access to storage decoder is going to be removed.

Check warning on line 16 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (IOS, 16.3)

'defaultStorageDecoder' is deprecated: Access to storage decoder is going to be removed.

Check warning on line 16 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (IOS, 16.3)

'defaultStorageDecoder' is deprecated: Access to storage decoder is going to be removed.

Check warning on line 16 in Sources/Storage/SupabaseStorage.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (16.3) (test, IOS, 16.3)

'defaultStorageDecoder' is deprecated: Access to storage decoder is going to be removed.
session: StorageHTTPSession = .init(),
logger: (any SupabaseLogger)? = nil
logger: (any SupabaseLogger)? = nil,
useNewHostname: Bool = false
) {
self.url = url
self.headers = headers
self.encoder = encoder
self.decoder = decoder
self.session = session
self.logger = logger
self.useNewHostname = useNewHostname
}
}

Expand Down
3 changes: 2 additions & 1 deletion Sources/Supabase/SupabaseClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ public final class SupabaseClient: Sendable {
url: storageURL,
headers: headers,
session: StorageHTTPSession(fetch: fetchWithAuth, upload: uploadWithAuth),
logger: options.global.logger
logger: options.global.logger,
useNewHostname: options.storage.useNewHostname
)
)
}
Expand Down
18 changes: 16 additions & 2 deletions Sources/Supabase/Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public struct SupabaseClientOptions: Sendable {
public let global: GlobalOptions
public let functions: FunctionsOptions
public let realtime: RealtimeClientOptions
public let storage: StorageOptions

public struct DatabaseOptions: Sendable {
/// The Postgres schema which your tables belong to. Must be on the list of exposed schemas in
Expand Down Expand Up @@ -118,18 +119,29 @@ public struct SupabaseClientOptions: Sendable {
}
}

public struct StorageOptions: Sendable {
/// Whether storage client should be initialized with the new hostname format, i.e. `project-ref.storage.supabase.co`
public let useNewHostname: Bool

public init(useNewHostname: Bool = false) {
self.useNewHostname = useNewHostname
}
}

public init(
db: DatabaseOptions = .init(),
auth: AuthOptions,
global: GlobalOptions = .init(),
functions: FunctionsOptions = .init(),
realtime: RealtimeClientOptions = .init()
realtime: RealtimeClientOptions = .init(),
storage: StorageOptions = .init()
) {
self.db = db
self.auth = auth
self.global = global
self.functions = functions
self.realtime = realtime
self.storage = storage
}
}

Expand All @@ -139,13 +151,15 @@ extension SupabaseClientOptions {
db: DatabaseOptions = .init(),
global: GlobalOptions = .init(),
functions: FunctionsOptions = .init(),
realtime: RealtimeClientOptions = .init()
realtime: RealtimeClientOptions = .init(),
storage: StorageOptions = .init()
) {
self.db = db
auth = .init()
self.global = global
self.functions = functions
self.realtime = realtime
self.storage = storage
}
#endif
}
Expand Down
64 changes: 60 additions & 4 deletions Tests/StorageTests/StorageBucketAPITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import Mocker
import TestHelpers
import XCTest

@testable import Storage

#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

@testable import Storage

final class StorageBucketAPITests: XCTestCase {
let url = URL(string: "http://localhost:54321/storage/v1")!
var storage: SupabaseStorageClient!
Expand Down Expand Up @@ -47,6 +47,60 @@ final class StorageBucketAPITests: XCTestCase {
Mocker.removeAll()
}

func testURLConstruction() {
let urlTestCases = [
(
"https://blah.supabase.co/storage/v1",
"https://blah.storage.supabase.co/storage/v1",
"update legacy prod host to new host"
),
(
"https://blah.supabase.red/storage/v1",
"https://blah.storage.supabase.red/storage/v1",
"update legacy staging host to new host"
),
(
"https://blah.storage.supabase.co/storage/v1",
"https://blah.storage.supabase.co/storage/v1",
"accept new host without modification"
),
(
"https://blah.supabase.co.example.com/storage/v1",
"https://blah.supabase.co.example.com/storage/v1",
"not modify non-platform hosts"
),
(
"http://localhost:1234/storage/v1",
"http://localhost:1234/storage/v1",
"support local host with port without modification"
),
]

for (input, expect, description) in urlTestCases {
XCTContext.runActivity(named: "should \(description) if useNewHostname is true") { _ in
let storage = SupabaseStorageClient(
configuration: StorageClientConfiguration(
url: URL(string: input)!,
headers: [:],
useNewHostname: true
)
)
XCTAssertEqual(storage.configuration.url.absoluteString, expect)
}

XCTContext.runActivity(named: "should not modify host if useNewHostname is false") { _ in
let storage = SupabaseStorageClient(
configuration: StorageClientConfiguration(
url: URL(string: input)!,
headers: [:],
useNewHostname: false
)
)
XCTAssertEqual(storage.configuration.url.absoluteString, input)
}
}
}

func testGetBucket() async throws {
Mock(
url: url.appendingPathComponent("bucket/bucket123"),
Expand Down Expand Up @@ -132,7 +186,8 @@ final class StorageBucketAPITests: XCTestCase {
"created_at": "2024-01-01T00:00:00.000Z",
"updated_at": "2024-01-01T00:00:00.000Z"
}
""".utf8)
""".utf8
)
]
)
.snapshotRequest {
Expand Down Expand Up @@ -171,7 +226,8 @@ final class StorageBucketAPITests: XCTestCase {
"created_at": "2024-01-01T00:00:00.000Z",
"updated_at": "2024-01-01T00:00:00.000Z"
}
""".utf8)
""".utf8
)
]
)
.snapshotRequest {
Expand Down
Loading