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-auth

v0.1.2

Published

Offline-capable identity for POS/apps: OAuth token vault with single-flight rotating refresh, local PIN (argon2id), Ed25519 offline activation, and an online/offline-degraded/offline-activated mode + grace-lock state machine. Zero dependency on any storag

Readme

qumra-pos-auth

Offline-capable identity for POS and local-first apps. Pure-JS, cross-platform (React Native, Web, Desktop, Node), and completely independent of any storage layer — you wire it to your data/sync code through one callback.

Install

npm i qumra-pos-auth
# or
yarn add qumra-pos-auth
# or
pnpm add qumra-pos-auth

Runtime deps are only @noble/hashes (argon2id) and @noble/curves (Ed25519) — both pure-JS, no native build on any platform.

What it does

  • Three operating modesonline (valid tokens, syncing) · offline-degraded (was online, token expired / no network, still runs on a local session) · offline-activated (an Ed25519-signed activation key, verified locally, server never contacted) · unactivated.
  • active → grace → locked state machine — data is never erased; the worst case is that new sales lock. Grace still sells (with a warning); recovery = any successful online contact.
  • Tokens — OAuth token vault with single-flight rotating refresh (15-min access / 30-day refresh by default). getValidToken() never throws — null means pause, not logout.
  • Local cashier PIN — argon2id verified against a synced hash (same code online & offline), with per-cashier lockout.
  • Offline activation — parses payload.signature, verifies the Ed25519 signature against a pinned public key, then device + expiry.

Quick start — the library takes a token from you

This package has zero endpoint code. You do login/refresh (REST, GraphQL, anything) and hand it the tokens through the AuthApi port. It never knows your server.

import { createAuth, type AuthApi } from "qumra-pos-auth";

// YOU own the network. The library only calls these two methods.
const api: AuthApi = {
  async login({ username, password }) {
    const t = await myBackend.login(username, password); // your REST/GraphQL call
    return { accessToken: t.access, refreshToken: t.refresh, expiresInSec: 900, refreshExpiresInSec: 2592000 };
  },
  async refresh(refreshToken) {
    const t = await myBackend.refresh(refreshToken); // your call
    return { accessToken: t.access, refreshToken: t.refresh, expiresInSec: 900, refreshExpiresInSec: 2592000 };
  },
};

const auth = createAuth({ api, vault, directory, activationPublicKey });
await auth.service.init();
await auth.service.onlineLogin({ username, password });
await auth.service.cashierLogin("cashier-1", "1234");
auth.service.onStatusChange((s) => renderBar(s)); // { mode, access, cashier, ... }

Even simpler — if you manage tokens 100% outside and don't need the vault/refresh logic, skip the auth token layer entirely and just feed your token to the sync engine: new SyncEngine(storage, { getAuthToken: () => myToken }).

The one seam to your storage/sync

qumra-pos-auth never imports your storage. Wire them in the app with a single callback. Since sync engines usually poll a synchronous token getter, use getAccessTokenSync (an in-memory cache kept warm by the async refresh loop):

// e.g. with qumra-pos-storage's SyncEngine:
new SyncEngine(storage, { getAuthToken: () => auth.getAccessTokenSync() });
  • getAccessTokenSync(): string | null — synchronous, no I/O. null ⇒ sync pauses.
  • getValidToken(): Promise<string | null> — async variant (triggers refresh if needed).

Ports you implement (per platform)

Everything I/O is an injectable port, so the same core runs everywhere:

  • AuthVault — secure persistence. Back it with Electron safeStorage, browser IndexedDB, or RN Keychain. (saveTokens/loadTokens, …Session, …Activation, …Meta.)
  • CashierDirectorylistCashiers(); return the synced cashier rows (id, name, pinHash, active) from your storage.
  • AuthApi — you implement login/refresh with your own fetch/GraphQL. The library never knows your endpoint; it just receives the tokens you return.
  • PinHasher / SignatureVerifier — default to the bundled NoblePinHasher (argon2id, PHC format) and NobleSignatureVerifier (Ed25519) from qumra-pos-auth/crypto; swap for a native impl on RN if you want.

Error semantics for your AuthApi

Throw the right error so the state machine behaves correctly:

  • Network / server-down / 5xx → throw new AuthNetworkError(...) — retryable, keeps the tokens, sync just pauses.
  • Rejected (bad credentials / refresh revoked) → throw new AuthRejectedError(...) — permanent, clears the tokens.

Both are exported from qumra-pos-auth.

Publishing

Ships dual ESM + CJS + .d.ts (built with tsup). Crypto is also available at the qumra-pos-auth/crypto subpath. To publish under a different name, change name in package.json.

MIT.