+0
-27
@@ -1,5 +0,2 @@ | ||
| /* @ts-self-types="./index.d.ts" */ | ||
| // This file replaces `index.js` in bundlers like webpack or Rollup, | ||
| // according to `browser` config in `package.json`. | ||
@@ -13,15 +10,4 @@ import { urlAlphabet as scopedUrlAlphabet } from './url-alphabet/index.js' | ||
| export let customRandom = (alphabet, defaultSize, getRandom) => { | ||
| // Random bytes are 0-255. `random % alphabet.length` can waste | ||
| // that entropy by making some symbols more likely. | ||
| // | ||
| // `safeByteCutoff` will be divided by `alphabet.length` without remainder | ||
| // fixing issue of broken distribution. | ||
| // | ||
| // Example: with 17 symbols, `safeByteCutoff` is 255. | ||
| // Bytes 0-254 preserve entropy evenly: each symbol gets 15 source bytes. | ||
| // Byte 255 would map to `0` again, making one symbol slightly more likely. | ||
| // So we reject 255. | ||
| let safeByteCutoff = 256 - (256 % alphabet.length) | ||
| // Power-of-two alphabets can use `& mask` instead of modulo. | ||
| if (safeByteCutoff === 256) { | ||
@@ -35,6 +21,4 @@ let mask = alphabet.length - 1 | ||
| let bytes = getRandom(size) | ||
| // A compact alternative for `for (var i = 0; i < step; i++)`. | ||
| let j = size | ||
| while (j--) { | ||
| // Here, `& mask` is equivalent to `% alphabet.length`, but faster | ||
| id += alphabet[bytes[j] & mask] | ||
@@ -47,8 +31,2 @@ if (id.length >= size) return id | ||
| // Secure random calls are expensive because system calls | ||
| // for entropy collection take time. To avoid extra calls, | ||
| // extra bytes are requested in advance to cover rejections. | ||
| // | ||
| // `step` determines how many random bytes to request. | ||
| // `1.6` is a magic number chosen from benchmarks. | ||
| let step = Math.ceil((1.6 * 256 * defaultSize) / safeByteCutoff) | ||
@@ -61,7 +39,4 @@ | ||
| let bytes = getRandom(step) | ||
| // A compact alternative for `for (var i = 0; i < step; i++)`. | ||
| let j = step | ||
| while (j--) { | ||
| // Reject bytes >= `safeByteCutoff` to avoid modulo bias | ||
| // and give each symbol an equal chance. | ||
| if (bytes[j] < safeByteCutoff) { | ||
@@ -83,4 +58,2 @@ id += alphabet[bytes[j] % alphabet.length] | ||
| while (size--) { | ||
| // The following mask reduces the random byte in the 0-255 value | ||
| // range to the 0-63 value range. | ||
| id += scopedUrlAlphabet[bytes[size] & 63] | ||
@@ -87,0 +60,0 @@ } |
+0
-34
@@ -7,7 +7,2 @@ import { webcrypto as crypto } from 'node:crypto' | ||
| // It is best to make fewer, larger requests to the crypto module to | ||
| // avoid system call overhead. So, random numbers are generated in a | ||
| // pool. The pool is a Buffer that is larger than the initial random | ||
| // request size by this multiplier. The pool is enlarged if subsequent | ||
| // requests exceed the maximum buffer size. | ||
| const POOL_SIZE_MULTIPLIER = 128 | ||
@@ -30,4 +25,2 @@ let pool, poolOffset | ||
| export function random(bytes) { | ||
| // `|=` convert `bytes` to number to prevent `valueOf` abusing | ||
| // and pool pollution | ||
| fillPool((bytes |= 0)) | ||
@@ -38,15 +31,4 @@ return pool.subarray(poolOffset - bytes, poolOffset) | ||
| export function customRandom(alphabet, defaultSize, getRandom) { | ||
| // Random bytes are 0-255. `random % alphabet.length` can waste | ||
| // that entropy by making some symbols more likely. | ||
| // | ||
| // `safeByteCutoff` will be divided by `alphabet.length` without remainder | ||
| // fixing issue of broken distribution. | ||
| // | ||
| // Example: with 17 symbols, `safeByteCutoff` is 255. | ||
| // Bytes 0-254 preserve entropy evenly: each symbol gets 15 source bytes. | ||
| // Byte 255 would map to `0` again, making one symbol slightly more likely. | ||
| // So we reject 255. | ||
| let safeByteCutoff = 256 - (256 % alphabet.length) | ||
| // Power-of-two alphabets can use `& mask` instead of modulo. | ||
| if (safeByteCutoff === 256) { | ||
@@ -60,6 +42,4 @@ let mask = alphabet.length - 1 | ||
| let bytes = getRandom(size) | ||
| // A compact alternative for `for (let i = 0; i < step; i++)`. | ||
| let i = size | ||
| while (i--) { | ||
| // Here, `& mask` is equivalent to `% alphabet.length`, but faster | ||
| id += alphabet[bytes[i] & mask] | ||
@@ -72,8 +52,2 @@ if (id.length >= size) return id | ||
| // Secure random calls are expensive because system calls | ||
| // for entropy collection take time. To avoid extra calls, | ||
| // extra bytes are requested in advance to cover rejections. | ||
| // | ||
| // `step` determines how many random bytes to request. | ||
| // `1.6` is a magic number chosen from benchmarks. | ||
| let step = Math.ceil((1.6 * 256 * defaultSize) / safeByteCutoff) | ||
@@ -86,7 +60,4 @@ | ||
| let bytes = getRandom(step) | ||
| // A compact alternative for `for (let i = 0; i < step; i++)`. | ||
| let i = step | ||
| while (i--) { | ||
| // Reject bytes >= `safeByteCutoff` to avoid modulo bias | ||
| // and give each symbol an equal chance. | ||
| if (bytes[i] < safeByteCutoff) { | ||
@@ -106,11 +77,6 @@ id += alphabet[bytes[i] % alphabet.length] | ||
| export function nanoid(size = 21) { | ||
| // `|=` convert `size` to number to prevent `valueOf` abusing | ||
| // and pool pollution | ||
| fillPool((size |= 0)) | ||
| let id = '' | ||
| // We are reading directly from the random pool to avoid creating new array | ||
| for (let i = poolOffset - size; i < poolOffset; i++) { | ||
| // The following mask reduces the random byte in the 0-255 value | ||
| // range to the 0-63 value range. | ||
| id += scopedUrlAlphabet[pool[i] & 63] | ||
@@ -117,0 +83,0 @@ } |
+0
-11
@@ -1,9 +0,2 @@ | ||
| /* @ts-self-types="./index.d.ts" */ | ||
| // This alphabet uses `A-Za-z0-9_-` symbols. | ||
| // The order of characters is optimized for better gzip and brotli compression. | ||
| // References to the same file (works both for gzip and brotli): | ||
| // `'use`, `andom`, and `rict'` | ||
| // References to the brotli default dictionary: | ||
| // `-26T`, `1983`, `40px`, `75px`, `bush`, `jack`, `mind`, `very`, and `wolf` | ||
| let urlAlphabet = | ||
@@ -15,6 +8,4 @@ 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict' | ||
| let id = '' | ||
| // A compact alternative for `for (var i = 0; i < step; i++)`. | ||
| let i = size | 0 | ||
| while (i--) { | ||
| // `| 0` is more compact and faster than `Math.floor()`. | ||
| id += alphabet[(Math.random() * alphabet.length) | 0] | ||
@@ -28,6 +19,4 @@ } | ||
| let id = '' | ||
| // A compact alternative for `for (var i = 0; i < step; i++)`. | ||
| let i = size | 0 | ||
| while (i--) { | ||
| // `| 0` is more compact and faster than `Math.floor()`. | ||
| id += urlAlphabet[(Math.random() * 64) | 0] | ||
@@ -34,0 +23,0 @@ } |
+1
-1
| { | ||
| "name": "nanoid", | ||
| "version": "5.1.13", | ||
| "version": "5.1.14", | ||
| "description": "A tiny (118 bytes), secure URL-friendly unique string ID generator", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
+0
-450
@@ -35,451 +35,1 @@ # Nano ID | ||
| [Size Limit]: https://github.com/ai/size-limit | ||
| ## Table of Contents | ||
| - [Table of Contents](#table-of-contents) | ||
| - [Comparison with UUID](#comparison-with-uuid) | ||
| - [Benchmark](#benchmark) | ||
| - [Security](#security) | ||
| - [Install](#install) | ||
| - [ESM](#esm) | ||
| - [CommonJS](#commonjs) | ||
| - [JSR](#jsr) | ||
| - [CDN](#cdn) | ||
| - [API](#api) | ||
| - [Blocking](#blocking) | ||
| - [Non-Secure](#non-secure) | ||
| - [Custom Alphabet or Size](#custom-alphabet-or-size) | ||
| - [Custom Random Bytes Generator](#custom-random-bytes-generator) | ||
| - [Usage](#usage) | ||
| - [React](#react) | ||
| - [React Native](#react-native) | ||
| - [PouchDB and CouchDB](#pouchdb-and-couchdb) | ||
| - [CLI](#cli) | ||
| - [TypeScript](#typescript) | ||
| - [Other Programming Languages](#other-programming-languages) | ||
| - [Tools](#tools) | ||
| ## Comparison with UUID | ||
| Nano ID is quite comparable to UUID v4 (random-based). | ||
| It has a similar number of random bits in the ID | ||
| (126 in Nano ID and 122 in UUID), so it has a similar collision probability: | ||
| > For there to be a one in a billion chance of duplication, | ||
| > 103 trillion version 4 IDs must be generated. | ||
| There are two main differences between Nano ID and UUID v4: | ||
| 1. Nano ID uses a bigger alphabet, so a similar number of random bits | ||
| are packed in just 21 symbols instead of 36. | ||
| 2. Nano ID code is **4 times smaller** than `uuid/v4` package: | ||
| 118 bytes instead of 423. | ||
| ## Benchmark | ||
| ```rust | ||
| $ node ./test/benchmark.js | ||
| nope-id 27,398,074 ops/sec | ||
| crypto.randomUUID 14,055,107 ops/sec | ||
| uuid v4 9,256,301 ops/sec | ||
| @napi-rs/uuid 7,100,180 ops/sec | ||
| uid/secure 7,312,765 ops/sec | ||
| @lukeed/uuid 5,543,254 ops/sec | ||
| nanoid 4,954,561 ops/sec | ||
| customAlphabet 6,708,339 ops/sec | ||
| nanoid for browser 497,980 ops/sec | ||
| secure-random-string 412,049 ops/sec | ||
| uid-safe.sync 420,669 ops/sec | ||
| Non-secure: | ||
| uid 27,106,859 ops/sec | ||
| nanoid/non-secure 2,672,540 ops/sec | ||
| rndm 2,666,518 ops/sec | ||
| ``` | ||
| Test configuration: Framework 13 7840U, Fedora 39, Node.js 21.6. | ||
| ## Security | ||
| _See a good article about random generators theory: | ||
| [Secure random values (in Node.js)]_ | ||
| - **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. | ||
| <img src="img/distribution.png" alt="Nano ID uniformity" | ||
| width="340" height="135"> | ||
| - **Well-documented:** all Nano ID hacks are documented. See comments | ||
| in [the source]. | ||
| - **Vulnerabilities:** to report a security vulnerability, please use | ||
| the [Tidelift security contact](https://tidelift.com/security). | ||
| Tidelift will coordinate the fix and disclosure. | ||
| [Secure random values (in Node.js)]: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba | ||
| [better algorithm]: https://github.com/ai/nanoid/blob/main/index.js | ||
| [the source]: https://github.com/ai/nanoid/blob/main/index.js | ||
| ## Install | ||
| ### ESM | ||
| Nano ID 5 works with ESM projects (with `import`) in tests or Node.js scripts. | ||
| ```bash | ||
| npm install nanoid | ||
| ``` | ||
| ### CommonJS | ||
| Nano ID can be used with CommonJS in one of the following ways: | ||
| - You can use `require()` to import Nano ID. You need to use latest Node.js | ||
| 22.12 (works out-of-the-box) or Node.js 20 | ||
| (with `--experimental-require-module`). | ||
| - For Node.js 18 you can dynamically import Nano ID as follows: | ||
| ```js | ||
| let nanoid | ||
| module.exports.createID = async () => { | ||
| if (!nanoid) ({ nanoid } = await import('nanoid')) | ||
| return nanoid() // => "V1StGXR8_Z5jdHi6B-myT" | ||
| } | ||
| ``` | ||
| - You can use Nano ID 3.x (we still support it): | ||
| ```bash | ||
| npm install nanoid@3 | ||
| ``` | ||
| ### JSR | ||
| [JSR](https://jsr.io) is a replacement for npm with open governance | ||
| and active development (in contrast to npm). | ||
| ```bash | ||
| npx jsr add @sitnik/nanoid | ||
| ``` | ||
| You can use it in Node.js, Deno, Bun, etc. | ||
| ```js | ||
| // Replace `nanoid` to `@sitnik/nanoid` in all imports | ||
| import { nanoid } from '@sitnik/nanoid' | ||
| ``` | ||
| For Deno install it by `deno add jsr:@sitnik/nanoid` or import | ||
| from `jsr:@sitnik/nanoid`. | ||
| ### CDN | ||
| For quick hacks, you can load Nano ID from CDN. Though, it is not recommended | ||
| to be used in production because of the lower loading performance. | ||
| ```js | ||
| import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js' | ||
| ``` | ||
| ## API | ||
| Nano ID has 2 APIs: normal and non-secure. | ||
| By default, Nano ID uses URL-friendly symbols (`A-Za-z0-9_-`) and returns an ID | ||
| with 21 characters (to have a collision probability similar to UUID v4). | ||
| ### Blocking | ||
| The safe and easiest way to use Nano ID. | ||
| In rare cases could block CPU from other work while noise collection | ||
| for hardware random generator. | ||
| ```js | ||
| import { nanoid } from 'nanoid' | ||
| model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT" | ||
| ``` | ||
| If you want to reduce the ID size (and increase collisions probability), | ||
| you can pass the size as an argument. | ||
| ```js | ||
| nanoid(10) //=> "IRFa-VaY2b" | ||
| ``` | ||
| Don’t forget to check the safety of your ID size | ||
| in our [ID collision probability] calculator. | ||
| You can also use a [custom alphabet](#custom-alphabet-or-size) | ||
| or a [random generator](#custom-random-bytes-generator). | ||
| [ID collision probability]: https://zelark.github.io/nano-id-cc/ | ||
| ### Non-Secure | ||
| By default, Nano ID uses hardware random bytes generation for security | ||
| and low collision probability. If you are not so concerned with security, | ||
| you can use it for environments without hardware random generators. | ||
| ```js | ||
| import { nanoid } from 'nanoid/non-secure' | ||
| const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ" | ||
| ``` | ||
| ### Custom Alphabet or Size | ||
| `customAlphabet` returns a function that allows you to create `nanoid` | ||
| with your own alphabet and ID size. | ||
| ```js | ||
| import { customAlphabet } from 'nanoid' | ||
| const nanoid = customAlphabet('1234567890abcdef', 10) | ||
| model.id = nanoid() //=> "4f90d13a42" | ||
| ``` | ||
| ```js | ||
| import { customAlphabet } from 'nanoid/non-secure' | ||
| const nanoid = customAlphabet('1234567890abcdef', 10) | ||
| user.id = nanoid() | ||
| ``` | ||
| 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 security of the internal generator algorithm is not guaranteed. | ||
| In addition to setting a default size, you can change the ID size when calling | ||
| the function: | ||
| ```js | ||
| import { customAlphabet } from 'nanoid' | ||
| const nanoid = customAlphabet('1234567890abcdef', 10) | ||
| model.id = nanoid(5) //=> "f01a2" | ||
| ``` | ||
| [`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary | ||
| ### Custom Random Bytes 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 | ||
| import { customRandom } from 'nanoid' | ||
| const rng = seedrandom(seed) | ||
| const nanoid = customRandom('abcdef', 10, size => { | ||
| return new Uint8Array(size).map(() => 256 * rng()) | ||
| }) | ||
| nanoid() //=> "fbaefaadeb" | ||
| ``` | ||
| `random` callback must accept the array size and return an array | ||
| with random numbers. | ||
| If you want to use the same URL-friendly symbols with `customRandom`, | ||
| you can get the default alphabet using the `urlAlphabet`. | ||
| ```js | ||
| import { customRandom, urlAlphabet } from 'nanoid' | ||
| const nanoid = customRandom(urlAlphabet, 10, random) | ||
| ``` | ||
| Note, that between Nano ID versions we may change random generator | ||
| call sequence. If you are using seed-based generators, we do not guarantee | ||
| the same result. | ||
| ## Usage | ||
| ### React | ||
| There’s no correct way to use Nano ID for React `key` prop | ||
| since it should be consistent among renders. | ||
| ```jsx | ||
| function Todos({ todos }) { | ||
| return ( | ||
| <ul> | ||
| {todos.map(todo => ( | ||
| <li key={nanoid()}> | ||
| {' '} | ||
| /* DON’T DO IT */ | ||
| {todo.text} | ||
| </li> | ||
| ))} | ||
| </ul> | ||
| ) | ||
| } | ||
| ``` | ||
| You should rather try to reach for stable ID inside your list item. | ||
| ```jsx | ||
| const todoItems = todos.map(todo => <li key={todo.id}>{todo.text}</li>) | ||
| ``` | ||
| In case you don’t have stable IDs you'd rather use index as `key` | ||
| instead of `nanoid()`: | ||
| ```jsx | ||
| const todoItems = todos.map((text, index) => ( | ||
| <li key={index}> | ||
| {' '} | ||
| /* Still not recommended but preferred over nanoid(). Only do this if items | ||
| have no stable IDs. */ | ||
| {text} | ||
| </li> | ||
| )) | ||
| ``` | ||
| In case you just need random IDs to link elements like labels | ||
| and input fields together, [`useId`] is recommended. | ||
| That hook was added in React 18. | ||
| [`useId`]: https://react.dev/reference/react/useId | ||
| ### React Native | ||
| React Native does not have built-in random generator. The following polyfill | ||
| works for plain React Native and Expo starting with `39.x`. | ||
| 1. Check [`react-native-get-random-values`] docs and install it. | ||
| 2. Import it before Nano ID. | ||
| ```js | ||
| 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 | ||
| In PouchDB and CouchDB, IDs can’t start with an underscore `_`. | ||
| A prefix is required to prevent this issue, as Nano ID might use a `_` | ||
| at the start of the ID by default. | ||
| Override the default ID with the following option: | ||
| ```js | ||
| db.put({ | ||
| _id: 'id' + nanoid(), | ||
| … | ||
| }) | ||
| ``` | ||
| ### CLI | ||
| You can get unique ID in terminal by calling `npx nanoid`. You need only | ||
| Node.js in the system. You do not need Nano ID to be installed anywhere. | ||
| ```sh | ||
| $ npx nanoid | ||
| npx: installed 1 in 0.63s | ||
| LZfXLFzPPR4NNrgjlWDxn | ||
| ``` | ||
| Size of generated ID can be specified with `--size` (or `-s`) option: | ||
| ```sh | ||
| $ npx nanoid --size 10 | ||
| L3til0JS4z | ||
| ``` | ||
| Custom alphabet can be specified with `--alphabet` (or `-a`) option | ||
| (note that in this case `--size` is required): | ||
| ```sh | ||
| $ npx nanoid --alphabet abc --size 15 | ||
| bccbcabaabaccab | ||
| ``` | ||
| ### TypeScript | ||
| Nano ID allows casting generated strings into opaque strings in TypeScript. | ||
| For example: | ||
| ```ts | ||
| declare const userIdBrand: unique symbol | ||
| type UserId = string & { [userIdBrand]: true } | ||
| // Use explicit type parameter: | ||
| mockUser(nanoid<UserId>()) | ||
| interface User { | ||
| id: UserId | ||
| name: string | ||
| } | ||
| const user: User = { | ||
| // Automatically casts to UserId: | ||
| id: nanoid(), | ||
| name: 'Alice' | ||
| } | ||
| ``` | ||
| ### Other Programming Languages | ||
| Nano ID was ported to many languages. You can use these ports to have | ||
| the same ID generator on the client and server side. | ||
| - [C](https://github.com/lukateras/nanoid.h) | ||
| - [C#](https://github.com/codeyu/nanoid-net) | ||
| - [C++](https://github.com/mcmikecreations/nanoid_cpp) | ||
| - [Clojure and ClojureScript](https://github.com/zelark/nano-id) | ||
| - [ColdFusion/CFML](https://github.com/JamoCA/cfml-nanoid) | ||
| - [Crystal](https://github.com/mamantoha/nanoid.cr) | ||
| - [Dart & Flutter](https://github.com/pd4d10/nanoid-dart) | ||
| - [Elixir](https://github.com/railsmechanic/nanoid) | ||
| - [Gleam](https://github.com/0xca551e/glanoid) | ||
| - [Go](https://github.com/matoous/go-nanoid) | ||
| - [Haskell](https://github.com/MichelBoucey/NanoID) | ||
| - [Haxe](https://github.com/flashultra/uuid) | ||
| - [Janet](https://sr.ht/~statianzo/janet-nanoid/) | ||
| - [Java](https://github.com/wosherco/jnanoid-enhanced) | ||
| - [Kotlin](https://github.com/viascom/nanoid-kotlin) | ||
| - [MySQL/MariaDB](https://github.com/viascom/nanoid-mysql-mariadb) | ||
| - [Nim](https://github.com/icyphox/nanoid.nim) | ||
| - [OCaml](https://github.com/routineco/ocaml-nanoid) | ||
| - [Perl](https://github.com/tkzwtks/Nanoid-perl) | ||
| - [PHP](https://github.com/hidehalo/nanoid-php) | ||
| - Python [native](https://github.com/puyuan/py-nanoid) implementation | ||
| with [dictionaries](https://pypi.org/project/nanoid-dictionary) | ||
| and [fast](https://github.com/oliverlambson/fastnanoid) implementation (written in Rust) | ||
| - Postgres [Extension](https://github.com/spa5k/uids-postgres) | ||
| and [Native Function](https://github.com/viascom/nanoid-postgres) | ||
| - [R](https://github.com/hrbrmstr/nanoid) (with dictionaries) | ||
| - [Ruby](https://github.com/radeno/nanoid.rb) | ||
| - [Rust](https://github.com/nikolay-govorov/nanoid) | ||
| - [Swift](https://github.com/ShivaHuang/swift-nanoid) | ||
| - [Unison](https://share.unison-lang.org/latest/namespaces/hojberg/nanoid) | ||
| - [V](https://github.com/invipal/nanoid) | ||
| - [Zig](https://github.com/SasLuca/zig-nanoid) | ||
| For other environments, [CLI] is available to generate IDs from a command line. | ||
| [CLI]: #cli | ||
| ## Tools | ||
| - [ID size calculator] shows collision probability when adjusting | ||
| the ID alphabet or size. | ||
| - [`nanoid-dictionary`] with popular alphabets to use with [`customAlphabet`]. | ||
| - [`nanoid-good`] to be sure that your ID doesn’t contain any obscene words. | ||
| [`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary | ||
| [ID size calculator]: https://zelark.github.io/nano-id-cc/ | ||
| [`customAlphabet`]: #custom-alphabet-or-size | ||
| [`nanoid-good`]: https://github.com/y-gagar1n/nanoid-good |
@@ -1,5 +0,2 @@ | ||
| // This alphabet uses `A-Za-z0-9_-` symbols. | ||
| // The order of characters is optimized for better gzip and brotli compression. | ||
| // Same as in non-secure/index.js | ||
| export let urlAlphabet = | ||
| 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict' |
13571
-55.77%335
-18.29%35
-92.78%