webserial-core
Version:
A strongly-typed, event-driven, abstract TypeScript library for the Web Serial API with custom parsers, command queue, handshake validation, and auto-reconnect.
126 lines (125 loc) • 4.97 kB
TypeScript
import { SerialEventEmitter } from './SerialEventEmitter.js';
import { SerialDeviceOptions, SerialPolyfillOptions, SerialProvider } from '../types/index.js';
/**
* Abstract base class for all serial devices.
*
* @typeParam T - Type of parsed data emitted by `"serial:data"` events.
* Use `string` with a delimiter parser, `Uint8Array` for raw/fixed-length,
* or any custom type with a custom parser.
*/
export declare abstract class AbstractSerialDevice<T> extends SerialEventEmitter<T> {
/** The currently open serial port, or `null` when disconnected. */
protected port: SerialPort | null;
private reader;
private writer;
private queue;
private options;
private isConnecting;
private abortController;
private userInitiatedDisconnect;
private reconnectTimerId;
private isHandshaking;
/**
* Custom serial provider (e.g. a WebUSB polyfill).
* Falls back to `navigator.serial` when not set.
*/
private static customProvider;
/**
* Options forwarded to the polyfill provider on every
* `requestPort()` / `getPorts()` call.
*/
private static polyfillOptions;
constructor(options: SerialDeviceOptions<T>);
/**
* Override this method in your subclass to perform a handshake
* after the port is opened. Return `true` if the handshake
* succeeds (correct device), or `false` to reject the port.
*
* The method receives the opened port and should write/read
* directly to validate the device identity.
*
* If not overridden, all ports are accepted (no handshake).
*/
protected handshake(): Promise<boolean>;
connect(): Promise<void>;
disconnect(): Promise<void>;
/**
* Returns `true` if the device is currently connected and the port
* is open, readable, and writable. Note that a port can become
* disconnected at any time (e.g. unplugged), so this is not a
* guarantee that a subsequent read/write will succeed, but it is
* a useful check before attempting communication.
* @returns `true` if the device is connected and ready for communication, `false` otherwise.
*/
isConnected(): boolean;
/**
* Returns `true` if the device is not connected or in the process of connecting.
* This is a convenience method equivalent to `!isConnected()`, but may be more
* semantically clear in certain contexts (e.g. when checking for disconnection
* in a read loop catch block).
* @returns `true` if the device is disconnected or not ready, `false` if it is currently connected.
*/
isDisconnected(): boolean;
/**
* Internal cleanup: tears down the port, reader, writer without
* marking it as user-initiated. This allows auto-reconnect to trigger.
*/
private cleanupPort;
forget(): Promise<void>;
send(data: string | Uint8Array): Promise<void>;
clearQueue(): void;
private writeToPort;
private readLoop;
/**
* Opens a port, locks it in the registry, starts reading, and runs the handshake.
* If handshake fails, tears down reader/queue, closes and unlocks the port.
*/
private openAndHandshake;
/**
* Cleans up after a failed handshake attempt and restores the queue.
*/
private teardownHandshake;
/**
* Cancels and releases the current reader.
*/
private stopReader;
/**
* Wraps the handshake() in a timeout race.
*/
private runHandshakeWithTimeout;
/**
* Iterates ALL previously-authorized ports matching filters.
* For each match, opens + handshake. Returns the first port that passes.
* If a port fails handshake, it is closed and the next one is tried.
*/
private findAndValidatePort;
private startReconnecting;
stopReconnecting(): void;
private reconnect;
static getInstances(): AbstractSerialDevice<unknown>[];
static connectAll(): Promise<void>;
/**
* Sets a custom serial provider (e.g. a WebUSB polyfill for Android).
* Call this once before any `connect()` if the native Web Serial API
* is not available.
*
* @param provider The provider object (`{ requestPort, getPorts }`).
* @param options Polyfill options forwarded on every `requestPort` /
* `getPorts` call. Use `usbControlInterfaceClass` to
* support devices that don't use the standard CDC class
* code (2). E.g. `{ usbControlInterfaceClass: 255 }`.
*
* @example
* ```ts
* import { serial as polyfill } from 'web-serial-polyfill';
* AbstractSerialDevice.setProvider(polyfill, {
* usbControlInterfaceClass: 255,
* });
* ```
*/
static setProvider(provider: SerialProvider, options?: SerialPolyfillOptions): void;
/**
* Returns the serial provider: instance provider > custom provider > navigator.serial > null.
*/
private getSerial;
}