beta.24: read lastActiveOrg cookie via JS, expose bootstrap body and lastActiveOrg in diagnostics
This commit is contained in:
@@ -48,6 +48,7 @@ struct DiagnosticsView: View {
|
||||
DiagRow("Signed in", vm.isSignedIn ? "Yes" : "No")
|
||||
DiagRow("Email", vm.userEmail.isEmpty ? "(none)" : vm.userEmail)
|
||||
DiagRow("Org ID", UserDefaults.standard.string(forKey: "claude_org_id") ?? "(none)")
|
||||
DiagRow("lastActiveOrg", vm.diagLastActiveOrg.isEmpty ? "(not read)" : vm.diagLastActiveOrg)
|
||||
DiagRow("Error", vm.errorMessage ?? "(none)")
|
||||
}
|
||||
|
||||
@@ -65,9 +66,24 @@ struct DiagnosticsView: View {
|
||||
|
||||
Divider()
|
||||
|
||||
// Bootstrap body
|
||||
if !vm.diagBootstrapBody.isEmpty {
|
||||
DiagSection(title: "Bootstrap Response (first 500 chars)") {
|
||||
Text(vm.diagBootstrapBody)
|
||||
.font(.system(size: 10, design: .monospaced))
|
||||
.foregroundColor(.secondary)
|
||||
.textSelection(.enabled)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(8)
|
||||
.background(Color.primary.opacity(0.04))
|
||||
.cornerRadius(5)
|
||||
}
|
||||
Divider()
|
||||
}
|
||||
|
||||
// Response body
|
||||
if !vm.diagLastBody.isEmpty {
|
||||
DiagSection(title: "Response Body (first 500 chars)") {
|
||||
DiagSection(title: "Last API Response (first 500 chars)") {
|
||||
Text(vm.diagLastBody)
|
||||
.font(.system(size: 10, design: .monospaced))
|
||||
.foregroundColor(.secondary)
|
||||
@@ -164,6 +180,7 @@ struct DiagnosticsView: View {
|
||||
lines.append("Signed in: \(vm.isSignedIn ? "Yes" : "No")")
|
||||
lines.append("Email: \(vm.userEmail.isEmpty ? "(none)" : vm.userEmail)")
|
||||
lines.append("Org ID: \(UserDefaults.standard.string(forKey: "claude_org_id") ?? "(none)")")
|
||||
lines.append("lastActiveOrg: \(vm.diagLastActiveOrg.isEmpty ? "(not read)" : vm.diagLastActiveOrg)")
|
||||
lines.append("Error: \(vm.errorMessage ?? "(none)")")
|
||||
lines.append("")
|
||||
lines.append("Last path: \(vm.diagLastPath)")
|
||||
@@ -173,7 +190,10 @@ struct DiagnosticsView: View {
|
||||
lines.append("Claude cookies: \(vm.diagClaudeCookieCount)")
|
||||
lines.append("Domains: \(vm.diagCookieDomains.joined(separator: ", "))")
|
||||
lines.append("")
|
||||
lines.append("Response body:")
|
||||
lines.append("Bootstrap body:")
|
||||
lines.append(vm.diagBootstrapBody)
|
||||
lines.append("")
|
||||
lines.append("Last API response:")
|
||||
lines.append(vm.diagLastBody)
|
||||
lines.append("")
|
||||
lines.append("Live cookies:")
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.2.1-beta.23</string>
|
||||
<string>1.2.1-beta.24</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>71</string>
|
||||
<string>72</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>13.0</string>
|
||||
<key>LSUIElement</key>
|
||||
|
||||
@@ -34,7 +34,7 @@ class UsageViewModel: ObservableObject {
|
||||
private var apiWebView: WKWebView?
|
||||
private var navWaiter: WKNavWaiter?
|
||||
|
||||
// Diagnostics — populated on every urlFetch call
|
||||
// Diagnostics
|
||||
@Published var diagCookieCount: Int = 0
|
||||
@Published var diagClaudeCookieCount: Int = 0
|
||||
@Published var diagCookieDomains: [String] = []
|
||||
@@ -42,6 +42,8 @@ class UsageViewModel: ObservableObject {
|
||||
@Published var diagLastStatus: Int = 0
|
||||
@Published var diagLastBody: String = ""
|
||||
@Published var diagLastError: String = ""
|
||||
@Published var diagLastActiveOrg: String = "" // lastActiveOrg cookie value from JS
|
||||
@Published var diagBootstrapBody: String = "" // raw bootstrap response (first 500 chars)
|
||||
@Published var diagLastFetch: Date? = nil
|
||||
|
||||
init() {
|
||||
@@ -225,10 +227,31 @@ class UsageViewModel: ObservableObject {
|
||||
defer { isLoading = false }
|
||||
|
||||
do {
|
||||
// Read lastActiveOrg cookie from JS — most reliable org source since it's
|
||||
// set by the claude.ai frontend to whichever org is currently active.
|
||||
var cookieOrgId: String? = nil
|
||||
if let wv = apiWebView, wv.url?.host?.hasSuffix("claude.ai") == true {
|
||||
let js = """
|
||||
return document.cookie.split(';')
|
||||
.map(c => c.trim().split('='))
|
||||
.filter(p => p[0] === 'lastActiveOrg')
|
||||
.map(p => p.slice(1).join('='))[0] || null;
|
||||
"""
|
||||
let raw: Any? = try? await withCheckedThrowingContinuation { cont in
|
||||
wv.callAsyncJavaScript(js, arguments: [:], in: nil, in: .defaultClient) { r in
|
||||
cont.resume(returning: (try? r.get()) ?? nil)
|
||||
}
|
||||
}
|
||||
if let v = raw as? String, !v.isEmpty {
|
||||
cookieOrgId = v
|
||||
diagLastActiveOrg = v
|
||||
}
|
||||
}
|
||||
|
||||
let (fetchedOrgId, fetchedEmail, fetchedPlan) = try await fetchBootstrap()
|
||||
|
||||
let orgId: String
|
||||
if let id = fetchedOrgId {
|
||||
if let id = cookieOrgId ?? fetchedOrgId {
|
||||
UserDefaults.standard.set(id, forKey: "claude_org_id")
|
||||
orgId = id
|
||||
} else if let cached = UserDefaults.standard.string(forKey: "claude_org_id") {
|
||||
@@ -292,6 +315,7 @@ class UsageViewModel: ObservableObject {
|
||||
guard body.trimmingCharacters(in: .whitespacesAndNewlines).hasPrefix("{") else {
|
||||
throw AppError.detail("Non-JSON response (HTML?): \(body.prefix(80))")
|
||||
}
|
||||
diagBootstrapBody = String(body.prefix(500))
|
||||
guard let data = body.data(using: .utf8),
|
||||
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
|
||||
return (nil, nil, nil)
|
||||
|
||||
Reference in New Issue
Block a user