Skip to content

Latest commit

 

History

History
149 lines (108 loc) · 4.92 KB

tpl.readme.md

File metadata and controls

149 lines (108 loc) · 4.92 KB

About

{{pkg.description}}

Idea based on segmentio/ksuid, though the added flexibility in terms of configuration & implementation also enables the creation of ULIDs:

Feature KSUID default ULID default
Configurable bit size 160 bits 128 bits
Base-N encoding scheme base62(1) base32 (Crockford)
Timestamp resolution seconds (32 bits) milliseconds (48 bits)
milliseconds (64 bits)
Epoch start time offset approx. 2020-09-13(2) none
Time-only base ID generation
ID parsing / decomposition
Configurable RNG source(3)
  • (1) See @thi.ng/base-n for alternatives
  • (2) With the default offset, the max. supported date for KSUID32 is 2156-10-20T18:54:55Z
  • (3) Default: window.crypto, Math.random as fallback

IDs generated w/ this package are composed of a 32, 48 or 64 bit Unix epochs and N additional bits of a random payload (from a configurable source). By default all timestamps are shifted to free up bits for the future. IDs can be generated as byte arrays or base-N encoded strings. For the latter, the JS runtime MUST support BigInt.

KSUID bit layout diagram

CLI usage

Since v3.1.0 a small CLI for ad-hoc KSUID generation is included. Currently only KSUID32 is supported and IDs are always based on the current time:

npx @thi.ng/ksuid
# 0dwncLZE8byaQdccncWDmsNmlYt

# optionally provide number of random bytes to be used (default: 16)
npx @thi.ng/ksuid 8
# 01ogp9KDpWlQ0pXCY

{{meta.status}}

Breaking changes

Since v3.0.0 all epoch time-shift config values are to be given in milliseconds. This change is unifying this behavior and is only a breaking change if using KSUID32 and specifying custom epoch offsets (using defaults is not impacted). Previously, KSUID32 used an offset given in seconds, whereas the other implementations already used milliseconds.

{{repo.supportPackages}}

{{repo.relatedPackages}}

{{meta.blogPosts}}

Installation

{{pkg.install}}

{{pkg.size}}

Dependencies

{{pkg.deps}}

{{repo.examples}}

API

{{pkg.docs}}

import { defKSUID32, defKSUID64, defULID } from "@thi.ng/ksuid";

// init 32bit epoch (resolution: seconds) w/ defaults
const id = defKSUID32();
// init 64bit epoch (resolution: milliseconds), same API
const id = defKSUID64();
// init 48bit epoch (resolution: milliseconds), same API
const id = defULID();

id.next();
// '05XCWbXa3akRqLDBUw4ogCVKGkd'

const a = id.nextBinary()
// Uint8Array(20) [
//     0, 160,  48, 77, 101, 251,
//   244,  17, 155, 97,  24, 101,
//    70,  71, 207, 23,  32,  21,
//   244, 116
// ]

// format a binary KSUID
id.format(a);
// '05XCZ32AaDZfZt0SWE2C22o6cqK'

id.parse("05XCZ32AaDZfZt0SWE2C22o6cqK")
// {
//   epoch: 1610498125000,
//   id: Uint8Array(16) [
//     101, 251, 244,  17, 155, 97,
//      24, 101,  70,  71, 207, 23,
//      32,  21, 244, 116
//   ]
// }

new Date(1610498125000).toISOString()
// '2021-01-13T00:35:25.000Z'

Creating custom IDs:

import { BASE36 } from "@thi.ng/base-n";

// using base36, no time shift, 64bit random part
const id36 = defKSUID32({ base: BASE36, epoch: 0, bytes: 8 });

id36.next();
// '2VOUKH4K59AG0RXR4XH'

Benchmarks

Benchmarks can be run via yarn bench. All timings in milliseconds (test config: Node v20.4.0, MBA M1 2021, 16GB). The benchmark collects N KSUIDs w/ different configs in an array, with each case being run 100 times.

Title Iter Size Total Mean Median Min Max Q1 Q3 SD%
b62, 128bit, n=10000 100 1 2158.68 21.59 21.57 19.91 25.91 20.42 21.87 6.26
b62, 64bit, n=10000 100 1 1200.40 12.00 11.95 11.27 14.66 11.82 12.10 3.99