TAKPacket-SDK — TypeScript - v0.7.0
    Preparing search index...

    Class TakCompressor

    Encodes a TAKPacketV2 into the on-wire [flags][zstd body] payload and decodes it back, using the bundled zstd dictionaries.

    Wire format. A compressed payload is one flags byte (bits 0–5 = dictionary ID, bits 6–7 reserved/zero) followed by a zstd frame body whose 4-byte magic number has been stripped (re-prepended on decode). When compression would not shrink the packet, compress instead emits the flags byte 0xFF followed by the raw protobuf (skip-compress), so tiny payloads never expand. The total wire payload must stay within the 237-byte LoRa MTU; use compressWithRemarksFallback to enforce that with graceful remarks stripping.

    Resilience. Each packet is compressed as one independent, one-shot zstd frame against the static shipped dictionary — never the streaming API and never any cross-packet/adaptive state — so any single packet decodes on its own from its own bytes plus the dictionary. This is the hard resilience invariant for a lossy LoRa link.

    windowLog. zstd-napi does not auto-size its compression window to a large loaded dictionary, so this class sets windowLog: 21 before loadDictionary (and windowLogMax: 27 on the decompressors) so small inputs can still reference deep matches in the 512 KB dictionary and peer frames with larger windows still decode. Setting windowLog after the dictionary is loaded would silently reset the digested dictionary.

    Dictionaries are loaded and digested lazily on the first compress/ decompress call, then reused for the lifetime of the instance, so reuse one TakCompressor rather than constructing one per packet.

    import { TakCompressor, parseCotXml, buildCotXml } from "@meshtastic/takpacket-sdk";

    const codec = new TakCompressor();

    // Encode CoT XML for the mesh:
    const packet = parseCotXml(cotXmlString);
    const wire = await codec.compress(packet); // Buffer, ≤ 237 bytes

    // Decode a received frame back to CoT XML:
    const decoded = await codec.decompress(wire);
    const xml = buildCotXml(decoded);
    Index

    Constructors

    Methods

    • Compress a TAKPacketV2 into a wire payload: [flags][zstd body].

      Serializes the packet to protobuf, picks the dictionary from the packet's CoT type (selectDictId), compresses as one independent zstd frame (level 19, content-size/checksum/dictID frame fields off), and strips the 4-byte zstd magic. If the raw protobuf is no larger than the compressed body, emits the skip-compress form [0xFF][raw protobuf] instead so the payload never expands.

      Parameters

      • packet: TAKPacketV2

        The packet to encode. Field units are wire units: speed in cm/s, course in degrees×100, altitude in meters HAE (may be negative), latitudeI/longitudeI in degrees×1e7, shape radii in cm. A packet with no payload variant and an a-f-* CoT type is an implicit PLI.

      Returns Promise<Buffer<ArrayBufferLike>>

      A Promise resolving to the compressed wire payload (Buffer).

      The caller is responsible for keeping the result within the 237-byte LoRa MTU; this method does not enforce it. Use compressWithRemarksFallback when you need MTU enforcement. Asynchronous because the protobuf schema is loaded lazily.

      If the packet fails protobuf validation, or no compressor exists for the selected dictionary, or the zstd frame header is not the expected magic.

      const codec = new TakCompressor();
      const wire = await codec.compress({ cotTypeId: 1, latitudeI: 388895000, longitudeI: -770353000 });
      // wire[0] is the flags byte (dictionary ID, or 0xFF if uncompressed)
    • Compress a packet, stripping remarks if the result exceeds maxWireBytes.

      First attempts compression with remarks intact. If the wire payload fits within maxWireBytes, returns it as-is. Otherwise, clears the remarks field and re-compresses. Returns null if even the stripped packet exceeds the limit (caller should drop the packet).

      This is a thin wrapper over compressWithRemarksFallbackDetailed that discards the remarksStripped flag. Use the Detailed variant if you need to tell "fit as-is", "fit after strip", and "dropped" apart — e.g. for observability or metrics.

      Parameters

      • packet: TAKPacketV2

        The packet with remarks populated.

      • maxWireBytes: number

        Maximum allowed wire payload size (e.g. 225).

      Returns Promise<Buffer<ArrayBufferLike> | null>

      The wire payload, or null if the packet is too large even without remarks.

    • Compress a packet and report its sizes and emitted mode.

      Equivalent to compress plus a CompressionResult describing the protobuf size, final wire size, and the dictionary/mode actually emitted (read back from the flags byte, so it reflects a skip-compress 0xFF fallback). Used by the golden compression-report tooling.

      Parameters

      Returns Promise<CompressionResult>

      A Promise resolving to the compression statistics, including the wire payload itself.

      The same conditions as compress.

    • Decompress a wire payload back into a TAKPacketV2.

      Reads the flags byte: 0xFF means the body is raw protobuf; otherwise the low 6 bits select the dictionary, the stripped 4-byte zstd magic is re-prepended, and the body is decompressed with that dictionary. The decompressed size is capped at 4096 bytes as a decompression-bomb guard before the protobuf is parsed.

      Parameters

      • wirePayload: Buffer

        A received [flags][body] payload (must be ≥ 2 bytes).

      Returns Promise<TAKPacketV2>

      A Promise resolving to the decoded packet. Field units are wire units (see compress).

      Reserved flag bits are ignored (the dictionary ID is masked with & 0x3F). Asynchronous because the protobuf schema is loaded lazily.

      If the payload is shorter than 2 bytes, the dictionary ID is unknown, zstd decompression fails, the decompressed size exceeds 4096 bytes, or the protobuf fails to parse.

      const codec = new TakCompressor();
      const packet = await codec.decompress(receivedWireBuffer);