label-printer 0.6.0 → 0.7.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 CHANGED
@@ -2,44 +2,192 @@
2
2
 
3
3
  > :warning: `label-printer` is still under heavy development and is subject to frequent API changes
4
4
 
5
- This package provides a js based implementation for variouse languages used for label printers
5
+ This package provides a TypeScript/JavaScript API to:
6
6
 
7
- ## Layers
7
+ - **Build labels** in a printer-language-independent way
8
+ - **Generate printer commands** (currently TSPL focused)
9
+ - **Find and talk to printers**
10
+ - **Browser**: via WebUSB
11
+ - **Node.js**: via USB and **automatic network discovery** (TCP/9100)
8
12
 
9
- The packages is logacally divided into multiple sub layers. These are not separate modules per say, but separated parts of the code that serve different purposes
13
+ ## Installation
10
14
 
11
- ### 1. Command Layer
15
+ ```bash
16
+ npm install label-printer
17
+ ```
18
+
19
+ ## Main exports
20
+
21
+ The library exposes three main areas:
22
+
23
+ - **Commands**: `import { Command } from "label-printer"`
24
+ - **Labels**: `import { Label } from "label-printer"`
25
+ - **Printers**: `import { PrinterService } from "label-printer"`
26
+
27
+ ## Runtime support (Browser vs Node)
28
+
29
+ ### Browser
30
+
31
+ - Uses **WebUSB** to communicate with USB label printers.
32
+ - Typical entry point: `PrinterService.requestPrinter()`.
33
+
34
+ ### Node.js
35
+
36
+ - Supports USB printing (where supported by the `usb` dependency).
37
+ - Supports **network printing over TCP** (raw printing, usually port `9100`).
38
+ - Supports **automatic network discovery**:
39
+ - First attempts Bonjour/mDNS discovery of printer-related services
40
+ - If Bonjour yields no candidates, falls back to a conservative private-subnet scan
41
+ - Every discovered candidate is **verified** by sending the TSPL identify command (`~!I`)
42
+
43
+ ## Printer layer
44
+
45
+ ### Discover printers
46
+
47
+ ```ts
48
+ import { PrinterService } from "label-printer"
49
+
50
+ const printers = await PrinterService.getPrinters()
51
+ if(printers.length === 0) {
52
+ throw new Error("No printers found")
53
+ }
54
+
55
+ const printer = printers[0]
56
+ ```
57
+
58
+ ### Request a printer (browser-focused)
59
+
60
+ ```ts
61
+ import { PrinterService } from "label-printer"
62
+
63
+ const printer = await PrinterService.requestPrinter()
64
+ if(!printer) throw new Error("No printer selected")
65
+ ```
66
+
67
+ ### Print or display a label
68
+
69
+ ```ts
70
+ import { Label } from "label-printer"
71
+
72
+ const label = new Label(50, 25)
73
+ // 1 label, 3mm gap
74
+ await printer.print(label, 1, 3)
75
+ // or
76
+ await printer.display(label)
12
77
 
13
- This layer provides a low lever wrapper for the different languages commands. Using this module, you can create commands that suite your needs the best or you can integrate this pacakge in your codebase
78
+ await printer.close()
79
+ ```
14
80
 
15
- #### TODO
81
+ ### Direct network usage (Node.js)
16
82
 
17
- - Finish implementing basic commands
18
- - Add example code
83
+ If you already know the printer IP and want to bypass discovery:
19
84
 
20
- ### 2. Label layer
85
+ ```ts
86
+ import TSPLPrinter from "label-printer/dist/printers/TSPLPrinter"
87
+ import NetworkDevice from "label-printer/dist/helpers/NetworkDevice"
21
88
 
22
- This layer provides a language independent API to construct a label (object representation) without any knowledge of the fine details of the printer the label will be printed on.
89
+ const printer = new TSPLPrinter(new NetworkDevice("192.168.100.31", 9100))
90
+ ```
23
91
 
24
- #### TODO
92
+ ## Device abstraction
25
93
 
26
- - Add example code
27
- - Implement layer
94
+ Commands write to a transport-agnostic `Device` interface. This enables the same printer and label APIs to work over different transports.
28
95
 
29
- ### 3. Printer layer
96
+ - **USB** device implementation is internal to `USBUtils`.
97
+ - **NetworkDevice** is a TCP implementation used in Node.js.
30
98
 
31
- This layer contains code to interact with printers
99
+ ## Label layer
32
100
 
33
- #### TODO
101
+ The label layer provides a language-independent way to construct labels, which can then be rendered to commands for the chosen printer language.
34
102
 
35
- - Add example code
36
- - Implement layer
103
+ ```ts
104
+ import { Label } from "label-printer"
37
105
 
38
- ## Documentation of supported languages
106
+ const label = new Label(50, 25)
107
+ // label.add(...fields)
108
+ ```
109
+
110
+ ## Supported languages
39
111
 
40
112
  - [TSPL](documentations/TSPL.pdf)
41
113
 
42
- ## Label fields
114
+ ## Fields
115
+
116
+ Fields live under `label-printer/dist/labels/fields` in the built output.
117
+
118
+ ### Text
119
+
120
+ Create a text field at (`x`, `y`) in **dots**.
121
+
122
+ ```ts
123
+ import { Label } from "label-printer/dist/labels"
124
+ import { Text } from "label-printer/dist/labels/fields"
125
+
126
+ const label = new Label(50, 25)
127
+
128
+ const text = new Text("Hello", 20, 20, true)
129
+ text.setSingleLine(200)
130
+
131
+ label.add(text)
132
+ ```
133
+
134
+ Text wrapping/clipping:
135
+
136
+ - `text.setSingleLine(width?)`
137
+ - `text.setMultiLine(width, height?)`
138
+
139
+ Formatted text (when `formatted = true`) supports basic tags:
140
+
141
+ - `<b>...</b>`: bold (uses weight `700`)
142
+ - `<i>...</i>`: italic
143
+ - `<u>...</u>`: underline
144
+ - `<s>...</s>`: strike
145
+
146
+ ### Line
147
+
148
+ Draw a line between two points (values in **dots**).
149
+
150
+ ```ts
151
+ import { Line } from "label-printer/dist/labels/fields"
152
+
153
+ label.add(new Line({ x: 10, y: 10 }, { x: 300, y: 10 }, 3))
154
+ ```
155
+
156
+ ### Image
157
+
158
+ Draw a black/white bitmap image. You can either provide a bitmap-like object directly,
159
+ or use the async helper to load/convert an image.
160
+
161
+ ```ts
162
+ import { Image } from "label-printer/dist/labels/fields"
163
+
164
+ const img = await Image.create("./logo.png", 10, 60, 200)
165
+ label.add(img)
166
+ ```
167
+
168
+ ### BarCode
169
+
170
+ Draw a barcode (TSPL-backed). Values are in **dots**.
171
+
172
+ ```ts
173
+ import { BarCode } from "label-printer/dist/labels/fields"
174
+
175
+ const barcode = new BarCode("123456789", 20, 120, "CODE128", 80)
176
+ barcode.setHumanReadable("bottom")
177
+ barcode.setRotation(0)
178
+
179
+ label.add(barcode)
180
+ ```
181
+
182
+ ### QRCode
183
+
184
+ Draw a QR code.
185
+
186
+ ```ts
187
+ import { QRCode } from "label-printer/dist/labels/fields"
188
+
189
+ label.add(new QRCode("https://example.com", 20, 220, 6))
190
+ ```
43
191
 
44
192
  ### Table
45
193
 
@@ -75,16 +223,88 @@ Sizing rules:
75
223
  - **If table size is not set**
76
224
  - Unspecified row/column sizes are measured from their content.
77
225
 
78
- # Usefull units:
226
+ ## Command layer
227
+
228
+ The command layer is the lowest level and represents printer-language-specific commands.
229
+
230
+ Most users will not need this directly. It is primarily used internally by `Label` to generate
231
+ print/display command sequences.
232
+
233
+ ## Public API summary
234
+
235
+ - **`Label`**
236
+ - Construct labels and add fields
237
+ - Generate language-specific print/display commands via printer layer
238
+ - **`PrinterService`**
239
+ - `getPrinters()`
240
+ - Browser: discovers accessible USB printers
241
+ - Node: discovers USB printers + network printers (Bonjour/mDNS, then subnet scan fallback)
242
+ - `requestPrinter()`
243
+ - Browser: prompts user for a USB device
244
+ - Node: selects first available USB device (may return `undefined`)
245
+ - **`Printer`**
246
+ - `print(label, sets, gap, copiesPerSet?, direction?, mirror?, gapOffset?)`
247
+ - `display(label, direction?, mirror?)`
248
+ - `close()`
249
+
250
+ ## Notes
251
+
252
+ ### Useful units
79
253
 
80
254
  - 1 pt = 1/72 inch
81
255
  - 1 dot = 1 / dpi
82
256
 
83
- # Notes
257
+ ### Fonts
258
+
259
+ There are two ways to use fonts:
260
+
261
+ 1. Use printer built-in fonts (by using `name: "default"`)
262
+ 2. Register and use custom fonts on a per-`Label` basis
263
+
264
+ #### Set a font on `Text` / `Table`
265
+
266
+ Fonts are configured using a `FontOption`:
267
+
268
+ ```ts
269
+ text.setFont({ name: "default", size: 10 })
270
+ // or
271
+ text.setFont({ name: "MyFont", size: 18, weight: 700, style: "normal" })
272
+ ```
273
+
274
+ - `size` is specified in **dots**.
275
+ - `weight` defaults to `400`.
276
+ - `style` defaults to `"normal"`.
277
+
278
+ #### Register a custom font on a `Label`
279
+
280
+ Registering fonts enables better text measurement (for wrapping) and ensures the font is uploaded
281
+ as part of the generated print/display command sequence.
282
+
283
+ ```ts
284
+ import { Label } from "label-printer/dist/labels"
285
+
286
+ const label = new Label(50, 25)
287
+
288
+ await label.registerFont({
289
+ name: "MyFont",
290
+ data: await (await fetch("/fonts/MyFont-Regular.ttf")).arrayBuffer(),
291
+ weight: 400,
292
+ style: "normal",
293
+ })
294
+
295
+ await label.registerFont({
296
+ name: "MyFont",
297
+ data: await (await fetch("/fonts/MyFont-Bold.ttf")).arrayBuffer(),
298
+ weight: 700,
299
+ style: "normal",
300
+ })
301
+ ```
302
+
303
+ Font notes:
84
304
 
85
- - If a font is not working, make sure the extension is TTF
86
- - If you want to use bold fonts, make sure you have one for weight 700
87
- - Regular font weight is 400
305
+ - If a font is not working, make sure the extension is **TTF**.
306
+ - If you want bold text, register a `weight: 700` variant.
307
+ - When using formatted text (`<b>...</b>`), the library will request `weight: 700`.
88
308
 
89
309
  # Update package
90
310
 
package/dist/index.d.mts CHANGED
@@ -1,54 +1,19 @@
1
1
  import { Font as Font$1 } from 'fontkit';
2
2
 
3
+ type DeviceReadResult = DataView | undefined;
3
4
  /**
4
- * Convenience wrapper for a web usb device
5
- * Its main purpose is to hide the details of the usb library from client code so in case
6
- * it needs to be switched, compatibility can be retained
5
+ * Transport-agnostic device interface.
6
+ *
7
+ * Implementations can represent a USB device (browser/node) or a network socket (node).
8
+ * Commands write to this interface so printers can be used over different transports.
7
9
  */
8
- declare class UsbDevice {
9
- private readonly device;
10
+ interface Device {
10
11
  get opened(): boolean;
11
- /**
12
- * All available endpoints
13
- */
14
- private get endpoints();
15
- /**
16
- * Endpoint for writing
17
- */
18
- private get outEndpoint();
19
- /**
20
- * Endpoint for reading
21
- */
22
- private get inEndpoint();
23
- constructor(device: USBDevice);
24
- /**
25
- * Open the device and claim its interface
26
- */
27
12
  openAndConfigure(): Promise<void>;
28
- /**
29
- * Closes the device
30
- */
31
13
  close(): Promise<void>;
32
- /**
33
- * Write data to an USB device
34
- * @param data Data to write
35
- */
36
14
  writeData(data: Uint8Array | ArrayBuffer): Promise<void>;
37
- /**
38
- * Writes a text to a device
39
- * @param text Text to write
40
- */
41
15
  writeString(text: string): Promise<void>;
42
- /**
43
- * Reads bytes from the usb device
44
- * @param length The max length of the incoming data.
45
- * @returns Bytes received as a DataView or undefined. If data is longer then `length`, undefined will be returned
46
- */
47
- readData(length: number): Promise<DataView | undefined>;
48
- /**
49
- * Reads data from the usb device and converts it to string
50
- * {@see readData}
51
- */
16
+ readData(length: number): Promise<DeviceReadResult>;
52
17
  readString(length: number): Promise<string | undefined>;
53
18
  }
54
19
 
@@ -63,10 +28,10 @@ declare abstract class Command {
63
28
  abstract get commandString(): string;
64
29
  print(fn: (command: string) => void): void;
65
30
  /**
66
- * Write the command data to a USB device
31
+ * Write the command data to a device
67
32
  * @param device Device to write to
68
33
  */
69
- write(device: UsbDevice): Promise<void>;
34
+ writeTo(device: Device): Promise<void>;
70
35
  /**
71
36
  * Byte representation of a newline
72
37
  */
@@ -76,18 +41,18 @@ declare abstract class Command {
76
41
  * @param data String representation of data
77
42
  * @param device Device to write to
78
43
  */
79
- protected writeString(data: string, device: UsbDevice): Promise<void>;
44
+ protected writeString(data: string, device: Device): Promise<void>;
80
45
  /**
81
46
  * Writes bytes to a device. It will automatically end a command with @see{commandTerminatorBytes}
82
47
  * @param data Byte array to send
83
48
  * @param device Device to write to
84
49
  */
85
- protected writeBytes(data: Uint8Array | ArrayBuffer, device: UsbDevice): Promise<void>;
50
+ protected writeBytes(data: Uint8Array | ArrayBuffer, device: Device): Promise<void>;
86
51
  /**
87
52
  * Write the command terminator to the device
88
53
  * @param device
89
54
  */
90
- protected terminateCommand(device: UsbDevice): Promise<void>;
55
+ protected terminateCommand(device: Device): Promise<void>;
91
56
  }
92
57
 
93
58
  /**
@@ -99,7 +64,7 @@ declare abstract class CommandGroup<T extends Command> extends Command {
99
64
  private commands;
100
65
  constructor(commands: T[]);
101
66
  print(fn: (command: string) => void): void;
102
- write(device: UsbDevice): Promise<void>;
67
+ writeTo(device: Device): Promise<void>;
103
68
  get commandString(): string;
104
69
  }
105
70
 
@@ -216,7 +181,7 @@ declare class TSPLBitmapCommand extends TSPLVisualCommand {
216
181
  get commandString(): string;
217
182
  private get commandWithoutBytes();
218
183
  private get modeValue();
219
- write(device: UsbDevice): Promise<void>;
184
+ writeTo(device: Device): Promise<void>;
220
185
  /**
221
186
  * Create a new bitmap command for the given image url
222
187
  * @param image Image to create command for
@@ -401,7 +366,7 @@ declare class TSPLDownload extends TSPLCommand {
401
366
  */
402
367
  constructor(fileName: string, data: Data);
403
368
  get commandString(): string;
404
- write(device: UsbDevice): Promise<void>;
369
+ writeTo(device: Device): Promise<void>;
405
370
  }
406
371
 
407
372
  type DisplayType = "CLS" | "IMAGE" | "OFF";
@@ -842,7 +807,7 @@ declare namespace index$1 {
842
807
  * Base class that encapsulates functionality of all printers
843
808
  */
844
809
  declare abstract class Printer {
845
- private readonly usbDevice;
810
+ private readonly device;
846
811
  /**
847
812
  * Printer language used by the type of printer the subclass represents
848
813
  */
@@ -851,7 +816,7 @@ declare abstract class Printer {
851
816
  * When called, it will feed the labels to the beginig of the next label
852
817
  */
853
818
  abstract feedLabel(): Promise<void>;
854
- constructor(device: UsbDevice);
819
+ constructor(device: Device);
855
820
  /**
856
821
  * Close the printer USB
857
822
  */
@@ -875,7 +840,7 @@ declare abstract class Printer {
875
840
  * Check if the device is indeed a printer
876
841
  * @param device
877
842
  */
878
- static try(_device: UsbDevice): Promise<boolean>;
843
+ static try(_device: Device): Promise<boolean>;
879
844
  }
880
845
 
881
846
  declare class PrinterService {
@@ -884,7 +849,17 @@ declare class PrinterService {
884
849
  * @param device
885
850
  * @returns
886
851
  */
887
- static printerForDevice(device: UsbDevice): Promise<Printer | undefined>;
852
+ static printerForDevice(device: Device): Promise<Printer | undefined>;
853
+ /**
854
+ * Discover devices using printer-specific discovery hooks.
855
+ *
856
+ * Each printer class may optionally implement `static discoverDevices(): Promise<Device[]>`
857
+ * to find candidates over non-USB transports.
858
+ *
859
+ * Candidates returned here are still verified by `printerForDevice` via the printer
860
+ * class' `try(device)` method.
861
+ */
862
+ private static discoverDevices;
888
863
  /**
889
864
  * @returns List of available printers
890
865
  */
package/dist/index.d.ts CHANGED
@@ -1,54 +1,19 @@
1
1
  import { Font as Font$1 } from 'fontkit';
2
2
 
3
+ type DeviceReadResult = DataView | undefined;
3
4
  /**
4
- * Convenience wrapper for a web usb device
5
- * Its main purpose is to hide the details of the usb library from client code so in case
6
- * it needs to be switched, compatibility can be retained
5
+ * Transport-agnostic device interface.
6
+ *
7
+ * Implementations can represent a USB device (browser/node) or a network socket (node).
8
+ * Commands write to this interface so printers can be used over different transports.
7
9
  */
8
- declare class UsbDevice {
9
- private readonly device;
10
+ interface Device {
10
11
  get opened(): boolean;
11
- /**
12
- * All available endpoints
13
- */
14
- private get endpoints();
15
- /**
16
- * Endpoint for writing
17
- */
18
- private get outEndpoint();
19
- /**
20
- * Endpoint for reading
21
- */
22
- private get inEndpoint();
23
- constructor(device: USBDevice);
24
- /**
25
- * Open the device and claim its interface
26
- */
27
12
  openAndConfigure(): Promise<void>;
28
- /**
29
- * Closes the device
30
- */
31
13
  close(): Promise<void>;
32
- /**
33
- * Write data to an USB device
34
- * @param data Data to write
35
- */
36
14
  writeData(data: Uint8Array | ArrayBuffer): Promise<void>;
37
- /**
38
- * Writes a text to a device
39
- * @param text Text to write
40
- */
41
15
  writeString(text: string): Promise<void>;
42
- /**
43
- * Reads bytes from the usb device
44
- * @param length The max length of the incoming data.
45
- * @returns Bytes received as a DataView or undefined. If data is longer then `length`, undefined will be returned
46
- */
47
- readData(length: number): Promise<DataView | undefined>;
48
- /**
49
- * Reads data from the usb device and converts it to string
50
- * {@see readData}
51
- */
16
+ readData(length: number): Promise<DeviceReadResult>;
52
17
  readString(length: number): Promise<string | undefined>;
53
18
  }
54
19
 
@@ -63,10 +28,10 @@ declare abstract class Command {
63
28
  abstract get commandString(): string;
64
29
  print(fn: (command: string) => void): void;
65
30
  /**
66
- * Write the command data to a USB device
31
+ * Write the command data to a device
67
32
  * @param device Device to write to
68
33
  */
69
- write(device: UsbDevice): Promise<void>;
34
+ writeTo(device: Device): Promise<void>;
70
35
  /**
71
36
  * Byte representation of a newline
72
37
  */
@@ -76,18 +41,18 @@ declare abstract class Command {
76
41
  * @param data String representation of data
77
42
  * @param device Device to write to
78
43
  */
79
- protected writeString(data: string, device: UsbDevice): Promise<void>;
44
+ protected writeString(data: string, device: Device): Promise<void>;
80
45
  /**
81
46
  * Writes bytes to a device. It will automatically end a command with @see{commandTerminatorBytes}
82
47
  * @param data Byte array to send
83
48
  * @param device Device to write to
84
49
  */
85
- protected writeBytes(data: Uint8Array | ArrayBuffer, device: UsbDevice): Promise<void>;
50
+ protected writeBytes(data: Uint8Array | ArrayBuffer, device: Device): Promise<void>;
86
51
  /**
87
52
  * Write the command terminator to the device
88
53
  * @param device
89
54
  */
90
- protected terminateCommand(device: UsbDevice): Promise<void>;
55
+ protected terminateCommand(device: Device): Promise<void>;
91
56
  }
92
57
 
93
58
  /**
@@ -99,7 +64,7 @@ declare abstract class CommandGroup<T extends Command> extends Command {
99
64
  private commands;
100
65
  constructor(commands: T[]);
101
66
  print(fn: (command: string) => void): void;
102
- write(device: UsbDevice): Promise<void>;
67
+ writeTo(device: Device): Promise<void>;
103
68
  get commandString(): string;
104
69
  }
105
70
 
@@ -216,7 +181,7 @@ declare class TSPLBitmapCommand extends TSPLVisualCommand {
216
181
  get commandString(): string;
217
182
  private get commandWithoutBytes();
218
183
  private get modeValue();
219
- write(device: UsbDevice): Promise<void>;
184
+ writeTo(device: Device): Promise<void>;
220
185
  /**
221
186
  * Create a new bitmap command for the given image url
222
187
  * @param image Image to create command for
@@ -401,7 +366,7 @@ declare class TSPLDownload extends TSPLCommand {
401
366
  */
402
367
  constructor(fileName: string, data: Data);
403
368
  get commandString(): string;
404
- write(device: UsbDevice): Promise<void>;
369
+ writeTo(device: Device): Promise<void>;
405
370
  }
406
371
 
407
372
  type DisplayType = "CLS" | "IMAGE" | "OFF";
@@ -842,7 +807,7 @@ declare namespace index$1 {
842
807
  * Base class that encapsulates functionality of all printers
843
808
  */
844
809
  declare abstract class Printer {
845
- private readonly usbDevice;
810
+ private readonly device;
846
811
  /**
847
812
  * Printer language used by the type of printer the subclass represents
848
813
  */
@@ -851,7 +816,7 @@ declare abstract class Printer {
851
816
  * When called, it will feed the labels to the beginig of the next label
852
817
  */
853
818
  abstract feedLabel(): Promise<void>;
854
- constructor(device: UsbDevice);
819
+ constructor(device: Device);
855
820
  /**
856
821
  * Close the printer USB
857
822
  */
@@ -875,7 +840,7 @@ declare abstract class Printer {
875
840
  * Check if the device is indeed a printer
876
841
  * @param device
877
842
  */
878
- static try(_device: UsbDevice): Promise<boolean>;
843
+ static try(_device: Device): Promise<boolean>;
879
844
  }
880
845
 
881
846
  declare class PrinterService {
@@ -884,7 +849,17 @@ declare class PrinterService {
884
849
  * @param device
885
850
  * @returns
886
851
  */
887
- static printerForDevice(device: UsbDevice): Promise<Printer | undefined>;
852
+ static printerForDevice(device: Device): Promise<Printer | undefined>;
853
+ /**
854
+ * Discover devices using printer-specific discovery hooks.
855
+ *
856
+ * Each printer class may optionally implement `static discoverDevices(): Promise<Device[]>`
857
+ * to find candidates over non-USB transports.
858
+ *
859
+ * Candidates returned here are still verified by `printerForDevice` via the printer
860
+ * class' `try(device)` method.
861
+ */
862
+ private static discoverDevices;
888
863
  /**
889
864
  * @returns List of available printers
890
865
  */