Skip to content

Commit 4848114

Browse files
Merge pull request #119 from ulid/feat/v3-rework
feat(v3): Rework ulid based on ulidx
2 parents 0e660a6 + bf04496 commit 4848114

37 files changed

Lines changed: 1906 additions & 5200 deletions

.babelrc

Lines changed: 0 additions & 11 deletions
This file was deleted.

.editorconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ root = true
33

44
[*]
55
indent_style = space
6-
indent_size = 2
6+
indent_size = 4
77
end_of_line = lf
88
charset = utf-8
99
trim_trailing_whitespace = true

.github/workflows/test.yml

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,40 @@ name: Tests
22

33
on:
44
push:
5+
branches:
6+
- master
57
pull_request:
8+
branches:
9+
- master
610

711
jobs:
812
nodejs:
913
runs-on: ubuntu-latest
1014
strategy:
1115
matrix:
12-
node-version: [16.x, 22.x]
16+
node-version: [18.x, 22.x]
1317
steps:
1418
- uses: actions/checkout@v2
1519
- name: Node.js specs ${{ matrix.node-version }}
1620
uses: actions/setup-node@v1
1721
with:
1822
node-version: ${{ matrix.node-version }}
19-
- run: npm ci
23+
- run: npm i
2024
- run: npm run build
21-
- run: npm run test
25+
- run: npm run test:specs
26+
format:
27+
runs-on: ubuntu-latest
28+
strategy:
29+
matrix:
30+
node-version: [22.x]
31+
steps:
32+
- uses: actions/checkout@v2
33+
- name: Type checks ${{ matrix.node-version }}
34+
uses: actions/setup-node@v1
35+
with:
36+
node-version: ${{ matrix.node-version }}
37+
- run: npm i
38+
- run: npm run test:format
2239
types:
2340
runs-on: ubuntu-latest
2441
strategy:
@@ -30,6 +47,6 @@ jobs:
3047
uses: actions/setup-node@v1
3148
with:
3249
node-version: ${{ matrix.node-version }}
33-
- run: npm ci
50+
- run: npm i
3451
- run: npm run build
35-
- run: npx --yes @arethetypeswrong/cli@latest --pack .
52+
- run: npm run test:types

.gitignore

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,6 @@
11
.DS_Store
2-
3-
# Logs
4-
logs
52
*.log
6-
npm-debug.log*
7-
8-
# Runtime data
9-
pids
10-
*.pid
11-
*.seed
12-
13-
# Directory for instrumented libs generated by jscoverage/JSCover
14-
lib-cov
15-
16-
# Coverage directory used by tools like istanbul
17-
coverage
18-
19-
# nyc test coverage
20-
.nyc_output
213

22-
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
23-
.grunt
24-
25-
# node-waf configuration
26-
.lock-wscript
27-
28-
# Compiled binary addons (http://nodejs.org/api/addons.html)
29-
build/Release
30-
31-
# Dependency directories
324
node_modules
33-
jspm_packages
34-
35-
# Optional npm cache directory
36-
.npm
37-
38-
# Optional REPL history
39-
.node_repl_history
5+
/dist
6+
coverage

.prettierrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"printWidth": 100,
3+
"tabWidth": 4,
4+
"trailingComma": "none",
5+
"arrowParens": "avoid"
6+
}

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"typescript.preferences.importModuleSpecifierEnding": "js"
3+
}

README.md

Lines changed: 75 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,25 @@
77
<br>
88
</h1>
99

10+
# Universally Unique Lexicographically Sortable Identifier
11+
1012
[![Tests](https://github.com/ulid/javascript/actions/workflows/test.yml/badge.svg)](https://github.com/ulid/javascript/actions/workflows/test.yml)
1113
[![codecov](https://codecov.io/gh/ulid/javascript/branch/master/graph/badge.svg)](https://codecov.io/gh/ulid/javascript)
12-
[![npm](https://img.shields.io/npm/dm/ulid.svg)](https://www.npmjs.com/package/ulid)
14+
[![npm](https://img.shields.io/npm/dm/ulid.svg)](https://www.npmjs.com/package/ulid) [![npm](https://img.shields.io/npm/dy/ulid)](https://www.npmjs.com/package/ulid)
1315

14-
# Universally Unique Lexicographically Sortable Identifier
16+
ULIDs are unique, sortable identifiers that work much in the same way as UUIDs, though with some improvements:
17+
18+
* Lexicographically sortable
19+
* Canonically encoded as a 26 character string, as opposed to the 36 character UUID
20+
* Uses Crockford's base32 for better efficiency and readability (5 bits per character)
21+
* Monotonic sort order (correctly detects and handles the same millisecond)
22+
23+
ULIDs also provide:
24+
25+
* 128-bit compatibility with UUID
26+
* 1.21e+24 unique IDs per millisecond
27+
* Case insensitivity
28+
* No special characters (URL safe)
1529

1630
UUID can be suboptimal for many uses-cases because:
1731

@@ -20,164 +34,122 @@ UUID can be suboptimal for many uses-cases because:
2034
- UUID v3/v5 requires a unique seed and produces randomly distributed IDs, which can cause fragmentation in many data structures
2135
- UUID v4 provides no other information than randomness which can cause fragmentation in many data structures
2236

23-
Instead, herein is proposed ULID:
24-
25-
- 128-bit compatibility with UUID
26-
- 1.21e+24 unique ULIDs per millisecond
27-
- Lexicographically sortable!
28-
- Canonically encoded as a 26 character string, as opposed to the 36 character UUID
29-
- Uses Crockford's base32 for better efficiency and readability (5 bits per character)
30-
- Case insensitive
31-
- No special characters (URL safe)
32-
- Monotonic sort order (correctly detects and handles the same millisecond)
37+
## Installation
3338

34-
## Install with a script tag
39+
Install using NPM:
3540

36-
```html
37-
<script src="https://unpkg.com/ulid@{{VERSION_NUMBER}}/dist/index.umd.js"></script>
38-
<script>
39-
ULID.ulid()
40-
</script>
41+
```shell
42+
npm install ulid --save
4143
```
4244

43-
## Install with NPM
44-
45-
```
46-
npm install --save ulid
47-
```
48-
49-
### Import
50-
51-
**TypeScript, ES6+, Babel, Webpack, Rollup, etc.. environments**
52-
```javascript
53-
import { ulid } from 'ulid'
54-
55-
ulid() // 01ARZ3NDEKTSV4RRFFQ69G5FAV
56-
```
45+
### Compatibility
5746

58-
**CommonJS environments**
59-
```javascript
60-
const ULID = require('ulid')
47+
ULID supports the following environments:
6148

62-
ULID.ulid()
63-
```
49+
| Version | NodeJS | Browsers | React-Native | Web Workers | Edge Functions |
50+
|-----------|-----------|---------------|---------------|---------------|-------------------|
51+
| v3 | v18+ | Yes | Yes | Yes | ? |
52+
| v2 | v16+ | Yes | No | No | No |
6453

65-
**AMD (RequireJS) environments**
66-
```javascript
67-
define(['ULID'] , function (ULID) {
68-
ULID.ulid()
69-
});
70-
```
54+
Additionally, both ESM and CommonJS entrypoints are provided.
7155

7256
## Usage
7357

74-
To generate a ULID, simply run the function!
58+
To quickly generate a ULID, you can simply import the `ulid` function:
7559

76-
```javascript
77-
import { ulid } from 'ulid'
60+
```typescript
61+
import { ulid } from "ulid";
7862

79-
ulid() // 01ARZ3NDEKTSV4RRFFQ69G5FAV
63+
ulid(); // "01ARZ3NDEKTSV4RRFFQ69G5FAV"
8064
```
8165

8266
### Seed Time
8367

8468
You can also input a seed time which will consistently give you the same string for the time component. This is useful for migrating to ulid.
8569

86-
```javascript
87-
ulid(1469918176385) // 01ARYZ6S41TSV4RRFFQ69G5FAV
70+
```typescript
71+
ulid(1469918176385) // "01ARYZ6S41TSV4RRFFQ69G5FAV"
8872
```
8973

9074
### Monotonic ULIDs
9175

92-
To generate monotonically increasing ULIDs, create a monotonic counter.
76+
To generate monotonically increasing ULIDs, create a monotonic counter with `monotonicFactory`.
9377

94-
*Note that the same seed time is being passed in for this example to demonstrate its behaviour when generating multiple ULIDs within the same millisecond*
78+
> Note that the same seed time is being passed in for this example to demonstrate its behaviour when generating multiple ULIDs within the same millisecond
9579
96-
```javascript
97-
import { monotonicFactory } from 'ulid'
80+
```typescript
81+
import { monotonicFactory } from "ulid";
9882

99-
const ulid = monotonicFactory()
83+
const ulid = monotonicFactory();
10084

10185
// Strict ordering for the same timestamp, by incrementing the least-significant random bit by 1
102-
ulid(150000) // 000XAL6S41ACTAV9WEVGEMMVR8
103-
ulid(150000) // 000XAL6S41ACTAV9WEVGEMMVR9
104-
ulid(150000) // 000XAL6S41ACTAV9WEVGEMMVRA
105-
ulid(150000) // 000XAL6S41ACTAV9WEVGEMMVRB
106-
ulid(150000) // 000XAL6S41ACTAV9WEVGEMMVRC
86+
ulid(150000); // "000XAL6S41ACTAV9WEVGEMMVR8"
87+
ulid(150000); // "000XAL6S41ACTAV9WEVGEMMVR9"
88+
ulid(150000); // "000XAL6S41ACTAV9WEVGEMMVRA"
89+
ulid(150000); // "000XAL6S41ACTAV9WEVGEMMVRB"
90+
ulid(150000); // "000XAL6S41ACTAV9WEVGEMMVRC"
10791

10892
// Even if a lower timestamp is passed (or generated), it will preserve sort order
109-
ulid(100000) // 000XAL6S41ACTAV9WEVGEMMVRD
93+
ulid(100000); // "000XAL6S41ACTAV9WEVGEMMVRD"
11094
```
11195

11296
### Pseudo-Random Number Generators
11397

114-
`ulid` automatically detects a suitable (cryptographically-secure) PRNG. In the browser it will use `crypto.getRandomValues` and on node it will use `crypto.randomBytes`.
98+
`ulid` automatically detects a suitable (cryptographically-secure) PRNG. In the browser it will use `crypto.getRandomValues` and on NodeJS it will use `crypto.randomBytes`.
11599

116-
#### Allowing the insecure `Math.random`
100+
#### Using `Math.random` (insecure)
117101

118-
By default, `ulid` will not use `Math.random`, because that is insecure. To allow the use of `Math.random`, you'll have to use `factory` and `detectPrng`.
102+
By default, `ulid` will not use `Math.random` to generate random values. You can bypass this limitation by overriding the PRNG:
119103

120-
```javascript
121-
import { factory, detectPrng } from 'ulid'
104+
```typescript
105+
const ulid = monotonicFactory(() => Math.random());
122106

123-
const prng = detectPrng(true) // pass `true` to allow insecure
124-
const ulid = factory(prng)
125-
126-
ulid() // 01BXAVRG61YJ5YSBRM51702F6M
107+
ulid(); // "01BXAVRG61YJ5YSBRM51702F6M"
127108
```
128109

129-
#### Use your own PRNG
130-
131-
To use your own pseudo-random number generator, import the factory, and pass it your generator function.
110+
### Validity
132111

133-
```javascript
134-
import { factory } from 'ulid'
135-
import prng from 'somewhere'
112+
You can verify if a value is a valid ULID by using `isValid`:
136113

137-
const ulid = factory(prng)
114+
```typescript
115+
import { isValid } from "ulid";
138116

139-
ulid() // 01BXAVRG61YJ5YSBRM51702F6M
117+
isValid("01ARYZ6S41TSV4RRFFQ69G5FAV"); // true
118+
isValid("01ARYZ6S41TSV4RRFFQ69G5FA"); // false
140119
```
141120

142-
You can also pass in a `prng` to the `monotonicFactory` function.
121+
### ULID Time
143122

144-
```javascript
145-
import { monotonicFactory } from 'ulid'
146-
import prng from 'somewhere'
123+
You can encode and decode ULID timestamps by using `encodeTime` and `decodeTime` respectively:
147124

148-
const ulid = monotonicFactory(prng)
125+
```typescript
126+
import { decodeTime } from "ulid";
149127

150-
ulid() // 01BXAVRG61YJ5YSBRM51702F6M
128+
decodeTime("01ARYZ6S41TSV4RRFFQ69G5FAV"); // 1469918176385
151129
```
152130

153-
## Implementations in other languages
131+
Note that while `decodeTime` works on full ULIDs, `encodeTime` encodes only the _time portion_ of ULIDs:
154132

155-
Refer to [ulid/spec](https://github.com/ulid/spec)
133+
```typescript
134+
import { encodeTime } from "ulid";
156135

157-
## Specification
136+
encodeTime(1469918176385); // "01ARYZ6S41"
137+
```
158138

159-
Refer to [ulid/spec](https://github.com/ulid/spec)
139+
### Tests
160140

161-
## Test Suite
141+
Install dependencies using `npm install` first, and then simply run `npm test` to run the test suite.
162142

163-
```
164-
npm test
165-
```
143+
## Specification
144+
145+
You can find the full specification, as well as information regarding implementations in other languages, over at [ulid/spec](https://github.com/ulid/spec).
166146

167147
## Performance
168148

169-
```
170-
npm run perf
171-
```
149+
You can test `ulid`'s performance by running `npm run bench`:
172150

173151
```
174-
ulid
175-
336,331,131 op/s » encodeTime
176-
102,041,736 op/s » encodeRandom
177-
17,408 op/s » generate
178-
179-
180-
Suites: 1
181-
Benches: 3
182-
Elapsed: 7,285.75 ms
152+
Simple ulid x 56,782 ops/sec ±2.50% (86 runs sampled)
153+
ulid with timestamp x 58,574 ops/sec ±1.80% (87 runs sampled)
154+
Done!
183155
```

bin/cli.js

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)