From 5dcfe0f147c7871eaf5f3a88bd9e9fded38d4633 Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Mon, 13 Apr 2026 22:37:22 -0500 Subject: v1.2.0 domain management and wallet expansion Complete v1.1-aligned domain flows with forwards and glue CRUD, improve API payload resilience, and add wallet transaction/payment views. Harden error handling and UX states across domain screens, remove out-of-scope DNSSEC/renewal record flows for now, and keep auth/session behavior aligned with token-based usage. --- Rune/API/NjallaClient.swift | 82 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 2 deletions(-) (limited to 'Rune/API/NjallaClient.swift') diff --git a/Rune/API/NjallaClient.swift b/Rune/API/NjallaClient.swift index 8da52cb..f91c924 100644 --- a/Rune/API/NjallaClient.swift +++ b/Rune/API/NjallaClient.swift @@ -25,10 +25,17 @@ struct NjallaClient: Sendable, Equatable { request.httpBody = try JSONSerialization.data(withJSONObject: body) let (data, response) = try await URLSession.shared.data(for: request) - _ = (response as? HTTPURLResponse)?.statusCode ?? -1 + let statusCode = (response as? HTTPURLResponse)?.statusCode ?? -1 + debugLogRawResponse(method: method, statusCode: statusCode, data: data) let decoder = JSONDecoder() - let envelope = try decoder.decode(RPCResponse.self, from: data) + let envelope: RPCResponse + do { + envelope = try decoder.decode(RPCResponse.self, from: data) + } catch { + debugLogDecodeFailure(method: method, error: error) + throw error + } if let error = envelope.error { throw NjallaError.api(message: error.message) @@ -41,6 +48,19 @@ struct NjallaClient: Sendable, Equatable { return result } + private func debugLogRawResponse(method: String, statusCode: Int, data: Data) { + #if DEBUG + let body = String(data: data, encoding: .utf8) ?? "" + debugPrint("[NjallaClient][\(method)] status=\(statusCode) raw=\(body)") + #endif + } + + private func debugLogDecodeFailure(method: String, error: Error) { + #if DEBUG + debugPrint("[NjallaClient][\(method)] decode-failure=\(error.localizedDescription)") + #endif + } + func listDomains() async throws -> [Domain] { let response: DomainListResponse = try await call("list-domains") return response.domains @@ -83,6 +103,51 @@ struct NjallaClient: Sendable, Equatable { ) } + func listGlue(for domain: String) async throws -> [GlueRecord] { + let response: GlueListResponse = try await call("list-glue", params: ["domain": domain]) + return response.glue.map { record in + record.domain.isEmpty ? record.withDomain(domain) : record + } + } + + func addGlue(for domain: String, name: String, address4: String?, address6: String?) async throws { + var params: [String: Any] = [ + "domain": domain, + "name": name + ] + if let address4, !address4.isEmpty { + params["address4"] = address4 + } + if let address6, !address6.isEmpty { + params["address6"] = address6 + } + let _: EmptyResult = try await call("add-glue", params: params) + } + + func editGlue(for domain: String, name: String, address4: String?, address6: String?) async throws { + var params: [String: Any] = [ + "domain": domain, + "name": name + ] + if let address4, !address4.isEmpty { + params["address4"] = address4 + } + if let address6, !address6.isEmpty { + params["address6"] = address6 + } + let _: EmptyResult = try await call("edit-glue", params: params) + } + + func removeGlue(for domain: String, name: String) async throws { + let _: EmptyResult = try await call( + "remove-glue", + params: [ + "domain": domain, + "name": name + ] + ) + } + func listRecords(for domain: String) async throws -> [DNSRecord] { let response: RecordListResponse = try await call("list-records", params: ["domain": domain]) return response.records.map { record in @@ -124,9 +189,22 @@ struct NjallaClient: Sendable, Equatable { let _: EmptyResult = try await call("remove-token", params: ["key": key]) } + func logout() async throws { + let _: EmptyResult = try await call("logout") + } + func getBalance() async throws -> WalletBalance { try await call("get-balance") } + + func listTransactions() async throws -> [WalletTransaction] { + let response: WalletTransactionListResponse = try await call("list-transactions") + return response.transactions + } + + func getPayment(id: String) async throws -> WalletPayment { + try await call("get-payment", params: ["id": id]) + } } enum NjallaError: LocalizedError { -- cgit v1.2.3