Verified on node.js v6, v8, v10, v11 and v12
Table of Contents
AnyID is a simple and flexible API to generate various kinds of string ID / code.
The generated ID is compounded by sections with optional delimiter. Each section is encoded into specificed chars and may have fix length.
sdk3ksxjcs-JEDke3x8F-sldle34CZs
^^^^^^^^^^ ^
│ │
└ section └ delimiter
A section may contain one or more values. Multiple values are concatenated into bit stream before encoded.
┌───────────────────────┬───────────────┬──────────────────┐
│ timestamp (41 bits) │ seq (12 bits) │ worker (10 bits) │
└───────────────────────┴───────────────┴──────────────────┘
Use it in your code:
import {anyid} from 'anyid';
const ids = anyid().encode('Aa0').length(21).random();
console.log(ids.id());
If you aren't using ES6, this is the way to require it:
var anyid = require('anyid').anyid;
>>> Try it in your browser. <<<
Encode with given charset:
encode(charset: string)
Charset is specified by simple letter:
A
- Alphabet in upper casea
- Alphabet in lower case0
- Numeric
Individual letters can be exclude by followed after -
, be appended by followed after +
.
Example:
Aa0
= A-Z a-z 0-90A-IO
= 0-9 A-Z, excludesI
andO
0+ABCDEF
= 0-9 A-FA+012-IO
= A-Z 0 1 2, excludesI
andO
A section accepts an AnyId
object as parameter. For ID containing single section, section
function is not used.
section( anyid: AnyId )
Section length can be fixed or variant. When length is specified, section will be trimmed or padded at beginning side.
length(n: number)
For some kinds of value, e.g. random, length must be given.
Hint What length will be if not specified?
b: value bytes a: charset size length ≧ logₐ256ᵇ = log₂ 256ᵇ / log₂ a = 8b / log₂ a
For example:
Value is 4 bytes UInt32, charset is A-Za-z0-9 which has 62 characters.
8 * 4 / log₂ 62 = 5.37
. Maximum length will be 6.
Delimiter can be put between sections. It's output as is and never be encoded.
delimiter( s: string )
AnyID supports several kinds of value:
- random
- timestamp
- sequence
- fix value
- function result
- variable
Value is either non-negative integer (UInt32) or Buffer
(byte array).
A section may have more than one values. Values will be concatenated as bit stream before encoded.
You can use bits
to specify the bit width of a value. Higher bits will be discard if value has more bits than desired.
bits( n: number )
Generate value by random. Length or bits must be specified.
random()
Internally it uses crypto.randomBytes()
to generate random.
Hint The probability of duplicates in
n
random IDs is:p(n) ≈ n²/(2*C^L)
Where
L
is the length of random id,C
is the size of encode charset.For example: using
anyid().encode('Aa0').length(21).random()
to generate randome ID,L
is 21 andC
is 62. Thenp(n) ≈ n²/(2*62^21)
. It has lower probability of duplicates then type 4 (random) UUID.
Use current timestamp as value.
time( unit: string = 'ms' )
Unit can be ms
, s
, m
, h
, d
.
By default, timestamp value is since UNIX epoch time. You can overwrite it to a recent date to save some bits.
since( t: Date )
Sequence increases everytime an ID is generated.
seq()
By default, sequence starts from 0. You can set it to any non-negative integer.
startWith( n: number )
Sequence will be reset after it reaches max value.
It can not exceed 2^32
(max value represented by UInt32).
max( n: number )
Or, let it reset when timestamp changes:
resetByTime()
To use resetByTime
, there must be a timestamp value in the ID.
fixed( n: number | Buffer )
Value is either non-negative integer (UInt32) or Buffer
(byte array).
Similar to fix value, but the value is returned by a function which is called an ID is to be generated.
of( f: () => number | Buffer )
Similar to fix value, but the value is given in id
function call.
variable( name?: string )
When there is only one variable used in ID generator, the name can be omitted in variable()
and the value is directly passing in id
function call:
id( v: number | Buffer )
When there are multiple variables used in ID generator, the values need to be passing in id
in an object:
id( v: {[name: string]: number | Buffer} )
Read example below to check how it's used.
This id has essence the same low probability of a clash as type 4 (random) UUID:
const ids = anyid().encode('Aa0').length(21).random()
const id = ids.id();
1LrKcmd0uk1Ma8szUxtda
const ids = anyid()
.encode('0A-IO')
.section( anyid().fixed(process.pid) )
.delimiter('-')
.section( anyid().time() );
It uses human friendly charset: I
and O
are excluded because of similarity to 1
and 0
.
008CL-00TYMZS0P3
It's Twitter Snowflake style ID with timestamp, sequence and worker.
const ids = anyid()
.encode('0')
.bits(41).time().since(new Date('2016-7-1'))
.bits(12).seq().resetByTime();
.bits(10).fix(workerId);
Timestamp is since 2016-7-1. Sequence is reset every millisecond.
071243223959339218
ID contains second and nanosecond. Nanosecond is retrieved by a function.
const nanotime = () => process.hrtime()[1];
const ids = anyid()
.encode('Aa0')
.section( anyid().time('s') )
.delimiter('+')
.section( anyid().of(nanotime) );
BlX6bX+j3Uz0
The ID has default charset A-IO
. The second section uses charset 0
.
const ids = anyid()
.encode('A-IO')
.section( anyid().length(3).random() )
.delimiter(' ')
.section( anyid().encode('0').length(3).random() )
.delimiter(' ')
.section( anyid().length(3).random() );
HQX 552 ATC
const ids = anyid()
.encode('Aa0')
.section( anyid().variable() )
.delimiter('-')
.section( anyid().time() );
const id = ids(Buffer.from('user-xxx'));
KFLnaOrolmA-AAZ28TmMo
const ids = anyid()
.encode('Aa0')
.section( anyid().variable('countryId') )
.delimiter('-')
.section( anyid().variable('userId') )
.delimiter('-')
.section( anyid().length(5).random() );
const id = ids.id({ countryId: 86, userId: 635023 });
AAABY-ACpMT-EBwQJ