Skip to content

@moqtap/trace

Read, write, and record MoQT session traces.

npm | GitHub

@moqtap/trace implements the .moqtrace binary format for JavaScript/TypeScript. It provides:

  • One-shot and streaming read/write of .moqtrace files
  • A recorder that wraps @moqtap/codec sessions and auto-captures events
  • Detail-level filtering (control only through full wire bytes)
  • JSON serialization for inspection and debugging

Peer dependency on @moqtap/codec. Uses cbor-x for CBOR encoding.

Terminal window
npm install @moqtap/trace @moqtap/codec
import { readMoqtrace, readMoqtraceHeader } from '@moqtap/trace';
// Full read — header + all events
const trace = readMoqtrace(bytes);
console.log(trace.header.protocol); // 'moq-transport-14'
console.log(trace.events.length); // number of events
// Header-only read — fast metadata extraction
const header = readMoqtraceHeader(bytes);
console.log(header.perspective); // 'client'
console.log(header.detail); // 'control'
import { writeMoqtrace, createMoqtraceWriter } from '@moqtap/trace';
// One-shot — serialize a complete trace to bytes
const bytes = writeMoqtrace({ header, events });
// Streaming — write incrementally as events arrive
const writer = createMoqtraceWriter(header);
const preamble = writer.preamble(); // magic + version + header
const chunk1 = writer.writeEvent(event1);
const chunk2 = writer.writeEvent(event2);
// Concatenate preamble + chunks to get the complete file

The recorder wraps a SessionState from @moqtap/codec and auto-captures control messages, state transitions, and data events filtered by detail level.

import { createRecorder } from '@moqtap/trace';
import { createSessionState } from '@moqtap/codec/session';
import { MESSAGE_ID_MAP } from '@moqtap/codec/draft14';
const recorder = createRecorder({
detail: 'headers',
protocol: 'moq-transport-14',
perspective: 'client',
source: 'my-app/1.0.0',
endpoint: 'https://relay.example.com/moq',
messageTypeId: (name) => Number(MESSAGE_ID_MAP.get(name) ?? 0),
});
// messageTypeId resolves message names to wire type IDs for control events.
// The recorder is draft-agnostic — you bring your own mapping.
// Defaults to () => 0 if omitted.
// Wrap a session — receive/send calls are auto-recorded
const session = createSessionState({ draft: 'moq-transport-14', role: 'client' });
const traced = recorder.wrapSession(session);
// Use the wrapped session normally
traced.send(clientSetup);
traced.receive(serverSetup);
// State changes and control messages are captured automatically
// Record data events manually
recorder.recordStreamOpened(0n, 1, 0); // incoming subgroup stream
recorder.recordObjectHeader(0n, 1n, 0n, 128, 0);
recorder.recordObjectPayload(0n, 1n, 0n, 256);
recorder.recordStreamClosed(0n, 0);
// Add custom annotations
recorder.annotate('user-action', { clicked: 'subscribe' });
// Finalize and export
const trace = recorder.finalize();
const bytes = writeMoqtrace(trace);

The recorder automatically filters events based on the configured detail level:

Detail levelControl messagesStream/object headersPayload sizesPayload bytesRaw wire bytes
controlYes
headersYesYes
headers+sizesYesYesYes
headers+dataYesYesYesYes
fullYesYesYesYesYes

Errors and annotations are always recorded regardless of detail level.

The recorder defaults to a 100,000 event buffer. When the limit is reached, the oldest events are evicted. Sequence numbers remain monotonically increasing (they are not reset on eviction).

const recorder = createRecorder({
// ...
maxEvents: 50_000, // custom buffer size
});

For inspection and debugging, traces can be converted to JSON. Note that this is lossy — bigint values become hex strings and Uint8Array values become hex strings.

import { traceToJSON } from '@moqtap/trace';
const json = traceToJSON(trace); // pretty-printed JSON string
FunctionDescription
readMoqtrace(bytes)Parse a complete .moqtrace file into a Trace
readMoqtraceHeader(bytes)Parse only the header (skip events)
writeMoqtrace(trace)Serialize a Trace to .moqtrace bytes
createMoqtraceWriter(header)Create a streaming writer
createRecorder(options)Create a session recorder
traceToJSON(trace)Serialize to JSON (lossy)

Events use a discriminated union on the type field:

TypeDescription
controlControl message sent or received
stream-openedQUIC stream opened
stream-closedQUIC stream closed
object-headerObject metadata parsed from data stream
object-payloadObject payload bytes
state-changeSession FSM phase transition
errorProtocol or transport error
annotationUser-defined event

See .moqtrace File Format for the complete binary specification.