@thermal-label/brother-ql-web 0.4.0 → 0.6.0
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/README.md +37 -0
- package/dist/__tests__/printer-read-loop.test.d.ts +2 -0
- package/dist/__tests__/printer-read-loop.test.d.ts.map +1 -0
- package/dist/__tests__/printer-read-loop.test.js +173 -0
- package/dist/__tests__/printer-read-loop.test.js.map +1 -0
- package/dist/__tests__/printer.test.js +206 -8
- package/dist/__tests__/printer.test.js.map +1 -1
- package/dist/__tests__/request-printers.test.d.ts +2 -0
- package/dist/__tests__/request-printers.test.d.ts.map +1 -0
- package/dist/__tests__/request-printers.test.js +250 -0
- package/dist/__tests__/request-printers.test.js.map +1 -0
- package/dist/__tests__/webusb-mock.d.ts +11 -0
- package/dist/__tests__/webusb-mock.d.ts.map +1 -1
- package/dist/__tests__/webusb-mock.js +54 -5
- package/dist/__tests__/webusb-mock.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/printer.d.ts +93 -0
- package/dist/printer.d.ts.map +1 -1
- package/dist/printer.js +226 -11
- package/dist/printer.js.map +1 -1
- package/dist/request-printers.d.ts +31 -0
- package/dist/request-printers.d.ts.map +1 -0
- package/dist/request-printers.js +109 -0
- package/dist/request-printers.js.map +1 -0
- package/package.json +5 -5
package/dist/printer.js
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
import { DEFAULT_MEDIA, DEVICES, ROTATE_DIRECTION, STATUS_REQUEST, createPreviewOffline, encodeJobForEngine, findDevice, flipHorizontal, parseStatus, pickRotation, renderImage, renderMultiPlaneImage, } from '@thermal-label/brother-ql-core';
|
|
2
|
-
import { MediaNotSpecifiedError } from '@thermal-label/contracts';
|
|
1
|
+
import { DEFAULT_MEDIA, DEVICES, ROTATE_DIRECTION, STATUS_REQUEST, buildInitialize, buildInvalidate, createPreviewOffline, encodeJobForEngine, findDevice, flipHorizontal, parseStatus, pickRotation, renderImage, renderMultiPlaneImage, } from '@thermal-label/brother-ql-core';
|
|
2
|
+
import { MediaNotSpecifiedError, pollingOnStatus, WriteSerializer } from '@thermal-label/contracts';
|
|
3
3
|
import { WebUsbTransport } from '@thermal-label/transport/web';
|
|
4
|
+
// Detect transport errors across module boundaries — under pnpm link /
|
|
5
|
+
// multi-version installs `instanceof` checks against the contracts
|
|
6
|
+
// classes can return false even for the right class. The contracts
|
|
7
|
+
// classes pin `this.name`, so name-checking is the portable test.
|
|
8
|
+
function isTransportClosedError(err) {
|
|
9
|
+
return err instanceof Error && err.name === 'TransportClosedError';
|
|
10
|
+
}
|
|
4
11
|
const STATUS_BYTE_COUNT = 32;
|
|
12
|
+
// A persistent read loop is the sole reader of the bulk-IN pipe: it
|
|
13
|
+
// parses every 32-byte status frame the printer emits and dispatches it
|
|
14
|
+
// to `statusListeners`. `getStatus()` writes ESC iS and awaits the next
|
|
15
|
+
// frame from that stream; spontaneous frames (lid open/close, media
|
|
16
|
+
// insert, end of job, errors) flow through the same loop. `onStatus()`
|
|
17
|
+
// is a polling shim over `getStatus()` — see that method.
|
|
18
|
+
const STATUS_RESPONSE_TIMEOUT_MS = 1500;
|
|
19
|
+
const READ_LOOP_BACKOFF_MS = 100;
|
|
5
20
|
// Same OUT-pipe chunking as the Node driver — see packages/node/src/printer.ts
|
|
6
21
|
// for the rationale. WebUSB rides the same libusb-style bulk transfer path,
|
|
7
22
|
// so the firmware buffer-overrun risk is identical.
|
|
@@ -20,9 +35,34 @@ export class WebBrotherQLPrinter {
|
|
|
20
35
|
device;
|
|
21
36
|
transport;
|
|
22
37
|
lastStatus;
|
|
38
|
+
statusListeners = new Set();
|
|
39
|
+
readLoopStarted = false;
|
|
40
|
+
readLoopStopped = false;
|
|
41
|
+
/**
|
|
42
|
+
* Serialises every bulk-OUT operation (print + getStatus). Required
|
|
43
|
+
* because `getStatus()` may write the QL preamble (`buildInvalidate` —
|
|
44
|
+
* 200×0x00 + `ESC @`) to put the parser in a known state, and the
|
|
45
|
+
* preamble's "invalidate" cancels any in-flight print job. Polling
|
|
46
|
+
* concurrently with a print would shred the raster stream.
|
|
47
|
+
*
|
|
48
|
+
* Plan 15 A4: this was a hand-rolled `writeLock`/`runLocked` pair;
|
|
49
|
+
* it is now the shared `WriteSerializer` from `@thermal-label/contracts`
|
|
50
|
+
* so all four drivers serialise identically. Behaviour is unchanged —
|
|
51
|
+
* `WriteSerializer.run()` is exactly the old `runLocked` semantics.
|
|
52
|
+
*/
|
|
53
|
+
serializer = new WriteSerializer();
|
|
54
|
+
/**
|
|
55
|
+
* Whether the printer's command parser is in a known-clean state.
|
|
56
|
+
* Set to `true` after a successful `getStatus()`; flipped back to
|
|
57
|
+
* `false` on timeout so the next attempt re-sends the preamble. The
|
|
58
|
+
* preamble (200-byte invalidate + `ESC @`) is only needed once per
|
|
59
|
+
* session unless the parser falls back into a confused state.
|
|
60
|
+
*/
|
|
61
|
+
parserReady = false;
|
|
23
62
|
constructor(device, transport) {
|
|
24
63
|
this.device = device;
|
|
25
64
|
this.transport = transport;
|
|
65
|
+
this.startReadLoop();
|
|
26
66
|
}
|
|
27
67
|
get model() {
|
|
28
68
|
return this.device.name;
|
|
@@ -39,7 +79,16 @@ export class WebBrotherQLPrinter {
|
|
|
39
79
|
// on the right side of the printed face when the leading edge is held
|
|
40
80
|
// up. Mirror the rendered bitmap so the input image's x-axis matches
|
|
41
81
|
// the printed x-axis. Verified on QL-820NWBc + DK-22251.
|
|
42
|
-
|
|
82
|
+
// PackBits compression on by default for the web path. Bench
|
|
83
|
+
// experience: WebUSB pacing alone (1024 / 20 ms) isn't enough on
|
|
84
|
+
// QL_700-class firmware — uncompressed raster rows can stall the
|
|
85
|
+
// print engine even when bytes are arriving. Compression keeps
|
|
86
|
+
// each row small enough to ride the firmware's buffer comfortably
|
|
87
|
+
// and matches the encoding the Brother driver itself emits.
|
|
88
|
+
const pageOptions = {
|
|
89
|
+
compress: true,
|
|
90
|
+
...(options?.highRes === true ? { highResolution: true } : {}),
|
|
91
|
+
};
|
|
43
92
|
let page;
|
|
44
93
|
if (resolvedMedia.palette) {
|
|
45
94
|
const { black, red } = renderMultiPlaneImage(image, {
|
|
@@ -50,7 +99,7 @@ export class WebBrotherQLPrinter {
|
|
|
50
99
|
bitmap: flipHorizontal(black),
|
|
51
100
|
redBitmap: flipHorizontal(red),
|
|
52
101
|
media: resolvedMedia,
|
|
53
|
-
|
|
102
|
+
options: pageOptions,
|
|
54
103
|
};
|
|
55
104
|
}
|
|
56
105
|
else {
|
|
@@ -58,13 +107,13 @@ export class WebBrotherQLPrinter {
|
|
|
58
107
|
page = {
|
|
59
108
|
bitmap,
|
|
60
109
|
media: resolvedMedia,
|
|
61
|
-
|
|
110
|
+
options: pageOptions,
|
|
62
111
|
};
|
|
63
112
|
}
|
|
64
113
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- every brother-ql device has at least one engine (data invariant)
|
|
65
114
|
const engine = this.device.engines[0];
|
|
66
115
|
const bytes = encodeJobForEngine([page], {}, engine, this.device.name);
|
|
67
|
-
await this.writeChunked(bytes);
|
|
116
|
+
await this.serializer.run(() => this.writeChunked(bytes));
|
|
68
117
|
}
|
|
69
118
|
async writeChunked(bytes) {
|
|
70
119
|
for (let off = 0; off < bytes.length; off += USB_CHUNK_SIZE) {
|
|
@@ -87,14 +136,125 @@ export class WebBrotherQLPrinter {
|
|
|
87
136
|
assumed: true,
|
|
88
137
|
});
|
|
89
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Send ESC iS and resolve with the next status frame the printer
|
|
141
|
+
* emits. The read loop is the sole reader of the bulk-IN pipe —
|
|
142
|
+
* `getStatus()` subscribes transiently, writes the request, and the
|
|
143
|
+
* subscription receives the response (alongside any spontaneous
|
|
144
|
+
* frames; see `onStatus()`).
|
|
145
|
+
*
|
|
146
|
+
* The QL preamble (200×0x00 invalidate + `ESC @` initialize) is
|
|
147
|
+
* sent only when the parser hasn't been confirmed clean — first
|
|
148
|
+
* call of the session, or after a previous timeout. Steady-state
|
|
149
|
+
* polls send bare `ESC iS`. Bench observation: a freshly-opened QL
|
|
150
|
+
* doesn't reply to bare `ESC iS` until the invalidate flushes any
|
|
151
|
+
* stale parser state from a prior session.
|
|
152
|
+
*/
|
|
90
153
|
async getStatus() {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
154
|
+
return this.serializer.run(async () => {
|
|
155
|
+
const next = this.nextStatusFrame(STATUS_RESPONSE_TIMEOUT_MS);
|
|
156
|
+
if (!this.parserReady) {
|
|
157
|
+
await this.transport.write(buildInvalidate());
|
|
158
|
+
await this.transport.write(buildInitialize());
|
|
159
|
+
}
|
|
160
|
+
await this.transport.write(STATUS_REQUEST);
|
|
161
|
+
try {
|
|
162
|
+
const status = await next;
|
|
163
|
+
this.parserReady = true;
|
|
164
|
+
return status;
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
// Timeout / read failure — printer may be in a confused
|
|
168
|
+
// state. Re-arm the preamble for the next attempt.
|
|
169
|
+
this.parserReady = false;
|
|
170
|
+
throw err;
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Subscribe to status updates. A polling shim built on
|
|
176
|
+
* `pollingOnStatus` from contracts — it calls `getStatus()` on first
|
|
177
|
+
* subscribe and then every `DEFAULT_POLLING_INTERVAL_MS`, matching the
|
|
178
|
+
* labelwriter and labelmanager web drivers (plan 11 §`onStatus`
|
|
179
|
+
* parity).
|
|
180
|
+
*
|
|
181
|
+
* An earlier revision skipped polling and relied solely on the
|
|
182
|
+
* printer's unsolicited frames. That was a workaround for the Chromium
|
|
183
|
+
* WebUSB sub-packet stall — `getStatus()`'s `read()` would hang, so
|
|
184
|
+
* polling looked unreliable and was dropped. `WebUsbTransport.read()`
|
|
185
|
+
* now rounds reads up to the endpoint packet size, so `getStatus()` is
|
|
186
|
+
* dependable and polling is restored.
|
|
187
|
+
*/
|
|
188
|
+
onStatus(cb) {
|
|
189
|
+
return pollingOnStatus(this, cb);
|
|
190
|
+
}
|
|
191
|
+
nextStatusFrame(timeoutMs) {
|
|
192
|
+
return new Promise((resolve, reject) => {
|
|
193
|
+
const timer = setTimeout(() => {
|
|
194
|
+
this.statusListeners.delete(handler);
|
|
195
|
+
reject(new Error(`Printer did not respond to status request within ${String(timeoutMs)}ms`));
|
|
196
|
+
}, timeoutMs);
|
|
197
|
+
const handler = (s) => {
|
|
198
|
+
clearTimeout(timer);
|
|
199
|
+
this.statusListeners.delete(handler);
|
|
200
|
+
resolve(s);
|
|
201
|
+
};
|
|
202
|
+
this.statusListeners.add(handler);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
startReadLoop() {
|
|
206
|
+
/* v8 ignore next -- defensive: startReadLoop is only ever called once, from the constructor, where readLoopStarted is still false; the re-entry guard can never be true */
|
|
207
|
+
if (this.readLoopStarted)
|
|
208
|
+
return;
|
|
209
|
+
this.readLoopStarted = true;
|
|
210
|
+
void this.readLoop();
|
|
211
|
+
}
|
|
212
|
+
async readLoop() {
|
|
213
|
+
while (!this.readLoopStopped && this.transport.connected) {
|
|
214
|
+
let bytes;
|
|
215
|
+
try {
|
|
216
|
+
bytes = await this.transport.read(STATUS_BYTE_COUNT);
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
if (isTransportClosedError(err))
|
|
220
|
+
return;
|
|
221
|
+
// If close() ran while the read was pending, the next iteration's
|
|
222
|
+
// while-guard exits the loop — no early return needed.
|
|
223
|
+
// Transient error — back off briefly to avoid hot-spinning.
|
|
224
|
+
// eslint-disable-next-line no-console -- driver-level diagnostic
|
|
225
|
+
console.warn('[brother-ql-web] status read error, backing off:', err);
|
|
226
|
+
await new Promise(r => setTimeout(r, READ_LOOP_BACKOFF_MS));
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (bytes.length < STATUS_BYTE_COUNT)
|
|
230
|
+
continue;
|
|
231
|
+
let status;
|
|
232
|
+
try {
|
|
233
|
+
status = parseStatus(bytes, this.device.engines[0]);
|
|
234
|
+
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
// eslint-disable-next-line no-console -- driver-level diagnostic
|
|
237
|
+
console.warn('[brother-ql-web] failed to parse status frame:', err);
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
this.lastStatus = status;
|
|
241
|
+
// Snapshot listeners so unsubscribes during dispatch don't skip siblings.
|
|
242
|
+
const snapshot = Array.from(this.statusListeners);
|
|
243
|
+
for (const cb of snapshot) {
|
|
244
|
+
try {
|
|
245
|
+
cb(status);
|
|
246
|
+
/* v8 ignore next 4 -- defensive: the only registrant of statusListeners is nextStatusFrame's internal handler (clearTimeout + delete + resolve), which cannot throw; kept for future persistent-listener callers */
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
// eslint-disable-next-line no-console -- driver-level diagnostic
|
|
250
|
+
console.warn('[brother-ql-web] status listener threw:', err);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
96
254
|
}
|
|
97
255
|
async close() {
|
|
256
|
+
this.readLoopStopped = true;
|
|
257
|
+
this.statusListeners.clear();
|
|
98
258
|
await this.transport.close();
|
|
99
259
|
}
|
|
100
260
|
}
|
|
@@ -107,16 +267,46 @@ export const DEFAULT_FILTERS = Object.values(DEVICES)
|
|
|
107
267
|
*
|
|
108
268
|
* Requires a user gesture. Opens the device and claims interface 0 via
|
|
109
269
|
* `WebUsbTransport.fromDevice()`.
|
|
270
|
+
*
|
|
271
|
+
* Single-instance entry point — preserved for back-compat with existing
|
|
272
|
+
* consumers (CLIs, ad-hoc scripts). For the symmetric driver-web shape
|
|
273
|
+
* (1-key map keyed by engine role) call `requestPrinters()` instead;
|
|
274
|
+
* the harness shell uses that path.
|
|
275
|
+
*
|
|
276
|
+
* @deprecated Use `requestPrinters({ transport: 'usb' })` from
|
|
277
|
+
* `./request-printers.ts`. Removed once consumers migrate (plan 11).
|
|
110
278
|
*/
|
|
111
279
|
export async function requestPrinter(options = {}) {
|
|
112
280
|
const filters = options.filters ?? DEFAULT_FILTERS;
|
|
113
281
|
const usbDevice = await navigator.usb.requestDevice({ filters });
|
|
282
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated -- legacy alias chain; the deprecation guidance is aimed at external callers, not internal usage
|
|
114
283
|
return fromUSBDevice(usbDevice);
|
|
115
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* Show the browser's USB picker and return one `PrinterAdapter` per
|
|
287
|
+
* drivable engine on the selected device, keyed by engine role.
|
|
288
|
+
*
|
|
289
|
+
* Brother QL devices are always single-engine — this returns a 1-key
|
|
290
|
+
* record keyed by the device's `engines[0].role` (typically `'primary'`).
|
|
291
|
+
*
|
|
292
|
+
* @deprecated Use the generic `requestPrinters({ transport: 'usb' })`
|
|
293
|
+
* from `./request-printers.ts` — the legacy USB-only name is preserved
|
|
294
|
+
* as `requestPrintersUsbLegacy` for back-compat. Removed once
|
|
295
|
+
* consumers migrate (plan 11).
|
|
296
|
+
*/
|
|
297
|
+
export async function requestPrintersUsbLegacy(options = {}) {
|
|
298
|
+
const filters = options.filters ?? DEFAULT_FILTERS;
|
|
299
|
+
const usbDevice = await navigator.usb.requestDevice({ filters });
|
|
300
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated -- legacy alias chain
|
|
301
|
+
return fromUSBDeviceAll(usbDevice);
|
|
302
|
+
}
|
|
116
303
|
/**
|
|
117
304
|
* Wrap an already-selected `USBDevice`.
|
|
118
305
|
*
|
|
119
306
|
* @throws when the VID/PID is not in the Brother QL registry.
|
|
307
|
+
*
|
|
308
|
+
* @deprecated Use `requestPrinters({ transport: 'usb' })` from
|
|
309
|
+
* `./request-printers.ts`. Removed once consumers migrate (plan 11).
|
|
120
310
|
*/
|
|
121
311
|
export async function fromUSBDevice(usbDevice) {
|
|
122
312
|
const descriptor = findDevice(usbDevice.vendorId, usbDevice.productId);
|
|
@@ -126,4 +316,29 @@ export async function fromUSBDevice(usbDevice) {
|
|
|
126
316
|
const transport = await WebUsbTransport.fromDevice(usbDevice);
|
|
127
317
|
return new WebBrotherQLPrinter(descriptor, transport);
|
|
128
318
|
}
|
|
319
|
+
/**
|
|
320
|
+
* Wrap an already-selected `USBDevice` and return a 1-key adapter map
|
|
321
|
+
* keyed by the device's `engines[0].role`. Public surface for
|
|
322
|
+
* `requestPrinters()`; exported so harnesses that already hold a
|
|
323
|
+
* `USBDevice` (e.g. picked-up via `navigator.usb.getDevices()` on a
|
|
324
|
+
* returning visit) can skip the picker.
|
|
325
|
+
*
|
|
326
|
+
* Brother QL is single-engine and single-interface (IF 0).
|
|
327
|
+
*
|
|
328
|
+
* @deprecated Use `requestPrinters({ transport: 'usb' })` from
|
|
329
|
+
* `./request-printers.ts`. Removed once consumers migrate (plan 11).
|
|
330
|
+
*/
|
|
331
|
+
export async function fromUSBDeviceAll(usbDevice) {
|
|
332
|
+
const descriptor = findDevice(usbDevice.vendorId, usbDevice.productId);
|
|
333
|
+
if (!descriptor) {
|
|
334
|
+
throw new Error(`Unsupported USB device: VID=0x${usbDevice.vendorId.toString(16)} PID=0x${usbDevice.productId.toString(16)}`);
|
|
335
|
+
}
|
|
336
|
+
const engine = descriptor.engines[0];
|
|
337
|
+
/* v8 ignore next 3 -- defensive: every brother-ql registry entry declares at least one engine (data invariant); guard kept against a malformed future registry edit */
|
|
338
|
+
if (!engine) {
|
|
339
|
+
throw new Error(`Device ${descriptor.key} has no engines.`);
|
|
340
|
+
}
|
|
341
|
+
const transport = await WebUsbTransport.fromDevice(usbDevice);
|
|
342
|
+
return { [engine.role]: new WebBrotherQLPrinter(descriptor, transport) };
|
|
343
|
+
}
|
|
129
344
|
//# sourceMappingURL=printer.js.map
|
package/dist/printer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"printer.js","sourceRoot":"","sources":["../src/printer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,OAAO,EACP,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,UAAU,EACV,cAAc,EACd,WAAW,EACX,YAAY,EACZ,WAAW,EACX,qBAAqB,GACtB,MAAM,gCAAgC,CAAC;AAexC,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"printer.js","sourceRoot":"","sources":["../src/printer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type ConnectOptions, type DeviceEntry, type PrinterAdapterMap, type TransportType } from '@thermal-label/contracts';
|
|
2
|
+
/**
|
|
3
|
+
* Unified browser-picker factory for the brother-ql driver family.
|
|
4
|
+
*
|
|
5
|
+
* Dispatches on `opts.transport`:
|
|
6
|
+
*
|
|
7
|
+
* - `'usb'` — opens `navigator.usb` picker. Auto-identifies via
|
|
8
|
+
* `usbDevice.vendorId/productId` against the registry. Throws
|
|
9
|
+
* `DeviceIdentificationRequiredError` only if the picked device's
|
|
10
|
+
* VID/PID is not in the brother-ql registry.
|
|
11
|
+
* - `'bluetooth-spp'` — always-ask (Web Serial has no BT name
|
|
12
|
+
* surface). `opts.deviceKey` required; if omitted, throws
|
|
13
|
+
* `DeviceIdentificationRequiredError` with the BT-SPP-capable
|
|
14
|
+
* subset of `DEVICES` (e.g. QL_820NWBc, PT_P910BT).
|
|
15
|
+
* `continueWith(deviceKey)` opens the Web Serial picker for the
|
|
16
|
+
* chosen device.
|
|
17
|
+
* - `'serial'` — not declared in the brother-ql registry today;
|
|
18
|
+
* throws unconditionally.
|
|
19
|
+
* - `'bluetooth-gatt'` — not declared in the brother-ql registry today;
|
|
20
|
+
* throws unconditionally.
|
|
21
|
+
*
|
|
22
|
+
* Returns a 1-key `PrinterAdapterMap` keyed by the device's primary
|
|
23
|
+
* engine role.
|
|
24
|
+
*/
|
|
25
|
+
export declare function requestPrinters(opts: ConnectOptions): Promise<PrinterAdapterMap>;
|
|
26
|
+
/**
|
|
27
|
+
* Filter the registry to entries declaring `transport`. Used to
|
|
28
|
+
* populate `DeviceIdentificationRequiredError.candidates`.
|
|
29
|
+
*/
|
|
30
|
+
export declare function devicesForTransport(transport: TransportType): readonly DeviceEntry[];
|
|
31
|
+
//# sourceMappingURL=request-printers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-printers.d.ts","sourceRoot":"","sources":["../src/request-printers.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EAEtB,KAAK,aAAa,EACnB,MAAM,0BAA0B,CAAC;AAKlC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAWtF;AAgFD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,aAAa,GAAG,SAAS,WAAW,EAAE,CAEpF"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { DeviceIdentificationRequiredError, } from '@thermal-label/contracts';
|
|
2
|
+
import { DEVICES, findDevice } from '@thermal-label/brother-ql-core';
|
|
3
|
+
import { WebSerialTransport, WebUsbTransport } from '@thermal-label/transport/web';
|
|
4
|
+
import { DEFAULT_FILTERS, WebBrotherQLPrinter } from './printer.js';
|
|
5
|
+
/**
|
|
6
|
+
* Unified browser-picker factory for the brother-ql driver family.
|
|
7
|
+
*
|
|
8
|
+
* Dispatches on `opts.transport`:
|
|
9
|
+
*
|
|
10
|
+
* - `'usb'` — opens `navigator.usb` picker. Auto-identifies via
|
|
11
|
+
* `usbDevice.vendorId/productId` against the registry. Throws
|
|
12
|
+
* `DeviceIdentificationRequiredError` only if the picked device's
|
|
13
|
+
* VID/PID is not in the brother-ql registry.
|
|
14
|
+
* - `'bluetooth-spp'` — always-ask (Web Serial has no BT name
|
|
15
|
+
* surface). `opts.deviceKey` required; if omitted, throws
|
|
16
|
+
* `DeviceIdentificationRequiredError` with the BT-SPP-capable
|
|
17
|
+
* subset of `DEVICES` (e.g. QL_820NWBc, PT_P910BT).
|
|
18
|
+
* `continueWith(deviceKey)` opens the Web Serial picker for the
|
|
19
|
+
* chosen device.
|
|
20
|
+
* - `'serial'` — not declared in the brother-ql registry today;
|
|
21
|
+
* throws unconditionally.
|
|
22
|
+
* - `'bluetooth-gatt'` — not declared in the brother-ql registry today;
|
|
23
|
+
* throws unconditionally.
|
|
24
|
+
*
|
|
25
|
+
* Returns a 1-key `PrinterAdapterMap` keyed by the device's primary
|
|
26
|
+
* engine role.
|
|
27
|
+
*/
|
|
28
|
+
export async function requestPrinters(opts) {
|
|
29
|
+
switch (opts.transport) {
|
|
30
|
+
case 'usb':
|
|
31
|
+
return requestPrintersUsb(opts);
|
|
32
|
+
case 'bluetooth-spp':
|
|
33
|
+
return requestPrintersBluetoothSpp(opts);
|
|
34
|
+
case 'serial':
|
|
35
|
+
throw new Error('brother-ql: serial transport not declared in the registry');
|
|
36
|
+
case 'bluetooth-gatt':
|
|
37
|
+
throw new Error('brother-ql: bluetooth-gatt transport not declared in the registry');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function requestPrintersUsb(opts) {
|
|
41
|
+
const filters = DEFAULT_FILTERS;
|
|
42
|
+
const usbDevice = await navigator.usb.requestDevice({ filters });
|
|
43
|
+
if (opts.deviceKey !== undefined) {
|
|
44
|
+
const entry = entryByKey(opts.deviceKey);
|
|
45
|
+
if (!entry) {
|
|
46
|
+
throw new Error(`requestPrinters(usb): unknown deviceKey "${opts.deviceKey}"`);
|
|
47
|
+
}
|
|
48
|
+
const transport = await WebUsbTransport.fromDevice(usbDevice);
|
|
49
|
+
return adapterMap(entry, transport);
|
|
50
|
+
}
|
|
51
|
+
const entry = findDevice(usbDevice.vendorId, usbDevice.productId);
|
|
52
|
+
if (entry) {
|
|
53
|
+
const transport = await WebUsbTransport.fromDevice(usbDevice);
|
|
54
|
+
return adapterMap(entry, transport);
|
|
55
|
+
}
|
|
56
|
+
// No registry match — let the caller pick from the USB-capable
|
|
57
|
+
// candidates and keep the same USBDevice across the
|
|
58
|
+
// `continueWith` resume.
|
|
59
|
+
throw new DeviceIdentificationRequiredError(devicesForTransport('usb'), async (deviceKey) => {
|
|
60
|
+
const chosen = entryByKey(deviceKey);
|
|
61
|
+
if (!chosen) {
|
|
62
|
+
throw new Error(`continueWith: unknown deviceKey "${deviceKey}"`);
|
|
63
|
+
}
|
|
64
|
+
const transport = await WebUsbTransport.fromDevice(usbDevice);
|
|
65
|
+
return adapterMap(chosen, transport);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function requestPrintersBluetoothSpp(opts) {
|
|
69
|
+
if (opts.deviceKey === undefined) {
|
|
70
|
+
return Promise.reject(new DeviceIdentificationRequiredError(devicesForTransport('bluetooth-spp'), deviceKey => openBluetoothSpp(deviceKey, opts.baudRate)));
|
|
71
|
+
}
|
|
72
|
+
return openBluetoothSpp(opts.deviceKey, opts.baudRate);
|
|
73
|
+
}
|
|
74
|
+
async function openBluetoothSpp(deviceKey, baudRate) {
|
|
75
|
+
const entry = entryByKey(deviceKey);
|
|
76
|
+
if (!entry) {
|
|
77
|
+
throw new Error(`requestPrinters(bluetooth-spp): unknown deviceKey "${deviceKey}"`);
|
|
78
|
+
}
|
|
79
|
+
if (!entry.transports['bluetooth-spp']) {
|
|
80
|
+
throw new Error(`requestPrinters(bluetooth-spp): ${deviceKey} does not declare bluetooth-spp transport`);
|
|
81
|
+
}
|
|
82
|
+
// SPP baud is negotiated on the link; default to 9600 when not
|
|
83
|
+
// specified.
|
|
84
|
+
const transport = await WebSerialTransport.request(undefined, baudRate ?? 9600);
|
|
85
|
+
return adapterMap(entry, transport);
|
|
86
|
+
}
|
|
87
|
+
function adapterMap(entry, transport) {
|
|
88
|
+
const engine = entry.engines[0];
|
|
89
|
+
/* v8 ignore next -- defensive: every brother-ql registry entry declares at least one engine (data invariant); guard kept against a malformed future registry edit */
|
|
90
|
+
if (!engine)
|
|
91
|
+
throw new Error(`Device ${entry.key} has no engines.`);
|
|
92
|
+
// WebBrotherQLPrinter accepts a generic Transport — the encoder is
|
|
93
|
+
// transport-agnostic, so the BT-SPP path is just the same printer
|
|
94
|
+
// class wrapped around a WebSerialTransport. Bench-confirmed on
|
|
95
|
+
// QL-820NWBc.
|
|
96
|
+
const printer = new WebBrotherQLPrinter(entry, transport);
|
|
97
|
+
return { [engine.role]: printer };
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Filter the registry to entries declaring `transport`. Used to
|
|
101
|
+
* populate `DeviceIdentificationRequiredError.candidates`.
|
|
102
|
+
*/
|
|
103
|
+
export function devicesForTransport(transport) {
|
|
104
|
+
return Object.values(DEVICES).filter(d => transport in d.transports);
|
|
105
|
+
}
|
|
106
|
+
function entryByKey(key) {
|
|
107
|
+
return DEVICES[key];
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=request-printers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-printers.js","sourceRoot":"","sources":["../src/request-printers.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thermal-label/brother-ql-web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "WebUSB browser driver for Brother QL label printers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"brother",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"type": "module",
|
|
14
14
|
"author": "Mannes Brak",
|
|
15
15
|
"license": "MIT",
|
|
16
|
-
"homepage": "https://thermal-label.github.io/brother-ql/",
|
|
16
|
+
"homepage": "https://thermal-label.github.io/brother-ql/web",
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
19
|
"url": "https://github.com/thermal-label/brother-ql.git",
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@thermal-label/contracts": "^0.
|
|
56
|
-
"@thermal-label/transport": "^0.
|
|
57
|
-
"@thermal-label/brother-ql-core": "0.
|
|
55
|
+
"@thermal-label/contracts": "^0.6.0",
|
|
56
|
+
"@thermal-label/transport": "^0.6.0",
|
|
57
|
+
"@thermal-label/brother-ql-core": "0.6.0"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"typescript": ">=5.0"
|