import Foundation struct Node: Identifiable, Hashable, Decodable { let nodeId: String? let nodeNum: Int? let longName: String? let shortName: String? let hopsAway: Int? let lastHeard: Double? let hasPKC: Bool? var id: String { nodeId ?? String(nodeNum ?? 0) } var displayName: String { longName ?? shortName ?? id } } struct NodeListResponse: Decodable { let data: [Node] } struct ServerStatus: Decodable { struct LocalNode: Decodable { let nodeId: String? let longName: String? let nodeNum: Int? } struct Connection: Decodable { let connected: Bool? let localNode: LocalNode? } struct Statistics: Decodable { let nodes: Int? let messages: Int? let channels: Int? } struct V1Data: Decodable { let connected: Bool? let nodeResponsive: Bool? let localNodeId: String? let longName: String? let localNodeNum: Int? } enum MeshState { case online, idle, offline } let version: String? let uptime: Double? let connection: Connection? let statistics: Statistics? let data: V1Data? var isConnected: Bool { data?.connected ?? connection?.connected ?? false } var meshState: MeshState { let connected = data?.connected ?? connection?.connected ?? false guard connected else { return .offline } // nodeResponsive only ships in v1; absence is treated as responsive. return (data?.nodeResponsive ?? true) ? .online : .idle } var localNodeId: String? { data?.localNodeId ?? connection?.localNode?.nodeId } var localNodeNum: Int? { data?.localNodeNum ?? connection?.localNode?.nodeNum } var localNodeName: String? { data?.longName ?? connection?.localNode?.longName } }