@mrjee-org/mj-multiple-printer
v2.0.0
Published
Official TypeScript SDK for connecting web applications to Mrjee Print Bridge
Maintainers
Readme
Mrjee Print Bridge — JavaScript/TypeScript SDK
Official zero-dependency SDK for communicating with the Mrjee Print Bridge desktop application. It wraps the local REST and WebSocket APIs, adds Bearer Token authentication, and keeps printing traffic on the user's computer.
Features
- 🔌 Zero Dependencies: Core SDK uses vanilla
fetchand standardWebSocket. - ⚡ Real-time Event Hookup: Connect via WebSockets to listen to print progress, errors, connection status, and configuration changes.
- 🖨️ Logical Routing: Print to logical names (e.g.,
barcode,receipt) configured on the desktop bridge, allowing physical printers to be changed without updating web application code. - 🎯 Direct Printing: Bypass mappings to print directly to any physical printer recognized by the OS.
- 🌐 Direct IP/TCP Raw Printing: Send raw data directly to network/Ethernet printers by passing an IP address or hostname.
- 📄 Diverse Formats: Native support for PDF (including base64), images (PNG/JPG), and raw printer commands (ZPL, SBPL, TSPL, ESC/POS, etc.).
- ⚙️ Advanced Print Customization: Control copies, custom paper sizes/units, resolution (DPI), orientation, margins, and PDF rasterization.
Installation
Install via npm:
npm install @mrjee-org/mj-multiple-printerQuick Start
import { PrintBridge } from '@mrjee-org/mj-multiple-printer';
// Copy this token from Mrjee Print Bridge > Settings.
// Store it per computer; do not hard-code it in a public repository.
const bridge = new PrintBridge({
token: localStorage.getItem("mrjee_print_token") ?? "",
});
// Connect via WebSocket for real-time status and logs (optional)
await bridge.connect();
// Base64 PDF data to print
const base64PdfData = "JVBERi0xLjQKJ..."
// Option A: Print using a preconfigured logical name
await bridge.print("barcode", base64PdfData);
// Option B: Print directly to a specific physical OS printer
await bridge.printDirect("SATO CG408TT", base64PdfData, {
type: "pdf",
density: 302,
rasterize: true, // Recommended for thermal/label printers
size: { width: 3, height: 2 },
units: "in",
});Advanced Print Techniques
Direct IP/TCP Printing
If the physical printer name matches an IP address (e.g., 192.168.1.100 or 192.168.1.100:9100), the desktop bridge will bypass local OS drivers and stream the raw payload directly to that device over a raw TCP socket.
// Sends raw print command (ZPL/ESC-POS/etc.) to an Ethernet printer
await bridge.printDirect("192.168.1.100:9100", "^XA^FO50,50^A0N,50,50^FDHello World^FS^XZ", {
type: "raw"
});PDF Rasterization
For thermal barcode or receipt printers, printing vector PDFs can sometimes result in scaling or driver issues. Set rasterize: true in PrintOptions to convert the PDF pages into optimized black-and-white/grayscale images before sending them to the printer driver.
API Reference
new PrintBridge(config?)
| Config Option | Type | Default | Description |
| ------------- | --------- | ------------- | ------------------------------------ |
| host | string | "localhost" | Bridge host IP or hostname |
| port | number | 9000 | Bridge HTTP/WS server port |
| secure | boolean | false | Use secure connections (https/wss) |
| token | string | "" | Local API Security Token from Bridge Settings |
If token is empty, SDK 2.x remains compatible with legacy/internal bridges that use the original local endpoints.
setToken(token: string): void
Updates the token at runtime without creating a new SDK instance:
bridge.setToken(token);
localStorage.setItem("mrjee_print_token", token);Methods
connect(): Promise<void>
Establishes a WebSocket connection with the bridge server. Resolves once connected. Automatically schedules reconnection attempts if disconnected.
disconnect(): void
Closes the WebSocket connection and cleans up reconnection timers.
isConnected: boolean (getter)
Returns true if the WebSocket connection is active.
getStatus(): Promise<BridgeStatus>
Queries the bridge API for overall status (uptime, total jobs, failed jobs, etc.).
getPrinters(): Promise<PhysicalPrinter[]>
Lists physical printers installed and recognized on the host operating system.
getMappings(): Promise<PrinterMapping[]>
Retrieves printer routing configurations mapped in the desktop application.
print(logicalName: string, data: string, overrides?: Partial<PrintOptions>): Promise<PrintResponse>
Routes a print job using a logical name configured in the desktop app.
data: Base64 PDF, image, or raw commands.overrides: Option overrides to apply dynamically to the configured defaults.
printDirect(printerName: string, data: string, options?: PrintOptions & { type?: 'pdf' | 'raw' | 'image' }): Promise<PrintResponse>
Bypasses logical mappings and prints directly to the physical printer.
printerName: OS printer name or network printer IP (e.g.192.168.1.50).data: Base64 PDF, image, or raw commands.
on(event: BridgeEventType, callback: BridgeEventCallback): () => void
Registers a listener for specific websocket events. Returns an unsubscribe function to clean up the listener.
TypeScript Interface Definitions
PrintOptions
interface PrintOptions {
/** Number of copies to print */
copies?: number;
/** Paper/label size dimensions */
size?: {
width: number;
height: number;
};
/** Size units for dimensions ('in' = inches, 'mm' = millimeters, 'cm' = centimeters) */
units?: 'in' | 'mm' | 'cm';
/** Print density/resolution in DPI (e.g., 203, 300, 302, 600) */
density?: number;
/** Whether to rasterize PDF before printing (highly recommended for thermal/label printers) */
rasterize?: boolean;
/** Page orientation */
orientation?: 'portrait' | 'landscape';
/** Color mode options */
colorType?: 'blackwhite' | 'color' | 'grayscale';
/** Page margins - single value for all sides or an object specifying per-side margin sizes */
margins?: number | { top?: number; left?: number; bottom?: number; right?: number };
}PrinterMapping
interface PrinterMapping {
id: string;
logicalName: string; // Name used by web application (e.g. "receipt-printer")
physicalName: string; // Name registered in host OS or network IP
type: 'pdf' | 'raw' | 'image';
enabled: boolean;
config: PrintOptions;
}PrintResponse
interface PrintResponse {
success: boolean; // True if successfully processed by the bridge
message?: string; // Success or failure error message
jobId?: string; // Unique identifier for the print job
}BridgeStatus
interface BridgeStatus {
running: boolean;
version: string;
uptime: number; // Server uptime in seconds
totalJobs: number; // Total print jobs processed since launch
failedJobs: number; // Failed print jobs since launch
port: number; // Active port the server is listening on
}PhysicalPrinter
interface PhysicalPrinter {
name: string; // Name of the printer on the OS
isDefault: boolean; // Is this set as the default system printer?
status?: string; // OS status description (if available)
}BridgeEventType
WebSocket event types you can listen to:
'connected': Triggered when connection with the WebSocket server is established.'disconnected': Triggered when connection is lost.'print-success': Emits when a print job completes successfully.'print-error': Emits when a print job fails.'status': Periodically broadcasts status logs.
Examples
React Hook Integration
Here is a clean custom React hook to manage bridge connection state and mappings in your React app:
import { useState, useEffect, useCallback } from "react";
import { PrintBridge, type PrinterMapping } from "@mrjee-org/mj-multiple-printer";
// Instantiate a single instance of the print bridge
const bridge = new PrintBridge({
host: "localhost",
port: 9000,
token: localStorage.getItem("mrjee_print_token") ?? "",
});
export function usePrintBridge() {
const [isConnected, setIsConnected] = useState(false);
const [mappings, setMappings] = useState<PrinterMapping[]>([]);
useEffect(() => {
// Connect to WebSocket
bridge.connect()
.then(() => setIsConnected(true))
.catch(() => setIsConnected(false));
// Register WebSocket event listeners
const unsubConnect = bridge.on("connected", () => setIsConnected(true));
const unsubDisconnect = bridge.on("disconnected", () => setIsConnected(false));
return () => {
unsubConnect();
unsubDisconnect();
bridge.disconnect();
};
}, []);
// Fetch mappings when connected
useEffect(() => {
if (isConnected) {
bridge.getMappings()
.then(setMappings)
.catch((err) => console.error("Failed to load mappings:", err));
}
}, [isConnected]);
// Wrapper function to send print jobs
const print = useCallback(async (logicalName: string, data: string) => {
return bridge.print(logicalName, data);
}, []);
return { isConnected, mappings, print, bridge };
}Vanilla Javascript Example
<!DOCTYPE html>
<html>
<head>
<title>Print Bridge Test</title>
<script type="module">
import { PrintBridge } from 'https://cdn.jsdelivr.net/npm/@mrjee-org/mj-multiple-printer/dist/index.mjs';
const bridge = new PrintBridge({
token: localStorage.getItem('mrjee_print_token') || ''
});
async function init() {
// Connect WebSocket
await bridge.connect();
console.log('Connected to print bridge!');
// Set up listeners
bridge.on('print-success', (payload) => {
alert(`Print Success: ${payload.id}`);
});
bridge.on('print-error', (payload) => {
alert(`Print Error: ${payload.error}`);
});
}
window.printDocument = async function() {
const base64Data = "JVBERi0xLjQKJ...";
try {
await bridge.print("receipt", base64Data);
} catch (err) {
console.error(err);
}
};
init();
</script>
</head>
<body>
<button onclick="printDocument()">Print Receipt</button>
</body>
</html>Troubleshooting
"Failed to connect to Print Bridge" or Connection Failures
- Ensure Desktop App is Running: The Local Print Bridge Electron desktop application must be open and running on the target client computer.
- Port Conflict: Check if another application is using port
9000. You can change the port setting in the desktop app config dashboard. If updated, pass the custom port number into thePrintBridgeconstructor:const bridge = new PrintBridge({ port: 9005 }); - CORS Restrictions: Ensure that the web app's origin domain is permitted under the CORS configurations in the desktop app's Settings page.
- HTTPS to HTTP Block: If your web app is served over HTTPS, modern browsers might block connections to a local HTTP endpoint (
http://localhost:9000) due to mixed-content policies. Configure HTTPS/WSS in the desktop app and passsecure: truein the SDK config.
License
MIT
Compatibility
- SDK
1.8.1: legacy/internal bridge integration. - SDK
2.x: public Mrjee Print Bridge with token support, while retaining the legacy fallback. - Print payloads go directly to
localhost; the SDK does not upload print files to Mrjee servers.
