import type { PathConfidence } from "./enums"; // response wrappers export interface CursorPage { items: T[]; nextCursor: number | null; hasMore: boolean; } export interface LatestObserver { id: string; displayName?: string; iata: string; // path fields land on the REST list from beacon-server ae0669c, and on live rows via the WS feed; // resolvedSource/Destination are WS-only for now — the list endpoints leave them nil on purpose. pathLength?: PathLength; pathBytes?: string; resolvedSource?: ResolvedHop; resolvedDestination?: ResolvedHop; // per-hop resolved path, for the REST list once the backend fills it in — nothing populates it today. resolvedPath?: ResolvedHop[]; } // packet list and detail shapes export interface PacketSummary { packetHash: string; payloadType: number; payloadTypeName: string; routeType: number; routeTypeName: string; firstHeardAt: number; lastHeardAt: number; observationCount: number; latestObserver?: LatestObserver; scope?: string; // matched transport scope name, e.g. "#bc" summary?: string; // packet-derived display text, currently the advertised name } export interface ResolvedNode { id: string; // uuid name?: string; publicKey: string; // hex-encoded prefix latitude?: number; // decimal degrees (resolved DB value, not the 1e7 advert encoding) longitude?: number; } export interface ResolvedHop { confidence: PathConfidence; nodes: ResolvedNode[]; // empty when confidence is "none" snr?: number; // per-hop link SNR (dB) when the backend resolved it hashBytes?: string; // hex per-hop path-hash prefix, carried by RouteHop; trace hops get theirs from rawPath instead } export interface PathLength { raw: string; // path-length byte as hex (e.g. "1e") hashSize: number; // bytes per hop hash hopCount: number; } export interface Observation { id: number; observerId: string; observerName?: string; iata: string; heardAt: number; pathLength: PathLength; pathBytes?: string; rssi?: number; snr?: number; propagationTimeMs?: number; radio?: { freqMhz?: number; spreadFactor?: number; bandwidthKhz?: number; codingRate?: number; }; sourceBroker: string; resolvedPath: ResolvedHop[]; // the packet's logical endpoints, resolved from the payload; separate from the relay // resolvedPath. Absent for payload types with no addressed endpoint (GRP_TXT/GRP_DATA/TRACE). resolvedSource?: ResolvedHop; resolvedDestination?: ResolvedHop; } export interface PacketHeader { raw: string; // header byte as hex (e.g. "11") routeType: number; routeTypeName: string; payloadType: number; payloadTypeName: string; payloadVersion: number; } export interface TransportCodes { regionCode: number; subRegionCode: number; } export interface PacketDetail { packetHash: string; header: PacketHeader; transportCodes?: TransportCodes; scope?: string; // matched transport scope name, e.g. "#bc" originPubkey?: string; parsedPayload?: Record | string; rawPayload: string; decrypted: boolean; channelHash?: string; firstHeardAt: number; lastHeardAt: number; firstToLastMs: number; // ms between first and last hearing — the packet's overall propagation time observationCount: number; // trace packets only: the resolved intended route from the trace's path hashes (one hop per hash) resolvedRoute?: ResolvedHop[]; observations: Observation[]; } // region metadata export interface IataCode { iata: string; displayName?: string; lat?: number; lon?: number; } // A region groups IATAs under a URL-safe slug. The list endpoint returns summaries; the detail // endpoint adds the member IATAs and map-focus hints. export interface RegionSummary { id: number; slug: string; // e.g. "western-canada" name: string; } export interface Region extends RegionSummary { description?: string; centerLat?: number; centerLng?: number; zoomLevel?: number; iatas: string[]; // member IATA codes } export interface BrokerStatus { name: string; connected: boolean; } // known routes — fully resolved multi-hop paths discovered at ingest, where every hop matched a node // at high confidence. One RouteHop per hash, in order. export interface RouteHop { nodeId: string; // uuid of the resolved node hashBytes: string; // hex-encoded path-hash prefix for this hop node?: ResolvedNode; // resolved node detail for this hop } export interface KnownRoute { id: number; iata: string; hopCount: number; hops: RouteHop[]; firstSeen: number; // epoch ms lastSeen: number; // epoch ms observationCount: number; } // the boundary hop in a cross-IATA route: the link from the last node in the source IATA to the // first node in the target IATA. export interface CrossIATAHop { fromNode: ResolvedNode; toNode: ResolvedNode; fromIata: string; toIata: string; lastSeen: number; // epoch ms } // a route spanning two IATAs: a segment in the source IATA, the boundary hop, then a segment in the // target IATA. From GET /routes/cross. export interface CrossIATARoute { sourceSegment: RouteHop[]; crossHop: CrossIATAHop; targetSegment: RouteHop[]; totalHops: number; } // trace tags — a trace series groups the packets that share a 4-byte trace tag. The list endpoint // returns per-tag summaries; the detail endpoint returns the tag's packets with their resolved routes. // Each tag is either a route TRACE or a PING (round-trip) — the backend tags which. export type TraceType = "TRACE" | "PING"; export interface TraceTagSummary { traceTag: string; // hex-encoded 4-byte tag firstHeardAt: number; // epoch ms lastHeardAt: number; // epoch ms packetCount: number; iataCount: number; // distinct IATAs the tag was heard in traceType: TraceType; pathHashes: string[]; // hops from the most complete observation we've seen for this tag snrValues: number[]; // per-hop SNR (dB), index-aligned with pathHashes } export interface RawHop { hash: string; // hex per-hop path-hash prefix snr?: number; // per-hop link SNR (dB) when known } export interface TracePacket { packetHash: string; routeType: number; routeTypeName: string; scope?: string; // matched transport scope name, when any firstHeardAt: number; // epoch ms lastHeardAt: number; // epoch ms rawPath: RawHop[]; // one hop per trace path hash, index-aligned with resolvedRoute resolvedRoute: ResolvedHop[]; // one hop per trace path hash; nodes empty when unresolved } export interface TraceDetail { traceTag: string; packets: TracePacket[]; }