// 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; } var APRS_SPRITE_COLUMNS = 16; var APRS_SPRITE_CELL_PX = 24; var APRS_SPRITE_FIRST_CODE = 33; var APRS_SPRITE_LAST_CODE = 126; function aprsSpriteOffset(code) { if (code.length !== 1) return null; const point = code.charCodeAt(0); if (point < APRS_SPRITE_FIRST_CODE || point > APRS_SPRITE_LAST_CODE) return null; const index = point - APRS_SPRITE_FIRST_CODE; const column = index % APRS_SPRITE_COLUMNS; const row = Math.floor(index / APRS_SPRITE_COLUMNS); return `${String(-column * APRS_SPRITE_CELL_PX)}px ${String(-row * APRS_SPRITE_CELL_PX)}px`; } function aprsSymbolSprite(symbolTable, symbolCode) { if (!symbolTable || !symbolCode) return null; const symbolOffset = aprsSpriteOffset(symbolCode); if (!symbolOffset) return null; if (symbolTable === "/") { return { className: "aprs-symbol-primary", backgroundPosition: symbolOffset, label: `Primary APRS symbol ${symbolTable}${symbolCode}` }; } if (symbolTable === "\\") { return { className: "aprs-symbol-alternate", backgroundPosition: symbolOffset, label: `Alternate APRS symbol ${symbolTable}${symbolCode}` }; } const overlayOffset = aprsSpriteOffset(symbolTable); if (!overlayOffset) return null; return { className: "aprs-symbol-overlaid", backgroundPosition: `${overlayOffset}, ${symbolOffset}`, label: `Alternate APRS symbol \\${symbolCode} with overlay ${symbolTable}` }; } function renderLocalAprsSymbol(packet, escapeHtml) { if (!packet.symbolTable || !packet.symbolCode) return ""; const sprite = aprsSymbolSprite(packet.symbolTable, packet.symbolCode); if (sprite) { 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, aprsSymbolSprite, renderLocalAprsSymbol, normalizeAprsPacket };