{"_id":"@danidoble/webserial-hopper","name":"@danidoble/webserial-hopper","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@danidoble/webserial-hopper","type":"module","version":"1.0.0","description":"A strongly-typed, event-driven USB hopper driver for the Web Serial API, built on top of webserial-core.","author":{"name":"Danidoble","email":"ddanidoble@gmail.com"},"license":"GPL-3.0-only","homepage":"https://github.com/danidoble/webserial-hopper#readme","repository":{"type":"git","url":"git+https://github.com/danidoble/webserial-hopper.git"},"bugs":{"url":"https://github.com/danidoble/webserial-hopper/issues"},"exports":{".":{"import":"./dist/index.mjs","require":"./dist/index.cjs"},"./package.json":"./package.json"},"devDependencies":{"@eslint/js":"^10.0.1","@typescript/native-preview":"7.0.0-dev.20260328.1","bumpp":"^11.0.1","eslint":"^10.2.1","globals":"^17.5.0","prettier":"3.8.3","tsdown":"^0.21.10","typescript":"^6.0.3","typescript-eslint":"^8.59.0","vitest":"^4.1.5","webserial-core":"^2.1.0"},"peerDependencies":{"webserial-core":"^2.1.0"},"main":"./dist/index.cjs","module":"./dist/index.mjs","types":"./dist/index.d.cts","scripts":{"build":"tsdown","dev":"prettier --write ./src/**/*.ts && tsdown --watch","test":"vitest","typecheck":"tsc --noEmit","release":"bumpp","lint":"eslint ./src/**/*.ts ./tests/**/*.ts","format":"prettier --write ./src/ ./tests/ ./README.md ./package.json"},"_id":"@danidoble/webserial-hopper@1.0.0","_integrity":"sha512-eZzyFcw6SebXIqq/gMklMxgPrFf+P8ij1ejR0ktV/T0Hdy1bP5xeaShbERtmEoXBZDWv+YU8gox2tEIwds8l/Q==","_resolved":"/tmp/0ec685d7e1d561b4c52124ac614d825c/danidoble-webserial-hopper-1.0.0.tgz","_from":"file:danidoble-webserial-hopper-1.0.0.tgz","_nodeVersion":"24.12.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-eZzyFcw6SebXIqq/gMklMxgPrFf+P8ij1ejR0ktV/T0Hdy1bP5xeaShbERtmEoXBZDWv+YU8gox2tEIwds8l/Q==","shasum":"400ef48e0c65cda0cc4d03423a5cf7ec19d6cf83","tarball":"https://registry.npmjs.org/@danidoble/webserial-hopper/-/webserial-hopper-1.0.0.tgz","fileCount":7,"unpackedSize":84204,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDehXKVj7oGFG01uyrAuSbm7TNINfYK62u7jl1zfxjbLQIgM4xsji9Rjd3hWOkrpphj0yxXTd6BMCvWFkymxZWM70A="}]},"_npmUser":{"name":"danidoble","email":"ddanidoble@gmail.com"},"directories":{},"maintainers":[{"name":"danidoble","email":"ddanidoble@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/webserial-hopper_1.0.0_1776995352746_0.5843658849693469"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-24T01:49:12.684Z","1.0.0":"2026-04-24T01:49:12.890Z","modified":"2026-04-24T01:49:13.045Z"},"maintainers":[{"name":"danidoble","email":"ddanidoble@gmail.com"}],"description":"A strongly-typed, event-driven USB hopper driver for the Web Serial API, built on top of webserial-core.","homepage":"https://github.com/danidoble/webserial-hopper#readme","repository":{"type":"git","url":"git+https://github.com/danidoble/webserial-hopper.git"},"author":{"name":"Danidoble","email":"ddanidoble@gmail.com"},"bugs":{"url":"https://github.com/danidoble/webserial-hopper/issues"},"license":"GPL-3.0-only","readme":"# @danidoble/webserial-hopper\n\nA strongly-typed, event-driven coin hopper driver built on top of [`webserial-core`](https://github.com/danidoble/webserial-core).\n\nSupports up to **4 independent coin hoppers**, a **coin validator**, balance tracking, and change dispensing — all through a clean event API. The binary serial protocol, handshake, frame parsing, auto-reconnect, and multi-frame splitting are handled automatically.\n\nNot tied to a single transport: swap in the **WebUSB**, **Web Bluetooth**, or **WebSocket** provider from `webserial-core`, or implement your own `SerialProvider` for any platform.\n\n[![npm version](https://img.shields.io/npm/v/@danidoble/webserial-hopper)](https://www.npmjs.com/package/@danidoble/webserial-hopper)\n[![license](https://img.shields.io/npm/l/@danidoble/webserial-hopper)](./LICENSE.md)\n\n---\n\n## Requirements\n\n- [`webserial-core`](https://www.npmjs.com/package/webserial-core) `^2.1.0` (peer dependency)\n- A compatible transport (see [Providers](#providers)):\n  - **Web Serial API** — Chrome / Edge 89+ (default, no extra setup)\n  - **WebUSB** — Chrome / Edge (via `WebUsbProvider`)\n  - **Web Bluetooth** — Chrome / Edge (via `createBluetoothProvider`, Nordic UART Service)\n  - **WebSocket** — any environment (via `createWebSocketProvider` + a bridge server)\n  - **Custom** — any platform via your own `SerialProvider` implementation\n\n---\n\n## Installation\n\n```bash\n# npm\nnpm install @danidoble/webserial-hopper webserial-core\n\n# pnpm\npnpm add @danidoble/webserial-hopper webserial-core\n\n# yarn\nyarn add @danidoble/webserial-hopper webserial-core\n\n# bun\nbun add @danidoble/webserial-hopper webserial-core\n```\n\n> `webserial-core` is a **peer dependency** — it must be installed alongside this package.\n\n---\n\n## Quick start\n\n```ts\nimport { Hopper } from '@danidoble/webserial-hopper';\n\nconst hopper = new Hopper({ filters: [{ usbVendorId: 0x2341 }] });\n\n// ── Configure hoppers (optional — these are the defaults) ──────────────\nhopper\n  .setHopperName({ hopper: 1, name: '10 Pesos' })\n  .setHopperCurrency({ hopper: 1, currency: 10 })\n  .setMaxCapacity({ hopper: 1, capacity: 1000 });\n\n// ── Listen for events ──────────────────────────────────────────────────\nhopper.on('serial:connecting',      () => console.log('Opening port…'));\nhopper.on('serial:connected',       () => console.log('Port open, running handshake…'));\nhopper.on('serial:disconnected',    () => console.log('Disconnected'));\n\nhopper.on('hopper:levels',          (levels) => console.log('All levels:', levels));\nhopper.on('hopper:updated',         (level)  => console.log(`Hopper ${level.id} → ${level.amount}`));\nhopper.on('hopper:coin:inserted',   ({ coinValue }) => console.log('Coin inserted, value:', coinValue));\nhopper.on('hopper:balance:updated', ({ balance })   => console.log('Balance:', balance));\nhopper.on('hopper:dispense-change', ({ amount })    => console.log('Change dispensed:', amount));\nhopper.on('hopper:message',         (msg)  => console.log(`[${msg.no_code}] ${msg.name}`));\n\n// ── Open the port (requires a user gesture) ────────────────────────────\nawait hopper.connect();\n\n// ── Read all hopper levels ─────────────────────────────────────────────\nawait hopper.sendRequestStatus();\n\n// ── Read / write a single hopper ──────────────────────────────────────\nawait hopper.sendReadHopper({ hopper: 1 });\nawait hopper.sendWriteHopper({ hopper: 1, quantity: 500 });\n\n// ── Dispense from a specific hopper ───────────────────────────────────\nawait hopper.sendDispenseHopper({ hopper: 1 });\n\n// ── Dispense exact change (sum across hoppers) ─────────────────────────\nawait hopper.sendDispenseChange({ change: 15 }); // dispenses 15 units\n\n// ── Balance management ─────────────────────────────────────────────────\nawait hopper.sendReadBalance();\nawait hopper.sendClearBalance();\n\n// ── Validator (coin acceptor) ──────────────────────────────────────────\nawait hopper.sendEnableValidator();\nawait hopper.sendDisableValidator();\n```\n\n---\n\n## Serial settings\n\nThe constructor pre-configures the following defaults — no extra setup needed:\n\n| Setting            | Value                    |\n| ------------------ | ------------------------ |\n| Baud rate          | 9 600                    |\n| Data bits          | 8                        |\n| Stop bits          | 1                        |\n| Parity             | none                     |\n| Flow control       | none                     |\n| Buffer size        | 255 B                    |\n| Parser             | interByteTimeout (40 ms) |\n| Command timeout    | 3 000 ms                 |\n| Auto-reconnect     | ✓                        |\n| Reconnect interval | 1 500 ms                 |\n| Handshake timeout  | 2 000 ms                 |\n\n---\n\n## Providers\n\nBy default the library uses the browser's native **Web Serial API** (`navigator.serial`). You can replace this with any of the built-in providers from `webserial-core`, or write your own.\n\n### Web Serial API (default)\n\nNo setup required — works out of the box in Chrome / Edge 89+.\n\n```ts\nimport { Hopper } from '@danidoble/webserial-hopper';\n\nconst hopper = new Hopper({ filters: [{ usbVendorId: 0x2341 }] });\nawait hopper.connect();\n```\n\n### WebUSB (`WebUsbProvider`)\n\nUse the **WebUSB API** as the transport. Useful for devices or platforms where the native Web Serial API is unavailable, or when targeting CP210x / vendor-specific USB chips.\n\n```ts\nimport { Hopper, WebUsbProvider } from '@danidoble/webserial-hopper';\n\nconst hopper = new Hopper({\n  filters: [{ usbVendorId: 0x2341 }],\n  provider: new WebUsbProvider()\n});\n\nawait hopper.connect();\n```\n\n### Web Bluetooth (`createBluetoothProvider`)\n\nCommunicate over **Bluetooth Low Energy** using the Nordic UART Service (NUS). The device must expose NUS characteristics.\n\n```ts\nimport { Hopper, createBluetoothProvider } from '@danidoble/webserial-hopper';\n\nconst hopper = new Hopper({\n  provider: createBluetoothProvider()\n});\n\nawait hopper.connect(); // shows the browser Bluetooth picker\n```\n\n### WebSocket (`createWebSocketProvider`)\n\nRoute serial communication through a **WebSocket bridge server** — ideal for Node.js environments or remote devices. A reference bridge implementation is available in the [`webserial-core` demos](https://github.com/danidoble/webserial-core).\n\n```ts\nimport { Hopper, createWebSocketProvider } from '@danidoble/webserial-hopper';\n\nconst hopper = new Hopper({\n  filters: [{ usbVendorId: 0x2341 }],\n  provider: createWebSocketProvider('ws://localhost:8080')\n});\n\nawait hopper.connect();\n```\n\n### Global provider (`AbstractSerialDevice.setProvider`)\n\nSet a provider once for **all** device instances instead of per-instance. Import `AbstractSerialDevice` directly from `webserial-core`:\n\n```ts\nimport { AbstractSerialDevice, WebUsbProvider } from 'webserial-core';\nimport { Hopper } from '@danidoble/webserial-hopper';\n\nAbstractSerialDevice.setProvider(new WebUsbProvider());\n\nconst hopper = new Hopper({ filters: [{ usbVendorId: 0x2341 }] });\nawait hopper.connect();\n```\n\n### Custom provider\n\nImplement the `SerialProvider` interface to target any platform:\n\n```ts\nimport type { SerialProvider, SerialPortFilter } from '@danidoble/webserial-hopper';\nimport { Hopper } from '@danidoble/webserial-hopper';\n\nconst myProvider: SerialProvider = {\n  async requestPort(options?: { filters?: SerialPortFilter[] }): Promise<SerialPort> {\n    // return a SerialPort-compatible object\n  },\n  async getPorts(): Promise<SerialPort[]> {\n    // return previously authorised ports\n  }\n};\n\nconst hopper = new Hopper({\n  filters: [{ usbVendorId: 0x2341 }],\n  provider: myProvider\n});\n```\n\n---\n\n## API\n\n### `new Hopper(options?)`\n\n| Option            | Type                  | Default | Description                                                        |\n| ----------------- | --------------------- | ------- | ------------------------------------------------------------------ |\n| `filters`         | `SerialPortFilter[]`  | `[]`    | USB vendor/product filters for port matching.                      |\n| `provider`        | `SerialProvider`      | —       | Per-instance provider. Overrides the global static provider.       |\n| `polyfillOptions` | `SerialDeviceOptions` | —       | Extra options forwarded to the provider (e.g. baud rate override). |\n\n### `hopper.connect()`\n\nOpens the serial port and runs the binary handshake. Shows a browser port-picker dialog on first connection; subsequent calls reuse the last authorised port.\n\n```ts\nawait hopper.connect();\n```\n\n### `hopper.disconnect()`\n\nGracefully closes the port and stops auto-reconnect.\n\n```ts\nawait hopper.disconnect();\n```\n\n### `hopper.isConnected()`\n\nReturns `true` when the port is open and the handshake has completed.\n\n---\n\n### Commands\n\n#### `hopper.sendConnect()`\n\nSends the connection handshake frame manually. Useful if you need to re-trigger the handshake.\n\n#### `hopper.sendRequestStatus()`\n\nRequests the live coin level of all 4 hoppers at once. Triggers a `hopper:levels` event.\n\n```ts\nawait hopper.sendRequestStatus();\n```\n\n#### `hopper.sendReadHopper(options?)`\n\nReads the level of a single hopper. Triggers `hopper:updated`.\n\n| Option   | Type           | Default | Description              |\n| -------- | -------------- | ------- | ------------------------ |\n| `hopper` | `HopperNumber` | `1`     | Hopper to read (1 – 4).  |\n\n```ts\nawait hopper.sendReadHopper({ hopper: 2 });\n```\n\n#### `hopper.sendWriteHopper(options?)`\n\nWrites (overwrites) the coin count of a single hopper. Triggers `hopper:updated`.\n\n| Option     | Type           | Default | Description                              |\n| ---------- | -------------- | ------- | ---------------------------------------- |\n| `hopper`   | `HopperNumber` | `1`     | Hopper to write (1 – 4).                 |\n| `quantity` | `number`       | `0`     | New coin count (−32 768 – 32 767, integer). |\n\n```ts\nawait hopper.sendWriteHopper({ hopper: 1, quantity: 500 });\n```\n\n#### `hopper.sendDispenseHopper(options?)`\n\nDispenses one coin from the specified hopper. Triggers `hopper:updated`.\n\n| Option   | Type           | Default | Description               |\n| -------- | -------------- | ------- | ------------------------- |\n| `hopper` | `HopperNumber` | `1`     | Hopper to dispense from.  |\n\n```ts\nawait hopper.sendDispenseHopper({ hopper: 3 });\n```\n\n#### `hopper.sendDispenseChange(options?)`\n\nDispenses the exact change amount using the available hoppers. Triggers `hopper:dispense-change`.\n\n| Option   | Type     | Default | Description                          |\n| -------- | -------- | ------- | ------------------------------------ |\n| `change` | `number` | `0`     | Amount to dispense (0 – 32 767, integer). |\n\n```ts\nawait hopper.sendDispenseChange({ change: 15 });\n```\n\n#### `hopper.sendReadBalance()`\n\nReads the accumulated balance (total inserted value). Triggers `hopper:balance:updated`.\n\n```ts\nawait hopper.sendReadBalance();\n```\n\n#### `hopper.sendClearBalance()`\n\nClears the accumulated balance. Triggers `hopper:balance:updated`.\n\n```ts\nawait hopper.sendClearBalance();\n```\n\n#### `hopper.sendEnableValidator()` / `hopper.sendDisableValidator()`\n\nEnables or disables the coin validator (acceptor). Shorthand for `sendConfigValidator`.\n\n```ts\nawait hopper.sendEnableValidator();\nawait hopper.sendDisableValidator();\n```\n\n#### `hopper.sendConfigValidator(options?)`\n\nLow-level validator toggle.\n\n| Option   | Type      | Default | Description                   |\n| -------- | --------- | ------- | ----------------------------- |\n| `enable` | `boolean` | `false` | `true` to enable the validator. |\n\n```ts\nawait hopper.sendConfigValidator({ enable: true });\n```\n\n#### `hopper.sendChange1x1(options?)`\n\nSends a 1-for-1 change command (platform-specific).\n\n| Option   | Type           | Default | Description       |\n| -------- | -------------- | ------- | ----------------- |\n| `hopper` | `HopperNumber` | `1`     | Target hopper.    |\n\n#### `hopper.sendCustomCode(options?)`\n\nSends a raw byte array as a command frame. Use for vendor-specific extensions.\n\n| Option | Type       | Default | Description                           |\n| ------ | ---------- | ------- | ------------------------------------- |\n| `code` | `number[]` | `[]`    | Bytes to send (each 0 – 255, max 12). |\n\n```ts\nawait hopper.sendCustomCode({ code: [0x0a, 0xff, 0x01] });\n```\n\n---\n\n### Configuration (chainable)\n\nThese methods update the in-memory hopper metadata and return `this` for chaining. They do **not** send any serial command.\n\n#### `hopper.setMaxCapacity(options?)`\n\n| Option     | Type           | Default  | Description                          |\n| ---------- | -------------- | -------- | ------------------------------------ |\n| `hopper`   | `HopperNumber` | `1`      | Hopper to configure (1 – 4).         |\n| `capacity` | `number`       | `1000`   | Maximum coin capacity.               |\n\n#### `hopper.setHopperName(options?)`\n\n| Option   | Type           | Default | Description                  |\n| -------- | -------------- | ------- | ---------------------------- |\n| `hopper` | `HopperNumber` | `1`     | Hopper to configure (1 – 4). |\n| `name`   | `string`       | `''`    | Human-readable label.        |\n\n#### `hopper.setHopperKey(options?)`\n\n| Option   | Type           | Default | Description                                |\n| -------- | -------------- | ------- | ------------------------------------------ |\n| `hopper` | `HopperNumber` | `1`     | Hopper to configure (1 – 4).               |\n| `key`    | `string`       | `''`    | Machine-readable identifier (e.g. `\"ten_pesos\"`). |\n\n#### `hopper.setHopperCurrency(options?)`\n\n| Option     | Type           | Default | Description                            |\n| ---------- | -------------- | ------- | -------------------------------------- |\n| `hopper`   | `HopperNumber` | `1`     | Hopper to configure (1 – 4).           |\n| `currency` | `number`       | `1`     | Coin denomination (positive number).   |\n\n```ts\n// Chainable example\nhopper\n  .setHopperName({ hopper: 1, name: '10 Pesos' })\n  .setHopperCurrency({ hopper: 1, currency: 10 })\n  .setMaxCapacity({ hopper: 1, capacity: 800 });\n```\n\n---\n\n### Getters\n\n| Getter                   | Type                    | Description                                          |\n| ------------------------ | ----------------------- | ---------------------------------------------------- |\n| `hopper.balance`         | `number`                | Last known accumulated balance from the validator.   |\n| `hopper.currentHopper`   | `HopperNumber \\| null`  | The hopper targeted by the most recent command.      |\n| `hopper.levels`          | `HopperLevel[]`         | Array of 4 `HopperLevel` objects (one per hopper).   |\n\n`HopperLevel` shape:\n\n```ts\ninterface HopperLevel {\n  id: number;       // 1 – 4\n  currency: number; // denomination value (e.g. 10)\n  key: string;      // machine key (e.g. \"Hopper 1\")\n  name: string;     // display label (e.g. \"10 Pesos\")\n  amount: number;   // current coin count\n  capacity: number; // maximum capacity\n}\n```\n\n---\n\n## Events\n\n### Core events (from `webserial-core`)\n\n| Event                    | Payload                           | Description                                       |\n| ------------------------ | --------------------------------- | ------------------------------------------------- |\n| `serial:connecting`      | `instance`                        | Port is being opened.                             |\n| `serial:connected`       | `instance`                        | Port opened successfully.                         |\n| `serial:disconnected`    | `instance`                        | Port closed or device unplugged.                  |\n| `serial:reconnecting`    | `instance`                        | Auto-reconnect attempt in progress.               |\n| `serial:data`            | `data: Uint8Array`, `instance`    | Raw binary frame received from the device.        |\n| `serial:sent`            | `data: Uint8Array`, `instance`    | Raw bytes written to the port.                    |\n| `serial:error`           | `error: Error`, `instance`        | An error occurred during communication.           |\n| `serial:need-permission` | `instance`                        | No authorised port found; user must grant access. |\n| `serial:timeout`         | `command: Uint8Array`, `instance` | A queued command timed out.                       |\n\n### Hopper events\n\n| Event                      | Payload                      | Description                                             |\n| -------------------------- | ---------------------------- | ------------------------------------------------------- |\n| `hopper:test`              | `Uint8Array`                 | Handshake / test frame received.                        |\n| `hopper:levels`            | `HopperLevel[]`              | All 4 hopper levels updated (from `sendRequestStatus`). |\n| `hopper:updated`           | `HopperLevel`                | Single hopper level updated (read / write / dispense).  |\n| `hopper:dispense-change`   | `{ amount: number }`         | Change dispensed; `amount` reflects what was paid out.  |\n| `hopper:balance:updated`   | `{ balance: number }`        | Accumulated balance changed (read or cleared).          |\n| `hopper:coin:inserted`     | `{ coinValue: number }`      | Coin(s) inserted by the customer (debounced 500 ms; `coinValue` is the pulse count). |\n| `hopper:validator:message` | `HopperMessage`              | Message from the coin validator module.                 |\n| `hopper:unknown`           | `HopperMessage`              | Unrecognised but valid frame received.                  |\n| `hopper:message`           | `HopperMessage`              | Emitted for **every** device response.                  |\n\n### `HopperMessage`\n\n```ts\ninterface HopperMessage {\n  code: Uint8Array;         // raw frame bytes\n  name: string | null;      // protocol name (e.g. \"STATUS\")\n  description: string | null;\n  request: string | null;\n  no_code: number;          // see table below\n  error: boolean;\n  data: unknown;\n  hopper?: HopperNumber | null;\n}\n```\n\n#### `no_code` reference\n\n| `no_code` | Name               | Trigger                                           |\n| --------- | ------------------ | ------------------------------------------------- |\n| `0`       | `TEST`             | Handshake / test response.                        |\n| `1`       | `STATUS`           | All hopper levels (`sendRequestStatus`).          |\n| `2`       | `READ_HOPPER`      | Single hopper read (`sendReadHopper`).            |\n| `3`       | `WRITE_HOPPER`     | Single hopper write (`sendWriteHopper`).          |\n| `4`       | `DISPENSE_HOPPER`  | Dispense from hopper (`sendDispenseHopper`).      |\n| `5`       | `DISPENSE_CHANGE`  | Change dispensed (`sendDispenseChange`).          |\n| `6`       | `READ_BALANCE`     | Balance read (`sendReadBalance`).                 |\n| `7`       | `CLEAR_BALANCE`    | Balance cleared (`sendClearBalance`).             |\n| `8`       | `VALIDATOR_MESSAGE`| Message from coin validator.                     |\n| `9`       | `INSERTED_COIN`    | Coin inserted by customer.                        |\n| `400`     | `SYNTAX_ERROR`     | Device reported a syntax error (`0xFF 0xFF 0xFF`). |\n| `401`     | `LOW_LEVEL`        | Low coin level in hopper (`0xFF 0xAA 0xAA`).      |\n| `402`     | `TIMEOUT_DISPENSE` | Dispense timed out (`0xFF 0xBB 0xBB`).            |\n| `999`     | `UNKNOWN`          | Unrecognised frame.                               |\n\n---\n\n## TypeScript\n\nAll events and method signatures are fully typed. The package ships with `.d.mts` / `.d.cts` declaration files — no extra `@types` package required.\n\nCommonly used types and all built-in providers are re-exported so you do not need to import directly from `webserial-core`:\n\n```ts\nimport {\n  Hopper,\n  WebUsbProvider,\n  createBluetoothProvider,\n  createWebSocketProvider,\n} from '@danidoble/webserial-hopper';\n\nimport type {\n  HopperOptions,\n  HopperLevel,\n  HopperMessage,\n  HopperNumber,\n  MaxCapacityOptions,\n  HopperNameOptions,\n  HopperKeyOptions,\n  HopperCurrencyOptions,\n  ReadHopperOptions,\n  WriteHopperOptions,\n  DispenseHopperOptions,\n  DispenseChangeOptions,\n  ConfigValidatorOptions,\n  Change1x1Options,\n  CustomCodeOptions,\n  SerialPortFilter,\n  SerialDeviceOptions,\n  SerialEventMap,\n  SerialProvider,\n  SerialPolyfillOptions,\n} from '@danidoble/webserial-hopper';\n```\n\n---\n\n## License\n\n[GPL-3.0-only](./LICENSE.md) © [Danidoble](https://github.com/danidoble)\n","readmeFilename":"README.md","_rev":"1-e7d91a516230b98f17a010767c195b91"}