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

kashipu-printer

v2.0.0

Published

Thermal printer SDK for ESC/POS printers. Print text, QR codes, images, and barcodes via Bluetooth or USB.

Readme

kashipu-printer

SDK para impresoras térmicas ESC/POS. Imprime texto con formato, códigos QR, imágenes y códigos de barras via Bluetooth o USB desde cualquier proyecto TypeScript/JavaScript.

Instalación

npm install kashipu-printer

Inicio rápido

import { ThermalPrinter, ReceiptBuilder, UsbAdapter } from 'kashipu-printer';

// 1. Crear impresora con un adaptador
const printer = new ThermalPrinter({
  adapter: new UsbAdapter('http://localhost:9100'),
  columns: 32,        // 32 para 48mm, 42 para 58mm, 48 para 80mm
  codepage: 'windows1252'
});

// 2. Conectar
await printer.connect();

// 3. Construir recibo
const receipt = new ReceiptBuilder()
  .text('MI NEGOCIO', { align: 'center', bold: true, size: 'double' })
  .text('NIT: 800.123.456-1', { align: 'center' })
  .separator()
  .keyValue('Placa', 'ABC-123')
  .keyValue('Fecha', '2026-03-10')
  .separator()
  .keyValue('TOTAL', '$11.900', { bold: true })
  .spacer()
  .qrcode('https://miweb.com/ticket/123')
  .text('Gracias por su visita', { align: 'center' })
  .build();

// 4. Imprimir
await printer.print(receipt);

Adaptadores

La librería usa el patrón adaptador para soportar diferentes conexiones. Escoge el que necesites:

UsbAdapter (PC / Windows)

Envía datos ESC/POS a una impresora USB local a través de un servidor HTTP incluido.

import { UsbAdapter } from 'kashipu-printer';

const adapter = new UsbAdapter('http://127.0.0.1:9100');

Requisito: Ejecutar el print server (ver sección Print Server).

BluetoothAdapter (Mobile / Cordova)

Para apps móviles con Cordova/Capacitor. Requiere instalar el plugin Bluetooth Serial:

npm install @awesome-cordova-plugins/bluetooth-serial cordova-plugin-bluetooth-serial
import { BluetoothAdapter } from 'kashipu-printer';
import { BluetoothSerial } from '@awesome-cordova-plugins/bluetooth-serial/ngx';

const bluetoothSerial = new BluetoothSerial();
const adapter = new BluetoothAdapter(bluetoothSerial);

MockAdapter (Testing / Desarrollo)

Simula una impresora en consola. No requiere hardware.

import { MockAdapter } from 'kashipu-printer';

const adapter = new MockAdapter();
// Los datos enviados se loguean en console.log

Adaptador personalizado

Puedes crear tu propio adaptador implementando la interfaz PrinterAdapter:

import { PrinterAdapter, PrinterDevice } from 'kashipu-printer';

class MiAdapter implements PrinterAdapter {
  async scan(): Promise<PrinterDevice[]> { /* ... */ }
  async connect(address: string): Promise<boolean> { /* ... */ }
  async disconnect(): Promise<boolean> { /* ... */ }
  async isConnected(): Promise<boolean> { /* ... */ }
  async write(data: Uint8Array): Promise<boolean> { /* ... */ }
}

API de ThermalPrinter

const printer = new ThermalPrinter(options);

Constructor

| Opción | Tipo | Default | Descripción | |--------|------|---------|-------------| | adapter | PrinterAdapter | requerido | Adaptador de conexión | | columns | number | 32 | Caracteres por línea | | codepage | string | 'windows1252' | Codificación de caracteres | | language | 'esc-pos' \| 'star-prnt' | 'esc-pos' | Variante del lenguaje | | codepageMapping | 'epson' \| 'star' \| 'bixolon' | 'epson' | Mapeo de codepage |

Métodos

| Método | Retorno | Descripción | |--------|---------|-------------| | scan() | Promise<PrinterDevice[]> | Buscar impresoras disponibles | | connect(address?) | Promise<boolean> | Conectar a la impresora | | disconnect() | Promise<boolean> | Desconectar | | isConnected() | Promise<boolean> | Verificar conexión | | print(receipt) | Promise<boolean> | Imprimir un ReceiptData | | printText(text) | Promise<boolean> | Imprimir texto plano | | printRaw(data) | Promise<boolean> | Enviar bytes ESC/POS crudos | | preview(receipt) | string | Generar preview HTML del recibo | | getConfig() | PrinterConfig | Obtener configuración actual |

ReceiptBuilder

API fluente para construir recibos sección por sección:

const receipt = new ReceiptBuilder()
  // Texto con opciones de estilo
  .text('TÍTULO', { align: 'center', bold: true, size: 'double' })
  .text('Subtítulo', { align: 'center' })
  .text('Subrayado', { underline: true })
  .text('Doble subrayado', { underline: 2 })
  .text('Itálica', { italic: true })
  .text(' Invertido ', { invert: true })
  .text('Font B pequeña', { font: 'B' })
  .text('Ancho 3x', { width: 3 })
  .text('Alto 2x', { height: 2 })

  // Par clave-valor
  .keyValue('Producto', 'Café')
  .keyValue('Total', '$5.000', { bold: true })

  // Línea separadora (caracter por defecto: '-')
  .separator()
  .separator('=')

  // Línea horizontal nativa
  .rule()                    // simple
  .rule('double')            // doble

  // Tabla con columnas
  .table(
    [{ width: 16, align: 'left' }, { width: 10, align: 'right' }],
    [['Producto', 'Precio'], ['Café', '$3.000']]
  )

  // Caja con bordes
  .box('TOTAL: $5.000', { style: 'double' })

  // Líneas vacías
  .spacer()      // 1 línea
  .spacer(3)     // 3 líneas

  // Código QR (tamaño 1-8, default 6)
  .qrcode('https://ejemplo.com', 6)

  // Código de barras
  .barcode('7501234567890', 'ean13', 60)

  // PDF417 (facturación electrónica)
  .pdf417('Datos de factura', { width: 3, height: 3 })

  // Imagen bitmap (requiere ImageData: { data, width, height })
  // Algoritmos: 'atkinson', 'floydsteinberg', 'bayer', 'threshold'
  .image(imageData, 'atkinson', 128)

  // Corte de papel
  .cut('full')     // o 'partial'

  // Construir
  .build();

Opciones de texto

| Opción | Valores | Default | |--------|---------|---------| | align | 'left', 'center', 'right' | 'left' | | bold | boolean | false | | underline | boolean \| 2 | false | | italic | boolean | false | | invert | boolean (blanco sobre negro) | false | | font | 'A' (normal), 'B' (pequeña) | 'A' | | size | 'normal', 'double' | 'normal' | | width | 1-8 (escala horizontal) | 1 | | height | 1-8 (escala vertical) | 1 |

Algoritmos de dithering para imágenes

| Algoritmo | Descripción | |-----------|-------------| | threshold | Binario simple (rápido, menos detalle) | | bayer | Patrón ordenado 4x4 (líneas diagonales) | | floydsteinberg | Difusión de error (alta calidad, gradientes naturales) | | atkinson | Difusión de error suave (mejor para detalles finos) |

Preview HTML

Genera un string HTML que simula visualmente el recibo térmico. Útil para previsualizaciones en la app:

const html = printer.preview(receipt);
document.getElementById('preview').innerHTML = html;

Print Server (USB en Windows)

Para imprimir desde el navegador a una impresora USB en Windows, se necesita el print server incluido. Este recibe datos ESC/POS via HTTP y los envía a la impresora usando la API Win32 winspool.drv.

Requisitos previos

  1. Tener la impresora instalada en Windows (Panel de control > Impresoras)
  2. Conocer el nombre exacto de la impresora (ej: "Generic / Text Only")

Iniciar el servidor

# Opción 1: Con npx (después de instalar kashipu-printer)
npx kashipu-print-server
npx kashipu-print-server "Mi Impresora"

# Opción 2: Directamente con node
node node_modules/kashipu-printer/tools/print-server/server.js "Mi Impresora"

# Opción 3: Desde el repo clonado
npm run print-server

Variables de entorno

| Variable | Default | Descripción | |----------|---------|-------------| | KASHIPU_PORT | 9100 | Puerto del servidor | | KASHIPU_PRINTER | Generic / Text Only | Nombre de la impresora |

Endpoints

| Método | Ruta | Descripción | |--------|------|-------------| | GET | /status | Estado de la impresora: { connected, printer, port } | | POST | /print | Enviar bytes ESC/POS (body: application/octet-stream) |

Probar conexión

# Verificar que la impresora está conectada
curl http://127.0.0.1:9100/status

Respuesta esperada:

{ "connected": true, "printer": "Generic / Text Only", "port": "USB001" }

Impresoras probadas

| Impresora | Conexión | Columnas | Codepage | Estado | |-----------|----------|----------|----------|--------| | GEZHI Mini (48mm) | USB | 32 | windows1252 | Funciona |

Configuración por tamaño de papel

| Papel | Columnas | |-------|----------| | 48mm | 32 | | 58mm | 42 | | 80mm | 48 |

Codepages comunes

| Codepage | Uso | |----------|-----| | windows1252 | Español, Francés, Portugués (caracteres acentuados) | | cp850 | DOS Latin-1 | | cp437 | ASCII extendido original |

Ejemplos

Ticket de entrada (parqueadero)

const ticket = new ReceiptBuilder()
  .text('PARQUEADERO CENTRAL', { align: 'center', bold: true, size: 'double' })
  .spacer()
  .text('TICKET DE ENTRADA', { align: 'center' })
  .spacer()
  .keyValue('Placa', 'ABC-123')
  .keyValue('Tipo', 'CARRO')
  .keyValue('Fecha', '10/03/2026')
  .keyValue('Hora', '14:30')
  .spacer()
  .text('Conserve su ticket', { align: 'center' })
  .build();

await printer.print(ticket);

Factura de venta

const factura = new ReceiptBuilder()
  .text('RESTAURANTE DOÑA ROSA', { align: 'center', bold: true, size: 'double' })
  .text('NIT: 900.456.789-1', { align: 'center' })
  .text('Calle 45 #12-30', { align: 'center' })
  .separator()
  .keyValue('Mesa', '5')
  .keyValue('Mesero', 'Carlos')
  .separator()
  .keyValue('2x Bandeja Paisa', '$36.000')
  .keyValue('1x Jugo Natural', '$6.000')
  .keyValue('1x Postre', '$8.000')
  .separator('=')
  .keyValue('SUBTOTAL', '$50.000')
  .keyValue('IVA 19%', '$9.500')
  .keyValue('TOTAL', '$59.500', { bold: true })
  .spacer()
  .text('EFECTIVO', { align: 'center' })
  .spacer()
  .qrcode('https://miweb.com/factura/001')
  .text('Gracias por su visita', { align: 'center' })
  .build();

await printer.print(factura);

Texto simple

await printer.printText('Hola mundo desde kashipu-printer!');

Imprimir imagen

// Desde un Canvas (navegador)
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.src = 'logo.png';
img.onload = async () => {
  canvas.width = img.width;
  // Altura debe ser múltiplo de 8
  canvas.height = Math.ceil(img.height / 8) * 8;
  ctx.drawImage(img, 0, 0);
  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

  const receipt = new ReceiptBuilder()
    .image(imageData, 'atkinson')
    .build();

  await printer.print(receipt);
};

Estructura del proyecto

kashipu-printer/
├── src/
│   ├── index.ts                    # Barrel export
│   ├── printer.ts                  # ThermalPrinter (clase principal)
│   ├── models/
│   │   ├── config.ts               # PrinterConfig, PrinterDevice
│   │   └── receipt.ts              # ReceiptData, secciones
│   ├── builder/
│   │   ├── receipt-builder.ts      # API fluent para construir recibos
│   │   ├── esc-pos-builder.ts      # ReceiptData → Uint8Array
│   │   └── html-preview-builder.ts # ReceiptData → HTML string
│   └── adapters/
│       ├── adapter.ts              # PrinterAdapter interface
│       ├── usb.adapter.ts          # HTTP print server
│       ├── bluetooth.adapter.ts    # Cordova Bluetooth Serial
│       └── mock.adapter.ts         # Console mock
└── tools/
    └── print-server/
        ├── server.js               # HTTP → Win32 RAW print
        └── raw-print.ps1           # PowerShell winspool.drv

Licencia

MIT