nanoid
Advanced tools
Comparing version 2.1.11 to 3.0.0
@@ -1,37 +0,68 @@ | ||
// This file replaces `async/index.js` in bundlers like webpack or Rollup, | ||
// according to `browser` config in `package.json`. | ||
let customAlphabet = (alphabet, size) => { | ||
// First, a bitmask is necessary to generate the ID. The bitmask makes bytes | ||
// values closer to the alphabet size. The bitmask calculates the closest | ||
// `2^31 - 1` number, which exceeds the alphabet size. | ||
// For example, the bitmask for the alphabet size 30 is 31 (00011111). | ||
// `Math.clz32` is not used, because it is not available in browsers. | ||
let mask = (2 << Math.log(alphabet.length - 1) / Math.LN2) - 1 | ||
// Though, the bitmask solution is not perfect since the bytes exceeding | ||
// the alphabet size are refused. Therefore, to reliably generate the ID, | ||
// the random bytes redundancy has to be satisfied. | ||
var crypto = self.crypto || self.msCrypto | ||
// Note: every hardware random generator call is performance expensive, | ||
// because the system call for entropy collection takes a lot of time. | ||
// So, to avoid additional system calls, extra bytes are requested in advance. | ||
// This alphabet uses a-z A-Z 0-9 _- symbols. | ||
// Symbols are generated for smaller size. | ||
// -_zyxwvutsrqponmlkjihgfedcba9876543210ZYXWVUTSRQPONMLKJIHGFEDCBA | ||
var url = '-_' | ||
// Loop from 36 to 0 (from z to a and 9 to 0 in Base36). | ||
var i = 36 | ||
while (i--) { | ||
// 36 is radix. Number.prototype.toString(36) returns number | ||
// in Base36 representation. Base36 is like hex, but it uses 0–9 and a-z. | ||
url += i.toString(36) | ||
// Next, a step determines how many random bytes to generate. | ||
// The number of random bytes gets decided upon the ID size, mask, | ||
// alphabet size, and magic number 1.6 (using 1.6 peaks at performance | ||
// according to benchmarks). | ||
// `-~f => Math.ceil(f)` if f is a float | ||
// `-~i => i + 1` if i is an integer | ||
let step = -~(1.6 * mask * size / alphabet.length) | ||
return () => { | ||
let id = '' | ||
while (true) { | ||
let bytes = crypto.getRandomValues(new Uint8Array(step)) | ||
// A compact alternative for `for (var i = 0; i < step; i++)`. | ||
let i = step | ||
while (i--) { | ||
// Adding `|| ''` refuses a random byte that exceeds the alphabet size. | ||
id += alphabet[bytes[i] & mask] || '' | ||
// `id.length + 1 === size` is a more compact option. | ||
if (id.length === +size) return id | ||
} | ||
} | ||
} | ||
} | ||
// Loop from 36 to 10 (from Z to A in Base36). | ||
i = 36 | ||
while (i-- - 10) { | ||
url += i.toString(36).toUpperCase() | ||
} | ||
module.exports = function (size) { | ||
var id = '' | ||
var bytes = crypto.getRandomValues(new Uint8Array(size || 21)) | ||
i = size || 21 | ||
let nanoid = (size = 21) => { | ||
let id = '' | ||
let bytes = crypto.getRandomValues(new Uint8Array(size)) | ||
// Compact alternative for `for (var i = 0; i < size; i++)` | ||
while (i--) { | ||
// We can’t use bytes bigger than the alphabet. 63 is 00111111 bitmask. | ||
// This mask reduces random byte 0-255 to 0-63 values. | ||
// There is no need in `|| ''` and `* 1.6` hacks in here, | ||
// because bitmask trim bytes exact to alphabet size. | ||
id += url[bytes[i] & 63] | ||
// A compact alternative for `for (var i = 0; i < step; i++)`. | ||
while (size--) { | ||
// It is incorrect to use bytes exceeding the alphabet size. | ||
// The following mask reduces the random byte in the 0-255 value | ||
// range to the 0-63 value range. Therefore, adding hacks, such | ||
// as empty string fallback or magic numbers, is unneccessary because | ||
// the bitmask trims bytes down to the alphabet size. | ||
let byte = bytes[size] & 63 | ||
if (byte < 36) { | ||
// `0-9a-z` | ||
id += byte.toString(36) | ||
} else if (byte < 62) { | ||
// `A-Z` | ||
id += (byte - 26).toString(36).toUpperCase() | ||
} else if (byte < 63) { | ||
id += '_' | ||
} else { | ||
id += '-' | ||
} | ||
} | ||
return Promise.resolve(id) | ||
} | ||
export { nanoid, customAlphabet } |
@@ -1,37 +0,69 @@ | ||
var random = require('./random') | ||
var url = require('../url') | ||
import crypto from 'crypto' | ||
/** | ||
* Generate secure URL-friendly unique ID. Non-blocking version. | ||
* | ||
* By default, ID will have 21 symbols to have a collision probability similar | ||
* to UUID v4. | ||
* | ||
* @param {number} [size=21] The number of symbols in ID. | ||
* | ||
* @return {Promise} Promise with random string. | ||
* | ||
* @example | ||
* const nanoidAsync = require('nanoid/async') | ||
* nanoidAsync.then(id => { | ||
* model.id = id | ||
* }) | ||
* | ||
* @name async | ||
* @function | ||
*/ | ||
module.exports = function (size) { | ||
size = size || 21 | ||
return random(size).then(function (bytes) { | ||
var id = '' | ||
// Compact alternative for `for (var i = 0; i < size; i++)` | ||
while (size--) { | ||
// We can’t use bytes bigger than the alphabet. 63 is 00111111 bitmask. | ||
// This mask reduces random byte 0-255 to 0-63 values. | ||
// There is no need in `|| ''` and `* 1.6` hacks in here, | ||
// because bitmask trim bytes exact to alphabet size. | ||
id += url[bytes[size] & 63] | ||
import { urlAlphabet } from '../index.js' | ||
// `crypto.randomFill()` is a little faster than `crypto.randomBytes()`, | ||
// because it is possible to use in combination with `Buffer.allocUnsafe()`. | ||
let random = bytes => new Promise((resolve, reject) => { | ||
// `Buffer.allocUnsafe()` is faster because it doesn’t flush the memory. | ||
// Memory flushing is unnecessary since the buffer allocation itself resets | ||
// the memory with the new bytes. | ||
crypto.randomFill(Buffer.allocUnsafe(bytes), (err, buf) => { | ||
if (err) { | ||
reject(err) | ||
} else { | ||
resolve(buf) | ||
} | ||
return id | ||
}) | ||
}) | ||
let customAlphabet = (alphabet, size) => { | ||
// First, a bitmask is necessary to generate the ID. The bitmask makes bytes | ||
// values closer to the alphabet size. The bitmask calculates the closest | ||
// `2^31 - 1` number, which exceeds the alphabet size. | ||
// For example, the bitmask for the alphabet size 30 is 31 (00011111). | ||
let mask = (2 << 31 - Math.clz32((alphabet.length - 1) | 1)) - 1 | ||
// Though, the bitmask solution is not perfect since the bytes exceeding | ||
// the alphabet size are refused. Therefore, to reliably generate the ID, | ||
// the random bytes redundancy has to be satisfied. | ||
// Note: every hardware random generator call is performance expensive, | ||
// because the system call for entropy collection takes a lot of time. | ||
// So, to avoid additional system calls, extra bytes are requested in advance. | ||
// Next, a step determines how many random bytes to generate. | ||
// The number of random bytes gets decided upon the ID size, mask, | ||
// alphabet size, and magic number 1.6 (using 1.6 peaks at performance | ||
// according to benchmarks). | ||
let step = Math.ceil(1.6 * mask * size / alphabet.length) | ||
let tick = id => random(step).then(bytes => { | ||
// A compact alternative for `for (var i = 0; i < step; i++)`. | ||
let i = step | ||
while (i--) { | ||
// Adding `|| ''` refuses a random byte that exceeds the alphabet size. | ||
id += alphabet[bytes[i] & mask] || '' | ||
// `id.length + 1 === size` is a more compact option. | ||
if (id.length === +size) return id | ||
} | ||
return tick(id) | ||
}) | ||
return () => tick('') | ||
} | ||
let nanoid = (size = 21) => random(size).then(bytes => { | ||
let id = '' | ||
// A compact alternative for `for (var i = 0; i < step; i++)`. | ||
while (size--) { | ||
// It is incorrect to use bytes exceeding the alphabet size. | ||
// The following mask reduces the random byte in the 0-255 value | ||
// range to the 0-63 value range. Therefore, adding hacks, such | ||
// as empty string fallback or magic numbers, is unneccessary because | ||
// the bitmask trims bytes down to the alphabet size. | ||
id += urlAlphabet[bytes[size] & 63] | ||
} | ||
return id | ||
}) | ||
export { nanoid, customAlphabet } |
# Change Log | ||
This project adheres to [Semantic Versioning](http://semver.org/). | ||
## 3.0 | ||
Migration guide: <https://github.com/ai/nanoid/releases/tag/3.0.0> | ||
* Move to ES2016 syntax. You need to use Babel for IE 11. | ||
* Move to named exports `import { nanoid } from 'nanoid'`. | ||
* Move `import url from 'nanoid/url'` to `import { urlAlphabet } from 'nanoid'`. | ||
* Replace `format()` to `customRandom()`. | ||
* Replace `generate()` to `customAlphabet()`. | ||
* Remove `async/format`. | ||
* Remove React Native support for `nanoid/async`. | ||
* Add `nanoid.js` to use directly in browser from CDN. | ||
* Add TypeScript type definitions. | ||
* Add ES modules support for bundlers, Node.js, and React Native. | ||
* Fix React Native support. | ||
* Reduce size. | ||
* Improve docs (by Dair Aidarkhanov). | ||
## 2.1.11 | ||
@@ -5,0 +21,0 @@ * Reduce size (by Anton Evzhakov). |
@@ -5,12 +5,21 @@ // This file replaces `index.js` in bundlers like webpack or Rollup, | ||
if (process.env.NODE_ENV !== 'production') { | ||
// All bundlers will remove this block in production bundle | ||
if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') { | ||
// All bundlers will remove this block in the production bundle. | ||
if ( | ||
typeof navigator !== 'undefined' && | ||
navigator.product === 'ReactNative' && | ||
!self.crypto | ||
) { | ||
throw new Error( | ||
'React Native does not have a built-in secure random generator. ' + | ||
'If you don’t need unpredictable IDs, you can use `nanoid/non-secure`. ' + | ||
'For secure ID install `expo-random` locally and use `nanoid/async`.' | ||
'For secure IDs, import `react-native-get-random-values` before Nano ID.' | ||
) | ||
} | ||
if (typeof self === 'undefined' || (!self.crypto && !self.msCrypto)) { | ||
if (typeof self !== 'undefined' && self.msCrypto && !self.crypto) { | ||
throw new Error( | ||
'Add self.crypto = self.msCrypto before Nano ID to fix IE 11 support' | ||
) | ||
} | ||
if (typeof self === 'undefined' || !self.crypto) { | ||
throw new Error( | ||
'Your browser does not have secure random generator. ' + | ||
@@ -22,35 +31,78 @@ 'If you don’t need unpredictable IDs, you can use nanoid/non-secure.' | ||
var crypto = self.crypto || self.msCrypto | ||
// This alphabet uses `A-Za-z0-9_-` symbols. The genetic algorithm helped | ||
// optimize the gzip compression for this alphabet. | ||
let urlAlphabet = | ||
'ModuleSymbhasOwnPr-0123456789ABCDEFGHNRVfgctiUvz_KqYTJkLxpZXIjQW' | ||
// This alphabet uses a-z A-Z 0-9 _- symbols. | ||
// Symbols are generated for smaller size. | ||
// -_zyxwvutsrqponmlkjihgfedcba9876543210ZYXWVUTSRQPONMLKJIHGFEDCBA | ||
var url = '-_' | ||
// Loop from 36 to 0 (from z to a and 9 to 0 in Base36). | ||
var i = 36 | ||
while (i--) { | ||
// 36 is radix. Number.prototype.toString(36) returns number | ||
// in Base36 representation. Base36 is like hex, but it uses 0–9 and a-z. | ||
url += i.toString(36) | ||
let random = bytes => crypto.getRandomValues(new Uint8Array(bytes)) | ||
let customRandom = (alphabet, size, getRandom) => { | ||
// First, a bitmask is necessary to generate the ID. The bitmask makes bytes | ||
// values closer to the alphabet size. The bitmask calculates the closest | ||
// `2^31 - 1` number, which exceeds the alphabet size. | ||
// For example, the bitmask for the alphabet size 30 is 31 (00011111). | ||
// `Math.clz32` is not used, because it is not available in browsers. | ||
let mask = (2 << Math.log(alphabet.length - 1) / Math.LN2) - 1 | ||
// Though, the bitmask solution is not perfect since the bytes exceeding | ||
// the alphabet size are refused. Therefore, to reliably generate the ID, | ||
// the random bytes redundancy has to be satisfied. | ||
// Note: every hardware random generator call is performance expensive, | ||
// because the system call for entropy collection takes a lot of time. | ||
// So, to avoid additional system calls, extra bytes are requested in advance. | ||
// Next, a step determines how many random bytes to generate. | ||
// The number of random bytes gets decided upon the ID size, mask, | ||
// alphabet size, and magic number 1.6 (using 1.6 peaks at performance | ||
// according to benchmarks). | ||
// `-~f => Math.ceil(f)` if f is a float | ||
// `-~i => i + 1` if i is an integer | ||
let step = -~(1.6 * mask * size / alphabet.length) | ||
return () => { | ||
let id = '' | ||
while (true) { | ||
let bytes = getRandom(step) | ||
// A compact alternative for `for (var i = 0; i < step; i++)`. | ||
let j = step | ||
while (j--) { | ||
// Adding `|| ''` refuses a random byte that exceeds the alphabet size. | ||
id += alphabet[bytes[j] & mask] || '' | ||
// `id.length + 1 === size` is a more compact option. | ||
if (id.length === +size) return id | ||
} | ||
} | ||
} | ||
} | ||
// Loop from 36 to 10 (from Z to A in Base36). | ||
i = 36 | ||
while (i-- - 10) { | ||
url += i.toString(36).toUpperCase() | ||
} | ||
module.exports = function (size) { | ||
var id = '' | ||
var bytes = crypto.getRandomValues(new Uint8Array(size || 21)) | ||
i = size || 21 | ||
let customAlphabet = (alphabet, size) => customRandom(alphabet, size, random) | ||
// Compact alternative for `for (var i = 0; i < size; i++)` | ||
while (i--) { | ||
// We can’t use bytes bigger than the alphabet. 63 is 00111111 bitmask. | ||
// This mask reduces random byte 0-255 to 0-63 values. | ||
// There is no need in `|| ''` and `* 1.6` hacks in here, | ||
// because bitmask trim bytes exact to alphabet size. | ||
id += url[bytes[i] & 63] | ||
let nanoid = (size = 21) => { | ||
let id = '' | ||
let bytes = crypto.getRandomValues(new Uint8Array(size)) | ||
// A compact alternative for `for (var i = 0; i < step; i++)`. | ||
while (size--) { | ||
// It is incorrect to use bytes exceeding the alphabet size. | ||
// The following mask reduces the random byte in the 0-255 value | ||
// range to the 0-63 value range. Therefore, adding hacks, such | ||
// as empty string fallback or magic numbers, is unneccessary because | ||
// the bitmask trims bytes down to the alphabet size. | ||
let byte = bytes[size] & 63 | ||
if (byte < 36) { | ||
// `0-9a-z` | ||
id += byte.toString(36) | ||
} else if (byte < 62) { | ||
// `A-Z` | ||
id += (byte - 26).toString(36).toUpperCase() | ||
} else if (byte < 63) { | ||
id += '_' | ||
} else { | ||
id += '-' | ||
} | ||
} | ||
return id | ||
} | ||
export { nanoid, customAlphabet, customRandom, urlAlphabet, random } |
98
index.js
@@ -1,34 +0,74 @@ | ||
var random = require('./random') | ||
var url = require('./url') | ||
import crypto from 'crypto' | ||
/** | ||
* Generate secure URL-friendly unique ID. | ||
* | ||
* By default, ID will have 21 symbols to have a collision probability similar | ||
* to UUID v4. | ||
* | ||
* @param {number} [size=21] The number of symbols in ID. | ||
* | ||
* @return {string} Random string. | ||
* | ||
* @example | ||
* const nanoid = require('nanoid') | ||
* model.id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqL" | ||
* | ||
* @name nanoid | ||
* @function | ||
*/ | ||
module.exports = function (size) { | ||
size = size || 21 | ||
var bytes = random(size) | ||
var id = '' | ||
// Compact alternative for `for (var i = 0; i < size; i++)` | ||
let urlAlphabet = | ||
'_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' | ||
// We reuse buffers with the same size to avoid memory fragmentations | ||
// for better performance. | ||
let buffers = { } | ||
let random = bytes => { | ||
let buffer = buffers[bytes] | ||
if (!buffer) { | ||
// `Buffer.allocUnsafe()` is faster because it doesn’t flush the memory. | ||
// Memory flushing is unnecessary since the buffer allocation itself resets | ||
// the memory with the new bytes. | ||
buffer = Buffer.allocUnsafe(bytes) | ||
if (bytes <= 255) buffers[bytes] = buffer | ||
} | ||
return crypto.randomFillSync(buffer) | ||
} | ||
let customRandom = (alphabet, size, getRandom) => { | ||
// First, a bitmask is necessary to generate the ID. The bitmask makes bytes | ||
// values closer to the alphabet size. The bitmask calculates the closest | ||
// `2^31 - 1` number, which exceeds the alphabet size. | ||
// For example, the bitmask for the alphabet size 30 is 31 (00011111). | ||
let mask = (2 << 31 - Math.clz32((alphabet.length - 1) | 1)) - 1 | ||
// Though, the bitmask solution is not perfect since the bytes exceeding | ||
// the alphabet size are refused. Therefore, to reliably generate the ID, | ||
// the random bytes redundancy has to be satisfied. | ||
// Note: every hardware random generator call is performance expensive, | ||
// because the system call for entropy collection takes a lot of time. | ||
// So, to avoid additional system calls, extra bytes are requested in advance. | ||
// Next, a step determines how many random bytes to generate. | ||
// The number of random bytes gets decided upon the ID size, mask, | ||
// alphabet size, and magic number 1.6 (using 1.6 peaks at performance | ||
// according to benchmarks). | ||
let step = Math.ceil(1.6 * mask * size / alphabet.length) | ||
return () => { | ||
let id = '' | ||
while (true) { | ||
let bytes = getRandom(step) | ||
// A compact alternative for `for (var i = 0; i < step; i++)`. | ||
let i = step | ||
while (i--) { | ||
// Adding `|| ''` refuses a random byte that exceeds the alphabet size. | ||
id += alphabet[bytes[i] & mask] || '' | ||
// `id.length + 1 === size` is a more compact option. | ||
if (id.length === +size) return id | ||
} | ||
} | ||
} | ||
} | ||
let customAlphabet = (alphabet, size) => customRandom(alphabet, size, random) | ||
let nanoid = (size = 21) => { | ||
let bytes = random(size) | ||
let id = '' | ||
// A compact alternative for `for (var i = 0; i < step; i++)`. | ||
while (size--) { | ||
// We can’t use bytes bigger than the alphabet. 63 is 00111111 bitmask. | ||
// This mask reduces random byte 0-255 to 0-63 values. | ||
// There is no need in `|| ''` and `* 1.6` hacks in here, | ||
// because bitmask trim bytes exact to alphabet size. | ||
id += url[bytes[size] & 63] | ||
// It is incorrect to use bytes exceeding the alphabet size. | ||
// The following mask reduces the random byte in the 0-255 value | ||
// range to the 0-63 value range. Therefore, adding hacks, such | ||
// as empty string fallback or magic numbers, is unneccessary because | ||
// the bitmask trims bytes down to the alphabet size. | ||
id += urlAlphabet[bytes[size] & 63] | ||
} | ||
return id | ||
} | ||
export { nanoid, customAlphabet, customRandom, urlAlphabet, random } |
@@ -1,42 +0,27 @@ | ||
// This alphabet uses a-z A-Z 0-9 _- symbols. | ||
// Symbols are generated for smaller size. | ||
// -_zyxwvutsrqponmlkjihgfedcba9876543210ZYXWVUTSRQPONMLKJIHGFEDCBA | ||
var url = '-_' | ||
// Loop from 36 to 0 (from z to a and 9 to 0 in Base36). | ||
var i = 36 | ||
while (i--) { | ||
// 36 is radix. Number.prototype.toString(36) returns number | ||
// in Base36 representation. Base36 is like hex, but it uses 0–9 and a-z. | ||
url += i.toString(36) | ||
import { urlAlphabet } from '../index.js' | ||
let customAlphabet = (alphabet, size) => { | ||
return () => { | ||
let id = '' | ||
// A compact alternative for `for (var i = 0; i < step; i++)`. | ||
let i = size | ||
while (i--) { | ||
// `| 0` is more compact and faster than `Math.floor()`. | ||
id += alphabet[Math.random() * alphabet.length | 0] | ||
} | ||
return id | ||
} | ||
} | ||
// Loop from 36 to 10 (from Z to A in Base36). | ||
i = 36 | ||
while (i-- - 10) { | ||
url += i.toString(36).toUpperCase() | ||
} | ||
/** | ||
* Generate URL-friendly unique ID. This method use non-secure predictable | ||
* random generator with bigger collision probability. | ||
* | ||
* @param {number} [size=21] The number of symbols in ID. | ||
* | ||
* @return {string} Random string. | ||
* | ||
* @example | ||
* const nanoid = require('nanoid/non-secure') | ||
* model.id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqL" | ||
* | ||
* @name nonSecure | ||
* @function | ||
*/ | ||
module.exports = function (size) { | ||
var id = '' | ||
i = size || 21 | ||
// Compact alternative for `for (var i = 0; i < size; i++)` | ||
let nanoid = (size = 21) => { | ||
let id = '' | ||
// A compact alternative for `for (var i = 0; i < step; i++)`. | ||
let i = size | ||
while (i--) { | ||
// `| 0` is compact and faster alternative for `Math.floor()` | ||
id += url[Math.random() * 64 | 0] | ||
// `| 0` is more compact and faster than `Math.floor()`. | ||
id += urlAlphabet[Math.random() * 64 | 0] | ||
} | ||
return id | ||
} | ||
export { nanoid, customAlphabet } |
{ | ||
"name": "nanoid", | ||
"version": "2.1.11", | ||
"description": "A tiny (119 bytes), secure URL-friendly unique string ID generator", | ||
"version": "3.0.0", | ||
"description": "A tiny (108 bytes), secure URL-friendly unique string ID generator", | ||
"keywords": [ | ||
@@ -15,20 +15,28 @@ "uuid", | ||
"browser": { | ||
"./index.js": "./index.browser.js", | ||
"./format.js": "./format.browser.js", | ||
"./random.js": "./random.browser.js", | ||
"./async/index.js": "./async/index.browser.js", | ||
"./async/format.js": "./async/format.browser.js", | ||
"./async/random.js": "./async/random.browser.js" | ||
"./index.js": "./index.browser.js" | ||
}, | ||
"react-native": { | ||
"./async/random.js": "./async/random.rn.js" | ||
}, | ||
"sideEffects": false, | ||
"eslintIgnore": [ | ||
"test/demo/build" | ||
], | ||
"sharec": { | ||
"config": "@logux/sharec-config", | ||
"version": "0.5.6" | ||
"type": "module", | ||
"main": "index.cjs", | ||
"module": "index.js", | ||
"react-native": "index.js", | ||
"exports": { | ||
"./package.json": "./package.json", | ||
".": { | ||
"require": "./index.cjs", | ||
"import": "./index.js", | ||
"browser": "./index.browser.js" | ||
}, | ||
"./async/package.json": "./async/package.json", | ||
"./async": { | ||
"require": "./async/index.cjs", | ||
"import": "./async/index.js", | ||
"browser": "./async/index.browser.js" | ||
}, | ||
"./non-secure/package.json": "./non-secure/package.json", | ||
"./non-secure": { | ||
"require": "./non-secure/index.cjs", | ||
"import": "./non-secure/index.js" | ||
} | ||
} | ||
} | ||
} |
312
README.md
@@ -8,7 +8,10 @@ # Nano ID | ||
* **Small.** 119 bytes (minified and gzipped). No dependencies. | ||
> “An amazing level of senseless perfectionism, | ||
> which is simply impossible not to respect.” | ||
* **Small.** 108 bytes (minified and gzipped). No dependencies. | ||
[Size Limit] controls the size. | ||
* **Safe.** It uses cryptographically strong random APIs. | ||
Can be used in clusters. | ||
* **Fast.** It’s 16% faster than UUID. | ||
* **Fast.** It is 16% faster than UUID. | ||
* **Compact.** It uses a larger alphabet than UUID (`A-Za-z0-9_-`). | ||
@@ -18,10 +21,11 @@ So ID size was reduced from 36 to 21 symbols. | ||
```js | ||
const nanoid = require('nanoid') | ||
import { nanoid } from 'nanoid' | ||
model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT" | ||
``` | ||
Supports [all browsers], Node.js and React Native. | ||
Supports modern browsers, IE with Babel, Node.js and React Native. | ||
Try to make us smaller in the [online tool]. | ||
[all browsers]: http://caniuse.com/#feat=getrandomvalues | ||
[Size Limit]: https://github.com/ai/size-limit | ||
[online tool]: https://gitpod.io/#https://github.com/ai/nanoid/ | ||
[Size Limit]: https://github.com/ai/size-limit | ||
@@ -35,19 +39,20 @@ <a href="https://evilmartians.com/?utm_source=nanoid"> | ||
1. [Comparison with UUID](#comparison-with-uuid) | ||
2. [Benchmark](#benchmark) | ||
4. [Tools](#tools) | ||
3. [Security](#security) | ||
6. Usage | ||
1. [JS](#js) | ||
2. [React](#react) | ||
3. [React Native](#react-native) | ||
4. [Web Workers](#web-workers) | ||
5. [PouchDB and CouchDB](#pouchdb-and-couchdb) | ||
5. [Mongoose](#mongoose) | ||
6. [Other Programming Languages](#other-programming-languages) | ||
7. API | ||
1. [Async](#async) | ||
2. [Non-Secure](#non-secure) | ||
3. [Custom Alphabet or Length](#custom-alphabet-or-length) | ||
4. [Custom Random Bytes Generator](#custom-random-bytes-generator) | ||
* [Comparison with UUID](#comparison-with-uuid) | ||
* [Benchmark](#benchmark) | ||
* [Tools](#tools) | ||
* [Security](#security) | ||
* [Usage](#usage) | ||
* [JS](#js) | ||
* [React](#react) | ||
* [React Native](#react-native) | ||
* [PouchDB and CouchDB](#pouchdb-and-couchdb) | ||
* [Mongoose](#mongoose) | ||
* [ES Modules](#es-modules) | ||
* [Web Workers](#web-workers) | ||
* [Other Programming Languages](#other-programming-languages) | ||
* [API](#api) | ||
* [Async](#async) | ||
* [Non-Secure](#non-secure) | ||
* [Custom Alphabet or Size](#custom-alphabet-or-size) | ||
* [Custom Random Bytes Generator](#custom-random-bytes-generator) | ||
@@ -68,4 +73,4 @@ | ||
are packed in just 21 symbols instead of 36. | ||
2. Nano ID code is 4 times less than `uuid/v4` package: | ||
119 bytes instead of 435. | ||
2. Nano ID code is 3 times less than `uuid/v4` package: | ||
108 bytes instead of 345. | ||
3. Because of memory allocation tricks, Nano ID is 16% faster than UUID. | ||
@@ -78,26 +83,29 @@ | ||
$ ./test/benchmark | ||
nanoid 693,132 ops/sec | ||
nanoid/generate 624,291 ops/sec | ||
uid.sync 487,706 ops/sec | ||
uuid/v4 471,299 ops/sec | ||
secure-random-string 448,386 ops/sec | ||
shortid 66,809 ops/sec | ||
nanoid 655,798 ops/sec | ||
customAlphabet 635,421 ops/sec | ||
uid.sync 375,816 ops/sec | ||
uuid v4 396,756 ops/sec | ||
secure-random-string 366,434 ops/sec | ||
shortid 59,343 ops/sec | ||
Async: | ||
nanoid/async 105,024 ops/sec | ||
nanoid/async/generate 106,682 ops/sec | ||
secure-random-string 94,217 ops/sec | ||
uid 92,026 ops/sec | ||
async nanoid 101,966 ops/sec | ||
async customAlphabet 102,471 ops/sec | ||
async secure-random-string 97,206 ops/sec | ||
uid 91,291 ops/sec | ||
Non-secure: | ||
nanoid/non-secure 2,555,814 ops/sec | ||
rndm 2,413,565 ops/sec | ||
non-secure nanoid 2,754,423 ops/sec | ||
rndm 2,437,262 ops/sec | ||
``` | ||
Test configuration: Dell XPS 2-in-a 7390, Fedora 32, Node.js 13.11. | ||
## Tools | ||
* [ID size calculator] to choice smaller ID size depends on your case. | ||
* [`nanoid-dictionary`] with popular alphabets to use with `nanoid/generate`. | ||
* [`nanoid-cli`] to generate ID from CLI. | ||
* [ID size calculator] shows collision probability when adjusting | ||
the ID alphabet or size. | ||
* [`nanoid-dictionary`] with popular alphabets to use with `customAlphabet`. | ||
* [`nanoid-cli`] to generate IDs from CLI. | ||
* [`nanoid-good`] to be sure that your ID doesn't contain any obscene words. | ||
@@ -117,32 +125,22 @@ | ||
### Unpredictability | ||
* **Unpredictability.** Instead of using the unsafe `Math.random()`, Nano ID | ||
uses the `crypto` module in Node.js and the Web Crypto API in browsers. | ||
These modules use unpredictable hardware random generator. | ||
* **Uniformity.** `random % alphabet` is a popular mistake to make when coding | ||
an ID generator. The distribution will not be even; there will be a lower | ||
chance for some symbols to appear compared to others. So, it will reduce | ||
the number of tries when brute-forcing. Nano ID uses a [better algorithm] | ||
and is tested for uniformity. | ||
Instead of using the unsafe `Math.random()`, Nano ID uses the `crypto` module | ||
in Node.js and the Web Crypto API in browsers. These modules use unpredictable | ||
hardware random generator. | ||
<img src="img/distribution.png" alt="Nano ID uniformity" | ||
width="340" height="135"> | ||
* **Vulnerabilities:** to report a security vulnerability, please use | ||
the [Tidelift security contact](https://tidelift.com/security). | ||
Tidelift will coordinate the fix and disclosure. | ||
### Uniformity | ||
`random % alphabet` is a popular mistake to make when coding an ID generator. | ||
The spread will not be even; there will be a lower chance for some symbols | ||
to appear compared to others—so it will reduce the number of tries | ||
when brute-forcing. | ||
Nano ID uses a [better algorithm] and is tested for uniformity. | ||
<img src="img/distribution.png" alt="Nano ID uniformity" | ||
width="340" height="135"> | ||
[Secure random values (in Node.js)]: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba | ||
[better algorithm]: https://github.com/ai/nanoid/blob/master/format.js | ||
[better algorithm]: https://github.com/ai/nanoid/blob/master/format.js | ||
### Vulnerabilities | ||
To report a security vulnerability, please use the | ||
[Tidelift security contact](https://tidelift.com/security). | ||
Tidelift will coordinate the fix and disclosure. | ||
## Usage | ||
@@ -156,8 +154,8 @@ | ||
```js | ||
const nanoid = require('nanoid') | ||
import { nanoid } from 'nanoid' | ||
model.id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ" | ||
``` | ||
If you want to reduce ID length (and increase collisions probability), | ||
you can pass the length as an argument. | ||
If you want to reduce the ID size (and increase collisions probability), | ||
you can pass the size as an argument. | ||
@@ -168,7 +166,7 @@ ```js | ||
Don’t forget to check the safety of your ID length | ||
Don’t forget to check the safety of your ID size | ||
in our [ID collision probability] calculator. | ||
You can also use [custom alphabet](#custom-alphabet-or-length) | ||
or [random generator](#custom-random-bytes-generator). | ||
You can also use a [custom alphabet](#custom-alphabet-or-size) | ||
or a [random generator](#custom-random-bytes-generator). | ||
@@ -180,5 +178,7 @@ [ID collision probability]: https://zelark.github.io/nano-id-cc/ | ||
**Do not** use a nanoid for `key` prop. In React `key` should be consistence | ||
between renders. This is bad code: | ||
**Do not** call `nanoid` in the `key` prop. In React, `key` should be consistent | ||
among renders. | ||
This is the bad example: | ||
```jsx | ||
@@ -188,3 +188,3 @@ <Item key={nanoid()} /> /* DON’T DO IT */ | ||
This is good code. `id` will be generated only once: | ||
This is the good example (`id` will be generated only once): | ||
@@ -198,4 +198,4 @@ ```jsx | ||
If you want to use Nano ID for `id`, you must to set some string prefix. | ||
Nano ID could be started from number. HTML ID can’t be started from the number. | ||
If you want to use Nano ID in the `key` prop, you must set some string prefix | ||
(it is invalid for the HTML ID to start with a number). | ||
@@ -209,16 +209,15 @@ ```jsx | ||
React Native doesn’t have built-in random generator. | ||
React Native does not have built-in random generator. | ||
1. Check [`expo-random`] docs and install it. | ||
2. Use `nanoid/async` instead of synchronous `nanoid`. | ||
1. Check [`react-native-get-random-values`] docs and install it. | ||
2. Import it before Nano ID. | ||
```js | ||
const nanoid = require('nanoid/async') | ||
async function createUser () { | ||
user.id = await nanoid() | ||
} | ||
import 'react-native-get-random-values' | ||
import { nanoid } from 'nanoid' | ||
``` | ||
[`react-native-get-random-values`]: https://github.com/LinusU/react-native-get-random-values | ||
### PouchDB and CouchDB | ||
@@ -252,23 +251,43 @@ | ||
### Web Workers | ||
### ES Modules | ||
Web Workers don’t have access to a secure random generator. | ||
Nano ID provides ES modules. You do not need to do anything to use Nano ID | ||
as ESM in webpack, Parcel, or Node.js. | ||
Security is important in IDs, when IDs should be unpredictable. For instance, | ||
in “access by URL” link generation. | ||
```js | ||
import { nanoid } from 'nanoid' | ||
``` | ||
If you don’t need unpredictable IDs, but you need Web Workers support, | ||
you can use non‑secure ID generator. Note, that they have bigger collision | ||
probability. | ||
For quick hacks, you can load Nano ID from CDN. Special minified | ||
`nanoid.js` module is available on jsDelivr. | ||
Though, it is not recommended to be used in production | ||
because of the lower performance. | ||
```js | ||
const nanoid = require('nanoid/non-secure') | ||
import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js' | ||
``` | ||
### Web Workers | ||
Web Workers do not have access to a secure random generator. | ||
Security is important in IDs, when IDs should be unpredictable. | ||
For instance, in "access by URL" link generation. | ||
If you do not need unpredictable IDs, but you need to use Web Workers, | ||
you can use the non‑secure ID generator. | ||
```js | ||
import { nanoid } from 'nanoid/non-secure' | ||
nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ" | ||
``` | ||
Note: non-secure IDs are more prone to collision attacks. | ||
### Other Programming Languages | ||
Nano ID was ported to many languages. You can use these ports to have the same | ||
ID generators on client and server side. | ||
Nano ID was ported to many languages. You can use these ports to have | ||
the same ID generator on the client and server side. | ||
@@ -285,3 +304,4 @@ * [C#](https://github.com/codeyu/nanoid-net) | ||
* [PHP](https://github.com/hidehalo/nanoid-php) | ||
* [Python](https://github.com/puyuan/py-nanoid) with [dictionaries](https://pypi.org/project/nanoid-dictionary) | ||
* [Python](https://github.com/puyuan/py-nanoid) | ||
with [dictionaries](https://pypi.org/project/nanoid-dictionary) | ||
* [Ruby](https://github.com/radeno/nanoid.rb) | ||
@@ -300,10 +320,11 @@ * [Rust](https://github.com/nikolay-govorov/nanoid) | ||
To generate hardware random bytes, CPU will collect electromagnetic noise. | ||
During the collection, CPU doesn’t work. | ||
To generate hardware random bytes, CPU collects electromagnetic noise. | ||
In the synchronous API during the noise collection, | ||
the CPU does not do anything useful. | ||
If we will use asynchronous API for random generator, | ||
another code could be executed during the entropy collection. | ||
Using the asynchronous API of Nano ID, another code can run during | ||
the entropy collection. | ||
```js | ||
const nanoid = require('nanoid/async') | ||
import { nanoid } from 'nanoid/async' | ||
@@ -315,4 +336,5 @@ async function createUser () { | ||
Unfortunately, you will not have any benefits in a browser, since Web Crypto API | ||
doesn’t have asynchronous API. | ||
Unfortunately, you will lose Web Crypto API advantages in a browser | ||
if you the asynchronous API. So, currently, in the browser, you are limited | ||
with either security or asynchronous behavior. | ||
@@ -322,37 +344,39 @@ | ||
By default, Nano ID uses hardware random generator for security | ||
and low collision probability. If you don’t need it, you can use | ||
very fast non-secure generator. | ||
By default, Nano ID uses hardware random bytes generation for security | ||
and low collision probability. If you are not so concerned with security | ||
and more with performance, you can use the faster non-secure generator. | ||
```js | ||
const nonSecure = require('nanoid/non-secure') | ||
const id = nonSecure() //=> "Uakgb_J5m9g-0JDMbcJqLJ" | ||
import { nanoid } from 'nanoid/non-secure' | ||
const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ" | ||
``` | ||
Note that it is predictable and have bigger collision probability. | ||
Note: your IDs will be more predictable and prone to collision attacks. | ||
### Custom Alphabet or Length | ||
### Custom Alphabet or Size | ||
If you want to change the ID's alphabet or length | ||
you can use the low-level `generate` module. | ||
`customAlphabet` allows you to create `nanoid` with your own alphabet | ||
and ID size. | ||
```js | ||
const generate = require('nanoid/generate') | ||
model.id = generate('1234567890abcdef', 10) //=> "4f90d13a42" | ||
import { customAlphabet } from 'nanoid' | ||
const nanoid = customAlphabet('1234567890abcdef', 10) | ||
model.id = nanoid() //=> "4f90d13a42" | ||
``` | ||
Check the safety of your custom alphabet and ID length | ||
in our [ID collision probability] calculator. | ||
You can find popular alphabets in [`nanoid-dictionary`]. | ||
Check the safety of your custom alphabet and ID size in our | ||
[ID collision probability] calculator. For more alphabets, check out the options | ||
in [`nanoid-dictionary`]. | ||
Alphabet must contain 256 symbols or less. | ||
Otherwise, the generator will not be secure. | ||
Otherwise, the security of the internal generator algorithm is not guaranteed. | ||
Asynchronous and non-secure API is also available: | ||
Customizable asynchronous and non-secure APIs are also available: | ||
```js | ||
const generate = require('nanoid/async/generate') | ||
import { customAlphabet } from 'nanoid/async' | ||
const nanoid = customAlphabet('1234567890abcdef', 10) | ||
async function createUser () { | ||
user.id = await generate('1234567890abcdef', 10) | ||
user.id = await nanoid() | ||
} | ||
@@ -362,5 +386,5 @@ ``` | ||
```js | ||
const generate = require('nanoid/non-secure/generate') | ||
user.id = generate('1234567890abcdef', 10) | ||
import { customAlphabet } from 'nanoid/non-secure' | ||
const nanoid = customAlphabet('1234567890abcdef', 10) | ||
user.id = nanoid() | ||
``` | ||
@@ -374,17 +398,16 @@ | ||
You can replace the default safe random generator using the `format` module. | ||
For instance, to use a seed-based generator. | ||
`customRandom` allows you to create a `nanoid` and replace alphabet | ||
and the default random bytes generator. | ||
In this example, a seed-based generator is used: | ||
```js | ||
const format = require('nanoid/format') | ||
import { customRandom } from 'nanoid' | ||
function random (size) { | ||
const result = [] | ||
for (let i = 0; i < size; i++) { | ||
result.push(randomByte()) | ||
} | ||
return result | ||
} | ||
const rng = seedrandom(seed) | ||
const nanoid = customRandom('abcdef', 10, size => { | ||
return (new Uint8Array(size)).map(() => 256 * rng()) | ||
}) | ||
format(random, "abcdef", 10) //=> "fbaefaadeb" | ||
nanoid() //=> "fbaefaadeb" | ||
``` | ||
@@ -395,23 +418,10 @@ | ||
If you want to use the same URL-friendly symbols with `format`, | ||
you can get the default alphabet from the `url` file. | ||
If you want to use the same URL-friendly symbols with `customRandom`, | ||
you can get the default alphabet using the `urlAlphabet`. | ||
```js | ||
const url = require('nanoid/url') | ||
format(random, url, 10) //=> "93ce_Ltuub" | ||
const { customRandom, urlAlphabet } = require('nanoid') | ||
const nanoid = customRandom(urlAlphabet, 10, random) | ||
``` | ||
Asynchronous API is also available: | ||
```js | ||
const format = require('nanoid/async/format') | ||
const url = require('nanoid/url') | ||
function random (size) { | ||
return new Promise(…) | ||
} | ||
async function createUser () { | ||
user.id = await format(random, url, 10) | ||
} | ||
``` | ||
Asynchronous and non-secure APIs are not available for `customRandom`. |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
42198
619
408
Yes
18
1