@risleylima/escpos 0.2.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +116 -755
- package/dist/adapter/index.d.ts +29 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapter/index.js +25 -0
- package/dist/adapter/index.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/network-adapter/index.d.ts +24 -0
- package/dist/network-adapter/index.d.ts.map +1 -0
- package/dist/network-adapter/index.js +263 -0
- package/dist/network-adapter/index.js.map +1 -0
- package/dist/printer/commands-types.d.ts +37 -0
- package/dist/printer/commands-types.d.ts.map +1 -0
- package/dist/printer/commands-types.js +63 -0
- package/dist/printer/commands-types.js.map +1 -0
- package/dist/printer/commands.d.ts +169 -0
- package/dist/printer/commands.d.ts.map +1 -0
- package/dist/printer/commands.js +192 -0
- package/dist/printer/commands.js.map +1 -0
- package/dist/printer/image-loader.d.ts +17 -0
- package/dist/printer/image-loader.d.ts.map +1 -0
- package/dist/printer/image-loader.js +462 -0
- package/dist/printer/image-loader.js.map +1 -0
- package/dist/printer/image.d.ts +43 -0
- package/dist/printer/image.d.ts.map +1 -0
- package/dist/printer/image.js +132 -0
- package/dist/printer/image.js.map +1 -0
- package/dist/printer/index.d.ts +158 -0
- package/dist/printer/index.d.ts.map +1 -0
- package/dist/printer/index.js +703 -0
- package/dist/printer/index.js.map +1 -0
- package/dist/printer/profiles/bematech/mp4200th.d.ts +13 -0
- package/dist/printer/profiles/bematech/mp4200th.d.ts.map +1 -0
- package/dist/printer/profiles/bematech/mp4200th.js +29 -0
- package/dist/printer/profiles/bematech/mp4200th.js.map +1 -0
- package/dist/printer/profiles/custom/bematech-mp4200th.d.ts +13 -0
- package/dist/printer/profiles/custom/bematech-mp4200th.d.ts.map +1 -0
- package/dist/printer/profiles/custom/bematech-mp4200th.js +21 -0
- package/dist/printer/profiles/custom/bematech-mp4200th.js.map +1 -0
- package/dist/printer/profiles/custom/vkp80iii.d.ts +19 -0
- package/dist/printer/profiles/custom/vkp80iii.d.ts.map +1 -0
- package/dist/printer/profiles/custom/vkp80iii.js +87 -0
- package/dist/printer/profiles/custom/vkp80iii.js.map +1 -0
- package/dist/printer/profiles/default.d.ts +7 -0
- package/dist/printer/profiles/default.d.ts.map +1 -0
- package/dist/printer/profiles/default.js +15 -0
- package/dist/printer/profiles/default.js.map +1 -0
- package/dist/printer/profiles/index.d.ts +41 -0
- package/dist/printer/profiles/index.d.ts.map +1 -0
- package/dist/printer/profiles/index.js +98 -0
- package/dist/printer/profiles/index.js.map +1 -0
- package/dist/printer/profiles/merge.d.ts +7 -0
- package/dist/printer/profiles/merge.d.ts.map +1 -0
- package/dist/printer/profiles/merge.js +58 -0
- package/dist/printer/profiles/merge.js.map +1 -0
- package/dist/printer/profiles/types.d.ts +99 -0
- package/dist/printer/profiles/types.d.ts.map +1 -0
- package/dist/printer/profiles/types.js +8 -0
- package/dist/printer/profiles/types.js.map +1 -0
- package/dist/printer/utils.d.ts +9 -0
- package/dist/printer/utils.d.ts.map +1 -0
- package/dist/printer/utils.js +54 -0
- package/dist/printer/utils.js.map +1 -0
- package/dist/serial-adapter/index.d.ts +21 -0
- package/dist/serial-adapter/index.d.ts.map +1 -0
- package/dist/serial-adapter/index.js +180 -0
- package/dist/serial-adapter/index.js.map +1 -0
- package/dist/usb-adapter/index.d.ts +20 -0
- package/dist/usb-adapter/index.d.ts.map +1 -0
- package/dist/usb-adapter/index.js +264 -0
- package/dist/usb-adapter/index.js.map +1 -0
- package/package.json +42 -15
- package/CHANGELOG.md +0 -74
- package/docs/COVERAGE_ANALYSIS.md +0 -98
- package/docs/DEPENDENCIES_REVIEW.md +0 -127
- package/docs/JSDOC_REVIEW.md +0 -122
- package/docs/LIBRARY_OVERVIEW.md +0 -383
- package/docs/PRE_PUBLISH_CHECKLIST.md +0 -331
- package/docs/PUBLIC_API_ANALYSIS.md +0 -223
- package/docs/README.md +0 -37
- package/docs/SERIALPORT_V13_MIGRATION_COMPLETE.md +0 -127
- package/docs/TESTS_IMPLEMENTED.md +0 -129
- package/docs/USB_V2_REVIEW.md +0 -148
- package/docs/VERIFICATION_RESULTS.md +0 -172
- package/docs/VERSIONING.md +0 -102
- package/examples/printTest.js +0 -59
- package/index.js +0 -7
- package/jest.config.js +0 -16
- package/src/adapter/index.js +0 -75
- package/src/printer/commands.js +0 -199
- package/src/printer/image.js +0 -159
- package/src/printer/index.js +0 -621
- package/src/printer/utils.js +0 -58
- package/src/serial-adapter/index.js +0 -198
- package/src/usb-adapter/index.js +0 -283
- package/tests/README.md +0 -67
- package/tests/integration/printer-flow.test.js +0 -128
- package/tests/unit/adapters/adapter.test.js +0 -49
- package/tests/unit/adapters/serial-adapter.test.js +0 -238
- package/tests/unit/adapters/usb-adapter.test.js +0 -319
- package/tests/unit/image/image.test.js +0 -157
- package/tests/unit/printer/buffer.test.js +0 -60
- package/tests/unit/printer/commands.test.js +0 -109
- package/tests/unit/printer/printer.test.js +0 -405
- package/tests/unit/utils/utils.test.js +0 -96
package/README.md
CHANGED
|
@@ -3,832 +3,193 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@risleylima/escpos)
|
|
4
4
|
[](https://nodejs.org/)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[]()
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
**The definitive thermal printing library for Node.js.** — Industrial-grade robustness, O(n) performance, and a fully agnostic architecture.
|
|
8
9
|
|
|
9
|
-
##
|
|
10
|
+
## 🚀 Why choose this library?
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
- 🔌 **Multiple Adapters**: USB and Serial port support
|
|
13
|
-
- 📝 **Fluent API**: Method chaining for easy command composition
|
|
14
|
-
- 🖼️ **Image Printing**: Convert and print images on thermal printers
|
|
15
|
-
- 📊 **Barcode Generation**: Support for multiple barcode formats (EAN13, EAN8, CODE128, CODE39, etc.)
|
|
16
|
-
- 🌐 **Encoding Support**: Multiple character encodings (GB18030, UTF-8, ASCII, etc.)
|
|
17
|
-
- 📦 **Modern JavaScript**: Promise-based async/await, ES6+
|
|
18
|
-
- ✅ **Well Tested**: 100% test coverage with 145+ tests
|
|
19
|
-
- 📚 **Fully Documented**: Complete JSDoc documentation
|
|
20
|
-
- 🔄 **Event-Driven**: EventEmitter-based architecture for connection events
|
|
12
|
+
This library was designed to solve common technical bottlenecks found in traditional thermal printing implementations. Our focus is on reliability, performance, and clean architecture.
|
|
21
13
|
|
|
22
|
-
|
|
14
|
+
### Technical Advantages
|
|
23
15
|
|
|
24
|
-
|
|
16
|
+
| Feature | Our Modern Approach | Common Legacy Patterns |
|
|
17
|
+
| :--- | :--- | :--- |
|
|
18
|
+
| **Buffer Efficiency** | **O(n)** (Smart chunk accumulation) | O(n²) (Recursive concatenation) |
|
|
19
|
+
| **Event Loop** | **Protected** (Async pixel processing) | Blocked (Synchronous processing) |
|
|
20
|
+
| **State Management** | **Instantiable** (Multi-printer support) | Singletons (Global state limits) |
|
|
21
|
+
| **Protocol Support** | **Modern GS ( k** (QR Functions 165/167/169/180/181) | Legacy ESC Z commands |
|
|
22
|
+
| **Connectivity** | **Fully Agnostic** (Interface-based) | Coupled to specific IO |
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
npm install @risleylima/escpos
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### Via Yarn
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
yarn add @risleylima/escpos
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Requirements
|
|
37
|
-
|
|
38
|
-
- **Node.js**: >= 18.0.0
|
|
39
|
-
- **Operating System**: Linux, macOS, or Windows
|
|
40
|
-
|
|
41
|
-
### Platform-Specific Requirements
|
|
42
|
-
|
|
43
|
-
#### Linux
|
|
44
|
-
- For USB: `libusb` development libraries
|
|
45
|
-
```bash
|
|
46
|
-
sudo apt-get install libusb-1.0-0-dev # Debian/Ubuntu
|
|
47
|
-
sudo yum install libusb-devel # CentOS/RHEL
|
|
48
|
-
```
|
|
49
|
-
- For Serial: Usually built-in, may need permissions
|
|
50
|
-
```bash
|
|
51
|
-
sudo usermod -a -G dialout $USER # Add user to dialout group
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
#### macOS
|
|
55
|
-
- For USB: Usually works out of the box
|
|
56
|
-
- For Serial: Usually works out of the box
|
|
57
|
-
|
|
58
|
-
#### Windows
|
|
59
|
-
- For USB: Usually works out of the box
|
|
60
|
-
- For Serial: Usually works out of the box
|
|
61
|
-
|
|
62
|
-
## Quick Start
|
|
63
|
-
|
|
64
|
-
### USB Printer Example
|
|
65
|
-
|
|
66
|
-
```javascript
|
|
67
|
-
const { USB, Printer } = require('@risleylima/escpos');
|
|
68
|
-
|
|
69
|
-
(async () => {
|
|
70
|
-
try {
|
|
71
|
-
// Connect to USB printer (VID and PID)
|
|
72
|
-
await USB.connect(1046, 20497);
|
|
73
|
-
await USB.open();
|
|
74
|
-
|
|
75
|
-
// Create printer instance
|
|
76
|
-
const printer = new Printer(USB);
|
|
77
|
-
|
|
78
|
-
// Print a receipt
|
|
79
|
-
printer
|
|
80
|
-
.hardware('init')
|
|
81
|
-
.align('ct')
|
|
82
|
-
.size(2, 2)
|
|
83
|
-
.textln('RECEIPT')
|
|
84
|
-
.size(1, 1)
|
|
85
|
-
.align('lt')
|
|
86
|
-
.textln('Item 1: $10.00')
|
|
87
|
-
.textln('Item 2: $20.00')
|
|
88
|
-
.align('rt')
|
|
89
|
-
.textln('Total: $30.00')
|
|
90
|
-
.cut(true);
|
|
91
|
-
|
|
92
|
-
// Send to printer
|
|
93
|
-
await printer.flush();
|
|
94
|
-
|
|
95
|
-
// Close connection
|
|
96
|
-
await USB.close();
|
|
97
|
-
await USB.disconnect();
|
|
98
|
-
} catch (error) {
|
|
99
|
-
console.error('Error:', error);
|
|
100
|
-
}
|
|
101
|
-
})();
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
### Serial Printer Example
|
|
105
|
-
|
|
106
|
-
```javascript
|
|
107
|
-
const { Serial, Printer } = require('@risleylima/escpos');
|
|
108
|
-
|
|
109
|
-
(async () => {
|
|
110
|
-
try {
|
|
111
|
-
// Connect to serial printer
|
|
112
|
-
await Serial.connect('/dev/ttyUSB0');
|
|
113
|
-
await Serial.open();
|
|
114
|
-
|
|
115
|
-
// Create printer instance
|
|
116
|
-
const printer = new Printer(Serial);
|
|
117
|
-
|
|
118
|
-
// Print text
|
|
119
|
-
printer
|
|
120
|
-
.hardware('init')
|
|
121
|
-
.textln('Hello, World!')
|
|
122
|
-
.cut(true);
|
|
123
|
-
|
|
124
|
-
// Send to printer
|
|
125
|
-
await printer.flush();
|
|
126
|
-
|
|
127
|
-
// Close connection
|
|
128
|
-
await Serial.close();
|
|
129
|
-
await Serial.disconnect();
|
|
130
|
-
} catch (error) {
|
|
131
|
-
console.error('Error:', error);
|
|
132
|
-
}
|
|
133
|
-
})();
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
## API Documentation
|
|
137
|
-
|
|
138
|
-
### Exports
|
|
139
|
-
|
|
140
|
-
The library exports the following modules:
|
|
141
|
-
|
|
142
|
-
```javascript
|
|
143
|
-
const { USB, Serial, Printer, Adapter, Image } = require('@risleylima/escpos');
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
- **`USB`**: USB adapter instance (EventEmitter)
|
|
147
|
-
- **`Serial`**: Serial port adapter instance (EventEmitter)
|
|
148
|
-
- **`Printer`**: ESC/POS command generator class
|
|
149
|
-
- **`Adapter`**: Base adapter class
|
|
150
|
-
- **`Image`**: Image processing utilities
|
|
151
|
-
|
|
152
|
-
### USB Adapter
|
|
153
|
-
|
|
154
|
-
#### Methods
|
|
155
|
-
|
|
156
|
-
##### `USB.listUSB()`
|
|
157
|
-
List all available USB printer devices.
|
|
158
|
-
|
|
159
|
-
```javascript
|
|
160
|
-
const devices = await USB.listUSB();
|
|
161
|
-
console.log(devices); // Array of USB devices with manufacturer and product info
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
##### `USB.connect(vid, pid)`
|
|
165
|
-
Connect to a USB printer by Vendor ID and Product ID.
|
|
166
|
-
|
|
167
|
-
```javascript
|
|
168
|
-
await USB.connect(1046, 20497); // Connect to specific device
|
|
169
|
-
// OR
|
|
170
|
-
await USB.connect(); // Connect to first available printer
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
**Events:**
|
|
174
|
-
- `connect` - Emitted when device connects
|
|
175
|
-
- `detach` - Emitted when device is unplugged
|
|
176
|
-
|
|
177
|
-
##### `USB.open()`
|
|
178
|
-
Open the USB device and claim the printer interface.
|
|
179
|
-
|
|
180
|
-
```javascript
|
|
181
|
-
await USB.open();
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
**Events:**
|
|
185
|
-
- `connect` - Emitted when device is opened
|
|
186
|
-
|
|
187
|
-
##### `USB.write(data)`
|
|
188
|
-
Write data buffer to the printer.
|
|
189
|
-
|
|
190
|
-
```javascript
|
|
191
|
-
await USB.write(Buffer.from('Hello', 'ascii'));
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
##### `USB.close()`
|
|
195
|
-
Close the USB device connection.
|
|
196
|
-
|
|
197
|
-
```javascript
|
|
198
|
-
await USB.close();
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
**Events:**
|
|
202
|
-
- `close` - Emitted when device closes
|
|
203
|
-
|
|
204
|
-
##### `USB.disconnect()`
|
|
205
|
-
Disconnect from the USB device (calls `close` internally).
|
|
206
|
-
|
|
207
|
-
```javascript
|
|
208
|
-
await USB.disconnect();
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
**Events:**
|
|
212
|
-
- `disconnect` - Emitted when device disconnects
|
|
213
|
-
|
|
214
|
-
### Serial Adapter
|
|
215
|
-
|
|
216
|
-
#### Methods
|
|
217
|
-
|
|
218
|
-
##### `Serial.listSerial()`
|
|
219
|
-
List all available serial ports.
|
|
220
|
-
|
|
221
|
-
```javascript
|
|
222
|
-
const ports = await Serial.listSerial();
|
|
223
|
-
console.log(ports); // Array of serial port objects with path, manufacturer, vendorId, productId, etc.
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
##### `Serial.connect(port, options)`
|
|
227
|
-
Connect to a serial port printer.
|
|
228
|
-
|
|
229
|
-
```javascript
|
|
230
|
-
await Serial.connect('/dev/ttyUSB0');
|
|
231
|
-
// OR with options
|
|
232
|
-
await Serial.connect('/dev/ttyUSB0', {
|
|
233
|
-
baudRate: 9600,
|
|
234
|
-
dataBits: 8,
|
|
235
|
-
stopBits: 1,
|
|
236
|
-
parity: 'none'
|
|
237
|
-
});
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
**Events:**
|
|
241
|
-
- `connect` - Emitted when port connects
|
|
242
|
-
- `close` - Emitted when reconnecting (closing previous connection)
|
|
243
|
-
|
|
244
|
-
##### `Serial.open()`
|
|
245
|
-
Open the serial port if it's closed.
|
|
246
|
-
|
|
247
|
-
```javascript
|
|
248
|
-
await Serial.open();
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
##### `Serial.write(data)`
|
|
252
|
-
Write data buffer to the printer.
|
|
253
|
-
|
|
254
|
-
```javascript
|
|
255
|
-
await Serial.write(Buffer.from('Hello', 'ascii'));
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
##### `Serial.read()`
|
|
259
|
-
Read data from the serial port.
|
|
260
|
-
|
|
261
|
-
```javascript
|
|
262
|
-
const data = await Serial.read();
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
##### `Serial.close(timeout)`
|
|
266
|
-
Close the serial port connection.
|
|
267
|
-
|
|
268
|
-
```javascript
|
|
269
|
-
await Serial.close(); // Default timeout: 50ms
|
|
270
|
-
await Serial.close(100); // Custom timeout: 100ms
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
**Events:**
|
|
274
|
-
- `close` - Emitted when port closes
|
|
275
|
-
|
|
276
|
-
##### `Serial.disconnect(timeout)`
|
|
277
|
-
Disconnect from the serial port (calls `close` internally).
|
|
278
|
-
|
|
279
|
-
```javascript
|
|
280
|
-
await Serial.disconnect();
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
**Events:**
|
|
284
|
-
- `disconnect` - Emitted when port disconnects
|
|
285
|
-
|
|
286
|
-
### Printer Class
|
|
287
|
-
|
|
288
|
-
#### Constructor
|
|
289
|
-
|
|
290
|
-
```javascript
|
|
291
|
-
const printer = new Printer(adapter, options);
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
**Parameters:**
|
|
295
|
-
- `adapter` (Adapter): USB or Serial adapter instance
|
|
296
|
-
- `options` (Object, optional):
|
|
297
|
-
- `encoding` (String): Character encoding (default: 'GB18030')
|
|
298
|
-
- `width` (Number): Paper width in columns (default: 48)
|
|
299
|
-
|
|
300
|
-
#### Text Operations
|
|
301
|
-
|
|
302
|
-
##### `printer.print(content)`
|
|
303
|
-
Print raw text without encoding.
|
|
304
|
-
|
|
305
|
-
```javascript
|
|
306
|
-
printer.print('Hello');
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
##### `printer.println(content)`
|
|
310
|
-
Print text with line break.
|
|
311
|
-
|
|
312
|
-
```javascript
|
|
313
|
-
printer.println('Hello');
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
##### `printer.text(content, encoding)`
|
|
317
|
-
Print text with encoding.
|
|
318
|
-
|
|
319
|
-
```javascript
|
|
320
|
-
printer.text('Hello', 'UTF-8');
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
##### `printer.textln(content, encoding)`
|
|
324
|
-
Print text with encoding and line break.
|
|
325
|
-
|
|
326
|
-
```javascript
|
|
327
|
-
printer.textln('Hello', 'UTF-8');
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
##### `printer.newLine()`
|
|
331
|
-
Send end of line command.
|
|
332
|
-
|
|
333
|
-
```javascript
|
|
334
|
-
printer.newLine();
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
#### Formatting
|
|
338
|
-
|
|
339
|
-
##### `printer.align(position)`
|
|
340
|
-
Set text alignment.
|
|
341
|
-
|
|
342
|
-
```javascript
|
|
343
|
-
printer.align('lt'); // Left
|
|
344
|
-
printer.align('ct'); // Center
|
|
345
|
-
printer.align('rt'); // Right
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
##### `printer.size(width, height)`
|
|
349
|
-
Set text size (1-8 for both width and height).
|
|
350
|
-
|
|
351
|
-
```javascript
|
|
352
|
-
printer.size(2, 2); // Double width and height
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
##### `printer.style(type)`
|
|
356
|
-
Set text style.
|
|
357
|
-
|
|
358
|
-
```javascript
|
|
359
|
-
printer.style('B'); // Bold
|
|
360
|
-
printer.style('I'); // Italic
|
|
361
|
-
printer.style('U'); // Underline
|
|
362
|
-
printer.style('NORMAL'); // Normal
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
##### `printer.font(family)`
|
|
366
|
-
Set font family.
|
|
367
|
-
|
|
368
|
-
```javascript
|
|
369
|
-
printer.font('A'); // Font A (42 columns)
|
|
370
|
-
printer.font('B'); // Font B (56 columns)
|
|
371
|
-
printer.font('C'); // Font C
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
##### `printer.encode(encoding)`
|
|
375
|
-
Set character encoding.
|
|
376
|
-
|
|
377
|
-
```javascript
|
|
378
|
-
printer.encode('UTF-8');
|
|
379
|
-
printer.encode('GB18030');
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
#### Hardware Control
|
|
24
|
+
---
|
|
383
25
|
|
|
384
|
-
|
|
385
|
-
Send hardware commands.
|
|
26
|
+
## 🛠️ Architectural Pillars
|
|
386
27
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
28
|
+
1. **Transport Agnostic (IO):** The printer core is pure and communicates through an `AdapterLike` abstraction. Use USB, Serial, or Network interchangeably.
|
|
29
|
+
2. **Model Agnostic (Profiles):** Handle manufacturer-specific "quirks" (Epson, Elgin, Bematech, Custom) via a robust Profile system.
|
|
30
|
+
3. **Industrial Reliability:** Built-in mechanisms for `drain` and graceful shutdown to ensure zero data loss.
|
|
390
31
|
|
|
391
|
-
|
|
392
|
-
Cut paper.
|
|
393
|
-
|
|
394
|
-
```javascript
|
|
395
|
-
printer.cut(true); // Partial cut
|
|
396
|
-
printer.cut(false); // Full cut
|
|
397
|
-
printer.cut(true, 5); // Partial cut with 5 line feeds
|
|
398
|
-
```
|
|
32
|
+
---
|
|
399
33
|
|
|
400
|
-
|
|
401
|
-
Beep buzzer.
|
|
34
|
+
## 📦 Installation
|
|
402
35
|
|
|
403
|
-
```
|
|
404
|
-
|
|
36
|
+
```bash
|
|
37
|
+
npm install @risleylima/escpos
|
|
405
38
|
```
|
|
406
39
|
|
|
407
|
-
|
|
408
|
-
Open cash drawer.
|
|
409
|
-
|
|
410
|
-
```javascript
|
|
411
|
-
printer.cashdraw(2); // Pulse pin 2
|
|
412
|
-
printer.cashdraw(5); // Pulse pin 5
|
|
413
|
-
```
|
|
40
|
+
---
|
|
414
41
|
|
|
415
|
-
|
|
42
|
+
## 🧰 Development Setup
|
|
416
43
|
|
|
417
|
-
|
|
418
|
-
|
|
44
|
+
- **Official package manager:** `yarn`
|
|
45
|
+
- Use `yarn install` for dependency install in this repository.
|
|
46
|
+
- Use `yarn test`, `yarn test:coverage`, and `yarn build` for local workflows.
|
|
419
47
|
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
// CODE128 with options
|
|
425
|
-
printer.barcode('ABC123', 'CODE128', {
|
|
426
|
-
width: 2,
|
|
427
|
-
height: 100,
|
|
428
|
-
position: 'BLW', // Below: 'OFF', 'ABV', 'BLW', 'BTH'
|
|
429
|
-
font: 'A',
|
|
430
|
-
includeParity: true
|
|
431
|
-
});
|
|
48
|
+
```bash
|
|
49
|
+
yarn install
|
|
50
|
+
yarn build
|
|
51
|
+
yarn test
|
|
432
52
|
```
|
|
433
53
|
|
|
434
|
-
|
|
435
|
-
- `EAN13`, `EAN8`, `UPC-A`, `UPC-E`
|
|
436
|
-
- `CODE39`, `CODE93`, `CODE128`
|
|
437
|
-
- `ITF`, `NW7`
|
|
438
|
-
|
|
439
|
-
#### Image Printing
|
|
440
|
-
|
|
441
|
-
##### `printer.image(image, density)`
|
|
442
|
-
Print image in bitmap mode.
|
|
443
|
-
|
|
444
|
-
```javascript
|
|
445
|
-
const { Image } = require('@risleylima/escpos');
|
|
446
|
-
|
|
447
|
-
// Load image
|
|
448
|
-
const image = await Image.load('/path/to/image.png', 'image/png');
|
|
449
|
-
|
|
450
|
-
// Print image
|
|
451
|
-
printer.image(image, 'd24'); // Density: 'd8', 's8', 'd24', 's24'
|
|
452
|
-
```
|
|
54
|
+
---
|
|
453
55
|
|
|
454
|
-
|
|
455
|
-
Print image in raster mode.
|
|
56
|
+
## ⚡ Quick Start
|
|
456
57
|
|
|
58
|
+
### Network (TCP RAW) Example
|
|
457
59
|
```javascript
|
|
458
|
-
|
|
459
|
-
printer.raster(image, 'normal'); // Mode: 'normal', 'dw', 'dh', 'dwdh'
|
|
460
|
-
```
|
|
60
|
+
import { Network, Printer } from '@risleylima/escpos';
|
|
461
61
|
|
|
462
|
-
|
|
62
|
+
const adapter = new Network();
|
|
63
|
+
await adapter.connect('10.1.1.50', 9100);
|
|
64
|
+
await adapter.open();
|
|
463
65
|
|
|
464
|
-
|
|
465
|
-
|
|
66
|
+
const printer = new Printer(adapter);
|
|
67
|
+
printer.textln('Hello World').cut();
|
|
466
68
|
|
|
467
|
-
```javascript
|
|
468
69
|
await printer.flush();
|
|
70
|
+
await adapter.close();
|
|
469
71
|
```
|
|
470
72
|
|
|
471
|
-
|
|
472
|
-
Close connection and flush buffer.
|
|
473
|
-
|
|
73
|
+
### Serial Example
|
|
474
74
|
```javascript
|
|
475
|
-
|
|
476
|
-
```
|
|
75
|
+
import { Serial, Printer } from '@risleylima/escpos';
|
|
477
76
|
|
|
478
|
-
|
|
77
|
+
const adapter = new Serial();
|
|
78
|
+
// baudRate is optional; if omitted, 9600 is used when opening (node-serialport requires it).
|
|
79
|
+
// Port path: Linux/macOS → /dev/ttyUSB0, /dev/tty.usbmodem*; Windows → COM1, COM2, COM3, ...
|
|
80
|
+
await adapter.connect(process.platform === 'win32' ? 'COM3' : '/dev/tty.usbmodem112301', { baudRate: 115200 });
|
|
81
|
+
await adapter.open();
|
|
479
82
|
|
|
480
|
-
|
|
481
|
-
|
|
83
|
+
const printer = new Printer(adapter);
|
|
84
|
+
printer.textln('Serial Printing').cut();
|
|
482
85
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
printer.drawLine('='); // Draw line with equals
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
##### `printer.feed(n)`
|
|
489
|
-
Feed paper n lines.
|
|
490
|
-
|
|
491
|
-
```javascript
|
|
492
|
-
printer.feed(3); // Feed 3 lines
|
|
86
|
+
await printer.flush();
|
|
87
|
+
await adapter.close();
|
|
493
88
|
```
|
|
89
|
+
**Windows:** Use the COM port shown in Device Manager (Ports COM & LPT), e.g. `COM3` or `COM4`. On Windows the path is always `COMn`.
|
|
494
90
|
|
|
495
|
-
|
|
496
|
-
Set print color (if printer supports it).
|
|
497
|
-
|
|
91
|
+
Windows-only Serial example:
|
|
498
92
|
```javascript
|
|
499
|
-
|
|
500
|
-
printer.color(1); // Red
|
|
501
|
-
```
|
|
93
|
+
import { Serial, Printer } from '@risleylima/escpos';
|
|
502
94
|
|
|
503
|
-
|
|
504
|
-
|
|
95
|
+
const adapter = new Serial();
|
|
96
|
+
await adapter.connect('COM3', { baudRate: 9600 }); // or 115200, depending on the printer
|
|
97
|
+
await adapter.open();
|
|
505
98
|
|
|
506
|
-
|
|
507
|
-
printer.
|
|
508
|
-
printer.
|
|
99
|
+
const printer = new Printer(adapter);
|
|
100
|
+
printer.textln('Windows print').cut();
|
|
101
|
+
await printer.flush();
|
|
102
|
+
await adapter.close();
|
|
509
103
|
```
|
|
510
104
|
|
|
511
|
-
|
|
512
|
-
Write raw ESC/POS commands.
|
|
513
|
-
|
|
105
|
+
### USB Example
|
|
514
106
|
```javascript
|
|
515
|
-
|
|
516
|
-
printer.raw('1B40'); // Initialize
|
|
517
|
-
|
|
518
|
-
// Buffer
|
|
519
|
-
printer.raw(Buffer.from('1B40', 'hex'));
|
|
520
|
-
```
|
|
107
|
+
import { USB, Printer } from '@risleylima/escpos';
|
|
521
108
|
|
|
522
|
-
|
|
109
|
+
const adapter = new USB();
|
|
110
|
+
await adapter.connect(0x04b8, 0x0202); // VID, PID
|
|
111
|
+
await adapter.open();
|
|
523
112
|
|
|
524
|
-
|
|
113
|
+
const printer = new Printer(adapter);
|
|
114
|
+
printer.textln('USB Printing').cut();
|
|
525
115
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
(async () => {
|
|
530
|
-
await USB.connect(1046, 20497);
|
|
531
|
-
await USB.open();
|
|
532
|
-
|
|
533
|
-
const printer = new Printer(USB, {
|
|
534
|
-
encoding: 'UTF-8',
|
|
535
|
-
width: 48
|
|
536
|
-
});
|
|
537
|
-
|
|
538
|
-
printer
|
|
539
|
-
.hardware('init')
|
|
540
|
-
.beep(1, 1)
|
|
541
|
-
.align('ct')
|
|
542
|
-
.size(2, 2)
|
|
543
|
-
.textln('MY STORE')
|
|
544
|
-
.size(1, 1)
|
|
545
|
-
.textln('123 Main Street')
|
|
546
|
-
.textln('City, State 12345')
|
|
547
|
-
.textln('Phone: (555) 123-4567')
|
|
548
|
-
.drawLine()
|
|
549
|
-
.align('lt')
|
|
550
|
-
.textln('Date: ' + new Date().toLocaleString())
|
|
551
|
-
.textln('Receipt #: 001234')
|
|
552
|
-
.drawLine()
|
|
553
|
-
.textln('Item 1 $10.00')
|
|
554
|
-
.textln('Item 2 $20.00')
|
|
555
|
-
.textln('Item 3 $15.00')
|
|
556
|
-
.drawLine()
|
|
557
|
-
.align('rt')
|
|
558
|
-
.textln('Subtotal: $45.00')
|
|
559
|
-
.textln('Tax: $4.50')
|
|
560
|
-
.size(2, 1)
|
|
561
|
-
.textln('Total: $49.50')
|
|
562
|
-
.size(1, 1)
|
|
563
|
-
.drawLine()
|
|
564
|
-
.align('ct')
|
|
565
|
-
.textln('Thank you for your purchase!')
|
|
566
|
-
.feed(3)
|
|
567
|
-
.cut(true);
|
|
568
|
-
|
|
569
|
-
await printer.flush();
|
|
570
|
-
await USB.close();
|
|
571
|
-
await USB.disconnect();
|
|
572
|
-
})();
|
|
116
|
+
await printer.flush();
|
|
117
|
+
await adapter.close();
|
|
573
118
|
```
|
|
574
119
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
```javascript
|
|
578
|
-
const { USB, Printer } = require('@risleylima/escpos');
|
|
579
|
-
|
|
580
|
-
(async () => {
|
|
581
|
-
await USB.connect(1046, 20497);
|
|
582
|
-
await USB.open();
|
|
583
|
-
|
|
584
|
-
const printer = new Printer(USB);
|
|
585
|
-
|
|
586
|
-
printer
|
|
587
|
-
.hardware('init')
|
|
588
|
-
.align('ct')
|
|
589
|
-
.textln('PRODUCT CODE')
|
|
590
|
-
.barcode('123456789012', 'EAN13', {
|
|
591
|
-
width: 2,
|
|
592
|
-
height: 100,
|
|
593
|
-
position: 'BLW',
|
|
594
|
-
font: 'A'
|
|
595
|
-
})
|
|
596
|
-
.feed(2)
|
|
597
|
-
.cut(true);
|
|
598
|
-
|
|
599
|
-
await printer.flush();
|
|
600
|
-
await USB.close();
|
|
601
|
-
await USB.disconnect();
|
|
602
|
-
})();
|
|
603
|
-
```
|
|
120
|
+
---
|
|
604
121
|
|
|
605
|
-
|
|
122
|
+
## 📝 Visual Result Preview
|
|
606
123
|
|
|
607
|
-
```
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
printer
|
|
620
|
-
.hardware('init')
|
|
621
|
-
.align('ct')
|
|
622
|
-
.image(image, 'd24')
|
|
623
|
-
.feed(2)
|
|
624
|
-
.textln('Company Logo')
|
|
625
|
-
.cut(true);
|
|
626
|
-
|
|
627
|
-
await printer.flush();
|
|
628
|
-
await USB.close();
|
|
629
|
-
await USB.disconnect();
|
|
630
|
-
})();
|
|
124
|
+
```text
|
|
125
|
+
------------------------------------------------
|
|
126
|
+
MY STORE
|
|
127
|
+
1024 Engineering Street
|
|
128
|
+
------------------------------------------------
|
|
129
|
+
Item 001 $ 10.00
|
|
130
|
+
Item 002 $ 20.00
|
|
131
|
+
------------------------------------------------
|
|
132
|
+
TOTAL $ 30.00
|
|
133
|
+
------------------------------------------------
|
|
134
|
+
[ MODERN QR CODE HERE ]
|
|
135
|
+
------------------------------------------------
|
|
631
136
|
```
|
|
632
137
|
|
|
633
|
-
|
|
138
|
+
---
|
|
634
139
|
|
|
635
|
-
|
|
636
|
-
const { USB, Printer } = require('@risleylima/escpos');
|
|
637
|
-
|
|
638
|
-
USB.on('connect', (device) => {
|
|
639
|
-
console.log('Device connected:', device);
|
|
640
|
-
});
|
|
641
|
-
|
|
642
|
-
USB.on('disconnect', (device) => {
|
|
643
|
-
console.log('Device disconnected:', device);
|
|
644
|
-
});
|
|
645
|
-
|
|
646
|
-
USB.on('close', (device) => {
|
|
647
|
-
console.log('Device closed:', device);
|
|
648
|
-
});
|
|
649
|
-
|
|
650
|
-
USB.on('detach', () => {
|
|
651
|
-
console.log('Device unplugged!');
|
|
652
|
-
});
|
|
653
|
-
|
|
654
|
-
(async () => {
|
|
655
|
-
await USB.connect(1046, 20497);
|
|
656
|
-
await USB.open();
|
|
657
|
-
|
|
658
|
-
const printer = new Printer(USB);
|
|
659
|
-
printer.textln('Hello, World!');
|
|
660
|
-
await printer.flush();
|
|
661
|
-
|
|
662
|
-
await USB.close();
|
|
663
|
-
await USB.disconnect();
|
|
664
|
-
})();
|
|
665
|
-
```
|
|
140
|
+
## 🖼️ Industrial Image Processing
|
|
666
141
|
|
|
667
|
-
|
|
142
|
+
- **Formats:** PNG (Indexed/Gray/RGB), BMP (1/4/8/24-bit), JPEG, GIF, and SVG.
|
|
143
|
+
- **Non-blocking:** Asynchronous decoding with `setImmediate` ensuring your server stays responsive.
|
|
668
144
|
|
|
669
145
|
```javascript
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
(
|
|
673
|
-
// List all USB printers
|
|
674
|
-
const devices = await USB.listUSB();
|
|
675
|
-
|
|
676
|
-
console.log('Found printers:');
|
|
677
|
-
devices.forEach((device, index) => {
|
|
678
|
-
console.log(`${index + 1}. ${device.manufacturer} - ${device.product}`);
|
|
679
|
-
console.log(` VID: ${device.deviceDescriptor.idVendor}`);
|
|
680
|
-
console.log(` PID: ${device.deviceDescriptor.idProduct}`);
|
|
681
|
-
});
|
|
682
|
-
|
|
683
|
-
// Connect to first printer
|
|
684
|
-
if (devices.length > 0) {
|
|
685
|
-
await USB.connect();
|
|
686
|
-
await USB.open();
|
|
687
|
-
// ... use printer
|
|
688
|
-
}
|
|
689
|
-
})();
|
|
146
|
+
import { Image } from '@risleylima/escpos';
|
|
147
|
+
const image = await Image.load('./logo.png');
|
|
148
|
+
printer.raster(image);
|
|
690
149
|
```
|
|
691
150
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
The Printer class supports method chaining for fluent API:
|
|
695
|
-
|
|
696
|
-
```javascript
|
|
697
|
-
printer
|
|
698
|
-
.hardware('init')
|
|
699
|
-
.align('ct')
|
|
700
|
-
.size(2, 2)
|
|
701
|
-
.textln('TITLE')
|
|
702
|
-
.size(1, 1)
|
|
703
|
-
.align('lt')
|
|
704
|
-
.textln('Content here')
|
|
705
|
-
.cut(true);
|
|
706
|
-
```
|
|
151
|
+
---
|
|
707
152
|
|
|
708
|
-
##
|
|
153
|
+
## 🔍 Status Monitoring
|
|
709
154
|
|
|
710
|
-
|
|
155
|
+
Reliable hardware feedback:
|
|
711
156
|
|
|
712
157
|
```javascript
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
const printer = new Printer(USB);
|
|
718
|
-
printer.textln('Hello');
|
|
719
|
-
await printer.flush();
|
|
720
|
-
|
|
721
|
-
await USB.close();
|
|
722
|
-
await USB.disconnect();
|
|
723
|
-
} catch (error) {
|
|
724
|
-
console.error('Printer error:', error);
|
|
725
|
-
// Handle error appropriately
|
|
158
|
+
const status = await printer.getStatus('PAPER');
|
|
159
|
+
if (status[0] & 0x0C) {
|
|
160
|
+
console.log('Alert: Paper low or out of paper!');
|
|
726
161
|
}
|
|
727
162
|
```
|
|
728
163
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
The library includes comprehensive tests:
|
|
732
|
-
|
|
733
|
-
```bash
|
|
734
|
-
# Run all tests
|
|
735
|
-
npm test
|
|
736
|
-
|
|
737
|
-
# Run tests in watch mode
|
|
738
|
-
npm run test:watch
|
|
739
|
-
|
|
740
|
-
# Run tests with coverage
|
|
741
|
-
npm run test:coverage
|
|
742
|
-
```
|
|
743
|
-
|
|
744
|
-
**Test Coverage: 100%** ✅
|
|
745
|
-
- 145+ tests
|
|
746
|
-
- Unit and integration tests
|
|
747
|
-
- All edge cases covered
|
|
748
|
-
|
|
749
|
-
## Documentation
|
|
750
|
-
|
|
751
|
-
Additional documentation is available in the `docs/` folder:
|
|
752
|
-
|
|
753
|
-
- [Library Overview](./docs/LIBRARY_OVERVIEW.md) - Complete library overview
|
|
754
|
-
- [JSDoc Review](./docs/JSDOC_REVIEW.md) - JSDoc documentation review
|
|
755
|
-
- [Test Coverage](./docs/COVERAGE_ANALYSIS.md) - Test coverage analysis
|
|
756
|
-
- [Dependencies Review](./docs/DEPENDENCIES_REVIEW.md) - Dependencies status
|
|
757
|
-
- [USB v2 Migration](./docs/USB_V2_MIGRATION.md) - USB library migration guide
|
|
758
|
-
- [SerialPort v13 Migration](./docs/SERIALPORT_V13_MIGRATION_COMPLETE.md) - SerialPort migration guide
|
|
759
|
-
|
|
760
|
-
## Contributing
|
|
761
|
-
|
|
762
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
763
|
-
|
|
764
|
-
1. Fork the repository
|
|
765
|
-
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
|
|
766
|
-
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
|
|
767
|
-
4. Push to the branch (`git push origin feature/AmazingFeature`)
|
|
768
|
-
5. Open a Pull Request
|
|
769
|
-
|
|
770
|
-
### Development Setup
|
|
771
|
-
|
|
772
|
-
```bash
|
|
773
|
-
# Clone repository
|
|
774
|
-
git clone https://github.com/risleylima/escpos.git
|
|
775
|
-
cd escpos
|
|
776
|
-
|
|
777
|
-
# Install dependencies
|
|
778
|
-
npm install
|
|
779
|
-
# or
|
|
780
|
-
yarn install
|
|
781
|
-
|
|
782
|
-
# Run tests
|
|
783
|
-
npm test
|
|
784
|
-
|
|
785
|
-
# Run tests with coverage
|
|
786
|
-
npm run test:coverage
|
|
787
|
-
```
|
|
788
|
-
|
|
789
|
-
## License
|
|
790
|
-
|
|
791
|
-
MIT License
|
|
164
|
+
---
|
|
792
165
|
|
|
793
|
-
|
|
166
|
+
## 🖨️ Profile Support
|
|
794
167
|
|
|
795
|
-
|
|
796
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
797
|
-
in the Software without restriction, including without limitation the rights
|
|
798
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
799
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
800
|
-
furnished to do so, subject to the following conditions:
|
|
168
|
+
The library uses profiles to handle model-specific commands:
|
|
801
169
|
|
|
802
|
-
|
|
803
|
-
|
|
170
|
+
- **'default'**: Standard ESC/POS.
|
|
171
|
+
- **'custom-vkp80iii'**: CUSTOM VKP80III (Uses FS P for advanced cut/eject).
|
|
172
|
+
- **'bematech-mp4200th'**: Bematech MP-4200 TH in ESC/POS mode.
|
|
804
173
|
|
|
805
|
-
|
|
806
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
807
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
808
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
809
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
810
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
811
|
-
SOFTWARE.
|
|
174
|
+
You can also register model profiles at runtime with `registerProfile(...)`, or use an isolated registry with `createProfileRegistry(...)` for multi-tenant applications.
|
|
812
175
|
|
|
813
|
-
|
|
176
|
+
---
|
|
814
177
|
|
|
815
|
-
|
|
178
|
+
## ⚙️ Reliability and Safety Notes
|
|
816
179
|
|
|
817
|
-
|
|
180
|
+
- **Serial:** If you omit `baudRate` in `connect(port, options)`, the adapter uses 9600 when opening. Pass `baudRate` to match the printer (e.g. 115200 for Bematech MP-4200 TH).
|
|
181
|
+
- `flush()` is transactional: if adapter write fails, payload is preserved in buffer for retry/recovery.
|
|
182
|
+
- Printer I/O is serialized internally for `flush()`, `close()`, and `getStatus()` to reduce race conditions in concurrent flows.
|
|
183
|
+
- Passing an unknown profile id now fails fast with a descriptive error instead of silently falling back.
|
|
818
184
|
|
|
819
|
-
|
|
820
|
-
- **Email**: risley@rlimainfo.com.br
|
|
185
|
+
---
|
|
821
186
|
|
|
822
|
-
##
|
|
187
|
+
## ✅ Reliability
|
|
823
188
|
|
|
824
|
-
|
|
825
|
-
-
|
|
826
|
-
-
|
|
827
|
-
- ✅ Migrated SerialPort from v12 to v13 (Promise-based)
|
|
828
|
-
- ✅ 100% test coverage (145+ tests)
|
|
829
|
-
- ✅ Complete JSDoc documentation
|
|
830
|
-
- ✅ Architecture improvements and bug fixes
|
|
189
|
+
- **138 Unit and Integration Tests.**
|
|
190
|
+
- **Strict TypeScript:** Full type safety for the entire ESC/POS command set.
|
|
191
|
+
- **Spec-Validated:** QR Code aligned to ESC/POS GS ( k (Functions 165/167/169/180/181) and industrial connection lifecycles.
|
|
831
192
|
|
|
832
193
|
---
|
|
833
194
|
|
|
834
|
-
**
|
|
195
|
+
**Built with ❤️ for mission-critical systems.**
|