@lacspace/id 1.0.0 → 1.0.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.
package/README.md CHANGED
@@ -50,18 +50,24 @@ Why v7? Because random UUIDs (v4) scatter across a database index, hurting inser
50
50
 
51
51
  ## Licensing
52
52
 
53
- This package is **free** under the **[Lacspace Free Licence](https://lacspace.com/licenses/lacspace-free-1.0)** — MIT-equivalent freedoms. Use it in personal and commercial projects at no cost; just keep the notice.
53
+ This package is **free** under the **[Lacspace Free Licence](https://lacspace.com/licenses/lacspace-free-1.0)** — permissive freedoms. Use it in personal and commercial projects at no cost; just keep the notice.
54
54
 
55
55
  Not every Lacspace package is free. We also offer **Commercial**, **Client-specific** and **Private** packages under separate terms — see the **[Lacspace Licence Centre](https://lacspace.com/licenses)**.
56
56
 
57
+ <!-- LACSPACE-DEV-PLATFORM -->
58
+
57
59
  ---
58
60
 
59
- <div align="center">
61
+ ## The Lacspace Developer Platform
60
62
 
61
- **Part of the Lacspace ecosystem zero-dependency, isomorphic TypeScript packages.**
63
+ `@lacspace/id` is part of **63 zero-dependency, isomorphic TypeScript packages** — one standard library for the modern web. Explore the ecosystem:
62
64
 
63
- [All packages ↗](https://lacspace.com/packages) · [npm org ↗](https://www.npmjs.com/org/lacspace) · [Licence Centre ↗](https://lacspace.com/licenses) · [GitHub ↗](https://github.com/lacspace/npm-packages)
65
+ - 📦 **This package, documented** https://developer.lacspace.com/packages/id
66
+ - 🗂️ **All 63 packages** — https://developer.lacspace.com/packages
67
+ - 🧭 **Developer handbook** — guides & runnable recipes — https://developer.lacspace.com/handbook
68
+ - 🧪 **Live playground** — run any package in your browser — https://developer.lacspace.com/playground
69
+ - 🖥️ **Finished app templates** — https://templates.lacspace.com
70
+ - 🚀 **Scaffold a full app** — `npm create lacspace-app@latest`
64
71
 
65
- </div>
72
+ Free under the **[Lacspace Free Licence](https://lacspace.com/licenses/lacspace-free-1.0)** — a permissive, free-to-use licence.
66
73
 
67
- <div align="center"><sub>Built with care by <a href="https://lacspace.com">Lacspace</a> · Lacspace Free Licence · <a href="https://github.com/lacspace/npm-packages">source</a></sub></div>
package/dist/index.cjs CHANGED
@@ -23,9 +23,15 @@ function uuidv4() {
23
23
  var lastV7Time = 0;
24
24
  var v7Counter = 0;
25
25
  function uuidv7(now) {
26
- const time = now ?? Date.now();
27
- if (time === lastV7Time) v7Counter++;
28
- else {
26
+ let time = now ?? Date.now();
27
+ if (time === lastV7Time) {
28
+ v7Counter++;
29
+ if (v7Counter > 4095) {
30
+ time = lastV7Time + 1;
31
+ lastV7Time = time;
32
+ v7Counter = 0;
33
+ }
34
+ } else {
29
35
  lastV7Time = time;
30
36
  v7Counter = 0;
31
37
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["id"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @lacspace/id\n *\n * Unique IDs done right — UUID v4, **UUID v7** (time-sortable), Nano-ID-style\n * and short URL-safe codes. Cryptographically random (Web Crypto), monotonic\n * v7 within the same millisecond, zero-dependency and isomorphic.\n */\n\nfunction getRandom(bytes: Uint8Array): Uint8Array {\n const c = (globalThis as { crypto?: Crypto }).crypto;\n if (!c || typeof c.getRandomValues !== \"function\") {\n throw new Error(\"Web Crypto getRandomValues is unavailable in this environment.\");\n }\n c.getRandomValues(bytes);\n return bytes;\n}\n\nconst HEX: string[] = [];\nfor (let i = 0; i < 256; i++) HEX.push((i + 0x100).toString(16).slice(1));\n\nfunction bytesToUuid(b: Uint8Array): string {\n return (\n HEX[b[0]!]! + HEX[b[1]!]! + HEX[b[2]!]! + HEX[b[3]!]! + \"-\" +\n HEX[b[4]!]! + HEX[b[5]!]! + \"-\" +\n HEX[b[6]!]! + HEX[b[7]!]! + \"-\" +\n HEX[b[8]!]! + HEX[b[9]!]! + \"-\" +\n HEX[b[10]!]! + HEX[b[11]!]! + HEX[b[12]!]! + HEX[b[13]!]! + HEX[b[14]!]! + HEX[b[15]!]!\n );\n}\n\n/** RFC 4122 UUID v4 (random). */\nexport function uuidv4(): string {\n const b = getRandom(new Uint8Array(16));\n b[6] = (b[6]! & 0x0f) | 0x40; // version 4\n b[8] = (b[8]! & 0x3f) | 0x80; // variant\n return bytesToUuid(b);\n}\n\nlet lastV7Time = 0;\nlet v7Counter = 0;\n\n/**\n * UUID v7 — a time-sortable UUID (48-bit Unix-ms timestamp + randomness).\n * Great as a primary key: lexicographically sortable by creation time, index-\n * friendly, still globally unique. Monotonic within the same millisecond.\n */\nexport function uuidv7(now?: number): string {\n const time = now ?? Date.now();\n if (time === lastV7Time) v7Counter++;\n else { lastV7Time = time; v7Counter = 0; }\n\n const b = getRandom(new Uint8Array(16));\n // 48-bit timestamp (big-endian) in bytes 0..5\n b[0] = (time / 2 ** 40) & 0xff;\n b[1] = (time / 2 ** 32) & 0xff;\n b[2] = (time / 2 ** 24) & 0xff;\n b[3] = (time / 2 ** 16) & 0xff;\n b[4] = (time / 2 ** 8) & 0xff;\n b[5] = time & 0xff;\n // rand_a (12 bits) holds a monotonic counter so same-ms ids stay sortable\n b[6] = 0x70 | ((v7Counter >> 8) & 0x0f); // version 7 + counter high nibble\n b[7] = v7Counter & 0xff; // counter low byte\n b[8] = (b[8]! & 0x3f) | 0x80; // variant\n return bytesToUuid(b);\n}\n\n/** Extract the timestamp (ms) embedded in a UUID v7. */\nexport function uuidv7Time(uuid: string): number {\n const hex = uuid.replace(/-/g, \"\").slice(0, 12);\n return parseInt(hex, 16);\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n/** Is this a well-formed UUID? */\nexport function isUuid(s: string): boolean {\n return UUID_RE.test(s);\n}\n\n/** UUID version digit (1–8), or null if not a UUID. */\nexport function uuidVersion(s: string): number | null {\n return isUuid(s) ? parseInt(s[14]!, 16) : null;\n}\n\nconst NANO_ALPHABET = \"useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict\";\nconst URL_ALPHABET = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_\";\n\nfunction randomFromAlphabet(size: number, alphabet: string): string {\n const mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1;\n const step = Math.ceil((1.6 * mask * size) / alphabet.length);\n let id = \"\";\n while (id.length < size) {\n const bytes = getRandom(new Uint8Array(step));\n for (let i = 0; i < step && id.length < size; i++) {\n const idx = bytes[i]! & mask;\n if (idx < alphabet.length) id += alphabet[idx];\n }\n }\n return id;\n}\n\n/** Nano-ID-style URL-safe id (default 21 chars). */\nexport function nanoid(size = 21): string {\n return randomFromAlphabet(size, NANO_ALPHABET);\n}\n\n/** Short, URL-safe, human-shareable code (default 8 chars). */\nexport function shortId(size = 8): string {\n return randomFromAlphabet(size, URL_ALPHABET);\n}\n\n/** A prefixed id, e.g. `id(\"user\")` → \"user_9f8c…\". Uses nanoid. */\nexport function id(prefix: string, size = 16): string {\n return `${prefix}_${nanoid(size)}`;\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["id"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @lacspace/id\n *\n * Unique IDs done right — UUID v4, **UUID v7** (time-sortable), Nano-ID-style\n * and short URL-safe codes. Cryptographically random (Web Crypto), monotonic\n * v7 within the same millisecond, zero-dependency and isomorphic.\n */\n\nfunction getRandom(bytes: Uint8Array): Uint8Array {\n const c = (globalThis as { crypto?: Crypto }).crypto;\n if (!c || typeof c.getRandomValues !== \"function\") {\n throw new Error(\"Web Crypto getRandomValues is unavailable in this environment.\");\n }\n c.getRandomValues(bytes);\n return bytes;\n}\n\nconst HEX: string[] = [];\nfor (let i = 0; i < 256; i++) HEX.push((i + 0x100).toString(16).slice(1));\n\nfunction bytesToUuid(b: Uint8Array): string {\n return (\n HEX[b[0]!]! + HEX[b[1]!]! + HEX[b[2]!]! + HEX[b[3]!]! + \"-\" +\n HEX[b[4]!]! + HEX[b[5]!]! + \"-\" +\n HEX[b[6]!]! + HEX[b[7]!]! + \"-\" +\n HEX[b[8]!]! + HEX[b[9]!]! + \"-\" +\n HEX[b[10]!]! + HEX[b[11]!]! + HEX[b[12]!]! + HEX[b[13]!]! + HEX[b[14]!]! + HEX[b[15]!]!\n );\n}\n\n/** RFC 4122 UUID v4 (random). */\nexport function uuidv4(): string {\n const b = getRandom(new Uint8Array(16));\n b[6] = (b[6]! & 0x0f) | 0x40; // version 4\n b[8] = (b[8]! & 0x3f) | 0x80; // variant\n return bytesToUuid(b);\n}\n\nlet lastV7Time = 0;\nlet v7Counter = 0;\n\n/**\n * UUID v7 — a time-sortable UUID (48-bit Unix-ms timestamp + randomness).\n * Great as a primary key: lexicographically sortable by creation time, index-\n * friendly, still globally unique. Monotonic within the same millisecond.\n */\nexport function uuidv7(now?: number): string {\n let time = now ?? Date.now();\n if (time === lastV7Time) {\n v7Counter++;\n // rand_a is only 12 bits (0..4095). If we exhaust the counter within a\n // single millisecond, borrow from the next ms so ordering stays monotonic\n // instead of overflowing the reserved nibble.\n if (v7Counter > 0x0fff) {\n time = lastV7Time + 1;\n lastV7Time = time;\n v7Counter = 0;\n }\n } else {\n lastV7Time = time;\n v7Counter = 0;\n }\n\n const b = getRandom(new Uint8Array(16));\n // 48-bit timestamp (big-endian) in bytes 0..5\n b[0] = (time / 2 ** 40) & 0xff;\n b[1] = (time / 2 ** 32) & 0xff;\n b[2] = (time / 2 ** 24) & 0xff;\n b[3] = (time / 2 ** 16) & 0xff;\n b[4] = (time / 2 ** 8) & 0xff;\n b[5] = time & 0xff;\n // rand_a (12 bits) holds a monotonic counter so same-ms ids stay sortable\n b[6] = 0x70 | ((v7Counter >> 8) & 0x0f); // version 7 + counter high nibble\n b[7] = v7Counter & 0xff; // counter low byte\n b[8] = (b[8]! & 0x3f) | 0x80; // variant\n return bytesToUuid(b);\n}\n\n/** Extract the timestamp (ms) embedded in a UUID v7. */\nexport function uuidv7Time(uuid: string): number {\n const hex = uuid.replace(/-/g, \"\").slice(0, 12);\n return parseInt(hex, 16);\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n/** Is this a well-formed UUID? */\nexport function isUuid(s: string): boolean {\n return UUID_RE.test(s);\n}\n\n/** UUID version digit (1–8), or null if not a UUID. */\nexport function uuidVersion(s: string): number | null {\n return isUuid(s) ? parseInt(s[14]!, 16) : null;\n}\n\nconst NANO_ALPHABET = \"useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict\";\nconst URL_ALPHABET = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_\";\n\nfunction randomFromAlphabet(size: number, alphabet: string): string {\n const mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1;\n const step = Math.ceil((1.6 * mask * size) / alphabet.length);\n let id = \"\";\n while (id.length < size) {\n const bytes = getRandom(new Uint8Array(step));\n for (let i = 0; i < step && id.length < size; i++) {\n const idx = bytes[i]! & mask;\n if (idx < alphabet.length) id += alphabet[idx];\n }\n }\n return id;\n}\n\n/** Nano-ID-style URL-safe id (default 21 chars). */\nexport function nanoid(size = 21): string {\n return randomFromAlphabet(size, NANO_ALPHABET);\n}\n\n/** Short, URL-safe, human-shareable code (default 8 chars). */\nexport function shortId(size = 8): string {\n return randomFromAlphabet(size, URL_ALPHABET);\n}\n\n/** A prefixed id, e.g. `id(\"user\")` → \"user_9f8c…\". Uses nanoid. */\nexport function id(prefix: string, size = 16): string {\n return `${prefix}_${nanoid(size)}`;\n}\n"]}
package/dist/index.js CHANGED
@@ -21,9 +21,15 @@ function uuidv4() {
21
21
  var lastV7Time = 0;
22
22
  var v7Counter = 0;
23
23
  function uuidv7(now) {
24
- const time = now ?? Date.now();
25
- if (time === lastV7Time) v7Counter++;
26
- else {
24
+ let time = now ?? Date.now();
25
+ if (time === lastV7Time) {
26
+ v7Counter++;
27
+ if (v7Counter > 4095) {
28
+ time = lastV7Time + 1;
29
+ lastV7Time = time;
30
+ v7Counter = 0;
31
+ }
32
+ } else {
27
33
  lastV7Time = time;
28
34
  v7Counter = 0;
29
35
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["id"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @lacspace/id\n *\n * Unique IDs done right — UUID v4, **UUID v7** (time-sortable), Nano-ID-style\n * and short URL-safe codes. Cryptographically random (Web Crypto), monotonic\n * v7 within the same millisecond, zero-dependency and isomorphic.\n */\n\nfunction getRandom(bytes: Uint8Array): Uint8Array {\n const c = (globalThis as { crypto?: Crypto }).crypto;\n if (!c || typeof c.getRandomValues !== \"function\") {\n throw new Error(\"Web Crypto getRandomValues is unavailable in this environment.\");\n }\n c.getRandomValues(bytes);\n return bytes;\n}\n\nconst HEX: string[] = [];\nfor (let i = 0; i < 256; i++) HEX.push((i + 0x100).toString(16).slice(1));\n\nfunction bytesToUuid(b: Uint8Array): string {\n return (\n HEX[b[0]!]! + HEX[b[1]!]! + HEX[b[2]!]! + HEX[b[3]!]! + \"-\" +\n HEX[b[4]!]! + HEX[b[5]!]! + \"-\" +\n HEX[b[6]!]! + HEX[b[7]!]! + \"-\" +\n HEX[b[8]!]! + HEX[b[9]!]! + \"-\" +\n HEX[b[10]!]! + HEX[b[11]!]! + HEX[b[12]!]! + HEX[b[13]!]! + HEX[b[14]!]! + HEX[b[15]!]!\n );\n}\n\n/** RFC 4122 UUID v4 (random). */\nexport function uuidv4(): string {\n const b = getRandom(new Uint8Array(16));\n b[6] = (b[6]! & 0x0f) | 0x40; // version 4\n b[8] = (b[8]! & 0x3f) | 0x80; // variant\n return bytesToUuid(b);\n}\n\nlet lastV7Time = 0;\nlet v7Counter = 0;\n\n/**\n * UUID v7 — a time-sortable UUID (48-bit Unix-ms timestamp + randomness).\n * Great as a primary key: lexicographically sortable by creation time, index-\n * friendly, still globally unique. Monotonic within the same millisecond.\n */\nexport function uuidv7(now?: number): string {\n const time = now ?? Date.now();\n if (time === lastV7Time) v7Counter++;\n else { lastV7Time = time; v7Counter = 0; }\n\n const b = getRandom(new Uint8Array(16));\n // 48-bit timestamp (big-endian) in bytes 0..5\n b[0] = (time / 2 ** 40) & 0xff;\n b[1] = (time / 2 ** 32) & 0xff;\n b[2] = (time / 2 ** 24) & 0xff;\n b[3] = (time / 2 ** 16) & 0xff;\n b[4] = (time / 2 ** 8) & 0xff;\n b[5] = time & 0xff;\n // rand_a (12 bits) holds a monotonic counter so same-ms ids stay sortable\n b[6] = 0x70 | ((v7Counter >> 8) & 0x0f); // version 7 + counter high nibble\n b[7] = v7Counter & 0xff; // counter low byte\n b[8] = (b[8]! & 0x3f) | 0x80; // variant\n return bytesToUuid(b);\n}\n\n/** Extract the timestamp (ms) embedded in a UUID v7. */\nexport function uuidv7Time(uuid: string): number {\n const hex = uuid.replace(/-/g, \"\").slice(0, 12);\n return parseInt(hex, 16);\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n/** Is this a well-formed UUID? */\nexport function isUuid(s: string): boolean {\n return UUID_RE.test(s);\n}\n\n/** UUID version digit (1–8), or null if not a UUID. */\nexport function uuidVersion(s: string): number | null {\n return isUuid(s) ? parseInt(s[14]!, 16) : null;\n}\n\nconst NANO_ALPHABET = \"useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict\";\nconst URL_ALPHABET = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_\";\n\nfunction randomFromAlphabet(size: number, alphabet: string): string {\n const mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1;\n const step = Math.ceil((1.6 * mask * size) / alphabet.length);\n let id = \"\";\n while (id.length < size) {\n const bytes = getRandom(new Uint8Array(step));\n for (let i = 0; i < step && id.length < size; i++) {\n const idx = bytes[i]! & mask;\n if (idx < alphabet.length) id += alphabet[idx];\n }\n }\n return id;\n}\n\n/** Nano-ID-style URL-safe id (default 21 chars). */\nexport function nanoid(size = 21): string {\n return randomFromAlphabet(size, NANO_ALPHABET);\n}\n\n/** Short, URL-safe, human-shareable code (default 8 chars). */\nexport function shortId(size = 8): string {\n return randomFromAlphabet(size, URL_ALPHABET);\n}\n\n/** A prefixed id, e.g. `id(\"user\")` → \"user_9f8c…\". Uses nanoid. */\nexport function id(prefix: string, size = 16): string {\n return `${prefix}_${nanoid(size)}`;\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["id"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @lacspace/id\n *\n * Unique IDs done right — UUID v4, **UUID v7** (time-sortable), Nano-ID-style\n * and short URL-safe codes. Cryptographically random (Web Crypto), monotonic\n * v7 within the same millisecond, zero-dependency and isomorphic.\n */\n\nfunction getRandom(bytes: Uint8Array): Uint8Array {\n const c = (globalThis as { crypto?: Crypto }).crypto;\n if (!c || typeof c.getRandomValues !== \"function\") {\n throw new Error(\"Web Crypto getRandomValues is unavailable in this environment.\");\n }\n c.getRandomValues(bytes);\n return bytes;\n}\n\nconst HEX: string[] = [];\nfor (let i = 0; i < 256; i++) HEX.push((i + 0x100).toString(16).slice(1));\n\nfunction bytesToUuid(b: Uint8Array): string {\n return (\n HEX[b[0]!]! + HEX[b[1]!]! + HEX[b[2]!]! + HEX[b[3]!]! + \"-\" +\n HEX[b[4]!]! + HEX[b[5]!]! + \"-\" +\n HEX[b[6]!]! + HEX[b[7]!]! + \"-\" +\n HEX[b[8]!]! + HEX[b[9]!]! + \"-\" +\n HEX[b[10]!]! + HEX[b[11]!]! + HEX[b[12]!]! + HEX[b[13]!]! + HEX[b[14]!]! + HEX[b[15]!]!\n );\n}\n\n/** RFC 4122 UUID v4 (random). */\nexport function uuidv4(): string {\n const b = getRandom(new Uint8Array(16));\n b[6] = (b[6]! & 0x0f) | 0x40; // version 4\n b[8] = (b[8]! & 0x3f) | 0x80; // variant\n return bytesToUuid(b);\n}\n\nlet lastV7Time = 0;\nlet v7Counter = 0;\n\n/**\n * UUID v7 — a time-sortable UUID (48-bit Unix-ms timestamp + randomness).\n * Great as a primary key: lexicographically sortable by creation time, index-\n * friendly, still globally unique. Monotonic within the same millisecond.\n */\nexport function uuidv7(now?: number): string {\n let time = now ?? Date.now();\n if (time === lastV7Time) {\n v7Counter++;\n // rand_a is only 12 bits (0..4095). If we exhaust the counter within a\n // single millisecond, borrow from the next ms so ordering stays monotonic\n // instead of overflowing the reserved nibble.\n if (v7Counter > 0x0fff) {\n time = lastV7Time + 1;\n lastV7Time = time;\n v7Counter = 0;\n }\n } else {\n lastV7Time = time;\n v7Counter = 0;\n }\n\n const b = getRandom(new Uint8Array(16));\n // 48-bit timestamp (big-endian) in bytes 0..5\n b[0] = (time / 2 ** 40) & 0xff;\n b[1] = (time / 2 ** 32) & 0xff;\n b[2] = (time / 2 ** 24) & 0xff;\n b[3] = (time / 2 ** 16) & 0xff;\n b[4] = (time / 2 ** 8) & 0xff;\n b[5] = time & 0xff;\n // rand_a (12 bits) holds a monotonic counter so same-ms ids stay sortable\n b[6] = 0x70 | ((v7Counter >> 8) & 0x0f); // version 7 + counter high nibble\n b[7] = v7Counter & 0xff; // counter low byte\n b[8] = (b[8]! & 0x3f) | 0x80; // variant\n return bytesToUuid(b);\n}\n\n/** Extract the timestamp (ms) embedded in a UUID v7. */\nexport function uuidv7Time(uuid: string): number {\n const hex = uuid.replace(/-/g, \"\").slice(0, 12);\n return parseInt(hex, 16);\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n/** Is this a well-formed UUID? */\nexport function isUuid(s: string): boolean {\n return UUID_RE.test(s);\n}\n\n/** UUID version digit (1–8), or null if not a UUID. */\nexport function uuidVersion(s: string): number | null {\n return isUuid(s) ? parseInt(s[14]!, 16) : null;\n}\n\nconst NANO_ALPHABET = \"useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict\";\nconst URL_ALPHABET = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_\";\n\nfunction randomFromAlphabet(size: number, alphabet: string): string {\n const mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1;\n const step = Math.ceil((1.6 * mask * size) / alphabet.length);\n let id = \"\";\n while (id.length < size) {\n const bytes = getRandom(new Uint8Array(step));\n for (let i = 0; i < step && id.length < size; i++) {\n const idx = bytes[i]! & mask;\n if (idx < alphabet.length) id += alphabet[idx];\n }\n }\n return id;\n}\n\n/** Nano-ID-style URL-safe id (default 21 chars). */\nexport function nanoid(size = 21): string {\n return randomFromAlphabet(size, NANO_ALPHABET);\n}\n\n/** Short, URL-safe, human-shareable code (default 8 chars). */\nexport function shortId(size = 8): string {\n return randomFromAlphabet(size, URL_ALPHABET);\n}\n\n/** A prefixed id, e.g. `id(\"user\")` → \"user_9f8c…\". Uses nanoid. */\nexport function id(prefix: string, size = 16): string {\n return `${prefix}_${nanoid(size)}`;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lacspace/id",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Unique IDs done right — UUID v4, time-sortable UUID v7, Nano-ID-style and short URL-safe codes. Cryptographically random (Web Crypto), zero-dependency, isomorphic.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -43,7 +43,7 @@
43
43
  ],
44
44
  "author": "Lacspace <contact@lacspace.com>",
45
45
  "license": "SEE LICENSE IN LICENSE",
46
- "homepage": "https://lacspace.com/packages",
46
+ "homepage": "https://developer.lacspace.com/packages/id",
47
47
  "repository": {
48
48
  "type": "git",
49
49
  "url": "git+https://github.com/lacspace/npm-packages.git",
@@ -53,7 +53,7 @@
53
53
  "url": "https://github.com/lacspace/npm-packages/issues"
54
54
  },
55
55
  "engines": {
56
- "node": ">=18"
56
+ "node": ">=20"
57
57
  },
58
58
  "publishConfig": {
59
59
  "access": "public"