enhanced-printer
v1.0.9
Published
Advanced PDF printing library with job tracking, custom page sizes, and tray selection for Node.js and Electron
Maintainers
Readme
Enhanced Printer Library
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+.
Features
✅ PDF Printing - Print PDF files with full control
✅ Job ID Tracking - Retrieve Windows print spooler job IDs
✅ Custom Page Sizes - Support for standard and custom paper sizes
✅ Tray Selection - Select specific printer trays/bins
✅ Default Preferences - Automatically uses printer defaults when settings not specified
✅ Job Monitoring - Query job status and manage print queue
✅ Electron Compatible - Works seamlessly with Electron 39+
Installation
npm install enhanced-printerRequirements
- Node.js: 20.0.0 or higher
- Electron: 39.0.0 or higher (optional)
- OS: Windows (uses PowerShell for job tracking)
Quick Start
const { print, getPrinters } = require('enhanced-printer');
async function printPDF() {
// Get available printers
const printers = await getPrinters();
console.log('Available printers:', printers);
// Print with default settings
const result = await print({
printerName: 'Your Printer Name',
filePath: 'C:\\path\\to\\document.pdf',
jobName: 'MyJob_001'
});
console.log('Success:', result.success);
console.log('Job ID:', result.jobId);
console.log('Job Name:', result.jobName);
}
printPDF();Available Methods
| Method | Description |
|--------|-------------|
| print() | Print a PDF with custom settings |
| getPrinters() | Get list of available printers |
| getDefaultPrinter() | Get default printer name |
| getJobInfo() | Get info of a specific job by custom job name |
| getJobs() | Get all print jobs for a printer |
| cancelJob() | Cancel a print job by custom job name |
| watchJob() | Poll a job until it completes, errors, or times out |
API Reference
print(options: PrintOptions): Promise<PrintResult>
Prints a PDF file with the specified options.
Parameters:
interface PrintOptions {
printerName: string; // Required: Name of the printer
filePath: string; // Required: Path to PDF file
// Optional settings - defaults to printer preferences if not specified
pageSize?: string; // e.g., "A4", "A5", "A6", "Letter", "Legal"
tray?: string | number; // Tray name or number
jobName?: string; // Custom job name for tracking (auto-generated if not provided)
copies?: number; // Number of copies
orientation?: 'portrait' | 'landscape';
duplex?: 'simplex' | 'duplex';
monochrome?: boolean; // Black & white printing
pages?: string; // e.g., "1-3,5" to print specific pages
subset?: 'odd' | 'even'; // Print only odd or even pages
}Returns:
interface PrintResult {
success: boolean;
jobId?: number; // Job ID from print spooler (if available)
jobName: string; // Custom job name used for tracking
error?: string; // Error message if print failed
}Example:
const result = await print({
printerName: 'HP LaserJet',
filePath: './invoice.pdf',
pageSize: 'A4',
tray: 2,
copies: 2,
jobName: 'Invoice_12345'
});getPrinters(): Promise<PrinterInfo[]>
Gets a list of available printers.
Returns:
interface PrinterInfo {
name: string;
isDefault: boolean;
status: string;
}Example:
const printers = await getPrinters();
printers.forEach(p => {
console.log(`${p.name} - ${p.status} ${p.isDefault ? '(Default)' : ''}`);
});getDefaultPrinter(): Promise<string | null>
Gets the name of the default printer.
Example:
const defaultPrinter = await getDefaultPrinter();
console.log('Default printer:', defaultPrinter);getJobInfo(customJobName: string, printerName?: string): Promise<JobInfo | null>
Gets detailed information about a specific print job using the custom job name provided during printing.
Returns:
interface JobInfo {
jobId: number;
jobName: string; // Document name from Windows
customJobName: string; // Custom job name provided during print
printerName: string;
status: string[]; // List of status flags, e.g. ["PRINTING", "RETAINED"]
pages: number;
size?: number; // Size in bytes
userName?: string;
submittedTime?: string;
}Possible status values: PAUSED, ERROR, DELETING, SPOOLING, PRINTING, OFFLINE, PAPER_OUT, PRINTED, DELETED, BLOCKED_DEVICE_QUEUE, USER_INTERVENTION, RESTART, COMPLETE, RETAINED, RENDERING_LOCALLY
Example:
const jobInfo = await getJobInfo('Invoice_12345');
console.log('Status:', jobInfo.status); // ["PRINTING", "RETAINED"]
console.log('Pages:', jobInfo.pages);getJobs(printerName: string): Promise<JobInfo[]>
Gets all print jobs for a specific printer.
Example:
const jobs = await getJobs('HP LaserJet');
jobs.forEach(job => {
console.log(`Job ${job.jobId} (${job.customJobName}): ${job.status.join(', ')}`);
});cancelJob(customJobName: string, printerName?: string): Promise<boolean>
Cancels a print job using the custom job name.
Example:
const cancelled = await cancelJob('Invoice_12345');
console.log('Cancelled:', cancelled);watchJob(customJobName: string, printerName?: string, options?: WatchJobOptions): Promise<WatchJobResult>
Polls a print job at regular intervals until it completes, enters an error state, is aborted, or times out.
Why use this? Windows removes completed jobs from the print queue immediately. Without
watchJob, pollinggetJobInfoafter completion returnsnull, which is indistinguishable from an error.watchJobtracks the last known status and correctly resolves a vanished job asCOMPLETED.
Options:
interface WatchJobOptions {
pollInterval?: number; // ms between polls (default: 500)
timeout?: number; // max wait ms — 0 or omit = no timeout (default: 0)
onStatusChange?: (status: string[]) => void; // called on every status change
signal?: AbortSignal; // AbortController signal for manual stop
}Returns:
interface WatchJobResult {
finalStatus: string[]; // e.g. ["COMPLETED"], ["ERROR"], ["ABORTED"]
completed: boolean; // true = success, false = error / timed out / aborted
}Example — basic watch with timeout:
const { finalStatus, completed } = await watchJob('Invoice_12345', undefined, {
timeout: 30000, // stop after 30 seconds
pollInterval: 500,
onStatusChange: (status) => console.log('Status:', status)
});
console.log('Completed:', completed); // true
console.log('Final status:', finalStatus); // ["COMPLETED"]Example — watch indefinitely (no timeout):
// timeout: 0 (default) = never times out, watches until job finishes or errors
const { finalStatus, completed } = await watchJob('Invoice_12345');Example — manual stop via AbortController:
const controller = new AbortController();
// Start watching (doesn't block — run via Promise if needed)
const watchPromise = watchJob('Invoice_12345', undefined, {
signal: controller.signal,
onStatusChange: (status) => console.log('Status:', status)
});
// Stop watching manually (e.g. user cancelled, component unmounted, etc.)
controller.abort();
const { finalStatus } = await watchPromise;
console.log(finalStatus); // ["ABORTED"]Usage Examples
Using Printer Defaults
When you don't specify optional settings, the library automatically uses the printer's default configuration:
const result = await print({
printerName: 'My Printer',
filePath: './document.pdf'
});Custom Page Size with Default Tray
const result = await print({
printerName: 'Label Printer',
filePath: './label.pdf',
pageSize: 'A6'
// tray not specified - uses default
});Multiple Custom Settings
const result = await print({
printerName: 'My Printer',
filePath: './document.pdf',
pageSize: 'Legal',
tray: 1,
copies: 3,
orientation: 'landscape',
duplex: 'duplex',
monochrome: true,
jobName: 'Important-Document'
});Job Tracking
const result = await print({
printerName: 'My Printer',
filePath: './document.pdf',
jobName: 'MyJob_001'
});
if (result.success) {
// Get job info using custom job name
const jobInfo = await getJobInfo('MyJob_001');
console.log(`Job ${jobInfo.jobId}: ${jobInfo.status.join(', ')}`);
// Get all jobs for the printer
const allJobs = await getJobs('My Printer');
console.log(`Total jobs in queue: ${allJobs.length}`);
// Cancel if needed
// await cancelJob('MyJob_001');
}Electron Integration
Main Process:
const { ipcMain } = require('electron');
const { print, getPrinters, getJobs } = require('enhanced-printer');
ipcMain.handle('print-pdf', async (event, options) => {
return await print(options);
});
ipcMain.handle('get-printers', async () => {
return await getPrinters();
});
ipcMain.handle('get-jobs', async (event, printerName) => {
return await getJobs(printerName);
});Renderer Process:
const result = await window.printerAPI.print({
printerName: 'My Printer',
filePath: pdfPath,
jobName: 'MyJob_001'
});TypeScript Support
This library is written in TypeScript and includes full type definitions.
import { print, PrintOptions, PrintResult, JobInfo } from 'enhanced-printer';
const options: PrintOptions = {
printerName: 'My Printer',
filePath: './document.pdf',
pageSize: 'A4',
jobName: 'TypedJob_001'
};
const result: PrintResult = await print(options);How It Works
- PDF Printing: Uses
pdf-to-printerlibrary which wraps SumatraPDF on Windows - Job ID Retrieval: Queries Windows print spooler using PowerShell commands
- Custom Job Names: Maps user-provided job names to system job IDs for easy tracking
- Status Decoding: Converts numeric Windows job status bitmask into human-readable status flags
- Default Settings: When settings aren't specified, SumatraPDF uses the printer's DEVMODE defaults
Limitations
- Windows Only: Job ID tracking requires PowerShell (Windows-specific)
- PDF Files: Designed for PDF printing (for raw data, convert to PDF first)
- Job ID Timing: Very fast printers may complete jobs before ID can be retrieved
Troubleshooting
Job ID is undefined
This can happen if:
- The print job completes very quickly
- The printer isn't accessible
- PowerShell execution is blocked
The library will still print successfully; only job ID retrieval may fail.
Custom page size not working
Ensure the page size is either:
- A standard size name ("A4", "Letter", etc.)
- A custom size that's been pre-configured in Windows printer settings
Printer not found
Use getPrinters() to see available printers and verify the exact printer name (case-sensitive).
License
MIT
Contributing
Contributions welcome! Please open an issue or pull request.
