npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mrjee-org/mj-multiple-printer

v2.0.0

Published

Official TypeScript SDK for connecting web applications to Mrjee Print Bridge

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 fetch and standard WebSocket.
  • ⚡ 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-printer

Quick 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

  1. Ensure Desktop App is Running: The Local Print Bridge Electron desktop application must be open and running on the target client computer.
  2. 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 the PrintBridge constructor:
    const bridge = new PrintBridge({ port: 9005 });
  3. CORS Restrictions: Ensure that the web app's origin domain is permitted under the CORS configurations in the desktop app's Settings page.
  4. 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 pass secure: true in 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.