Conversation
|
@dblythy I still needs to do a little work on this and test it, but let me know what you think. I won't be for sure without testing, but from parse-community/parse-server#8661 it looks like you might be sending |
📝 WalkthroughSummary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings. WalkthroughThe PR introduces OTP-based authentication support for ParseSwift with completion-based, async/await, and Combine APIs. Additionally, documentation across existing GitHub, Google, and LinkedIn authentication providers is standardized by removing "graph API" terminology. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ParseOTP
participant API as Parse API
participant AuthUser as AuthenticatedUser
User->>ParseOTP: verify(token)
ParseOTP->>AuthUser: Read current user
AuthUser-->>ParseOTP: Current user + existing token
ParseOTP->>ParseOTP: Preserve token as oldToken
ParseOTP->>ParseOTP: Inject new token into authData
ParseOTP->>ParseOTP: link(authData)
ParseOTP->>API: Link request with OTP authData
API-->>ParseOTP: Authentication result
ParseOTP-->>User: AuthenticatedUser
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR adds OTP (One-Time Password) authenticator support to ParseSwift by introducing three new files: ParseOTP.swift, ParseOTP+async.swift, and ParseOTP+combine.swift. The implementation follows the existing pattern used for third-party authenticators like Apple, Facebook, and Google.
Changes:
- Added ParseOTP authenticator implementation with support for OTP-based multi-factor authentication
- Provided async/await and Combine variants for the OTP authenticator
- Updated Xcode project to include the new ParseOTP files and organize 3rd party authenticators alphabetically
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 12
🤖 Fix all issues with AI agents
In `@Sources/ParseSwift/Authentication/3rd` Party/ParseOTP/ParseOTP.swift:
- Around line 216-228: The error message in the guard that calls
AuthenticationKeys.token.verifyMandatoryKeys(authData:) is incorrect (it
mentions "id", "idToken", "accessToken" from Google); update the completion
error message inside that guard to accurately state the required OTP keys
("token" or "mobile") so the failure returned by ParseOTP.verifyMandatoryKeys
reflects the real expected keys; locate the guard in ParseOTP.swift and replace
the message passed to .init(message:) with a concise message saying the authData
must contain "token" or "mobile".
- Around line 210-236: The completion closure parameter in
ParseOTP.link(authData:options:callbackQueue:completion:) must be declared
`@Sendable` to match the `@Sendable` expectation of AuthenticatedUser.link; update
the method signature to mark the completion parameter as `@Sendable` (and ensure
any internal forwarding still passes it unchanged to AuthenticatedUser.link).
Apply the same `@Sendable` annotation to the other ParseOTP.link overloads (the
other link methods in this file) so all link(...) completion handlers match
AuthenticatedUser.link's `@Sendable` requirement.
- Around line 115-153: verify currently invokes completion directly inside the
Task error paths (when AuthenticatedUser.current() fails or when authData is
missing) which ignores the provided callbackQueue; update both failure branches
to dispatch the completion call onto callbackQueue (e.g., callbackQueue.async {
completion(.failure(...)) }) so that all completion calls from verify (including
errors) honor the callbackQueue the caller provided; refer to the verify
function, the completion closure, callbackQueue parameter, and existing
link(...) success path for consistency.
- Around line 86-102: The completion closure in ParseOTP.login should be marked
`@Sendable` to satisfy Swift 6 concurrency checking; update the method signature
for login to declare completion as `@Sendable` `@escaping`
(Result<AuthenticatedUser, ParseError>) -> Void (i.e., change completion:
`@escaping` to completion: `@Sendable` `@escaping`) and adjust any callers if
necessary to match the new closure type (referencing the
login(authData:options:callbackQueue:completion:) function and its completion
parameter).
In `@Sources/ParseSwift/Authentication/3rd` Party/ParseOTP/ParseOTP+async.swift:
- Around line 23-38: The async wrapper login(id:idToken:accessToken:options:) in
ParseOTP+async.swift calls a non-existent completion-based overload; remove this
async wrapper or rewrite it to use the existing API by converting to the
authData variant: call the class's
login(authData:options:callbackQueue:completion:) (or delete the async login
entirely since ParseOTP currently returns "login not supported"); update or
remove the function named login in ParseOTP+async.swift so it no longer calls
self.login(id:idToken:accessToken:options:completion:).
- Around line 46-57: The async wrapper login(authData:options:) must accept and
forward the missing callbackQueue required by the underlying method
login(authData:options:callbackQueue:completion:); update the async function
signature to include a callbackQueue parameter (matching the underlying method's
type and default if present) and forward that parameter in the call to
self.login(..., callbackQueue: callbackQueue, completion: continuation.resume)
so the continuation is invoked on the correct queue.
- Around line 95-106: The async wrapper link(authData:options:) calls the
underlying self.link(...) overload but omits the required callbackQueue
parameter; update the call inside withCheckedThrowingContinuation to pass the
callbackQueue argument expected by the underlying API (e.g., add callbackQueue:
nil or the appropriate DispatchQueue/CallbackQueue used elsewhere) so the
invocation matches the signature used by the other login variant and forwards
completion: continuation.resume.
- Around line 71-86: The async wrapper calls a non-existent link variant;
instead construct an authData dictionary from the provided id, idToken and
accessToken and call the existing
link(authData:options:callbackQueue:completion:) helper. Update the body of
ParseOTP+async.swift's link(id:idToken:accessToken:options:) to build authData
(include only non-nil values), then call self.link(authData: authData, options:
options, callbackQueue: /* same queue used elsewhere, e.g. .main */ ,
completion: continuation.resume) so the continuation gets resumed by the actual
existing implementation.
In `@Sources/ParseSwift/Authentication/3rd` Party/ParseOTP/ParseOTP+combine.swift:
- Around line 50-61: The loginPublisher is calling
login(authData:options:completion:) but the real API requires
login(authData:options:callbackQueue:completion:); update the call inside
loginPublisher to pass the callbackQueue through (accept or default a
DispatchQueue parameter if needed) so it calls
login(authData:options:callbackQueue:completion:). Also, to satisfy Sendable
requirements, wrap the promise with nonisolated(unsafe) as done in
ParseGitHub+combine.swift when passing the completion closure to login. Ensure
you reference the loginPublisher function and the
login(authData:options:callbackQueue:completion:) signature when making the
change.
- Around line 29-43: Remove the stray duplicate self.login(...) call in
loginPublisher (the incomplete call at lines 30-34) and replace the remaining
call so it matches an existing completion-based API, or implement the missing
completion-based method in ParseOTP.swift; specifically ensure either
ParseOTP+combine.swift invokes an existing method like
login(id:idToken:accessToken:options:completion:) that actually exists, or add
that method (ParseOTP.login(id:idToken:accessToken:options:completion:)) to
ParseOTP.swift with the expected signature and completion handling so the
Future's promise can be passed as the completion.
- Around line 97-108: linkPublisher is missing the callbackQueue parameter when
calling link; update the call inside func linkPublisher(authData:options:) to
pass callbackQueue: .main to the self.link(...) invocation so the completion is
invoked on the main queue (refer to function linkPublisher and the
link(authData:options:completion:) overload).
- Around line 74-89: The linkPublisher currently calls a non-existent
self.link(id:idToken:accessToken:options:completion:); update linkPublisher (in
ParseOTP+combine.swift) to call the actual ParseOTP link overloads instead — use
self.link(authData:options:completion:) when you have token(s) (build an
authData dictionary from id, idToken, accessToken), use
self.link(mobile:options:completion:) when the id represents a mobile number, or
use self.link(secret:token:options:completion:) when the intended API is the
secret/token pair; implement a small conditional branch inside linkPublisher to
pick the correct existing method and pass the provided options and the promise
as completion.
| func login( | ||
| authData: [String: String], | ||
| options: API.Options = [], | ||
| callbackQueue: DispatchQueue = .main, | ||
| completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void | ||
| ) { | ||
| callbackQueue.async { | ||
| completion( | ||
| .failure( | ||
| .init( | ||
| code: .otherCause, | ||
| message: "Login is not supported. Please use \"link(...)\"." | ||
| ) | ||
| ) | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
The completion handler needs @Sendable annotation, young hero!
To be a Symbol of Peace in Swift 6 concurrency, the completion handler should be marked @Sendable. The static analysis is warning about capturing non-Sendable types in @Sendable closures.
♻️ Proposed fix
func login(
authData: [String: String],
options: API.Options = [],
callbackQueue: DispatchQueue = .main,
- completion: `@escaping` (Result<AuthenticatedUser, ParseError>) -> Void
+ completion: `@escaping` `@Sendable` (Result<AuthenticatedUser, ParseError>) -> Void
) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func login( | |
| authData: [String: String], | |
| options: API.Options = [], | |
| callbackQueue: DispatchQueue = .main, | |
| completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void | |
| ) { | |
| callbackQueue.async { | |
| completion( | |
| .failure( | |
| .init( | |
| code: .otherCause, | |
| message: "Login is not supported. Please use \"link(...)\"." | |
| ) | |
| ) | |
| ) | |
| } | |
| } | |
| func login( | |
| authData: [String: String], | |
| options: API.Options = [], | |
| callbackQueue: DispatchQueue = .main, | |
| completion: `@escaping` `@Sendable` (Result<AuthenticatedUser, ParseError>) -> Void | |
| ) { | |
| callbackQueue.async { | |
| completion( | |
| .failure( | |
| .init( | |
| code: .otherCause, | |
| message: "Login is not supported. Please use \"link(...)\"." | |
| ) | |
| ) | |
| ) | |
| } | |
| } |
🧰 Tools
🪛 GitHub Check: spm-test
[warning] 93-93:
capture of 'completion' with non-Sendable type '(Result<AuthenticatedUser, ParseError>) -> Void' in a '@sendable' closure [#SendableClosureCaptures]
[warning] 93-93:
capture of 'completion' with non-Sendable type '(Result<AuthenticatedUser, ParseError>) -> Void' in a '@sendable' closure [#SendableClosureCaptures]
[warning] 93-93:
capture of 'completion' with non-Sendable type '(Result<AuthenticatedUser, ParseError>) -> Void' in a '@sendable' closure [#SendableClosureCaptures]
[warning] 93-93:
capture of 'completion' with non-Sendable type '(Result<AuthenticatedUser, ParseError>) -> Void' in a '@sendable' closure [#SendableClosureCaptures]
[warning] 93-93:
capture of 'completion' with non-Sendable type '(Result<AuthenticatedUser, ParseError>) -> Void' in a '@sendable' closure [#SendableClosureCaptures]
🤖 Prompt for AI Agents
In `@Sources/ParseSwift/Authentication/3rd` Party/ParseOTP/ParseOTP.swift around
lines 86 - 102, The completion closure in ParseOTP.login should be marked
`@Sendable` to satisfy Swift 6 concurrency checking; update the method signature
for login to declare completion as `@Sendable` `@escaping`
(Result<AuthenticatedUser, ParseError>) -> Void (i.e., change completion:
`@escaping` to completion: `@Sendable` `@escaping`) and adjust any callers if
necessary to match the new closure type (referencing the
login(authData:options:callbackQueue:completion:) function and its completion
parameter).
| func verify( | ||
| token: String, | ||
| options: API.Options = [], | ||
| callbackQueue: DispatchQueue = .main, | ||
| completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void | ||
| ) { | ||
| Task { | ||
| do { | ||
| let currentUser = try await AuthenticatedUser.current() | ||
| guard let potentialOTPAuthData = currentUser.authData?[Self.__type], | ||
| var otpAuthData = potentialOTPAuthData else { | ||
| let error = ParseError( | ||
| code: .otherCause, | ||
| message: "Logged in user is missing authData, did you link MFA before attempting to call \"verify()\"." | ||
| ) | ||
| completion(.failure(error)) | ||
| return | ||
| } | ||
| if let oldToken = otpAuthData[AuthenticationKeys.token.rawValue] { | ||
| otpAuthData[AuthenticationKeys.oldToken.rawValue] = oldToken | ||
| } | ||
| otpAuthData[AuthenticationKeys.token.rawValue] = token | ||
| link( | ||
| authData: otpAuthData, | ||
| options: options, | ||
| callbackQueue: callbackQueue, | ||
| completion: completion | ||
| ) | ||
| } catch { | ||
| let defaultError = ParseError( | ||
| code: .otherCause, | ||
| message: "Could not retrieve logged in user from Keychain", | ||
| swift: error | ||
| ) | ||
| let parseError = error as? ParseError ?? defaultError | ||
| completion(.failure(parseError)) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
The verify method doesn't consistently use callbackQueue, hero!
The verify method accepts a callbackQueue parameter but when errors occur inside the Task block (lines 130 and 150), completion is called directly without dispatching to callbackQueue. This could cause unexpected threading behavior!
The successful path at line 137-142 does dispatch via link(...) which respects the queue, but the error paths don't.
💥 Proposed fix
do {
let currentUser = try await AuthenticatedUser.current()
guard let potentialOTPAuthData = currentUser.authData?[Self.__type],
var otpAuthData = potentialOTPAuthData else {
let error = ParseError(
code: .otherCause,
message: "Logged in user is missing authData, did you link MFA before attempting to call \"verify()\"."
)
- completion(.failure(error))
+ callbackQueue.async {
+ completion(.failure(error))
+ }
return
}
// ... success path ...
} catch {
let defaultError = ParseError(
code: .otherCause,
message: "Could not retrieve logged in user from Keychain",
swift: error
)
let parseError = error as? ParseError ?? defaultError
- completion(.failure(parseError))
+ callbackQueue.async {
+ completion(.failure(parseError))
+ }
}🤖 Prompt for AI Agents
In `@Sources/ParseSwift/Authentication/3rd` Party/ParseOTP/ParseOTP.swift around
lines 115 - 153, verify currently invokes completion directly inside the Task
error paths (when AuthenticatedUser.current() fails or when authData is missing)
which ignores the provided callbackQueue; update both failure branches to
dispatch the completion call onto callbackQueue (e.g., callbackQueue.async {
completion(.failure(...)) }) so that all completion calls from verify (including
errors) honor the callbackQueue the caller provided; refer to the verify
function, the completion closure, callbackQueue parameter, and existing
link(...) success path for consistency.
| func link( | ||
| authData: [String: String], | ||
| options: API.Options = [], | ||
| callbackQueue: DispatchQueue = .main, | ||
| completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void | ||
| ) { | ||
| guard AuthenticationKeys.token.verifyMandatoryKeys(authData: authData) else { | ||
| callbackQueue.async { | ||
| completion( | ||
| .failure( | ||
| .init( | ||
| code: .otherCause, | ||
| message: "Should have \"authData\" in consisting of keys \"id\", \"idToken\" or \"accessToken\"." | ||
| ) | ||
| ) | ||
| ) | ||
| } | ||
| return | ||
| } | ||
| AuthenticatedUser.link( | ||
| Self.__type, | ||
| authData: authData, | ||
| options: options, | ||
| callbackQueue: callbackQueue, | ||
| completion: completion | ||
| ) | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
This link method also needs @Sendable on the completion handler!
Static analysis reports at line 234: "passing non-Sendable parameter 'completion' to function expecting a '@sendable' closure". The underlying AuthenticatedUser.link expects a @Sendable completion.
♻️ Proposed fix
func link(
authData: [String: String],
options: API.Options = [],
callbackQueue: DispatchQueue = .main,
- completion: `@escaping` (Result<AuthenticatedUser, ParseError>) -> Void
+ completion: `@escaping` `@Sendable` (Result<AuthenticatedUser, ParseError>) -> Void
) {Apply the same fix to the other link method signatures at lines 168 and 195.
🧰 Tools
🪛 GitHub Check: spm-test
[warning] 218-218:
capture of 'completion' with non-Sendable type '(Result<AuthenticatedUser, ParseError>) -> Void' in a '@sendable' closure [#SendableClosureCaptures]
[warning] 218-218:
capture of 'completion' with non-Sendable type '(Result<AuthenticatedUser, ParseError>) -> Void' in a '@sendable' closure [#SendableClosureCaptures]
[warning] 218-218:
capture of 'completion' with non-Sendable type '(Result<AuthenticatedUser, ParseError>) -> Void' in a '@sendable' closure [#SendableClosureCaptures]
[warning] 218-218:
capture of 'completion' with non-Sendable type '(Result<AuthenticatedUser, ParseError>) -> Void' in a '@sendable' closure [#SendableClosureCaptures]
[warning] 218-218:
capture of 'completion' with non-Sendable type '(Result<AuthenticatedUser, ParseError>) -> Void' in a '@sendable' closure [#SendableClosureCaptures]
[failure] 234-234:
passing non-Sendable parameter 'completion' to function expecting a '@sendable' closure
🤖 Prompt for AI Agents
In `@Sources/ParseSwift/Authentication/3rd` Party/ParseOTP/ParseOTP.swift around
lines 210 - 236, The completion closure parameter in
ParseOTP.link(authData:options:callbackQueue:completion:) must be declared
`@Sendable` to match the `@Sendable` expectation of AuthenticatedUser.link; update
the method signature to mark the completion parameter as `@Sendable` (and ensure
any internal forwarding still passes it unchanged to AuthenticatedUser.link).
Apply the same `@Sendable` annotation to the other ParseOTP.link overloads (the
other link methods in this file) so all link(...) completion handlers match
AuthenticatedUser.link's `@Sendable` requirement.
| guard AuthenticationKeys.token.verifyMandatoryKeys(authData: authData) else { | ||
| callbackQueue.async { | ||
| completion( | ||
| .failure( | ||
| .init( | ||
| code: .otherCause, | ||
| message: "Should have \"authData\" in consisting of keys \"id\", \"idToken\" or \"accessToken\"." | ||
| ) | ||
| ) | ||
| ) | ||
| } | ||
| return | ||
| } |
There was a problem hiding this comment.
YOUNG HERO! The error message doesn't match the actual OTP keys!
The error message at line 222 states:
"Should have "authData" in consisting of keys "id", "idToken" or "accessToken"."
But according to AuthenticationKeys enum and verifyMandatoryKeys, OTP actually requires "token" or "mobile" keys! This appears to be copy-pasted from ParseGoogle.swift. A true hero always provides accurate guidance!
📝 Proposed fix
completion(
.failure(
.init(
code: .otherCause,
- message: "Should have \"authData\" in consisting of keys \"id\", \"idToken\" or \"accessToken\"."
+ message: "Should have \"authData\" consisting of key \"token\" or \"mobile\"."
)
)
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| guard AuthenticationKeys.token.verifyMandatoryKeys(authData: authData) else { | |
| callbackQueue.async { | |
| completion( | |
| .failure( | |
| .init( | |
| code: .otherCause, | |
| message: "Should have \"authData\" in consisting of keys \"id\", \"idToken\" or \"accessToken\"." | |
| ) | |
| ) | |
| ) | |
| } | |
| return | |
| } | |
| guard AuthenticationKeys.token.verifyMandatoryKeys(authData: authData) else { | |
| callbackQueue.async { | |
| completion( | |
| .failure( | |
| .init( | |
| code: .otherCause, | |
| message: "Should have \"authData\" consisting of key \"token\" or \"mobile\"." | |
| ) | |
| ) | |
| ) | |
| } | |
| return | |
| } |
🧰 Tools
🪛 GitHub Check: spm-test
[warning] 218-218:
capture of 'completion' with non-Sendable type '(Result<AuthenticatedUser, ParseError>) -> Void' in a '@sendable' closure [#SendableClosureCaptures]
[warning] 218-218:
capture of 'completion' with non-Sendable type '(Result<AuthenticatedUser, ParseError>) -> Void' in a '@sendable' closure [#SendableClosureCaptures]
[warning] 218-218:
capture of 'completion' with non-Sendable type '(Result<AuthenticatedUser, ParseError>) -> Void' in a '@sendable' closure [#SendableClosureCaptures]
[warning] 218-218:
capture of 'completion' with non-Sendable type '(Result<AuthenticatedUser, ParseError>) -> Void' in a '@sendable' closure [#SendableClosureCaptures]
[warning] 218-218:
capture of 'completion' with non-Sendable type '(Result<AuthenticatedUser, ParseError>) -> Void' in a '@sendable' closure [#SendableClosureCaptures]
🤖 Prompt for AI Agents
In `@Sources/ParseSwift/Authentication/3rd` Party/ParseOTP/ParseOTP.swift around
lines 216 - 228, The error message in the guard that calls
AuthenticationKeys.token.verifyMandatoryKeys(authData:) is incorrect (it
mentions "id", "idToken", "accessToken" from Google); update the completion
error message inside that guard to accurately state the required OTP keys
("token" or "mobile") so the failure returned by ParseOTP.verifyMandatoryKeys
reflects the real expected keys; locate the guard in ParseOTP.swift and replace
the message passed to .init(message:) with a concise message saying the authData
must contain "token" or "mobile".
| func login( | ||
| id: String, | ||
| idToken: String? = nil, | ||
| accessToken: String? = nil, | ||
| options: API.Options = [] | ||
| ) async throws -> AuthenticatedUser { | ||
| try await withCheckedThrowingContinuation { continuation in | ||
| self.login( | ||
| id: id, | ||
| idToken: idToken, | ||
| accessToken: accessToken, | ||
| options: options, | ||
| completion: continuation.resume | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
YOUNG HERO! This method calls a non-existent function - compilation will fail!
The async wrapper is calling self.login(id:idToken:accessToken:options:completion:) but this method signature does not exist in ParseOTP.swift! The base ParseOTP class only provides login(authData:options:callbackQueue:completion:) which returns an error stating login is not supported.
This appears to be copied from ParseGoogle+async.swift but OTP has a fundamentally different API design. The static analysis confirming "extra argument 'completion' in call" validates this issue!
💥 Proposed fix - Remove this method or implement the underlying completion-based method
Since OTP login is explicitly not supported (per line 97 in ParseOTP.swift), consider removing these login async wrappers entirely, or only keeping the authData variant:
- func login(
- id: String,
- idToken: String? = nil,
- accessToken: String? = nil,
- options: API.Options = []
- ) async throws -> AuthenticatedUser {
- try await withCheckedThrowingContinuation { continuation in
- self.login(
- id: id,
- idToken: idToken,
- accessToken: accessToken,
- options: options,
- completion: continuation.resume
- )
- }
- }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func login( | |
| id: String, | |
| idToken: String? = nil, | |
| accessToken: String? = nil, | |
| options: API.Options = [] | |
| ) async throws -> AuthenticatedUser { | |
| try await withCheckedThrowingContinuation { continuation in | |
| self.login( | |
| id: id, | |
| idToken: idToken, | |
| accessToken: accessToken, | |
| options: options, | |
| completion: continuation.resume | |
| ) | |
| } | |
| } |
🧰 Tools
🪛 GitHub Check: spm-test
[failure] 35-35:
extra argument 'completion' in call
[failure] 35-35:
extra argument 'completion' in call
🪛 GitHub Check: test (platform=watchOS\ Simulator,name=Apple\ Watch\ Series\ 11\ \(46mm\), build)
[failure] 35-35:
extra argument 'completion' in call
🤖 Prompt for AI Agents
In `@Sources/ParseSwift/Authentication/3rd` Party/ParseOTP/ParseOTP+async.swift
around lines 23 - 38, The async wrapper login(id:idToken:accessToken:options:)
in ParseOTP+async.swift calls a non-existent completion-based overload; remove
this async wrapper or rewrite it to use the existing API by converting to the
authData variant: call the class's
login(authData:options:callbackQueue:completion:) (or delete the async login
entirely since ParseOTP currently returns "login not supported"); update or
remove the function named login in ParseOTP+async.swift so it no longer calls
self.login(id:idToken:accessToken:options:completion:).
| func link( | ||
| authData: [String: String], | ||
| options: API.Options = [] | ||
| ) async throws -> AuthenticatedUser { | ||
| try await withCheckedThrowingContinuation { continuation in | ||
| self.link( | ||
| authData: authData, | ||
| options: options, | ||
| completion: continuation.resume | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
Missing callbackQueue parameter here too, young hero!
Same issue as the login variant - the underlying method requires callbackQueue parameter.
💥 Proposed fix
func link(
authData: [String: String],
options: API.Options = []
) async throws -> AuthenticatedUser {
try await withCheckedThrowingContinuation { continuation in
self.link(
authData: authData,
options: options,
+ callbackQueue: .main,
completion: continuation.resume
)
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func link( | |
| authData: [String: String], | |
| options: API.Options = [] | |
| ) async throws -> AuthenticatedUser { | |
| try await withCheckedThrowingContinuation { continuation in | |
| self.link( | |
| authData: authData, | |
| options: options, | |
| completion: continuation.resume | |
| ) | |
| } | |
| } | |
| func link( | |
| authData: [String: String], | |
| options: API.Options = [] | |
| ) async throws -> AuthenticatedUser { | |
| try await withCheckedThrowingContinuation { continuation in | |
| self.link( | |
| authData: authData, | |
| options: options, | |
| callbackQueue: .main, | |
| completion: continuation.resume | |
| ) | |
| } | |
| } |
🧰 Tools
🪛 GitHub Check: spm-test
[failure] 103-103:
converting a value of type '@sendable (__shared sending Result<AuthenticatedUser, ParseError>) -> ()' to type '(Result<AuthenticatedUser, ParseError>) -> Void' risks causing data races
🪛 GitHub Check: test (platform=watchOS\ Simulator,name=Apple\ Watch\ Series\ 11\ \(46mm\), build)
[failure] 103-103:
converting a value of type '@sendable (__shared sending Result<AuthenticatedUser, ParseError>) -> ()' to type '(Result<AuthenticatedUser, ParseError>) -> Void' risks causing data races
🤖 Prompt for AI Agents
In `@Sources/ParseSwift/Authentication/3rd` Party/ParseOTP/ParseOTP+async.swift
around lines 95 - 106, The async wrapper link(authData:options:) calls the
underlying self.link(...) overload but omits the required callbackQueue
parameter; update the call inside withCheckedThrowingContinuation to pass the
callbackQueue argument expected by the underlying API (e.g., add callbackQueue:
nil or the appropriate DispatchQueue/CallbackQueue used elsewhere) so the
invocation matches the signature used by the other login variant and forwards
completion: continuation.resume.
| Future { promise in | ||
| self.login( | ||
| id: id, | ||
| accessToken: accessToken, | ||
|
|
||
| ) | ||
| self.login( | ||
| id: id, | ||
| idToken: idToken, | ||
| accessToken: accessToken, | ||
| options: options, | ||
| completion: promise | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
YOUNG HERO! There's duplicate code AND a missing method here!
I see TWO issues with this loginPublisher, and they're blocking your path to becoming a true hero:
-
Lines 30-34: This is an incomplete/duplicate
self.login()call with no completion handler - it appears to be leftover code that should be removed! -
Lines 35-41: The intended call uses
self.login(id:idToken:accessToken:options:completion:)which does NOT exist inParseOTP.swift!
Static analysis confirms: "extra argument 'completion' in call" - PLUS ULTRA compilation failure incoming!
💥 Proposed fix - Remove duplicate and fix method signature
func loginPublisher(
id: String,
idToken: String? = nil,
accessToken: String? = nil,
options: API.Options = []
) -> Future<AuthenticatedUser, ParseError> {
Future { promise in
- self.login(
- id: id,
- accessToken: accessToken,
-
- )
- self.login(
- id: id,
- idToken: idToken,
- accessToken: accessToken,
- options: options,
- completion: promise
- )
+ // Note: OTP login is not supported per ParseOTP.swift
+ // Consider removing this publisher or implementing underlying method
+ promise(.failure(ParseError(code: .otherCause, message: "Login is not supported for OTP. Please use link...")))
}
}Or if login should be supported, the underlying completion-based method needs to be added to ParseOTP.swift first!
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Future { promise in | |
| self.login( | |
| id: id, | |
| accessToken: accessToken, | |
| ) | |
| self.login( | |
| id: id, | |
| idToken: idToken, | |
| accessToken: accessToken, | |
| options: options, | |
| completion: promise | |
| ) | |
| } | |
| } | |
| Future { promise in | |
| // Note: OTP login is not supported per ParseOTP.swift | |
| // Consider removing this publisher or implementing underlying method | |
| promise(.failure(ParseError(code: .otherCause, message: "Login is not supported for OTP. Please use link..."))) | |
| } | |
| } |
🧰 Tools
🪛 GitHub Check: Codacy Static Code Analysis
[notice] 33-33: Sources/ParseSwift/Authentication/3rd Party/ParseOTP/ParseOTP+combine.swift#L33
Lines should not have trailing whitespace
🪛 GitHub Check: spm-test
[failure] 40-40:
extra argument 'completion' in call
🤖 Prompt for AI Agents
In `@Sources/ParseSwift/Authentication/3rd` Party/ParseOTP/ParseOTP+combine.swift
around lines 29 - 43, Remove the stray duplicate self.login(...) call in
loginPublisher (the incomplete call at lines 30-34) and replace the remaining
call so it matches an existing completion-based API, or implement the missing
completion-based method in ParseOTP.swift; specifically ensure either
ParseOTP+combine.swift invokes an existing method like
login(id:idToken:accessToken:options:completion:) that actually exists, or add
that method (ParseOTP.login(id:idToken:accessToken:options:completion:)) to
ParseOTP.swift with the expected signature and completion handling so the
Future's promise can be passed as the completion.
| func loginPublisher( | ||
| authData: [String: String], | ||
| options: API.Options = [] | ||
| ) -> Future<AuthenticatedUser, ParseError> { | ||
| Future { promise in | ||
| self.login( | ||
| authData: authData, | ||
| options: options, | ||
| completion: promise | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
This loginPublisher is also missing the callbackQueue parameter!
The underlying method signature is login(authData:options:callbackQueue:completion:) but you're calling it without callbackQueue.
💥 Proposed fix
func loginPublisher(
authData: [String: String],
options: API.Options = []
) -> Future<AuthenticatedUser, ParseError> {
Future { promise in
self.login(
authData: authData,
options: options,
+ callbackQueue: .main,
completion: promise
)
}
}Note: You may also need to wrap promise with nonisolated(unsafe) like in ParseGitHub+combine.swift to handle Sendable requirements.
🤖 Prompt for AI Agents
In `@Sources/ParseSwift/Authentication/3rd` Party/ParseOTP/ParseOTP+combine.swift
around lines 50 - 61, The loginPublisher is calling
login(authData:options:completion:) but the real API requires
login(authData:options:callbackQueue:completion:); update the call inside
loginPublisher to pass the callbackQueue through (accept or default a
DispatchQueue parameter if needed) so it calls
login(authData:options:callbackQueue:completion:). Also, to satisfy Sendable
requirements, wrap the promise with nonisolated(unsafe) as done in
ParseGitHub+combine.swift when passing the completion closure to login. Ensure
you reference the loginPublisher function and the
login(authData:options:callbackQueue:completion:) signature when making the
change.
| func linkPublisher( | ||
| id: String, | ||
| idToken: String? = nil, | ||
| accessToken: String? = nil, | ||
| options: API.Options = [] | ||
| ) -> Future<AuthenticatedUser, ParseError> { | ||
| Future { promise in | ||
| self.link( | ||
| id: id, | ||
| idToken: idToken, | ||
| accessToken: accessToken, | ||
| options: options, | ||
| completion: promise | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
This linkPublisher calls a non-existent method too!
self.link(id:idToken:accessToken:options:completion:) does not exist in ParseOTP.swift. The available link methods use different signatures (secret:token:, mobile:, or authData:).
💥 Proposed fix - Match actual ParseOTP link signatures
- func linkPublisher(
- id: String,
- idToken: String? = nil,
- accessToken: String? = nil,
- options: API.Options = []
- ) -> Future<AuthenticatedUser, ParseError> {
- Future { promise in
- self.link(
- id: id,
- idToken: idToken,
- accessToken: accessToken,
- options: options,
- completion: promise
- )
- }
- }
+ func linkPublisher(
+ secret: String,
+ token: String,
+ options: API.Options = []
+ ) -> Future<AuthenticatedUser, ParseError> {
+ Future { promise in
+ nonisolated(unsafe) let promise = promise
+ self.link(
+ secret: secret,
+ token: token,
+ options: options,
+ callbackQueue: .main,
+ completion: promise
+ )
+ }
+ }
+
+ func linkPublisher(
+ mobile: String,
+ options: API.Options = []
+ ) -> Future<AuthenticatedUser, ParseError> {
+ Future { promise in
+ nonisolated(unsafe) let promise = promise
+ self.link(
+ mobile: mobile,
+ options: options,
+ callbackQueue: .main,
+ completion: promise
+ )
+ }
+ }🧰 Tools
🪛 GitHub Check: spm-test
[failure] 86-86:
extra argument 'completion' in call
🤖 Prompt for AI Agents
In `@Sources/ParseSwift/Authentication/3rd` Party/ParseOTP/ParseOTP+combine.swift
around lines 74 - 89, The linkPublisher currently calls a non-existent
self.link(id:idToken:accessToken:options:completion:); update linkPublisher (in
ParseOTP+combine.swift) to call the actual ParseOTP link overloads instead — use
self.link(authData:options:completion:) when you have token(s) (build an
authData dictionary from id, idToken, accessToken), use
self.link(mobile:options:completion:) when the id represents a mobile number, or
use self.link(secret:token:options:completion:) when the intended API is the
secret/token pair; implement a small conditional branch inside linkPublisher to
pick the correct existing method and pass the provided options and the promise
as completion.
| func linkPublisher( | ||
| authData: [String: String], | ||
| options: API.Options = [] | ||
| ) -> Future<AuthenticatedUser, ParseError> { | ||
| Future { promise in | ||
| self.link( | ||
| authData: authData, | ||
| options: options, | ||
| completion: promise | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
Missing callbackQueue parameter again, hero!
Same pattern - needs callbackQueue: .main parameter.
💥 Proposed fix
func linkPublisher(
authData: [String: String],
options: API.Options = []
) -> Future<AuthenticatedUser, ParseError> {
Future { promise in
+ nonisolated(unsafe) let promise = promise
self.link(
authData: authData,
options: options,
+ callbackQueue: .main,
completion: promise
)
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func linkPublisher( | |
| authData: [String: String], | |
| options: API.Options = [] | |
| ) -> Future<AuthenticatedUser, ParseError> { | |
| Future { promise in | |
| self.link( | |
| authData: authData, | |
| options: options, | |
| completion: promise | |
| ) | |
| } | |
| } | |
| func linkPublisher( | |
| authData: [String: String], | |
| options: API.Options = [] | |
| ) -> Future<AuthenticatedUser, ParseError> { | |
| Future { promise in | |
| nonisolated(unsafe) let promise = promise | |
| self.link( | |
| authData: authData, | |
| options: options, | |
| callbackQueue: .main, | |
| completion: promise | |
| ) | |
| } | |
| } |
🤖 Prompt for AI Agents
In `@Sources/ParseSwift/Authentication/3rd` Party/ParseOTP/ParseOTP+combine.swift
around lines 97 - 108, linkPublisher is missing the callbackQueue parameter when
calling link; update the call inside func linkPublisher(authData:options:) to
pass callbackQueue: .main to the self.link(...) invocation so the completion is
invoked on the main queue (refer to function linkPublisher and the
link(authData:options:completion:) overload).
New Pull Request Checklist
Issue Description
Approach
TODOs before merging