enhanced-printer 1.0.4 → 1.0.6
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 +100 -58
- package/lib/job-tracker.js +44 -2
- package/lib/types.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,9 +18,6 @@ A powerful Node.js/Electron library for advanced PDF printing with job tracking,
|
|
|
18
18
|
npm install enhanced-printer
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
> **Note**: Replace `enhanced-printer` with the actual package name you choose when publishing to npm.
|
|
22
|
-
> Check `PUBLISH-CHECKLIST.md` for publishing steps.
|
|
23
|
-
|
|
24
21
|
## Requirements
|
|
25
22
|
|
|
26
23
|
- **Node.js**: 20.0.0 or higher
|
|
@@ -40,11 +37,13 @@ async function printPDF() {
|
|
|
40
37
|
// Print with default settings
|
|
41
38
|
const result = await print({
|
|
42
39
|
printerName: 'Your Printer Name',
|
|
43
|
-
filePath: 'C:\\path\\to\\document.pdf'
|
|
40
|
+
filePath: 'C:\\path\\to\\document.pdf',
|
|
41
|
+
jobName: 'MyJob_001'
|
|
44
42
|
});
|
|
45
43
|
|
|
46
44
|
console.log('Success:', result.success);
|
|
47
45
|
console.log('Job ID:', result.jobId);
|
|
46
|
+
console.log('Job Name:', result.jobName);
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
printPDF();
|
|
@@ -52,13 +51,14 @@ printPDF();
|
|
|
52
51
|
|
|
53
52
|
## Available Methods
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
54
|
+
| Method | Description |
|
|
55
|
+
|--------|-------------|
|
|
56
|
+
| `print()` | Print a PDF with custom settings |
|
|
57
|
+
| `getPrinters()` | Get list of available printers |
|
|
58
|
+
| `getDefaultPrinter()` | Get default printer name |
|
|
59
|
+
| `getJobInfo()` | Get info of a specific job by custom job name |
|
|
60
|
+
| `getJobs()` | Get all print jobs for a printer |
|
|
61
|
+
| `cancelJob()` | Cancel a print job by custom job name |
|
|
62
62
|
|
|
63
63
|
## API Reference
|
|
64
64
|
|
|
@@ -76,7 +76,7 @@ interface PrintOptions {
|
|
|
76
76
|
// Optional settings - defaults to printer preferences if not specified
|
|
77
77
|
pageSize?: string; // e.g., "A4", "A5", "A6", "Letter", "Legal"
|
|
78
78
|
tray?: string | number; // Tray name or number
|
|
79
|
-
jobName?: string; //
|
|
79
|
+
jobName?: string; // Custom job name for tracking (auto-generated if not provided)
|
|
80
80
|
copies?: number; // Number of copies
|
|
81
81
|
orientation?: 'portrait' | 'landscape';
|
|
82
82
|
duplex?: 'simplex' | 'duplex';
|
|
@@ -92,7 +92,7 @@ interface PrintOptions {
|
|
|
92
92
|
interface PrintResult {
|
|
93
93
|
success: boolean;
|
|
94
94
|
jobId?: number; // Job ID from print spooler (if available)
|
|
95
|
-
jobName: string; //
|
|
95
|
+
jobName: string; // Custom job name used for tracking
|
|
96
96
|
error?: string; // Error message if print failed
|
|
97
97
|
}
|
|
98
98
|
```
|
|
@@ -105,10 +105,13 @@ const result = await print({
|
|
|
105
105
|
filePath: './invoice.pdf',
|
|
106
106
|
pageSize: 'A4',
|
|
107
107
|
tray: 2,
|
|
108
|
-
copies: 2
|
|
108
|
+
copies: 2,
|
|
109
|
+
jobName: 'Invoice_12345'
|
|
109
110
|
});
|
|
110
111
|
```
|
|
111
112
|
|
|
113
|
+
---
|
|
114
|
+
|
|
112
115
|
### `getPrinters(): Promise<PrinterInfo[]>`
|
|
113
116
|
|
|
114
117
|
Gets a list of available printers.
|
|
@@ -132,29 +135,80 @@ printers.forEach(p => {
|
|
|
132
135
|
});
|
|
133
136
|
```
|
|
134
137
|
|
|
138
|
+
---
|
|
139
|
+
|
|
135
140
|
### `getDefaultPrinter(): Promise<string | null>`
|
|
136
141
|
|
|
137
142
|
Gets the name of the default printer.
|
|
138
143
|
|
|
139
|
-
|
|
144
|
+
**Example:**
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
const defaultPrinter = await getDefaultPrinter();
|
|
148
|
+
console.log('Default printer:', defaultPrinter);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
### `getJobInfo(customJobName: string, printerName?: string): Promise<JobInfo | null>`
|
|
154
|
+
|
|
155
|
+
Gets detailed information about a specific print job using the custom job name provided during printing.
|
|
156
|
+
|
|
157
|
+
**Returns:**
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
interface JobInfo {
|
|
161
|
+
jobId: number;
|
|
162
|
+
jobName: string; // Document name from Windows
|
|
163
|
+
customJobName: string; // Custom job name provided during print
|
|
164
|
+
printerName: string;
|
|
165
|
+
status: string[]; // List of status flags, e.g. ["PRINTING", "RETAINED"]
|
|
166
|
+
pages: number;
|
|
167
|
+
size?: number; // Size in bytes
|
|
168
|
+
userName?: string;
|
|
169
|
+
submittedTime?: string;
|
|
170
|
+
}
|
|
171
|
+
```
|
|
140
172
|
|
|
141
|
-
|
|
173
|
+
**Possible status values:** `PAUSED`, `ERROR`, `DELETING`, `SPOOLING`, `PRINTING`, `OFFLINE`, `PAPER_OUT`, `PRINTED`, `DELETED`, `BLOCKED_DEVICE_QUEUE`, `USER_INTERVENTION`, `RESTART`, `COMPLETE`, `RETAINED`, `RENDERING_LOCALLY`
|
|
142
174
|
|
|
143
175
|
**Example:**
|
|
144
176
|
|
|
145
177
|
```javascript
|
|
146
|
-
const jobInfo = await
|
|
147
|
-
console.log('Status:', jobInfo.status);
|
|
178
|
+
const jobInfo = await getJobInfo('Invoice_12345');
|
|
179
|
+
console.log('Status:', jobInfo.status); // ["PRINTING", "RETAINED"]
|
|
148
180
|
console.log('Pages:', jobInfo.pages);
|
|
149
181
|
```
|
|
150
182
|
|
|
151
|
-
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
### `getJobs(printerName: string): Promise<JobInfo[]>`
|
|
152
186
|
|
|
153
187
|
Gets all print jobs for a specific printer.
|
|
154
188
|
|
|
155
|
-
|
|
189
|
+
**Example:**
|
|
190
|
+
|
|
191
|
+
```javascript
|
|
192
|
+
const jobs = await getJobs('HP LaserJet');
|
|
193
|
+
jobs.forEach(job => {
|
|
194
|
+
console.log(`Job ${job.jobId} (${job.customJobName}): ${job.status.join(', ')}`);
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
### `cancelJob(customJobName: string, printerName?: string): Promise<boolean>`
|
|
156
201
|
|
|
157
|
-
Cancels a print job.
|
|
202
|
+
Cancels a print job using the custom job name.
|
|
203
|
+
|
|
204
|
+
**Example:**
|
|
205
|
+
|
|
206
|
+
```javascript
|
|
207
|
+
const cancelled = await cancelJob('Invoice_12345');
|
|
208
|
+
console.log('Cancelled:', cancelled);
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
158
212
|
|
|
159
213
|
## Usage Examples
|
|
160
214
|
|
|
@@ -163,7 +217,6 @@ Cancels a print job.
|
|
|
163
217
|
When you don't specify optional settings, the library automatically uses the printer's default configuration:
|
|
164
218
|
|
|
165
219
|
```javascript
|
|
166
|
-
// Uses printer's default page size, tray, and other settings
|
|
167
220
|
const result = await print({
|
|
168
221
|
printerName: 'My Printer',
|
|
169
222
|
filePath: './document.pdf'
|
|
@@ -173,27 +226,14 @@ const result = await print({
|
|
|
173
226
|
### Custom Page Size with Default Tray
|
|
174
227
|
|
|
175
228
|
```javascript
|
|
176
|
-
// Custom page size, but uses printer's default tray
|
|
177
229
|
const result = await print({
|
|
178
230
|
printerName: 'Label Printer',
|
|
179
231
|
filePath: './label.pdf',
|
|
180
|
-
pageSize: 'A6'
|
|
232
|
+
pageSize: 'A6'
|
|
181
233
|
// tray not specified - uses default
|
|
182
234
|
});
|
|
183
235
|
```
|
|
184
236
|
|
|
185
|
-
### Custom Tray with Default Page Size
|
|
186
|
-
|
|
187
|
-
```javascript
|
|
188
|
-
// Specific tray, but uses printer's default page size
|
|
189
|
-
const result = await print({
|
|
190
|
-
printerName: 'Office Printer',
|
|
191
|
-
filePath: './document.pdf',
|
|
192
|
-
tray: 'Tray 2' // or use number: tray: 2
|
|
193
|
-
// pageSize not specified - uses default
|
|
194
|
-
});
|
|
195
|
-
```
|
|
196
|
-
|
|
197
237
|
### Multiple Custom Settings
|
|
198
238
|
|
|
199
239
|
```javascript
|
|
@@ -215,28 +255,31 @@ const result = await print({
|
|
|
215
255
|
```javascript
|
|
216
256
|
const result = await print({
|
|
217
257
|
printerName: 'My Printer',
|
|
218
|
-
filePath: './document.pdf'
|
|
258
|
+
filePath: './document.pdf',
|
|
259
|
+
jobName: 'MyJob_001'
|
|
219
260
|
});
|
|
220
261
|
|
|
221
|
-
if (result.
|
|
222
|
-
//
|
|
223
|
-
const jobInfo = await
|
|
224
|
-
console.log(`Job ${jobInfo.jobId}: ${jobInfo.status}`);
|
|
262
|
+
if (result.success) {
|
|
263
|
+
// Get job info using custom job name
|
|
264
|
+
const jobInfo = await getJobInfo('MyJob_001');
|
|
265
|
+
console.log(`Job ${jobInfo.jobId}: ${jobInfo.status.join(', ')}`);
|
|
266
|
+
|
|
267
|
+
// Get all jobs for the printer
|
|
268
|
+
const allJobs = await getJobs('My Printer');
|
|
269
|
+
console.log(`Total jobs in queue: ${allJobs.length}`);
|
|
225
270
|
|
|
226
271
|
// Cancel if needed
|
|
227
|
-
// await cancelJob('
|
|
272
|
+
// await cancelJob('MyJob_001');
|
|
228
273
|
}
|
|
229
274
|
```
|
|
230
275
|
|
|
231
276
|
## Electron Integration
|
|
232
277
|
|
|
233
|
-
See `examples/electron-integration.js` for a complete example.
|
|
234
|
-
|
|
235
278
|
**Main Process:**
|
|
236
279
|
|
|
237
280
|
```javascript
|
|
238
281
|
const { ipcMain } = require('electron');
|
|
239
|
-
const { print, getPrinters } = require('
|
|
282
|
+
const { print, getPrinters, getJobs } = require('enhanced-printer');
|
|
240
283
|
|
|
241
284
|
ipcMain.handle('print-pdf', async (event, options) => {
|
|
242
285
|
return await print(options);
|
|
@@ -245,6 +288,10 @@ ipcMain.handle('print-pdf', async (event, options) => {
|
|
|
245
288
|
ipcMain.handle('get-printers', async () => {
|
|
246
289
|
return await getPrinters();
|
|
247
290
|
});
|
|
291
|
+
|
|
292
|
+
ipcMain.handle('get-jobs', async (event, printerName) => {
|
|
293
|
+
return await getJobs(printerName);
|
|
294
|
+
});
|
|
248
295
|
```
|
|
249
296
|
|
|
250
297
|
**Renderer Process:**
|
|
@@ -252,7 +299,8 @@ ipcMain.handle('get-printers', async () => {
|
|
|
252
299
|
```javascript
|
|
253
300
|
const result = await window.printerAPI.print({
|
|
254
301
|
printerName: 'My Printer',
|
|
255
|
-
filePath: pdfPath
|
|
302
|
+
filePath: pdfPath,
|
|
303
|
+
jobName: 'MyJob_001'
|
|
256
304
|
});
|
|
257
305
|
```
|
|
258
306
|
|
|
@@ -261,12 +309,13 @@ const result = await window.printerAPI.print({
|
|
|
261
309
|
This library is written in TypeScript and includes full type definitions.
|
|
262
310
|
|
|
263
311
|
```typescript
|
|
264
|
-
import { print, PrintOptions, PrintResult } from '
|
|
312
|
+
import { print, PrintOptions, PrintResult, JobInfo } from 'enhanced-printer';
|
|
265
313
|
|
|
266
314
|
const options: PrintOptions = {
|
|
267
315
|
printerName: 'My Printer',
|
|
268
316
|
filePath: './document.pdf',
|
|
269
|
-
pageSize: 'A4'
|
|
317
|
+
pageSize: 'A4',
|
|
318
|
+
jobName: 'TypedJob_001'
|
|
270
319
|
};
|
|
271
320
|
|
|
272
321
|
const result: PrintResult = await print(options);
|
|
@@ -276,7 +325,9 @@ const result: PrintResult = await print(options);
|
|
|
276
325
|
|
|
277
326
|
1. **PDF Printing**: Uses `pdf-to-printer` library which wraps SumatraPDF on Windows
|
|
278
327
|
2. **Job ID Retrieval**: Queries Windows print spooler using PowerShell commands
|
|
279
|
-
3. **
|
|
328
|
+
3. **Custom Job Names**: Maps user-provided job names to system job IDs for easy tracking
|
|
329
|
+
4. **Status Decoding**: Converts numeric Windows job status bitmask into human-readable status flags
|
|
330
|
+
5. **Default Settings**: When settings aren't specified, SumatraPDF uses the printer's DEVMODE defaults
|
|
280
331
|
|
|
281
332
|
## Limitations
|
|
282
333
|
|
|
@@ -284,15 +335,6 @@ const result: PrintResult = await print(options);
|
|
|
284
335
|
- **PDF Files**: Designed for PDF printing (for raw data, convert to PDF first)
|
|
285
336
|
- **Job ID Timing**: Very fast printers may complete jobs before ID can be retrieved
|
|
286
337
|
|
|
287
|
-
## Examples
|
|
288
|
-
|
|
289
|
-
See the `examples/` directory for complete working examples:
|
|
290
|
-
|
|
291
|
-
- `basic-print.js` - Simple printing with defaults
|
|
292
|
-
- `custom-settings.js` - Custom page sizes, trays, and options
|
|
293
|
-
- `job-monitoring.js` - Job status tracking
|
|
294
|
-
- `electron-integration.js` - Electron app integration
|
|
295
|
-
|
|
296
338
|
## Troubleshooting
|
|
297
339
|
|
|
298
340
|
### Job ID is undefined
|
package/lib/job-tracker.js
CHANGED
|
@@ -6,6 +6,48 @@ exports.getJobInfo = getJobInfo;
|
|
|
6
6
|
exports.getAllJobs = getAllJobs;
|
|
7
7
|
const child_process_1 = require("child_process");
|
|
8
8
|
const job_name_mapper_1 = require("./job-name-mapper");
|
|
9
|
+
/**
|
|
10
|
+
* Windows print job status flags (bitmask values)
|
|
11
|
+
* See: https://learn.microsoft.com/en-us/windows/win32/printdocs/job-info-2
|
|
12
|
+
*/
|
|
13
|
+
const JOB_STATUS_FLAGS = {
|
|
14
|
+
0x0001: 'PAUSED',
|
|
15
|
+
0x0002: 'ERROR',
|
|
16
|
+
0x0004: 'DELETING',
|
|
17
|
+
0x0008: 'SPOOLING',
|
|
18
|
+
0x0010: 'PRINTING',
|
|
19
|
+
0x0020: 'OFFLINE',
|
|
20
|
+
0x0040: 'PAPER_OUT',
|
|
21
|
+
0x0080: 'PRINTED',
|
|
22
|
+
0x0100: 'DELETED',
|
|
23
|
+
0x0200: 'BLOCKED_DEVICE_QUEUE',
|
|
24
|
+
0x0400: 'USER_INTERVENTION',
|
|
25
|
+
0x0800: 'RESTART',
|
|
26
|
+
0x1000: 'COMPLETE',
|
|
27
|
+
0x2000: 'RETAINED',
|
|
28
|
+
0x4000: 'RENDERING_LOCALLY',
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Decodes a numeric job status bitmask into a list of status strings.
|
|
32
|
+
* e.g. 8210 (0x2012) => ["Error", "Printing", "Retained"]
|
|
33
|
+
*/
|
|
34
|
+
function decodeJobStatus(status) {
|
|
35
|
+
// If it's already a string, return it as a single-element array
|
|
36
|
+
if (typeof status === 'string') {
|
|
37
|
+
return status ? [status] : ['Unknown'];
|
|
38
|
+
}
|
|
39
|
+
const numericStatus = Number(status);
|
|
40
|
+
if (isNaN(numericStatus) || numericStatus === 0) {
|
|
41
|
+
return ['None'];
|
|
42
|
+
}
|
|
43
|
+
const flags = [];
|
|
44
|
+
for (const [bit, name] of Object.entries(JOB_STATUS_FLAGS)) {
|
|
45
|
+
if (numericStatus & Number(bit)) {
|
|
46
|
+
flags.push(name);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return flags.length > 0 ? flags : ['Unknown'];
|
|
50
|
+
}
|
|
9
51
|
/**
|
|
10
52
|
* Retrieves job ID by document name using PowerShell
|
|
11
53
|
*/
|
|
@@ -45,7 +87,7 @@ async function getJobInfoBySystemId(printerName, jobId) {
|
|
|
45
87
|
jobName: result.DocumentName || '',
|
|
46
88
|
customJobName: customName || result.DocumentName || '',
|
|
47
89
|
printerName: printerName,
|
|
48
|
-
status: result.JobStatus
|
|
90
|
+
status: decodeJobStatus(result.JobStatus),
|
|
49
91
|
pages: result.TotalPages || 0,
|
|
50
92
|
size: result.Size,
|
|
51
93
|
userName: result.UserName,
|
|
@@ -90,7 +132,7 @@ async function getAllJobs(printerName) {
|
|
|
90
132
|
jobName: job.DocumentName || '',
|
|
91
133
|
customJobName: customName || job.DocumentName || '', // Use custom name if available
|
|
92
134
|
printerName: printerName,
|
|
93
|
-
status: job.JobStatus
|
|
135
|
+
status: decodeJobStatus(job.JobStatus),
|
|
94
136
|
pages: job.TotalPages || 0,
|
|
95
137
|
size: job.Size,
|
|
96
138
|
userName: job.UserName,
|
package/lib/types.d.ts
CHANGED
|
@@ -68,8 +68,8 @@ export interface JobInfo {
|
|
|
68
68
|
customJobName: string;
|
|
69
69
|
/** Name of the printer */
|
|
70
70
|
printerName: string;
|
|
71
|
-
/** Current status of the job */
|
|
72
|
-
status: string;
|
|
71
|
+
/** Current status of the job (list of active status flags) */
|
|
72
|
+
status: string[];
|
|
73
73
|
/** Number of pages */
|
|
74
74
|
pages: number;
|
|
75
75
|
/** Size in bytes */
|
package/package.json
CHANGED