// src/plugins/aprs-shared.ts function aprsPacketCategory(packet) { const type = (packet.type ?? "").toLowerCase(); const info = (packet.info ?? "").toLowerCase(); if (packet.lat != null && packet.lon != null || type.includes("position")) return "position"; if (type.includes("message") || info.startsWith(":")) return "message"; if (type.includes("weather") || info.startsWith("_")) return "weather"; if (type.includes("telemetry") || info.startsWith("t#")) return "telemetry"; return "other"; } function aprsCategoryLabel(category) { switch (category) { case "position": return "Position"; case "message": return "Message"; case "weather": return "Weather"; case "telemetry": return "Telemetry"; default: return "Other"; } } function aprsAgeText(timestampMs) { if (typeof timestampMs !== "number" || !Number.isFinite(timestampMs)) return "just now"; const seconds = Math.round(Math.max(0, Date.now() - timestampMs) / 1e3); if (seconds < 5) return "just now"; if (seconds < 60) return `${String(seconds)}s ago`; const minutes = Math.round(seconds / 60); if (minutes < 60) return `${String(minutes)}m ago`; return `${String(Math.round(minutes / 60))}h ago`; } function aprsPacketSignature(packet) { return [ packet.srcCall ?? "", packet.destCall ?? "", packet.path ?? "", packet.info ?? "", packet.type ?? "", packet.lat?.toFixed(4) ?? "", packet.lon?.toFixed(4) ?? "" ].join("|"); } function collapseAprsDuplicates(packets) { const seen = /* @__PURE__ */ new Set(); return packets.filter((packet) => { const signature = aprsPacketSignature(packet); if (seen.has(signature)) return false; seen.add(signature); return true; }); } function aprsHexBytes(bytes) { if (!bytes?.length) return "--"; return bytes.map((byte) => byte.toString(16).toUpperCase().padStart(2, "0")).join(" "); } function renderAprsInfo(packet) { if (packet.info_bytes?.length) { return packet.info_bytes.map((byte) => renderAprsByte(byte)).join(""); } return Array.from(packet.info ?? "", (character) => renderAprsCharacter(character)).join(""); } function renderAprsByte(byte) { return byte >= 32 && byte <= 126 ? escapeAprsCharacter(String.fromCharCode(byte)) : `0x${byte.toString(16).toUpperCase().padStart(2, "0")}`; } function renderAprsCharacter(character) { const code = character.charCodeAt(0); return code >= 32 && code <= 126 ? escapeAprsCharacter(character) : `0x${code.toString(16).toUpperCase().padStart(2, "0")}`; } function escapeAprsCharacter(character) { if (character === "<") return "<"; if (character === ">") return ">"; if (character === "&") return "&"; if (character === '"') return """; return character; } function renderLocalAprsSymbol(packet, escapeHtml) { if (!packet.symbolTable || !packet.symbolCode) return ""; const symbol = escapeHtml(packet.symbolCode); const table = packet.symbolTable === "/" ? "Primary" : "Alternate"; return `${symbol}`; } function normalizeAprsPacket(packet, receiver) { return { rig_id: packet.rig_id || null, receiver, srcCall: packet.src_call ?? "", destCall: packet.dest_call ?? "", path: packet.path ?? "", info: packet.info ?? "", info_bytes: packet.info_bytes ?? [], type: packet.packet_type ?? "", crcOk: packet.crc_ok ?? false, ts_ms: packet.ts_ms ?? null, lat: packet.lat ?? null, lon: packet.lon ?? null, symbolTable: packet.symbol_table ?? null, symbolCode: packet.symbol_code ?? null }; } export { aprsPacketCategory, aprsCategoryLabel, aprsAgeText, collapseAprsDuplicates, aprsHexBytes, renderAprsInfo, renderLocalAprsSymbol, normalizeAprsPacket };