fix: add KVO on webView.url to catch SPA pushState navigation

didFinish only fires for cross-document (full page) navigations. After
loading https://claude.ai/login the SPA redirects authenticated users
via history.pushState to /new — this changes the URL visually but never
fires didFinish, so auth was never detected.

KVO on webView.url fires for every URL change including SPA pushState,
covering the case where the app routes client-side after the initial
page load. Both KVO and didFinish now call the same checkCurrentURL
helper so detection is not missed regardless of navigation type.
This commit is contained in:
superdooper86
2026-05-11 10:46:11 +02:00
parent 88252e4d59
commit 58b947e515
2 changed files with 16 additions and 7 deletions
+2 -2
View File
@@ -15,9 +15,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.2.1-beta.10</string>
<string>1.2.1-beta.11</string>
<key>CFBundleVersion</key>
<string>58</string>
<string>59</string>
<key>LSMinimumSystemVersion</key>
<string>13.0</string>
<key>LSUIElement</key>
+14 -5
View File
@@ -12,6 +12,12 @@ struct LoginWebView: NSViewRepresentable {
let webView = WKWebView(frame: .zero, configuration: config)
webView.navigationDelegate = context.coordinator
// KVO on url catches SPA pushState navigations that don't fire didFinish
context.coordinator.urlObservation = webView.observe(\.url, options: [.new]) { [weak coordinator = context.coordinator] wv, _ in
coordinator?.checkCurrentURL(wv.url?.absoluteString)
}
webView.load(URLRequest(url: URL(string: "https://claude.ai/login")!))
return webView
}
@@ -25,22 +31,25 @@ struct LoginWebView: NSViewRepresentable {
class Coordinator: NSObject, WKNavigationDelegate {
let onAuthenticated: () -> Void
var didAuthenticate = false
var urlObservation: NSKeyValueObservation?
init(onAuthenticated: @escaping () -> Void) {
self.onAuthenticated = onAuthenticated
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
guard !didAuthenticate else { return }
guard let url = webView.url?.absoluteString else { return }
// Stay on login/auth pages user hasn't completed sign-in yet
func checkCurrentURL(_ url: String?) {
guard !didAuthenticate, let url else { return }
if url.contains("/login") || url.contains("/auth") { return }
// Navigated away from login server redirected us, so sign-in completed
didAuthenticate = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.onAuthenticated()
}
}
// Covers full cross-document navigations
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
checkCurrentURL(webView.url?.absoluteString)
}
}
}