@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
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { DeviceIdentificationRequiredError } from '@thermal-label/contracts';
|
|
3
|
+
import { DEVICES } from '@thermal-label/brother-ql-core';
|
|
4
|
+
import { devicesForTransport, requestPrinters } from '../request-printers.js';
|
|
5
|
+
import { createMockUSBDevice } from './webusb-mock.js';
|
|
6
|
+
/**
|
|
7
|
+
* Minimal Web Serial `SerialPort` double for the Web Serial picker
|
|
8
|
+
* path. Typed structurally (not as the DOM `SerialPort`) because the
|
|
9
|
+
* web package only pulls in `w3c-web-usb`, not `w3c-web-serial`.
|
|
10
|
+
*
|
|
11
|
+
* `WebSerialTransport.fromPort` opens the port and locks a
|
|
12
|
+
* reader/writer; its pump loop awaits `reader.read()` indefinitely.
|
|
13
|
+
* This double's reader hangs until `cancel()` fires (mirroring a real
|
|
14
|
+
* idle SPP link) so `close()` can unwind the pump cleanly.
|
|
15
|
+
*/
|
|
16
|
+
function createMockSerialPort() {
|
|
17
|
+
let cancelReader;
|
|
18
|
+
const reader = {
|
|
19
|
+
read: () => new Promise(resolve => {
|
|
20
|
+
cancelReader = () => {
|
|
21
|
+
resolve({ value: new Uint8Array(0), done: true });
|
|
22
|
+
};
|
|
23
|
+
}),
|
|
24
|
+
cancel: () => {
|
|
25
|
+
cancelReader?.();
|
|
26
|
+
return Promise.resolve();
|
|
27
|
+
},
|
|
28
|
+
releaseLock: () => {
|
|
29
|
+
/* no-op */
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
const writer = {
|
|
33
|
+
write: () => Promise.resolve(),
|
|
34
|
+
close: () => Promise.resolve(),
|
|
35
|
+
releaseLock: () => {
|
|
36
|
+
/* no-op */
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
open: vi.fn(() => Promise.resolve()),
|
|
41
|
+
close: vi.fn(() => Promise.resolve()),
|
|
42
|
+
readable: { getReader: () => reader },
|
|
43
|
+
writable: { getWriter: () => writer },
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
describe('requestPrinters(opts) — brother-ql generic factory', () => {
|
|
47
|
+
afterEach(() => {
|
|
48
|
+
vi.restoreAllMocks();
|
|
49
|
+
});
|
|
50
|
+
describe('transport: bluetooth-spp', () => {
|
|
51
|
+
it('throws DeviceIdentificationRequiredError when deviceKey omitted (no picker open)', async () => {
|
|
52
|
+
// No navigator.serial stubbed — a picker call would TypeError.
|
|
53
|
+
await expect(requestPrinters({ transport: 'bluetooth-spp' })).rejects.toBeInstanceOf(DeviceIdentificationRequiredError);
|
|
54
|
+
});
|
|
55
|
+
it('candidates are filtered to bluetooth-spp-capable entries (QL_820NWBc, PT_P910BT)', async () => {
|
|
56
|
+
try {
|
|
57
|
+
await requestPrinters({ transport: 'bluetooth-spp' });
|
|
58
|
+
throw new Error('expected DeviceIdentificationRequiredError');
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
if (!(err instanceof DeviceIdentificationRequiredError))
|
|
62
|
+
throw err;
|
|
63
|
+
const keys = err.candidates.map(c => c.key);
|
|
64
|
+
// Bench-confirmed SPP-capable models in the brother-ql registry.
|
|
65
|
+
expect(keys).toContain(DEVICES.QL_820NWBc.key);
|
|
66
|
+
expect(keys).toContain(DEVICES.PT_P910BT.key);
|
|
67
|
+
for (const candidate of err.candidates) {
|
|
68
|
+
expect(candidate.transports['bluetooth-spp']).toBeDefined();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
it('rejects an unknown deviceKey on bluetooth-spp', async () => {
|
|
73
|
+
await expect(requestPrinters({ transport: 'bluetooth-spp', deviceKey: 'NOT_A_KEY' })).rejects.toThrow(/unknown deviceKey/);
|
|
74
|
+
});
|
|
75
|
+
it('rejects a deviceKey for a model that does not declare bluetooth-spp', async () => {
|
|
76
|
+
// PT_P750W is a registered USB-only model — no bluetooth-spp entry.
|
|
77
|
+
expect(DEVICES.PT_P750W.transports['bluetooth-spp']).toBeUndefined();
|
|
78
|
+
await expect(requestPrinters({ transport: 'bluetooth-spp', deviceKey: DEVICES.PT_P750W.key })).rejects.toThrow(/does not declare bluetooth-spp/);
|
|
79
|
+
});
|
|
80
|
+
it('opens the Web Serial picker and returns a 1-key adapter map for a known SPP model', async () => {
|
|
81
|
+
const port = createMockSerialPort();
|
|
82
|
+
const requestPort = vi.fn().mockResolvedValue(port);
|
|
83
|
+
vi.stubGlobal('navigator', { serial: { requestPort } });
|
|
84
|
+
const printers = await requestPrinters({
|
|
85
|
+
transport: 'bluetooth-spp',
|
|
86
|
+
deviceKey: DEVICES.QL_820NWBc.key,
|
|
87
|
+
});
|
|
88
|
+
const roles = Object.keys(printers);
|
|
89
|
+
expect(roles).toHaveLength(1);
|
|
90
|
+
expect(roles[0]).toBe(DEVICES.QL_820NWBc.engines[0].role);
|
|
91
|
+
expect(printers[roles[0]].family).toBe('brother-ql');
|
|
92
|
+
expect(requestPort).toHaveBeenCalledOnce();
|
|
93
|
+
await printers[roles[0]].close();
|
|
94
|
+
});
|
|
95
|
+
it('continueWith opens the Web Serial picker with the operator-chosen SPP model', async () => {
|
|
96
|
+
const port = createMockSerialPort();
|
|
97
|
+
const requestPort = vi.fn().mockResolvedValue(port);
|
|
98
|
+
vi.stubGlobal('navigator', { serial: { requestPort } });
|
|
99
|
+
try {
|
|
100
|
+
await requestPrinters({ transport: 'bluetooth-spp' });
|
|
101
|
+
throw new Error('expected DeviceIdentificationRequiredError');
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
if (!(err instanceof DeviceIdentificationRequiredError))
|
|
105
|
+
throw err;
|
|
106
|
+
// No picker is opened until the operator resolves the choice.
|
|
107
|
+
expect(requestPort).not.toHaveBeenCalled();
|
|
108
|
+
const printers = await err.continueWith(DEVICES.PT_P910BT.key);
|
|
109
|
+
const roles = Object.keys(printers);
|
|
110
|
+
expect(roles).toHaveLength(1);
|
|
111
|
+
expect(requestPort).toHaveBeenCalledOnce();
|
|
112
|
+
await printers[roles[0]].close();
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
it('continueWith rejects an unknown deviceKey', async () => {
|
|
116
|
+
try {
|
|
117
|
+
await requestPrinters({ transport: 'bluetooth-spp' });
|
|
118
|
+
throw new Error('expected DeviceIdentificationRequiredError');
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
if (!(err instanceof DeviceIdentificationRequiredError))
|
|
122
|
+
throw err;
|
|
123
|
+
await expect(err.continueWith('NOT_A_KEY')).rejects.toThrow(/unknown deviceKey/);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
describe('transport: serial', () => {
|
|
128
|
+
it('throws because brother-ql does not declare serial', async () => {
|
|
129
|
+
await expect(requestPrinters({ transport: 'serial' })).rejects.toThrow(/not declared/);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
describe('transport: bluetooth-gatt', () => {
|
|
133
|
+
it('throws because brother-ql does not declare bluetooth-gatt', async () => {
|
|
134
|
+
await expect(requestPrinters({ transport: 'bluetooth-gatt' })).rejects.toThrow(/not declared/);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
describe('transport: usb — auto-identify', () => {
|
|
138
|
+
it('returns a 1-key adapter map when the picked USBDevice matches a registry entry', async () => {
|
|
139
|
+
// QL_820NWBc canonical VID/PID — registered.
|
|
140
|
+
const known = DEVICES.QL_820NWBc.transports.usb;
|
|
141
|
+
if (!known)
|
|
142
|
+
throw new Error('QL_820NWBc missing usb transport in registry');
|
|
143
|
+
const device = createMockUSBDevice({
|
|
144
|
+
vendorId: Number.parseInt(known.vid, 16),
|
|
145
|
+
productId: Number.parseInt(known.pid, 16),
|
|
146
|
+
});
|
|
147
|
+
const usbStub = {
|
|
148
|
+
requestDevice: vi.fn().mockResolvedValue(device),
|
|
149
|
+
getDevices: vi.fn().mockResolvedValue([device]),
|
|
150
|
+
};
|
|
151
|
+
vi.stubGlobal('navigator', { usb: usbStub });
|
|
152
|
+
const printers = await requestPrinters({ transport: 'usb' });
|
|
153
|
+
const roles = Object.keys(printers);
|
|
154
|
+
expect(roles).toHaveLength(1);
|
|
155
|
+
const printer = printers[roles[0]];
|
|
156
|
+
expect(printer.family).toBe('brother-ql');
|
|
157
|
+
await printer.close();
|
|
158
|
+
});
|
|
159
|
+
it('uses an explicit deviceKey to wrap the picked USBDevice without registry auto-match', async () => {
|
|
160
|
+
// Pass a deviceKey alongside a device whose VID/PID would NOT
|
|
161
|
+
// auto-match — the explicit key takes the priority branch.
|
|
162
|
+
const device = createMockUSBDevice({ vendorId: 0x04f9, productId: 0xabcd });
|
|
163
|
+
const usbStub = {
|
|
164
|
+
requestDevice: vi.fn().mockResolvedValue(device),
|
|
165
|
+
getDevices: vi.fn().mockResolvedValue([device]),
|
|
166
|
+
};
|
|
167
|
+
vi.stubGlobal('navigator', { usb: usbStub });
|
|
168
|
+
const printers = await requestPrinters({
|
|
169
|
+
transport: 'usb',
|
|
170
|
+
deviceKey: DEVICES.QL_820NWBc.key,
|
|
171
|
+
});
|
|
172
|
+
const roles = Object.keys(printers);
|
|
173
|
+
expect(roles).toHaveLength(1);
|
|
174
|
+
expect(roles[0]).toBe(DEVICES.QL_820NWBc.engines[0].role);
|
|
175
|
+
await printers[roles[0]].close();
|
|
176
|
+
});
|
|
177
|
+
it('rejects an explicit unknown deviceKey on usb', async () => {
|
|
178
|
+
const device = createMockUSBDevice({ vendorId: 0x04f9, productId: 0x209d });
|
|
179
|
+
const usbStub = {
|
|
180
|
+
requestDevice: vi.fn().mockResolvedValue(device),
|
|
181
|
+
getDevices: vi.fn().mockResolvedValue([device]),
|
|
182
|
+
};
|
|
183
|
+
vi.stubGlobal('navigator', { usb: usbStub });
|
|
184
|
+
await expect(requestPrinters({ transport: 'usb', deviceKey: 'NOT_A_KEY' })).rejects.toThrow(/unknown deviceKey/);
|
|
185
|
+
});
|
|
186
|
+
it('continueWith rejects an unknown deviceKey on the usb path', async () => {
|
|
187
|
+
const device = createMockUSBDevice({ vendorId: 0x04f9, productId: 0xabcd });
|
|
188
|
+
const usbStub = {
|
|
189
|
+
requestDevice: vi.fn().mockResolvedValue(device),
|
|
190
|
+
getDevices: vi.fn().mockResolvedValue([device]),
|
|
191
|
+
};
|
|
192
|
+
vi.stubGlobal('navigator', { usb: usbStub });
|
|
193
|
+
try {
|
|
194
|
+
await requestPrinters({ transport: 'usb' });
|
|
195
|
+
throw new Error('expected DeviceIdentificationRequiredError');
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
if (!(err instanceof DeviceIdentificationRequiredError))
|
|
199
|
+
throw err;
|
|
200
|
+
await expect(err.continueWith('NOT_A_KEY')).rejects.toThrow(/unknown deviceKey/);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
it('throws DeviceIdentificationRequiredError when the picked device has unknown VID/PID', async () => {
|
|
204
|
+
const device = createMockUSBDevice({ vendorId: 0xdead, productId: 0xbeef });
|
|
205
|
+
const usbStub = {
|
|
206
|
+
requestDevice: vi.fn().mockResolvedValue(device),
|
|
207
|
+
getDevices: vi.fn().mockResolvedValue([device]),
|
|
208
|
+
};
|
|
209
|
+
vi.stubGlobal('navigator', { usb: usbStub });
|
|
210
|
+
await expect(requestPrinters({ transport: 'usb' })).rejects.toBeInstanceOf(DeviceIdentificationRequiredError);
|
|
211
|
+
});
|
|
212
|
+
it('continueWith resumes with the chosen deviceKey reusing the picked USBDevice', async () => {
|
|
213
|
+
// Use a real Brother VID with an unknown PID — the registry
|
|
214
|
+
// won't match, the picker fires once, and continueWith wraps
|
|
215
|
+
// the same device with the operator's choice.
|
|
216
|
+
const device = createMockUSBDevice({ vendorId: 0x04f9, productId: 0xabcd });
|
|
217
|
+
const requestDevice = vi.fn().mockResolvedValue(device);
|
|
218
|
+
const usbStub = {
|
|
219
|
+
requestDevice,
|
|
220
|
+
getDevices: vi.fn().mockResolvedValue([device]),
|
|
221
|
+
};
|
|
222
|
+
vi.stubGlobal('navigator', { usb: usbStub });
|
|
223
|
+
try {
|
|
224
|
+
await requestPrinters({ transport: 'usb' });
|
|
225
|
+
throw new Error('expected DeviceIdentificationRequiredError');
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
if (!(err instanceof DeviceIdentificationRequiredError))
|
|
229
|
+
throw err;
|
|
230
|
+
const printers = await err.continueWith(DEVICES.QL_820NWBc.key);
|
|
231
|
+
const roles = Object.keys(printers);
|
|
232
|
+
expect(roles).toHaveLength(1);
|
|
233
|
+
// continueWith must not open the picker a second time.
|
|
234
|
+
expect(requestDevice).toHaveBeenCalledTimes(1);
|
|
235
|
+
await printers[roles[0]].close();
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
describe('devicesForTransport — brother-ql', () => {
|
|
241
|
+
it('returns only entries declaring the given transport', () => {
|
|
242
|
+
for (const entry of devicesForTransport('usb')) {
|
|
243
|
+
expect(entry.transports.usb).toBeDefined();
|
|
244
|
+
}
|
|
245
|
+
for (const entry of devicesForTransport('bluetooth-spp')) {
|
|
246
|
+
expect(entry.transports['bluetooth-spp']).toBeDefined();
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
//# sourceMappingURL=request-printers.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-printers.test.js","sourceRoot":"","sources":["../../src/__tests__/request-printers.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,10 +4,21 @@ export interface MockUSBDevice extends USBDevice {
|
|
|
4
4
|
data: Uint8Array;
|
|
5
5
|
}[];
|
|
6
6
|
__statusBytes: Uint8Array;
|
|
7
|
+
/**
|
|
8
|
+
* Inject an unsolicited status frame into the bulk-IN pipe. Used by
|
|
9
|
+
* tests to simulate spontaneous events the printer pushes outside of
|
|
10
|
+
* a getStatus request (lid open/close, media insert, etc.).
|
|
11
|
+
*/
|
|
12
|
+
__pushUnsolicited: (frame: Uint8Array) => void;
|
|
7
13
|
}
|
|
8
14
|
export declare function createMockUSBDevice(overrides?: {
|
|
9
15
|
vendorId?: number;
|
|
10
16
|
productId?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Response template for ESC iS (`1B 69 53`). Each status request
|
|
19
|
+
* enqueues a copy of this frame — modelling the real printer's
|
|
20
|
+
* "request → one response" cycle. Defaults to a 32-byte zero frame.
|
|
21
|
+
*/
|
|
11
22
|
statusBytes?: Uint8Array;
|
|
12
23
|
}): MockUSBDevice;
|
|
13
24
|
//# sourceMappingURL=webusb-mock.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webusb-mock.d.ts","sourceRoot":"","sources":["../../src/__tests__/webusb-mock.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAc,SAAQ,SAAS;IAC9C,WAAW,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,EAAE,CAAC;IAC5D,aAAa,EAAE,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"webusb-mock.d.ts","sourceRoot":"","sources":["../../src/__tests__/webusb-mock.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAc,SAAQ,SAAS;IAC9C,WAAW,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,EAAE,CAAC;IAC5D,aAAa,EAAE,UAAU,CAAC;IAC1B;;;;OAIG;IACH,iBAAiB,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CAChD;AAED,wBAAgB,mBAAmB,CAAC,SAAS,CAAC,EAAE;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,WAAW,CAAC,EAAE,UAAU,CAAC;CAC1B,GAAG,aAAa,CAoHhB"}
|
|
@@ -2,6 +2,19 @@ import { vi } from 'vitest';
|
|
|
2
2
|
export function createMockUSBDevice(overrides) {
|
|
3
3
|
const transfers = [];
|
|
4
4
|
let opened = false;
|
|
5
|
+
// Single in-flight pipe queue. Each ESC iS write appends a response
|
|
6
|
+
// copy. Pending readers (calls to `transferIn` made while the queue
|
|
7
|
+
// is empty) park in `waiters` and are resolved as soon as a frame is
|
|
8
|
+
// appended — matching real WebUSB bulk-IN behaviour.
|
|
9
|
+
const frameQueue = [];
|
|
10
|
+
const waiters = [];
|
|
11
|
+
function enqueue(frame) {
|
|
12
|
+
const waiter = waiters.shift();
|
|
13
|
+
if (waiter)
|
|
14
|
+
waiter(frame);
|
|
15
|
+
else
|
|
16
|
+
frameQueue.push(frame);
|
|
17
|
+
}
|
|
5
18
|
const endpoints = [
|
|
6
19
|
{ endpointNumber: 2, direction: 'out' },
|
|
7
20
|
{ endpointNumber: 1, direction: 'in' },
|
|
@@ -40,6 +53,20 @@ export function createMockUSBDevice(overrides) {
|
|
|
40
53
|
}),
|
|
41
54
|
close: vi.fn(() => {
|
|
42
55
|
opened = false;
|
|
56
|
+
// Reject any pending readers with a TransportClosed-shaped error
|
|
57
|
+
// so the read loop can exit cleanly.
|
|
58
|
+
while (waiters.length > 0) {
|
|
59
|
+
const waiter = waiters.shift();
|
|
60
|
+
if (waiter) {
|
|
61
|
+
const err = new Error('Transport closed');
|
|
62
|
+
err.name = 'TransportClosedError';
|
|
63
|
+
// The mock's transferIn signals via the resolved Promise — to
|
|
64
|
+
// surface a rejection, route via the waiter as a thrown call.
|
|
65
|
+
// Using a sentinel "empty" frame works because the read loop
|
|
66
|
+
// checks `transport.connected` which flips to false on close.
|
|
67
|
+
waiter(new Uint8Array(0));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
43
70
|
return Promise.resolve();
|
|
44
71
|
}),
|
|
45
72
|
selectConfiguration: vi.fn(() => Promise.resolve()),
|
|
@@ -48,18 +75,40 @@ export function createMockUSBDevice(overrides) {
|
|
|
48
75
|
transferOut: vi.fn((endpointNumber, data) => {
|
|
49
76
|
const array = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
50
77
|
transfers.push({ endpointNumber, data: Uint8Array.from(array) });
|
|
78
|
+
// Brother ESC iS = `1B 69 53`. Enqueue a response copy.
|
|
79
|
+
if (array.length >= 3 && array[0] === 0x1b && array[1] === 0x69 && array[2] === 0x53) {
|
|
80
|
+
enqueue(Uint8Array.from(statusBytes));
|
|
81
|
+
}
|
|
51
82
|
return Promise.resolve({ bytesWritten: array.byteLength, status: 'ok' });
|
|
52
83
|
}),
|
|
53
84
|
transferIn: vi.fn((_endpointNumber, length) => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
85
|
+
// Drain any pre-queued frames first.
|
|
86
|
+
const next = frameQueue.shift();
|
|
87
|
+
if (next) {
|
|
88
|
+
const out = new Uint8Array(length);
|
|
89
|
+
out.set(next.subarray(0, length));
|
|
90
|
+
return Promise.resolve({
|
|
91
|
+
data: new DataView(out.buffer),
|
|
92
|
+
status: 'ok',
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// Park as a waiter; resolve when a future frame is enqueued.
|
|
96
|
+
return new Promise(resolve => {
|
|
97
|
+
waiters.push(frame => {
|
|
98
|
+
const out = new Uint8Array(length);
|
|
99
|
+
out.set(frame.subarray(0, Math.min(length, frame.length)));
|
|
100
|
+
resolve({
|
|
101
|
+
data: new DataView(out.buffer, 0, frame.length),
|
|
102
|
+
status: 'ok',
|
|
103
|
+
});
|
|
104
|
+
});
|
|
59
105
|
});
|
|
60
106
|
}),
|
|
61
107
|
__transfers: transfers,
|
|
62
108
|
__statusBytes: statusBytes,
|
|
109
|
+
__pushUnsolicited: (frame) => {
|
|
110
|
+
enqueue(Uint8Array.from(frame));
|
|
111
|
+
},
|
|
63
112
|
};
|
|
64
113
|
return device;
|
|
65
114
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webusb-mock.js","sourceRoot":"","sources":["../../src/__tests__/webusb-mock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"webusb-mock.js","sourceRoot":"","sources":["../../src/__tests__/webusb-mock.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
export { DEFAULT_FILTERS, WebBrotherQLPrinter,
|
|
1
|
+
export { DEFAULT_FILTERS, WebBrotherQLPrinter, type RequestOptions } from './printer.js';
|
|
2
|
+
export { fromUSBDevice, fromUSBDeviceAll, requestPrinter, requestPrintersUsbLegacy, } from './printer.js';
|
|
3
|
+
export { devicesForTransport, requestPrinters } from './request-printers.js';
|
|
4
|
+
export type { ConnectOptions, PrinterAdapterMap } from '@thermal-label/contracts';
|
|
5
|
+
export { DeviceIdentificationRequiredError } from '@thermal-label/contracts';
|
|
2
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAGzF,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,wBAAwB,GACzB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7E,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClF,OAAO,EAAE,iCAAiC,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
export { DEFAULT_FILTERS, WebBrotherQLPrinter
|
|
1
|
+
export { DEFAULT_FILTERS, WebBrotherQLPrinter } from './printer.js';
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-deprecated -- legacy factories re-exported during plan-10 transition */
|
|
3
|
+
export { fromUSBDevice, fromUSBDeviceAll, requestPrinter, requestPrintersUsbLegacy, } from './printer.js';
|
|
4
|
+
/* eslint-enable @typescript-eslint/no-deprecated */
|
|
5
|
+
export { devicesForTransport, requestPrinters } from './request-printers.js';
|
|
6
|
+
export { DeviceIdentificationRequiredError } from '@thermal-label/contracts';
|
|
2
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAuB,MAAM,cAAc,CAAC;AAEzF,+GAA+G;AAC/G,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,wBAAwB,GACzB,MAAM,cAAc,CAAC;AACtB,oDAAoD;AAEpD,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAG7E,OAAO,EAAE,iCAAiC,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/printer.d.ts
CHANGED
|
@@ -15,13 +15,69 @@ export declare class WebBrotherQLPrinter implements PrinterAdapter {
|
|
|
15
15
|
readonly device: BrotherQLDevice;
|
|
16
16
|
private readonly transport;
|
|
17
17
|
private lastStatus;
|
|
18
|
+
private readonly statusListeners;
|
|
19
|
+
private readLoopStarted;
|
|
20
|
+
private readLoopStopped;
|
|
21
|
+
/**
|
|
22
|
+
* Serialises every bulk-OUT operation (print + getStatus). Required
|
|
23
|
+
* because `getStatus()` may write the QL preamble (`buildInvalidate` —
|
|
24
|
+
* 200×0x00 + `ESC @`) to put the parser in a known state, and the
|
|
25
|
+
* preamble's "invalidate" cancels any in-flight print job. Polling
|
|
26
|
+
* concurrently with a print would shred the raster stream.
|
|
27
|
+
*
|
|
28
|
+
* Plan 15 A4: this was a hand-rolled `writeLock`/`runLocked` pair;
|
|
29
|
+
* it is now the shared `WriteSerializer` from `@thermal-label/contracts`
|
|
30
|
+
* so all four drivers serialise identically. Behaviour is unchanged —
|
|
31
|
+
* `WriteSerializer.run()` is exactly the old `runLocked` semantics.
|
|
32
|
+
*/
|
|
33
|
+
private readonly serializer;
|
|
34
|
+
/**
|
|
35
|
+
* Whether the printer's command parser is in a known-clean state.
|
|
36
|
+
* Set to `true` after a successful `getStatus()`; flipped back to
|
|
37
|
+
* `false` on timeout so the next attempt re-sends the preamble. The
|
|
38
|
+
* preamble (200-byte invalidate + `ESC @`) is only needed once per
|
|
39
|
+
* session unless the parser falls back into a confused state.
|
|
40
|
+
*/
|
|
41
|
+
private parserReady;
|
|
18
42
|
constructor(device: BrotherQLDevice, transport: Transport);
|
|
19
43
|
get model(): string;
|
|
20
44
|
get connected(): boolean;
|
|
21
45
|
print(image: RawImageData, media?: MediaDescriptor, options?: BrotherQLPrintOptions): Promise<void>;
|
|
22
46
|
private writeChunked;
|
|
23
47
|
createPreview(image: RawImageData, options?: PreviewOptions): Promise<PreviewResult>;
|
|
48
|
+
/**
|
|
49
|
+
* Send ESC iS and resolve with the next status frame the printer
|
|
50
|
+
* emits. The read loop is the sole reader of the bulk-IN pipe —
|
|
51
|
+
* `getStatus()` subscribes transiently, writes the request, and the
|
|
52
|
+
* subscription receives the response (alongside any spontaneous
|
|
53
|
+
* frames; see `onStatus()`).
|
|
54
|
+
*
|
|
55
|
+
* The QL preamble (200×0x00 invalidate + `ESC @` initialize) is
|
|
56
|
+
* sent only when the parser hasn't been confirmed clean — first
|
|
57
|
+
* call of the session, or after a previous timeout. Steady-state
|
|
58
|
+
* polls send bare `ESC iS`. Bench observation: a freshly-opened QL
|
|
59
|
+
* doesn't reply to bare `ESC iS` until the invalidate flushes any
|
|
60
|
+
* stale parser state from a prior session.
|
|
61
|
+
*/
|
|
24
62
|
getStatus(): Promise<BrotherQLStatus>;
|
|
63
|
+
/**
|
|
64
|
+
* Subscribe to status updates. A polling shim built on
|
|
65
|
+
* `pollingOnStatus` from contracts — it calls `getStatus()` on first
|
|
66
|
+
* subscribe and then every `DEFAULT_POLLING_INTERVAL_MS`, matching the
|
|
67
|
+
* labelwriter and labelmanager web drivers (plan 11 §`onStatus`
|
|
68
|
+
* parity).
|
|
69
|
+
*
|
|
70
|
+
* An earlier revision skipped polling and relied solely on the
|
|
71
|
+
* printer's unsolicited frames. That was a workaround for the Chromium
|
|
72
|
+
* WebUSB sub-packet stall — `getStatus()`'s `read()` would hang, so
|
|
73
|
+
* polling looked unreliable and was dropped. `WebUsbTransport.read()`
|
|
74
|
+
* now rounds reads up to the endpoint packet size, so `getStatus()` is
|
|
75
|
+
* dependable and polling is restored.
|
|
76
|
+
*/
|
|
77
|
+
onStatus(cb: (status: BrotherQLStatus) => void): () => void;
|
|
78
|
+
private nextStatusFrame;
|
|
79
|
+
private startReadLoop;
|
|
80
|
+
private readLoop;
|
|
25
81
|
close(): Promise<void>;
|
|
26
82
|
}
|
|
27
83
|
export declare const DEFAULT_FILTERS: USBDeviceFilter[];
|
|
@@ -30,12 +86,49 @@ export declare const DEFAULT_FILTERS: USBDeviceFilter[];
|
|
|
30
86
|
*
|
|
31
87
|
* Requires a user gesture. Opens the device and claims interface 0 via
|
|
32
88
|
* `WebUsbTransport.fromDevice()`.
|
|
89
|
+
*
|
|
90
|
+
* Single-instance entry point — preserved for back-compat with existing
|
|
91
|
+
* consumers (CLIs, ad-hoc scripts). For the symmetric driver-web shape
|
|
92
|
+
* (1-key map keyed by engine role) call `requestPrinters()` instead;
|
|
93
|
+
* the harness shell uses that path.
|
|
94
|
+
*
|
|
95
|
+
* @deprecated Use `requestPrinters({ transport: 'usb' })` from
|
|
96
|
+
* `./request-printers.ts`. Removed once consumers migrate (plan 11).
|
|
33
97
|
*/
|
|
34
98
|
export declare function requestPrinter(options?: RequestOptions): Promise<WebBrotherQLPrinter>;
|
|
99
|
+
/**
|
|
100
|
+
* Show the browser's USB picker and return one `PrinterAdapter` per
|
|
101
|
+
* drivable engine on the selected device, keyed by engine role.
|
|
102
|
+
*
|
|
103
|
+
* Brother QL devices are always single-engine — this returns a 1-key
|
|
104
|
+
* record keyed by the device's `engines[0].role` (typically `'primary'`).
|
|
105
|
+
*
|
|
106
|
+
* @deprecated Use the generic `requestPrinters({ transport: 'usb' })`
|
|
107
|
+
* from `./request-printers.ts` — the legacy USB-only name is preserved
|
|
108
|
+
* as `requestPrintersUsbLegacy` for back-compat. Removed once
|
|
109
|
+
* consumers migrate (plan 11).
|
|
110
|
+
*/
|
|
111
|
+
export declare function requestPrintersUsbLegacy(options?: RequestOptions): Promise<Record<string, WebBrotherQLPrinter>>;
|
|
35
112
|
/**
|
|
36
113
|
* Wrap an already-selected `USBDevice`.
|
|
37
114
|
*
|
|
38
115
|
* @throws when the VID/PID is not in the Brother QL registry.
|
|
116
|
+
*
|
|
117
|
+
* @deprecated Use `requestPrinters({ transport: 'usb' })` from
|
|
118
|
+
* `./request-printers.ts`. Removed once consumers migrate (plan 11).
|
|
39
119
|
*/
|
|
40
120
|
export declare function fromUSBDevice(usbDevice: USBDevice): Promise<WebBrotherQLPrinter>;
|
|
121
|
+
/**
|
|
122
|
+
* Wrap an already-selected `USBDevice` and return a 1-key adapter map
|
|
123
|
+
* keyed by the device's `engines[0].role`. Public surface for
|
|
124
|
+
* `requestPrinters()`; exported so harnesses that already hold a
|
|
125
|
+
* `USBDevice` (e.g. picked-up via `navigator.usb.getDevices()` on a
|
|
126
|
+
* returning visit) can skip the picker.
|
|
127
|
+
*
|
|
128
|
+
* Brother QL is single-engine and single-interface (IF 0).
|
|
129
|
+
*
|
|
130
|
+
* @deprecated Use `requestPrinters({ transport: 'usb' })` from
|
|
131
|
+
* `./request-printers.ts`. Removed once consumers migrate (plan 11).
|
|
132
|
+
*/
|
|
133
|
+
export declare function fromUSBDeviceAll(usbDevice: USBDevice): Promise<Record<string, WebBrotherQLPrinter>>;
|
|
41
134
|
//# sourceMappingURL=printer.d.ts.map
|
package/dist/printer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"printer.d.ts","sourceRoot":"","sources":["../src/printer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"printer.d.ts","sourceRoot":"","sources":["../src/printer.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EACV,eAAe,EAEf,qBAAqB,EACrB,eAAe,EAEf,eAAe,EAEf,cAAc,EACd,aAAa,EACb,cAAc,EACd,YAAY,EACZ,SAAS,EACV,MAAM,gCAAgC,CAAC;AA4BxC,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,qBAAa,mBAAoB,YAAW,cAAc;IACxD,QAAQ,CAAC,MAAM,eAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IAEjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgD;IAChF,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,eAAe,CAAS;IAChC;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD;;;;;;OAMG;IACH,OAAO,CAAC,WAAW,CAAS;gBAEhB,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,SAAS;IAMzD,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAEK,KAAK,CACT,KAAK,EAAE,YAAY,EACnB,KAAK,CAAC,EAAE,eAAe,EACvB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,IAAI,CAAC;YAgDF,YAAY;IAU1B,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAWpF;;;;;;;;;;;;;OAaG;IACG,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC;IAqB3C;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI;IAI3D,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,aAAa;YAOP,QAAQ;IAuChB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B;AAED,eAAO,MAAM,eAAe,EAAE,eAAe,EAGmC,CAAC;AAEjF;;;;;;;;;;;;;GAaG;AACH,wBAAsB,cAAc,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAK/F;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAK9C;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAStF;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAc9C"}
|