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

@qumra/pos

v0.3.2

Published

Qumra's all-in-one facade: connect to the printer, build an Arabic receipt, and print

Readme

@qumra/pos

npm version types license

Qumra's all-in-one, Arabic-first facade: connect, build the receipt, print.

Part of the @qumra suite. It hides the connection, ESC/POS encoding, and Arabic rendering behind a single fluent API, and ships 8 built-in receipt designs. Bundles @qumra/webusb + @qumra/receipt-encoder + @qumra/arabic-canvas.

Features

  • 🚀 One package — install once, no wiring required.
  • ⛓️ Fluent builderstore().items().total().cut().
  • 🅰️ Arabic-first — correct shaping + RTL, printed as an image.
  • 🔢 Quantities, sequential invoice number, currency, and auto-computed total.
  • 🎨 8 built-in templates selectable via the Templates enum, or inject your own.
  • 🌐 Dual-environment — the same code runs in the browser (WebUSB) and Electron (node-usb) via auto-detection; inject a custom transport when you need one.
  • 🗓️ Gregorian or Hijri dates. Defaults to 58mm paper.

Installation

npm install @qumra/pos

Quick start

import { Pos, Templates } from '@qumra/pos';

const printer = await Pos.connect();           // WebUSB, any printer (inside a user gesture)

const receipt = printer.receipt({ template: Templates.Tax, currency: 'ر.س' }) // 58mm default
  .store({ name: 'متجر قمرة', address: 'الرياض', vat: '300000000000003' })
  .serial(1024)                                // sequential invoice number → "فاتورة #01024"
  .date(new Date(), { calendar: 'hijri' })     // Hijri date
  .items([                                     // an array of objects — easy to read, edit, validate
    { name: 'قهوة عربية', price: 15.00, qty: 2 },
    { name: 'كرواسون', price: 12.50 },         // qty defaults to 1
  ])
  // .total(...) is optional — computed automatically from the items
  .footer('شكراً لزيارتكم')
  .cut();

await printer.print(receipt);
await printer.openDrawer();

API

Pos.connect(options?)Promise<QumraPrinter>

Connects to a printer. By default it auto-detects the transport: the Electron native bridge if window.qumraNative is present, otherwise WebUSB. Pass { transport } to override. In the browser it must be called inside a user gesture.

await Pos.connect();                          // auto: browser → WebUSB, Electron → node-usb
await Pos.connect({ transport: webUsb() });   // force WebUSB
await Pos.connect({ transport: myTransport }); // a custom Transport (bluetooth/network/tests)

options also accepts WebUSB filters (forwarded to the auto-detected WebUSB transport).

QumraPrinter

| Method | Description | |---|---| | receipt(options?) | Starts a receipt builder. options: { width?: 58 \| 80, currency?: string, template?: TemplateName \| Template }. | | print(input) | Prints a ReceiptBuilder, an encoder, or a Uint8Array. | | openDrawer() | Opens the cash drawer. | | disconnect() | Closes the connection. | | device | Connected device info. |

ReceiptBuilder (fluent)

| Method | Description | |---|---| | store({ name, address?, vat? }) | Store details. | | title(text) | Receipt title. | | serial(value) | Sequential invoice number. Numbers are padded to 5 digits. | | date(value, { calendar? }) | Date: 'gregorian' (default) or 'hijri'. | | item(name, price, qty?) | A single line item. qty defaults to 1; line total = price × qty. | | items([{ name, price, qty? }]) | Add many items from an array of objects (validated). | | total(amount) | The total. Optional — auto-computed from items if omitted. | | footer(text) | Footer line. | | cut() · drawer() | Cut paper · open the cash drawer. | | encode() | Returns Uint8Array (called automatically by print). |

Templates

Pick a built-in design with the Templates enum (safe + autocomplete), or inject your own Template function. Defaults to Templates.Standard.

import { Pos, Templates, registerTemplate, type Template } from '@qumra/pos';

printer.receipt({ template: Templates.Coupon });   // built-in by name
printer.receipt({ template: myDesign });           // custom: (content, { width }) => HTMLCanvasElement

registerTemplate('brand', myDesign);               // register once, then use by name
printer.receipt({ template: 'brand' });

| Built-in | Description | |---|---| | Standard | Clean default layout (via @qumra/arabic-canvas). | | Modern | Black header band + boxed total. | | Classic | Double-ruled rounded frame with dotted leaders. | | Elegant | Circular monogram + diamond ornaments. | | Compact | Tight spacing, ideal for 58mm. | | Tax | Simplified tax invoice with 15% VAT breakdown. | | Coupon | Dashed “cut here” frame with promo band. | | Kitchen | Large item lines with check boxes, no prices. |

Transports (dual-environment)

pos depends on a small Transport abstraction, so the same renderer code works in both environments:

| Transport | Runs in | Backed by | |---|---|---| | webUsb(options?) | Browser / Electron renderer | @qumra/webusb | | bridge(window.qumraNative) | Electron renderer → main | IPC → @qumra/node-usb | | your own | anywhere | implements Transport |

Transport is just { connect(): Promise<DeviceInfo>; print(bytes: Uint8Array): Promise<void>; disconnect?(): Promise<void> }.

Electron — expose a bridge in preload, print in main via @qumra/node-usb; Pos.connect() then auto-selects it:

// preload.cjs
contextBridge.exposeInMainWorld('qumraNative', {
  print: (bytes) => ipcRenderer.invoke('printer:print', bytes),
});

// main.cjs
ipcMain.handle('printer:print', async (_e, bytes) => {
  const { QumraNodeUsbPrinter } = await import('@qumra/node-usb');
  const p = new QumraNodeUsbPrinter();
  if (!p.connected) await p.connect();
  await p.print(Uint8Array.from(bytes));
});

// renderer — identical to the web code
const printer = await Pos.connect();   // detects window.qumraNative → node-usb

The Arabic receipt is always rendered to a canvas in the renderer, then the bytes are sent to whichever transport is active.

Related packages

License

MIT © Qumra