Skip to content

Commit

Permalink
fix: linux build (#350)
Browse files Browse the repository at this point in the history
* fix: linux build

* fix: add missing callback version of receive method

* fix: conditionally import AuthenticationSevices

* ci: run only AuthTests

* add make dot-env step

* Fix tests in linux

* chore: add supported platforms in README

* Update README.md

* ci: add linux job to all workflows
  • Loading branch information
grdsdev committed Apr 22, 2024
1 parent dfe09bc commit e62ad89
Show file tree
Hide file tree
Showing 11 changed files with 245 additions and 96 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/auth.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,21 @@ jobs:
run: sudo xcode-select -s /Applications/Xcode_15.3.app
- name: Run tests
run: PLATFORM="${{ matrix.platform }}" SCHEME=Auth make test-library

test-linux:
name: Test Auth (Linux)
strategy:
fail-fast: false
matrix:
swift-version: ["5.9", "5.10"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-deptch: 0
- uses: swift-actions/setup-swift@v2
with:
swift-version: ${{ matrix.swift-version }}
- run: make dot-env
- name: Run tests
run: swift test --filter AuthTests.
17 changes: 17 additions & 0 deletions .github/workflows/functions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,20 @@ jobs:
run: sudo xcode-select -s /Applications/Xcode_15.3.app
- name: Run tests
run: PLATFORM="${{ matrix.platform }}" SCHEME=Functions make test-library
test-linux:
name: Test Functions (Linux)
strategy:
fail-fast: false
matrix:
swift-version: ["5.9", "5.10"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-deptch: 0
- uses: swift-actions/setup-swift@v2
with:
swift-version: ${{ matrix.swift-version }}
- run: make dot-env
- name: Run tests
run: swift test --filter FunctionsTests.
17 changes: 17 additions & 0 deletions .github/workflows/postgrest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,20 @@ jobs:
run: sudo xcode-select -s /Applications/Xcode_15.3.app
- name: Run tests
run: PLATFORM="${{ matrix.platform }}" SCHEME=PostgREST make test-library
test-linux:
name: Test Postgrest (Linux)
strategy:
fail-fast: false
matrix:
swift-version: ["5.9", "5.10"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-deptch: 0
- uses: swift-actions/setup-swift@v2
with:
swift-version: ${{ matrix.swift-version }}
- run: make dot-env
- name: Run tests
run: swift test --filter PostgRESTTests.
17 changes: 17 additions & 0 deletions .github/workflows/realtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,20 @@ jobs:
run: sudo xcode-select -s /Applications/Xcode_15.3.app
- name: Run tests
run: PLATFORM="${{ matrix.platform }}" SCHEME=Realtime make test-library
test-linux:
name: Test Realtime (Linux)
strategy:
fail-fast: false
matrix:
swift-version: ["5.9", "5.10"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-deptch: 0
- uses: swift-actions/setup-swift@v2
with:
swift-version: ${{ matrix.swift-version }}
- run: make dot-env
- name: Run tests
run: swift test --filter RealtimeTests.
17 changes: 17 additions & 0 deletions .github/workflows/storage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,20 @@ jobs:
run: sudo xcode-select -s /Applications/Xcode_15.3.app
- name: Run tests
run: PLATFORM="${{ matrix.platform }}" SCHEME=Storage make test-library
test-linux:
name: Test Storage (Linux)
strategy:
fail-fast: false
matrix:
swift-version: ["5.9", "5.10"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-deptch: 0
- uses: swift-actions/setup-swift@v2
with:
swift-version: ${{ matrix.swift-version }}
- run: make dot-env
- name: Run tests
run: swift test --filter StorageTests.
17 changes: 17 additions & 0 deletions .github/workflows/supabase.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,20 @@ jobs:
run: sudo xcode-select -s /Applications/Xcode_15.3.app
- name: Run tests
run: PLATFORM="${{ matrix.platform }}" SCHEME=Supabase make test-library
test-linux:
name: Test Supabase (Linux)
strategy:
fail-fast: false
matrix:
swift-version: ["5.9", "5.10"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-deptch: 0
- uses: swift-actions/setup-swift@v2
with:
swift-version: ${{ matrix.swift-version }}
- run: make dot-env
- name: Run tests
run: swift test --filter SupabaseTests.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,22 @@ Supabase client for swift. Mirrors the design of [supabase-js](https://github.co

* Documentation: [https://supabase.com/docs/reference/swift/introduction](https://supabase.com/docs/reference/swift/introduction)

## Supported Platforms

| Platform | Support |
|--------|--------|
| iOS ||
| macOS ||
| watchOS ||
| tvOS ||
| visionOS ||
| Linux | ☑️ |
| Windows | ☑️ |

> ✅ Official support
>
> ☑️ Works but not officially supported, and not guaranttee to keep working on future versions of the library.
## Usage

Install the library using the Swift Package Manager.
Expand Down
129 changes: 67 additions & 62 deletions Sources/Auth/AuthClient.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import _Helpers
import AuthenticationServices
import Foundation

#if canImport(AuthenticationServices)
import AuthenticationServices
#endif

#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
Expand Down Expand Up @@ -652,75 +655,77 @@ public final class AuthClient: @unchecked Sendable {
return try await session(from: resultURL)
}

/// Sign-in an existing user via a third-party provider using ``ASWebAuthenticationSession``.
///
/// - Parameters:
/// - provider: The third-party provider.
/// - redirectTo: A URL to send the user to after they are confirmed.
/// - scopes: A space-separated list of scopes granted to the OAuth application.
/// - queryParams: Additional query params.
/// - configure: A configuration closure that you can use to customize the internal
/// ``ASWebAuthenticationSession`` object.
///
/// - Note: This method support the PKCE flow.
/// - Warning: Do not call `start()` on the `ASWebAuthenticationSession` object inside the
/// `configure` closure, as the method implementation calls it already.
@available(watchOS 6.2, tvOS 16.0, *)
@discardableResult
public func signInWithOAuth(
provider: Provider,
redirectTo: URL? = nil,
scopes: String? = nil,
queryParams: [(name: String, value: String?)] = [],
configure: @Sendable (_ session: ASWebAuthenticationSession) -> Void = { _ in }
) async throws -> Session {
try await signInWithOAuth(
provider: provider,
redirectTo: redirectTo,
scopes: scopes,
queryParams: queryParams
) { @MainActor url in
try await withCheckedThrowingContinuation { continuation in
guard let callbackScheme = (configuration.redirectToURL ?? redirectTo)?.scheme else {
continuation.resume(throwing: AuthError.invalidRedirectScheme)
return
}

#if !os(tvOS) && !os(watchOS)
var presentationContextProvider: DefaultPresentationContextProvider?
#endif

let session = ASWebAuthenticationSession(
url: url,
callbackURLScheme: callbackScheme
) { url, error in
if let error {
continuation.resume(throwing: error)
} else if let url {
continuation.resume(returning: url)
} else {
continuation.resume(throwing: AuthError.missingURL)
#if canImport(AuthenticationServices)
/// Sign-in an existing user via a third-party provider using ``ASWebAuthenticationSession``.
///
/// - Parameters:
/// - provider: The third-party provider.
/// - redirectTo: A URL to send the user to after they are confirmed.
/// - scopes: A space-separated list of scopes granted to the OAuth application.
/// - queryParams: Additional query params.
/// - configure: A configuration closure that you can use to customize the internal
/// ``ASWebAuthenticationSession`` object.
///
/// - Note: This method support the PKCE flow.
/// - Warning: Do not call `start()` on the `ASWebAuthenticationSession` object inside the
/// `configure` closure, as the method implementation calls it already.
@available(watchOS 6.2, tvOS 16.0, *)
@discardableResult
public func signInWithOAuth(
provider: Provider,
redirectTo: URL? = nil,
scopes: String? = nil,
queryParams: [(name: String, value: String?)] = [],
configure: @Sendable (_ session: ASWebAuthenticationSession) -> Void = { _ in }
) async throws -> Session {
try await signInWithOAuth(
provider: provider,
redirectTo: redirectTo,
scopes: scopes,
queryParams: queryParams
) { @MainActor url in
try await withCheckedThrowingContinuation { continuation in
guard let callbackScheme = (configuration.redirectToURL ?? redirectTo)?.scheme else {
continuation.resume(throwing: AuthError.invalidRedirectScheme)
return
}

#if !os(tvOS) && !os(watchOS)
// Keep a strong reference to presentationContextProvider until the flow completes.
_ = presentationContextProvider
var presentationContextProvider: DefaultPresentationContextProvider?
#endif
}

configure(session)

#if !os(tvOS) && !os(watchOS)
if session.presentationContextProvider == nil {
presentationContextProvider = DefaultPresentationContextProvider()
session.presentationContextProvider = presentationContextProvider
let session = ASWebAuthenticationSession(
url: url,
callbackURLScheme: callbackScheme
) { url, error in
if let error {
continuation.resume(throwing: error)
} else if let url {
continuation.resume(returning: url)
} else {
continuation.resume(throwing: AuthError.missingURL)
}

#if !os(tvOS) && !os(watchOS)
// Keep a strong reference to presentationContextProvider until the flow completes.
_ = presentationContextProvider
#endif
}
#endif

session.start()
configure(session)

#if !os(tvOS) && !os(watchOS)
if session.presentationContextProvider == nil {
presentationContextProvider = DefaultPresentationContextProvider()
session.presentationContextProvider = presentationContextProvider
}
#endif

session.start()
}
}
}
}
#endif

/// Gets the session data from a OAuth2 callback URL.
@discardableResult
Expand Down Expand Up @@ -1281,7 +1286,7 @@ extension AuthClient {
public static let authChangeSessionInfoKey = "AuthClient.authChangeSession"
}

#if !os(tvOS) && !os(watchOS)
#if canImport(AuthenticationServices) && !os(tvOS) && !os(watchOS)
@MainActor
final class DefaultPresentationContextProvider: NSObject,
ASWebAuthenticationPresentationContextProviding
Expand Down
11 changes: 11 additions & 0 deletions Sources/Realtime/V2/WebSocketClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,14 @@ final class SocketStream: AsyncSequence, Sendable {
try await task.send(message)
}
}

#if os(Linux) || os(Windows)
extension URLSessionWebSocketTask {
func receive(completionHandler: @Sendable @escaping (Result<URLSessionWebSocketTask.Message, any Error>) -> Void) {
Task {
let result = await Result(catching: { try await self.receive() })
completionHandler(result)
}
}
}
#endif
11 changes: 6 additions & 5 deletions Tests/AuthTests/AuthClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -324,17 +324,18 @@ final class AuthClientTests: XCTestCase {
XCTAssertEqual(emitReceivedEvents.value.map(\.0), [.signedIn])
}

@available(watchOS 6.2, tvOS 16.0, *)
func testSignInWithOAuthWithInvalidRedirecTo() async {
let sut = makeSUT()

do {
try await sut.signInWithOAuth(
provider: .google,
redirectTo: nil
) { _ in
XCTFail("Should not call launchFlow.")
}
redirectTo: nil,
launchFlow: { _ in
XCTFail("Should not call launchFlow.")
return URL(string: "https://supabase.com")!
}
)
} catch let error as AuthError {
XCTAssertEqual(error, .invalidRedirectScheme)
} catch {
Expand Down
Loading

0 comments on commit e62ad89

Please sign in to comment.