Parsers
Parsers transform a stream of raw Uint8Array chunks into structured values of type T. Pass a parser to SerialDeviceOptions.parser.
Built-in parsers
delimiter(separator, options?)
Accumulates bytes until the delimiter sequence is found, then emits the frame with the delimiter stripped (unless includeDelimiter is true).
- When
separatoris a string, bytes are decoded as UTF-8 and astringis emitted. - When
separatoris aUint8Arrayornumber[], raw bytes are emitted asUint8Array.
import { delimiter } from "webserial-core";
// Split on newline — good for Arduino Serial.println()
parser: delimiter("\n");
// Split on carriage-return + newline
parser: delimiter("\r\n");
// Include the delimiter in the emitted value
parser: delimiter("\n", { includeDelimiter: true });
// Split on a binary sequence — emits Uint8Array
parser: delimiter(new Uint8Array([0x0d, 0x0a]));
// Split using a number array — emits Uint8Array
parser: delimiter([0xaa, 0xff]);| Parameter | Type | Description |
|---|---|---|
separator | string | Uint8Array | number[] | Byte sequence that marks the end of a frame |
options.includeDelimiter | boolean | Append the delimiter to each emitted value. Default: false |
Emits: string (when separator is string) · Uint8Array (when separator is binary)
readline(options?)
Splits the byte stream on a configurable line delimiter and emits each line as a decoded string. Equivalent to @serialport/parser-readline.
import { readline } from "webserial-core";
// Default — split on '\n', UTF-8
parser: readline();
// Custom delimiter and encoding
parser: readline({ delimiter: "\r\n", encoding: "ascii" });
// Include the delimiter
parser: readline({ delimiter: "\n", includeDelimiter: true });| Option | Type | Default | Description |
|---|---|---|---|
delimiter | string | Uint8Array | number[] | '\n' | Line terminator sequence |
includeDelimiter | boolean | false | Append the delimiter to each emitted string |
encoding | string | 'utf-8' | Text encoding used to decode bytes |
Emits: string
fixedLength(length)
Emits every N bytes as a raw Uint8Array. Useful for binary protocols with fixed-size packets.
import { fixedLength } from "webserial-core";
// Emit every 16 bytes
parser: fixedLength(16);| Parameter | Type | Description |
|---|---|---|
length | number | Number of bytes per frame |
Emits: Uint8Array
raw()
Passes each chunk from the port unchanged. Use this when you want to handle framing yourself.
import { raw } from "webserial-core";
parser: raw();Emits: Uint8Array
interByteTimeout(options)
Buffers incoming bytes and emits them after a period of silence (interval ms with no new bytes), or when the buffer reaches maxBufferSize. Equivalent to @serialport/parser-inter-byte-timeout.
import { interByteTimeout } from "webserial-core";
// Emit buffered data after 30 ms of silence
parser: interByteTimeout({ interval: 30 });
// With a max buffer cap
parser: interByteTimeout({ interval: 30, maxBufferSize: 1024 });| Option | Type | Default | Description |
|---|---|---|---|
interval | number | — | Silence period in milliseconds before emitting (required) |
maxBufferSize | number | 65536 | Maximum bytes to buffer before forcing an emit |
Emits: Uint8Array
packetLength(options?)
Frames packets using a leading delimiter byte and an embedded length field. Equivalent to @serialport/parser-packet-length.
Default packet layout: [0xAA][0x00][len][payload...][footer]
import { packetLength } from "webserial-core";
// Default options
parser: packetLength();
// Custom packet structure: [0xBC][0x00][lenHi][lenLo][cargo...][footer0][footer1]
parser: packetLength({ delimiter: 0xbc, packetOverhead: 5, lengthBytes: 2, lengthOffset: 2 });| Option | Type | Default | Description |
|---|---|---|---|
delimiter | number | 0xAA | Byte value that marks the start of each packet |
packetOverhead | number | 2 | Total fixed overhead bytes (delimiter + length field(s) + any footer) |
lengthBytes | number | 1 | Number of bytes that encode the payload length |
lengthOffset | number | 1 | Byte offset from the delimiter to the first length byte |
maxLen | number | 0xFF | Maximum allowed payload length; packets exceeding this are discarded |
Emits: Uint8Array
regexParser(options)
Decodes incoming bytes and splits the resulting string on a regular expression, emitting each segment. Equivalent to @serialport/parser-regex.
import { regexParser } from "webserial-core";
// Split on any combination of \r and \n
parser: regexParser({ regex: /[\r\n]+/ });
// Split on semicolons, case-insensitive
parser: regexParser({ regex: /;+/ });| Option | Type | Default | Description |
|---|---|---|---|
regex | RegExp | string | — | Pattern used to split the incoming text |
encoding | string | 'utf-8' | Text encoding used to decode bytes |
Emits: string
readyParser(options)
Discards all incoming bytes until a configurable "ready" sequence is detected. After that, every subsequent byte chunk is emitted as-is. Fires an optional onReady callback when the sequence is found. Equivalent to @serialport/parser-ready.
import { readyParser } from "webserial-core";
parser: readyParser({
delimiter: "READY\n",
onReady: () => console.log("device is ready"),
});| Option | Type | Description |
|---|---|---|
delimiter | string | Uint8Array | number[] | Byte sequence that signals the device is ready (required) |
onReady | () => void | Called once when the ready sequence is detected |
Emits: Uint8Array (all data received after the ready sequence)
ccTalk(maxDelayBetweenBytesMs?)
Parses ccTalk bus packets. Each packet is N + 5 bytes where N is the data length in byte 1. The internal buffer is discarded if no byte arrives within maxDelayBetweenBytesMs. Equivalent to @serialport/parser-cctalk.
import { ccTalk } from "webserial-core";
// Default 50 ms inter-byte timeout
parser: ccTalk();
// Custom timeout
parser: ccTalk(100);| Parameter | Type | Default | Description |
|---|---|---|---|
maxDelayBetweenBytesMs | number | 50 | Maximum silence between bytes before the buffer is reset |
Emits: Uint8Array
slipDecoder(options?)
Decodes a SLIP-framed byte stream (RFC 1055) and emits each packet. Optional custom escape / end bytes are supported. Equivalent to SlipDecoder from @serialport/parser-slip-encoder.
import { slipDecoder } from "webserial-core";
// Standard SLIP
parser: slipDecoder();
// Custom framing bytes
parser: slipDecoder({ END: 0xc0, ESC: 0xdb, ESC_END: 0xdc, ESC_ESC: 0xdd });
// Bluetooth quirk — expects a START byte before each packet
parser: slipDecoder({ START: 0xc0 });| Option | Type | Default | Description |
|---|---|---|---|
END | number | 0xC0 | Packet end byte |
ESC | number | 0xDB | Escape byte |
ESC_END | number | 0xDC | ESC sequence for the END byte |
ESC_ESC | number | 0xDD | ESC sequence for the ESC byte |
START | number | — | Optional packet start byte |
ESC_START | number | ESC | ESC sequence for the START byte |
Emits: Uint8Array
slipEncode(data, options?)
Utility function (not a parser) that SLIP-encodes an outgoing packet before writing it to the serial port.
import { slipEncode } from "webserial-core";
const frame = slipEncode(new Uint8Array([0x01, 0xc0, 0x02]));
await device.send(frame);
// Bluetooth quirk — prepends an extra END byte
const frame = slipEncode(payload, { bluetoothQuirk: true });| Option | Type | Default | Description |
|---|---|---|---|
bluetoothQuirk | boolean | false | Prepend an END byte at the beginning of each packet |
| (+ all SLIP bytes from above) |
Returns: Uint8Array
spacePacket(options?)
Parses CCSDS Space Packet Protocol frames and emits a structured SpacePacket object for each complete packet. Equivalent to @serialport/parser-spacepacket.
import { spacePacket } from "webserial-core";
// No secondary header
parser: spacePacket();
// With a time code field in the secondary header
parser: spacePacket({ timeCodeFieldLength: 8 });
// With both time code and ancillary data fields
parser: spacePacket({ timeCodeFieldLength: 4, ancillaryDataFieldLength: 2 });| Option | Type | Default | Description |
|---|---|---|---|
timeCodeFieldLength | number | 0 | Length in bytes of the Time Code Field |
ancillaryDataFieldLength | number | 0 | Length in bytes of the Ancillary Data Field |
Emits: SpacePacket
interface SpacePacket {
header: {
versionNumber: number;
identification: { apid: number; secondaryHeader: number; type: number };
sequenceControl: { packetName: number; sequenceFlags: number };
dataLength: number;
};
secondaryHeader?: {
timeCode?: string;
ancillaryData?: string;
};
data: string;
}Custom parsers
Implement SerialParser<T> to handle any custom protocol:
import type { SerialParser } from "webserial-core";
interface MyPacket {
command: number;
payload: Uint8Array;
}
function myProtocolParser(): SerialParser<MyPacket> {
const buffer: number[] = [];
return {
parse(chunk, emit) {
for (const byte of chunk) {
buffer.push(byte);
// Simple framing: packets start with 0xAA and are 5 bytes long
if (buffer[0] !== 0xaa) {
buffer.shift();
continue;
}
if (buffer.length < 5) continue;
emit({
command: buffer[1],
payload: new Uint8Array(buffer.splice(0, 5).slice(2)),
});
}
},
reset() {
buffer.length = 0;
},
};
}Then use it in your device:
super({
baudRate: 115200,
parser: myProtocolParser(),
});The T type parameter on AbstractSerialDevice<T> and SerialEventMap<T> will automatically match the type your parser emits.
Parser interface
interface SerialParser<T> {
/** Called for each raw chunk received from the port. */
parse(chunk: Uint8Array, emit: (value: T) => void): void;
/** Optional — resets internal buffer state (e.g. on reconnect). */
reset?(): void;
}