๐๐ชธ A simple 12-character UID system for small-to-medium-scale applications, optimized for string storage and display. Not intended (but may be suited) for large-scale use.
Note
Still in the stage of finalizing the spec before package starts construction, feedback is welcome!
- 12-character pretty string
- Case-insensitive and URL-safe
- Cleanly separable parts in the string form
- Lexicographically sortable to the timestamp, and guaranteed within a "tank"
- Uses the Unix epoch time with millisecond precision, supporting up to the year 3085
- Support for light distributed setups
- Up to 32 parallel machines with 1024 IDs possible per ms on each
- Official lightweight JavaScript/TypeScript package
samplefishid
samplefis(9 chars): 45-bit millisecond-precision Unix timestamp to the year 3085h(1 char): 5-bit tank ID (32 total)id(2 chars): 10-bit sequence number (1024 IDs/ms)
The bits are converted to string using Crockford's Base32 encoding.
Generating a FishID:
import { FishIdGenerator } from "fishid";
const fish = new FishIdGenerator({
tankId: 0,
lower: false,
random: true
}); // Config optional, example shown here is the default
fish.next();Config explanation:
tankId: The tank ID used to distinguish machines, ID types, etc. Needs to be different in all the ID-generating machines/processes running simultaneously to avoid duplicates. Needs to be an integer between 0-31. (default: 0)lower: Whether the letters in the output ID strings should be in lowercase instead of uppercase. (default: false)random: For lower-volume demands, introduce some randomness into the sequence number section to prevent IDs always ending in "00", at the expense of up to 1/2 of the maximum IDs per millisecond. (default: true)
Parsing metadata from a FishID:
import { FishId } from "fishid";
const id = new FishId("samplefishid");
id.date(); //
id.time(); //
id.tankId(); // - It required configuring an epoch
- The standard representation of a 19-char number is good enough but slightly less ideal
- Less than 70 years of supported time being right at the edge of enough but slightly concerning
- That 1 unused bit for signed integer compatibility
- It's a bit too long (26 chars) due to their choice of using 80 bits of randomness to avoid collisions, but I loved everything else about it
- Mostly still the aesthetics (25 chars)
- The standard string representation of UUIDs is too long and ugly (36 characters counting the dashes! That's 3x FishID)
- It is not supported by the standard JS Cryptro API anyways, so you'd still need a package
- Unacceptable collision probability given our length constraint.
- I didn't want to show in public how many entries are in the database or arbitrarily fake a number.
Yes, 13 characters of base32 (5 bits each) represents 65 bits of information - that's one whole bit of waste if we aim for the 64-bit binary store then encode later >:( , and binary is not the problem we wanted to solve in the beginning! Since we're optimizing for string storage & display, FishID is designed from the resulting string back. 12 characters also feels better, groups into 4-character groups when that is needed, and the binary still fits into 8 bytes.
Since we're using base32, 45 bits make it easily separable using 9 characters in the final string-form ID. It's also a perfect length for our use of the Unix epoch with millisecond-precision support.
This project was first created to solve the UID problem of a salmon-related game.