web-serial-rxjs API Documentation
    Preparing search index...

    Interface SerialSession

    Public API for interacting with the Web Serial API through a minimal, session-oriented surface.

    The session is intentionally slim so that apps (Angular, Vue, React, etc.) can drive their UI from state$ (canonical lifecycle state) + errors$ (error event channel) + receive$ + terminalText$ + lines$ and never have to rebuild BehaviorSubjects, manage a read loop, or serialize writes themselves.

    All imperative Web Serial work (open / read loop / write / close) is encapsulated by the implementation. Only Observables are exposed.

    import { createSerialSession, SerialSessionStatus } from '@gurezo/web-serial-rxjs';

    const session = createSerialSession({ baudRate: 115200 });

    session.state$.subscribe((state) => {
    switch (state.status) {
    case SerialSessionStatus.Connected:
    console.log('connected:', state.portInfo);
    break;
    case SerialSessionStatus.Error:
    console.error('error:', state.error);
    break;
    }
    });
    session.receive$.subscribe((chunk) => console.log('rx:', chunk));
    session.errors$.subscribe((error) => console.error('err:', error));

    session.connect$().subscribe();
    session.send$('hello\r\n').subscribe();
    interface SerialSession {
        errors$: Observable<SerialError<SerialErrorCode>>;
        isConnected$: Observable<boolean>;
        lines$: Observable<string>;
        portInfo$: Observable<SerialPortInfo | null>;
        receive$: Observable<string>;
        receiveReplay$: Observable<string>;
        state$: Observable<SerialSessionState>;
        terminalText$: Observable<string>;
        connect$(): Observable<void>;
        destroy$(): Observable<void>;
        disconnect$(): Observable<void>;
        dispose$(): Observable<void>;
        getPortInfo(): SerialPortInfo | null;
        isBrowserSupported(): boolean;
        send$(data: SerialPayload): Observable<void>;
    }
    Index
    errors$: Observable<SerialError<SerialErrorCode>>

    Canonical fatal / non-fatal error channel.

    All SerialError instances produced by the session (connect / read / write / close) are multiplexed here. This is the main channel, not a supplementary one.

    Every emission is the exact same instance that is also surfaced to the relevant call-site subscriber (for example connect$().subscribe receives the same SerialError that errors$ emits for that failure), so a single subscription is enough to observe the full error history without double-normalisation.

    Fatal failures (connect / read / close) additionally drive state$ to 'error' and tear down the live pump + port; non-fatal failures (currently only send$ write failures) are multiplexed here without mutating state$, on the assumption that a real connection loss is detected by the read pump on the next tick.

    isConnected$: Observable<boolean>

    true when state$ has status: 'connected', false otherwise.

    Derived from state$ with distinctUntilChanged so UIs can bind connect/disabled flags without reimplementing the comparison.

    Prefer narrowing state$ with SerialSessionStatus.Connected. Retained for backward compatibility; scheduled for removal in the next major version.

    lines$: Observable<string>

    Decoded text split into complete lines using \n, \r\n, and lone interior \r (see implementation). Intended for logs, newline-framed command responses, and parsers—not for mirroring raw terminal output where \r must be preserved for progress/redraw. For rendering terminal text, prefer terminalText$.

    A trailing fragment without a line terminator is buffered until a later chunk completes a line, or discarded on disconnect. The incomplete tail is bounded by SerialSessionOptions.lineBuffer maxChars (default 1,048,576); when exceeded, leading characters are discarded and a non-fatal SerialErrorCode.LINE_BUFFER_OVERFLOW is emitted on errors$. Pass { maxChars: 0 } for unlimited growth. It is not subscription-lazy: the same framing runs whenever the read pump is active, independent of subscribers.

    portInfo$: Observable<SerialPortInfo | null>

    The active port’s SerialPort.getInfo snapshot, or null when no port is open (including SerialSessionStatus.Idle, SerialSessionStatus.Error, and SerialSessionStatus.Unsupported).

    Emits the current value on subscribe. Use with state$ to know when the value is valid for your UI.

    Prefer narrowing state$ with SerialSessionStatus.Connected and using state.portInfo. Retained for backward compatibility; scheduled for removal in the next major version.

    receive$: Observable<string>

    Incoming data from the serial port as UTF-8 decoded text.

    The stream is driven by the read pump started by connect$ and is decoded internally with a streaming TextDecoder, so multi-byte characters split across chunks are joined correctly. It is not subscription-lazy: emissions happen regardless of whether a consumer is currently subscribed, so late subscribers see only new data.

    Emits raw decoder chunks (not line-aligned): carriage returns and other control characters from the peer are preserved. Use this for terminal-like mirrors, progress output that relies on \r, or raw inspection. Do not drive those UIs from lines$, which may split on interior \r and break redraw semantics.

    For newline-framed protocols, logs, or line-by-line parsing, prefer lines$ or derive custom framing from receive$.

    receiveReplay$: Observable<string>

    Same source data as receive$ but, when SerialSessionOptions.receiveReplay has enabled: true, it uses a replay buffer per open connection so new subscribers can receive the last N decoded text chunks from that connection. When receive replay is off (default), this is the same hot stream as receive$.

    Does not change lines$ (line framing is not replayed here).

    state$: Observable<SerialSessionState>

    Canonical lifecycle source for the session.

    Reactive session lifecycle state as a discriminated union. Replays the current state on subscribe. Switch on state.status and use the per-variant fields (portInfo when SerialSessionStatus.Connected, error when SerialSessionStatus.Error) instead of correlating separate streams.

    terminalText$: Observable<string>

    Terminal-display oriented cumulative text derived from receive$.

    This stream collapses carriage-return redraws (\r) and keeps normal newline behavior (\n, \r\n) so apps can bind terminal-like output directly without wrapping createTerminalBuffer in every consumer. By default, retains at most 10,000 completed lines and 1,048,576 characters; configure via SerialSessionOptions.terminalBuffer.

    Equivalent behavior:

    createTerminalBuffer(receive$).text$
    
    • Open a serial port and start the internal read pump.

      Returns an Observable that completes when the port is fully opened and the read pump is running. Subscribing to receive$ before calling connect$ is safe: emissions simply start after the pump is active.

      Returns Observable<void>

      An Observable that completes on successful connection.

    • Close the active serial port and stop the internal read pump.

      Safe to call when already disconnected or while a disconnect is already in progress. When called during 'connecting', cancels the in-flight connect$() (closes any opened port) and returns the session to 'idle' without reaching 'connected'.

      Returns Observable<void>

      An Observable that completes when the port is fully closed.

    • Permanently tear down the session and complete all observables.

      Unlike disconnect$, which returns the session to 'idle' for reuse, dispose$ closes any active connection, releases internal resources, emits 'disposed' on state$, and completes every session stream. After disposal, connect$ and send$ fail with SerialErrorCode.SESSION_DISPOSED; create a new session instead of reusing this instance.

      Safe to call multiple times; subsequent calls complete immediately.

      Returns Observable<void>

      An Observable that completes when disposal has finished.

    • Enqueue data for ordered transmission.

      Writes are serialized internally through a FIFO send queue so that concurrent send$ calls are delivered to the port in call order, regardless of how quickly each subscriber runs. String payloads are UTF-8 encoded via a shared TextEncoder; Uint8Array payloads are passed through unchanged. Write failures are normalized into SerialError with SerialErrorCode.WRITE_FAILED and multiplexed on SerialSession.errors$ in addition to being surfaced to the subscriber, so a single subscription is enough to observe every I/O error. Calling send$ while the session is not in 'connected' state fails fast with SerialErrorCode.PORT_NOT_OPEN.

      The returned Observable completes once the enqueued payload has been flushed to the underlying writer.

      Parameters

      Returns Observable<void>

      An Observable that completes when the payload is written.