uniku 0.0.3 → 0.0.4
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.
- package/README.md +38 -0
- package/build/nanoid/nanoid.d.mts +39 -0
- package/build/nanoid/nanoid.d.mts.map +1 -0
- package/build/nanoid/nanoid.mjs +73 -0
- package/build/nanoid/nanoid.mjs.map +1 -0
- package/build/{random-kKYJ4YeW.mjs → random-Dul5R6oJ.mjs} +1 -1
- package/build/{random-kKYJ4YeW.mjs.map → random-Dul5R6oJ.mjs.map} +1 -1
- package/build/ulid/ulid.mjs +1 -1
- package/build/uuid/v4.mjs +2 -2
- package/build/uuid/v7.mjs +2 -2
- package/build/{uuid-DWH0cHB2.mjs → uuid-cJ5hOOIR.mjs} +1 -1
- package/build/{uuid-DWH0cHB2.mjs.map → uuid-cJ5hOOIR.mjs.map} +1 -1
- package/package.json +10 -1
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ Minimal, tree-shakeable UUID and ULID utilities for every JavaScript runtime.
|
|
|
24
24
|
- UUID v7 ([RFC 9562](../../rfcs/rfc9562.txt), time-ordered, monotonic sequencing)
|
|
25
25
|
- ULID ([spec](../../rfcs/ulid.txt), time-ordered, monotonic sequencing)
|
|
26
26
|
- CUID2 ([spec](../../rfcs/cuid2.txt), secure, non-time-ordered)
|
|
27
|
+
- Nanoid ([spec](../../rfcs/nanoid.txt), URL-friendly, custom alphabet support)
|
|
27
28
|
|
|
28
29
|
## Installation
|
|
29
30
|
|
|
@@ -105,6 +106,27 @@ if (cuid2.isValid(maybeId)) {
|
|
|
105
106
|
}
|
|
106
107
|
```
|
|
107
108
|
|
|
109
|
+
### Nanoid (URL-friendly, custom alphabet)
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { nanoid } from 'uniku/nanoid'
|
|
113
|
+
|
|
114
|
+
const id = nanoid()
|
|
115
|
+
// => "V1StGXR8_Z5jdHi6B-myT"
|
|
116
|
+
|
|
117
|
+
// Custom size
|
|
118
|
+
const shortId = nanoid(10)
|
|
119
|
+
// => "IRFa-VaY2b"
|
|
120
|
+
|
|
121
|
+
// Custom alphabet and size via options
|
|
122
|
+
const hexId = nanoid({ alphabet: '0123456789abcdef', size: 12 })
|
|
123
|
+
// => "4f90d13a42bc"
|
|
124
|
+
|
|
125
|
+
// Validation (default alphabet only)
|
|
126
|
+
nanoid.isValid(id)
|
|
127
|
+
// => true
|
|
128
|
+
```
|
|
129
|
+
|
|
108
130
|
## API Reference
|
|
109
131
|
|
|
110
132
|
### `uuidv4` (from `uniku/uuid/v4`)
|
|
@@ -166,6 +188,22 @@ cuid2.isValid(id: unknown): id is string
|
|
|
166
188
|
|
|
167
189
|
Note: Unlike UUID and ULID, CUID2 does not provide `toBytes`/`fromBytes` because it is a string-native format with no canonical binary representation.
|
|
168
190
|
|
|
191
|
+
### `nanoid` (from `uniku/nanoid`)
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
nanoid(): string
|
|
195
|
+
nanoid(size: number): string
|
|
196
|
+
nanoid(options: NanoidOptions): string
|
|
197
|
+
nanoid.isValid(id: unknown): id is string
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Options:**
|
|
201
|
+
- `size?: number` - ID length (default 21, max 2048)
|
|
202
|
+
- `alphabet?: string` - Custom alphabet (2-256 printable ASCII characters)
|
|
203
|
+
- `random?: Uint8Array` - Custom random bytes for testing
|
|
204
|
+
|
|
205
|
+
Note: `isValid()` only validates IDs against the default URL-safe alphabet (`A-Za-z0-9_-`). IDs generated with custom alphabets cannot be validated with this method.
|
|
206
|
+
|
|
169
207
|
## Documentation
|
|
170
208
|
|
|
171
209
|
For advanced usage, examples, and contributing guidelines, see the [full documentation on GitHub](https://github.com/jkomyno/uniku).
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//#region src/nanoid/nanoid.d.ts
|
|
2
|
+
/** Default URL-safe alphabet (64 characters): A-Z, a-z, 0-9, underscore, hyphen */
|
|
3
|
+
declare const URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
|
|
4
|
+
type NanoidOptions = {
|
|
5
|
+
/**
|
|
6
|
+
* Random bytes for deterministic output (testing).
|
|
7
|
+
* Must provide enough bytes for rejection sampling (~size * 2).
|
|
8
|
+
*/
|
|
9
|
+
random?: Uint8Array;
|
|
10
|
+
/**
|
|
11
|
+
* Custom alphabet to use. Default: URL-safe A-Za-z0-9_-
|
|
12
|
+
* Must be 2-256 printable ASCII characters (32-126) with no duplicates.
|
|
13
|
+
*/
|
|
14
|
+
alphabet?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Length of generated ID. Default: 21. Maximum: 2048.
|
|
17
|
+
*/
|
|
18
|
+
size?: number;
|
|
19
|
+
};
|
|
20
|
+
type Nanoid = {
|
|
21
|
+
/** Generate nanoid with default settings */
|
|
22
|
+
(): string;
|
|
23
|
+
/** Generate nanoid with custom size */
|
|
24
|
+
(size: number): string;
|
|
25
|
+
/** Generate nanoid with options */
|
|
26
|
+
(options: NanoidOptions): string;
|
|
27
|
+
/**
|
|
28
|
+
* Validate a nanoid string against the default URL-safe alphabet.
|
|
29
|
+
* Note: Does not validate IDs generated with custom alphabets.
|
|
30
|
+
*/
|
|
31
|
+
isValid(id: unknown): id is string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Generate a URL-friendly unique string ID.
|
|
35
|
+
*/
|
|
36
|
+
declare const nanoid: Nanoid;
|
|
37
|
+
//#endregion
|
|
38
|
+
export { Nanoid, NanoidOptions, URL_ALPHABET, nanoid };
|
|
39
|
+
//# sourceMappingURL=nanoid.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nanoid.d.mts","names":["nanoid: Nanoid"],"sources":["../../src/nanoid/nanoid.ts"],"sourcesContent":[],"mappings":";;AACa,cAAA,YAAA,GAAA,kEAAA;AAMD,KAAA,aAAA,GAAA;EAiBZ;AAsHA;;;WAlIW;;;;;;;;;;;KAYC,MAAA;;;;;;YAMA;;;;;;;;;;cAgHCA,QAAQ"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
//#region src/nanoid/nanoid.ts
|
|
2
|
+
/** Default URL-safe alphabet (64 characters): A-Z, a-z, 0-9, underscore, hyphen */
|
|
3
|
+
const URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
|
|
4
|
+
const DEFAULT_SIZE = 21;
|
|
5
|
+
const MAX_SIZE = 2048;
|
|
6
|
+
const NANOID_REGEX = /^[A-Za-z0-9_-]+$/;
|
|
7
|
+
/**
|
|
8
|
+
* Validate alphabet: 2-256 printable ASCII chars, no duplicates
|
|
9
|
+
*/
|
|
10
|
+
function validateAlphabet(alphabet) {
|
|
11
|
+
if (alphabet.length < 2) throw new Error("Alphabet must contain at least 2 characters");
|
|
12
|
+
if (alphabet.length > 256) throw new Error("Alphabet must not exceed 256 characters");
|
|
13
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14
|
+
for (const char of alphabet) {
|
|
15
|
+
const code = char.charCodeAt(0);
|
|
16
|
+
if (code < 32 || code > 126) throw new Error("Alphabet must contain only printable ASCII characters (32-126)");
|
|
17
|
+
if (seen.has(char)) throw new Error(`Duplicate character in alphabet: "${char}"`);
|
|
18
|
+
seen.add(char);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Validate size parameter
|
|
23
|
+
*/
|
|
24
|
+
function validateSize(size) {
|
|
25
|
+
if (!Number.isInteger(size) || size < 0) throw new RangeError("Size must be a non-negative integer");
|
|
26
|
+
if (size > MAX_SIZE) throw new RangeError(`Size must not exceed ${MAX_SIZE}`);
|
|
27
|
+
}
|
|
28
|
+
function nanoidFn(sizeOrOptions) {
|
|
29
|
+
let size = DEFAULT_SIZE;
|
|
30
|
+
let alphabet = URL_ALPHABET;
|
|
31
|
+
let randomBytes;
|
|
32
|
+
if (typeof sizeOrOptions === "number") size = sizeOrOptions;
|
|
33
|
+
else if (sizeOrOptions) {
|
|
34
|
+
size = sizeOrOptions.size ?? DEFAULT_SIZE;
|
|
35
|
+
alphabet = sizeOrOptions.alphabet ?? URL_ALPHABET;
|
|
36
|
+
randomBytes = sizeOrOptions.random;
|
|
37
|
+
if (sizeOrOptions.alphabet) validateAlphabet(alphabet);
|
|
38
|
+
}
|
|
39
|
+
validateSize(size);
|
|
40
|
+
if (size === 0) return "";
|
|
41
|
+
const mask = (2 << 31 - Math.clz32(alphabet.length - 1 | 1)) - 1;
|
|
42
|
+
const step = Math.ceil(1.6 * mask * size / alphabet.length);
|
|
43
|
+
let id = "";
|
|
44
|
+
let randomOffset = 0;
|
|
45
|
+
while (id.length < size) {
|
|
46
|
+
let bytes;
|
|
47
|
+
if (randomBytes) {
|
|
48
|
+
if (randomBytes.length - randomOffset < step) throw new Error(`Insufficient random bytes: need at least ${step} more, have ${randomBytes.length - randomOffset}`);
|
|
49
|
+
bytes = randomBytes.subarray(randomOffset, randomOffset + step);
|
|
50
|
+
randomOffset += step;
|
|
51
|
+
} else bytes = globalThis.crypto.getRandomValues(new Uint8Array(step));
|
|
52
|
+
for (let i = 0; i < bytes.length && id.length < size; i++) {
|
|
53
|
+
const index = bytes[i] & mask;
|
|
54
|
+
if (index < alphabet.length) id += alphabet[index];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return id;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Validate a nanoid string against the default URL-safe alphabet.
|
|
61
|
+
* Note: Does not validate IDs generated with custom alphabets.
|
|
62
|
+
*/
|
|
63
|
+
function isValid(id) {
|
|
64
|
+
return typeof id === "string" && id.length > 0 && NANOID_REGEX.test(id);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Generate a URL-friendly unique string ID.
|
|
68
|
+
*/
|
|
69
|
+
const nanoid = Object.assign(nanoidFn, { isValid });
|
|
70
|
+
|
|
71
|
+
//#endregion
|
|
72
|
+
export { URL_ALPHABET, nanoid };
|
|
73
|
+
//# sourceMappingURL=nanoid.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nanoid.mjs","names":["randomBytes: Uint8Array | undefined","bytes: Uint8Array","nanoid: Nanoid"],"sources":["../../src/nanoid/nanoid.ts"],"sourcesContent":["/** Default URL-safe alphabet (64 characters): A-Z, a-z, 0-9, underscore, hyphen */\nexport const URL_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-'\n\nconst DEFAULT_SIZE = 21\nconst MAX_SIZE = 2048\nconst NANOID_REGEX = /^[A-Za-z0-9_-]+$/\n\nexport type NanoidOptions = {\n /**\n * Random bytes for deterministic output (testing).\n * Must provide enough bytes for rejection sampling (~size * 2).\n */\n random?: Uint8Array\n /**\n * Custom alphabet to use. Default: URL-safe A-Za-z0-9_-\n * Must be 2-256 printable ASCII characters (32-126) with no duplicates.\n */\n alphabet?: string\n /**\n * Length of generated ID. Default: 21. Maximum: 2048.\n */\n size?: number\n}\n\nexport type Nanoid = {\n /** Generate nanoid with default settings */\n (): string\n /** Generate nanoid with custom size */\n (size: number): string\n /** Generate nanoid with options */\n (options: NanoidOptions): string\n /**\n * Validate a nanoid string against the default URL-safe alphabet.\n * Note: Does not validate IDs generated with custom alphabets.\n */\n isValid(id: unknown): id is string\n}\n\n/**\n * Validate alphabet: 2-256 printable ASCII chars, no duplicates\n */\nfunction validateAlphabet(alphabet: string): void {\n if (alphabet.length < 2) {\n throw new Error('Alphabet must contain at least 2 characters')\n }\n if (alphabet.length > 256) {\n throw new Error('Alphabet must not exceed 256 characters')\n }\n const seen = new Set<string>()\n for (const char of alphabet) {\n const code = char.charCodeAt(0)\n if (code < 32 || code > 126) {\n throw new Error('Alphabet must contain only printable ASCII characters (32-126)')\n }\n if (seen.has(char)) {\n throw new Error(`Duplicate character in alphabet: \"${char}\"`)\n }\n seen.add(char)\n }\n}\n\n/**\n * Validate size parameter\n */\nfunction validateSize(size: number): void {\n if (!Number.isInteger(size) || size < 0) {\n throw new RangeError('Size must be a non-negative integer')\n }\n if (size > MAX_SIZE) {\n throw new RangeError(`Size must not exceed ${MAX_SIZE}`)\n }\n}\n\n// Overloads\nfunction nanoidFn(): string\nfunction nanoidFn(size: number): string\nfunction nanoidFn(options: NanoidOptions): string\nfunction nanoidFn(sizeOrOptions?: number | NanoidOptions): string {\n let size = DEFAULT_SIZE\n let alphabet = URL_ALPHABET\n let randomBytes: Uint8Array | undefined\n\n if (typeof sizeOrOptions === 'number') {\n size = sizeOrOptions\n } else if (sizeOrOptions) {\n size = sizeOrOptions.size ?? DEFAULT_SIZE\n alphabet = sizeOrOptions.alphabet ?? URL_ALPHABET\n randomBytes = sizeOrOptions.random\n if (sizeOrOptions.alphabet) {\n validateAlphabet(alphabet)\n }\n }\n\n validateSize(size)\n\n if (size === 0) return ''\n\n // Calculate mask: smallest power-of-2 minus 1 that covers alphabet size\n const mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1\n // Calculate step: random bytes per batch (1.6x accounts for rejection)\n const step = Math.ceil((1.6 * mask * size) / alphabet.length)\n\n let id = ''\n let randomOffset = 0\n\n while (id.length < size) {\n let bytes: Uint8Array\n if (randomBytes) {\n if (randomBytes.length - randomOffset < step) {\n throw new Error(\n `Insufficient random bytes: need at least ${step} more, have ${randomBytes.length - randomOffset}`,\n )\n }\n bytes = randomBytes.subarray(randomOffset, randomOffset + step)\n randomOffset += step\n } else {\n bytes = globalThis.crypto.getRandomValues(new Uint8Array(step))\n }\n\n for (let i = 0; i < bytes.length && id.length < size; i++) {\n const index = bytes[i] & mask\n if (index < alphabet.length) {\n id += alphabet[index]\n }\n // Otherwise reject and continue (no modulo bias)\n }\n }\n\n return id\n}\n\n/**\n * Validate a nanoid string against the default URL-safe alphabet.\n * Note: Does not validate IDs generated with custom alphabets.\n */\nfunction isValid(id: unknown): id is string {\n return typeof id === 'string' && id.length > 0 && NANOID_REGEX.test(id)\n}\n\n/**\n * Generate a URL-friendly unique string ID.\n */\nexport const nanoid: Nanoid = Object.assign(nanoidFn, {\n isValid,\n})\n"],"mappings":";;AACA,MAAa,eAAe;AAE5B,MAAM,eAAe;AACrB,MAAM,WAAW;AACjB,MAAM,eAAe;;;;AAoCrB,SAAS,iBAAiB,UAAwB;AAChD,KAAI,SAAS,SAAS,EACpB,OAAM,IAAI,MAAM,8CAA8C;AAEhE,KAAI,SAAS,SAAS,IACpB,OAAM,IAAI,MAAM,0CAA0C;CAE5D,MAAM,uBAAO,IAAI,KAAa;AAC9B,MAAK,MAAM,QAAQ,UAAU;EAC3B,MAAM,OAAO,KAAK,WAAW,EAAE;AAC/B,MAAI,OAAO,MAAM,OAAO,IACtB,OAAM,IAAI,MAAM,iEAAiE;AAEnF,MAAI,KAAK,IAAI,KAAK,CAChB,OAAM,IAAI,MAAM,qCAAqC,KAAK,GAAG;AAE/D,OAAK,IAAI,KAAK;;;;;;AAOlB,SAAS,aAAa,MAAoB;AACxC,KAAI,CAAC,OAAO,UAAU,KAAK,IAAI,OAAO,EACpC,OAAM,IAAI,WAAW,sCAAsC;AAE7D,KAAI,OAAO,SACT,OAAM,IAAI,WAAW,wBAAwB,WAAW;;AAQ5D,SAAS,SAAS,eAAgD;CAChE,IAAI,OAAO;CACX,IAAI,WAAW;CACf,IAAIA;AAEJ,KAAI,OAAO,kBAAkB,SAC3B,QAAO;UACE,eAAe;AACxB,SAAO,cAAc,QAAQ;AAC7B,aAAW,cAAc,YAAY;AACrC,gBAAc,cAAc;AAC5B,MAAI,cAAc,SAChB,kBAAiB,SAAS;;AAI9B,cAAa,KAAK;AAElB,KAAI,SAAS,EAAG,QAAO;CAGvB,MAAM,QAAQ,KAAM,KAAK,KAAK,MAAO,SAAS,SAAS,IAAK,EAAE,IAAK;CAEnE,MAAM,OAAO,KAAK,KAAM,MAAM,OAAO,OAAQ,SAAS,OAAO;CAE7D,IAAI,KAAK;CACT,IAAI,eAAe;AAEnB,QAAO,GAAG,SAAS,MAAM;EACvB,IAAIC;AACJ,MAAI,aAAa;AACf,OAAI,YAAY,SAAS,eAAe,KACtC,OAAM,IAAI,MACR,4CAA4C,KAAK,cAAc,YAAY,SAAS,eACrF;AAEH,WAAQ,YAAY,SAAS,cAAc,eAAe,KAAK;AAC/D,mBAAgB;QAEhB,SAAQ,WAAW,OAAO,gBAAgB,IAAI,WAAW,KAAK,CAAC;AAGjE,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,UAAU,GAAG,SAAS,MAAM,KAAK;GACzD,MAAM,QAAQ,MAAM,KAAK;AACzB,OAAI,QAAQ,SAAS,OACnB,OAAM,SAAS;;;AAMrB,QAAO;;;;;;AAOT,SAAS,QAAQ,IAA2B;AAC1C,QAAO,OAAO,OAAO,YAAY,GAAG,SAAS,KAAK,aAAa,KAAK,GAAG;;;;;AAMzE,MAAaC,SAAiB,OAAO,OAAO,UAAU,EACpD,SACD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"random-
|
|
1
|
+
{"version":3,"file":"random-Dul5R6oJ.mjs","names":[],"sources":["../src/uuid/common/random.ts"],"sourcesContent":["export function randomBytes(out: Uint8Array): void {\n const crypto = globalThis.crypto\n crypto.getRandomValues(out)\n}\n\n/**\n * Generate 16 bytes of cryptographically strong random data.\n * Used internally by UUID generators.\n */\nexport function rng(): Uint8Array {\n const bytes = new Uint8Array(16)\n randomBytes(bytes)\n return bytes\n}\n"],"mappings":";AAAA,SAAgB,YAAY,KAAuB;AAEjD,CADe,WAAW,OACnB,gBAAgB,IAAI;;;;;;AAO7B,SAAgB,MAAkB;CAChC,MAAM,QAAQ,IAAI,WAAW,GAAG;AAChC,aAAY,MAAM;AAClB,QAAO"}
|
package/build/ulid/ulid.mjs
CHANGED
package/build/uuid/v4.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as rng } from "../random-
|
|
2
|
-
import { n as parseUuid, t as formatUuid } from "../uuid-
|
|
1
|
+
import { t as rng } from "../random-Dul5R6oJ.mjs";
|
|
2
|
+
import { n as parseUuid, t as formatUuid } from "../uuid-cJ5hOOIR.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/uuid/v4.ts
|
|
5
5
|
const UUID_V4_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
package/build/uuid/v7.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as rng } from "../random-
|
|
2
|
-
import { n as parseUuid, t as formatUuid } from "../uuid-
|
|
1
|
+
import { t as rng } from "../random-Dul5R6oJ.mjs";
|
|
2
|
+
import { n as parseUuid, t as formatUuid } from "../uuid-cJ5hOOIR.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/uuid/v7.ts
|
|
5
5
|
const UUID_V7_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uuid-
|
|
1
|
+
{"version":3,"file":"uuid-cJ5hOOIR.mjs","names":[],"sources":["../src/uuid/common/hex.ts","../src/uuid/common/uuid.ts"],"sourcesContent":["// Pre-computed lookup table for byte-to-hex conversion (0x00 -> \"00\", 0xff -> \"ff\")\nconst HEX_TABLE = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'))\n\nexport function bytesToHex(bytes: Uint8Array): string {\n // Build string directly, without intermediate array allocation\n let hex = ''\n for (let i = 0; i < bytes.length; i += 1) {\n hex += HEX_TABLE[bytes[i]]\n }\n return hex\n}\n\n// ASCII code ranges for hex character validation\nconst ASCII_0 = 48 // '0'\nconst ASCII_9 = 57 // '9'\nconst ASCII_A = 65 // 'A'\nconst ASCII_F = 70 // 'F'\nconst ASCII_a = 97 // 'a'\nconst ASCII_f = 102 // 'f'\n\nfunction hexValue(code: number): number {\n if (code >= ASCII_0 && code <= ASCII_9) {\n return code - ASCII_0\n }\n if (code >= ASCII_A && code <= ASCII_F) {\n return code - ASCII_A + 10\n }\n if (code >= ASCII_a && code <= ASCII_f) {\n return code - ASCII_a + 10\n }\n return -1 // Invalid hex character\n}\n\nexport function hexToBytes(hex: string, out: Uint8Array): void {\n if (hex.length !== out.length * 2) {\n throw new Error(`hex string must be ${out.length * 2} chars, got ${hex.length}`)\n }\n\n for (let i = 0; i < out.length; i += 1) {\n const hi = hexValue(hex.charCodeAt(i * 2))\n const lo = hexValue(hex.charCodeAt(i * 2 + 1))\n if (hi === -1 || lo === -1) {\n throw new Error('hex string contains invalid characters')\n }\n out[i] = (hi << 4) | lo\n }\n}\n","import { bytesToHex, hexToBytes } from './hex'\n\nconst UUID_BYTE_LENGTH = 16\nconst UUID_STRING_LENGTH = 36\n\nexport function formatUuid(bytes: Uint8Array): string {\n // precondition: bytes.length === UUID_BYTE_LENGTH\n const hex = bytesToHex(bytes)\n\n // Build UUID string with dashes at positions 8, 13, 18, 23\n // Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n}\n\nexport function parseUuid(value: string): Uint8Array {\n if (value.length !== UUID_STRING_LENGTH) {\n throw new Error('uuid string must be 36 characters')\n }\n\n // Validate separator positions directly (more efficient than full loop)\n if (value[8] !== '-' || value[13] !== '-' || value[18] !== '-' || value[23] !== '-') {\n throw new Error('uuid string has invalid separators')\n }\n\n const hex = value.slice(0, 8) + value.slice(9, 13) + value.slice(14, 18) + value.slice(19, 23) + value.slice(24)\n\n const bytes = new Uint8Array(UUID_BYTE_LENGTH)\n hexToBytes(hex, bytes)\n return bytes\n}\n"],"mappings":";AACA,MAAM,YAAY,MAAM,KAAK,EAAE,QAAQ,KAAK,GAAG,GAAG,MAAM,EAAE,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC;AAExF,SAAgB,WAAW,OAA2B;CAEpD,IAAI,MAAM;AACV,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,EACrC,QAAO,UAAU,MAAM;AAEzB,QAAO;;AAIT,MAAM,UAAU;AAChB,MAAM,UAAU;AAChB,MAAM,UAAU;AAChB,MAAM,UAAU;AAChB,MAAM,UAAU;AAChB,MAAM,UAAU;AAEhB,SAAS,SAAS,MAAsB;AACtC,KAAI,QAAQ,WAAW,QAAQ,QAC7B,QAAO,OAAO;AAEhB,KAAI,QAAQ,WAAW,QAAQ,QAC7B,QAAO,OAAO,UAAU;AAE1B,KAAI,QAAQ,WAAW,QAAQ,QAC7B,QAAO,OAAO,UAAU;AAE1B,QAAO;;AAGT,SAAgB,WAAW,KAAa,KAAuB;AAC7D,KAAI,IAAI,WAAW,IAAI,SAAS,EAC9B,OAAM,IAAI,MAAM,sBAAsB,IAAI,SAAS,EAAE,cAAc,IAAI,SAAS;AAGlF,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK,GAAG;EACtC,MAAM,KAAK,SAAS,IAAI,WAAW,IAAI,EAAE,CAAC;EAC1C,MAAM,KAAK,SAAS,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;AAC9C,MAAI,OAAO,MAAM,OAAO,GACtB,OAAM,IAAI,MAAM,yCAAyC;AAE3D,MAAI,KAAM,MAAM,IAAK;;;;;;AC1CzB,MAAM,mBAAmB;AACzB,MAAM,qBAAqB;AAE3B,SAAgB,WAAW,OAA2B;CAEpD,MAAM,MAAM,WAAW,MAAM;AAI7B,QAAO,GAAG,IAAI,MAAM,GAAG,EAAE,CAAC,GAAG,IAAI,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,MAAM,GAAG;;AAG1G,SAAgB,UAAU,OAA2B;AACnD,KAAI,MAAM,WAAW,mBACnB,OAAM,IAAI,MAAM,oCAAoC;AAItD,KAAI,MAAM,OAAO,OAAO,MAAM,QAAQ,OAAO,MAAM,QAAQ,OAAO,MAAM,QAAQ,IAC9E,OAAM,IAAI,MAAM,qCAAqC;CAGvD,MAAM,MAAM,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,MAAM,GAAG,GAAG,GAAG,MAAM,MAAM,IAAI,GAAG,GAAG,MAAM,MAAM,IAAI,GAAG,GAAG,MAAM,MAAM,GAAG;CAEhH,MAAM,QAAQ,IAAI,WAAW,iBAAiB;AAC9C,YAAW,KAAK,MAAM;AACtB,QAAO"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"private": false,
|
|
3
3
|
"name": "uniku",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.4",
|
|
5
5
|
"description": "Minimal, tree-shakeable UUID utilities for every JavaScript runtime",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Alberto Schiabel",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"uuidv7",
|
|
25
25
|
"ulid",
|
|
26
26
|
"cuid2",
|
|
27
|
+
"nanoid",
|
|
27
28
|
"unique",
|
|
28
29
|
"id",
|
|
29
30
|
"identifier",
|
|
@@ -84,6 +85,14 @@
|
|
|
84
85
|
},
|
|
85
86
|
"default": "./build/cuid2/cuid2.mjs"
|
|
86
87
|
},
|
|
88
|
+
"./nanoid": {
|
|
89
|
+
"types": "./build/nanoid/nanoid.d.mts",
|
|
90
|
+
"import": {
|
|
91
|
+
"@jkomyno/source": "./src/nanoid/nanoid.ts",
|
|
92
|
+
"default": "./build/nanoid/nanoid.mjs"
|
|
93
|
+
},
|
|
94
|
+
"default": "./build/nanoid/nanoid.mjs"
|
|
95
|
+
},
|
|
87
96
|
"./package.json": "./package.json"
|
|
88
97
|
},
|
|
89
98
|
"dependencies": {
|