diff --git a/@platform/codebase/@features/ai-copilot/cockpit-kit/Sources/CocotteCockpitKit/LiveCockpitAPI.swift b/@platform/codebase/@features/ai-copilot/cockpit-kit/Sources/CocotteCockpitKit/LiveCockpitAPI.swift index 427916a..92d5cd4 100644 --- a/@platform/codebase/@features/ai-copilot/cockpit-kit/Sources/CocotteCockpitKit/LiveCockpitAPI.swift +++ b/@platform/codebase/@features/ai-copilot/cockpit-kit/Sources/CocotteCockpitKit/LiveCockpitAPI.swift @@ -24,8 +24,21 @@ public struct LiveCockpitAPI: CockpitAPI { return d } + /// Resolve a path (optionally carrying a `?query`) against `baseURL`. + /// `URL.appendingPathComponent` percent-encodes `?`/`=`, mangling queries + /// into the path — so split the query off and set it via URLComponents. + private func requestURL(_ pathAndQuery: String) -> URL { + let parts = pathAndQuery.split(separator: "?", maxSplits: 1, omittingEmptySubsequences: false) + let url = baseURL.appendingPathComponent(String(parts[0])) + guard parts.count > 1, var comps = URLComponents(url: url, resolvingAgainstBaseURL: false) else { + return url + } + comps.percentEncodedQuery = String(parts[1]) + return comps.url ?? url + } + private func get(_ path: String, _ type: T.Type) async throws -> T { - var req = URLRequest(url: baseURL.appendingPathComponent(path)) + var req = URLRequest(url: requestURL(path)) if let token = try await auth.authToken() { req.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") } @@ -38,7 +51,7 @@ public struct LiveCockpitAPI: CockpitAPI { @discardableResult private func post(_ path: String, body: [String: String] = [:]) async throws -> Data { - var req = URLRequest(url: baseURL.appendingPathComponent(path)) + var req = URLRequest(url: requestURL(path)) req.httpMethod = "POST" req.setValue("application/json", forHTTPHeaderField: "Content-Type") if let token = try await auth.authToken() {