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

sonyflake-ts

v0.1.1

Published

TypeScript port of github.com/sony/sonyflake — distributed unique ID generator for Node.js and Bun

Readme

sonyflake-ts

npm version npm downloads CI bundle size license

TypeScript port of sony/sonyflake — a distributed unique ID generator inspired by Twitter's Snowflake, with a layout optimised for a longer lifetime and more machines.

  • Pure TypeScript. No FFI, no native build, no platform-specific binaries — just BigInt.
  • Zero runtime dependencies.
  • Works on Node.js (≥20) and Bun (≥1.0). ESM-only.
  • Bit-for-bit compatible with the Go reference, verified on every CI run by re-decomposing IDs produced by sony/sonyflake v1.2.0.

Install

npm install sonyflake-ts
# or
bun add sonyflake-ts
# or
pnpm add sonyflake-ts

Quick start

import { Sonyflake, decompose } from "sonyflake-ts";

// Default machine ID is the lower 16 bits of a private IPv4 address —
// fine for a laptop, you almost certainly want to set it explicitly in prod.
const sf = await Sonyflake.create({ machineID: 0x1234 });

const id = await sf.nextID(); // bigint, e.g. 617439447843082386n
console.log(id.toString());        // decimal — store as TEXT/BIGINT
console.log(id.toString(16));      // hex

Bit layout

 63                                            24 23      16 15            0
+-+--------------------------------------------+---------+----------------+
|0|       39 bits time (10 ms units)           | 8 bits  |  16 bits       |
| |       since startTime epoch                | sequence|  machine id    |
+-+--------------------------------------------+---------+----------------+

| field | bits | range | | ---------- | ---: | ----------------------------------------------------------- | | msb | 1 | always 0 — keeps IDs positive in signed int64 | | time | 39 | 10 ms units since the configured epoch | | sequence | 8 | 0–255, resets every 10 ms tick | | machine id | 16 | 0–65 535 |

That gives:

  • lifetime ≈ 174 years from the configured epoch (vs. ~69 for Snowflake)
  • machines up to 2¹⁶ = 65 536
  • throughput 256 IDs per machine per 10 ms (≈ 25 600 / s). When the per-tick budget is exhausted nextID() waits for the next tick.

IDs are 63 bits wide so they fit in a signed int64 — and in JS they're returned as bigint. Don't cast to Number: above 2⁵³ you'll lose precision.

API

Sonyflake.create(options?)Promise<Sonyflake>

interface SonyflakeOptions {
  /** Epoch as a Date or ms-since-unix-epoch. Defaults to 2014-09-01 UTC. */
  startTime?: Date | number;

  /** 16-bit machine ID. May be a number, sync fn, or async fn (etcd/Redis/...). */
  machineID?: number | (() => number | Promise<number>);

  /** Optional uniqueness check, called once with the resolved machine ID. */
  checkMachineID?: (id: number) => boolean | Promise<boolean>;
}

The async constructor lets you resolve machineID from a coordination service:

const sf = await Sonyflake.create({
  machineID: async () => {
    const id = await redis.incr("sonyflake:next-machine-id");
    return id & 0xffff;
  },
  checkMachineID: async (id) => (await redis.sismember("sonyflake:taken", id)) === 0,
});

Throws SonyflakeError if startTime is in the future or the machine ID is out of [0, 0xFFFF].

sf.nextID()Promise<bigint>

Returns the next ID. Calls are internally serialized so concurrent invocations from the same process never produce duplicates.

decompose(id)DecomposedID

const parts = decompose(id);
// { id, msb, time, sequence, machineID }   // all bigints

SonyflakeError

Thrown on invalid options or when the 39-bit time space is exhausted (after ~174 years).

Storage tips

  • PostgresBIGINT. Pass as string: JSON.stringify({ id: id.toString() }).
  • MySQLBIGINT UNSIGNED works (we never set the top bit).
  • JSONBigInt is not JSON-serialisable. Convert with id.toString() before sending; on the wire treat it as a string. The receiver can use BigInt(str).
  • Sorting — IDs are roughly time-ordered, so a B-tree index on the ID column gives you cheap "recent first" pagination via ORDER BY id DESC.

Compatibility with sony/sonyflake

The bit layout is identical, so an ID produced by this package is bit-equal to one produced by the Go library given the same startTime, machineID, and wall-clock instant. The CI suite enforces this: it shells out to a tiny Go program that uses github.com/sony/sonyflake to generate IDs, then re-decomposes them with this package's decompose() and asserts every field matches.

What's intentionally different:

  • Sonyflake.create() is async so machineID / checkMachineID can be (the Go API is sync).
  • nextID() returns a Promise to allow internal sleep when the per-tick sequence wraps. Concurrent callers are queued.
  • IDs come back as bigint instead of uint64.

Development

bun install
bun run build       # tsc -> dist/
bun x vitest run    # tests + Go-compat (skipped if `go` is missing)

CI runs the test suite under both Bun (latest) and Node (20 & 22) with a Go toolchain present so the sony/sonyflake cross-validation always executes.

Credits

  • sony/sonyflake — the original Go implementation by Sony Group Corporation.
  • The 10 ms time unit and bit layout are from that project; this package is a faithful port.

License

MIT — same as the original.