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
27 changes: 16 additions & 11 deletions Sources/Auth/AuthClient.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import ConcurrencyExtras
import Foundation
import IssueReporting

#if canImport(AuthenticationServices)
import AuthenticationServices
Expand Down Expand Up @@ -121,8 +122,8 @@
/// - Parameters:
/// - configuration: The client configuration.
public init(configuration: Configuration) {
AuthClient.globalClientID += 1

Check warning on line 125 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, MACOS, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Check warning on line 125 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, MACOS, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Check warning on line 125 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, MAC_CATALYST, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Check warning on line 125 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, MAC_CATALYST, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Check warning on line 125 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, IOS, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Check warning on line 125 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, IOS, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6
clientID = AuthClient.globalClientID

Check warning on line 126 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, MACOS, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Check warning on line 126 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, MAC_CATALYST, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Check warning on line 126 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, IOS, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Dependencies[clientID] = Dependencies(
configuration: configuration,
Expand All @@ -132,7 +133,7 @@
sessionStorage: .live(clientID: clientID),
sessionManager: .live(clientID: clientID),
logger: configuration.logger.map {
AuthClientLoggerDecorator(clientID: clientID, decoratee: $0)

Check warning on line 136 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, MACOS, 15.4)

nonisolated property 'clientID' can not be referenced from a non-isolated context; this is an error in Swift 6

Check warning on line 136 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, MAC_CATALYST, 15.4)

nonisolated property 'clientID' can not be referenced from a non-isolated context; this is an error in Swift 6

Check warning on line 136 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, IOS, 15.4)

nonisolated property 'clientID' can not be referenced from a non-isolated context; this is an error in Swift 6
}
)

Expand Down Expand Up @@ -1410,17 +1411,21 @@
let session = try? await session
eventEmitter.emit(.initialSession, session: session, token: token)

logger?.warning(
"""
Initial session emitted after attempting to refresh the local stored session.
This is incorrect behavior and will be fixed in the next major release since it’s a breaking change.
For now, if you want to opt-in to the new behavior, add the trait `EmitLocalSessionAsInitialSession` to your Package.swift file when importing the Supabase dependency.
The new behavior ensures that the locally stored session is always emitted, regardless of its validity or expiration.
If you rely on the initial session to opt users in, you need to add an additional check for `session.isExpired` in the session.

Check https://github.com/supabase/supabase-swift/pull/822 for more information.
"""
)
// Properly expecting issues during tests isn't working as expected, I think because the reportIssue is usually triggered inside an unstructured Task
// because of this I'm disabling issue reporting during tests, so we can use it only for advising developers when running their applications.
if !isTesting {
reportIssue(
"""
Initial session emitted after attempting to refresh the local stored session.
This is incorrect behavior and will be fixed in the next major release since it’s a breaking change.
For now, if you want to opt-in to the new behavior, add the trait `EmitLocalSessionAsInitialSession` to your Package.swift file when importing the Supabase dependency.
The new behavior ensures that the locally stored session is always emitted, regardless of its validity or expiration.
If you rely on the initial session to opt users in, you need to add an additional check for `session.isExpired` in the session.

Check https://github.com/supabase/supabase-swift/pull/822 for more information.
"""
)
}
#endif
}

Expand Down Expand Up @@ -1669,7 +1674,7 @@
final class DefaultPresentationContextProvider: NSObject,
ASWebAuthenticationPresentationContextProviding
{
func presentationAnchor(for _: ASWebAuthenticationSession) -> ASPresentationAnchor {

Check warning on line 1677 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, MACOS, 15.4)

main actor-isolated instance method 'presentationAnchor(for:)' cannot be used to satisfy nonisolated protocol requirement

Check warning on line 1677 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, MACOS, 15.4)

main actor-isolated instance method 'presentationAnchor(for:)' cannot be used to satisfy nonisolated protocol requirement

Check warning on line 1677 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, MAC_CATALYST, 15.4)

main actor-isolated instance method 'presentationAnchor(for:)' cannot be used to satisfy nonisolated protocol requirement

Check warning on line 1677 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, MAC_CATALYST, 15.4)

main actor-isolated instance method 'presentationAnchor(for:)' cannot be used to satisfy nonisolated protocol requirement

Check warning on line 1677 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, IOS, 15.4)

main actor-isolated instance method 'presentationAnchor(for:)' cannot be used to satisfy nonisolated protocol requirement

Check warning on line 1677 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (macOS legacy) (test, IOS, 15.4)

main actor-isolated instance method 'presentationAnchor(for:)' cannot be used to satisfy nonisolated protocol requirement
ASPresentationAnchor()
}
}
Expand Down
11 changes: 10 additions & 1 deletion Sources/Helpers/Codable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import ConcurrencyExtras
import Foundation
import XCTestDynamicOverlay

extension JSONDecoder {
/// Default `JSONDecoder` for decoding types from Supabase.
Expand All @@ -21,7 +22,8 @@ extension JSONDecoder {
}

throw DecodingError.dataCorruptedError(
in: container, debugDescription: "Invalid date format: \(string)"
in: container,
debugDescription: "Invalid date format: \(string)"
)
}
return decoder
Expand All @@ -36,6 +38,13 @@ extension JSONEncoder {
let string = date.iso8601String
try container.encode(string)
}

#if DEBUG
if isTesting {
encoder.outputFormatting = [.sortedKeys]
}
#endif

return encoder
}
}
24 changes: 15 additions & 9 deletions Sources/Realtime/RealtimeChannelV2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ public final class RealtimeChannelV2: Sendable, RealtimeChannelProtocol {
}
headers[.authorization] = "Bearer \(accessToken)"

let body = try await JSONEncoder().encode(
let body = try await JSONEncoder.supabase().encode(
BroadcastMessagePayload(
messages: [
BroadcastMessagePayload.Message(
Expand All @@ -315,7 +315,8 @@ public final class RealtimeChannelV2: Sendable, RealtimeChannelProtocol {
body: body
)

let response = try await withTimeout(interval: timeout ?? socket.options.timeoutInterval) { [self] in
let response = try await withTimeout(interval: timeout ?? socket.options.timeoutInterval) {
[self] in
await Result {
try await socket.http.send(request)
}
Expand Down Expand Up @@ -346,11 +347,17 @@ public final class RealtimeChannelV2: Sendable, RealtimeChannelProtocol {
@MainActor
public func broadcast(event: String, message: JSONObject) async {
if status != .subscribed {
logger?.warning(
"Realtime broadcast() is automatically falling back to REST API. "
+ "This behavior will be deprecated in the future. "
+ "Please use httpSend() explicitly for REST delivery."
)
// Properly expecting issues during tests isn't working as expected, I think because the reportIssue is usually triggered inside an unstructured Task
// because of this I'm disabling issue reporting during tests, so we can use it only for advising developers when running their applications.
if !isTesting {
reportIssue(
"""
Realtime broadcast() is automatically falling back to REST API.
This behavior will be deprecated in the future.
Please use httpSend() explicitly for REST delivery.
"""
)
}

var headers: HTTPFields = [.contentType: "application/json"]
if let apiKey = socket.options.apikey {
Expand All @@ -366,7 +373,7 @@ public final class RealtimeChannelV2: Sendable, RealtimeChannelProtocol {
url: socket.broadcastURL,
method: .post,
headers: headers,
body: JSONEncoder().encode(
body: JSONEncoder.supabase().encode(
BroadcastMessagePayload(
messages: [
BroadcastMessagePayload.Message(
Expand Down Expand Up @@ -751,4 +758,3 @@ public final class RealtimeChannelV2: Sendable, RealtimeChannelProtocol {
push?.didReceive(status: PushStatus(rawValue: status) ?? .ok)
}
}

34 changes: 12 additions & 22 deletions Tests/RealtimeTests/RealtimeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ final class RealtimeTests: XCTestCase {

// Wait for the timeout for rejoining.
await testClock.advance(by: .seconds(timeoutInterval))

// Wait for the retry delay (base delay is 1.0s, but we need to account for jitter)
// The retry delay is calculated as: baseDelay * pow(2, attempt-1) + jitter
// For attempt 2: 1.0 * pow(2, 1) = 2.0s + jitter (up to ±25% = ±0.5s)
Expand Down Expand Up @@ -443,7 +443,7 @@ final class RealtimeTests: XCTestCase {

await testClock.advance(by: .seconds(timeoutInterval))
subscribeTask.cancel()

do {
try await subscribeTask.value
XCTFail("Expected cancellation error but got success")
Expand Down Expand Up @@ -597,26 +597,16 @@ final class RealtimeTests: XCTestCase {
try await channel.broadcast(event: "test", message: ["value": 42])

let request = await http.receivedRequests.last
assertInlineSnapshot(of: request?.urlRequest, as: .raw(pretty: true)) {
"""
POST http://localhost:54321/realtime/v1/api/broadcast
Authorization: Bearer custom.access.token
Content-Type: application/json
apiKey: anon.api.key

{
"messages" : [
{
"event" : "test",
"payload" : {
"value" : 42
},
"private" : false,
"topic" : "realtime:public:messages"
}
]
}
"""
assertInlineSnapshot(of: request?.urlRequest, as: .curl) {
#"""
curl \
--request POST \
--header "Authorization: Bearer custom.access.token" \
--header "Content-Type: application/json" \
--header "apiKey: anon.api.key" \
--data "{\"messages\":[{\"event\":\"test\",\"payload\":{\"value\":42},\"private\":false,\"topic\":\"realtime:public:messages\"}]}" \
"http://localhost:54321/realtime/v1/api/broadcast"
"""#
}
}

Expand Down
Loading