uniku 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +52 -560
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -2,618 +2,110 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/uniku.svg)](https://www.npmjs.com/package/uniku)
4
4
  [![npm downloads](https://img.shields.io/npm/dm/uniku.svg)](https://npmjs.com/package/uniku)
5
- [![Bundle Size](https://img.shields.io/bundlephobia/minzip/uniku)](https://bundlephobia.com/package/uniku)
6
5
  [![CI](https://github.com/jkomyno/uniku/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/jkomyno/uniku/actions/workflows/ci.yaml)
7
- [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
6
+ [![Documentation](https://img.shields.io/badge/docs-read-5b5bd6.svg)](https://jkomyno.github.io/uniku/)
8
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
9
8
 
10
- One library. Every ID format. Every runtime. One runtime dependency (`@noble/hashes`, CUID2 only).
9
+ One library. Every ID format. Every modern JavaScript runtime.
11
10
 
12
11
  > **uniku** */uˈniːku/* — Maltese for "unique"
13
12
 
13
+ [Documentation](https://jkomyno.github.io/uniku/) · [Getting started](https://jkomyno.github.io/uniku/docs/getting-started/) · [Choosing an ID](https://jkomyno.github.io/uniku/docs/guides/choosing-an-id/) · [API reference](https://jkomyno.github.io/uniku/docs/reference/entry-points/) · [CLI](https://jkomyno.github.io/uniku/docs/cli/)
14
+
14
15
  ```ts
15
16
  import { uuidv7 } from 'uniku/uuid/v7'
16
17
 
17
18
  const id = uuidv7()
18
19
  // => "018e5e5c-7c8a-7000-8000-000000000000"
19
-
20
- // Time-ordered: IDs sort by creation time
21
- const [first, second, third] = [uuidv7(), uuidv7(), uuidv7()]
22
- console.log(first < second && second < third) // true
23
- ```
24
-
25
- ## At a Glance
26
-
27
- | | uniku | [uuid](https://github.com/uuidjs/uuid) | [typeid-js](https://github.com/jetify-com/typeid-js) | [nanoid](https://github.com/ai/nanoid) | [ulid](https://github.com/ulid/javascript) | [cuid2](https://github.com/paralleldrive/cuid2) | [ksuid](https://github.com/owpz/ksuid) | [bson](https://github.com/mongodb/js-bson) | [tsid-ts](https://github.com/yubinTW/tsid-ts) |
28
- |--------------------|:-----:|:----:|:---------:|:------:|:----:|:-----:|:-----:|:-----:|:-----:|
29
- | UUID v4 | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
30
- | UUID v7 | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
31
- | TypeID | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
32
- | Nanoid | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
33
- | ULID | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
34
- | CUID2 | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
35
- | KSUID | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
36
- | ObjectID | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ |
37
- | TSID | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
38
- | XID | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
39
- | Tree-shakeable | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
40
- | ESM-only | ✅ | ✅¹ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
41
- | Edge/Workers | ✅ | ✅ | ✅ | ✅ | ⚠️ | ✅ | ⚠️ | ⚠️ | ⚠️ |
42
- | Byte ↔ String | ✅ | ✅ | ✅ | - | ⚠️² | - | ✅ | ✅ | ✅ |
43
-
44
- > **Notes:**
45
- > - Byte ↔ String conversion doesn't make sense for nanoid and cuid2, since they are string-native formats with no canonical binary representation.
46
- > - ¹ `uuid@13` is ESM-only; earlier versions support CommonJS.
47
- > - ² `ulid` only provides timestamp encoding/decoding, not full binary serialization.
48
-
49
- ### Works Everywhere
50
-
51
- <p align="center">
52
- <img src="https://img.shields.io/badge/Node.js-339933?logo=nodedotjs&logoColor=white" alt="Node.js">
53
- <img src="https://img.shields.io/badge/Deno-000000?logo=deno&logoColor=white" alt="Deno">
54
- <img src="https://img.shields.io/badge/Bun-000000?logo=bun&logoColor=white" alt="Bun">
55
- <img src="https://img.shields.io/badge/Cloudflare_Workers-F38020?logo=cloudflare&logoColor=white" alt="Cloudflare Workers">
56
- <img src="https://img.shields.io/badge/Vercel_Edge-000000?logo=vercel&logoColor=white" alt="Vercel Edge">
57
- <img src="https://img.shields.io/badge/Browsers-4285F4?logo=googlechrome&logoColor=white" alt="Browsers">
58
- </p>
59
-
60
- Uses `globalThis.crypto` (Web Crypto API) — no Node.js-specific APIs.
61
-
62
- ## Performance
63
-
64
- | Generator | uniku vs npm |
65
- |-----------|-------------:|
66
- | ULID | **85× faster** |
67
- | CUID2 | **8× faster** |
68
- | KSUID | **1.5× faster** |
69
- | ObjectID | **1.1× faster** |
70
- | TSID | **1.7× faster** |
71
- | XID | **1.3× faster** |
72
- | UUID v7 | **1.1× faster** |
73
- | Nanoid | **1.9× faster** |
74
- | Nanoid (10 chars) | **1.3× faster** |
75
- | TypeID | **2.6× faster** |
76
- | UUID v4 | npm is 1.1× faster |
77
-
78
- ## Which ID Should I Use?
79
-
80
- ### Quick Recommendations
81
-
82
- | Use Case | Recommended | Why |
83
- |----------|-------------|-----|
84
- | Database primary keys | **UUID v7** or **ULID** | Time-ordered for index efficiency |
85
- | API/domain identifiers | **TypeID** | UUID v7 with readable type prefixes like `user_...` |
86
- | URL shorteners | **Nanoid** | Compact, URL-safe characters |
87
- | Prevent enumeration | **CUID2** | Non-sequential, secure |
88
- | Maximum compatibility | **UUID v4** | Universal standard |
89
- | Distributed systems needing sortable, URL-safe IDs | **ULID** | Millisecond ordering + 80-bit entropy |
90
- | Very high-volume distributed systems | **KSUID** | Time-ordered with 128-bit entropy |
91
- | MongoDB `_id` compatibility | **ObjectID** | Drop-in match for MongoDB's native document ID format |
92
- | Native 64-bit sortable integer ID | **TSID** | Fits a database `BIGINT` primary key, no UUID-sized overhead |
93
- | Go rs/xid compatibility | **XID** | Compact, time-ordered 12-byte identifier |
94
-
95
- ### Detailed Guide
96
-
97
- **UUID v4** — Use when you need maximum compatibility with existing systems.
98
- - 36 characters, 122-bit entropy
99
- - Universally supported by databases (native `UUID` type)
100
- - Not time-ordered (random distribution)
101
- - Best for: Legacy systems, cross-platform compatibility
102
-
103
- **UUID v7** — Use for database primary keys when you need RFC compliance.
104
- - 36 characters, time-ordered with millisecond precision
105
- - Native database support as `UUID` type
106
- - Strictly monotonic within same millisecond
107
- - Best for: PostgreSQL/MySQL primary keys, API identifiers
108
-
109
- **ULID** — Use for database primary keys when you want URL-safe IDs.
110
- - 26 characters, time-ordered with millisecond precision
111
- - URL-safe (no hyphens), case-insensitive
112
- - 80-bit random entropy per millisecond
113
- - Best for: APIs, URLs, distributed systems needing sortability
114
-
115
- **TypeID** — Use when API IDs should expose their entity type.
116
- - Prefix plus 26-character UUID v7 suffix, e.g. `user_01h2xcejqtf2nbrexx3vqjhp41`
117
- - Empty prefix support for canonical 26-character TypeIDs
118
- - Time-ordered through UUID v7, with lowercase snake_case type prefixes
119
- - Best for: Public API identifiers, logs, debugging, domain-specific IDs
120
-
121
- **KSUID** — Use when you need highest collision resistance.
122
- - 27 characters, time-ordered with second precision
123
- - URL-safe, 128-bit random entropy (highest of all formats)
124
- - Best for: Very high-volume distributed systems, event sourcing
125
-
126
- **ObjectID** — Use when you need drop-in compatibility with MongoDB.
127
- - 24-character lowercase hex, time-ordered with second precision
128
- - 4-byte timestamp + 5-byte per-process random + 3-byte always-incrementing counter
129
- - Counter never resets on a new timestamp (unlike ULID/UUIDv7/KSUID sequences)
130
- - Best for: MongoDB `_id` fields, systems already speaking the ObjectID wire format
131
-
132
- **TSID** — Use when you need a native 64-bit sortable integer ID, e.g. a database `BIGINT` primary key.
133
- - 64-bit Snowflake-style value, time-ordered with millisecond precision
134
- - Returns a `bigint` by default (the only uniku generator that isn't string-primary); `toString`/`fromString` convert to/from the 13-character canonical string
135
- - 42-bit timestamp + 10-bit node + 12-bit per-millisecond counter, with a persistent lazily-random node ID
136
- - Best for: relational database `BIGINT` primary keys, high-throughput distributed ID generation without central coordination
137
-
138
- **Nanoid** — Use for short, URL-friendly identifiers.
139
- - 21 characters (configurable), 126-bit entropy
140
- - Customizable alphabet and length
141
- - Not time-ordered
142
- - Best for: URL shorteners, session tokens, invite codes
143
-
144
- **CUID2** — Use when ID unpredictability matters.
145
- - 24 characters (configurable), hash-based
146
- - Non-sequential, prevents enumeration attacks
147
- - Not time-ordered
148
- - Best for: User-facing IDs where security matters
149
-
150
- ### Binary Serialization: When to Use `toBytes()`
151
-
152
- Formats with binary representations (UUID, ULID, KSUID, ObjectID, TSID) support `toBytes()` and `fromBytes()` for efficient storage:
153
-
154
- ```ts
155
- // Store as BINARY(16) instead of VARCHAR(36)
156
- const bytes = uuidv7.toBytes(id) // 16 bytes
157
- db.insert({ id: bytes })
158
-
159
- // Retrieve and convert back
160
- const id = uuidv7.fromBytes(row.id)
161
20
  ```
162
21
 
163
- **Benefits of binary storage:**
164
- - **Up to 50% smaller**: E.g., 16 bytes vs 36 characters for UUID
165
- - **Faster indexing**: Binary comparison is faster than string comparison
166
- - **Reduced I/O**: Less data transferred between app and database
167
-
168
- **When to use binary:**
169
- - High-volume tables (millions of rows)
170
- - Performance-critical queries on ID columns
171
- - Storage cost is a concern
172
-
173
- **Exception — `tsid`:** `toBytes()`/`fromBytes()` operate on `bigint`, not `string`, since `bigint` is TSID's primary type (see [`tsid`](#tsid-from-unikutsid) in the API Reference below). Every other generator's `toBytes()`/`fromBytes()` operate on its primary `string` type.
174
-
175
- **When to keep strings:**
176
- - Debugging/logging convenience
177
- - API responses (humans read them)
178
- - Small tables where savings are negligible
22
+ ## Why `uniku`?
179
23
 
180
- | Format | String Length | Binary Size | Savings |
181
- |--------|--------------|-------------|---------|
182
- | UUID v4/v7 | 36 chars | 16 bytes | 56% |
183
- | ULID | 26 chars | 16 bytes | 38% |
184
- | TypeID | prefix + 27 chars | 16 bytes | prefix-dependent |
185
- | KSUID | 27 chars | 20 bytes | 26% |
186
- | ObjectID | 24 chars | 12 bytes | 50% |
187
- | TSID | 13 chars* | 8 bytes | 38% |
188
- | Nanoid | 21 chars | N/A | - |
189
- | CUID2 | 24 chars | N/A | - |
24
+ - **One focused package** — UUID v4/v7, ULID, TypeID, CUID v2, Nanoid, KSUID, ObjectID, XID, and TSID.
25
+ - **Portable by default** — Runs on Node.js, Bun, Deno, browsers, edge runtimes, and Cloudflare Workers using `globalThis.crypto`.
26
+ - **Tree-shakeable entry points** — Import only the generator you use; the package root is intentionally not exported.
27
+ - **Useful at system boundaries** — Validate unknown input, convert canonical binary formats to bytes, or write directly into a caller-owned buffer.
28
+ - **Small dependency surface** — CUID v2 is the only generator with a runtime dependency (`@noble/hashes`).
190
29
 
191
- > **Note**: Nanoid and CUID2 don't have binary representations because they're string-native formats with no canonical byte encoding.
192
- >
193
- > \* TSID's primary type is `bigint`, not a string; the 13-character figure is its canonical `toString()` form, shown here only for a size comparison against the other formats' native strings.
30
+ ## Install
194
31
 
195
- ## Installation
196
-
197
- ```bash
198
- # pnpm (recommended)
199
- pnpm add uniku
200
-
201
- # bun
202
- bun add uniku
203
-
204
- # npm
32
+ ```sh
205
33
  npm install uniku
206
-
207
- # yarn
208
- yarn add uniku
209
-
210
- # deno
211
- deno install npm:uniku
212
34
  ```
213
35
 
214
- ### Bundle Impact
215
-
216
- | Import | Minified + gzipped |
217
- |--------|-------------------:|
218
- | `uniku/uuid/v4` | ~1.1 KB |
219
- | `uniku/uuid/v7` | ~1.4 KB |
220
- | `uniku/ulid` | ~1.8 KB |
221
- | `uniku/typeid` | ~1.6 KB |
222
- | `uniku/cuid/v2` | ~992 B* |
223
- | `uniku/cuid2` | ~1007 B* |
224
- | `uniku/nanoid` | ~1.2 KB |
225
- | `uniku/ksuid` | ~1.3 KB |
226
- | `uniku/objectid` | ~1.3 KB |
227
- | `uniku/tsid` | ~1.4 KB |
228
- | `uniku/xid` | ~1.9 KB |
229
- | `uniku/generators` | ~98 B |
230
-
231
- * The CUID2 entry point imports SHA3-512 from `@noble/hashes`; this table's entry-point size excludes that external dependency.
232
-
233
- ## Quick Start
234
-
235
- ### UUID v4 (random)
36
+ The [getting-started guide](https://jkomyno.github.io/uniku/docs/getting-started/) also covers pnpm, Bun, and Deno.
236
37
 
237
- ```ts
238
- import { uuidv4 } from 'uniku/uuid/v4'
239
-
240
- const id = uuidv4()
241
- // => "550e8400-e29b-41d4-a716-446655440000"
242
-
243
- // Convert to/from bytes
244
- const bytes = uuidv4.toBytes(id)
245
- const str = uuidv4.fromBytes(bytes)
246
- ```
38
+ ## Quick start
247
39
 
248
- ### UUID v7 (time-ordered)
40
+ Every generator has its own entry point and keeps related operations on the generator function:
249
41
 
250
42
  ```ts
251
43
  import { uuidv7 } from 'uniku/uuid/v7'
252
44
 
253
45
  const id = uuidv7()
254
- // => "018e5e5c-7c8a-7000-8000-000000000000"
46
+ const bytes = uuidv7.toBytes(id)
47
+ const restored = uuidv7.fromBytes(bytes)
255
48
 
256
- // IDs are lexicographically sortable by creation time
257
- const ids = [uuidv7(), uuidv7(), uuidv7()]
258
- ids.sort() // Already in creation order
49
+ if (uuidv7.isValid(restored)) {
50
+ console.log(uuidv7.timestamp(restored))
51
+ }
259
52
  ```
260
53
 
261
- ### ULID (time-ordered)
54
+ There are no barrel exports:
262
55
 
263
56
  ```ts
57
+ import { uuidv4 } from 'uniku/uuid/v4'
264
58
  import { ulid } from 'uniku/ulid'
265
-
266
- const id = ulid()
267
- // => "01HW9T2W9W9YJ3JZ1H4P4M2T8Q"
268
-
269
- // Convert to/from bytes
270
- const bytes = ulid.toBytes(id)
271
- const str = ulid.fromBytes(bytes)
272
- ```
273
-
274
- ### TypeID (prefixed UUID v7)
275
-
276
- ```ts
277
59
  import { typeid } from 'uniku/typeid'
278
-
279
- const id = typeid('user')
280
- // => "user_01h2xcejqtf2nbrexx3vqjhp41"
281
-
282
- const uuid = typeid.toUuid(id)
283
- const restored = typeid.fromUuid('user', uuid)
284
-
285
- const canonical = typeid('')
286
- // => "01h2xcejqtf2nbrexx3vqjhp41"
287
- ```
288
-
289
- ### CUID2 (secure, non-time-ordered)
290
-
291
- ```ts
292
60
  import { cuidv2 } from 'uniku/cuid/v2'
293
-
294
- const id = cuidv2()
295
- // => "pfh0haxfpzowht3oi213cqos"
296
-
297
- // Custom length
298
- const shortId = cuidv2({ length: 10 })
299
- // => "tz4a98xxat"
300
-
301
- // Validation (type guard)
302
- if (cuidv2.isValid(maybeId)) {
303
- console.log(maybeId) // TypeScript knows this is a string
304
- }
305
- ```
306
-
307
- > `uniku/cuid/v2` is the canonical entry point. The older `uniku/cuid2` import
308
- > still works and re-exports the same generator, but is now deprecated — prefer
309
- > `import { cuidv2 } from 'uniku/cuid/v2'`.
310
-
311
- ### Nanoid (URL-friendly, custom alphabet)
312
-
313
- ```ts
314
61
  import { nanoid } from 'uniku/nanoid'
315
-
316
- const id = nanoid()
317
- // => "V1StGXR8_Z5jdHi6B-myT"
318
-
319
- // Custom size
320
- const shortId = nanoid(10)
321
- // => "IRFa-VaY2b"
322
-
323
- // Custom alphabet and size via options
324
- const hexId = nanoid({ alphabet: '0123456789abcdef', size: 12 })
325
- // => "4f90d13a42bc"
326
- ```
327
-
328
- ### KSUID (time-ordered, high entropy)
329
-
330
- ```ts
331
62
  import { ksuid } from 'uniku/ksuid'
332
-
333
- const id = ksuid()
334
- // => "2QnJjKLvpSfpZqGiPPxVwWLMy2p"
335
-
336
- // Convert to/from bytes
337
- const bytes = ksuid.toBytes(id)
338
- const str = ksuid.fromBytes(bytes)
339
-
340
- // Extract timestamp (milliseconds)
341
- const ts = ksuid.timestamp(id)
342
- ```
343
-
344
- ### ObjectID (time-ordered, MongoDB-compatible)
345
-
346
- ```ts
347
63
  import { objectid } from 'uniku/objectid'
348
-
349
- const id = objectid()
350
- // => "667c3f2a1e2b3c4d5e6f7081"
351
-
352
- // Convert to/from bytes
353
- const bytes = objectid.toBytes(id)
354
- const str = objectid.fromBytes(bytes)
355
-
356
- // Extract timestamp (milliseconds)
357
- const ts = objectid.timestamp(id)
358
- ```
359
-
360
- ### TSID (time-ordered, 64-bit integer)
361
-
362
- ```ts
363
- import { tsid } from 'uniku/tsid'
364
-
365
- // Generate a TSID bigint (the primary type, not a string)
366
- const id = tsid()
367
- // => 862301223059968074n
368
-
369
- // Convert to/from the canonical 13-character string
370
- const str = tsid.toString(id)
371
- // => "0QXW2CK4XZM2A"
372
- tsid.fromString(str) === id // true
373
-
374
- // Extract timestamp (milliseconds, full precision)
375
- const ts = tsid.timestamp(id)
376
-
377
- // Convert to/from 8 bytes
378
- const bytes = tsid.toBytes(id)
379
- const restored = tsid.fromBytes(bytes)
380
- ```
381
-
382
- ### XID (time-ordered, rs/xid-compatible)
383
-
384
- ```ts
385
64
  import { xid } from 'uniku/xid'
386
-
387
- const id = xid()
388
- // => "9m4e2mr0ui3e8a215n4g"
389
-
390
- const bytes = xid.toBytes(id)
391
- const restored = xid.fromBytes(bytes)
392
- const timestamp = xid.timestamp(id)
393
- ```
394
-
395
- XID caches a random identity per runtime and uses a shared, always-incrementing counter. Supply `machineId`, `processId`, `secs`, and `counter` for deterministic output.
396
-
397
- ## Migrating to uniku
398
-
399
- ### From `uuid`
400
-
401
- ```diff
402
- - import { v4 as uuidv4 } from 'uuid'
403
- + import { uuidv4 } from 'uniku/uuid/v4'
404
- ```
405
-
406
- ### From `nanoid`
407
-
408
- ```diff
409
- - import { nanoid } from 'nanoid'
410
- + import { nanoid } from 'uniku/nanoid'
411
- ```
412
-
413
- ### From `ulid`
414
-
415
- ```diff
416
- - import { ulid } from 'ulid'
417
- + import { ulid } from 'uniku/ulid'
418
- ```
419
-
420
- ### From `@paralleldrive/cuid2`
421
-
422
- ```diff
423
- - import { createId } from '@paralleldrive/cuid2'
424
- + import { cuid2 } from 'uniku/cuid2'
425
- ```
426
-
427
- ### From `@owpz/ksuid`
428
-
429
- ```diff
430
- - import { KSUID } from '@owpz/ksuid'
431
- + import { ksuid } from 'uniku/ksuid'
432
-
433
- - const id = KSUID.random().toString()
434
- + const id = ksuid()
435
-
436
- - const parsed = KSUID.parse(str)
437
- - const timestamp = parsed.timestamp
438
- + const timestamp = ksuid.timestamp(str)
439
- ```
440
-
441
- ### From `bson`
442
-
443
- ```diff
444
- - import { ObjectId } from 'bson'
445
- + import { objectid } from 'uniku/objectid'
446
-
447
- - const id = new ObjectId().toHexString()
448
- + const id = objectid()
449
-
450
- - const timestamp = new ObjectId(str).getTimestamp().getTime()
451
- + const timestamp = objectid.timestamp(str)
452
- ```
453
-
454
- ## API Reference
455
-
456
- ### `uuidv4` (from `uniku/uuid/v4`)
457
-
458
- ```ts
459
- uuidv4(options?: UuidV4Options): string
460
- uuidv4(options: UuidV4Options | undefined, buf: Uint8Array, offset?: number): Uint8Array
461
- uuidv4.toBytes(id: string): Uint8Array
462
- uuidv4.fromBytes(bytes: Uint8Array): string
463
- uuidv4.isValid(id: unknown): id is string
464
- uuidv4.NIL // "00000000-0000-0000-0000-000000000000"
465
- uuidv4.MAX // "ffffffff-ffff-ffff-ffff-ffffffffffff"
466
- ```
467
-
468
- ### `uuidv7` (from `uniku/uuid/v7`)
469
-
470
- ```ts
471
- uuidv7(options?: UuidV7Options): string
472
- uuidv7(options: UuidV7Options | undefined, buf: Uint8Array, offset?: number): Uint8Array
473
- uuidv7.toBytes(id: string): Uint8Array
474
- uuidv7.fromBytes(bytes: Uint8Array): string
475
- uuidv7.timestamp(id: string): number
476
- uuidv7.isValid(id: unknown): id is string
477
- uuidv7.NIL // "00000000-0000-0000-0000-000000000000"
478
- uuidv7.MAX // "ffffffff-ffff-ffff-ffff-ffffffffffff"
479
- ```
480
-
481
- ### `ulid` (from `uniku/ulid`)
482
-
483
- ```ts
484
- ulid(options?: UlidOptions): string
485
- ulid(options: UlidOptions | undefined, buf: Uint8Array, offset?: number): Uint8Array
486
- ulid.toBytes(id: string): Uint8Array
487
- ulid.fromBytes(bytes: Uint8Array): string
488
- ulid.timestamp(id: string): number
489
- ulid.isValid(id: unknown): id is string
490
- ulid.NIL // "00000000000000000000000000"
491
- ulid.MAX // "7ZZZZZZZZZZZZZZZZZZZZZZZZZ"
492
- ```
493
-
494
- ### `typeid` (from `uniku/typeid`)
495
-
496
- ```ts
497
- typeid(prefix: string, options?: TypeidOptions): string
498
- typeid.toBytes(id: string): Uint8Array
499
- typeid.fromBytes(prefix: string, bytes: Uint8Array): string
500
- typeid.toUuid(id: string): string
501
- typeid.fromUuid(prefix: string, uuid: string): string
502
- typeid.timestamp(id: string): number
503
- typeid.prefix(id: string): string
504
- typeid.suffix(id: string): string
505
- typeid.isValid(id: unknown): id is string
506
- ```
507
-
508
- Use an empty prefix (`typeid('')`) to generate Jetify-compatible prefixless TypeIDs.
509
-
510
- ### `cuidv2` (from `uniku/cuid/v2`)
511
-
512
- ```ts
513
- cuidv2(options?: CuidV2Options): string
514
- cuidv2.isValid(id: unknown): id is string
515
- ```
516
-
517
- > Also available (deprecated) as `cuid2` from `uniku/cuid2` — the same generator
518
- > under the pre-versioned entry point.
519
-
520
- ### `nanoid` (from `uniku/nanoid`)
521
-
522
- ```ts
523
- nanoid(): string
524
- nanoid(size: number): string
525
- nanoid(options: NanoidOptions): string
526
- nanoid.isValid(id: unknown): id is string
527
-
528
- // Constant
529
- URL_ALPHABET // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"
530
- ```
531
-
532
- ### `ksuid` (from `uniku/ksuid`)
533
-
534
- ```ts
535
- ksuid(options?: KsuidOptions): string
536
- ksuid(options: KsuidOptions | undefined, buf: Uint8Array, offset?: number): Uint8Array
537
- ksuid.toBytes(id: string): Uint8Array
538
- ksuid.fromBytes(bytes: Uint8Array): string
539
- ksuid.timestamp(id: string): number
540
- ksuid.isValid(id: unknown): id is string
541
- ksuid.NIL // "000000000000000000000000000"
542
- ksuid.MAX // "aWgEPTl1tmebfsQzFP4bxwgy80V"
543
- ```
544
-
545
- ### `objectid` (from `uniku/objectid`)
546
-
547
- ```ts
548
- objectid(options?: ObjectIdOptions): string
549
- objectid(options: ObjectIdOptions | undefined, buf: Uint8Array, offset?: number): Uint8Array
550
- objectid.toBytes(id: string): Uint8Array
551
- objectid.fromBytes(bytes: Uint8Array): string
552
- objectid.timestamp(id: string): number
553
- objectid.isValid(id: unknown): id is string
554
- objectid.NIL // "000000000000000000000000"
555
- objectid.MAX // "ffffffffffffffffffffffff"
65
+ import { tsid } from 'uniku/tsid'
556
66
  ```
557
67
 
558
- ### `tsid` (from `uniku/tsid`)
68
+ ## Choose an ID
559
69
 
560
- ```ts
561
- tsid(options?: TsidOptions): bigint
562
- tsid(options: TsidOptions | undefined, buf: Uint8Array, offset?: number): Uint8Array
563
- tsid.toBytes(id: bigint): Uint8Array
564
- tsid.fromBytes(bytes: Uint8Array): bigint
565
- tsid.toString(id: bigint): string
566
- tsid.fromString(str: string): bigint
567
- tsid.timestamp(id: bigint, epoch?: number): number
568
- tsid.isValid(id: unknown): id is bigint
569
- tsid.NIL // 0n
570
- tsid.MAX // 18446744073709551615n
571
- ```
70
+ | Situation | Start with | Why |
71
+ | --- | --- | --- |
72
+ | Database primary keys | UUID v7 or ULID | Time-ordered values improve index locality |
73
+ | Public API resources | TypeID | UUID v7 with a readable, domain-specific prefix |
74
+ | Short URLs and invite codes | Nanoid | Compact and URL-safe |
75
+ | Values that should resist enumeration | CUID v2 | Non-sequential and secure |
76
+ | MongoDB `_id` compatibility | ObjectID | Matches MongoDB's 12-byte ObjectID format |
77
+ | Go rs/xid compatibility | XID | Matches rs/xid's text and binary representation |
78
+ | Native `BIGINT` storage | TSID | A sortable 64-bit integer rather than a UUID-shaped string |
79
+ | Broad standards compatibility | UUID v4 | The conventional random UUID format |
572
80
 
573
- > Unlike every other generator listed here, `tsid()` returns `bigint` by default, and `toBytes`/`fromBytes`/`timestamp`/`isValid` all operate on that `bigint`. `toString`/`fromString` are the boundary conversions to/from the 13-character canonical Crockford Base32 string.
574
-
575
- ### `xid` (from `uniku/xid`)
576
-
577
- ```ts
578
- xid(options?: XidOptions): string
579
- xid(options: XidOptions | undefined, buf: Uint8Array, offset?: number): Uint8Array
580
- xid.toBytes(id: string): Uint8Array
581
- xid.fromBytes(bytes: Uint8Array): string
582
- xid.timestamp(id: string): number
583
- xid.isValid(id: unknown): id is string
584
- xid.NIL // "00000000000000000000"
585
- xid.MAX // "vvvvvvvvvvvvvvvvvvvg"
586
- ```
81
+ The [choosing guide](https://jkomyno.github.io/uniku/docs/guides/choosing-an-id/) covers ordering, timestamp leakage, storage boundaries, and format-specific trade-offs.
587
82
 
588
83
  ## Documentation
589
84
 
590
- For advanced usage, examples, and contributing guidelines, see the [full documentation on GitHub](https://github.com/jkomyno/uniku).
591
- The [`uniku@1.x` stability contract](../../docs/STABILITY.md) defines the supported entry points, runtimes, and release gates.
85
+ - [Getting started](https://jkomyno.github.io/uniku/docs/getting-started/) — installation, direct imports, validation, and byte helpers
86
+ - [Generator reference](https://jkomyno.github.io/uniku/docs/reference/entry-points/) — generated from the public TypeScript signatures and JSDoc
87
+ - [Migration guide](https://jkomyno.github.io/uniku/docs/migration/from-other-libraries/) — move from `uuid`, `nanoid`, `ulid`, CUID2, KSUID, BSON, TSID, or XID libraries
88
+ - [Performance and bundle size](https://jkomyno.github.io/uniku/docs/guides/performance/) — benchmark methodology, current measurements, and reproduction commands
89
+ - [Stability contract](https://github.com/jkomyno/uniku/blob/main/docs/STABILITY.md) — the entry points and compatibility policy planned for `uniku@1.0.0`
592
90
 
593
- ## Related Projects
91
+ ## CLI companion
594
92
 
595
- Third-party libraries that inspired this project:
93
+ `@uniku/cli` generates, validates, and inspects IDs from a terminal or shell pipeline. Install the current standalone binary:
596
94
 
597
- - [uuid](https://github.com/uuidjs/uuid): the most popular UUID library for JavaScript
598
- - [ulid](https://github.com/ulid/javascript): the reference ULID implementation for JavaScript
599
- - [TypeID-JS](https://github.com/jetify-com/typeid-js): official JavaScript implementation of TypeID
600
- - [@paralleldrive/cuid2](https://github.com/paralleldrive/cuid2): secure, collision-resistant IDs
601
- - [@owpz/ksuid](https://github.com/owpz/ksuid): K-Sortable Unique Identifier
602
- - [bson](https://github.com/mongodb/js-bson): official MongoDB BSON library, including the ObjectId implementation
603
- - [nanoid](https://github.com/ai/nanoid): tiny, URL-friendly unique string ID generator
604
- - [tsid-ts](https://github.com/yubinTW/tsid-ts): TypeScript implementation of TSID, a Snowflake-style 64-bit Time-Sorted Unique Identifier
95
+ ```sh
96
+ curl -fsSL https://raw.githubusercontent.com/jkomyno/uniku/main/install.sh | sh
605
97
 
606
- Other:
607
-
608
- - [pnpm-monorepo-template](https://github.com/jkomyno/pnpm-monorepo-template): the template I used to create this library
98
+ uniku uuid -v 7
99
+ uniku validate 018e5e5c-7c8a-7000-8000-000000000000
100
+ uniku inspect 018e5e5c-7c8a-7000-8000-000000000000
101
+ ```
609
102
 
610
- ## Author
103
+ See the [CLI documentation](https://jkomyno.github.io/uniku/docs/cli/) for package-manager installs and the complete command reference.
611
104
 
612
- Hi, I'm Alberto Schiabel, aka @jkomyno. You can follow me on:
105
+ ## Contributing
613
106
 
614
- - Github: [@jkomyno](https://github.com/jkomyno)
615
- - X: [@jkomyno](https://x.com/jkomyno)
107
+ See [CONTRIBUTING.md](https://github.com/jkomyno/uniku/blob/main/CONTRIBUTING.md) for the development workflow, tests, benchmarks, and preview releases.
616
108
 
617
109
  ## License
618
110
 
619
- MIT — see [LICENSE](https://github.com/jkomyno/uniku/blob/main/LICENSE)
111
+ MIT © [Alberto Schiabel](https://github.com/jkomyno)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "uniku",
4
- "version": "0.4.1",
4
+ "version": "0.4.2",
5
5
  "description": "Minimal, tree-shakeable unique ID generators for every JavaScript runtime",
6
6
  "author": {
7
7
  "name": "Alberto Schiabel",
@@ -14,7 +14,7 @@
14
14
  "url": "git+https://github.com/jkomyno/uniku.git",
15
15
  "directory": "packages/uniku"
16
16
  },
17
- "homepage": "https://github.com/jkomyno/uniku#readme",
17
+ "homepage": "https://jkomyno.github.io/uniku/",
18
18
  "bugs": {
19
19
  "url": "https://github.com/jkomyno/uniku/issues"
20
20
  },