@thermal-label/brother-ql-web 0.0.1 → 0.3.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.
@@ -1,156 +1,175 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import { WebBrotherQLPrinter, openWebDevice } from '../printer.js';
3
- import { DEVICES, findMedia } from '@thermal-label/brother-ql-core';
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { MediaNotSpecifiedError } from '@thermal-label/contracts';
3
+ import { DEVICES, MEDIA } from '@thermal-label/brother-ql-core';
4
+ import { fromUSBDevice, requestPrinter } from '../printer.js';
4
5
  import { createMockUSBDevice } from './webusb-mock.js';
5
- const media62mm = findMedia(259);
6
- function makeImageData(width = 10, height = 10) {
7
- return { width, height, data: new Uint8ClampedArray(width * height * 4) };
6
+ function solidRgba(width, height) {
7
+ return { width, height, data: new Uint8Array(width * height * 4).fill(0) };
8
+ }
9
+ function redRgba(width, height) {
10
+ const data = new Uint8Array(width * height * 4);
11
+ for (let i = 0; i < data.length; i += 4) {
12
+ data[i] = 255;
13
+ data[i + 1] = 0;
14
+ data[i + 2] = 0;
15
+ data[i + 3] = 255;
16
+ }
17
+ return { width, height, data };
8
18
  }
9
19
  describe('WebBrotherQLPrinter', () => {
10
- let mock;
11
- beforeEach(() => {
12
- mock = createMockUSBDevice({ productId: 0x20a7 }); // QL-820NWB
13
- });
14
- afterEach(() => {
15
- vi.unstubAllGlobals();
16
- });
17
- it('openWebDevice opens and claims interface', async () => {
18
- const printer = await openWebDevice(mock.device);
19
- expect(mock.spies.open).toHaveBeenCalledOnce();
20
- expect(mock.spies.selectConfiguration).toHaveBeenCalledWith(1);
21
- expect(mock.spies.claimInterface).toHaveBeenCalledWith(0);
22
- expect(printer.descriptor.name).toBe('QL-820NWB');
23
- });
24
- it('openWebDevice throws for unknown device', async () => {
25
- const { device } = createMockUSBDevice({ vendorId: 0x04f9, productId: 0x9999 });
26
- await expect(openWebDevice(device)).rejects.toThrow('Unsupported device');
27
- });
28
- it('print writes encoded bytes via transferOut', async () => {
29
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
30
- const bitmap = { widthPx: 720, heightPx: 10, data: new Uint8Array(90 * 10) };
31
- await printer.print([{ bitmap, media: media62mm }]);
32
- expect(mock.spies.transferOut).toHaveBeenCalled();
33
- const bytes = mock.spies.transferOut.mock.calls[0]?.[1];
34
- // Job starts with ESC i a 01 (raster mode) then 200-byte invalidate
35
- expect(bytes[0]).toBe(0x1b);
36
- expect(bytes[1]).toBe(0x69);
37
- expect(bytes[2]).toBe(0x61);
38
- // Ends with 0x1A (print last page)
39
- expect(bytes.at(-1)).toBe(0x1a);
40
- });
41
- it('getStatus sends status request and parses response', async () => {
42
- const statusBytes = new Uint8Array(32);
43
- statusBytes[0] = 0x80;
44
- statusBytes[10] = 62; // 62mm media
45
- statusBytes[11] = 0x0a; // continuous
46
- mock.spies.transferIn.mockResolvedValueOnce({
47
- status: 'ok',
48
- data: new DataView(statusBytes.buffer),
49
- });
50
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
20
+ it('exposes adapter metadata for a QL-820NWB', async () => {
21
+ const device = createMockUSBDevice({ productId: 0x20a7 });
22
+ const printer = await fromUSBDevice(device);
23
+ expect(printer.family).toBe('brother-ql');
24
+ expect(printer.model).toBe('QL-820NWB');
25
+ expect(printer.device.twoColor).toBe(true);
26
+ expect(printer.connected).toBe(true);
27
+ });
28
+ it('print() splits two-colour images when media carries a palette', async () => {
29
+ const device = createMockUSBDevice({ productId: 0x20a7 });
30
+ const printer = await fromUSBDevice(device);
31
+ await printer.print(redRgba(64, 64), MEDIA[251]);
32
+ expect(device.__transfers.length).toBeGreaterThan(0);
33
+ });
34
+ it('createPreview() returns two planes on multi-ink media', async () => {
35
+ const device = createMockUSBDevice({ productId: 0x20a7 });
36
+ const printer = await fromUSBDevice(device);
37
+ const preview = await printer.createPreview(redRgba(64, 64), { media: MEDIA[251] });
38
+ expect(preview.planes.map(p => p.name)).toEqual(['black', 'red']);
39
+ expect(preview.assumed).toBe(false);
40
+ });
41
+ it('createPreview() returns one plane on single-ink media', async () => {
42
+ const device = createMockUSBDevice({ productId: 0x20a7 });
43
+ const printer = await fromUSBDevice(device);
44
+ const preview = await printer.createPreview(solidRgba(64, 64), { media: MEDIA[259] });
45
+ expect(preview.planes).toHaveLength(1);
46
+ });
47
+ it('createPreview() reuses detected media from a prior getStatus', async () => {
48
+ const bytes = new Uint8Array(32);
49
+ bytes[10] = 62;
50
+ bytes[11] = 0x0a;
51
+ const device = createMockUSBDevice({ productId: 0x20a7, statusBytes: bytes });
52
+ const printer = await fromUSBDevice(device);
53
+ await printer.getStatus();
54
+ const preview = await printer.createPreview(solidRgba(64, 64));
55
+ expect(preview.assumed).toBe(false);
56
+ expect(preview.media.id).toBe(259);
57
+ });
58
+ it('createPreview() falls back to DEFAULT_MEDIA with assumed=true', async () => {
59
+ const device = createMockUSBDevice({ productId: 0x20a7 });
60
+ const printer = await fromUSBDevice(device);
61
+ const preview = await printer.createPreview(solidRgba(64, 64));
62
+ expect(preview.assumed).toBe(true);
63
+ expect(preview.media.id).toBe(259);
64
+ });
65
+ it('close() releases the underlying USB device', async () => {
66
+ const device = createMockUSBDevice({ productId: 0x20a7 });
67
+ const printer = await fromUSBDevice(device);
68
+ await printer.close();
69
+ expect(device.opened).toBe(false);
70
+ expect(printer.connected).toBe(false);
71
+ });
72
+ it('print() writes an encoded raster job for single-ink media', async () => {
73
+ const device = createMockUSBDevice({ productId: 0x20a7 });
74
+ const printer = await fromUSBDevice(device);
75
+ await printer.print(solidRgba(64, 64), MEDIA[259]);
76
+ expect(device.__transfers.length).toBeGreaterThan(0);
77
+ });
78
+ it("print() auto-rotates landscape input on 'horizontal' die-cut media", async () => {
79
+ // MEDIA[271] = DK-11201 29×90, defaultOrientation: 'horizontal'.
80
+ // 800×200 landscape RGBA — auto-rotate kicks in. Bypass with
81
+ // `rotate: 0` for the comparison case; the auto path encodes more
82
+ // raster rows so the total transfer is larger.
83
+ const autoDevice = createMockUSBDevice({ productId: 0x20a7 });
84
+ const autoPrinter = await fromUSBDevice(autoDevice);
85
+ await autoPrinter.print(solidRgba(800, 200), MEDIA[271]);
86
+ const bypassDevice = createMockUSBDevice({ productId: 0x20a7 });
87
+ const bypassPrinter = await fromUSBDevice(bypassDevice);
88
+ await bypassPrinter.print(solidRgba(800, 200), MEDIA[271], { rotate: 0 });
89
+ const totalAuto = autoDevice.__transfers.reduce((acc, t) => acc + t.data.length, 0);
90
+ const totalBypass = bypassDevice.__transfers.reduce((acc, t) => acc + t.data.length, 0);
91
+ expect(totalAuto).toBeGreaterThan(totalBypass);
92
+ });
93
+ // See node printer.test.ts for the same helper — searches for a 3-byte
94
+ // raster-row header (opcode, colour, LEN=90).
95
+ function firstRasterRow(bytes, opcode, colour) {
96
+ for (let i = 0; i < bytes.length - 3 - 90; i++) {
97
+ if (bytes[i] === opcode && bytes[i + 1] === colour && bytes[i + 2] === 90) {
98
+ return bytes.slice(i + 3, i + 3 + 90);
99
+ }
100
+ }
101
+ throw new Error(`no raster row with opcode 0x${opcode.toString(16)} colour 0x${colour.toString(16)}`);
102
+ }
103
+ it('print() horizontally mirrors the rendered bitmap (single-colour)', async () => {
104
+ const device = createMockUSBDevice({ productId: 0x20a7 });
105
+ const printer = await fromUSBDevice(device);
106
+ const data = new Uint8Array(16 * 4).fill(0xff);
107
+ data[0] = 0;
108
+ data[1] = 0;
109
+ data[2] = 0;
110
+ await printer.print({ width: 16, height: 1, data }, MEDIA[259]);
111
+ const row = firstRasterRow(device.__transfers[0].data, 0x67, 0x00);
112
+ expect(row[3]).toBe(0x10);
113
+ expect(row[1]).toBe(0x00);
114
+ });
115
+ it('print() splits the job into ≤1 KB OUT-pipe chunks (firmware flow-control)', async () => {
116
+ const device = createMockUSBDevice({ productId: 0x20a7 });
117
+ const printer = await fromUSBDevice(device);
118
+ await printer.print(solidRgba(696, 120), MEDIA[251]);
119
+ expect(device.__transfers.length).toBeGreaterThan(1);
120
+ for (const t of device.__transfers) {
121
+ expect(t.data.length).toBeLessThanOrEqual(1024);
122
+ }
123
+ });
124
+ it('print() horizontally mirrors both planes on two-colour media', async () => {
125
+ const device = createMockUSBDevice({ productId: 0x20a7 });
126
+ const printer = await fromUSBDevice(device);
127
+ const data = new Uint8Array(16 * 4).fill(0xff);
128
+ data[0] = 255;
129
+ data[1] = 0;
130
+ data[2] = 0;
131
+ data[3] = 255;
132
+ await printer.print({ width: 16, height: 1, data }, MEDIA[251]);
133
+ const redRow = firstRasterRow(device.__transfers[0].data, 0x77, 0x02);
134
+ expect(redRow[3]).toBe(0x10);
135
+ expect(redRow[1]).toBe(0x00);
136
+ });
137
+ it('print() throws MediaNotSpecifiedError when media is missing', async () => {
138
+ const device = createMockUSBDevice({ productId: 0x20a7 });
139
+ const printer = await fromUSBDevice(device);
140
+ await expect(printer.print(solidRgba(64, 64))).rejects.toBeInstanceOf(MediaNotSpecifiedError);
141
+ });
142
+ it('getStatus returns BrotherQLStatus with detected media when present', async () => {
143
+ const bytes = new Uint8Array(32);
144
+ bytes[10] = 62;
145
+ bytes[11] = 0x0a;
146
+ const device = createMockUSBDevice({ productId: 0x20a7, statusBytes: bytes });
147
+ const printer = await fromUSBDevice(device);
51
148
  const status = await printer.getStatus();
52
- const outBytes = mock.spies.transferOut.mock.calls[0]?.[1];
53
- expect(outBytes).toEqual(new Uint8Array([0x1b, 0x69, 0x53]));
54
- expect(status.mediaWidthMm).toBe(62);
55
- expect(status.mediaType).toBe('continuous');
56
- });
57
- it('getStatus throws when no data is returned', async () => {
58
- mock.spies.transferIn.mockResolvedValueOnce({ status: 'ok', data: null });
59
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
60
- await expect(printer.getStatus()).rejects.toThrow('No status data received');
61
- });
62
- it('disconnect releases interface and closes device', async () => {
63
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
64
- await printer.disconnect();
65
- expect(mock.spies.releaseInterface).toHaveBeenCalledWith(0);
66
- expect(mock.spies.close).toHaveBeenCalledOnce();
67
- });
68
- it('isConnected reflects device opened state', async () => {
69
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
70
- expect(printer.isConnected()).toBe(false);
71
- await mock.device.open();
72
- expect(printer.isConnected()).toBe(true);
73
- });
74
- it('printText() renders text and sends to device', async () => {
75
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
76
- await printer.printText('hello', media62mm);
77
- expect(mock.spies.transferOut).toHaveBeenCalled();
78
- });
79
- it('printText() passes PageOptions through to print', async () => {
80
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
81
- await printer.printText('hi', media62mm, { autoCut: true });
82
- expect(mock.spies.transferOut).toHaveBeenCalled();
83
- });
84
- it('printText() forwards invert and scale options', async () => {
85
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
86
- await printer.printText('test', media62mm, { invert: true, scaleX: 2, scaleY: 2 });
87
- expect(mock.spies.transferOut).toHaveBeenCalled();
88
- });
89
- it('printImage() renders ImageData and sends to device', async () => {
90
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
91
- await printer.printImage(makeImageData(), media62mm);
92
- expect(mock.spies.transferOut).toHaveBeenCalled();
93
- });
94
- it('printImage() passes renderImage options', async () => {
95
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
96
- await printer.printImage(makeImageData(), media62mm, {
97
- threshold: 100,
98
- dither: true,
99
- invert: true,
149
+ expect(status.rawBytes.length).toBe(32);
150
+ expect(status.editorLiteMode).toBe(false);
151
+ expect(status.detectedMedia?.id).toBe(259);
152
+ });
153
+ it('throws for unknown USB devices', async () => {
154
+ const device = createMockUSBDevice({ vendorId: 0x1234, productId: 0x5678 });
155
+ await expect(fromUSBDevice(device)).rejects.toThrow('Unsupported USB device');
156
+ });
157
+ });
158
+ describe('requestPrinter', () => {
159
+ it('passes the brother-ql VID/PIDs to navigator.usb.requestDevice', async () => {
160
+ const device = createMockUSBDevice({ productId: 0x20a7 });
161
+ const requestDevice = vi.fn(() => Promise.resolve(device));
162
+ Object.defineProperty(globalThis, 'navigator', {
163
+ value: { usb: { requestDevice } },
164
+ configurable: true,
100
165
  });
101
- expect(mock.spies.transferOut).toHaveBeenCalled();
102
- });
103
- it('printImage() applies explicit rotation when provided', async () => {
104
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
105
- await printer.printImage(makeImageData(), media62mm, { rotate: 180 });
106
- expect(mock.spies.transferOut).toHaveBeenCalled();
107
- });
108
- it('printImage() passes PageOptions through to print', async () => {
109
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
110
- await printer.printImage(makeImageData(), media62mm, { autoCut: true });
111
- expect(mock.spies.transferOut).toHaveBeenCalled();
112
- });
113
- it('printImageURL() fetches URL and prints via canvas', async () => {
114
- const blobMock = new Blob();
115
- const bmpMock = { width: 10, height: 10 };
116
- const ctxMock = {
117
- drawImage: vi.fn(),
118
- getImageData: vi.fn().mockReturnValue(makeImageData()),
119
- };
120
- const canvasMock = { getContext: vi.fn().mockReturnValue(ctxMock) };
121
- vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ blob: vi.fn().mockResolvedValue(blobMock) }));
122
- vi.stubGlobal('createImageBitmap', vi.fn().mockResolvedValue(bmpMock));
123
- vi.stubGlobal('OffscreenCanvas', vi.fn().mockReturnValue(canvasMock));
124
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
125
- await printer.printImageURL('https://example.com/label.png', media62mm);
126
- expect(mock.spies.transferOut).toHaveBeenCalled();
127
- });
128
- it('printImageURL() throws when canvas context cannot be obtained', async () => {
129
- const blobMock = new Blob();
130
- const bmpMock = { width: 10, height: 10 };
131
- const canvasMock = { getContext: vi.fn().mockReturnValue(null) };
132
- vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ blob: vi.fn().mockResolvedValue(blobMock) }));
133
- vi.stubGlobal('createImageBitmap', vi.fn().mockResolvedValue(bmpMock));
134
- vi.stubGlobal('OffscreenCanvas', vi.fn().mockReturnValue(canvasMock));
135
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
136
- await expect(printer.printImageURL('https://example.com/label.png', media62mm)).rejects.toThrow('Could not get canvas context');
137
- });
138
- it('printTwoColor throws on non-two-color device', async () => {
139
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_700);
140
- const imgData = makeImageData();
141
- await expect(printer.printTwoColor(imgData, imgData, media62mm)).rejects.toThrow('does not support two-color');
142
- });
143
- it('printTwoColor() renders and prints both channels', async () => {
144
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
145
- const imgData = makeImageData();
146
- await printer.printTwoColor(imgData, imgData, media62mm);
147
- expect(mock.spies.transferOut).toHaveBeenCalled();
148
- });
149
- it('printTwoColor() passes options through to print', async () => {
150
- const printer = new WebBrotherQLPrinter(mock.device, DEVICES.QL_820NWB);
151
- const imgData = makeImageData();
152
- await printer.printTwoColor(imgData, imgData, media62mm, { autoCut: true });
153
- expect(mock.spies.transferOut).toHaveBeenCalled();
166
+ await requestPrinter();
167
+ expect(requestDevice).toHaveBeenCalledOnce();
168
+ const call = requestDevice.mock.calls[0][0];
169
+ const pids = call.filters.map(f => f.productId);
170
+ for (const d of Object.values(DEVICES)) {
171
+ expect(pids).toContain(d.pid);
172
+ }
154
173
  });
155
174
  });
156
175
  //# sourceMappingURL=printer.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"printer.test.js","sourceRoot":"","sources":["../../src/__tests__/printer.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"printer.test.js","sourceRoot":"","sources":["../../src/__tests__/printer.test.ts"],"names":[],"mappings":"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"}
@@ -1,21 +1,13 @@
1
- import { vi } from 'vitest';
2
- export interface MockUSBDeviceSpies {
3
- open: ReturnType<typeof vi.fn>;
4
- close: ReturnType<typeof vi.fn>;
5
- selectConfiguration: ReturnType<typeof vi.fn>;
6
- claimInterface: ReturnType<typeof vi.fn>;
7
- releaseInterface: ReturnType<typeof vi.fn>;
8
- transferOut: ReturnType<typeof vi.fn>;
9
- transferIn: ReturnType<typeof vi.fn>;
10
- }
11
- export interface MockUSBDevice {
12
- device: USBDevice;
13
- spies: MockUSBDeviceSpies;
1
+ export interface MockUSBDevice extends USBDevice {
2
+ __transfers: {
3
+ endpointNumber: number;
4
+ data: Uint8Array;
5
+ }[];
6
+ __statusBytes: Uint8Array;
14
7
  }
15
8
  export declare function createMockUSBDevice(overrides?: {
16
9
  vendorId?: number;
17
10
  productId?: number;
18
- serialNumber?: string;
19
11
  statusBytes?: Uint8Array;
20
12
  }): MockUSBDevice;
21
13
  //# 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":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE5B,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/B,KAAK,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAChC,mBAAmB,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9C,cAAc,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACzC,gBAAgB,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC3C,WAAW,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACtC,UAAU,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,kBAAkB,CAAC;CAC3B;AAED,wBAAgB,mBAAmB,CAAC,SAAS,CAAC,EAAE;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,UAAU,CAAC;CAC1B,GAAG,aAAa,CA8ChB"}
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;CAC3B;AAED,wBAAgB,mBAAmB,CAAC,SAAS,CAAC,EAAE;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,UAAU,CAAC;CAC1B,GAAG,aAAa,CAoEhB"}
@@ -1,44 +1,66 @@
1
1
  import { vi } from 'vitest';
2
2
  export function createMockUSBDevice(overrides) {
3
- const spies = {
4
- open: vi.fn().mockImplementation(() => Promise.resolve()),
5
- close: vi.fn().mockImplementation(() => Promise.resolve()),
6
- selectConfiguration: vi.fn().mockImplementation(() => Promise.resolve()),
7
- claimInterface: vi.fn().mockImplementation(() => Promise.resolve()),
8
- releaseInterface: vi.fn().mockImplementation(() => Promise.resolve()),
9
- transferOut: vi
10
- .fn()
11
- .mockImplementation(() => Promise.resolve({ bytesWritten: 0, status: 'ok' })),
12
- transferIn: vi.fn().mockImplementation(() => Promise.resolve({
13
- status: 'ok',
14
- data: new DataView((overrides?.statusBytes ?? new Uint8Array(32)).buffer),
15
- })),
16
- };
3
+ const transfers = [];
17
4
  let opened = false;
18
- spies.open.mockImplementation(() => {
19
- opened = true;
20
- return Promise.resolve();
21
- });
22
- spies.close.mockImplementation(() => {
23
- opened = false;
24
- return Promise.resolve();
25
- });
5
+ const endpoints = [
6
+ { endpointNumber: 2, direction: 'out' },
7
+ { endpointNumber: 1, direction: 'in' },
8
+ ];
9
+ const configuration = {
10
+ configurationValue: 1,
11
+ configurationName: null,
12
+ interfaces: [
13
+ {
14
+ interfaceNumber: 0,
15
+ alternate: {
16
+ alternateSetting: 0,
17
+ interfaceClass: 7,
18
+ interfaceSubclass: 1,
19
+ interfaceProtocol: 2,
20
+ interfaceName: null,
21
+ endpoints,
22
+ },
23
+ alternates: [],
24
+ claimed: false,
25
+ },
26
+ ],
27
+ };
28
+ const statusBytes = overrides?.statusBytes ?? new Uint8Array(32);
26
29
  const device = {
27
30
  vendorId: overrides?.vendorId ?? 0x04f9,
28
31
  productId: overrides?.productId ?? 0x20a7,
29
- serialNumber: overrides?.serialNumber,
30
- configuration: { interfaces: [{ interfaceNumber: 0, claimed: false }] },
32
+ serialNumber: undefined,
31
33
  get opened() {
32
34
  return opened;
33
35
  },
34
- open: spies.open,
35
- close: spies.close,
36
- selectConfiguration: spies.selectConfiguration,
37
- claimInterface: spies.claimInterface,
38
- releaseInterface: spies.releaseInterface,
39
- transferOut: spies.transferOut,
40
- transferIn: spies.transferIn,
36
+ configuration,
37
+ open: vi.fn(() => {
38
+ opened = true;
39
+ return Promise.resolve();
40
+ }),
41
+ close: vi.fn(() => {
42
+ opened = false;
43
+ return Promise.resolve();
44
+ }),
45
+ selectConfiguration: vi.fn(() => Promise.resolve()),
46
+ claimInterface: vi.fn(() => Promise.resolve()),
47
+ releaseInterface: vi.fn(() => Promise.resolve()),
48
+ transferOut: vi.fn((endpointNumber, data) => {
49
+ const array = data instanceof Uint8Array ? data : new Uint8Array(data);
50
+ transfers.push({ endpointNumber, data: Uint8Array.from(array) });
51
+ return Promise.resolve({ bytesWritten: array.byteLength, status: 'ok' });
52
+ }),
53
+ transferIn: vi.fn((_endpointNumber, length) => {
54
+ const out = new Uint8Array(length);
55
+ out.set(statusBytes.subarray(0, length));
56
+ return Promise.resolve({
57
+ data: new DataView(out.buffer),
58
+ status: 'ok',
59
+ });
60
+ }),
61
+ __transfers: transfers,
62
+ __statusBytes: statusBytes,
41
63
  };
42
- return { device, spies };
64
+ return device;
43
65
  }
44
66
  //# sourceMappingURL=webusb-mock.js.map
@@ -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;AAiB5B,MAAM,UAAU,mBAAmB,CAAC,SAKnC;IACC,MAAM,KAAK,GAAuB;QAChC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACzD,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAC1D,mBAAmB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACxE,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACnE,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrE,WAAW,EAAE,EAAE;aACZ,EAAE,EAAE;aACJ,kBAAkB,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/E,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAC1C,OAAO,CAAC,OAAO,CAAC;YACd,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE,IAAI,QAAQ,CAAC,CAAC,SAAS,EAAE,WAAW,IAAI,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;SAC1E,CAAC,CACH;KACF,CAAC;IAEF,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,GAAG,EAAE;QACjC,MAAM,GAAG,IAAI,CAAC;QACd,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAG,EAAE;QAClC,MAAM,GAAG,KAAK,CAAC;QACf,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG;QACb,QAAQ,EAAE,SAAS,EAAE,QAAQ,IAAI,MAAM;QACvC,SAAS,EAAE,SAAS,EAAE,SAAS,IAAI,MAAM;QACzC,YAAY,EAAE,SAAS,EAAE,YAAY;QACrC,aAAa,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE;QACvE,IAAI,MAAM;YACR,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;QAC9C,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;QACxC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,UAAU,EAAE,KAAK,CAAC,UAAU;KACL,CAAC;IAE1B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC3B,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,7 +1,2 @@
1
- export { WebBrotherQLPrinter } from './printer.js';
2
- export { requestPrinter, fromUSBDevice } from './request.js';
3
- export type { RequestOptions } from './request.js';
4
- export type { DeviceDescriptor, MediaDescriptor, PageData, PageOptions, JobOptions, PrinterStatus, TextPrintOptions, ImagePrintOptions, MediaType, } from '@thermal-label/brother-ql-core';
5
- export { DEVICES, MEDIA, findDevice, findMedia, findMediaByWidth, renderText, renderImage, rotateBitmap, } from '@thermal-label/brother-ql-core';
6
- export type { LabelBitmap, RawImageData } from '@thermal-label/brother-ql-core';
1
+ export { DEFAULT_FILTERS, WebBrotherQLPrinter, fromUSBDevice, requestPrinter, type RequestOptions, } from './printer.js';
7
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACR,WAAW,EACX,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,SAAS,GACV,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,OAAO,EACP,KAAK,EACL,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,YAAY,GACb,MAAM,gCAAgC,CAAC;AACxC,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,cAAc,EACd,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,2 @@
1
- export { WebBrotherQLPrinter } from './printer.js';
2
- export { requestPrinter, fromUSBDevice } from './request.js';
3
- export { DEVICES, MEDIA, findDevice, findMedia, findMediaByWidth, renderText, renderImage, rotateBitmap, } from '@thermal-label/brother-ql-core';
1
+ export { DEFAULT_FILTERS, WebBrotherQLPrinter, fromUSBDevice, requestPrinter, } from './printer.js';
4
2
  //# 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,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAe7D,OAAO,EACL,OAAO,EACP,KAAK,EACL,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,YAAY,GACb,MAAM,gCAAgC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,cAAc,GAEf,MAAM,cAAc,CAAC"}
package/dist/printer.d.ts CHANGED
@@ -1,16 +1,41 @@
1
- import { type DeviceDescriptor, type JobOptions, type MediaDescriptor, type PageData, type PageOptions, type PrinterStatus, type TextPrintOptions, type ImagePrintOptions } from '@thermal-label/brother-ql-core';
2
- export declare class WebBrotherQLPrinter {
3
- readonly device: USBDevice;
4
- readonly descriptor: DeviceDescriptor;
5
- constructor(device: USBDevice, descriptor: DeviceDescriptor);
6
- isConnected(): boolean;
7
- getStatus(): Promise<PrinterStatus>;
8
- print(pages: PageData[], options?: JobOptions): Promise<void>;
9
- printText(text: string, media: MediaDescriptor, options?: TextPrintOptions): Promise<void>;
10
- printImage(imageData: ImageData, media: MediaDescriptor, options?: ImagePrintOptions): Promise<void>;
11
- printImageURL(url: string, media: MediaDescriptor, options?: ImagePrintOptions): Promise<void>;
12
- printTwoColor(blackImageData: ImageData, redImageData: ImageData, media: MediaDescriptor, options?: PageOptions): Promise<void>;
13
- disconnect(): Promise<void>;
1
+ import type { BrotherQLDevice, BrotherQLPrintOptions, BrotherQLStatus, MediaDescriptor, PreviewOptions, PreviewResult, PrinterAdapter, RawImageData, Transport } from '@thermal-label/brother-ql-core';
2
+ export interface RequestOptions {
3
+ filters?: USBDeviceFilter[];
14
4
  }
15
- export declare function openWebDevice(device: USBDevice): Promise<WebBrotherQLPrinter>;
5
+ /**
6
+ * WebUSB `PrinterAdapter` for Brother QL printers.
7
+ *
8
+ * Mirrors the node driver's behaviour — `renderMultiPlaneImage()` runs
9
+ * internally when the resolved media carries a `palette`, and
10
+ * `pickRotation` auto-rotates landscape input on media tagged
11
+ * `defaultOrientation: 'horizontal'`.
12
+ */
13
+ export declare class WebBrotherQLPrinter implements PrinterAdapter {
14
+ readonly family: "brother-ql";
15
+ readonly device: BrotherQLDevice;
16
+ private readonly transport;
17
+ private lastStatus;
18
+ constructor(device: BrotherQLDevice, transport: Transport);
19
+ get model(): string;
20
+ get connected(): boolean;
21
+ print(image: RawImageData, media?: MediaDescriptor, options?: BrotherQLPrintOptions): Promise<void>;
22
+ private writeChunked;
23
+ createPreview(image: RawImageData, options?: PreviewOptions): Promise<PreviewResult>;
24
+ getStatus(): Promise<BrotherQLStatus>;
25
+ close(): Promise<void>;
26
+ }
27
+ export declare const DEFAULT_FILTERS: USBDeviceFilter[];
28
+ /**
29
+ * Show the browser's USB picker and wrap the selected device.
30
+ *
31
+ * Requires a user gesture. Opens the device and claims interface 0 via
32
+ * `WebUsbTransport.fromDevice()`.
33
+ */
34
+ export declare function requestPrinter(options?: RequestOptions): Promise<WebBrotherQLPrinter>;
35
+ /**
36
+ * Wrap an already-selected `USBDevice`.
37
+ *
38
+ * @throws when the VID/PID is not in the Brother QL registry.
39
+ */
40
+ export declare function fromUSBDevice(usbDevice: USBDevice): Promise<WebBrotherQLPrinter>;
16
41
  //# sourceMappingURL=printer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"printer.d.ts","sourceRoot":"","sources":["../src/printer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EAQvB,MAAM,gCAAgC,CAAC;AASxC,qBAAa,mBAAmB;IAC9B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;gBAE1B,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,gBAAgB;IAK3D,WAAW,IAAI,OAAO;IAIhB,SAAS,IAAI,OAAO,CAAC,aAAa,CAAC;IAOnC,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7D,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB1F,UAAU,CACd,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,eAAe,EACtB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC;IAuBV,aAAa,CACjB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,eAAe,EACtB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC;IAYV,aAAa,CACjB,cAAc,EAAE,SAAS,EACzB,YAAY,EAAE,SAAS,EACvB,KAAK,EAAE,eAAe,EACtB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,IAAI,CAAC;IAuBV,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAIlC;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAWnF"}
1
+ {"version":3,"file":"printer.d.ts","sourceRoot":"","sources":["../src/printer.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,eAAe,EAEf,qBAAqB,EACrB,eAAe,EAEf,eAAe,EAEf,cAAc,EACd,aAAa,EACb,cAAc,EACd,YAAY,EACZ,SAAS,EACV,MAAM,gCAAgC,CAAC;AAaxC,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;gBAEpC,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,SAAS;IAKzD,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;YA8BF,YAAY;IAU1B,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAW9E,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC;IAQrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B;AAED,eAAO,MAAM,eAAe,mBAA0C,CAAC;AAEvE;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAI/F;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAStF"}
package/dist/printer.js CHANGED
@@ -1,114 +1,119 @@
1
- import { encodeJob, findDevice, parseStatus, renderImage, renderText, rotateBitmap, STATUS_REQUEST, } from '@thermal-label/brother-ql-core';
2
- const BROTHER_VID = 0x04f9;
3
- const USB_INTERFACE = 0;
4
- const BULK_OUT_ENDPOINT = 2;
5
- const BULK_IN_ENDPOINT = 1;
1
+ import { DEFAULT_MEDIA, DEVICES, ROTATE_DIRECTION, STATUS_REQUEST, createPreviewOffline, encodeJob, findDevice, flipHorizontal, parseStatus, pickRotation, renderImage, renderMultiPlaneImage, } from '@thermal-label/brother-ql-core';
2
+ import { MediaNotSpecifiedError } from '@thermal-label/contracts';
3
+ import { buildUsbFilters } from '@thermal-label/transport';
4
+ import { WebUsbTransport } from '@thermal-label/transport/web';
6
5
  const STATUS_BYTE_COUNT = 32;
7
- const CONFIGURATION_VALUE = 1;
6
+ // Same OUT-pipe chunking as the Node driver — see packages/node/src/printer.ts
7
+ // for the rationale. WebUSB rides the same libusb-style bulk transfer path,
8
+ // so the firmware buffer-overrun risk is identical.
9
+ const USB_CHUNK_SIZE = 1024;
10
+ const USB_CHUNK_DELAY_MS = 20;
11
+ /**
12
+ * WebUSB `PrinterAdapter` for Brother QL printers.
13
+ *
14
+ * Mirrors the node driver's behaviour — `renderMultiPlaneImage()` runs
15
+ * internally when the resolved media carries a `palette`, and
16
+ * `pickRotation` auto-rotates landscape input on media tagged
17
+ * `defaultOrientation: 'horizontal'`.
18
+ */
8
19
  export class WebBrotherQLPrinter {
20
+ family = 'brother-ql';
9
21
  device;
10
- descriptor;
11
- constructor(device, descriptor) {
22
+ transport;
23
+ lastStatus;
24
+ constructor(device, transport) {
12
25
  this.device = device;
13
- this.descriptor = descriptor;
26
+ this.transport = transport;
14
27
  }
15
- isConnected() {
16
- return this.device.opened;
28
+ get model() {
29
+ return this.device.name;
17
30
  }
18
- async getStatus() {
19
- await this.device.transferOut(BULK_OUT_ENDPOINT, STATUS_REQUEST);
20
- const result = await this.device.transferIn(BULK_IN_ENDPOINT, STATUS_BYTE_COUNT);
21
- if (!result.data)
22
- throw new Error('No status data received');
23
- return parseStatus(new Uint8Array(result.data.buffer));
31
+ get connected() {
32
+ return this.transport.connected;
24
33
  }
25
- async print(pages, options) {
26
- const bytes = encodeJob(pages, options);
27
- await this.device.transferOut(BULK_OUT_ENDPOINT, bytes);
34
+ async print(image, media, options) {
35
+ const resolvedMedia = (media ?? this.lastStatus?.detectedMedia);
36
+ if (!resolvedMedia)
37
+ throw new MediaNotSpecifiedError();
38
+ const rotate = pickRotation(image, resolvedMedia, ROTATE_DIRECTION, options?.rotate);
39
+ // Brother QL print head: pin 0 (the first pin in each raster row) sits
40
+ // on the right side of the printed face when the leading edge is held
41
+ // up. Mirror the rendered bitmap so the input image's x-axis matches
42
+ // the printed x-axis. Verified on QL-820NWBc + DK-22251.
43
+ let page;
44
+ if (resolvedMedia.palette) {
45
+ const { black, red } = renderMultiPlaneImage(image, {
46
+ palette: resolvedMedia.palette,
47
+ rotate,
48
+ });
49
+ page = {
50
+ bitmap: flipHorizontal(black),
51
+ redBitmap: flipHorizontal(red),
52
+ media: resolvedMedia,
53
+ };
54
+ }
55
+ else {
56
+ const bitmap = flipHorizontal(renderImage(image, { dither: true, rotate }));
57
+ page = { bitmap, media: resolvedMedia };
58
+ }
59
+ const bytes = encodeJob([page]);
60
+ await this.writeChunked(bytes);
28
61
  }
29
- async printText(text, media, options) {
30
- const { invert, scaleX, scaleY, ...pageOptions } = options ?? {};
31
- const base = renderText(text, { scaleX: 1, scaleY: 1 });
32
- const autoScale = Math.max(1, Math.floor(media.printAreaDots / Math.max(base.widthPx, base.heightPx)));
33
- const rawBitmap = renderText(text, {
34
- ...(invert !== undefined ? { invert } : {}),
35
- scaleX: scaleX ?? autoScale,
36
- scaleY: scaleY ?? autoScale,
37
- });
38
- const bitmap = rotateBitmap(rawBitmap, 270);
39
- const page = {
40
- bitmap,
41
- media,
42
- ...(Object.keys(pageOptions).length > 0 ? { options: pageOptions } : {}),
43
- };
44
- await this.print([page]);
62
+ async writeChunked(bytes) {
63
+ for (let off = 0; off < bytes.length; off += USB_CHUNK_SIZE) {
64
+ const end = Math.min(off + USB_CHUNK_SIZE, bytes.length);
65
+ await this.transport.write(bytes.subarray(off, end));
66
+ if (end < bytes.length) {
67
+ await new Promise(r => setTimeout(r, USB_CHUNK_DELAY_MS));
68
+ }
69
+ }
45
70
  }
46
- async printImage(imageData, media, options) {
47
- const { threshold, dither, invert, rotate, ...pageOptions } = options ?? {};
48
- const rawImage = {
49
- width: imageData.width,
50
- height: imageData.height,
51
- data: new Uint8Array(imageData.data.buffer),
52
- };
53
- const rawBitmap = renderImage(rawImage, {
54
- ...(threshold !== undefined ? { threshold } : {}),
55
- ...(dither ? { dither: true } : {}),
56
- ...(invert ? { invert: true } : {}),
71
+ createPreview(image, options) {
72
+ const override = options?.media;
73
+ const detected = this.lastStatus?.detectedMedia;
74
+ if (override)
75
+ return Promise.resolve(createPreviewOffline(image, override));
76
+ if (detected)
77
+ return Promise.resolve(createPreviewOffline(image, detected));
78
+ return Promise.resolve({
79
+ ...createPreviewOffline(image, DEFAULT_MEDIA),
80
+ assumed: true,
57
81
  });
58
- const rotationAngle = rotate ?? 0;
59
- const bitmap = rotationAngle === 0 ? rotateBitmap(rawBitmap, 270) : rotateBitmap(rawBitmap, rotationAngle);
60
- const page = {
61
- bitmap,
62
- media,
63
- ...(Object.keys(pageOptions).length > 0 ? { options: pageOptions } : {}),
64
- };
65
- await this.print([page]);
66
82
  }
67
- async printImageURL(url, media, options) {
68
- const response = await fetch(url);
69
- const blob = await response.blob();
70
- const bmp = await createImageBitmap(blob);
71
- const canvas = new OffscreenCanvas(bmp.width, bmp.height);
72
- const ctx = canvas.getContext('2d');
73
- if (!ctx)
74
- throw new Error('Could not get canvas context');
75
- ctx.drawImage(bmp, 0, 0);
76
- const imageData = ctx.getImageData(0, 0, bmp.width, bmp.height);
77
- await this.printImage(imageData, media, options);
78
- }
79
- async printTwoColor(blackImageData, redImageData, media, options) {
80
- if (!this.descriptor.twoColor) {
81
- throw new Error(`Device ${this.descriptor.name} does not support two-color printing. ` +
82
- 'Use a QL-800, QL-810W, or QL-820NWB.');
83
- }
84
- const toRaw = (img) => ({
85
- width: img.width,
86
- height: img.height,
87
- data: new Uint8Array(img.data.buffer),
88
- });
89
- const blackBitmap = rotateBitmap(renderImage(toRaw(blackImageData)), 270);
90
- const redBitmap = rotateBitmap(renderImage(toRaw(redImageData)), 270);
91
- const page = {
92
- bitmap: blackBitmap,
93
- redBitmap,
94
- media,
95
- ...(options !== undefined ? { options } : {}),
96
- };
97
- await this.print([page]);
83
+ async getStatus() {
84
+ await this.transport.write(STATUS_REQUEST);
85
+ const bytes = await this.transport.read(STATUS_BYTE_COUNT);
86
+ const status = parseStatus(bytes);
87
+ this.lastStatus = status;
88
+ return status;
98
89
  }
99
- async disconnect() {
100
- await this.device.releaseInterface(USB_INTERFACE);
101
- await this.device.close();
90
+ async close() {
91
+ await this.transport.close();
102
92
  }
103
93
  }
104
- export async function openWebDevice(device) {
105
- const descriptor = findDevice(BROTHER_VID, device.productId);
94
+ export const DEFAULT_FILTERS = buildUsbFilters(Object.values(DEVICES));
95
+ /**
96
+ * Show the browser's USB picker and wrap the selected device.
97
+ *
98
+ * Requires a user gesture. Opens the device and claims interface 0 via
99
+ * `WebUsbTransport.fromDevice()`.
100
+ */
101
+ export async function requestPrinter(options = {}) {
102
+ const filters = options.filters ?? DEFAULT_FILTERS;
103
+ const usbDevice = await navigator.usb.requestDevice({ filters });
104
+ return fromUSBDevice(usbDevice);
105
+ }
106
+ /**
107
+ * Wrap an already-selected `USBDevice`.
108
+ *
109
+ * @throws when the VID/PID is not in the Brother QL registry.
110
+ */
111
+ export async function fromUSBDevice(usbDevice) {
112
+ const descriptor = findDevice(usbDevice.vendorId, usbDevice.productId);
106
113
  if (!descriptor) {
107
- throw new Error(`Unsupported device: VID=${BROTHER_VID.toString(16)} PID=${device.productId.toString(16)}`);
114
+ throw new Error(`Unsupported USB device: VID=0x${usbDevice.vendorId.toString(16)} PID=0x${usbDevice.productId.toString(16)}`);
108
115
  }
109
- await device.open();
110
- await device.selectConfiguration(CONFIGURATION_VALUE);
111
- await device.claimInterface(USB_INTERFACE);
112
- return new WebBrotherQLPrinter(device, descriptor);
116
+ const transport = await WebUsbTransport.fromDevice(usbDevice);
117
+ return new WebBrotherQLPrinter(descriptor, transport);
113
118
  }
114
119
  //# sourceMappingURL=printer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"printer.js","sourceRoot":"","sources":["../src/printer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"printer.js","sourceRoot":"","sources":["../src/printer.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.0.1",
3
+ "version": "0.3.0",
4
4
  "description": "WebUSB browser driver for Brother QL label printers",
5
5
  "keywords": [
6
6
  "brother",
@@ -44,21 +44,24 @@
44
44
  },
45
45
  "sideEffects": false,
46
46
  "main": "./dist/index.js",
47
- "types": "./src/index.ts",
47
+ "types": "./dist/index.d.ts",
48
48
  "exports": {
49
49
  ".": {
50
50
  "import": "./dist/index.js",
51
- "types": "./src/index.ts"
51
+ "types": "./dist/index.d.ts"
52
52
  }
53
53
  },
54
54
  "dependencies": {
55
- "@thermal-label/brother-ql-core": "0.0.1"
55
+ "@thermal-label/contracts": "^0.2.0",
56
+ "@thermal-label/transport": "^0.2.1",
57
+ "@thermal-label/brother-ql-core": "0.3.0"
56
58
  },
57
59
  "peerDependencies": {
58
60
  "typescript": ">=5.0"
59
61
  },
60
62
  "devDependencies": {
61
63
  "@mbtech-nl/tsconfig": "^1.0.0",
64
+ "@types/w3c-web-usb": "^1.0.0",
62
65
  "@vitest/coverage-v8": "^2.1.9",
63
66
  "jsdom": "^26.1.0",
64
67
  "typescript": "~5.5.0",
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=request.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"request.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/request.test.ts"],"names":[],"mappings":""}
@@ -1,57 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { DEVICES } from '@thermal-label/brother-ql-core';
3
- import { fromUSBDevice } from '../request.js';
4
- import { createMockUSBDevice } from './webusb-mock.js';
5
- const mockRequestDevice = vi.fn();
6
- Object.defineProperty(globalThis, 'navigator', {
7
- value: { usb: { requestDevice: mockRequestDevice } },
8
- writable: true,
9
- });
10
- beforeEach(() => {
11
- mockRequestDevice.mockClear();
12
- });
13
- describe('requestPrinter', () => {
14
- it('passes all known printer-class PIDs to requestDevice', async () => {
15
- const { device } = createMockUSBDevice({ productId: 0x20a7 });
16
- mockRequestDevice.mockResolvedValueOnce(device);
17
- const { requestPrinter } = await import('../request.js');
18
- await requestPrinter();
19
- expect(mockRequestDevice).toHaveBeenCalledOnce();
20
- const [opts] = mockRequestDevice.mock.calls[0];
21
- const pids = opts.filters.map(f => f.productId);
22
- for (const d of Object.values(DEVICES)) {
23
- expect(pids).toContain(d.pid);
24
- }
25
- });
26
- it('does not include mass-storage PIDs in filters', async () => {
27
- const { device } = createMockUSBDevice({ productId: 0x20a7 });
28
- mockRequestDevice.mockResolvedValueOnce(device);
29
- const { requestPrinter } = await import('../request.js');
30
- await requestPrinter();
31
- const [opts] = mockRequestDevice.mock.calls[0];
32
- const pids = opts.filters.map(f => f.productId);
33
- expect(pids).not.toContain(0x20aa);
34
- expect(pids).not.toContain(0x20ab);
35
- });
36
- it('uses custom filters when provided', async () => {
37
- const { device } = createMockUSBDevice({ productId: 0x20a7 });
38
- mockRequestDevice.mockResolvedValueOnce(device);
39
- const customFilters = [{ vendorId: 0x04f9, productId: 0x20a7 }];
40
- const { requestPrinter } = await import('../request.js');
41
- await requestPrinter({ filters: customFilters });
42
- const [opts] = mockRequestDevice.mock.calls[0];
43
- expect(opts.filters).toEqual(customFilters);
44
- });
45
- });
46
- describe('fromUSBDevice', () => {
47
- it('returns WebBrotherQLPrinter for known device', () => {
48
- const { device } = createMockUSBDevice({ productId: 0x20a7 });
49
- const printer = fromUSBDevice(device);
50
- expect(printer.descriptor.name).toBe('QL-820NWB');
51
- });
52
- it('throws for unknown product ID', () => {
53
- const { device } = createMockUSBDevice({ productId: 0x9999 });
54
- expect(() => fromUSBDevice(device)).toThrow('Unsupported device');
55
- });
56
- });
57
- //# sourceMappingURL=request.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"request.test.js","sourceRoot":"","sources":["../../src/__tests__/request.test.ts"],"names":[],"mappings":"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"}
package/dist/request.d.ts DELETED
@@ -1,7 +0,0 @@
1
- import { WebBrotherQLPrinter } from './printer.js';
2
- export interface RequestOptions {
3
- filters?: USBDeviceFilter[];
4
- }
5
- export declare function requestPrinter(options?: RequestOptions): Promise<WebBrotherQLPrinter>;
6
- export declare function fromUSBDevice(device: USBDevice): WebBrotherQLPrinter;
7
- //# sourceMappingURL=request.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../src/request.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAiB,MAAM,cAAc,CAAC;AAElE,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;CAC7B;AAMD,wBAAsB,cAAc,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAI3F;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,mBAAmB,CAMpE"}
package/dist/request.js DELETED
@@ -1,18 +0,0 @@
1
- import { DEVICES, findDevice } from '@thermal-label/brother-ql-core';
2
- import { WebBrotherQLPrinter, openWebDevice } from './printer.js';
3
- function defaultFilters() {
4
- return Object.values(DEVICES).map(d => ({ vendorId: d.vid, productId: d.pid }));
5
- }
6
- export async function requestPrinter(options) {
7
- const filters = options?.filters ?? defaultFilters();
8
- const device = await navigator.usb.requestDevice({ filters });
9
- return openWebDevice(device);
10
- }
11
- export function fromUSBDevice(device) {
12
- const descriptor = findDevice(0x04f9, device.productId);
13
- if (!descriptor) {
14
- throw new Error(`Unsupported device: productId=0x${device.productId.toString(16)}`);
15
- }
16
- return new WebBrotherQLPrinter(device, descriptor);
17
- }
18
- //# sourceMappingURL=request.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"request.js","sourceRoot":"","sources":["../src/request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAMlE,SAAS,cAAc;IACrB,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAwB;IAC3D,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,CAAC;IACrD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IAC9D,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAiB;IAC7C,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACxD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,mCAAmC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,IAAI,mBAAmB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AACrD,CAAC"}