diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 1889eded..a68bd0ef 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -2,42 +2,93 @@ name: Test
on:
push:
pull_request:
-env:
- FORCE_COLOR: 2
jobs:
full:
- name: Node.js 16 Full
+ name: Node.js 17 Full
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v2
+ - name: Install pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: latest
- name: Install Node.js
uses: actions/setup-node@v2
with:
- node-version: 16
+ node-version: 17
+ cache: pnpm
- name: Install dependencies
- uses: bahmutov/npm-install@v1
+ run: pnpm install --frozen-lockfile --ignore-scripts
- name: Run tests
- run: yarn test
+ run: pnpm test
+ env:
+ FORCE_COLOR: 2
short:
runs-on: ubuntu-latest
strategy:
matrix:
node-version:
+ - 16
- 14
- 12
- - 10
name: Node.js ${{ matrix.node-version }} Quick
steps:
- name: Checkout the repository
uses: actions/checkout@v2
+ - name: Install pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: latest
- name: Install Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
+ cache: pnpm
- name: Install dependencies
- uses: bahmutov/npm-install@v1
+ run: pnpm install --frozen-lockfile --ignore-scripts
+ - name: Run unit tests
+ run: pnpm unit
+ env:
+ FORCE_COLOR: 2
+ old:
+ runs-on: ubuntu-latest
+ name: Node.js 10 Quick
+ steps:
+ - name: Checkout the repository
+ uses: actions/checkout@v2
+ - name: Install pnpm
+ uses: pnpm/action-setup@v1
with:
- install-command: yarn install --ignore-engines
+ version: 3
+ env:
+ ACTIONS_ALLOW_UNSECURE_COMMANDS: true
+ - name: Install Node.js 10
+ uses: actions/setup-node@v2
+ with:
+ node-version: 10
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile --ignore-scripts
- name: Run unit tests
- run: npx jest
+ run: pnpm unit
+ env:
+ FORCE_COLOR: 2
+ benchmark:
+ name: Benchmark
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout the repository
+ uses: actions/checkout@v2
+ - name: Install pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: latest
+ - name: Install Node.js
+ uses: actions/setup-node@v2
+ with:
+ node-version: 16
+ cache: pnpm
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile --ignore-scripts
+ - name: Run benchmark
+ run: ./test/benchmark.js
diff --git a/.gitignore b/.gitignore
index 23568247..c6b9df27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,3 @@
node_modules/
-yarn-error.log
coverage/
-
-test/demo/build
-.parcel-cache
diff --git a/.npmignore b/.npmignore
index 33c122ce..1b3def76 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,9 +1,5 @@
-yarn-error.log
-yarn.lock
-
test/
tsconfig.json
coverage/
img/
-.parcel-cache
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aa63f807..2a346d56 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,32 @@
# Change Log
This project adheres to [Semantic Versioning](http://semver.org/).
+## 3.2
+* Added `--size` and `--alphabet` arguments to binary (by Vitaly Baev).
+
+## 3.1.32
+* Reduced `async` exports size (by Artyom Arutyunyan).
+* Moved from Jest to uvu (by Vitaly Baev).
+
+## 3.1.31
+* Fixed collision vulnerability on object in `size` (by Artyom Arutyunyan).
+
+## 3.1.30
+* Reduced size for project with `brotli` compression (by Anton Khlynovskiy).
+
+## 3.1.29
+* Reduced npm package size.
+
+## 3.1.28
+* Reduced npm package size.
+
+## 3.1.27
+* Cleaned `dependencies` from development tools.
+
+## 3.1.26
+* Improved performance (by Eitan Har-Shoshanim).
+* Reduced npm package size.
+
## 3.1.25
* Fixed `browserify` support.
diff --git a/README.id-ID.md b/README.id-ID.md
new file mode 100644
index 00000000..06acfb1f
--- /dev/null
+++ b/README.id-ID.md
@@ -0,0 +1,411 @@
+# Nano ID
+
+
+
+[English](./README.md) | [Русский](./README.ru.md) | [简体中文](./README.zh-CN.md) | **Bahasa Indonesia**
+
+Sebuah generator ID yang unik dalam bentuk string yang ringan, aman, serta _URL-friendly_ untuk JavaScript.
+
+> "Sebuah tingkat kesempurnaan yang luar biasa,
+> yang mana tidak mungkin untuk tidak dihormati."
+
+- **Ringan.** Hanya 130 bytes (diperkecil dan gzipped). Tidak ada ketergantungan (dependencies) apapun. [Size Limit](https://github.com/ai/size-limit) mengatur ukuran dari generator ini.
+- **Cepat.** Nano ID dua kali lipat lebih cepat dibanding UUID.
+- **Aman.** Nano ID menggunakan RNG yang terdapat pada perangkat keras. Dapat digunakan dalam lingkungan seperti klaster.
+- **ID yang pendek.** Nano ID menggunakan alfabet yang lebih banyak ketimbang UUID (`A-Za-z0-9_-`), karenanya ukuran ID menjadi berkurang dari 36 menjadi 21 simbol.
+- **Portabel.** Nano ID telah dimigrasi untuk [20 bahasa pemrograman lainnya](#bahasa-pemrograman-lainnya).
+
+```js
+import { nanoid } from 'nanoid'
+model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
+```
+
+Mendukung penjelajah (browser) modern, IE [dengan Babel](https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/), Node.js, dan React Native.
+
+
+
+
+
+## Table of Contents
+
+- [Perbandingan dengan UUID](#perbandingan-dengan-uuid)
+- [Benchmark](#benchmark)
+- [Keamanan](#keamanan)
+- [Instalasi](#instalasi)
+- [API](#api)
+ - [Blocking](#blocking)
+ - [Async](#async)
+ - [Non-Secure](#non-secure)
+ - [Alfabet dan Ukuran (Custom)](#alfabet-dan-ukuran-penyesuaian)
+ - [Generasi Random Bytes (Custom)](#generasi-random-bytes-custom)
+- [Penggunaan](#penggunaan)
+ - [IE](#ie)
+ - [React](#react)
+ - [React Native](#react-native)
+ - [Rollup](#rollup)
+ - [PouchDB dan CouchDB](#pouchdb-dan-couchdb)
+ - [Mongoose](#mongoose)
+ - [Web Workers](#web-workers)
+ - [CLI](#cli)
+ - [Bahasa Pemrograman Lainnya](#bahasa-pemrograman-lainnya)
+- [Alat](#alat)
+
+## Perbandingan dengan UUID
+
+Nano ID dapat dibandingkan dengan UUID v4 (yang berbasis acak / _randomly generated_). Nano ID dan UUID v4 memiliki jumlah bita yang mirip pada ID yang dihasilkan (126 bita pada NanoID dan 122 bita pada UUID), karenanya ia memiliki probabilitas _collision_ (konflik / tabrakan) yang hampir serupa:
+
+> Agar timbul kemungkinan collison / duplikasi ID satu dalam satu miliar, perlu dihasilkan 103 triliun UUID v4.
+
+Ada tiga buah perbedaan antara Nano ID dan UUID v4:
+
+1. Nano ID menggunakan alfabet yang lebih lebar, karenanya jumlah bita acak dapat 'dikemas' dalam 21 simbol, bukan 36 simbol.
+2. Kode sumber Nano ID **empat kali lebih kecil** ketimbang `uuid/v4`: 130 bytes dibanding 483 bytes.
+3. Karena menggunakan trik alokasi memori, Nano ID **dua kali lebih cepat** ketimbang UUID.
+
+## Benchmark
+
+```rust
+$ node ./test/benchmark.js
+crypto.randomUUID 25,603,857 ops/sec
+@napi-rs/uuid 9,973,819 ops/sec
+uid/secure 8,234,798 ops/sec
+@lukeed/uuid 7,464,706 ops/sec
+nanoid 5,616,592 ops/sec
+customAlphabet 3,115,207 ops/sec
+uuid v4 1,535,753 ops/sec
+secure-random-string 388,226 ops/sec
+uid-safe.sync 363,489 ops/sec
+cuid 187,343 ops/sec
+shortid 45,758 ops/sec
+
+Async:
+nanoid/async 96,094 ops/sec
+async customAlphabet 97,184 ops/sec
+async secure-random-string 92,794 ops/sec
+uid-safe 90,684 ops/sec
+
+Non-secure:
+uid 67,376,692 ops/sec
+nanoid/non-secure 2,849,639 ops/sec
+rndm 2,674,806 ops/sec
+```
+
+Konfigurasi pengujian: ThinkPad X1 Carbon Gen 9, Fedora 34, Node.js 16.10.
+
+## Keamanan
+
+_Lihat artikel yang informatif tentang teori angka acak: [Nilai acak yang aman dalam Node.js (English)](https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba)_.
+
+- **Ketidakpastian.** Sebagai ganti untuk penggunaan `Math.random()`, Nano ID menggunakan modul `crypto` yang ada di dalam Nodejs dan/atau Web Crypto API dalam penjelajah (_browser_). Modul-modul ini menggunakan generator acak berbasis perangkat keras yang tidak bisa diprediksi untuk mendapatkan nilai-nilai yang tidak pasti yang aman secara kriptografis.
+
+- **Keseragaman.** Pembagian dengan rumus `random % alphabet` adalah kesalahan yang seringkali dilakukan ketika merancang sebuah generator ID. Distribusi dari nilai-nilai tersebut tidak akan seimbang; dalam artian ada kesempatan untuk beberapa simbol untuk muncul dibandingkan dengan simbol yang lain. Ini memiliki dampak yang kurang baik, yakni mengurangi jumlah percobaan ketika seseorang mencoba untuk melakukan _brute-force attacks_. Nano ID menggunakan [algoritma yang lebih baik](https://github.com/ai/nanoid/blob/main/index.js) dan sudah diuji untuk keseragamannya.
+
+
+
+- **Terdokumentasi secara baik.** Seluruh algoritma Nano ID sudah terdokumentasi. Lihat komentar di [kode sumber](https://github.com/ai/nanoid/blob/main/index.js).
+
+- **Kerentanan.** Untuk melaporkan sebuah _security vulnerability_ atau kerentanan, mohon menggunakan [Tidelift Security Contact](https://tidelift.com/security). Tidelift akan mengkoordinasikan pembetulan dan penyingkapan dari kerentanan tersebut.
+
+## Instalasi
+
+```bash
+npm install --save nanoid
+```
+
+Apabila ingin 'coba-coba' terlebih dahulu, dapat digunakan Nano ID melalui CDN. Hal ini tidak direkomendasikan untuk digunakan pada lingkungan produksi karena performa pemuatan (_loading_) yang berkurang.
+
+```js
+import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'
+```
+
+Nano ID tersedia dalam bentuk ES modules. Tidak perlu melakukan konfigurasi apapun apabila menggunakan Nano ID dalam bentuk ESM di webpack, Rollup, Parcel, atau Node.js.
+
+```js
+import { nanoid } from 'nanoid'
+```
+
+Dalam Node.js, dapat digunakan gaya _import_ ala CommonJS:
+
+```js
+const { nanoid } = require('nanoid')
+```
+
+## API
+
+Nano ID memiliki tiga buah API: normal (_blocking_), asinkronus (_asynchronous_), dan _non-secure_.
+
+Bawaannya, Nano ID menggunakan simbol yang _URL-friendly_ (`A-Za-z0-9_-`) dan mengembalikan ID dengan 21 karakter (untuk memiliki probabilitas collision / tabrakan yang mirip dengan UUID v4).
+
+### Blocking
+
+Penggunaan Nano ID yang aman dan yang paling mudah.
+
+Dalam kasus langka, fungsi ini dapat menghambat CPU untuk melakukan proses yang lain ketika dalam proses 'noise-collection' untuk generasi nilai acak (yang dilakukan pada perangkat keras).
+
+```js
+import { nanoid } from 'nanoid'
+model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
+```
+
+Apabila ingin mengurangi ukuran ID (dan meningkatkan probabilitas collision), dapat dimasukkan `size` sebagai argumen dari fungsi `nanoid()`.
+
+```js
+nanoid(10) //=> "IRFa-VaY2b"
+```
+
+Jangan lupa memeriksa tingkat keamanan dari ukuran ID dalam situs [ID collision probability calculator](https://zelark.github.io/nano-id-cc/).
+
+Dapat digunakan pula [custom alphabet](#custom-alphabet-or-size) atau [random generator](#custom-random-bytes-generator) yang lain.
+
+### Async
+
+Untuk menghasilkan bytes yang acak dan aman secara kriptografis, CPU mengumpulkan noise elektromagnetik. Umumnya, entropi sudah dikumpulkan terlebih dahulu.
+
+Dalam API sinkronus, pada saat CPU mengumpulkan noise elektromagnetik, CPU berada dalam situasi 'busy' dan tidak dapat melakukan proses yang lain (contohnya yakni memorses permintaan HTTP).
+
+Ketika menggunakan API asinkronus dari Nano ID, proses lain dapat berjalan ketika CPU sedang mengumpulkan noise elektromagnetik.
+
+```js
+import { nanoid } from 'nanoid/async'
+
+async function createUser() {
+ user.id = await nanoid()
+}
+```
+
+Referensi lebih lanjut tentang entropi dapat dilihat pada dokumentasi fungsi [`crypto.randomBytes`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback) milik Node.js.
+
+Sayangnya, keuntungan Web Crypto API akan hilang di browser apabila menggunakan API asinkronus ini. Untuk sekarang, browser dibatasi hanya menggunakan API sinkronus (untuk keamanan) atau API asinkronus (lebih cepat, tetapi karena keuntungan Web Crypto hilang, keamanannya sedikit lebih rendah ketimbang penggunaan API sinkronus).
+
+### Non-Secure
+
+Konfigurasi bawaan Nano ID menggunakan random bytes generator yang berasal dari perangkat keras untuk keamanan dan probabilitas collision yang rendah. Apabila tidak terlalu memikirkan soal keamanan, dapat pula menggunakan non-secure generator yang lebih cepat.
+
+```js
+import { nanoid } from 'nanoid/non-secure'
+const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
+```
+
+### Alfabet dan Ukuran (Custom)
+
+`customAlphabet` digunakan untuk membuat Nano ID dengan alfabet dan ukuran ID yang sesuai dengan kebutuhan (dapat dikustomisasi).
+
+```js
+import { customAlphabet } from 'nanoid'
+const nanoid = customAlphabet('1234567890abcdef', 10)
+model.id = nanoid() //=> "4f90d13a42"
+```
+
+Ketika menggunakan fungsi ini, jangan lupa untuk memeriksa keamanan alfabet dan ukuran ID dalam [ID collision probability calculator](https://alex7kom.github.io/nano-nanoid-cc/). Untuk lebih banyak alfabet, dapat menggunakan [`nanoid-dictionary`](https://github.com/CyberAP/nanoid-dictionary).
+
+Alfabet harus terbentuk dari 256 simbol atau lebih kecil. Selain itu, keamanan algoritma generasi yang berada di dalam library ini tidak dijamin aman.
+
+API asinkronus dan non-secure yang dapat dikustomisasi dengan `customAlphabet` pun tersedia disini:
+
+```js
+import { customAlphabet } from 'nanoid/async'
+const nanoid = customAlphabet('1234567890abcdef', 10)
+async function createUser() {
+ user.id = await nanoid()
+}
+```
+
+```js
+import { customAlphabet } from 'nanoid/non-secure'
+const nanoid = customAlphabet('1234567890abcdef', 10)
+user.id = nanoid()
+```
+
+### Generasi Random Bytes (Custom)
+
+`customRandom` digunakan untuk membuat Nano ID yang mengganti alfabet dan algoritma _random bytes generator_ yang telah diimplementasikan pada versi bawaan (dalam artian menggunakan algoritma sendiri untuk mendapatkan random bytes).
+
+Pada contoh berikut, digunakan _seed-based generator_:
+
+```js
+import { customRandom } from 'nanoid'
+
+const rng = seedrandom(seed)
+const nanoid = customRandom('abcdef', 10, size => {
+ return new Uint8Array(size).map(() => 256 * rng())
+})
+
+nanoid() //=> "fbaefaadeb"
+```
+
+Fungsi _callback_ pada `random` harus menerima ukuran array dan mengembalikan sebuah array dengan angka acak.
+
+Apabila ingin menggunakan alfabet bawaan NanoID pada fungsi `customRandom`, dapat menggunakan konstanta `urlAlphabet` seperti berikut:
+
+```js
+const { customRandom, urlAlphabet } = require('nanoid')
+const nanoid = customRandom(urlAlphabet, 10, random)
+```
+
+API asinkronus dan non-secure tidak tersedia untuk fungsi `customRandom`.
+
+## Penggunaan
+
+### IE
+
+Apabila mengimplementasikan di Internet Explorer, dibutuhkan untuk melakukan [transpile pada `node_modules`](https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/) dengan Babel dan menambahkan alias untuk `crypto` seperti berikut:
+
+```js
+// polyfills.js
+if (!window.crypto) {
+ window.crypto = window.msCrypto
+}
+```
+
+```js
+import './polyfills.js'
+import { nanoid } from 'nanoid'
+```
+
+### React
+
+Dalam React, tidak ada cara yang benar bila ingin menggunakan Nano ID untuk prop `key`, karena `key` tersebut harus konsisten dalam setiap proses render yang terjadi.
+
+```jsx
+function Todos({ todos }) {
+ return (
+
+ )
+}
+```
+
+Karena hal tersebut, disarankan untuk menggunakan ID yang stabil pada setiap objek yang di-render oleh React.
+
+```jsx
+const todoItems = todos.map(todo =>
{todo.text}
)
+```
+
+Apabila tidak memiliki ID yang stabil pada setiap _item_ yang di-render pada React, lebih baik menggunakan indeks sebuah array sebagai `key` ketimbang menggunakan fungsi `nanoid()`, seperti berikut:
+
+```jsx
+const todoItems = todos.map((text, index) => (
+ /* Tetap tidak direkomendasikan, tetapi lebih disarankan dari 'nanoid()'. Lakukan ini
+ apabila setiap objek / item dalam list tidak ada ID yang stabil. */
+
{text}
+))
+```
+
+### React Native
+
+React Native tidak memiliki _built-in random generator_. Digunakan polyfill seperti berikut yang berjalan untuk React Native dan Expo yang bermula dari versi `39.x`.
+
+1. Periksa dokumentasi [`react-native-get-random-values`](https://github.com/LinusU/react-native-get-random-values) dan install di aplikasi.
+2. Import library tersebut sebelum Nano ID.
+
+```js
+import 'react-native-get-random-values'
+import { nanoid } from 'nanoid'
+```
+
+### Rollup
+
+Untuk Rollup, dibutuhkan [`@rollup/plugin-node-resolve`](https://github.com/rollup/plugins/tree/master/packages/node-resolve) untuk versi browser dan [`@rollup/plugin-replace`](https://github.com/rollup/plugins/tree/master/packages/replace) untuk menggantikan `process.env.NODE_ENV`.
+
+```js
+plugins: [
+ nodeResolve({
+ browser: true
+ }),
+ replace({
+ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
+ })
+]
+```
+
+### PouchDB dan CouchDB
+
+Dalam PouchDB dan CouchDB, ID tidak bisa dimulai dengan underscore `_`. Sebuah _prefix_ dibutuhkan untuk mencegah hal ini terjadi, karena Nano ID mungkin menggunakan `_` sebagai karakter pertama dari ID yang dihasilkan.
+
+ID bawaan dapat diubah dengan opsi berikut:
+
+```js
+db.put({
+ _id: 'id' + nanoid(),
+ …
+})
+```
+
+### Mongoose
+
+```js
+const mySchema = new Schema({
+ _id: {
+ type: String,
+ default: () => nanoid()
+ }
+})
+```
+
+### Web Workers
+
+Web Workers tidak memiliki akses untuk secure random generator.
+
+Keamanan sangat penting pada ID yang mana setiap ID harus memiliki sifat tidak bisa diprediksi, seperti pada contoh use-case generasi link pada "access by URL". Apabila tidak memerlukan ID yang tidak bisa diprediksi, tetapi ingin/harus menggunakan Web Workers, dapat digunakan NanoID dengan API non-secure.
+
+```js
+import { nanoid } from 'nanoid/non-secure'
+nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
+```
+
+Perhatian: ID yang dihasilkan dari non-secure dapat lebih mudah tabrakan / memiliki probabilitas collision yang lebih besar.
+
+### CLI
+
+Nano ID dapat didapatkan dengan cara menggunakan `npx nanoid` pada Terminal. Hanya diperlukan Node.js untuk ini, dan tidak perlu mengunduh dan menginstall Nano ID dalam sistem.
+
+```sh
+$ npx nanoid
+npx: installed 1 in 0.63s
+LZfXLFzPPR4NNrgjlWDxn
+```
+
+Bila ingin mengganti alfabet atau ukuran ID, dapat menggunakan [`nanoid-cli`](https://github.com/twhitbeck/nanoid-cli).
+
+### Bahasa Pemrograman Lainnya
+
+Nano ID telah bermigrasi ke berbagai macam bahasa. Seluruh versi dapat digunakan untuk mendapatkan ID generator yang sama pada sisi klien dan sisi penyedia layanan (_client-side_ dan _server-side_).
+
+- [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)
+- [Deno](https://github.com/ianfabs/nanoid)
+- [Go](https://github.com/matoous/go-nanoid)
+- [Elixir](https://github.com/railsmechanic/nanoid)
+- [Haskell](https://github.com/4e6/nanoid-hs)
+- [Janet](https://sr.ht/~statianzo/janet-nanoid/)
+- [Java](https://github.com/aventrix/jnanoid)
+- [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](https://github.com/puyuan/py-nanoid) with [dictionaries](https://pypi.org/project/nanoid-dictionary)
+- [Ruby](https://github.com/radeno/nanoid.rb)
+- [Rust](https://github.com/nikolay-govorov/nanoid)
+- [Swift](https://github.com/antiflasher/NanoID)
+- [Unison](https://share.unison-lang.org/latest/namespaces/hojberg/nanoid)
+- [V](https://github.com/invipal/nanoid)
+
+Untuk environment lainnya, [CLI](#cli) tersedia untuk melakukan generasi ID dari command line / Terminal.
+
+## Alat
+
+- [ID Size Calculator](https://zelark.github.io/nano-id-cc/) menunjukkan probabilitas collision ketika melakukan konfigurasi alfabet dan ukuran.
+- [`nanoid-dictionary`](https://github.com/CyberAP/nanoid-dictionary) untuk menggunakan alfabet popular dalam fungsi [`customAlphabet`](#custom-alphabet-or-size)
+- [`nanoid-good`](https://github.com/y-gagar1n/nanoid-good) untuk meyakinkan bahwa ID yang di-generasi tidak memiliki kata-kata yang kurang baik (kasar, tidak sopan, dsb.).
diff --git a/README.md b/README.md
index 189f1fc8..f5b81a22 100644
--- a/README.md
+++ b/README.md
@@ -3,20 +3,21 @@
+**English** | [Русский](./README.ru.md) | [简体中文](./README.zh-CN.md) | [Bahasa Indonesia](./README.id-ID.md)
+
A tiny, secure, URL-friendly, unique string ID generator for JavaScript.
> “An amazing level of senseless perfectionism,
> which is simply impossible not to respect.”
-* **Small.** 108 bytes (minified and gzipped). No dependencies.
+* **Small.** 130 bytes (minified and gzipped). No dependencies.
[Size Limit] controls the size.
-* **Fast.** It is 60% faster than UUID.
-* **Safe.** It uses cryptographically strong random APIs.
- Can be used in clusters.
-* **Compact.** It uses a larger alphabet than UUID (`A-Za-z0-9_-`).
+* **Fast.** It is 2 times faster than UUID.
+* **Safe.** It uses hardware random generator. Can be used in clusters.
+* **Short IDs.** It uses a larger alphabet than UUID (`A-Za-z0-9_-`).
So ID size was reduced from 36 to 21 symbols.
* **Portable.** Nano ID was ported
- to [14 programming languages](#other-programming-languages).
+ to [20 programming languages](#other-programming-languages).
```js
import { nanoid } from 'nanoid'
@@ -38,26 +39,24 @@ Supports modern browsers, IE [with Babel], Node.js and React Native.
* [Comparison with UUID](#comparison-with-uuid)
* [Benchmark](#benchmark)
-* [Tools](#tools)
* [Security](#security)
+* [API](#api)
+ * [Blocking](#blocking)
+ * [Async](#async)
+ * [Non-Secure](#non-secure)
+ * [Custom Alphabet or Size](#custom-alphabet-or-size)
+ * [Custom Random Bytes Generator](#custom-random-bytes-generator)
* [Usage](#usage)
- * [JS](#js)
* [IE](#ie)
* [React](#react)
- * [Create React App](#create-react-app)
* [React Native](#react-native)
* [Rollup](#rollup)
* [PouchDB and CouchDB](#pouchdb-and-couchdb)
* [Mongoose](#mongoose)
- * [ES Modules](#es-modules)
* [Web Workers](#web-workers)
* [CLI](#cli)
* [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)
+* [Tools](#tools)
## Comparison with UUID
@@ -73,47 +72,40 @@ There are three 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.5 times less** than `uuid/v4` package:
- 108 bytes instead of 483.
-3. Because of memory allocation tricks, Nano ID is **60%** faster than UUID.
+2. Nano ID code is **4 times less** than `uuid/v4` package:
+ 130 bytes instead of 483.
+3. Because of memory allocation tricks, Nano ID is **2 times** faster than UUID.
## Benchmark
```rust
$ node ./test/benchmark.js
-nanoid 2,280,683 ops/sec
-customAlphabet 1,851,117 ops/sec
-uuid v4 1,348,425 ops/sec
-uid.sync 313,306 ops/sec
-secure-random-string 294,161 ops/sec
-cuid 158,988 ops/sec
-shortid 37,222 ops/sec
+crypto.randomUUID 25,603,857 ops/sec
+@napi-rs/uuid 9,973,819 ops/sec
+uid/secure 8,234,798 ops/sec
+@lukeed/uuid 7,464,706 ops/sec
+nanoid 5,616,592 ops/sec
+customAlphabet 3,115,207 ops/sec
+uuid v4 1,535,753 ops/sec
+secure-random-string 388,226 ops/sec
+uid-safe.sync 363,489 ops/sec
+cuid 187,343 ops/sec
+shortid 45,758 ops/sec
Async:
-async nanoid 95,500 ops/sec
-async customAlphabet 93,800 ops/sec
-async secure-random-string 90,316 ops/sec
-uid 85,583 ops/sec
+nanoid/async 96,094 ops/sec
+async customAlphabet 97,184 ops/sec
+async secure-random-string 92,794 ops/sec
+uid-safe 90,684 ops/sec
Non-secure:
-non-secure nanoid 2,641,654 ops/sec
-rndm 2,447,086 ops/sec
+uid 67,376,692 ops/sec
+nanoid/non-secure 2,849,639 ops/sec
+rndm 2,674,806 ops/sec
```
-Test configuration: Dell XPS 2-in-1 7390, Fedora 32, Node.js 15.1.
-
-
-## 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/
-[`nanoid-good`]: https://github.com/y-gagar1n/nanoid-good
+Test configuration: ThinkPad X1 Carbon Gen 9, Fedora 34, Node.js 16.10.
## Security
@@ -133,24 +125,35 @@ Test configuration: Dell XPS 2-in-1 7390, Fedora 32, Node.js 15.1.
+* **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
-## Usage
+## Install
+
+```bash
+npm install --save nanoid
+```
-### JS
+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.
-The main module uses URL-friendly symbols (`A-Za-z0-9_-`) and returns an ID
-with 21 characters (to have a collision probability similar to UUID v4).
+```js
+import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'
+```
+
+Nano ID provides ES modules. You do not need to do anything to use Nano ID
+as ESM in webpack, Rollup, Parcel, or Node.js.
```js
import { nanoid } from 'nanoid'
-model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
```
In Node.js you can use CommonJS import:
@@ -159,6 +162,27 @@ In Node.js you can use CommonJS import:
const { nanoid } = require('nanoid')
```
+
+## API
+
+Nano ID has 3 APIs: normal (blocking), asynchronous, 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.
@@ -175,6 +199,120 @@ or a [random generator](#custom-random-bytes-generator).
[ID collision probability]: https://zelark.github.io/nano-id-cc/
+### Async
+
+To generate hardware random bytes, CPU collects electromagnetic noise.
+For most cases, entropy will be already collected.
+
+In the synchronous API during the noise collection, the CPU is busy and
+cannot do anything useful (for instance, process another HTTP request).
+
+Using the asynchronous API of Nano ID, another code can run during
+the entropy collection.
+
+```js
+import { nanoid } from 'nanoid/async'
+
+async function createUser () {
+ user.id = await nanoid()
+}
+```
+
+Read more about entropy collection in [`crypto.randomBytes`] docs.
+
+Unfortunately, you will lose Web Crypto API advantages in a browser
+if you use the asynchronous API. So, currently, in the browser, you are limited
+with either security (`nanoid`), asynchronous behavior (`nanoid/async`),
+or non-secure behavior (`nanoid/non-secure`) that will be explained
+in the next part of the documentation.
+
+[`crypto.randomBytes`]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
+
+
+### 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 the faster non-secure generator.
+
+```js
+import { nanoid } from 'nanoid/non-secure'
+const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
+```
+
+
+### Custom Alphabet or Size
+
+`customAlphabet` 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"
+```
+
+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.
+
+Customizable asynchronous and non-secure APIs are also available:
+
+```js
+import { customAlphabet } from 'nanoid/async'
+const nanoid = customAlphabet('1234567890abcdef', 10)
+async function createUser () {
+ user.id = await nanoid()
+}
+```
+
+```js
+import { customAlphabet } from 'nanoid/non-secure'
+const nanoid = customAlphabet('1234567890abcdef', 10)
+user.id = nanoid()
+```
+
+[ID collision probability]: https://alex7kom.github.io/nano-nanoid-cc/
+[`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
+const { customRandom, urlAlphabet } = require('nanoid')
+const nanoid = customRandom(urlAlphabet, 10, random)
+```
+
+Asynchronous and non-secure APIs are not available for `customRandom`.
+
+
+## Usage
+
### IE
If you support IE, you need to [transpile `node_modules`] by Babel
@@ -197,7 +335,7 @@ import { nanoid } from 'nanoid'
### React
-There’s currently no correct way to use nanoid for React `key` prop
+There’s no correct way to use Nano ID for React `key` prop
since it should be consistent among renders.
```jsx
@@ -214,7 +352,7 @@ function Todos({todos}) {
}
```
-You should rather try to reach for stable id inside your list item.
+You should rather try to reach for stable ID inside your list item.
```jsx
const todoItems = todos.map((todo) =>
@@ -224,7 +362,7 @@ const todoItems = todos.map((todo) =>
)
```
-In case you don’t have stable ids you'd rather use index as `key`
+In case you don’t have stable IDs you'd rather use index as `key`
instead of `nanoid()`:
```jsx
@@ -236,26 +374,6 @@ const todoItems = todos.map((text, index) =>
)
```
-If you want to use Nano ID in the `id` prop, you must set some string prefix
-(it is invalid for the HTML ID to start with a number).
-
-```jsx
-
-```
-
-
-### Create React App
-
-Create React App < 4.0.0 had
-[a problem](https://github.com/ai/nanoid/issues/205) with ES modules packages.
-
-```
-TypeError: (0 , _nanoid.nanoid) is not a function
-```
-
-Use Nano ID 2 `npm i nanoid@^2.0.0` if you're using a version below
-CRA 4.0.
-
### React Native
@@ -270,8 +388,6 @@ import 'react-native-get-random-values'
import { nanoid } from 'nanoid'
```
-For Expo framework see the next section.
-
[`react-native-get-random-values`]: https://github.com/LinusU/react-native-get-random-values
@@ -324,26 +440,6 @@ const mySchema = new Schema({
```
-### ES Modules
-
-Nano ID provides ES modules. You do not need to do anything to use Nano ID
-as ESM in webpack, Rollup, Parcel, or Node.js.
-
-```js
-import { nanoid } from 'nanoid'
-```
-
-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 loading performance.
-
-```js
-import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'
-```
-
-
### Web Workers
Web Workers do not have access to a secure random generator.
@@ -372,10 +468,20 @@ npx: installed 1 in 0.63s
LZfXLFzPPR4NNrgjlWDxn
```
-If you want to change alphabet or ID size, you should use [`nanoid-cli`].
+Size of generated ID can be specified with `--size` (or `-s`) option:
-[`nanoid-cli`]: https://github.com/twhitbeck/nanoid-cli
+```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
+```
### Other Programming Languages
@@ -385,6 +491,7 @@ the same ID generator on the client and server side.
* [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)
* [Deno](https://github.com/ianfabs/nanoid)
@@ -394,6 +501,7 @@ the same ID generator on the client and server side.
* [Janet](https://sr.ht/~statianzo/janet-nanoid/)
* [Java](https://github.com/aventrix/jnanoid)
* [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](https://github.com/puyuan/py-nanoid)
@@ -401,116 +509,22 @@ the same ID generator on the client and server side.
* [Ruby](https://github.com/radeno/nanoid.rb)
* [Rust](https://github.com/nikolay-govorov/nanoid)
* [Swift](https://github.com/antiflasher/NanoID)
+* [Unison](https://share.unison-lang.org/latest/namespaces/hojberg/nanoid)
* [V](https://github.com/invipal/nanoid)
-Also, [CLI] is available to generate IDs from a command line.
+For other environments, [CLI] is available to generate IDs from a command line.
[CLI]: #cli
-## API
-
-### Async
-
-To generate hardware random bytes, CPU collects electromagnetic noise.
-In the synchronous API during the noise collection, the CPU is busy and
-cannot do anything useful in parallel.
-
-Using the asynchronous API of Nano ID, another code can run during
-the entropy collection.
-
-```js
-import { nanoid } from 'nanoid/async'
-
-async function createUser () {
- user.id = await nanoid()
-}
-```
-
-Unfortunately, you will lose Web Crypto API advantages in a browser
-if you use the asynchronous API. So, currently, in the browser, you are limited
-with either security or asynchronous behavior.
-
-
-### 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
-and more concerned with performance, you can use the faster non-secure generator.
-
-```js
-import { nanoid } from 'nanoid/non-secure'
-const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
-```
-
-Note: your IDs will be more predictable and prone to collision attacks.
-
-
-### Custom Alphabet or Size
-
-`customAlphabet` 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"
-```
-
-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.
-
-Customizable asynchronous and non-secure APIs are also available:
-
-```js
-import { customAlphabet } from 'nanoid/async'
-const nanoid = customAlphabet('1234567890abcdef', 10)
-async function createUser () {
- user.id = await nanoid()
-}
-```
-
-```js
-import { customAlphabet } from 'nanoid/non-secure'
-const nanoid = customAlphabet('1234567890abcdef', 10)
-user.id = nanoid()
-```
-
-[ID collision probability]: https://alex7kom.github.io/nano-nanoid-cc/
-[`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`.
+## Tools
-```js
-const { customRandom, urlAlphabet } = require('nanoid')
-const nanoid = customRandom(urlAlphabet, 10, random)
-```
+* [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.
-Asynchronous and non-secure APIs are not available for `customRandom`.
+[`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
diff --git a/README.ru.md b/README.ru.md
new file mode 100644
index 00000000..12c85a9e
--- /dev/null
+++ b/README.ru.md
@@ -0,0 +1,517 @@
+# Nano ID
+
+
+
+[English](./README.md) | **Русский** | [简体中文](./README.zh-CN.md) | [Bahasa Indonesia](./README.id-ID.md)
+
+Генератор уникальных ID для JavaScript — лёгкий, безопасный,
+ID можно применять в URL.
+
+> «Поразительный уровень бессмысленного перфекционизма,
+> который просто невозможно не уважать»
+
+- **Лёгкий.** 130 байт (после минификации и gzip). Без зависимостей.
+ [Size Limit] следит за размером.
+- **Быстрый.** В 2 раза быстрее UUID.
+- **Безопасный.** Использует аппаратный генератор случайных чисел.
+ Можно использовать в кластерах машин.
+- **Короткие ID.** Используется больший алфавит, чем у UUID (`A-Za-z0-9_-`).
+ Поэтому длина ID уменьшена с 36 до 21 символа.
+- **Работает везде.** Nano ID уже портировали
+ на [20 языков программирования](#другие-языки-программирования).
+
+```js
+import { nanoid } from 'nanoid'
+model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
+```
+
+Поддерживает современные браузеры, IE ([с Babel]), Node.js и React Native.
+
+[online tool]: https://gitpod.io/#https://github.com/ai/nanoid/
+[с babel]: https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/
+[size limit]: https://github.com/ai/size-limit
+
+
+
+
+
+
+## Оглавление
+
+- [Сравнение с UUID](#сравнение-с-uuid)
+- [Сравнение производительности](#сравнение-производительности)
+- [Безопасность](#безопасность)
+- [Подключение](#подключение)
+- [API](#api)
+ - [Блокирующий](#блокирующий)
+ - [Асинхронный](#асинхронный)
+ - [Небезопасный](#небезопасный)
+ - [Смена алфавита или длины](#смена-алфавита-или-длины)
+ - [Смена генератора случайных чисел](#смена-генератора-случайных-чисел)
+- [Руководство](#руководство)
+ - [IE](#ie)
+ - [React](#react)
+ - [React Native](#react-native)
+ - [Rollup](#rollup)
+ - [PouchDB и CouchDB](#pouchdb-и-couchdb)
+ - [Mongoose](#mongoose)
+ - [Веб-воркеры](#веб-воркеры)
+ - [Терминал](#терминал)
+ - [Другие языки программирования](#другие-языки-программирования)
+- [Инструменты](#инструменты)
+
+
+## Сравнение с UUID
+
+Nano ID похож на UUID v4 (случайный).
+У них сравнимое число битов случайности в ID (126 у Nano ID против 122 у UUID),
+поэтому они обладают похожей вероятностью возникновения коллизий
+(повторной генерации ранее выданных ID):
+
+> Чтобы вероятность повтора приблизилась к 1 на миллиард,
+> нужно сгенерировать 103 триллиона ID.
+
+Но между ними есть 3 важных отличия:
+
+1. Nano ID использует более широкий алфавит, и сравнимое количество
+ битов случайности будут упакованы в более короткую строку
+ (21 символ, против 36 у UUID).
+2. Код Nano ID **в 4 раз меньше**, чем у `uuid/v4` — 130 байт против 483.
+3. Благодаря оптимизациям с выделением памяти,
+ Nano ID **в 2 раза быстрее** UUID.
+
+
+## Сравнение производительности
+
+```rust
+$ node ./test/benchmark.js
+crypto.randomUUID 25,603,857 ops/sec
+@napi-rs/uuid 9,973,819 ops/sec
+uid/secure 8,234,798 ops/sec
+@lukeed/uuid 7,464,706 ops/sec
+nanoid 5,616,592 ops/sec
+customAlphabet 3,115,207 ops/sec
+uuid v4 1,535,753 ops/sec
+secure-random-string 388,226 ops/sec
+uid-safe.sync 363,489 ops/sec
+cuid 187,343 ops/sec
+shortid 45,758 ops/sec
+
+Async:
+nanoid/async 96,094 ops/sec
+async customAlphabet 97,184 ops/sec
+async secure-random-string 92,794 ops/sec
+uid-safe 90,684 ops/sec
+
+Non-secure:
+uid 67,376,692 ops/sec
+nanoid/non-secure 2,849,639 ops/sec
+rndm 2,674,806 ops/sec
+```
+
+Среда сравнения: ThinkPad X1 Carbon Gen 9, Fedora 34, Node.js 16.10.
+
+
+## Безопасность
+
+_См. также хорошую статью о теориях генераторов случайных чисел:
+[Secure random values (in Node.js)]_
+
+- **Непредсказуемость.** Вместо предсказуемого `Math.random()`, Nano ID
+ использует модуль `crypto` в Node.js и Web Crypto API в браузере.
+ Эти модули дают доступ к аппаратному генератору случайных чисел.
+- **Равномерность.** Например, существует популярная ошибка `random % alphabet`,
+ которую часто допускают при разработке генератора ID.
+ Распределение вероятности для каждого символа может не быть одинаковым.
+ Из-за неравномерности использования пространства алфавита, на перебор ID
+ потребуется меньше времени, чем ожидается.
+ Nano ID использует [более совершенный алгоритм],
+ а равномерность распределения символов покрыта тестами.
+
+
+
+- **Документация:** все хитрости Nano ID хорошо документированы — смотрите
+ комментарии [в исходниках].
+- **Уязвимости:** если вы нашли уязвимость в Nano ID, свяжитесь с
+ [командой безопасности Tidelift](https://tidelift.com/security).
+ Они проконтролируют исправление и проинформируют пользователей.
+
+[secure random values (in node.js)]: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba
+[более совершенный алгоритм]: https://github.com/ai/nanoid/blob/main/index.js
+[в исходниках]: https://github.com/ai/nanoid/blob/main/index.js
+
+
+## Подключение
+
+```bash
+npm install --save nanoid
+```
+
+Для быстрого прототипирования вы можете подключить Nano ID с CDN без установки.
+Не используйте этот способ на реальном сайте, так как он сильно бьёт
+по скорости загрузки сайта.
+
+```js
+import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'
+```
+
+Nano ID поддерживает ES-модули. Вам не надо ничего делать, чтобы ES-импорты
+работали в webpack, Rollup, Parcel, или Node.js.
+
+```js
+import { nanoid } from 'nanoid'
+```
+
+Для Node.js также поддерживается CommonJS-импорт:
+
+```js
+const { nanoid } = require('nanoid')
+```
+
+
+## API
+
+Nano ID разделён на три модуля:
+стандартный (блокирующий), асинхронный и небезопасный.
+
+По умолчанию используются символы, безопасные для URL (`A-Za-z0-9_-`).
+Длина ID по умолчанию — 21 символ
+(чтобы вероятность коллизий была соизмеримой с UUID v4).
+
+
+### Блокирующий
+
+Безопасный и простой в использовании способ использования Nano ID.
+
+Из-за особенностей работы генератора случайных чисел при использовании этого
+способа ЦПУ может иногда простаивать без работы.
+
+```js
+import { nanoid } from 'nanoid'
+model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
+```
+
+Функция также принимает необязательный аргумент, задающий длину ID:
+
+```js
+nanoid(10) //=> "IRFa-VaY2b"
+```
+
+При изменении размера, всегда проверяйте риски
+в нашем [калькуляторе коллизий](https://zelark.github.io/nano-id-cc/).
+
+
+### Асинхронный
+
+Для аппаратной генерации случайных чисел процессор накапливает
+электромагнитные шумы. Обычно они накоплены заранее, и получение
+случайных чисел происходит быстро. Но могут быть ситуации, когда
+системе требуется время на накопление энтропии.
+
+При использовании синхронного API процесс заблокируется
+во время накопления энтропии. Например, веб-сервер не сможет
+обрабатывать запрос следующего посетителя, пока не сгенерирует
+ID для предыдущего.
+
+Но если использовать асинхронный API у Nano ID, то процесс будет работать
+более эффективно: во время накопления шума сможет выполняться другая задача.
+
+```js
+import { nanoid } from 'nanoid/async'
+
+async function createUser() {
+ user.id = await nanoid()
+}
+```
+
+Про ожидание накопления энтропии можно почитать в описании метода
+`crypto.randomBytes` в [документации Node.js].
+
+К сожалению, эта оптимизация имеет смысл только для Node.js. Web Crypto API
+в браузерах не имеет асинхронной версии.
+
+[документации node.js]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
+
+
+### Небезопасный
+
+По умолчанию, Nano ID использует аппаратный генератор случайных чисел для
+получения непредсказуемых ID и минимизации риска возникновения коллизий
+(повторной генерации ранее выданных ID).
+Но если вам не требуется устойчивость к подбору ID,
+то вы можете перейти на небезопасный генератор.
+
+```js
+import { nanoid } from 'nanoid/non-secure'
+const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
+```
+
+Но учтите, что предсказуемость ID может быть использована для атаки на систему.
+
+
+### Смена алфавита или длины
+
+Функция `customAlphabet` позволяет создать свою функцию `nanoid`
+с нужным вам алфавитом и длиной ID.
+
+```js
+import { customAlphabet } from 'nanoid'
+const nanoid = customAlphabet('1234567890abcdef', 10)
+user.id = nanoid() //=> "4f90d13a42"
+```
+
+```js
+import { customAlphabet } from 'nanoid/async'
+const nanoid = customAlphabet('1234567890abcdef', 10)
+async function createUser() {
+ user.id = await nanoid()
+}
+```
+
+```js
+import { customAlphabet } from 'nanoid/non-secure'
+const nanoid = customAlphabet('1234567890abcdef', 10)
+user.id = nanoid()
+```
+
+Не забудьте проверить риски коллизии вашего алфавита и длины
+[на нашем калькуляторе]. [`nanoid-dictionary`] содержит много популярных
+примеров альтернативных алфавитов.
+
+Алфавит должен содержать ≤256 символов. Иначе мы не сможем гарантировать
+непредсказуемость ID.
+
+[на нашем калькуляторе]: https://alex7kom.github.io/nano-nanoid-cc/
+[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary
+
+
+### Смена генератора случайных чисел
+
+Функция `customRandom` позволяет создать свою функцию `nanoid` со своими
+генераторами случайных чисел, алфавитом и длинной ID.
+
+Например, можно использовать генератор c seed для повторяемости тестов.
+
+```js
+import { customRandom } from 'nanoid'
+
+const rng = seedrandom(seed)
+const nanoid = customRandom('abcdef', 10, size => {
+ return new Uint8Array(size).map(() => 256 * rng())
+})
+
+nanoid() //=> "fbaefaadeb"
+```
+
+Функция в третьем аргументе `customRandom` должна принимать длину массива
+и возвращать нужный массив со случайными числами
+
+Если вы хотите заменить только генератор случайных чисел, но оставить
+URL-совместимый алфавит, то стандартный алфавит доступен
+в экспорте `urlAlphabet`.
+
+```js
+const { customRandom, urlAlphabet } = require('nanoid')
+const nanoid = customRandom(urlAlphabet, 10, random)
+```
+
+У асинхронной и небезопасной версий нет `customRandom`.
+
+
+## Руководство
+
+### IE
+
+Если вам нужна поддержка IE, потребуется включить [компиляцию `node_modules`]
+с помощью Babel и вручную убрать вендорный префикс у `crypto`.
+
+```js
+// polyfills.js
+if (!window.crypto) {
+ window.crypto = window.msCrypto
+}
+```
+
+```js
+import './polyfills.js'
+import { nanoid } from 'nanoid'
+```
+
+[компиляцию `node_modules`]: https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/
+
+
+### React
+
+Не используйте Nano ID для генерации свойства `key` в JSX. При каждом рендере
+`key` будет разный, что плохо скажется на производительности.
+
+```jsx
+function Todos({ todos }) {
+ return (
+
+ {todos.map(todo => (
+
/* НЕ ДЕЛАЙТЕ ТАК */
+ {todo.text}
+
+ ))}
+
+ )
+}
+```
+
+Подробнее об использовании свойства `key` читайте в
+[официальной документации React](https://ru.reactjs.org/docs/lists-and-keys.html#keys).
+
+### React Native
+
+React Native не имеет встроенного аппаратного генератора случайных чисел.
+Полифил ниже работает в чистом React Native и в Expo начиная с версии 39.
+
+1. Прочитайте документацию [`react-native-get-random-values`] и установите его.
+2. Импортируйте эту библиотеку до импорта 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
+
+
+### Rollup
+
+Для Rollup понадобятся плагины [`@rollup/plugin-node-resolve`]
+и [`@rollup/plugin-replace`].
+
+```js
+plugins: [
+ nodeResolve({
+ browser: true
+ }),
+ replace({
+ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
+ })
+]
+```
+
+[`@rollup/plugin-node-resolve`]: https://github.com/rollup/plugins/tree/master/packages/node-resolve
+[`@rollup/plugin-replace`]: https://github.com/rollup/plugins/tree/master/packages/replace
+
+
+### PouchDB и CouchDB
+
+В PouchDB и CouchDB, ID не могут начинаться с `_`. Добавьте к ID префикс,
+так как иногда Nano ID может сгенерировать ID начинающийся с `_`.
+
+Изменить стандартный ID можно через следующую опцию:
+
+```js
+db.put({
+ _id: 'id' + nanoid(),
+ …
+})
+```
+
+
+### Mongoose
+
+```js
+const mySchema = new Schema({
+ _id: {
+ type: String,
+ default: () => nanoid()
+ }
+})
+```
+
+
+### Веб-воркеры
+
+Веб-воркеры не имеют доступа к аппаратному генератору случайных чисел.
+
+Аппаратный генератор нужен, в том числе, для непредсказуемости ID. Например,
+когда доступ к секретному документу защищён ссылкой с уникальным ID.
+
+Если вам не нужна непредсказуемость ID, то в Веб-воркере можно использовать
+небезопасный генератор ID.
+
+```js
+import { nanoid } from 'nanoid/non-secure'
+nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
+```
+
+
+### Терминал
+
+Можно сгенерировать уникальный ID прямо из терминала, вызвав `npx nanoid`.
+Для этого в системе должна быть только Node.js. `npx` сама скачает Nano ID,
+если его нет в системе.
+
+```sh
+$ npx nanoid
+npx: installed 1 in 0.63s
+LZfXLFzPPR4NNrgjlWDxn
+```
+
+Длину генерируемых ID можно передать в аргументе `--size` (или `-s`):
+
+```sh
+$ npx nanoid --size 10
+L3til0JS4z
+```
+
+Изменить алфавит можно при помощи аргумента `--alphabet` (ли `-a`)
+(в этом случае `--size` обязателен):
+
+```sh
+$ npx nanoid --alphabet abc --size 15
+bccbcabaabaccab
+```
+
+### Другие языки программирования
+
+Nano ID был портирован на множество языков. Это полезно, чтобы сервер и клиент
+генерировали ID по одной схеме.
+
+- [C#](https://github.com/codeyu/nanoid-net)
+- [C++](https://github.com/mcmikecreations/nanoid_cpp)
+- [Clojure и 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)
+- [Deno](https://github.com/ianfabs/nanoid)
+- [Go](https://github.com/matoous/go-nanoid)
+- [Elixir](https://github.com/railsmechanic/nanoid)
+- [Haskell](https://github.com/4e6/nanoid-hs)
+- [Janet](https://sr.ht/~statianzo/janet-nanoid/)
+- [Java](https://github.com/aventrix/jnanoid)
+- [Nim](https://github.com/icyphox/nanoid.nim)
+- [Perl](https://github.com/tkzwtks/Nanoid-perl)
+- [PHP](https://github.com/hidehalo/nanoid-php)
+- [Python](https://github.com/puyuan/py-nanoid)
+ со [словарями](https://pypi.org/project/nanoid-dictionary)
+- [Ruby](https://github.com/radeno/nanoid.rb)
+- [Rust](https://github.com/nikolay-govorov/nanoid)
+- [Swift](https://github.com/antiflasher/NanoID)
+* [Unison](https://share.unison-lang.org/latest/namespaces/hojberg/nanoid)
+- [V](https://github.com/invipal/nanoid)
+
+Для остальных сред можно использовать Nano ID [для терминала].
+
+[для терминала]: #терминал
+
+
+## Инструменты
+
+- [Калькулятор длины ID] поможет подобрать оптимальную длину ID,
+ в зависимости от частоты выдачи ID и нужной надёжности системы.
+- [`nanoid-dictionary`] с популярными алфавитами для [`customAlphabet`].
+- [`nanoid-good`] гарантирует, что в случайном ID не будет матерных слов.
+
+[калькулятор длины id]: https://zelark.github.io/nano-id-cc/
+[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary
+[`customalphabet`]: #смена-алфавита-или-длины
+[`nanoid-good`]: https://github.com/y-gagar1n/nanoid-good
diff --git a/README.zh-CN.md b/README.zh-CN.md
new file mode 100644
index 00000000..8fcc75a4
--- /dev/null
+++ b/README.zh-CN.md
@@ -0,0 +1,504 @@
+# Nano ID
+
+
+
+[English](./README.md) | [Русский](./README.ru.md) | **简体中文** | [Bahasa Indonesia](./README.id-ID.md)
+
+一个小巧、安全、URL友好、唯一的 JavaScript 字符串ID生成器。
+
+> “一个惊人的无意义的完美主义水平,
+> 这简直让人无法不敬佩。”
+
+* **小巧.** 130 bytes (已压缩和 gzipped)。 没有依赖。
+ [Size Limit] 控制大小。
+* **快速.** 它比 UUID 快 60%。
+* **安全.** 它使用加密的强随机 API。可在集群中使用。
+* **紧凑.** 它使用比 UUID(`A-Za-z0-9_-`)更大的字母表。
+ 因此,ID 大小从36个符号减少到21个符号。
+* **易用.** Nano ID 已被移植到
+ [20种编程语言](#其他编程语言)。
+
+```js
+import { nanoid } from 'nanoid'
+model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
+```
+
+支持现代浏览器、IE [使用 Babel]、Node.js 和 React Native。
+
+[在线工具]: https://gitpod.io/#https://github.com/ai/nanoid/
+[使用 Babel]: https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/
+[Size Limit]: https://github.com/ai/size-limit
+
+
+
+
+
+## 目录
+
+* [与 UUID 的比较](#与-uuid-的比较)
+* [基准值](#基准值)
+* [安全性](#安全性)
+* [API](#api)
+ * [阻塞](#阻塞)
+ * [异步](#异步)
+ * [不安全](#不安全)
+ * [自定义字母或大小](#自定义字母或大小)
+ * [自定义随机字节生成器](#自定义随机字节生成器)
+* [用法](#用法)
+ * [IE](#ie)
+ * [React](#react)
+ * [React Native](#react-native)
+ * [Rollup](#rollup)
+ * [PouchDB and CouchDB](#pouchdb-and-couchdb)
+ * [Mongoose](#mongoose)
+ * [Web Workers](#web-workers)
+ * [CLI](#cli)
+ * [其他编程语言](#other-programming-languages)
+* [工具](#工具)
+
+
+## 与 UUID 的比较
+
+Nano ID 与 UUID v4 (基于随机) 相当。
+它们在 ID 中有相似数量的随机位
+(Nano ID 为126,UUID 为122),因此它们的冲突概率相似::
+
+> 要想有十亿分之一的重复机会,
+> 必须产生103万亿个版本4的ID.
+
+Nano ID 和 UUID v4之间有三个主要区别:
+
+1. Nano ID 使用更大的字母表,所以类似数量的随机位
+ 被包装在21个符号中,而不是36个。
+2. Nano ID 代码比 `uuid/v4` 包少 **4倍**: 130字节而不是483字节.
+3. 由于内存分配的技巧,Nano ID 比 UUID 快 **60%**。
+
+
+## 基准值
+
+```rust
+$ node ./test/benchmark.js
+crypto.randomUUID 25,603,857 ops/sec
+@napi-rs/uuid 9,973,819 ops/sec
+uid/secure 8,234,798 ops/sec
+@lukeed/uuid 7,464,706 ops/sec
+nanoid 5,616,592 ops/sec
+customAlphabet 3,115,207 ops/sec
+uuid v4 1,535,753 ops/sec
+secure-random-string 388,226 ops/sec
+uid-safe.sync 363,489 ops/sec
+cuid 187,343 ops/sec
+shortid 45,758 ops/sec
+
+Async:
+nanoid/async 96,094 ops/sec
+async customAlphabet 97,184 ops/sec
+async secure-random-string 92,794 ops/sec
+uid-safe 90,684 ops/sec
+
+Non-secure:
+uid 67,376,692 ops/sec
+nanoid/non-secure 2,849,639 ops/sec
+rndm 2,674,806 ops/sec
+```
+
+测试配置: ThinkPad X1 Carbon Gen 9, Fedora 34, Node.js 16.10.
+
+
+## 安全性
+
+*请看一篇关于随机生成器理论的好文章:
+[安全的随机值 (在 Node.js 中)]*
+
+* **不可预测性.** 不使用不安全的 `Math.random()`, Nano ID
+ 使用 Node.js 的 `crypto` 模块和浏览器的 Web Crypto API。
+ 这些模块使用不可预测的硬件随机生成器。
+* **统一性.** `随机 % 字母表` 是编写ID生成器时常犯的一个错误。
+ 符号的分布是不均匀的; 有些符号出现的几率会比其他符号低。因此, 它将减少刷新时的尝试次数。
+ Nano ID 使用了一种 [更好的算法],并进行了一致性测试。
+
+
+
+* **有据可查:** 所有的 Nano ID 的行为都有记录。
+ 见 [源代码] 中的注释。
+* **漏洞:** 报告安全漏洞,请使用
+ [安全联系人 Tidelift](https://tidelift.com/security).
+ Tidelift 将协调修复和披露。
+
+[安全的随机值 (在 Node.js 中)]: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba
+[更好的算法]: https://github.com/ai/nanoid/blob/main/index.js
+[源代码]: https://github.com/ai/nanoid/blob/main/index.js
+
+
+## 安装
+
+```bash
+npm install --save nanoid
+```
+
+对于快速的骇客用法,你可以从 CDN 加载 Nano ID。但是,它不建议
+在生产中使用,因为它的加载性能较低。
+
+```js
+import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'
+```
+
+Nano ID提供ES模块。在 webpack、Rollup、Parcel 或 Node.js 中
+你不需要做任何事情来使用 Nano ID
+
+```js
+import { nanoid } from 'nanoid'
+```
+
+在 Node.js 中,你可以使用 CommonJS 导入:
+
+```js
+const { nanoid } = require('nanoid')
+```
+
+
+## API
+
+Nano ID 有3个 API:正常(阻塞),异步,和不安全。
+
+默认情况下,Nano ID 使用 URL 友好的符号(`A-Za-z0-9_-`)并返回一个
+有21个字符(类似UUID v4的冲突概率)的ID。
+
+
+### 阻塞
+
+使用 Nano ID 最安全、最简单的方法
+
+在极少数情况下,噪声收集时可能会阻止CPU执行其他工作
+用于硬件随机发生器。
+
+```js
+import { nanoid } from 'nanoid'
+model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
+```
+
+如果你想要减小ID size(但是会增加冲突概率),
+可以将 size 作为参数传递
+
+```js
+nanoid(10) //=> "IRFa-VaY2b"
+```
+
+别忘了检查你的ID size 的安全性
+在我们的 [ID 冲突概率] 计算器.
+
+您也可以使用 [自定义字母表](#自定义字母或大小)
+或者是 [自定义生成器](#自定义随机字节生成器).
+
+[ID 冲突概率]: https://alex7kom.github.io/nano-nanoid-cc/
+
+
+### 异步
+
+为了生成硬件随机字节,CPU收集电磁噪声。
+在大多数情况下,熵已经被收集。
+
+在噪声收集期间的同步API中,CPU忙且
+无法执行任何有用的操作(例如,处理另一个HTTP请求)。
+
+使用Nano ID的异步API,可以在熵收集期间
+运行另一个代码。
+
+```js
+import { nanoid } from 'nanoid/async'
+
+async function createUser () {
+ user.id = await nanoid()
+}
+```
+
+阅读更多有关熵收集的信息 [`crypto.randomBytes`] 文档.
+
+不幸的是,您将在浏览器中失去 Web Crypto API 的优势
+如果您使用异步 API。那么,目前在浏览器中,
+您将受到安全性或异步行为的限制。
+
+[`crypto.randomBytes`]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
+
+### 不安全
+
+默认情况下,Nano ID 使用硬件随机字节生成器来实现安全性
+冲突概率低。如果你不那么关心安全
+更关心性能的话,您可以使用更快的非安全生成器.
+
+```js
+import { nanoid } from 'nanoid/non-secure'
+const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
+```
+
+
+### 自定义字母或大小
+
+`customAlphabet` 允许您使用自己的字母表创建 `nanoid`
+和 ID size。
+
+```js
+import { customAlphabet } from 'nanoid'
+const nanoid = customAlphabet('1234567890abcdef', 10)
+model.id = nanoid() //=> "4f90d13a42"
+```
+
+在我们的中 [ID 冲突概率] 计算器检查您的自定义字母表和 ID size 的安全性。
+有关更多字母表, 请在 [`nanoid-dictionary`] 查看选项.
+
+字母表必须包含256个或更少的符号。
+否则,无法保证内部生成器算法的安全性。
+
+还提供了可定制的异步和非安全API:
+
+```js
+import { customAlphabet } from 'nanoid/async'
+const nanoid = customAlphabet('1234567890abcdef', 10)
+async function createUser () {
+ user.id = await nanoid()
+}
+```
+
+```js
+import { customAlphabet } from 'nanoid/non-secure'
+const nanoid = customAlphabet('1234567890abcdef', 10)
+user.id = nanoid()
+```
+
+[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary
+
+
+### 自定义随机字节生成器
+
+`customRandom` 允许您创建一个 `nanoid` 并替换字母表
+和默认的随机字节生成器。
+
+在此示例中,使用基于种子的生成器:
+
+```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` 回调必须接受数组大小并返回随机数的数组。
+
+如果要使用与 `customRandom` 相同的URL友好符号,
+您可以使用 `urlAlphabet` 获取默认字母表。
+
+```js
+const { customRandom, urlAlphabet } = require('nanoid')
+const nanoid = customRandom(urlAlphabet, 10, random)
+```
+
+异步和非安全 API 不适用于 `customRandom`。
+
+## 用法
+
+
+### IE
+
+如果你需要支持 IE, 则需要使用 Babel [转换 `node_modules`]
+并添加 `crypto` 别名:
+
+```js
+// polyfills.js
+if (!window.crypto) {
+ window.crypto = window.msCrypto
+}
+```
+
+```js
+import './polyfills.js'
+import { nanoid } from 'nanoid'
+```
+
+[转换 `node_modules`]: https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/
+
+
+### React
+
+目前还没有将 nanoid 用于 React `key` prop 的正确方法
+因为它在不同的渲染中应该是一致的。
+
+```jsx
+function Todos({todos}) {
+ return (
+