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

nosh-device-bridge

v0.1.1

Published

Universal JavaScript client for the Nosh Device Bridge — securely print ESC/POS receipts to a local thermal printer from any browser app or Node service.

Readme

Nosh Device Bridge — JavaScript client

Print receipts to a local thermal printer from any website or Node app.

This is the JavaScript companion to the Nosh Device Bridge desktop app (a self-hosted QZ Tray alternative). The desktop app runs on the shop's computer next to the printer. This tiny library lets your web page or Node service talk to it and print ESC/POS receipts — no drivers, no browser plugins.

Works everywhere from one package:

  • Browser <script> tag or CDN → gives you window.DeviceBridge
  • Node / bundlers (import) → import { DeviceBridge, Receipt }
  • CommonJS (require) → const { DeviceBridge, Receipt } = require(...)

How it works (30-second version)

 Your app (browser or Node)          Cashier's PC
 ──────────────────────────          ─────────────
 opens a WebSocket to the    ───▶     Nosh Device Bridge app
 local bridge and asks it to          → talks to the printer
 print a receipt              ◀───     → replies { printed: true }
  1. Connect to the bridge (it lives on 127.0.0.1).
  2. Pair once — the user clicks Approve in the desktop app. You get back an appId + secret. Save them.
  3. Print — build a receipt and send it. Every request is signed so it can't be forged or replayed.

Install

Pick the line that matches how you build your app. You only need one.

Option A — npm / yarn / pnpm (Node, React, Vue, Next, bundlers)

npm install nosh-device-bridge
# or: yarn add nosh-device-bridge  /  pnpm add nosh-device-bridge

TypeScript types are included — no @types package needed.

Then import it:

import { DeviceBridge, Receipt } from "nosh-device-bridge";

Node version note. On Node 22+ nothing else is needed — WebSocket and crypto are built in. On older Node (18–21) also install a WebSocket: npm install ws. The package picks it up automatically.

Option B — plain <script> tag (any website, no build step)

Two ways, depending on whether you can reach the CDN:

<!-- 1) From a CDN (once published to npm) -->
<script src="https://unpkg.com/nosh-device-bridge"></script>

<!-- 2) Self-hosted: copy dist/nosh-device-bridge.cjs next to your page -->
<script src="./nosh-device-bridge.cjs"></script>

Either way you get two globals to use: window.DeviceBridge and window.NoshReceipt.


Quick start

Browser

<script src="https://unpkg.com/nosh-device-bridge"></script>
<script>
  async function printTest() {
    const db = new DeviceBridge({ appName: "My POS" });

    await db.connect();                 // finds the local bridge
    const creds = await db.pair();      // user clicks Approve in the app
    // 👉 SAVE creds.appId + creds.secret (send to your server) — pair only once.

    const receipt = NoshReceipt.make()
      .title("NOSH")
      .item("Coffee", 1, "£2.50")
      .total("TOTAL", "£2.50", true)
      .footer("Thank you!")
      .cut();

    await db.printReceipt(receipt, "127.0.0.1", 9100);
  }
</script>

Already paired before? Skip pairing and reuse your saved credentials:

const db = new DeviceBridge({ appName: "My POS" });
db.useCredentials(savedAppId, savedSecret);
await db.connect();
await db.printReceipt(receipt, "127.0.0.1", 9100);

Node

import { DeviceBridge, Receipt } from "nosh-device-bridge";

const db = new DeviceBridge({ appName: "Kitchen service" });
await db.connect();
db.useCredentials(process.env.BRIDGE_APP_ID, process.env.BRIDGE_SECRET);

const receipt = Receipt.make()
  .title("NOSH")
  .item("Cheeseburger", 2, "£17.00", ["No pickles"])
  .item("Fries", 1, "£3.50")
  .total("TOTAL", "£20.50", true)
  .cut();

console.log(await db.printReceipt(receipt, "127.0.0.1", 9100));
db.disconnect();

(CommonJS is the same, just const { DeviceBridge, Receipt } = require("nosh-device-bridge");.)


Building receipts

Receipt.make() gives you a fluent builder. Chain calls, end with .cut().

| Method | What it does | |---|---| | .title(t) / .subtitle(s) | Header title / subtitle | | .info(...lines) | Centered lines under the title (address, phone) | | .line(text, opts) | A free-form text line | | .item(name, qty, price, notes) | A line item (+ optional notes) | | .total(label, value, bold) | A totals row | | .footer(...lines) | Footer lines | | .qr(value) / .barcode(value) | Print a QR / barcode | | .openDrawer() | Kick the cash drawer | | .cut(on = true) | Cut the paper |


The client API

| Method | What it does | |---|---| | new DeviceBridge(opts) | opts: url, appName, appId, secret, timeout, allowInsecure | | connect() | Connects (tries wss://…:8442, falls back to ws://…:8443) | | pair() | Asks the user to approve; returns { appId, secret }. Do once. | | useCredentials(appId, secret) | Reuse saved credentials (skip pairing) | | ping() | Health check | | listPrinters() | List printers the bridge can reach | | printReceipt(receipt, host, port, copies) | Print a receipt to a network printer | | printRaw(data, host, port, copies) | Send raw text/ESC-POS bytes | | sign(action, payload) | Build a signed message without sending it | | relay(signedMessage) | Send a message that was signed elsewhere (e.g. your server) | | disconnect() | Close the connection |


Keeping the secret safe (recommended for production)

The simplest setup keeps the secret in the browser — fine for local dev, but anyone with the page can read it. For production, sign on your server and let the browser only relay:

  1. Your server holds the secret and builds a signed message (use our PHP package, or db.sign(...) in a Node backend).
  2. The browser fetches that signed message and relays it as-is:
const db = new DeviceBridge();
await db.connect();

const signed = await (await fetch("/pos/print/123", { method: "POST" })).json();
const result = await db.relay(signed);   // sent verbatim — do not modify it
console.log(result); // { printed: true }

relay() sends the message exactly as received. Any change breaks the signature.


Security

  • Every request is signed with HMAC-SHA256 over id|action|ts|nonce|payload, with a timestamp (±30s) and a one-time nonce — so requests can't be forged or replayed.
  • Uses the built-in Web Crypto in browsers and modern Node; falls back to Node's crypto module automatically.

License

MIT.