A TypeScript library for encoding and decoding CCSDS Space Packets — the standard packet format used in spacecraft telemetry and telecommand systems (CCSDS 133.0-B-2).
npm install @onion-party/spacepackets
# or
pnpm add @onion-party/spacepacketsimport { decode, PacketType } from "@onion-party/spacepackets";
const bytes = new Uint8Array([/* raw packet bytes from socket or file */]);
const packet = decode(bytes);
console.log(packet.header.apid); // Application Process ID
console.log(packet.header.sequenceCount); // For gap detection
console.log(packet.header.packetType); // PacketType.Telemetry or PacketType.Telecommand
console.log(packet.dataField); // Uint8Array — secondary header + user dataimport { encode, PacketType, SequenceFlags } from "@onion-party/spacepackets";
const packet = {
header: {
packetVersionNumber: 0,
packetType: PacketType.Telecommand,
secondaryHeaderFlag: false,
apid: 100,
sequenceFlags: SequenceFlags.Standalone,
sequenceCount: 0,
dataLength: 2, // dataField.byteLength - 1
},
dataField: new Uint8Array([0x01, 0x02, 0x03]),
};
const bytes = encode(packet); // Uint8Array ready for transmissionPackets often arrive in chunks — split across frame boundaries or delivered over a socket. PacketAssembler buffers incoming bytes and emits complete packets.
import { PacketAssembler } from "@onion-party/spacepackets";
const assembler = new PacketAssembler();
// Feed raw bytes as they arrive (e.g. from a UDP socket)
socket.on("data", (chunk: Buffer) => {
const packets = assembler.onChunk(chunk);
for (const packet of packets) {
console.log("received packet", packet.header.apid);
}
});All three stream classes compose via .pipe() for a fully declarative receive pipeline:
import {
PacketAssemblerStream,
GapDetectorStream,
SegmentationReassemblerStream,
type ReassembledAdu,
} from "@onion-party/spacepackets";
socket
.pipe(new PacketAssemblerStream({ maxBufferBytes: 1_000_000 }))
.pipe(new GapDetectorStream({
onGap: (gap) => console.warn(`APID ${gap.apid}: ${gap.missing} packet(s) missing`),
}))
.pipe(new SegmentationReassemblerStream({
onError: (err) => console.warn(`APID ${err.apid}: ${err.kind}`),
}))
.on("data", (adu: ReassembledAdu) => {
console.log(`APID ${adu.apid}: ${adu.data.byteLength} bytes`);
});GapDetector tracks the sequence count per APID and fires a callback whenever packets are missing.
import { GapDetector, PacketAssembler } from "@onion-party/spacepackets";
const assembler = new PacketAssembler();
const detector = new GapDetector({
onGap: (gap) => {
console.warn(`APID ${gap.apid}: expected ${gap.expected}, got ${gap.received} — ${gap.missing} packet(s) missing`);
},
});
socket.on("data", (chunk: Buffer) => {
const packets = assembler.onChunk(chunk);
for (const packet of packets) {
detector.onPacket(packet.header);
}
});Large application data units (ADUs) are sometimes split across multiple packets using First/Continuation/Last sequence flags. SegmentationReassembler buffers segments per APID and emits the fully concatenated data when the final segment arrives.
import { PacketAssembler, SegmentationReassembler } from "@onion-party/spacepackets";
const assembler = new PacketAssembler();
const reassembler = new SegmentationReassembler({
onAdu: (adu) => {
console.log(`APID ${adu.apid}: reassembled ${adu.data.byteLength} bytes`);
},
onError: (err) => {
if (err.kind === 'ORPHANED_SEGMENT') {
console.warn(`APID ${err.apid}: segment arrived with no matching First packet`);
} else {
console.warn(`APID ${err.apid}: new First arrived while ADU was in-progress — abandoned`);
}
},
});
socket.on("data", (chunk: Buffer) => {
const packets = assembler.onChunk(chunk);
for (const packet of packets) {
reassembler.onPacket(packet);
}
});All errors thrown by this library are instances of SpacePacketError. Use the code field to branch programmatically without parsing message strings.
import { decode, SpacePacketError } from "@onion-party/spacepackets";
try {
const packet = decode(bytes);
} catch (err) {
if (err instanceof SpacePacketError) {
switch (err.code) {
case "BUFFER_TOO_SHORT":
// Not enough bytes yet — wait for more data
break;
case "INVALID_VERSION":
// Packet version number is non-zero — malformed or unsupported
break;
}
}
}| Function | Description |
|---|---|
encode(packet) |
Serialize a SpacePacket to a Uint8Array |
decode(bytes) |
Parse a Uint8Array into a SpacePacket |
decodeHeader(bytes) |
Parse only the 6-byte primary header — useful in streaming contexts to learn the full packet length before the payload has arrived |
getPacketLength(header) |
Returns the total byte length of a packet given its header (6 + header.dataLength + 1) |
isIdlePacket(header) |
Returns true if the packet's APID is 0x7FF (the reserved idle/fill APID); idle packets carry no mission data and should be discarded |
| Class | Description |
|---|---|
PacketAssembler |
Stateful buffer that accepts raw byte chunks via onChunk(chunk) and returns complete SpacePacket[]. Handles packets split across chunk boundaries. |
GapDetector |
Tracks sequence counts per APID and calls onGap whenever packets are missing. Handles 14-bit wrap-around and ignores idle packets. |
SegmentationReassembler |
Reassembles segmented ADUs from First/Continuation/Last packet sequences. Calls onAdu when complete, onError on out-of-order or orphaned segments. |
PacketAssemblerStream |
Node.js Transform stream wrapping PacketAssembler. Accepts raw byte chunks on the writable side, emits decoded SpacePacket objects on the readable side. Emits INCOMPLETE_PACKET if the stream ends mid-packet. |
GapDetectorStream |
Passthrough Transform stream wrapping GapDetector. Accepts and re-emits SpacePacket objects; calls onGap as a side effect for any detected sequence gaps. |
SegmentationReassemblerStream |
Transform stream wrapping SegmentationReassembler. Accepts SpacePacket objects, emits ReassembledAdu objects when a complete ADU is assembled. |
SpacePacketError |
Thrown by encode/decode on malformed input, or emitted by PacketAssemblerStream. Has a code field: BUFFER_TOO_SHORT, INVALID_VERSION, APID_OUT_OF_RANGE, DATA_FIELD_EMPTY, DATA_LENGTH_MISMATCH, SEQUENCE_COUNT_OUT_OF_RANGE, PACKET_TOO_LARGE, BUFFER_OVERFLOW, INCOMPLETE_PACKET. |
This library implements CCSDS 133.0-B-2 — Space Packet Protocol, published by the Consultative Committee for Space Data Systems (CCSDS).
MIT
