webserial-core 1.2.0 → 2.0.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{LICENSE → LICENSE.md} +1 -1
- package/README.md +142 -287
- package/dist/adapters/web-bluetooth/WebBluetoothProvider.d.ts +19 -0
- package/dist/adapters/web-bluetooth/index.d.ts +6 -0
- package/dist/adapters/web-usb/WebUsbProvider.d.ts +127 -0
- package/dist/adapters/web-usb/index.d.ts +6 -0
- package/dist/adapters/websocket/WebSocketProvider.d.ts +20 -0
- package/dist/adapters/websocket/index.d.ts +6 -0
- package/dist/core/AbstractSerialDevice.d.ts +108 -0
- package/dist/core/SerialEventEmitter.d.ts +37 -0
- package/dist/core/SerialRegistry.d.ts +53 -0
- package/dist/errors/index.d.ts +40 -0
- package/dist/index.d.ts +10 -0
- package/dist/parsers/DelimiterParser.d.ts +22 -0
- package/dist/parsers/FixedLengthParser.d.ts +23 -0
- package/dist/parsers/RawParser.d.ts +22 -0
- package/dist/parsers/index.d.ts +7 -0
- package/dist/queue/CommandQueue.d.ts +98 -0
- package/dist/types/index.d.ts +124 -0
- package/dist/webserial-core.cjs +1 -0
- package/dist/webserial-core.mjs +853 -0
- package/dist/webserial-core.umd.js +1 -0
- package/package.json +62 -68
- package/dist/types/Core.d.ts +0 -268
- package/dist/types/Core.d.ts.map +0 -1
- package/dist/types/Devices.d.ts +0 -62
- package/dist/types/Devices.d.ts.map +0 -1
- package/dist/types/Dispatcher.d.ts +0 -98
- package/dist/types/Dispatcher.d.ts.map +0 -1
- package/dist/types/SerialError.d.ts +0 -61
- package/dist/types/SerialError.d.ts.map +0 -1
- package/dist/types/SerialEvent.d.ts +0 -4
- package/dist/types/SerialEvent.d.ts.map +0 -1
- package/dist/types/Socket.d.ts +0 -29
- package/dist/types/Socket.d.ts.map +0 -1
- package/dist/types/main.d.ts +0 -15
- package/dist/types/main.d.ts.map +0 -1
- package/dist/types/utils.d.ts +0 -3
- package/dist/types/utils.d.ts.map +0 -1
- package/dist/webserial-core.js +0 -1236
- package/dist/webserial-core.js.map +0 -1
- package/dist/webserial-core.umd.cjs +0 -5
- package/dist/webserial-core.umd.cjs.map +0 -1
package/{LICENSE → LICENSE.md}
RENAMED
package/README.md
CHANGED
|
@@ -1,30 +1,43 @@
|
|
|
1
|
-
#
|
|
1
|
+
# webserial-core
|
|
2
2
|
|
|
3
|
-
An easy way to connect to a serial port from a web page.
|
|
4
|
-
|
|
5
|
-
[](https://deepwiki.com/danidoble/webserial-core)
|
|
6
3
|
[](https://www.npmjs.com/package/webserial-core)
|
|
4
|
+
[](https://www.npmjs.com/package/webserial-core)
|
|
7
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+
[](https://deepwiki.com/danidoble/webserial-core)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
A strongly-typed, event-driven, abstract TypeScript library for serial
|
|
13
|
+
communication on the web. Supports **Web Serial**, **WebUSB**, **Web
|
|
14
|
+
Bluetooth**, and **WebSocket** transports through a unified API.
|
|
8
15
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
>
|
|
12
|
-
>
|
|
13
|
-
>
|
|
14
|
-
>
|
|
15
|
-
>
|
|
16
|
-
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
> **⚠️ Breaking Changes — v2**
|
|
19
|
+
>
|
|
20
|
+
> Version 2 is a complete rewrite. Tthe public API is completally changed,
|
|
21
|
+
> please if you has an implementation of this library is better read docs as like a
|
|
22
|
+
> new integration See the [Migration Guide](docs/guide/migration-v1-v2.md) before upgrading.
|
|
23
|
+
|
|
24
|
+
---
|
|
17
25
|
|
|
18
26
|
## Features
|
|
19
27
|
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
+
- **Provider-agnostic** — swap between Web Serial, WebUSB, Web Bluetooth, or
|
|
29
|
+
WebSocket transport by injecting a single provider.
|
|
30
|
+
- **Strictly typed** — full TypeScript generics, no implicit `any`, compatible
|
|
31
|
+
with `strict: true`.
|
|
32
|
+
- **Typed events** — `connecting`, `connected`, `disconnected`, `data`,
|
|
33
|
+
`sent`, `error`, `timeout`, `reconnecting`, and more — all fully typed.
|
|
34
|
+
- **Built-in parsers** — `delimiter`, `fixedLength`, `raw`. Implement
|
|
35
|
+
`SerialParser<T>` for any custom binary or text protocol.
|
|
36
|
+
- **Command queue** — FIFO write queue with optional per-command timeouts.
|
|
37
|
+
- **Auto-reconnect** — configurable reconnect loop with back-off.
|
|
38
|
+
- **WebUSB polyfill** — full WebUSB serial polyfill (CDC ACM, CP210x, CH340).
|
|
39
|
+
- **BLE NUS adapter** — Nordic UART Service over Web Bluetooth GATT.
|
|
40
|
+
- **WebSocket bridge** — relay serial I/O through a Node.js bridge server.
|
|
28
41
|
|
|
29
42
|
## Installation
|
|
30
43
|
|
|
@@ -32,301 +45,143 @@ An easy way to connect to a serial port from a web page.
|
|
|
32
45
|
npm install webserial-core
|
|
33
46
|
```
|
|
34
47
|
|
|
35
|
-
##
|
|
48
|
+
## Quick start
|
|
36
49
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
> ```bash
|
|
40
|
-
> sudo usermod -a -G dialout $USER
|
|
41
|
-
> ```
|
|
42
|
-
> After that, you need to log out and log in again to apply the changes.
|
|
50
|
+
```ts
|
|
51
|
+
import { AbstractSerialDevice, delimiter } from "webserial-core";
|
|
43
52
|
|
|
44
|
-
|
|
45
|
-
|
|
53
|
+
class MyDevice extends AbstractSerialDevice<string> {
|
|
54
|
+
constructor() {
|
|
55
|
+
super({
|
|
56
|
+
baudRate: 9600,
|
|
57
|
+
parser: delimiter("\n"),
|
|
58
|
+
autoReconnect: true,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
46
61
|
|
|
47
|
-
|
|
62
|
+
protected async handshake(): Promise<boolean> {
|
|
63
|
+
return true; // return false to reject the port
|
|
64
|
+
}
|
|
65
|
+
}
|
|
48
66
|
|
|
49
|
-
|
|
50
|
-
// serial.ino
|
|
67
|
+
const device = new MyDevice();
|
|
51
68
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
69
|
+
device.on("serial:connected", () => console.log("Connected!"));
|
|
70
|
+
device.on("serial:data", (line) => console.log("←", line));
|
|
71
|
+
device.on("serial:disconnected", () => console.log("Disconnected."));
|
|
72
|
+
device.on("serial:error", (err) => console.error(err.message));
|
|
55
73
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if(comando.startsWith("CONNECT")){
|
|
61
|
-
Serial.println("connected");
|
|
62
|
-
} else if (comando.startsWith("CREDITS")) {
|
|
63
|
-
Serial.println("created by danidoble");
|
|
64
|
-
} else if (comando.startsWith("HI")) {
|
|
65
|
-
Serial.println("hello there");
|
|
66
|
-
} else {
|
|
67
|
-
Serial.println("ara ara, what are you doing?");
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
74
|
+
await device.connect(); // opens the browser port picker
|
|
75
|
+
await device.send("PING\n"); // enqueues a write
|
|
76
|
+
await device.disconnect();
|
|
71
77
|
```
|
|
72
78
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
```javascript
|
|
76
|
-
// arduino.js
|
|
77
|
-
import { Core } from 'webserial-core';
|
|
78
|
-
|
|
79
|
-
export class Arduino extends Core {
|
|
80
|
-
constructor(
|
|
81
|
-
{
|
|
82
|
-
filters = null,
|
|
83
|
-
config_port = {
|
|
84
|
-
baudRate: 9600,
|
|
85
|
-
dataBits: 8,
|
|
86
|
-
stopBits: 1,
|
|
87
|
-
parity: "none",
|
|
88
|
-
bufferSize: 32768,
|
|
89
|
-
flowControl: "none",
|
|
90
|
-
},
|
|
91
|
-
no_device = 1,
|
|
92
|
-
} = {
|
|
93
|
-
filters: null,
|
|
94
|
-
config_port: {
|
|
95
|
-
baudRate: 9600,
|
|
96
|
-
dataBits: 8,
|
|
97
|
-
stopBits: 1,
|
|
98
|
-
parity: "none",
|
|
99
|
-
bufferSize: 32768,
|
|
100
|
-
flowControl: "none",
|
|
101
|
-
},
|
|
102
|
-
no_device: 1,
|
|
103
|
-
}
|
|
104
|
-
) {
|
|
105
|
-
super({ filters, config_port, no_device });
|
|
106
|
-
this.__internal__.device.type = "arduino";
|
|
107
|
-
Devices.registerType(this.__internal__.device.type);
|
|
108
|
-
if (Devices.getByNumber(this.typeDevice, no_device)) {
|
|
109
|
-
throw new Error(`Device ${this.typeDevice} ${no_device} already exists`);
|
|
110
|
-
}
|
|
111
|
-
this.__internal__.time.response_connection = 2e3;
|
|
112
|
-
this.__internal__.time.response_general = 2e3;
|
|
113
|
-
this.__internal__.serial.delay_first_connection = 1_000;
|
|
114
|
-
this.#registerAvailableListenersArduino();
|
|
115
|
-
Devices.add(this);
|
|
116
|
-
this.getResponseAsString();
|
|
117
|
-
}
|
|
79
|
+
## Transport adapters
|
|
118
80
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
'my_own_event_dispatched',
|
|
122
|
-
'my_other_own_event_dispatched',
|
|
123
|
-
];
|
|
124
|
-
for (const event of _) {
|
|
125
|
-
this.serialRegisterAvailableListener(event)
|
|
126
|
-
}
|
|
127
|
-
*/
|
|
128
|
-
}
|
|
81
|
+
All four adapters expose the same `SerialProvider` interface. Inject your
|
|
82
|
+
chosen adapter once before constructing any device:
|
|
129
83
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
description: "",
|
|
135
|
-
request: "",
|
|
136
|
-
no_code: 0,
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
message.code = codex;
|
|
140
|
-
|
|
141
|
-
switch (codex) {
|
|
142
|
-
case "connected":
|
|
143
|
-
message.name = "connected";
|
|
144
|
-
message.description = "Connection established";
|
|
145
|
-
message.request = "connect";
|
|
146
|
-
message.no_code = 100;
|
|
147
|
-
break;
|
|
148
|
-
case "created by danidoble":
|
|
149
|
-
message.name = "thanks";
|
|
150
|
-
message.description = "thanks for using this software";
|
|
151
|
-
message.request = "credits";
|
|
152
|
-
message.no_code = 101;
|
|
153
|
-
break;
|
|
154
|
-
case "hello there":
|
|
155
|
-
message.name = "hello there";
|
|
156
|
-
message.description = "hi human";
|
|
157
|
-
message.request = "hi";
|
|
158
|
-
message.no_code = 102;
|
|
159
|
-
break;
|
|
160
|
-
case "ara ara":
|
|
161
|
-
message.name = "ara ara";
|
|
162
|
-
message.description = "troll";
|
|
163
|
-
message.request = "ara ara";
|
|
164
|
-
message.no_code = 404;
|
|
165
|
-
break;
|
|
166
|
-
default:
|
|
167
|
-
message.name = "unknown";
|
|
168
|
-
message.description = "Unknown command";
|
|
169
|
-
message.request = "unknown";
|
|
170
|
-
message.no_code = 400;
|
|
171
|
-
break;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
this.dispatch("serial:message", message);
|
|
175
|
-
}
|
|
84
|
+
```ts
|
|
85
|
+
import { AbstractSerialDevice, WebUsbProvider } from "webserial-core";
|
|
86
|
+
import { createBluetoothProvider } from "webserial-core";
|
|
87
|
+
import { createWebSocketProvider } from "webserial-core";
|
|
176
88
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
89
|
+
// WebUSB polyfill (Android Chrome, or desktop for testing)
|
|
90
|
+
AbstractSerialDevice.setProvider(new WebUsbProvider());
|
|
180
91
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
await this.appendToQueue(arr, "credits");
|
|
184
|
-
}
|
|
92
|
+
// Web Bluetooth (Nordic UART Service over BLE GATT)
|
|
93
|
+
AbstractSerialDevice.setProvider(createBluetoothProvider());
|
|
185
94
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
95
|
+
// WebSocket bridge (requires Node.js server — see demos/websocket/)
|
|
96
|
+
AbstractSerialDevice.setProvider(
|
|
97
|
+
createWebSocketProvider("ws://localhost:8080"),
|
|
98
|
+
);
|
|
99
|
+
```
|
|
190
100
|
|
|
191
|
-
|
|
192
|
-
const arr = this.parseStringToBytes("OTHER");
|
|
193
|
-
await this.appendToQueue(arr, "ara");
|
|
194
|
-
}
|
|
101
|
+
## Parsers
|
|
195
102
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
103
|
+
```ts
|
|
104
|
+
import { delimiter, fixedLength, raw } from "webserial-core";
|
|
105
|
+
|
|
106
|
+
// Newline-delimited strings (Arduino Serial.println)
|
|
107
|
+
parser: delimiter("\n");
|
|
108
|
+
|
|
109
|
+
// 16-byte binary packets
|
|
110
|
+
parser: fixedLength(16);
|
|
111
|
+
|
|
112
|
+
// Raw Uint8Array chunks
|
|
113
|
+
parser: raw();
|
|
202
114
|
```
|
|
203
115
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
```javascript
|
|
207
|
-
// serialConnection.js
|
|
208
|
-
|
|
209
|
-
import { Arduino } from './arduino.js';
|
|
210
|
-
|
|
211
|
-
const arduino = new Arduino();
|
|
212
|
-
|
|
213
|
-
arduino.on('serial:message', (message) => {
|
|
214
|
-
console.log(message);
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
arduino.on('serial:timeout', (data) => {
|
|
218
|
-
console.log('serial:timeout', data.detail);
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
// if you need to debug the data sent
|
|
222
|
-
// arduino.on('serial:sent', data => {
|
|
223
|
-
// console.log('serial:sent',data.detail);
|
|
224
|
-
// });
|
|
225
|
-
|
|
226
|
-
arduino.on('serial:error', (event) => {
|
|
227
|
-
document.getElementById('log').innerText += event.detail.message + '\n\n';
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
// eslint-disable-next-line no-unused-vars
|
|
231
|
-
arduino.on('serial:disconnected', (event) => {
|
|
232
|
-
document.getElementById('log').innerText += 'Disconnected\n\n';
|
|
233
|
-
|
|
234
|
-
document.getElementById('disconnected').classList.remove('hidden');
|
|
235
|
-
document.getElementById('connect').classList.remove('hidden');
|
|
236
|
-
document.getElementById("disconnect")?.classList.add("hidden");
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
// eslint-disable-next-line no-unused-vars
|
|
240
|
-
arduino.on('serial:connecting', (event) => {
|
|
241
|
-
document.getElementById('log').innerText += 'Connecting\n\n';
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
// eslint-disable-next-line no-unused-vars
|
|
245
|
-
arduino.on('serial:connected', (event) => {
|
|
246
|
-
document.getElementById('log').innerText += 'Connected\n\n';
|
|
247
|
-
|
|
248
|
-
document.getElementById('disconnected').classList.add('hidden');
|
|
249
|
-
document.getElementById('need-permission').classList.add('hidden');
|
|
250
|
-
document.getElementById('connect').classList.add('hidden');
|
|
251
|
-
document.getElementById("disconnect")?.classList.remove("hidden");
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
// eslint-disable-next-line no-unused-vars
|
|
255
|
-
arduino.on('serial:need-permission', (event) => {
|
|
256
|
-
document.getElementById('disconnected').classList.remove('hidden');
|
|
257
|
-
document.getElementById('need-permission').classList.remove('hidden');
|
|
258
|
-
document.getElementById('connect').classList.remove('hidden');
|
|
259
|
-
document.getElementById("disconnect")?.classList.add("hidden");
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
// eslint-disable-next-line no-unused-vars
|
|
263
|
-
arduino.on('serial:soft-reload', (event) => {
|
|
264
|
-
// reset your variables
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
// eslint-disable-next-line no-unused-vars
|
|
268
|
-
arduino.on('serial:unsupported', (event) => {
|
|
269
|
-
document.getElementById('unsupported').classList.remove('hidden');
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
function tryConnect() {
|
|
273
|
-
arduino
|
|
274
|
-
.connect()
|
|
275
|
-
.then(() => {})
|
|
276
|
-
.catch(console.error);
|
|
277
|
-
}
|
|
116
|
+
## Events
|
|
278
117
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
118
|
+
| Event | Payload | Description |
|
|
119
|
+
| ------------------------ | ------------ | --------------------------------------------- |
|
|
120
|
+
| `serial:connecting` | — | `connect()` called, port picker about to open |
|
|
121
|
+
| `serial:connected` | — | Port open, handshake passed |
|
|
122
|
+
| `serial:disconnected` | — | Port closed |
|
|
123
|
+
| `serial:data` | `T` | Parser emitted a complete message |
|
|
124
|
+
| `serial:sent` | `Uint8Array` | Bytes written to the port |
|
|
125
|
+
| `serial:error` | `Error` | Unrecoverable error |
|
|
126
|
+
| `serial:need-permission` | — | User denied access |
|
|
127
|
+
| `serial:timeout` | `Uint8Array` | Command timed out |
|
|
128
|
+
| `serial:queue-empty` | — | Write queue is now idle |
|
|
129
|
+
| `serial:reconnecting` | — | Auto-reconnect attempt starting |
|
|
287
130
|
|
|
131
|
+
## Project structure
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
src/
|
|
135
|
+
core/ AbstractSerialDevice, SerialEventEmitter, SerialRegistry
|
|
136
|
+
adapters/
|
|
137
|
+
web-usb/ WebUsbProvider (WebUSB polyfill)
|
|
138
|
+
web-bluetooth/ createBluetoothProvider (BLE NUS)
|
|
139
|
+
websocket/ createWebSocketProvider (Node.js bridge)
|
|
140
|
+
parsers/ delimiter, fixedLength, raw
|
|
141
|
+
queue/ CommandQueue
|
|
142
|
+
errors/ SerialPortConflictError, SerialPermissionError, …
|
|
143
|
+
types/ SerialDeviceOptions, SerialProvider, SerialParser, …
|
|
144
|
+
demos/
|
|
145
|
+
web-serial/ Native Web Serial demo
|
|
146
|
+
web-usb/ WebUSB polyfill demo
|
|
147
|
+
web-bluetooth/ Web Bluetooth BLE demo
|
|
148
|
+
websocket/ WebSocket bridge demo + Node.js server
|
|
149
|
+
docs/ VitePress documentation site
|
|
288
150
|
```
|
|
289
151
|
|
|
290
|
-
|
|
152
|
+
## Building
|
|
291
153
|
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
|
|
154
|
+
```bash
|
|
155
|
+
npm run build
|
|
156
|
+
```
|
|
295
157
|
|
|
296
|
-
|
|
297
|
-
<meta charset="UTF-8">
|
|
298
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
299
|
-
<title>Webserial</title>
|
|
300
|
-
<script src="./serialConnection.js" type="module"></script>
|
|
301
|
-
</head>
|
|
158
|
+
Output in `dist/`:
|
|
302
159
|
|
|
303
|
-
|
|
160
|
+
| File | Format | Use case |
|
|
161
|
+
| ------------------------ | ---------- | ------------------------- |
|
|
162
|
+
| `webserial-core.mjs` | ESM | Bundlers, modern browsers |
|
|
163
|
+
| `webserial-core.cjs` | CJS | Node.js, legacy bundlers |
|
|
164
|
+
| `webserial-core.umd.cjs` | UMD | `<script>` tag, CDN |
|
|
165
|
+
| `index.d.ts` | TypeScript | Type declarations |
|
|
304
166
|
|
|
305
|
-
|
|
306
|
-
<div class="my-6"></div>
|
|
307
|
-
<button id="connect" class="hidden px-4 py-3 bg-gray-800 rounded-lg">Connect to serial</button>
|
|
308
|
-
<button id="disconnect" class="hidden px-4 py-3 bg-rose-800 rounded-lg">Disconnect device</button>
|
|
167
|
+
## Documentation
|
|
309
168
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
169
|
+
```bash
|
|
170
|
+
npm run docs:dev # live VitePress server
|
|
171
|
+
npm run docs:build # static build → docs/.vitepress/dist
|
|
172
|
+
```
|
|
314
173
|
|
|
315
|
-
|
|
316
|
-
The arduino is disconnected. Please, check the connection.
|
|
317
|
-
</div>
|
|
174
|
+
## Browser compatibility
|
|
318
175
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
176
|
+
| Feature | Browser requirement |
|
|
177
|
+
| ------------- | -------------------- |
|
|
178
|
+
| Web Serial | Chrome 89+, Edge 89+ |
|
|
179
|
+
| WebUSB | Chrome 61+, Edge 79+ |
|
|
180
|
+
| Web Bluetooth | Chrome 56+, Edge 79+ |
|
|
181
|
+
| WebSocket | All modern browsers |
|
|
322
182
|
|
|
323
|
-
|
|
324
|
-
Log: <br>
|
|
325
|
-
</div>
|
|
326
|
-
</div>
|
|
183
|
+
All browser APIs require a **secure context** (HTTPS or `localhost`).
|
|
327
184
|
|
|
328
|
-
|
|
329
|
-
</body>
|
|
185
|
+
## License
|
|
330
186
|
|
|
331
|
-
|
|
332
|
-
```
|
|
187
|
+
MIT © [danidoble](https://github.com/danidoble/webserial-core)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SerialProvider } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a {@link SerialProvider} that uses the Web Bluetooth API
|
|
4
|
+
* to communicate with Nordic UART Service (NUS) devices.
|
|
5
|
+
*
|
|
6
|
+
* Pass the returned provider to `AbstractSerialDevice.setProvider()` before
|
|
7
|
+
* calling `connect()`.
|
|
8
|
+
*
|
|
9
|
+
* @returns A `SerialProvider` backed by the Web Bluetooth API.
|
|
10
|
+
* @throws {Error} If `navigator.bluetooth` is not available in the current environment.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { createBluetoothProvider, AbstractSerialDevice } from 'webserial-core';
|
|
15
|
+
*
|
|
16
|
+
* AbstractSerialDevice.setProvider(createBluetoothProvider());
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function createBluetoothProvider(): SerialProvider;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { SerialPolyfillOptions, SerialPortFilter, SerialProvider } from '../../types/index.js';
|
|
2
|
+
interface USBDeviceFilter {
|
|
3
|
+
vendorId?: number;
|
|
4
|
+
productId?: number;
|
|
5
|
+
classCode?: number;
|
|
6
|
+
subclassCode?: number;
|
|
7
|
+
protocolCode?: number;
|
|
8
|
+
serialNumber?: string;
|
|
9
|
+
}
|
|
10
|
+
interface USBEndpoint {
|
|
11
|
+
readonly endpointNumber: number;
|
|
12
|
+
readonly direction: "in" | "out";
|
|
13
|
+
readonly type: "bulk" | "interrupt" | "isochronous";
|
|
14
|
+
readonly packetSize: number;
|
|
15
|
+
}
|
|
16
|
+
interface USBAlternateInterface {
|
|
17
|
+
readonly alternateSetting: number;
|
|
18
|
+
readonly interfaceClass: number;
|
|
19
|
+
readonly interfaceSubclass: number;
|
|
20
|
+
readonly interfaceProtocol: number;
|
|
21
|
+
readonly interfaceName: string | undefined;
|
|
22
|
+
readonly endpoints: readonly USBEndpoint[];
|
|
23
|
+
}
|
|
24
|
+
interface USBInterface {
|
|
25
|
+
readonly interfaceNumber: number;
|
|
26
|
+
readonly alternate: USBAlternateInterface;
|
|
27
|
+
readonly alternates: readonly USBAlternateInterface[];
|
|
28
|
+
readonly claimed: boolean;
|
|
29
|
+
}
|
|
30
|
+
interface USBConfiguration {
|
|
31
|
+
readonly configurationValue: number;
|
|
32
|
+
readonly configurationName: string | undefined;
|
|
33
|
+
readonly interfaces: readonly USBInterface[];
|
|
34
|
+
}
|
|
35
|
+
interface USBInTransferResult {
|
|
36
|
+
readonly data: DataView | undefined;
|
|
37
|
+
readonly status: "ok" | "stall" | "babble";
|
|
38
|
+
}
|
|
39
|
+
interface USBOutTransferResult {
|
|
40
|
+
readonly bytesWritten: number;
|
|
41
|
+
readonly status: "ok" | "stall";
|
|
42
|
+
}
|
|
43
|
+
interface USBControlTransferParameters {
|
|
44
|
+
requestType: "standard" | "class" | "vendor";
|
|
45
|
+
recipient: "device" | "interface" | "endpoint" | "other";
|
|
46
|
+
request: number;
|
|
47
|
+
value: number;
|
|
48
|
+
index: number;
|
|
49
|
+
}
|
|
50
|
+
interface USBDevice {
|
|
51
|
+
readonly vendorId: number;
|
|
52
|
+
readonly productId: number;
|
|
53
|
+
readonly configuration: USBConfiguration | null;
|
|
54
|
+
readonly configurations: readonly USBConfiguration[];
|
|
55
|
+
readonly opened: boolean;
|
|
56
|
+
open(): Promise<void>;
|
|
57
|
+
close(): Promise<void>;
|
|
58
|
+
forget(): Promise<void>;
|
|
59
|
+
selectConfiguration(configurationValue: number): Promise<void>;
|
|
60
|
+
claimInterface(interfaceNumber: number): Promise<void>;
|
|
61
|
+
releaseInterface(interfaceNumber: number): Promise<void>;
|
|
62
|
+
controlTransferOut(setup: USBControlTransferParameters, data?: BufferSource): Promise<USBOutTransferResult>;
|
|
63
|
+
transferIn(endpointNumber: number, length: number): Promise<USBInTransferResult>;
|
|
64
|
+
transferOut(endpointNumber: number, data: ArrayBuffer): Promise<USBOutTransferResult>;
|
|
65
|
+
}
|
|
66
|
+
interface USB {
|
|
67
|
+
requestDevice(options: {
|
|
68
|
+
filters: USBDeviceFilter[];
|
|
69
|
+
}): Promise<USBDevice>;
|
|
70
|
+
getDevices(): Promise<USBDevice[]>;
|
|
71
|
+
}
|
|
72
|
+
declare global {
|
|
73
|
+
interface Navigator {
|
|
74
|
+
readonly usb: USB;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* A {@link SerialProvider} implementation that uses the WebUSB API.
|
|
79
|
+
*
|
|
80
|
+
* Supported protocols (auto-detected unless overridden via `protocol`):
|
|
81
|
+
* - `cdc_acm` — Standard CDC ACM (auto-detected for interface class 2).
|
|
82
|
+
* - `cp210x` — Silicon Labs CP2102/CP2104 (auto-detected for vendorId `0x10c4`).
|
|
83
|
+
* - `none` — Raw bulk transfer, no initialization commands sent.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* import { WebUsbProvider, AbstractSerialDevice } from 'webserial-core';
|
|
88
|
+
*
|
|
89
|
+
* // Standard CDC ACM device (class 2, auto-detected)
|
|
90
|
+
* AbstractSerialDevice.setProvider(new WebUsbProvider());
|
|
91
|
+
*
|
|
92
|
+
* // Vendor-specific device with CP210x (e.g. ESP32 with CP2102)
|
|
93
|
+
* AbstractSerialDevice.setProvider(new WebUsbProvider({
|
|
94
|
+
* usbControlInterfaceClass: 255,
|
|
95
|
+
* usbTransferInterfaceClass: 255,
|
|
96
|
+
* }));
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export declare class WebUsbProvider implements SerialProvider {
|
|
100
|
+
private readonly options_;
|
|
101
|
+
/**
|
|
102
|
+
* @param options - Optional USB interface class and protocol settings.
|
|
103
|
+
* Defaults to CDC ACM (interface class 2).
|
|
104
|
+
*/
|
|
105
|
+
constructor(options?: SerialPolyfillOptions);
|
|
106
|
+
/**
|
|
107
|
+
* Prompts the user to select a USB device and returns a `SerialPort`-
|
|
108
|
+
* compatible wrapper for it.
|
|
109
|
+
*
|
|
110
|
+
* @param options - Optional filter list to narrow the USB device picker.
|
|
111
|
+
* @param polyfillOptions - Per-request override of polyfill settings.
|
|
112
|
+
* @returns A `SerialPort`-compatible object backed by the selected USB device.
|
|
113
|
+
* @throws {DOMException} If the user cancels the device picker.
|
|
114
|
+
*/
|
|
115
|
+
requestPort(options?: {
|
|
116
|
+
filters?: SerialPortFilter[];
|
|
117
|
+
}, polyfillOptions?: SerialPolyfillOptions): Promise<SerialPort>;
|
|
118
|
+
/**
|
|
119
|
+
* Returns `SerialPort`-compatible wrappers for all previously granted
|
|
120
|
+
* USB devices.
|
|
121
|
+
*
|
|
122
|
+
* @param polyfillOptions - Per-request override of polyfill settings.
|
|
123
|
+
* @returns An array of `SerialPort`-compatible objects.
|
|
124
|
+
*/
|
|
125
|
+
getPorts(polyfillOptions?: SerialPolyfillOptions): Promise<SerialPort[]>;
|
|
126
|
+
}
|
|
127
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SerialProvider } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a {@link SerialProvider} that communicates with a Node.js serial
|
|
4
|
+
* bridge server over WebSockets.
|
|
5
|
+
*
|
|
6
|
+
* The bridge server must implement the JSON wire protocol described in this
|
|
7
|
+
* file's module documentation. A reference implementation is provided in
|
|
8
|
+
* `demos/websocket/server.js`.
|
|
9
|
+
*
|
|
10
|
+
* @param serverUrl - The WebSocket URL of the bridge server (e.g. `"ws://localhost:8080"`).
|
|
11
|
+
* @returns A `SerialProvider` that relays serial I/O over WebSocket.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { createWebSocketProvider, AbstractSerialDevice } from 'webserial-core';
|
|
16
|
+
*
|
|
17
|
+
* AbstractSerialDevice.setProvider(createWebSocketProvider('ws://localhost:8080'));
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function createWebSocketProvider(serverUrl: string): SerialProvider;
|