enhanced-printer 1.0.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/LICENSE +21 -0
- package/README.md +313 -0
- package/lib/index.d.ts +14 -0
- package/lib/index.js +22 -0
- package/lib/job-tracker.d.ts +13 -0
- package/lib/job-tracker.js +141 -0
- package/lib/print-manager.d.ts +25 -0
- package/lib/print-manager.js +183 -0
- package/lib/types.d.ts +75 -0
- package/lib/types.js +2 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Akshay Malaviya
|
|
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,313 @@
|
|
|
1
|
+
# Enhanced Printer Library
|
|
2
|
+
|
|
3
|
+
A powerful Node.js/Electron library for advanced PDF printing with job tracking, custom page sizes, and tray selection. Compatible with **Node.js 20+** and **Electron 39+**.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
✅ **PDF Printing** - Print PDF files with full control
|
|
8
|
+
✅ **Job ID Tracking** - Retrieve Windows print spooler job IDs
|
|
9
|
+
✅ **Custom Page Sizes** - Support for standard and custom paper sizes
|
|
10
|
+
✅ **Tray Selection** - Select specific printer trays/bins
|
|
11
|
+
✅ **Default Preferences** - Automatically uses printer defaults when settings not specified
|
|
12
|
+
✅ **Job Monitoring** - Query job status and manage print queue
|
|
13
|
+
✅ **Electron Compatible** - Works seamlessly with Electron 39+
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install enhanced-printer
|
|
19
|
+
```
|
|
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
|
+
## Requirements
|
|
25
|
+
|
|
26
|
+
- **Node.js**: 20.0.0 or higher
|
|
27
|
+
- **Electron**: 39.0.0 or higher (optional)
|
|
28
|
+
- **OS**: Windows (uses PowerShell for job tracking)
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
const { print, getPrinters } = require('enhanced-printer');
|
|
34
|
+
|
|
35
|
+
async function printPDF() {
|
|
36
|
+
// Get available printers
|
|
37
|
+
const printers = await getPrinters();
|
|
38
|
+
console.log('Available printers:', printers);
|
|
39
|
+
|
|
40
|
+
// Print with default settings
|
|
41
|
+
const result = await print({
|
|
42
|
+
printerName: 'Your Printer Name',
|
|
43
|
+
filePath: 'C:\\path\\to\\document.pdf'
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
console.log('Success:', result.success);
|
|
47
|
+
console.log('Job ID:', result.jobId);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
printPDF();
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## API Reference
|
|
54
|
+
|
|
55
|
+
### `print(options: PrintOptions): Promise<PrintResult>`
|
|
56
|
+
|
|
57
|
+
Prints a PDF file with the specified options.
|
|
58
|
+
|
|
59
|
+
**Parameters:**
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
interface PrintOptions {
|
|
63
|
+
printerName: string; // Required: Name of the printer
|
|
64
|
+
filePath: string; // Required: Path to PDF file
|
|
65
|
+
|
|
66
|
+
// Optional settings - defaults to printer preferences if not specified
|
|
67
|
+
pageSize?: string; // e.g., "A4", "A5", "A6", "Letter", "Legal"
|
|
68
|
+
tray?: string | number; // Tray name or number
|
|
69
|
+
jobName?: string; // Document/job name for tracking
|
|
70
|
+
copies?: number; // Number of copies
|
|
71
|
+
orientation?: 'portrait' | 'landscape';
|
|
72
|
+
duplex?: 'simplex' | 'duplex';
|
|
73
|
+
monochrome?: boolean; // Black & white printing
|
|
74
|
+
pages?: string; // e.g., "1-3,5" to print specific pages
|
|
75
|
+
subset?: 'odd' | 'even'; // Print only odd or even pages
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Returns:**
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
interface PrintResult {
|
|
83
|
+
success: boolean;
|
|
84
|
+
jobId?: number; // Job ID from print spooler (if available)
|
|
85
|
+
jobName: string; // Document name used for tracking
|
|
86
|
+
error?: string; // Error message if print failed
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Example:**
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
const result = await print({
|
|
94
|
+
printerName: 'HP LaserJet',
|
|
95
|
+
filePath: './invoice.pdf',
|
|
96
|
+
pageSize: 'A4',
|
|
97
|
+
tray: 2,
|
|
98
|
+
copies: 2
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### `getPrinters(): Promise<PrinterInfo[]>`
|
|
103
|
+
|
|
104
|
+
Gets a list of available printers.
|
|
105
|
+
|
|
106
|
+
**Returns:**
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
interface PrinterInfo {
|
|
110
|
+
name: string;
|
|
111
|
+
isDefault: boolean;
|
|
112
|
+
status: string;
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Example:**
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
const printers = await getPrinters();
|
|
120
|
+
printers.forEach(p => {
|
|
121
|
+
console.log(`${p.name} - ${p.status} ${p.isDefault ? '(Default)' : ''}`);
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### `getDefaultPrinter(): Promise<string | null>`
|
|
126
|
+
|
|
127
|
+
Gets the name of the default printer.
|
|
128
|
+
|
|
129
|
+
### `getJobStatus(printerName: string, jobId: number): Promise<JobInfo | null>`
|
|
130
|
+
|
|
131
|
+
Gets information about a specific print job.
|
|
132
|
+
|
|
133
|
+
**Example:**
|
|
134
|
+
|
|
135
|
+
```javascript
|
|
136
|
+
const jobInfo = await getJobStatus('HP LaserJet', 123);
|
|
137
|
+
console.log('Status:', jobInfo.status);
|
|
138
|
+
console.log('Pages:', jobInfo.pages);
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### `getPrinterJobs(printerName: string): Promise<JobInfo[]>`
|
|
142
|
+
|
|
143
|
+
Gets all print jobs for a specific printer.
|
|
144
|
+
|
|
145
|
+
### `cancelJob(printerName: string, jobId: number): Promise<boolean>`
|
|
146
|
+
|
|
147
|
+
Cancels a print job.
|
|
148
|
+
|
|
149
|
+
## Usage Examples
|
|
150
|
+
|
|
151
|
+
### Using Printer Defaults
|
|
152
|
+
|
|
153
|
+
When you don't specify optional settings, the library automatically uses the printer's default configuration:
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
// Uses printer's default page size, tray, and other settings
|
|
157
|
+
const result = await print({
|
|
158
|
+
printerName: 'My Printer',
|
|
159
|
+
filePath: './document.pdf'
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Custom Page Size with Default Tray
|
|
164
|
+
|
|
165
|
+
```javascript
|
|
166
|
+
// Custom page size, but uses printer's default tray
|
|
167
|
+
const result = await print({
|
|
168
|
+
printerName: 'Label Printer',
|
|
169
|
+
filePath: './label.pdf',
|
|
170
|
+
pageSize: 'A6' // 4x6 inches for labels
|
|
171
|
+
// tray not specified - uses default
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Custom Tray with Default Page Size
|
|
176
|
+
|
|
177
|
+
```javascript
|
|
178
|
+
// Specific tray, but uses printer's default page size
|
|
179
|
+
const result = await print({
|
|
180
|
+
printerName: 'Office Printer',
|
|
181
|
+
filePath: './document.pdf',
|
|
182
|
+
tray: 'Tray 2' // or use number: tray: 2
|
|
183
|
+
// pageSize not specified - uses default
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Multiple Custom Settings
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
const result = await print({
|
|
191
|
+
printerName: 'My Printer',
|
|
192
|
+
filePath: './document.pdf',
|
|
193
|
+
pageSize: 'Legal',
|
|
194
|
+
tray: 1,
|
|
195
|
+
copies: 3,
|
|
196
|
+
orientation: 'landscape',
|
|
197
|
+
duplex: 'duplex',
|
|
198
|
+
monochrome: true,
|
|
199
|
+
jobName: 'Important-Document'
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Job Tracking
|
|
204
|
+
|
|
205
|
+
```javascript
|
|
206
|
+
const result = await print({
|
|
207
|
+
printerName: 'My Printer',
|
|
208
|
+
filePath: './document.pdf'
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
if (result.jobId) {
|
|
212
|
+
// Monitor job status
|
|
213
|
+
const jobInfo = await getJobStatus('My Printer', result.jobId);
|
|
214
|
+
console.log(`Job ${jobInfo.jobId}: ${jobInfo.status}`);
|
|
215
|
+
|
|
216
|
+
// Cancel if needed
|
|
217
|
+
// await cancelJob('My Printer', result.jobId);
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Electron Integration
|
|
222
|
+
|
|
223
|
+
See `examples/electron-integration.js` for a complete example.
|
|
224
|
+
|
|
225
|
+
**Main Process:**
|
|
226
|
+
|
|
227
|
+
```javascript
|
|
228
|
+
const { ipcMain } = require('electron');
|
|
229
|
+
const { print, getPrinters } = require('@your-org/enhanced-printer');
|
|
230
|
+
|
|
231
|
+
ipcMain.handle('print-pdf', async (event, options) => {
|
|
232
|
+
return await print(options);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
ipcMain.handle('get-printers', async () => {
|
|
236
|
+
return await getPrinters();
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Renderer Process:**
|
|
241
|
+
|
|
242
|
+
```javascript
|
|
243
|
+
const result = await window.printerAPI.print({
|
|
244
|
+
printerName: 'My Printer',
|
|
245
|
+
filePath: pdfPath
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## TypeScript Support
|
|
250
|
+
|
|
251
|
+
This library is written in TypeScript and includes full type definitions.
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
import { print, PrintOptions, PrintResult } from '@your-org/enhanced-printer';
|
|
255
|
+
|
|
256
|
+
const options: PrintOptions = {
|
|
257
|
+
printerName: 'My Printer',
|
|
258
|
+
filePath: './document.pdf',
|
|
259
|
+
pageSize: 'A4'
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const result: PrintResult = await print(options);
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## How It Works
|
|
266
|
+
|
|
267
|
+
1. **PDF Printing**: Uses `pdf-to-printer` library which wraps SumatraPDF on Windows
|
|
268
|
+
2. **Job ID Retrieval**: Queries Windows print spooler using PowerShell commands
|
|
269
|
+
3. **Default Settings**: When settings aren't specified, SumatraPDF uses the printer's DEVMODE defaults
|
|
270
|
+
|
|
271
|
+
## Limitations
|
|
272
|
+
|
|
273
|
+
- **Windows Only**: Job ID tracking requires PowerShell (Windows-specific)
|
|
274
|
+
- **PDF Files**: Designed for PDF printing (for raw data, convert to PDF first)
|
|
275
|
+
- **Job ID Timing**: Very fast printers may complete jobs before ID can be retrieved
|
|
276
|
+
|
|
277
|
+
## Examples
|
|
278
|
+
|
|
279
|
+
See the `examples/` directory for complete working examples:
|
|
280
|
+
|
|
281
|
+
- `basic-print.js` - Simple printing with defaults
|
|
282
|
+
- `custom-settings.js` - Custom page sizes, trays, and options
|
|
283
|
+
- `job-monitoring.js` - Job status tracking
|
|
284
|
+
- `electron-integration.js` - Electron app integration
|
|
285
|
+
|
|
286
|
+
## Troubleshooting
|
|
287
|
+
|
|
288
|
+
### Job ID is undefined
|
|
289
|
+
|
|
290
|
+
This can happen if:
|
|
291
|
+
- The print job completes very quickly
|
|
292
|
+
- The printer isn't accessible
|
|
293
|
+
- PowerShell execution is blocked
|
|
294
|
+
|
|
295
|
+
The library will still print successfully; only job ID retrieval may fail.
|
|
296
|
+
|
|
297
|
+
### Custom page size not working
|
|
298
|
+
|
|
299
|
+
Ensure the page size is either:
|
|
300
|
+
1. A standard size name ("A4", "Letter", etc.)
|
|
301
|
+
2. A custom size that's been pre-configured in Windows printer settings
|
|
302
|
+
|
|
303
|
+
### Printer not found
|
|
304
|
+
|
|
305
|
+
Use `getPrinters()` to see available printers and verify the exact printer name (case-sensitive).
|
|
306
|
+
|
|
307
|
+
## License
|
|
308
|
+
|
|
309
|
+
MIT
|
|
310
|
+
|
|
311
|
+
## Contributing
|
|
312
|
+
|
|
313
|
+
Contributions welcome! Please open an issue or pull request.
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced Printer Library
|
|
3
|
+
*
|
|
4
|
+
* A Node.js/Electron library for advanced PDF printing with job tracking.
|
|
5
|
+
* Compatible with Node.js 20+ and Electron 39+.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Print PDFs with custom page sizes and tray selection
|
|
9
|
+
* - Retrieve job IDs from Windows print spooler
|
|
10
|
+
* - Automatic use of printer defaults when settings not specified
|
|
11
|
+
* - Query job status and printer information
|
|
12
|
+
*/
|
|
13
|
+
export { print, getPrinters, getDefaultPrinter, getJobStatus, getPrinterJobs, cancelJob } from './print-manager';
|
|
14
|
+
export { PrintOptions, PrintResult, PrinterInfo, JobInfo } from './types';
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Enhanced Printer Library
|
|
4
|
+
*
|
|
5
|
+
* A Node.js/Electron library for advanced PDF printing with job tracking.
|
|
6
|
+
* Compatible with Node.js 20+ and Electron 39+.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Print PDFs with custom page sizes and tray selection
|
|
10
|
+
* - Retrieve job IDs from Windows print spooler
|
|
11
|
+
* - Automatic use of printer defaults when settings not specified
|
|
12
|
+
* - Query job status and printer information
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.cancelJob = exports.getPrinterJobs = exports.getJobStatus = exports.getDefaultPrinter = exports.getPrinters = exports.print = void 0;
|
|
16
|
+
var print_manager_1 = require("./print-manager");
|
|
17
|
+
Object.defineProperty(exports, "print", { enumerable: true, get: function () { return print_manager_1.print; } });
|
|
18
|
+
Object.defineProperty(exports, "getPrinters", { enumerable: true, get: function () { return print_manager_1.getPrinters; } });
|
|
19
|
+
Object.defineProperty(exports, "getDefaultPrinter", { enumerable: true, get: function () { return print_manager_1.getDefaultPrinter; } });
|
|
20
|
+
Object.defineProperty(exports, "getJobStatus", { enumerable: true, get: function () { return print_manager_1.getJobStatus; } });
|
|
21
|
+
Object.defineProperty(exports, "getPrinterJobs", { enumerable: true, get: function () { return print_manager_1.getPrinterJobs; } });
|
|
22
|
+
Object.defineProperty(exports, "cancelJob", { enumerable: true, get: function () { return print_manager_1.cancelJob; } });
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { JobInfo } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Retrieves job ID by document name using PowerShell
|
|
4
|
+
*/
|
|
5
|
+
export declare function getJobIdByName(printerName: string, jobName: string, maxRetries?: number, retryDelay?: number): Promise<number | null>;
|
|
6
|
+
/**
|
|
7
|
+
* Gets detailed information about a print job
|
|
8
|
+
*/
|
|
9
|
+
export declare function getJobInfo(printerName: string, jobId: number): Promise<JobInfo | null>;
|
|
10
|
+
/**
|
|
11
|
+
* Gets all print jobs for a printer
|
|
12
|
+
*/
|
|
13
|
+
export declare function getAllJobs(printerName: string): Promise<JobInfo[]>;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getJobIdByName = getJobIdByName;
|
|
4
|
+
exports.getJobInfo = getJobInfo;
|
|
5
|
+
exports.getAllJobs = getAllJobs;
|
|
6
|
+
const child_process_1 = require("child_process");
|
|
7
|
+
/**
|
|
8
|
+
* Retrieves job ID by document name using PowerShell
|
|
9
|
+
*/
|
|
10
|
+
async function getJobIdByName(printerName, jobName, maxRetries = 3, retryDelay = 200) {
|
|
11
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
12
|
+
const jobId = await queryJobId(printerName, jobName);
|
|
13
|
+
if (jobId !== null) {
|
|
14
|
+
return jobId;
|
|
15
|
+
}
|
|
16
|
+
// Wait before retrying (job might not be in spooler yet)
|
|
17
|
+
if (attempt < maxRetries - 1) {
|
|
18
|
+
await sleep(retryDelay);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Gets detailed information about a print job
|
|
25
|
+
*/
|
|
26
|
+
async function getJobInfo(printerName, jobId) {
|
|
27
|
+
const script = `
|
|
28
|
+
Get-PrintJob -PrinterName "${escapePowerShellString(printerName)}" |
|
|
29
|
+
Where-Object {$_.Id -eq ${jobId}} |
|
|
30
|
+
Select-Object Id, DocumentName, JobStatus, TotalPages, Size |
|
|
31
|
+
ConvertTo-Json
|
|
32
|
+
`;
|
|
33
|
+
try {
|
|
34
|
+
const output = await executePowerShell(script);
|
|
35
|
+
const result = JSON.parse(output);
|
|
36
|
+
if (!result || !result.Id) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
jobId: result.Id,
|
|
41
|
+
jobName: result.DocumentName || '',
|
|
42
|
+
printerName: printerName,
|
|
43
|
+
status: result.JobStatus || 'Unknown',
|
|
44
|
+
pages: result.TotalPages || 0,
|
|
45
|
+
size: result.Size
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Gets all print jobs for a printer
|
|
54
|
+
*/
|
|
55
|
+
async function getAllJobs(printerName) {
|
|
56
|
+
const script = `
|
|
57
|
+
Get-PrintJob -PrinterName "${escapePowerShellString(printerName)}" |
|
|
58
|
+
Select-Object Id, DocumentName, JobStatus, TotalPages, Size |
|
|
59
|
+
ConvertTo-Json
|
|
60
|
+
`;
|
|
61
|
+
try {
|
|
62
|
+
const output = await executePowerShell(script);
|
|
63
|
+
const result = JSON.parse(output);
|
|
64
|
+
// Handle single result vs array
|
|
65
|
+
const jobs = Array.isArray(result) ? result : (result ? [result] : []);
|
|
66
|
+
return jobs.map((job) => ({
|
|
67
|
+
jobId: job.Id,
|
|
68
|
+
jobName: job.DocumentName || '',
|
|
69
|
+
printerName: printerName,
|
|
70
|
+
status: job.JobStatus || 'Unknown',
|
|
71
|
+
pages: job.TotalPages || 0,
|
|
72
|
+
size: job.Size
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Query job ID by document name
|
|
81
|
+
*/
|
|
82
|
+
async function queryJobId(printerName, jobName) {
|
|
83
|
+
const script = `
|
|
84
|
+
Get-PrintJob -PrinterName "${escapePowerShellString(printerName)}" |
|
|
85
|
+
Where-Object {$_.DocumentName -eq "${escapePowerShellString(jobName)}"} |
|
|
86
|
+
Select-Object Id |
|
|
87
|
+
ConvertTo-Json
|
|
88
|
+
`;
|
|
89
|
+
try {
|
|
90
|
+
const output = await executePowerShell(script);
|
|
91
|
+
const result = JSON.parse(output);
|
|
92
|
+
return result?.Id || null;
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Executes a PowerShell script and returns output
|
|
100
|
+
*/
|
|
101
|
+
function executePowerShell(script) {
|
|
102
|
+
return new Promise((resolve, reject) => {
|
|
103
|
+
const ps = (0, child_process_1.spawn)('powershell.exe', [
|
|
104
|
+
'-NoProfile',
|
|
105
|
+
'-NonInteractive',
|
|
106
|
+
'-Command',
|
|
107
|
+
script
|
|
108
|
+
]);
|
|
109
|
+
let output = '';
|
|
110
|
+
let errorOutput = '';
|
|
111
|
+
ps.stdout.on('data', (data) => {
|
|
112
|
+
output += data.toString();
|
|
113
|
+
});
|
|
114
|
+
ps.stderr.on('data', (data) => {
|
|
115
|
+
errorOutput += data.toString();
|
|
116
|
+
});
|
|
117
|
+
ps.on('close', (code) => {
|
|
118
|
+
if (code === 0 && output.trim()) {
|
|
119
|
+
resolve(output.trim());
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
reject(new Error(`PowerShell error: ${errorOutput || 'Unknown error'}`));
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
ps.on('error', (err) => {
|
|
126
|
+
reject(err);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Escapes string for use in PowerShell
|
|
132
|
+
*/
|
|
133
|
+
function escapePowerShellString(str) {
|
|
134
|
+
return str.replace(/["'`$]/g, '`$&');
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Sleep utility
|
|
138
|
+
*/
|
|
139
|
+
function sleep(ms) {
|
|
140
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
141
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { PrintOptions, PrintResult, PrinterInfo, JobInfo } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Prints a PDF file with the specified options
|
|
4
|
+
*/
|
|
5
|
+
export declare function print(options: PrintOptions): Promise<PrintResult>;
|
|
6
|
+
/**
|
|
7
|
+
* Gets a list of available printers
|
|
8
|
+
*/
|
|
9
|
+
export declare function getPrinters(): Promise<PrinterInfo[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Gets the default printer name
|
|
12
|
+
*/
|
|
13
|
+
export declare function getDefaultPrinter(): Promise<string | null>;
|
|
14
|
+
/**
|
|
15
|
+
* Gets information about a specific print job
|
|
16
|
+
*/
|
|
17
|
+
export declare function getJobStatus(printerName: string, jobId: number): Promise<JobInfo | null>;
|
|
18
|
+
/**
|
|
19
|
+
* Gets all print jobs for a specific printer
|
|
20
|
+
*/
|
|
21
|
+
export declare function getPrinterJobs(printerName: string): Promise<JobInfo[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Cancels a print job
|
|
24
|
+
*/
|
|
25
|
+
export declare function cancelJob(printerName: string, jobId: number): Promise<boolean>;
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.print = print;
|
|
7
|
+
exports.getPrinters = getPrinters;
|
|
8
|
+
exports.getDefaultPrinter = getDefaultPrinter;
|
|
9
|
+
exports.getJobStatus = getJobStatus;
|
|
10
|
+
exports.getPrinterJobs = getPrinterJobs;
|
|
11
|
+
exports.cancelJob = cancelJob;
|
|
12
|
+
const pdf_to_printer_1 = __importDefault(require("pdf-to-printer"));
|
|
13
|
+
const uuid_1 = require("uuid");
|
|
14
|
+
const child_process_1 = require("child_process");
|
|
15
|
+
const job_tracker_1 = require("./job-tracker");
|
|
16
|
+
/**
|
|
17
|
+
* Prints a PDF file with the specified options
|
|
18
|
+
*/
|
|
19
|
+
async function print(options) {
|
|
20
|
+
try {
|
|
21
|
+
// Validate required options
|
|
22
|
+
if (!options.printerName) {
|
|
23
|
+
return {
|
|
24
|
+
success: false,
|
|
25
|
+
jobName: '',
|
|
26
|
+
error: 'Printer name is required'
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
if (!options.filePath) {
|
|
30
|
+
return {
|
|
31
|
+
success: false,
|
|
32
|
+
jobName: '',
|
|
33
|
+
error: 'File path is required'
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Generate unique job name if not provided
|
|
37
|
+
const jobName = options.jobName || `PrintJob_${(0, uuid_1.v4)()}`;
|
|
38
|
+
// Build pdf-to-printer options
|
|
39
|
+
// Only include settings that user explicitly provided
|
|
40
|
+
const printOptions = {
|
|
41
|
+
printer: options.printerName
|
|
42
|
+
};
|
|
43
|
+
// Optional settings - only add if provided
|
|
44
|
+
if (options.pageSize !== undefined) {
|
|
45
|
+
printOptions.paperSize = options.pageSize;
|
|
46
|
+
}
|
|
47
|
+
if (options.tray !== undefined) {
|
|
48
|
+
printOptions.bin = options.tray;
|
|
49
|
+
}
|
|
50
|
+
if (options.copies !== undefined) {
|
|
51
|
+
printOptions.copies = options.copies;
|
|
52
|
+
}
|
|
53
|
+
if (options.orientation !== undefined) {
|
|
54
|
+
printOptions.orientation = options.orientation;
|
|
55
|
+
}
|
|
56
|
+
if (options.duplex !== undefined) {
|
|
57
|
+
printOptions.side = options.duplex;
|
|
58
|
+
}
|
|
59
|
+
if (options.monochrome !== undefined) {
|
|
60
|
+
printOptions.monochrome = options.monochrome;
|
|
61
|
+
}
|
|
62
|
+
if (options.pages !== undefined) {
|
|
63
|
+
printOptions.pages = options.pages;
|
|
64
|
+
}
|
|
65
|
+
if (options.subset !== undefined) {
|
|
66
|
+
printOptions.subset = options.subset;
|
|
67
|
+
}
|
|
68
|
+
// Set the document name for job tracking
|
|
69
|
+
printOptions.win32 = ['-print-settings', `${jobName}`];
|
|
70
|
+
// Print the document
|
|
71
|
+
await pdf_to_printer_1.default.print(options.filePath, printOptions);
|
|
72
|
+
// Try to retrieve job ID
|
|
73
|
+
const jobId = await (0, job_tracker_1.getJobIdByName)(options.printerName, jobName);
|
|
74
|
+
return {
|
|
75
|
+
success: true,
|
|
76
|
+
jobId: jobId || undefined,
|
|
77
|
+
jobName: jobName
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
return {
|
|
82
|
+
success: false,
|
|
83
|
+
jobName: options.jobName || '',
|
|
84
|
+
error: error.message || 'Unknown error occurred'
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Gets a list of available printers
|
|
90
|
+
*/
|
|
91
|
+
async function getPrinters() {
|
|
92
|
+
const script = `
|
|
93
|
+
Get-Printer | Select-Object Name, PrinterStatus, Default |
|
|
94
|
+
ConvertTo-Json
|
|
95
|
+
`;
|
|
96
|
+
try {
|
|
97
|
+
const output = await executePowerShell(script);
|
|
98
|
+
const result = JSON.parse(output);
|
|
99
|
+
// Handle single result vs array
|
|
100
|
+
const printers = Array.isArray(result) ? result : (result ? [result] : []);
|
|
101
|
+
return printers.map((printer) => ({
|
|
102
|
+
name: printer.Name,
|
|
103
|
+
isDefault: printer.Default === true,
|
|
104
|
+
status: printer.PrinterStatus || 'Unknown'
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Gets the default printer name
|
|
113
|
+
*/
|
|
114
|
+
async function getDefaultPrinter() {
|
|
115
|
+
const printers = await getPrinters();
|
|
116
|
+
const defaultPrinter = printers.find(p => p.isDefault);
|
|
117
|
+
return defaultPrinter ? defaultPrinter.name : null;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Gets information about a specific print job
|
|
121
|
+
*/
|
|
122
|
+
async function getJobStatus(printerName, jobId) {
|
|
123
|
+
return (0, job_tracker_1.getJobInfo)(printerName, jobId);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Gets all print jobs for a specific printer
|
|
127
|
+
*/
|
|
128
|
+
async function getPrinterJobs(printerName) {
|
|
129
|
+
return (0, job_tracker_1.getAllJobs)(printerName);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Cancels a print job
|
|
133
|
+
*/
|
|
134
|
+
async function cancelJob(printerName, jobId) {
|
|
135
|
+
const script = `
|
|
136
|
+
Remove-PrintJob -PrinterName "${escapePowerShellString(printerName)}" -ID ${jobId}
|
|
137
|
+
`;
|
|
138
|
+
try {
|
|
139
|
+
await executePowerShell(script);
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Executes a PowerShell script and returns output
|
|
148
|
+
*/
|
|
149
|
+
function executePowerShell(script) {
|
|
150
|
+
return new Promise((resolve, reject) => {
|
|
151
|
+
const ps = (0, child_process_1.spawn)('powershell.exe', [
|
|
152
|
+
'-NoProfile',
|
|
153
|
+
'-NonInteractive',
|
|
154
|
+
'-Command',
|
|
155
|
+
script
|
|
156
|
+
]);
|
|
157
|
+
let output = '';
|
|
158
|
+
let errorOutput = '';
|
|
159
|
+
ps.stdout.on('data', (data) => {
|
|
160
|
+
output += data.toString();
|
|
161
|
+
});
|
|
162
|
+
ps.stderr.on('data', (data) => {
|
|
163
|
+
errorOutput += data.toString();
|
|
164
|
+
});
|
|
165
|
+
ps.on('close', (code) => {
|
|
166
|
+
if (code === 0 && output.trim()) {
|
|
167
|
+
resolve(output.trim());
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
reject(new Error(`PowerShell error: ${errorOutput || 'Unknown error'}`));
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
ps.on('error', (err) => {
|
|
174
|
+
reject(err);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Escapes string for use in PowerShell
|
|
180
|
+
*/
|
|
181
|
+
function escapePowerShellString(str) {
|
|
182
|
+
return str.replace(/["'`$]/g, '`$&');
|
|
183
|
+
}
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Information about a printer
|
|
3
|
+
*/
|
|
4
|
+
export interface PrinterInfo {
|
|
5
|
+
name: string;
|
|
6
|
+
isDefault: boolean;
|
|
7
|
+
status: string;
|
|
8
|
+
defaultPageSize?: string;
|
|
9
|
+
defaultTray?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Options for printing a document
|
|
13
|
+
*/
|
|
14
|
+
export interface PrintOptions {
|
|
15
|
+
/** Name of the printer to use */
|
|
16
|
+
printerName: string;
|
|
17
|
+
/** Path to PDF file to print */
|
|
18
|
+
filePath: string;
|
|
19
|
+
/**
|
|
20
|
+
* Paper size (optional - defaults to printer's default)
|
|
21
|
+
* Examples: "A4", "A5", "A6", "Letter", "Legal", "Tabloid"
|
|
22
|
+
*/
|
|
23
|
+
pageSize?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Tray/bin selection (optional - defaults to printer's default)
|
|
26
|
+
* Can be tray number (1, 2, 3...) or tray name
|
|
27
|
+
*/
|
|
28
|
+
tray?: string | number;
|
|
29
|
+
/**
|
|
30
|
+
* Document/job name for tracking (optional - auto-generated if not provided)
|
|
31
|
+
*/
|
|
32
|
+
jobName?: string;
|
|
33
|
+
/** Number of copies (optional - defaults to 1) */
|
|
34
|
+
copies?: number;
|
|
35
|
+
/** Page orientation (optional) */
|
|
36
|
+
orientation?: 'portrait' | 'landscape';
|
|
37
|
+
/** Duplex printing mode (optional) */
|
|
38
|
+
duplex?: 'simplex' | 'duplex';
|
|
39
|
+
/** Print in monochrome/black & white (optional) */
|
|
40
|
+
monochrome?: boolean;
|
|
41
|
+
/** Print specific pages (optional, e.g., "1-3,5") */
|
|
42
|
+
pages?: string;
|
|
43
|
+
/** Print only odd or even pages (optional) */
|
|
44
|
+
subset?: 'odd' | 'even';
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Result of a print operation
|
|
48
|
+
*/
|
|
49
|
+
export interface PrintResult {
|
|
50
|
+
/** Whether the print was successful */
|
|
51
|
+
success: boolean;
|
|
52
|
+
/** Job ID from Windows print spooler (may be undefined if retrieval failed) */
|
|
53
|
+
jobId?: number;
|
|
54
|
+
/** Document/job name used for tracking */
|
|
55
|
+
jobName: string;
|
|
56
|
+
/** Error message if print failed */
|
|
57
|
+
error?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Information about a print job
|
|
61
|
+
*/
|
|
62
|
+
export interface JobInfo {
|
|
63
|
+
/** Job ID in the print queue */
|
|
64
|
+
jobId: number;
|
|
65
|
+
/** Document name */
|
|
66
|
+
jobName: string;
|
|
67
|
+
/** Name of the printer */
|
|
68
|
+
printerName: string;
|
|
69
|
+
/** Current status of the job */
|
|
70
|
+
status: string;
|
|
71
|
+
/** Number of pages */
|
|
72
|
+
pages: number;
|
|
73
|
+
/** Size in bytes */
|
|
74
|
+
size?: number;
|
|
75
|
+
}
|
package/lib/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "enhanced-printer",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Advanced PDF printing library with job tracking, custom page sizes, and tray selection for Node.js and Electron",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "lib/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib/**/*",
|
|
9
|
+
"README.md",
|
|
10
|
+
"LICENSE"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"watch": "tsc --watch",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"printer",
|
|
19
|
+
"print",
|
|
20
|
+
"printing",
|
|
21
|
+
"pdf",
|
|
22
|
+
"pdf-printer",
|
|
23
|
+
"electron",
|
|
24
|
+
"windows",
|
|
25
|
+
"job-tracking",
|
|
26
|
+
"print-spooler",
|
|
27
|
+
"tray-selection",
|
|
28
|
+
"page-size",
|
|
29
|
+
"typescript"
|
|
30
|
+
],
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=20.0.0"
|
|
33
|
+
},
|
|
34
|
+
"os": [
|
|
35
|
+
"win32"
|
|
36
|
+
],
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"pdf-to-printer": "^5.6.1",
|
|
39
|
+
"uuid": "^10.0.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^20.17.10",
|
|
43
|
+
"@types/uuid": "^10.0.0",
|
|
44
|
+
"typescript": "^5.7.3"
|
|
45
|
+
},
|
|
46
|
+
"author": "Akshay Malaviya",
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "https://github.com/akshaymalaviya/enhanced-printer.git"
|
|
51
|
+
},
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/akshaymalaviya/enhanced-printer/issues"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://github.com/akshaymalaviya/enhanced-printer#readme"
|
|
56
|
+
}
|