@trupermax/print-agent
v1.0.0
Published
Librería JavaScript para comunicarse con Print Agent desde aplicaciones web.
Maintainers
Readme
@trupermax/print-agent
Librería JavaScript/TypeScript para comunicarse con el servicio local Print Agent desde aplicaciones web.
Instalación
npm install @trupermax/print-agentUso básico
import { PrintAgent, EscPos } from '@trupermax/print-agent'
const agent = new PrintAgent()
const data = new EscPos()
.init()
.align('center')
.bold(true)
.textLine('Hola Mundo')
.cut()
.build()
await agent.printEscPos(data, { useDefaultPrinter: true })PrintAgent
Constructor
const agent = new PrintAgent(options?)| Opción | Tipo | Defecto | Descripción |
|---|---|---|---|
| baseUrl | string | http://127.0.0.1:9876 | URL del servicio Print Agent |
Métodos
status()
Retorna el estado del servicio.
const res = await agent.status()
// { status: 'running', message: 'Print Agent funcionando correctamente' }printers()
Retorna la lista de impresoras disponibles.
const printers = await agent.printers()
// [{ name: 'EPSON TM-T20', driver: '...', port: '...', is_default: true }]printPDF(pdfBase64, options?)
Imprime un PDF a partir de un string en Base64.
await agent.printPDF(base64String, {
printerName: 'HP LaserJet',
useDefaultPrinter: true,
copies: 2,
})printZPL(raw, options?)
Imprime una etiqueta ZPL en una impresora Zebra.
await agent.printZPL('^XA^FO50,50^ADN,36,20^FDHola^FS^XZ', {
printerName: 'ZDesigner GK420d',
copies: 1,
})printEscPos(data, options?)
Imprime bytes ESC/POS en una impresora térmica.
const bytes = new EscPos().init().textLine('Hola').cut().build()
await agent.printEscPos(bytes, {
printerName: 'EPSON TM-T20',
useDefaultPrinter: false,
copies: 1,
})escpos()
Método de fábrica que retorna una nueva instancia del builder EscPos.
const builder = agent.escpos()
const bytes = builder.init().textLine('Hola').cut().build()Referencia de comandos EscPos
Todos los métodos retornan this para encadenarse. Llama .build() al final para obtener el Uint8Array.
| Método | Descripción |
|---|---|
| init() | Inicializa la impresora (resetea configuración) |
| align(value) | Alineación: 'left', 'center', 'right' |
| bold(enabled) | Negrita: true / false |
| underline(enabled) | Subrayado: true / false |
| fontSize(size) | Tamaño de fuente: 1 (normal) al 4 (cuádruple) |
| text(value) | Agrega texto sin salto de línea |
| textLine(value) | Agrega texto con salto de línea |
| line(char?, length?) | Línea separadora (defecto: 42 guiones) |
| feed(lines?) | Avanza el papel N líneas (defecto: 1) |
| row(left, right, width?) | Dos textos en la misma línea: izquierda y derecha |
| columns(cells, defs) | Tabla con N columnas de ancho y alineación individual |
| qr(data, options?) | Código QR generado por la impresora |
| barcode(data, type?, options?) | Código de barras generado por la impresora |
| cut(partial?) | Corta el papel: parcial (defecto) o completo |
| raw(bytes) | Agrega bytes ESC/POS crudos directamente |
| build() | Retorna el Uint8Array final para enviar al endpoint |
Detalle de cada comando
init()
Inicializa la impresora y resetea todos los ajustes. Siempre llámalo primero.
new EscPos().init()align(value)
.align('left') // izquierda (defecto)
.align('center') // centro
.align('right') // derechabold(enabled)
.bold(true)
.bold(false)underline(enabled)
.underline(true)
.underline(false)fontSize(size)
.fontSize(1) // normal
.fontSize(2) // doble
.fontSize(3) // triple
.fontSize(4) // cuádrupletext(value)
Agrega texto sin salto de línea al final.
.text('Subtotal: ').bold(true).text('Q.150.00').bold(false)textLine(value)
Agrega texto seguido de un salto de línea.
.textLine('Hola Mundo')line(char?, length?)
.line() // 42 guiones
.line('=', 42) // 42 signos igual
.line('*', 20) // 20 asteriscosfeed(lines?)
.feed() // avanza 1 línea
.feed(3) // avanza 3 líneasrow(left, right, width?)
Imprime dos textos en la misma línea rellenando el espacio entre ellos. Útil para pares clave-valor.
.row('Subtotal', 'Q.150.00') // ancho 42 por defecto
.row('IVA 12%', 'Q.18.00', 42)
.row('TOTAL', 'Q.168.00')columns(cells, defs)
Imprime N columnas con ancho y alineación individual. Ideal para tablas de productos.
.columns(
['Cant.', 'Descripción', 'Precio', 'Total'],
[
{ width: 6, align: 'left' },
{ width: 16, align: 'left' },
{ width: 10, align: 'right' },
{ width: 10, align: 'right' },
]
)Cada ColumnDef:
| Campo | Tipo | Defecto | Descripción |
|---|---|---|---|
| width | number | requerido | Ancho en caracteres |
| align | Align | 'left' | Alineación dentro de la columna |
La suma de todos los anchos debe coincidir con el ancho de la impresora (normalmente 42 para papel de 80mm).
qr(data, options?)
Genera un código QR usando el hardware de la impresora.
.qr('https://miempresa.com')
.qr('https://miempresa.com', {
size: 4, // tamaño del módulo: 1–8 (defecto: 4)
errorLevel: 'M', // corrección de error: 'L', 'M', 'Q', 'H' (defecto: 'M')
})| errorLevel | Corrección |
|---|---|
| 'L' | 7% — más compacto |
| 'M' | 15% — uso general (defecto) |
| 'Q' | 25% — ambientes con suciedad |
| 'H' | 30% — máxima corrección |
barcode(data, type?, options?)
Genera un código de barras usando el hardware de la impresora.
.barcode('1234567890128')
.barcode('1234567890128', 'EAN13', {
height: 60, // alto en puntos (defecto: 60)
width: 2, // ancho de módulo: 1–6 (defecto: 2)
textPosition: 'below', // posición del texto: 'none', 'above', 'below', 'both' (defecto: 'below')
})Tipos de código de barras soportados:
| Tipo | Uso típico |
|---|---|
| 'CODE128' | Uso general, alfanumérico (defecto) |
| 'CODE39' | Inventario, industria |
| 'CODE93' | Variante compacta de CODE39 |
| 'EAN13' | Productos retail (13 dígitos) |
| 'EAN8' | Productos pequeños (8 dígitos) |
| 'UPC-A' | Retail USA (12 dígitos) |
| 'UPC-E' | Versión comprimida de UPC-A |
| 'ITF' | Cajas y logística |
| 'CODABAR' | Bibliotecas, sangre, courier |
cut(partial?)
.cut() // corte parcial (defecto)
.cut(false) // corte completoraw(bytes)
Agrega bytes ESC/POS crudos. Útil para comandos avanzados no cubiertos por el builder.
.raw([0x1b, 0x21, 0x00])build()
Retorna el Uint8Array final con todos los bytes acumulados para enviar al endpoint.
const data = new EscPos().init().textLine('Hola').cut().build()Ejemplo completo — ticket con tabla y QR
import { PrintAgent, EscPos } from '@trupermax/print-agent'
const agent = new PrintAgent()
const items = [
{ code: 'A00310', desc: 'TOR HEX GR5 NC 3/8 X 1', qty: 2, price: 2.00 },
{ code: 'A03672', desc: 'FAJA A-40 LISA SUPERBELT', qty: 1, price: 37.00 },
]
const colDefs = [
{ width: 6, align: 'left' },
{ width: 10, align: 'right' },
{ width: 10, align: 'right' },
{ width: 16, align: 'right' },
]
const escpos = new EscPos()
.init()
.align('center')
.bold(true)
.textLine('MI EMPRESA S.A.')
.bold(false)
.textLine('NIT: 123456-7')
.feed(1)
.align('left')
.line('-', 42)
.columns(['Cant.', 'Precio', 'Desc.%', 'Total'], colDefs)
.line('-', 42)
items.forEach(item => {
const total = item.qty * item.price
escpos
.textLine(`${item.code} - ${item.desc}`)
.columns(
[String(item.qty), `Q.${item.price.toFixed(2)}`, '', `Q.${total.toFixed(2)}`],
colDefs
)
.feed(1)
})
escpos
.line('-', 42)
.align('right')
.bold(true)
.textLine(`TOTAL: Q.${items.reduce((s, i) => s + i.qty * i.price, 0).toFixed(2)}`)
.bold(false)
.feed(1)
.align('center')
.qr('https://miempresa.com', { size: 4 })
.feed(3)
.cut()
const bytes = escpos.build()
const printers = await agent.printers()
const printer = printers.find(p => p.is_default)?.name ?? ''
await agent.printEscPos(bytes, { printerName: printer })Types
type Align = 'left' | 'center' | 'right'
type FontSize = 1 | 2 | 3 | 4
type BarcodeType =
| 'UPC-A' | 'UPC-E' | 'EAN13' | 'EAN8'
| 'CODE39' | 'ITF' | 'CODABAR' | 'CODE93' | 'CODE128'
interface ColumnDef {
width: number
align?: Align
}
interface QROptions {
size?: number
errorLevel?: 'L' | 'M' | 'Q' | 'H'
}
interface BarcodeOptions {
height?: number
width?: number
textPosition?: 'none' | 'above' | 'below' | 'both'
}
interface Printer {
name: string
driver: string
port: string
is_default: boolean
}
interface PrintAgentOptions {
baseUrl?: string
}
interface PrintPDFOptions {
printerName?: string
useDefaultPrinter?: boolean
copies?: number
}
interface PrintZPLOptions {
printerName?: string
useDefaultPrinter?: boolean
copies?: number
}
interface PrintEscPosOptions {
printerName?: string
useDefaultPrinter?: boolean
copies?: number
}Desarrollo local y pruebas
# Compilar la librería
npm run build
# Ejecutar la demo manual (requiere Print Agent corriendo en localhost:9876)
node test/manual.mjsPara probar la impresión física, descomenta la llamada a printEscPos al final de test/manual.mjs.
