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

@nullvalues/base56

v0.3.0

Published

Configurable baseX encoding library with SQLite-backed sequences

Readme

base56

What it is

base56 is a baseX encoding library for Node.js, a faithful port of dart56. It encodes and decodes non-negative integers using a configurable character set that defaults to base56 (alphanumeric minus visually ambiguous characters O I L o i l). It also provides a SQLite-backed sequence generator that emits monotonically increasing bX-encoded values.

Installation

Once published to npm, consumers can install directly:

pnpm add @nullvalues/base56

To use the package before it is published (e.g. in a local monorepo), add it as a file dependency in your consuming project:

"dependencies": {
  "@nullvalues/base56": "file:../base56"
}

Run npm install after adding the entry. Each consuming project manages its own path pointer to base56.

tsconfig requirements

base56 is a pure ESM package. Consumers require Node.js ≥ 18.17.0 and must use import (no require). Any TypeScript module/moduleResolution combination that supports ESM works: NodeNext/NodeNext, Bundler/Bundler, or ESNext/Bundler. Next.js (App Router) and Vite-based projects work without changes. If you are using NodeNext resolution, your package.json must declare "type": "module".

Usage examples

B10 — decimal round-trip

import { B10 } from '@nullvalues/base56';

const encoded = B10.convertB10ToBx(560);   // => 'A0'  (560 is the default seqStartValue)
const decoded = B10.convertBxToB10("A0");  // => [[560]]
console.assert(decoded[0][0] === 560);     // round-trip verified

B8 — octal to bX

import { B8, Base8Int } from '@nullvalues/base56';

// octal 10 = decimal 8; position 8 in the default charset is '8'
const result = B8.convertB8ToBx(new Base8Int(10)); // => '8'

// Base8Int.fromInt converts a decimal value to its octal representation first:
// Base8Int.fromInt(8) => Base8Int(10) (octal) => B8.convertB8ToBx(...) => '8'
const same = B8.convertB8ToBx(Base8Int.fromInt(8)); // => '8'

BxSequence — SQLite-backed sequence

import { BxSequence } from '@nullvalues/base56';

const seq = new BxSequence("my-seq", { dbPath: "path/to/sequences.db" });
const v1 = await seq.nextValue(); // => 'A0' (default seqStartValue)
const v2 = await seq.nextValue(); // => 'A1'
await seq.dispose();              // required — closes the database handle

bootstrap — custom character set

import { bootstrap } from '@nullvalues/base56';

// Must be called before any encode/decode operation.
bootstrap.updateConfig({
  bX: {
    removeChars: "OILoil01",
    prependSeparator: "-",
    prependDefaultChar: "X",
    subdomainChar: ".",
    seqStartValue: "A0",
  },
});

Process-wide singleton. updateConfig must be called once, before any encode or decode operation in the process. After the first encode or decode call (including indirect calls via BxSequence construction), the config is frozen and updateConfig will throw. Two consumers in the same process cannot use different configs simultaneously. If updateConfig is never called, the default config is used automatically.

BxSequence database notes

  • Default dbPath is 'sequences.db' resolved relative to the process working directory.
  • Pass an explicit absolute path in production to control placement, and a unique path per test to achieve isolation.
  • dispose() is required. Failing to call it leaves the store handle open.
  • Concurrent-write safe. Each nextValue() call executes an atomic UPDATE … SET last_value = last_value + 1 … RETURNING last_value in WAL mode (PRAGMA journal_mode = WAL). Multiple processes pointing at the same database file will each receive a unique, monotonically increasing value with no external locking required.
  • Schema side-effect. The BxSequence constructor runs CREATE TABLE IF NOT EXISTS bx_sequences on the database at dbPath every time it is called. Pointing a BxSequence at an existing unrelated SQLite database will write a bx_sequences table into it. Use an explicit, dedicated dbPath in production.

Sequence stores

BxSequence supports pluggable storage backends through the SequenceStore interface. The default backend is SQLite via SqliteStore. A Postgres backend (PgStore) is also included for distributed deployments.

Default SQLite usage

import { BxSequence } from '@nullvalues/base56';

const seq = new BxSequence('users');
const id = await seq.nextValue(); // 'A0'
await seq.dispose();

Explicit SqliteStore

import { BxSequence, SqliteStore } from '@nullvalues/base56';

const store = new SqliteStore('./data/sequences.db');
const seq = new BxSequence('users', { store });
const id = await seq.nextValue();
await seq.dispose(); // closes the store (BxSequence owns it)

PgStore (requires postgres peer dep)

import postgres from 'postgres';
import { BxSequence, PgStore } from '@nullvalues/base56';

const sql = postgres(process.env.DATABASE_URL);
const store = new PgStore(sql);
const seq = new BxSequence('users', { store });
const id = await seq.nextValue();
// caller manages sql.end() — PgStore.close() is a no-op

postgres >= 3 is required as a peer dependency:

npm install postgres

The bx_sequences table must exist before first use (caller-managed migration):

CREATE TABLE IF NOT EXISTS bx_sequences (
  name TEXT PRIMARY KEY,
  last_value INTEGER NOT NULL DEFAULT 0
);

Custom store skeleton

import type { SequenceStore } from '@nullvalues/base56';

class MyStore implements SequenceStore {
  async getAndIncrement(name: string, initValue: number): Promise<number> { ... }
  async getCurrentValue(name: string): Promise<number | null> { ... }
  async reset(name: string, startValue: number): Promise<void> { ... }
  async close(): Promise<void> { ... }
}

native dependency

better-sqlite3 builds a native addon at install time and requires node-gyp, which in turn requires Python and a C++ compiler. Ensure these are present in your CI environment before running npm install.