+3
-5
| #!/usr/bin/env node | ||
| import { readFileSync } from 'node:fs' | ||
| import { dirname, join } from 'node:path' | ||
| import { fileURLToPath } from 'node:url' | ||
| import { join } from 'node:path' | ||
@@ -19,5 +18,4 @@ import { customAlphabet, nanoid } from '../index.js' | ||
| if (process.argv.includes('--version') || process.argv.includes('-v')) { | ||
| let root = dirname(fileURLToPath(import.meta.url)) | ||
| let pkg = JSON.parse(readFileSync(join(root, '..', 'package.json'), 'utf8')) | ||
| print(pkg.version) | ||
| let json = readFileSync(join(import.meta.dirname, '..', 'package.json')) | ||
| print(JSON.parse(json).version) | ||
| process.exit() | ||
@@ -24,0 +22,0 @@ } |
+3
-3
| import { urlAlphabet as scopedUrlAlphabet } from './url-alphabet/index.js' | ||
| import { urlAlphabet } from './url-alphabet/index.js' | ||
| export { urlAlphabet } from './url-alphabet/index.js' | ||
| export { urlAlphabet } | ||
@@ -54,5 +54,5 @@ export let random = bytes => crypto.getRandomValues(new Uint8Array(bytes)) | ||
| while (size--) { | ||
| id += scopedUrlAlphabet[bytes[size] & 63] | ||
| id += urlAlphabet[bytes[size] & 63] | ||
| } | ||
| return id | ||
| } |
+2
-2
@@ -73,3 +73,3 @@ /** | ||
| * @param alphabet Alphabet used to generate a random string. | ||
| * @param size Size of the random string. | ||
| * @param defaultSize Size of the random string. | ||
| * @param random A random bytes generator. | ||
@@ -81,3 +81,3 @@ * @typeparam Type The ID type to replace `string` with some opaque type. | ||
| alphabet: string, | ||
| size: number, | ||
| defaultSize: number, | ||
| random: (bytes: number) => Uint8Array | ||
@@ -84,0 +84,0 @@ ): (size?: number) => Type |
+75
-32
@@ -1,31 +0,22 @@ | ||
| import { webcrypto as crypto } from 'node:crypto' | ||
| import { urlAlphabet } from './url-alphabet/index.js' | ||
| import { urlAlphabet as scopedUrlAlphabet } from './url-alphabet/index.js' | ||
| export { urlAlphabet } | ||
| export { urlAlphabet } from './url-alphabet/index.js' | ||
| const GET_RANDOM_LIMIT = 65536 | ||
| const POOL_SIZE_MULTIPLIER = 128 | ||
| let pool, poolOffset | ||
| function fillPool(bytes) { | ||
| if (bytes < 0) throw new RangeError('Wrong ID size') | ||
| try { | ||
| if (!pool || pool.length < bytes) { | ||
| pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER) | ||
| crypto.getRandomValues(pool) | ||
| poolOffset = 0 | ||
| } else if (poolOffset + bytes > pool.length) { | ||
| crypto.getRandomValues(pool) | ||
| poolOffset = 0 | ||
| } | ||
| } catch (e) { | ||
| pool = undefined | ||
| throw e | ||
| function fillRandom(buffer) { | ||
| let from = 0 | ||
| while (from < buffer.length) { | ||
| let to = Math.min(from + GET_RANDOM_LIMIT, buffer.length) | ||
| crypto.getRandomValues(buffer.subarray(from, to)) | ||
| from = to | ||
| } | ||
| poolOffset += bytes | ||
| } | ||
| export function random(bytes) { | ||
| fillPool((bytes |= 0)) | ||
| return pool.subarray(poolOffset - bytes, poolOffset) | ||
| bytes |= 0 | ||
| if (bytes < 0) throw new RangeError('Wrong ID size') | ||
| let buffer = Buffer.allocUnsafe(bytes) | ||
| fillRandom(buffer) | ||
| return buffer | ||
| } | ||
@@ -71,14 +62,66 @@ | ||
| export function customAlphabet(alphabet, size = 21) { | ||
| return customRandom(alphabet, size, random) | ||
| } | ||
| export function nanoid(size = 21) { | ||
| fillPool((size |= 0)) | ||
| const POOL_MAX = GET_RANDOM_LIMIT / 2 | ||
| let id = '' | ||
| for (let i = poolOffset - size; i < poolOffset; i++) { | ||
| id += scopedUrlAlphabet[pool[i] & 63] | ||
| export function customAlphabet(alphabet, defaultSize = 21) { | ||
| if ( | ||
| typeof alphabet !== 'string' || | ||
| !alphabet.length || | ||
| alphabet.length > 256 | ||
| ) { | ||
| return customRandom(alphabet, defaultSize, random) | ||
| } | ||
| return id | ||
| for (let i = 0; i < alphabet.length; i++) { | ||
| if (alphabet.charCodeAt(i) > 255) { | ||
| return customRandom(alphabet, defaultSize, random) | ||
| } | ||
| } | ||
| let charCodes = Uint8Array.from(alphabet, str => { | ||
| return str.charCodeAt(0) | ||
| }) | ||
| let alphabetLen = alphabet.length | ||
| let mask = (2 << (31 - Math.clz32((alphabetLen - 1) | 1))) - 1 | ||
| let pool = '' | ||
| let poolOffset = 0 | ||
| let poolNext = 0 | ||
| return (size = defaultSize) => { | ||
| size |= 0 | ||
| if (size < 0) throw new RangeError('Wrong ID size') | ||
| if (size === 0) return '' | ||
| if (poolOffset + size > pool.length) { | ||
| let target = Math.max(poolNext, size) | ||
| poolNext = Math.min(target * 16, POOL_MAX) | ||
| let buffer = Buffer.allocUnsafe(target) | ||
| if (mask === alphabetLen - 1) { | ||
| fillRandom(buffer) | ||
| for (let i = 0; i < target; i++) { | ||
| buffer[i] = charCodes[buffer[i] & mask] | ||
| } | ||
| } else { | ||
| let randomBytes = Buffer.allocUnsafe( | ||
| Math.ceil((1.6 * (mask + 1) * target) / alphabetLen) | ||
| ) | ||
| let accepted = 0 | ||
| while (accepted < target) { | ||
| fillRandom(randomBytes) | ||
| for (let i = 0; i < randomBytes.length; i++) { | ||
| let index = randomBytes[i] & mask | ||
| if (index < alphabetLen) { | ||
| buffer[accepted++] = charCodes[index] | ||
| if (accepted === target) break | ||
| } | ||
| } | ||
| } | ||
| } | ||
| pool = buffer.toString('latin1') | ||
| poolOffset = 0 | ||
| } | ||
| poolOffset += size | ||
| return pool.substring(poolOffset - size, poolOffset) | ||
| } | ||
| } | ||
| export const nanoid = customAlphabet(urlAlphabet) |
| let urlAlphabet = | ||
| 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict' | ||
| import { urlAlphabet } from '../url-alphabet/index.js' | ||
@@ -5,0 +4,0 @@ export let customAlphabet = (alphabet, defaultSize = 21) => { |
+2
-2
| { | ||
| "name": "nanoid", | ||
| "version": "5.1.16", | ||
| "version": "6.0.0", | ||
| "description": "A tiny (118 bytes), secure URL-friendly unique string ID generator", | ||
@@ -44,4 +44,4 @@ "keywords": [ | ||
| "engines": { | ||
| "node": "^18 || >=20" | ||
| "node": "^22 || ^24 || >=26" | ||
| } | ||
| } |
+1
-0
@@ -15,2 +15,3 @@ # Nano ID | ||
| [Size Limit] controls the size. | ||
| - **Fast.** 50% faster than native `crypto.randomUUID()`. | ||
| - **Safe.** It uses hardware random generator. Can be used in clusters. | ||
@@ -17,0 +18,0 @@ - **Short IDs.** It uses a larger alphabet than UUID (`A-Za-z0-9_-`). |
14814
8.61%377
10.88%36
2.86%