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

    Interface SerialSession

    v2 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 purely from state$ + isConnected$ + receive$ + terminalText$ + lines$ + errors$ 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.

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

    session.state$.subscribe((state) => console.log('state:', state));
    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>;
        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>;
        disconnect$(): Observable<void>;
        getCurrentPort(): SerialPort | null;
        getPortInfo(): SerialPortInfo | null;
        isBrowserSupported(): boolean;
        send$(data: string | Uint8Array<ArrayBufferLike>): Observable<void>;
    }
    Index

    Properties

    errors$: Observable<SerialError>

    Primary 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$ is 'connected', false for all other states.

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

    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. 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 SerialSessionState.Idle, SerialSessionState.Error, and SerialSessionState.Unsupported).

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

    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>

    Reactive session lifecycle state.

    Replays the current state on subscribe. UIs should drive entirely from this stream instead of reconstructing their own BehaviorSubject.

    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.

    Equivalent behavior:

    createTerminalBuffer(receive$).text$
    

    Methods

    • 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.

      Returns Observable<void>

      An Observable that completes when the port is fully closed.

    • 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

      • data: string | Uint8Array<ArrayBufferLike>

        Text (UTF-8 encoded) or raw bytes to send.

      Returns Observable<void>

      An Observable that completes when the payload is written.