@plevands/epson-thermal-printer 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Colegio Plevand's
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,576 @@
1
+ # @plevands/epson-thermal-printer
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@plevands/epson-thermal-printer.svg)](https://www.npmjs.com/package/@plevands/epson-thermal-printer)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
6
+
7
+ Library for Epson thermal printer integration with PDF support and React hooks.
8
+
9
+ ## Requirements
10
+
11
+ - **Node.js** 18.x or higher
12
+ - **React** 18.x or higher (optional, for hooks API)
13
+ - **pdfjs-dist** 4.x or higher (optional, for PDF processing)
14
+ - Epson thermal printer with network connectivity
15
+
16
+ ## Features
17
+
18
+ - ✅ **Official Epson ePOS SDK** integration with TypeScript support
19
+ - 🔄 **Lazy loading** - SDK loads automatically on first use
20
+ - 📄 **PDF Processing** - Intelligent margin trimming and scaling for thermal printers
21
+ - ⚛️ **React Hooks** - Modern hooks-based API (`useEpsonPrinter`, `usePrinterConfig`, `usePdfProcessor`)
22
+ - 🔧 **Fully Configurable** - Control PDF processing, print quality, paper width, and more
23
+ - 📦 **TypeScript First** - Complete type definitions included
24
+ - 🎯 **Zero Config** - Works out of the box with sensible defaults
25
+ - ✨ **Self-contained** - Epson SDK is embedded, no external dependencies to configure
26
+
27
+ ## Installation
28
+
29
+ ### Development with npm link
30
+
31
+ ```bash
32
+ # In the library directory
33
+ npm install
34
+ npm run build
35
+ npm link
36
+
37
+ # In your project
38
+ npm link @plevands/epson-thermal-printer
39
+ ```
40
+
41
+ ### Usage in Your Projects
42
+
43
+ ```bash
44
+ npm install @plevands/epson-thermal-printer
45
+ ```
46
+
47
+ > **Note:** The Epson ePOS SDK v2.27.0 is embedded in the library. No additional setup required!
48
+
49
+ ### PDF Processing (Optional)
50
+
51
+ If you want to use PDF processing features (`processPdfFile`, `usePdfProcessor`), install `pdfjs-dist`:
52
+
53
+ ```bash
54
+ npm install pdfjs-dist
55
+ ```
56
+
57
+ If you don't use PDF features, you don't need to install it. The library uses dynamic imports so `pdfjs-dist` is only loaded when you call PDF processing functions.
58
+
59
+ ## Setup (Optional)
60
+
61
+ ### Custom PDF.js Worker
62
+
63
+ The PDF.js worker is auto-configured to use a CDN. Only configure it if you want to use your own worker:
64
+
65
+ ```typescript
66
+ import { configurePdfWorker } from '@plevands/epson-thermal-printer';
67
+
68
+ // Use your own worker instead of CDN
69
+ configurePdfWorker('/assets/pdf.worker.min.mjs');
70
+ ```
71
+
72
+ ## Quick Start
73
+
74
+ ### Basic Usage (Hooks API)
75
+
76
+ ```typescript
77
+ import { useEpsonPrinter, usePrinterConfig } from '@plevands/epson-thermal-printer';
78
+
79
+ function MyPrintComponent() {
80
+ const { config } = usePrinterConfig();
81
+ const { print, isLoading, error } = useEpsonPrinter(config);
82
+
83
+ const handlePrint = async () => {
84
+ const canvas = document.querySelector('canvas') as HTMLCanvasElement;
85
+ const result = await print(canvas);
86
+
87
+ if (result.success) {
88
+ alert('Print successful!');
89
+ } else {
90
+ alert(`Print failed: ${result.message}`);
91
+ }
92
+ };
93
+
94
+ return (
95
+ <div>
96
+ <button onClick={handlePrint} disabled={isLoading}>
97
+ {isLoading ? 'Printing...' : 'Print'}
98
+ </button>
99
+ {error && <p>Error: {error}</p>}
100
+ </div>
101
+ );
102
+ }
103
+ ```
104
+
105
+ ### Service API (No React)
106
+
107
+ ```typescript
108
+ import { EposPrintService } from '@plevands/epson-thermal-printer';
109
+
110
+ const service = new EposPrintService({
111
+ printerIP: '192.168.1.100',
112
+ printerPort: 80,
113
+ deviceId: 'local_printer',
114
+ });
115
+
116
+ // SDK loads automatically from configured path (default: /epos-2.27.0.js)
117
+ const result = await service.printCanvas(canvas);
118
+ ```
119
+
120
+ ### Check Printer Connection
121
+
122
+ You can verify if the printer is online before showing print options. This is useful to conditionally display UI elements or handle offline printers gracefully.
123
+
124
+ **Using Hooks (React):**
125
+
126
+ ```typescript
127
+ import { useEpsonPrinter, usePrinterConfig } from '@plevands/epson-thermal-printer';
128
+ import { useEffect, useState } from 'react';
129
+
130
+ function PrinterPanel() {
131
+ const { config } = usePrinterConfig();
132
+ const { checkConnection, print, isLoading, error } = useEpsonPrinter(config);
133
+ const [isOnline, setIsOnline] = useState<boolean | null>(null);
134
+
135
+ // Check connection when component mounts or config changes
136
+ useEffect(() => {
137
+ checkConnection().then(result => {
138
+ setIsOnline(result.success);
139
+ });
140
+ }, [checkConnection]);
141
+
142
+ if (isOnline === null) {
143
+ return <span>Checking printer connection...</span>;
144
+ }
145
+
146
+ if (!isOnline) {
147
+ return <span>⚠️ Printer offline: {error}</span>;
148
+ }
149
+
150
+ return (
151
+ <div>
152
+ <span>✅ Printer connected</span>
153
+ <button onClick={() => print(canvas)} disabled={isLoading}>
154
+ Print
155
+ </button>
156
+ </div>
157
+ );
158
+ }
159
+ ```
160
+
161
+ **Using Service API (No React):**
162
+
163
+ ```typescript
164
+ import { EposPrintService } from '@plevands/epson-thermal-printer';
165
+
166
+ const service = new EposPrintService({
167
+ printerIP: '192.168.1.100',
168
+ printerPort: 80,
169
+ });
170
+
171
+ // Check connection without printing anything
172
+ const result = await service.checkConnection();
173
+
174
+ if (result.success) {
175
+ console.log('Printer is online and ready!');
176
+ } else {
177
+ console.log('Printer offline:', result.message);
178
+ // result.message includes helpful details like:
179
+ // - "Printer offline"
180
+ // - "Cover open"
181
+ // - "Out of paper"
182
+ // - "Paper running low"
183
+ }
184
+ ```
185
+
186
+ | Method | Prints? | Use Case |
187
+ |--------|---------|----------|
188
+ | `checkConnection()` | ❌ No | Verify printer is online |
189
+ | `testConnection()` | ✅ Yes | Print a small test receipt |
190
+
191
+ ### With PDF Processing
192
+
193
+ ```typescript
194
+ import {
195
+ useEpsonPrinter,
196
+ usePdfProcessor,
197
+ usePrinterConfig
198
+ } from '@plevands/epson-thermal-printer';
199
+
200
+ function PdfPrinter() {
201
+ const { config } = usePrinterConfig();
202
+ const { processFile } = usePdfProcessor({
203
+ enabled: true,
204
+ trimMargins: { top: 10, bottom: 10, left: 5, right: 5 },
205
+ targetWidth: 576, // 80mm paper
206
+ monochromeThreshold: 160,
207
+ });
208
+ const { printPages } = useEpsonPrinter(config);
209
+
210
+ const handlePrint = async (file: File) => {
211
+ // Process PDF with margin trimming and scaling
212
+ const pages = await processFile(file);
213
+
214
+ // Print all processed pages
215
+ const result = await printPages(
216
+ pages.map(p => p.canvas),
217
+ { pageSelection: 'all' }
218
+ );
219
+ };
220
+
221
+ return <div>{/* Your UI */}</div>;
222
+ }
223
+ ```
224
+
225
+ ## Configuration
226
+
227
+ ### PDF Processing Options
228
+
229
+ ```typescript
230
+ interface PdfProcessingConfig {
231
+ enabled: boolean; // Enable/disable processing
232
+ trimMargins?: {
233
+ top?: number; // Default: 8px
234
+ bottom?: number; // Default: 8px
235
+ left?: number; // Default: 8px
236
+ right?: number; // Default: 8px
237
+ };
238
+ targetWidth?: number; // Default: 576 (80mm paper)
239
+ scale?: number; // Render scale, default: 3
240
+ monochromeThreshold?: number; // 0-255, default: 160
241
+ }
242
+ ```
243
+
244
+ #### Paper Width Reference
245
+
246
+ | Paper Size | Width (pixels) | `targetWidth` value |
247
+ |------------|----------------|---------------------|
248
+ | 80mm | 576px | 576 (default) |
249
+ | 58mm | 384px | 384 |
250
+
251
+ ### Print Options
252
+
253
+ ```typescript
254
+ interface PrintOptions {
255
+ halftone?: 0 | 1 | 2; // 0=DITHER, 1=ERROR_DIFFUSION, 2=THRESHOLD
256
+ brightness?: number; // 0.1 to 10.0, default 1.0
257
+ mode?: 'mono' | 'gray16';
258
+ cut?: boolean;
259
+ align?: 'left' | 'center' | 'right';
260
+ }
261
+ ```
262
+
263
+ ### Printer Configuration
264
+
265
+ ```typescript
266
+ interface EpsonPrinterConfig {
267
+ printerIP: string; // Required
268
+ printerPort?: number; // Default: 80
269
+ deviceId?: string; // Default: 'local_printer'
270
+ timeout?: number; // Default: 60000ms
271
+ }
272
+ ```
273
+
274
+ ## API Reference
275
+
276
+ ### Hooks
277
+
278
+ #### `useEpsonPrinter(config, options?)`
279
+
280
+ Main hook for printer operations with automatic SDK loading.
281
+
282
+ **Returns:**
283
+ - `print(canvas)` - Print a single canvas
284
+ - `printPages(canvases, options?)` - Print multiple pages
285
+ - `testConnection()` - Test printer connection
286
+ - `isLoading` - Loading state
287
+ - `error` - Error message if any
288
+ - `sdkStatus` - SDK loading status
289
+
290
+ #### `usePrinterConfig()`
291
+
292
+ Manages printer configuration with localStorage persistence.
293
+
294
+ **Returns:**
295
+ - `config` - Current configuration
296
+ - `updateConfig(partial)` - Update configuration
297
+ - `resetConfig()` - Reset to defaults
298
+ - `isConfigured` - Boolean
299
+
300
+ #### `usePdfProcessor(config?)`
301
+
302
+ Process PDF files with configurable options.
303
+
304
+ **Returns:**
305
+ - `processFile(file)` - Process PDF file
306
+ - `isProcessing` - Processing state
307
+ - `error` - Error message if any
308
+
309
+ ### Services
310
+
311
+ #### `EposPrintService`
312
+
313
+ Core service class for printing operations.
314
+
315
+ ```typescript
316
+ const service = new EposPrintService(config, options);
317
+
318
+ // Methods
319
+ await service.printCanvas(canvas);
320
+ await service.printWithBuilder((builder) => {
321
+ builder.addTextAlign('center');
322
+ builder.addText('Hello World!\n');
323
+ builder.addFeedLine(3);
324
+ builder.addCut('feed');
325
+ });
326
+ await service.printPages(canvases, { header: 'Header Text' });
327
+ await service.testConnection(); // Prints a test receipt
328
+ await service.printTestPage(); // Prints a detailed test page
329
+ ```
330
+
331
+ #### SDK Loader Functions
332
+
333
+ ```typescript
334
+ import {
335
+ loadEpsonSDK,
336
+ isEpsonSDKLoaded,
337
+ initializeEpsonSDK,
338
+ getEpsonSDK,
339
+ checkEpsonSDKStatus,
340
+ } from '@plevands/epson-thermal-printer';
341
+
342
+ // Check if loaded
343
+ const loaded = isEpsonSDKLoaded();
344
+
345
+ // Check detailed SDK status
346
+ const status = checkEpsonSDKStatus();
347
+ // Returns: { loaded: boolean, loading: boolean, error: string | null, classes: string[] }
348
+
349
+ // Get SDK instance (after loading)
350
+ const sdk = getEpsonSDK();
351
+
352
+ // Manual initialization (optional)
353
+ const result = await initializeEpsonSDK();
354
+
355
+ // Note: SDK loads automatically on first print - no manual call needed!
356
+ ```
357
+
358
+ #### PDF Processing Functions
359
+
360
+ ```typescript
361
+ import {
362
+ configurePdfWorker,
363
+ isPdfWorkerConfigured,
364
+ PDFJS_CDN_WORKER_URL,
365
+ processPdfFile,
366
+ processPdfPage,
367
+ } from '@plevands/epson-thermal-printer';
368
+
369
+ // Configure PDF.js worker (optional but recommended)
370
+ configurePdfWorker(PDFJS_CDN_WORKER_URL);
371
+
372
+ // Check if worker is configured
373
+ const configured = isPdfWorkerConfigured();
374
+
375
+ // Process a PDF file
376
+ const pages = await processPdfFile(file, {
377
+ targetWidth: 576,
378
+ trimMargins: { top: 10, bottom: 10 },
379
+ });
380
+ ```
381
+
382
+ ### Logging Configuration
383
+
384
+ By default, only errors are logged to the console. You can enable debug logs or intercept all logs with a custom handler:
385
+
386
+ ```typescript
387
+ import { configureLogger } from '@plevands/epson-thermal-printer';
388
+
389
+ // Enable all logs (debug, warn, error) in console
390
+ configureLogger({ enabled: true });
391
+
392
+ // Intercept all logs with custom handler
393
+ configureLogger({
394
+ enabled: false, // Don't show debug/warn in console (errors always shown)
395
+ onLog: (entry) => {
396
+ // entry: { level: 'debug' | 'warn' | 'error', message: string, args?: unknown[] }
397
+ myLoggingService.log(entry.level, entry.message, entry.args);
398
+ },
399
+ });
400
+
401
+ // Combine both: show in console AND send to custom handler
402
+ configureLogger({
403
+ enabled: true,
404
+ onLog: (entry) => sendToAnalytics(entry),
405
+ });
406
+ ```
407
+
408
+ ## Running the Demo App
409
+
410
+ This repository includes a demo application to test the library:
411
+
412
+ ```bash
413
+ # Clone the repository
414
+ git clone https://github.com/plevands/epson-printer.git
415
+ cd epson-printer
416
+
417
+ # Install dependencies
418
+ npm install
419
+
420
+ # Start the development server
421
+ npm run dev
422
+
423
+ # Open in browser: http://localhost:5123
424
+ ```
425
+
426
+ The demo app demonstrates:
427
+ - 🖨️ Printer configuration
428
+ - 📄 PDF file upload and preview
429
+ - 🎨 Real-time PDF processing visualization
430
+ - ⚙️ Print controls with customizable options
431
+
432
+ ## Development Workflow with npm link
433
+
434
+ ### In the Library
435
+
436
+ ```bash
437
+ # Make changes to the library
438
+ npm run build # Build once
439
+ # OR
440
+ npm run dev:lib # Watch mode - rebuilds on changes
441
+ ```
442
+
443
+ ### In Your Project
444
+
445
+ ```bash
446
+ # Link the library (once)
447
+ npm link @plevands/epson-thermal-printer
448
+
449
+ # Your project will use the local version
450
+ # Changes to the library reflect immediately after rebuild
451
+ ```
452
+
453
+ ### Unlinking
454
+
455
+ ```bash
456
+ # In your project
457
+ npm unlink @plevands/epson-thermal-printer
458
+
459
+ # In the library
460
+ npm unlink
461
+ ```
462
+
463
+ ## Network Requirements
464
+
465
+ ### CORS Configuration
466
+
467
+ The printer must allow CORS requests from your application domain. Configure your printer's web interface:
468
+
469
+ 1. Access printer at `http://[PRINTER_IP]`
470
+ 2. Navigate to Network > CORS settings
471
+ 3. Add your application origin (e.g., `http://localhost:5173`)
472
+
473
+ ### Firewall
474
+
475
+ Ensure port 80 (or custom port) is accessible on the printer's IP address.
476
+
477
+ ## Technical Notes
478
+
479
+ ### SDK Inheritance Pattern
480
+
481
+ The Epson ePOS SDK uses JavaScript prototypal inheritance where `ePOSPrint` extends `ePOSBuilder` via `ePOSPrint.prototype = new ePOSBuilder()`. This pattern has an important implication:
482
+
483
+ **Problem:** When calling builder methods directly on `ePOSPrint` instance (e.g., `printer.addText()`), the commands accumulate in a shared prototype `message` property, not an instance property. When `send()` is called internally, it creates a new empty `ePOSBuilder` instead of using the accumulated commands.
484
+
485
+ **Solution:** This library handles this by using separate `ePOSBuilder` instances:
486
+
487
+ ```typescript
488
+ // ✅ Correct pattern (used internally by this library)
489
+ const builder = new epson.ePOSBuilder();
490
+ builder.addText('Hello');
491
+ builder.addCut(builder.CUT_FEED);
492
+ const xml = builder.toString();
493
+
494
+ const printer = new epson.ePOSPrint(printerUrl);
495
+ printer.send(xml); // Pass XML explicitly
496
+ ```
497
+
498
+ If you're extending this library or using the raw SDK, always follow this pattern to avoid empty print requests.
499
+
500
+ ## Troubleshooting
501
+
502
+ ### SDK Not Loading
503
+
504
+ The SDK loads automatically on first print. If you see errors:
505
+
506
+ 1. Check console for loading errors
507
+ 2. Verify `public/epos-2.27.0.js` exists in your build
508
+ 3. Try manual initialization:
509
+ ```typescript
510
+ import { initializeEpsonSDK } from '@plevands/epson-thermal-printer';
511
+ await initializeEpsonSDK();
512
+ ```
513
+
514
+ ### Connection Failed
515
+
516
+ - Verify printer IP address is correct
517
+ - Check CORS configuration on printer
518
+ - Ensure printer is on same network
519
+ - Test connection:
520
+ ```typescript
521
+ const { testConnection } = useEpsonPrinter(config);
522
+ await testConnection();
523
+ ```
524
+
525
+ ### Print Quality Issues
526
+
527
+ Adjust print options:
528
+
529
+ ```typescript
530
+ const { print } = useEpsonPrinter(config, {
531
+ halftone: 1, // Try different values (0, 1, 2)
532
+ brightness: 1.2, // Increase for lighter prints
533
+ mode: 'mono', // Or 'gray16' for grayscale
534
+ });
535
+ ```
536
+
537
+ ### PDF Processing Issues
538
+
539
+ Fine-tune processing config:
540
+
541
+ ```typescript
542
+ const { processFile } = usePdfProcessor({
543
+ enabled: true,
544
+ trimMargins: { top: 0, bottom: 0, left: 0, right: 0 }, // Disable trimming
545
+ monochromeThreshold: 180, // Higher = more white
546
+ });
547
+ ```
548
+
549
+ ## Examples
550
+
551
+ See the included demo app in this repository for complete examples of all features.
552
+
553
+ ```bash
554
+ npm run dev # Start demo app
555
+ npm run build # Build library for production
556
+ npm run lint # Run ESLint
557
+ ```
558
+
559
+ ## Browser Support
560
+
561
+ | Browser | Supported |
562
+ |---------|-----------|
563
+ | Chrome | ✅ 90+ |
564
+ | Firefox | ✅ 88+ |
565
+ | Safari | ✅ 14+ |
566
+ | Edge | ✅ 90+ |
567
+
568
+ > **Note:** Requires modern browser with ES2020+ and Canvas API support.
569
+
570
+ ## License
571
+
572
+ MIT © [Colegio Plevand's](https://github.com/plevands)
573
+
574
+ ## Contributing
575
+
576
+ Contributions welcome! Please feel free to submit issues and pull requests.
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Hooks exports for @plevands/epson-thermal-printer
3
+ */
4
+ export { useEpsonPrinter } from './useEpsonPrinter';
5
+ export { usePrinterConfig } from './usePrinterConfig';
6
+ export { usePdfProcessor } from './usePdfProcessor';
@@ -0,0 +1,2 @@
1
+ import { EpsonPrinterConfig, PrintOptions, UseEpsonPrinterReturn } from '../types';
2
+ export declare function useEpsonPrinter(config: EpsonPrinterConfig, options?: PrintOptions): UseEpsonPrinterReturn;
@@ -0,0 +1,2 @@
1
+ import { PdfProcessingConfig, UsePdfProcessorReturn } from '../types';
2
+ export declare function usePdfProcessor(config?: PdfProcessingConfig): UsePdfProcessorReturn;
@@ -0,0 +1,2 @@
1
+ import { UsePrinterConfigReturn } from '../types';
2
+ export declare function usePrinterConfig(): UsePrinterConfigReturn;