sonyflake
v2.0.0
Published
A modern implementation Sonyflake on TypeScript
Maintainers
Readme
Sonyflake - A modern implementation Sonyflake on TypeScript
Ported from sony/sonyflake v2.2.0.
By default a Sonyflake ID is composed of
39 bits for time in units of 10 msec
8 bits for a sequence number
16 bits for a machine idRuntime support
Universal by construction: zero dependencies, and nothing outside the language
itself — the whole generator is Date.now(), BigInt and integer arithmetic.
There is no os, crypto or process anywhere in it, so it runs unchanged on
any ES2022 runtime.
| Runtime | Notes |
| -------------- | -------------------------------------------- |
| Node.js | 20.19 or newer, ESM and CommonJS |
| Bun | ESM and CommonJS |
| Deno | via npm:sonyflake |
| Browsers | Chrome/Edge 84+, Firefox 90+, Safari 15+ |
| Edge & workers | Cloudflare Workers, Vercel Edge, Deno Deploy |
This is checked, not merely claimed: CI runs the same smoke test against the same build on Node, Bun and Deno on every push.
Installation
npm i sonyflakeyarn add sonyflakepnpm add sonyflakebun add sonyflakedeno add npm:sonyflakeExample usage
Ships both ESM and CommonJS builds; the right one is picked automatically.
import { Sonyflake } from 'sonyflake';
const sonyflake = new Sonyflake({
machineId: 2, // in range 2^16
});
const snowflake = sonyflake.nextId();
console.log(snowflake); // => "86442873427329026"
console.log(sonyflake.decompose(snowflake)); // =>
// { id: '86442873427329026',
// time: 5152396764,
// sequence: 0,
// machineId: 2 }
console.log(new Date(sonyflake.toTime(snowflake)).toISOString());
// => "2026-08-20T08:12:47.640Z"CommonJS
const { Sonyflake } = require('sonyflake');
const sonyflake = new Sonyflake({ machineId: 2 });
console.log(sonyflake.nextId());Deno
import { Sonyflake } from 'npm:sonyflake';
console.log(new Sonyflake({ machineId: 2 }).nextId());Browser
No bundler required — any ESM CDN serves the published build.
<script type="module">
import { Sonyflake } from 'https://esm.sh/sonyflake';
console.log(new Sonyflake({ machineId: 2 }).nextId());
</script>Ids are only unique across instances that hold distinct machine ids, and a browser tab or a worker has no address of its own to derive one from. Hand it one issued by the server, or generate ids server-side.
Settings
new Sonyflake({
bitsSequence: 8,
bitsMachineId: 16,
timeUnit: 10,
startTime: Epoch.SONYFLAKE,
machineId: 2,
checkMachineId: (machineId) => machineId !== 0,
});bitsSequence— bit length of a sequence number,0to30. Defaults to8.bitsMachineId— bit length of a machine id,0to30. Defaults to16.timeUnit— time unit in milliseconds,1or more. Defaults to10.startTime— Unix time in milliseconds since which the elapsed time is counted. Defaults toEpoch.SONYFLAKE(2025-01-01 00:00:00 UTC). Must be before the current time.machineId— required,0to2^bitsMachineId - 1. Unlike the Go package there is no private-IP fallback, so that this library stays usable outside Node.checkMachineId— validates the uniqueness of the machine id. When it returnsfalsethe instance is not created.
The bit length of time is 63 - bitsSequence - bitsMachineId and must be at
least 32.
Epoch also carries UNIX, TWITTER and DISCORD for other start times.
API
nextId(): string— next unique id, as a decimal string.compose({ time, sequence, machineId }): string— build an id from its parts.timeis a Unix time in milliseconds.decompose(id): { id, time, sequence, machineId }—timeis the elapsed time counted intimeUnits, not a Unix timestamp.toTime(id): number— Unix time in milliseconds at which the id was generated.
Errors
Every failure throws a SonyflakeError carrying a code from
SonyflakeErrorCode:
import { Sonyflake, SonyflakeError, SonyflakeErrorCode } from 'sonyflake';
try {
new Sonyflake({ machineId: 70000 });
} catch (error) {
if (error instanceof SonyflakeError) {
console.log(error.code); // => "INVALID_MACHINE_ID"
}
}INVALID_BITS_TIME, INVALID_BITS_SEQUENCE, INVALID_BITS_MACHINE_ID,
INVALID_TIME_UNIT, INVALID_SEQUENCE, INVALID_MACHINE_ID,
START_TIME_AHEAD, OVER_TIME_LIMIT.
Differences from the Go implementation
nextId()returns a decimal string rather than anint64, so ids surviveJSON.stringifyuntouched.- On a sequence overflow the Go package sleeps until the wall clock catches up.
A single JS thread cannot block without stalling the event loop, so this port
advances the elapsed time instead. Ids stay unique and monotonic; only the
time embedded in them may run ahead of
Date.now()while a burst exceeds2^bitsSequenceids per time unit. - No
MachineIDdefault from the private IP address, and therefore noErrNoPrivateAddress.
