Full Code of ai/nanoid for AI

main 0232baeed59e cached
39 files
138.8 KB
46.8k tokens
23 symbols
1 requests
Download .txt
Repository: ai/nanoid
Branch: main
Commit: 0232baeed59e
Files: 39
Total size: 138.8 KB

Directory structure:
gitextract_garhu55w/

├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       ├── jsr.yml
│       ├── release.yml
│       └── test.yml
├── .gitignore
├── .npmignore
├── .prettierignore
├── CHANGELOG.md
├── LICENSE
├── README.ar.md
├── README.id-ID.md
├── README.ja.md
├── README.ko.md
├── README.md
├── README.ru.md
├── README.zh-CN.md
├── bin/
│   └── nanoid.js
├── eslint.config.js
├── index.browser.js
├── index.d.ts
├── index.js
├── jsr.json
├── nanoid.js
├── non-secure/
│   ├── index.d.ts
│   └── index.js
├── package.json
├── test/
│   ├── benchmark.js
│   ├── bin.test.js
│   ├── check-prebuild.js
│   ├── check-versions.js
│   ├── demo/
│   │   ├── index.html
│   │   ├── index.js
│   │   └── vite.config.js
│   ├── index.test.js
│   ├── non-secure.test.js
│   ├── prebuild.ts
│   └── update-prebuild.js
└── url-alphabet/
    └── index.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[nanoid.js]
insert_final_newline = false


================================================
FILE: .github/FUNDING.yml
================================================
tidelift: npm/nanoid
github: ai


================================================
FILE: .github/workflows/jsr.yml
================================================
name: Publish to JSR
on:
  push:
    tags:
      - '*'
permissions:
  contents: read
  id-token: write
jobs:
  jsr:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - name: Check tag version
        id: check
        run: |
          TAG=${GITHUB_REF#refs/tags/}
          MAJOR=$(echo $TAG | cut -d. -f1)
          if [[ "$MAJOR" =~ ^[0-9]+$ && "$MAJOR" -gt 3 ]]; then
            echo "version_ok=true" >> $GITHUB_OUTPUT
          fi
        shell: bash
      - name: Publish to JSR
        if: steps.check.outputs.version_ok == 'true'
        run: npx jsr publish


================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
  push:
    tags:
      - '*'
permissions:
  contents: write
jobs:
  release:
    name: Release On Tag
    if: startsWith(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    steps:
      - name: Checkout the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - name: Extract the changelog
        id: changelog
        run: |
          TAG_NAME=${GITHUB_REF/refs\/tags\//}
          READ_SECTION=false
          CHANGELOG=""
          while IFS= read -r line; do
            if [[ "$line" =~ ^#+\ +(.*) ]]; then
              if [[ "${BASH_REMATCH[1]}" == "$TAG_NAME" ]]; then
                READ_SECTION=true
              elif [[ "$READ_SECTION" == true ]]; then
                break
              fi
            elif [[ "$READ_SECTION" == true ]]; then
              CHANGELOG+="$line"$'\n'
            fi
          done < "CHANGELOG.md"
          CHANGELOG=$(echo "$CHANGELOG" | awk '/./ {$1=$1;print}')
          echo "changelog_content<<EOF" >> $GITHUB_OUTPUT
          echo "$CHANGELOG" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT
      - name: Create the release
        if: steps.changelog.outputs.changelog_content != ''
        uses: softprops/action-gh-release@1853d73993c8ca1b2c9c1a7fede39682d0ab5c2a # v2.5.3
        with:
          name: ${{ github.ref_name }}
          body: '${{ steps.changelog.outputs.changelog_content }}'
          draft: false
          prerelease: false


================================================
FILE: .github/workflows/test.yml
================================================
name: Test
on:
  push:
    branches:
      - main
      - v3
  pull_request:
permissions:
  contents: read
jobs:
  full:
    name: Node.js Latest Full
    runs-on: ubuntu-latest
    steps:
      - name: Checkout the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - name: Install pnpm
        uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
        with:
          version: 10
      - name: Install Node.js
        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
        with:
          node-version: 25
          cache: pnpm
      - name: Install dependencies
        run: pnpm install --ignore-scripts
      - name: Run tests
        run: pnpm test
  short:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version:
          - 24
          - 22
          - 20
          - 18
    name: Node.js ${{ matrix.node-version }} Quick
    steps:
      - name: Checkout the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - name: Install pnpm
        uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
        with:
          version: 10
      - name: Install Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
        with:
          node-version: ${{ matrix.node-version }}
          cache: pnpm
      - name: Install dependencies
        run: pnpm install --ignore-scripts
      - name: Run unit tests
        run: pnpm bnt
  benchmark:
    name: Benchmark
    runs-on: ubuntu-latest
    steps:
      - name: Checkout the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - name: Install pnpm
        uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
        with:
          version: 10
      - name: Install Node.js
        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
        with:
          node-version: 22
          cache: pnpm
      - name: Install dependencies
        run: pnpm install --ignore-scripts
      - name: Run benchmark
        run: node ./test/benchmark.js


================================================
FILE: .gitignore
================================================
node_modules/

coverage/


================================================
FILE: .npmignore
================================================
test/
tsconfig.json
coverage/

img/

jsr.json


================================================
FILE: .prettierignore
================================================
nanoid.js


================================================
FILE: CHANGELOG.md
================================================
# Change Log
This project adheres to [Semantic Versioning](http://semver.org/).

## 5.1.7
* Added `--version` to CLI (by @mahmoodhamdi).
* Updated `nanoid.js` for CDN (by @mahmoodhamdi).
* Fixed docs (by @mahmoodhamdi).
* Fixed `customRandom` types (by @oguimbal).

## 5.1.6
* Fixed infinite loop on 0 size for `customAlphabet`.

## 5.1.5
* Fixed latest version on npm after 3.x release.

## 5.1.4
* Fixed latest version on npm after 3.x release.

## 5.1.3
* Fixed React Native support (by @steida).

## 5.1.2
* Fixed module docs.

## 5.1.1
* Fixed opaque types support for non-secure generator.
* Added JSR support.

## 5.1.0
* Added opaque types support (by @kossnocorp).

## 5.0.9
* Fixed a way to break Nano ID by passing non-integer size (by @myndzi).

## 5.0.8
* Reduced `customAlphabet` size (by @kirillgroshkov).

## 5.0.7
* Fixed Parcel support (by @WilhelmYakunin).

## 5.0.6
* Fixed React Native support.

## 5.0.5
* Make browser’s version faster by increasing size a little (by Samuel Elgozi).

## 5.0.4
* Fixed CLI docs (by @ilyaboka).

## 5.0.3
* Fixed CLI docs (by Chris Schmich).

## 5.0.2
* Fixed `webcrypto` import (by Divyansh Singh).

## 5.0.1
* Fixed Node.js 18 support.

## 5.0
* Moved Node.js version to Web Crypto API.
* Removed async API since Web Crypto API has only sync version.
* Removed Node.js 14 and 16 support.

## 4.0.2
* Added [link](https://github.com/sponsors/ai) to Github Sponsors.

## 4.0.1
* Reduced npm package size (by @HiChen404).

## 4.0
* Removed CommonJS support. Nano ID 4 will work only with ESM applications.
  We will support 3.x branch with CommonJS for users who can’t migrate to ESM.
* Removed Node.js 10 and Node.js 12 support.
* Reduced npm package size.

## 3.3.11
* Fixed React Native support.

## 3.3.10
* Fixed React Native support (by @steida).

## 3.3.9
* Reduced npm package size.

## 3.3.8
* Fixed a way to break Nano ID by passing non-integer size (by @myndzi).

## 3.3.7
* Fixed `node16` TypeScript support (by Saadi Myftija).

## 3.3.6
* Fixed package.

## 3.3.5
* Backport funding information.

## 3.3.4
* Fixed `--help` in CLI (by @Lete114).

## 3.3.3
* Reduced size (by Anton Khlynovskiy).

## 3.3.2
* Fixed `enhanced-resolve` support.

## 3.3.1
* Reduced package size.

## 3.3
* Added `size` argument to function from `customAlphabet` (by Stefan Sundin).

## 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.

## 3.1.24
* Fixed `browserify` support (by Artur Paikin).

## 3.1.23
* Fixed `esbuild` support.

## 3.1.22
* Added `default` and `browser.default` to `package.exports`.

## 3.1.21
* Reduced npm package size.

## 3.1.20
* Fix ES modules support.

## 3.1.19
* Reduced `customAlphabet` size (by Enrico Scherlies).

## 3.1.18
* Fixed `package.exports`.

## 3.1.17
* Added files without `process`.

## 3.1.16
* Speeded up Nano ID 4 times (by Peter Boyer).

## 3.1.15
* Fixed `package.types` path.

## 3.1.14
* Added `package.types`.

## 3.1.13
* Removed Node.js 15.0.0 with `randomFillSync` regression from `engines.node`.

## 3.1.12
* Improved IE 11 docs.

## 3.1.11
* Fixed asynchronous `customAlphabet` in browser (by @LoneRifle).

## 3.1.10
* Fix ES modules support.

## 3.1.9
* Try to fix React Native Expo support.

## 3.1.8
* Add React Native Expo support.

## 3.1.7
* Clean up code.

## 3.1.6
* Avoid `self` using.

## 3.1.5
* Improve IE docs and warning.

## 3.1.4
* Restrict old Node.js 13 by `engines.node` (by Cansin Yildiz).

## 3.1.3
* Fix ES modules issue with CLI.

## 3.1.2
* Add shebang to CLI.

## 3.1.1
* Fix CLI.

## 3.1
* Add `npx nanoid` CLI.

## 3.0.2
* Fix docs (by Dylan Irlbeck ).

## 3.0.1
* Fix React Native warning on `non-secure` import (by Jia Huang).

## 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
* Reduce size (by Anton Evzhakov).

## 2.1.10
* Reduce size by 10% (by Anton Khlynovskiy).

## 2.1.9
* Reduce `format` and `async/format` size (by Dair Aidarkhanov).

## 2.1.8
* Improve React docs (by Nahum Zsilva).

## 2.1.7
* Reduce `index`, `async` and `non-secure` size (by @polemius).

## 2.1.6
* Reduce size (by Stas Lashmanov).
* Return fast mask for Node.js.

## 2.1.5
* Reduce size (by Max Graey).
* Fix IE support.

## 2.1.4
* Reduce `generate` size (by Vsevolod Rodionov).
* Reduce `format` and `format` size (by Victor).
* Reduce `async`, `non-secure` and `non-secure/generate` size.
* Speed up `format` and `async/format` (by Max Graey).
* Improve development process on Windows (by Stanislav Lashmanov).

## 2.1.3
* Improve performance (by Stephen Richardson).
* Reduce size (by Stephen Richardson).

## 2.1.2
* Improve docs.

## 2.1.1
* Fix React Native support (by Shawn Hwei).

## 2.1
* Improve React Native support (by Sebastian Werner).

## 2.0.4
* Improve error text for React Native (by Sebastian Werner).

## 2.0.3
* Fix freeze on string in ID length.

## 2.0.2
* Improve docs (by Sylvanus Kateile and Mark Stosberg).

## 2.0.1
* Reduce npm package size.
* Mark package as not having side effects (by @xiaody).

## 2.0
* Use `-` instead of `~` in default alphabet to by file name safe.
* Add `nanoid/non-secure/generate`.

## 1.3.4
* Reduce `non-secure` size.
* Add `async` callback type check.

## 1.3.3
* Fix `nanoid/async` performance regression.
* Fix old Node.js `not seeded` issue in synchronous version too.

## 1.3.2
* Fix random generator `not seeded` issue of old Node.js.

## 1.3.1
* Reduce library size.

## 1.3
* Add `nanoid/async/format` and `nanoid/async/generate`.
* Improve synchronous API performance.
* Reduce `url` size (by Daniil Poroshin).
* Improve React Native docs (by joelgetaction).

## 1.2.6
* Reduce library size (by rqrqrqrq).

## 1.2.5
* Fix Node.js 6.11.1 support (by Andrey Belym).

## 1.2.4
* Speed up Node.js secure generators (by Dmitriy Tsvettsikh).

## 1.2.3
* Fix JSDoc (by Hendry Sadrak).

## 1.2.2
* Fix distribution in `nanoid/non-secure` (by Eatall).

## 1.2.1
* Fix old Node.js support.

## 1.2
* Add `nanoid/async`.
* Fix `nanoid/non-secure` JSDoc.
* Add Chinese documentation (by Wenliang Dai).
* Speed up and reduce size of `nanoid/non-secure` (by Ori Livni).

## 1.1.1
* Improve performance and reduce size of non-secure ID generator.

## 1.1
* Add non-secure ID generator.
* Suggest to use non-secure ID generator for React Native developers.
* Reduce size.

## 1.0.7
* Fix documentation.

## 1.0.6
* Fix documentation.

## 1.0.5
* Reduce `nanoid/index` size (by Anton Khlynovskiy).

## 1.0.4
* Reduce npm package size.

## 1.0.3
* Reduce npm package size.

## 1.0.2
* Fix Web Workers support (by Zachary Golba).

## 1.0.1
* Reduce `nanoid/index` size (by Anton Khlynovskiy).

## 1.0
* Use 21 symbols by default (by David Klebanoff).

## 0.2.2
* Reduce `nanoid/generate` size (by Anton Khlynovskiy).
* Speed up Node.js random generator.

## 0.2.1
* Fix documentation (by Piper Chester).

## 0.2
* Add `size` argument to `nanoid()`.
* Improve performance by 50%.
* Reduce library size by 26% (by Vsevolod Rodionov and Oleg Mokhov).

## 0.1.1
* Reduce library size by 5%.

## 0.1
* Initial release.


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright 2017 Andrey Sitnik <andrey@sitnik.ru>

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: README.ar.md
================================================
# Nano ID

<img src="https://ai.github.io/nanoid/logo.svg" align="right"
     alt="Nano ID logo by Anton Lovchikov" width="180" height="94">

<div dir="rtl">

[English](./README.md) | [日本語](./README.ja.md) | [Русский](./README.ru.md) | [简体中文](./README.zh-CN.md) | [Bahasa Indonesia](./README.id-ID.md) | [한국어](./README.ko.md) | **العربية**

مُولِّد مُعرِّفات فريدة صغير الحجم وآمن ومتوافق مع الروابط (URL) لجافاسكربت.

> "مستوى مذهل من الكمالية التي لا معنى لها،
> والتي يستحيل ألّا تحظى بالاحترام."

* **صغير الحجم.** 118 بايت فقط (بعد التصغير والضغط ببروتلي). بدون أيّ اعتماديات خارجية.
  يتم التحكّم بالحجم عبر [Size Limit].
* **آمن.** يستخدم مُولِّد أرقام عشوائية على مستوى العتاد. يمكن استخدامه في بيئات الكلستر.
* **مُعرِّفات قصيرة.** يستخدم أبجدية أكبر من UUID وهي (`A-Za-z0-9_-`).
  لذا تم تقليص حجم المُعرِّف من 36 إلى 21 رمزًا.
* **قابل للنقل.** تم نقل Nano ID
  إلى أكثر من [20 لغة برمجة](./README.md#other-programming-languages).

</div>

```js
import { nanoid } from 'nanoid'
model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
```

---

<img src="https://cdn.evilmartians.com/badges/logo-no-label.svg" alt="" width="22" height="16" />  Made at <b><a href="https://evilmartians.com/devtools?utm_source=nanoid&utm_campaign=devtools-button&utm_medium=github">Evil Martians</a></b>, product consulting for <b>developer tools</b>.

---

[online tool]: https://gitpod.io/#https://github.com/ai/nanoid/
[with 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


<div dir="rtl">

## جدول المحتويات

- [جدول المحتويات](#جدول-المحتويات)
- [المقارنة مع UUID](#المقارنة-مع-uuid)
- [اختبار الأداء](#اختبار-الأداء)
- [الأمان](#الأمان)
- [التثبيت](#التثبيت)
  - [ESM](#esm)
  - [CommonJS](#commonjs)
  - [JSR](#jsr)
  - [CDN](#cdn)
- [واجهة البرمجة (API)](#واجهة-البرمجة-api)
  - [متزامن (Blocking)](#متزامن-blocking)
  - [غير آمن (Non-Secure)](#غير-آمن-non-secure)
  - [أبجدية أو حجم مخصّص](#أبجدية-أو-حجم-مخصّص)
  - [مُولِّد بايتات عشوائية مخصّص](#مُولِّد-بايتات-عشوائية-مخصّص)
- [الاستخدام](#الاستخدام)
  - [React](#react)
  - [React Native](#react-native)
  - [PouchDB و CouchDB](#pouchdb-و-couchdb)
  - [سطر الأوامر (CLI)](#سطر-الأوامر-cli)
  - [TypeScript](#typescript)
  - [لغات البرمجة الأخرى](#لغات-البرمجة-الأخرى)
- [الأدوات](#الأدوات)


## المقارنة مع UUID

Nano ID قابل للمقارنة مع UUID v4 (المبني على العشوائية).
يحتوي على عدد مماثل من البتّات العشوائية في المُعرِّف
(126 في Nano ID و122 في UUID)، لذا فإنّ احتمالية التكرار متقاربة:

> لكي تكون هناك فرصة واحدة من مليار لحدوث تكرار،
> يجب توليد 103 تريليون مُعرِّف من النوع v4.

يوجد اختلافان رئيسيان بين Nano ID و UUID v4:

1. يستخدم Nano ID أبجدية أكبر، لذا يتم ضغط عدد مماثل من البتّات العشوائية
   في 21 رمزًا فقط بدلاً من 36.
2. كود Nano ID أصغر بـ **4 مرات** من حزمة `uuid/v4`:
   118 بايت مقابل 423.


## اختبار الأداء

</div>

```rust
$ node ./test/benchmark.js
crypto.randomUUID          7,619,041 ops/sec
uuid v4                    7,436,626 ops/sec
@napi-rs/uuid              4,730,614 ops/sec
uid/secure                 4,729,185 ops/sec
@lukeed/uuid               4,015,673 ops/sec
nanoid                     3,693,964 ops/sec
customAlphabet             2,799,255 ops/sec
nanoid for browser           380,915 ops/sec
secure-random-string         362,316 ops/sec
uid-safe.sync                354,234 ops/sec
shortid                       38,808 ops/sec

Non-secure:
uid                       11,872,105 ops/sec
nanoid/non-secure          2,226,483 ops/sec
rndm                       2,308,044 ops/sec
```

<div dir="rtl">

بيئة الاختبار: Framework 13 7840U، فيدورا 39، Node.js 21.6.


## الأمان

*اقرأ مقالاً جيداً عن نظرية مُولِّدات الأرقام العشوائية:
[Secure random values (in Node.js)]*

* **عدم القابلية للتنبؤ.** بدلاً من استخدام `Math.random()` غير الآمن، يستخدم Nano ID
  وحدة `crypto` في Node.js و Web Crypto API في المتصفحات.
  هذه الوحدات تستخدم مُولِّد أرقام عشوائية على مستوى العتاد لا يمكن التنبؤ به.
* **التوزيع المنتظم.** `random % alphabet` هو خطأ شائع عند برمجة مُولِّد مُعرِّفات.
  التوزيع لن يكون متساويًا؛ بعض الرموز ستظهر بتواتر أقل من غيرها.
  وهذا يقلّل عدد المحاولات اللازمة للكسر بالقوة الغاشمة. يستخدم Nano ID
  [خوارزمية أفضل] وقد تم اختباره للتحقّق من انتظام التوزيع.

  <img src="img/distribution.png" alt="انتظام توزيع Nano ID"
     width="340" height="135">

* **موثّق جيداً:** جميع الحيل البرمجية في Nano ID موثّقة. اطّلع على التعليقات
  في [الكود المصدري].
* **الثغرات الأمنية:** للإبلاغ عن ثغرة أمنية، يُرجى استخدام
  [جهة اتصال Tidelift الأمنية](https://tidelift.com/security).
  سيقوم Tidelift بتنسيق الإصلاح والإفصاح.

[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


## التثبيت

### ESM

يعمل Nano ID 5 مع مشاريع ESM (باستخدام `import`) في الاختبارات أو سكربتات Node.js.

</div>

```bash
npm install nanoid
```

<div dir="rtl">

### CommonJS

يمكن استخدام Nano ID مع CommonJS بإحدى الطرق التالية:

- يمكنك استخدام `require()` لاستيراد Nano ID. تحتاج إلى استخدام أحدث إصدار من
  Node.js 22.12 (يعمل مباشرة) أو Node.js 20
  (مع علامة `--experimental-require-module`).

- لـ Node.js 18 يمكنك استيراد Nano ID ديناميكيًا كالتالي:

</div>

  ```js
  let nanoid
  module.exports.createID = async () => {
    if (!nanoid) ({ nanoid } = await import('nanoid'))
    return nanoid() // => "V1StGXR8_Z5jdHi6B-myT"
  }
  ```

<div dir="rtl">

- يمكنك استخدام Nano ID 3.x (ما زلنا ندعمه):

</div>

  ```bash
  npm install nanoid@3
  ```

<div dir="rtl">

### JSR

[JSR](https://jsr.io) هو بديل لـ npm بحوكمة مفتوحة
وتطوير نشط (على عكس npm).

</div>

```bash
npx jsr add @sitnik/nanoid
```

<div dir="rtl">

يمكنك استخدامه في Node.js و Deno و Bun وغيرها.

</div>

```js
// استبدل `nanoid` بـ `@sitnik/nanoid` في جميع الاستيرادات
import { nanoid } from '@sitnik/nanoid'
```

<div dir="rtl">

لـ Deno ثبّته عبر `deno add jsr:@sitnik/nanoid` أو استورده
من `jsr:@sitnik/nanoid`.


### CDN

للتجارب السريعة، يمكنك تحميل Nano ID من CDN. لكن لا يُنصح باستخدامه
في الإنتاج بسبب انخفاض أداء التحميل.

</div>

```js
import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'
```

<div dir="rtl">

## واجهة البرمجة (API)

يمتلك Nano ID واجهتي برمجة: عادية وغير آمنة.

بشكل افتراضي، يستخدم Nano ID رموزًا متوافقة مع الروابط (`A-Za-z0-9_-`) ويُنتج مُعرِّفًا
مكوّنًا من 21 حرفًا (ليكون احتمال التكرار مماثلاً لـ UUID v4).


### متزامن (Blocking)

الطريقة الأسهل والأكثر أمانًا لاستخدام Nano ID.

في حالات نادرة قد يحجب المعالج عن العمليات الأخرى أثناء جمع الضوضاء
لمُولِّد الأرقام العشوائية على مستوى العتاد.

</div>

```js
import { nanoid } from 'nanoid'
model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
```

<div dir="rtl">

إذا أردت تقليل حجم المُعرِّف (وزيادة احتمالية التكرار)،
يمكنك تمرير الحجم كمعامل.

</div>

```js
nanoid(10) //=> "IRFa-VaY2b"
```

<div dir="rtl">

لا تنسَ التحقّق من أمان حجم المُعرِّف الخاص بك
عبر حاسبة [احتمالية تكرار المُعرِّف].

يمكنك أيضًا استخدام [أبجدية مخصّصة](#أبجدية-أو-حجم-مخصّص)
أو [مُولِّد أرقام عشوائية مخصّص](#مُولِّد-بايتات-عشوائية-مخصّص).

[احتمالية تكرار المُعرِّف]: https://zelark.github.io/nano-id-cc/


### غير آمن (Non-Secure)

بشكل افتراضي، يستخدم Nano ID توليد بايتات عشوائية على مستوى العتاد
من أجل الأمان وتقليل احتمالية التكرار. إذا لم يكن الأمان مهمًا بالنسبة لك،
يمكنك استخدامه في بيئات لا تتوفر فيها مُولِّدات أرقام عشوائية على مستوى العتاد.

</div>

```js
import { nanoid } from 'nanoid/non-secure'
const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
```

<div dir="rtl">

### أبجدية أو حجم مخصّص

تُرجع `customAlphabet` دالة تتيح لك إنشاء `nanoid`
بأبجديتك وحجمك الخاصّين.

</div>

```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()
```

<div dir="rtl">

تحقّق من أمان أبجديتك المخصّصة وحجم المُعرِّف عبر
حاسبة [احتمالية تكرار المُعرِّف]. لمزيد من خيارات الأبجديات، اطّلع على
[`nanoid-dictionary`].

يجب أن تحتوي الأبجدية على 256 رمزًا أو أقل.
وإلا فإن أمان خوارزمية المُولِّد الداخلية غير مضمون.

بالإضافة إلى تحديد حجم افتراضي، يمكنك تغيير حجم المُعرِّف عند استدعاء
الدالة:

</div>

```js
import { customAlphabet } from 'nanoid'
const nanoid = customAlphabet('1234567890abcdef', 10)
model.id = nanoid(5) //=> "f01a2"
```

[احتمالية تكرار المُعرِّف]: https://zelark.github.io/nano-id-cc/
[`nanoid-dictionary`]:      https://github.com/CyberAP/nanoid-dictionary

<div dir="rtl">

### مُولِّد بايتات عشوائية مخصّص

تتيح لك `customRandom` إنشاء `nanoid` واستبدال الأبجدية
ومُولِّد البايتات العشوائية الافتراضي.

في هذا المثال، يتم استخدام مُولِّد مبني على بذرة (seed):

</div>

```js
import { customRandom } from 'nanoid'

const rng = seedrandom(seed)
const nanoid = customRandom('abcdef', 10, size => {
  return (new Uint8Array(size)).map(() => 256 * rng())
})

nanoid() //=> "fbaefaadeb"
```

<div dir="rtl">

يجب أن تقبل دالة `random` حجم المصفوفة وتُرجع مصفوفة
من الأرقام العشوائية.

إذا أردت استخدام نفس الرموز المتوافقة مع الروابط مع `customRandom`،
يمكنك الحصول على الأبجدية الافتراضية عبر `urlAlphabet`.

</div>

```js
const { customRandom, urlAlphabet } = require('nanoid')
const nanoid = customRandom(urlAlphabet, 10, random)
```

<div dir="rtl">

ملاحظة: بين إصدارات Nano ID قد يتغيّر تسلسل استدعاء مُولِّد الأرقام العشوائية.
إذا كنت تستخدم مُولِّدات مبنية على بذرة، فإننا لا نضمن نفس النتيجة.


## الاستخدام

### React

لا توجد طريقة صحيحة لاستخدام Nano ID كخاصية `key` في React
لأنها يجب أن تكون ثابتة بين عمليات التصيير (renders).

</div>

```jsx
function Todos({todos}) {
  return (
    <ul>
      {todos.map(todo => (
        <li key={nanoid()}> /* لا تفعل هذا */
          {todo.text}
        </li>
      ))}
    </ul>
  )
}
```

<div dir="rtl">

يجب عليك بدلاً من ذلك استخدام مُعرِّف ثابت من داخل عنصر القائمة.

</div>

```jsx
const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
)
```

<div dir="rtl">

في حال لم تمتلك مُعرِّفات ثابتة، يُفضّل استخدام الفهرس (index)
كـ `key` بدلاً من `nanoid()`:

</div>

```jsx
const todoItems = todos.map((text, index) =>
  <li key={index}> /* غير مُوصى به لكنه أفضل من nanoid().
                      استخدمه فقط إذا لم تكن لديك مُعرِّفات ثابتة. */
    {text}
  </li>
)
```

<div dir="rtl">

إذا كنت تحتاج فقط إلى مُعرِّفات عشوائية لربط العناصر ببعضها مثل
labels وحقول الإدخال، يُنصح باستخدام [`useId`].
تمت إضافة هذا الـ hook في React 18.

[`useId`]: https://react.dev/reference/react/useId


### React Native

لا يحتوي React Native على مُولِّد أرقام عشوائية مدمج. يعمل البوليفِل التالي
مع React Native العادي و Expo بدءًا من الإصدار `39.x`.

1. اطّلع على توثيق [`react-native-get-random-values`] وثبّتها.
2. استوردها قبل Nano ID.

</div>

```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

<div dir="rtl">

### PouchDB و CouchDB

في PouchDB و CouchDB، لا يمكن أن تبدأ المُعرِّفات بشرطة سفلية `_`.
يلزم إضافة بادئة لتجنّب هذه المشكلة، لأن Nano ID قد يستخدم `_`
في بداية المُعرِّف بشكل افتراضي.

أَعِد تعريف المُعرِّف الافتراضي بالخيار التالي:

</div>

```js
db.put({
  _id: 'id' + nanoid(),
  …
})
```

<div dir="rtl">

### سطر الأوامر (CLI)

يمكنك الحصول على مُعرِّف فريد في الطرفية عبر تشغيل `npx nanoid`. تحتاج فقط
إلى Node.js مثبّتًا على النظام. لا يلزم تثبيت Nano ID مسبقًا.

</div>

```sh
$ npx nanoid
npx: installed 1 in 0.63s
LZfXLFzPPR4NNrgjlWDxn
```

<div dir="rtl">

يمكن تحديد حجم المُعرِّف المُولَّد عبر خيار `--size` (أو `-s`):

</div>

```sh
$ npx nanoid --size 10
L3til0JS4z
```

<div dir="rtl">

يمكن تحديد أبجدية مخصّصة عبر خيار `--alphabet` (أو `-a`)
(لاحظ أن `--size` مطلوب في هذه الحالة):

</div>

```sh
$ npx nanoid --alphabet abc --size 15
bccbcabaabaccab
```

<div dir="rtl">

### TypeScript

يتيح Nano ID تحويل النصوص المُولَّدة إلى أنواع مبهمة (opaque types) في TypeScript.
مثال:

</div>

```ts
declare const userIdBrand: unique symbol
type UserId = string & { [userIdBrand]: true }

// استخدم معامل النوع الصريح:
mockUser(nanoid<UserId>())

interface User {
  id: UserId
  name: string
}

const user: User = {
  // يتم التحويل تلقائيًا إلى UserId:
  id: nanoid(),
  name: 'Alice'
}
```

<div dir="rtl">

### لغات البرمجة الأخرى

تم نقل Nano ID إلى العديد من اللغات. يمكنك استخدام هذه الإصدارات للحصول
على نفس مُولِّد المُعرِّفات على جانبَي العميل والخادم.

</div>

* [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)

<div dir="rtl">

للبيئات الأخرى، يتوفر [سطر الأوامر] لتوليد المُعرِّفات من الطرفية.

[سطر الأوامر]: #سطر-الأوامر-cli


## الأدوات

* [حاسبة حجم المُعرِّف] تعرض احتمالية التكرار عند تعديل
  أبجدية المُعرِّف أو حجمه.
* [`nanoid-dictionary`] تحتوي على أبجديات شائعة لاستخدامها مع [`customAlphabet`].
* [`nanoid-good`] للتأكد من أن المُعرِّف لا يحتوي على كلمات غير لائقة.

[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary
[حاسبة حجم المُعرِّف]:  https://zelark.github.io/nano-id-cc/
[`customAlphabet`]:    #أبجدية-أو-حجم-مخصّص
[`nanoid-good`]:       https://github.com/y-gagar1n/nanoid-good

</div>


================================================
FILE: README.id-ID.md
================================================
# Nano ID

<img src="https://ai.github.io/nanoid/logo.svg" align="right"
     alt="Logo Nano ID oleh Anton Lovchikov" width="180" height="94">

[English](./README.md) | [日本語](./README.ja.md) | [Русский](./README.ru.md) | [简体中文](./README.zh-CN.md) | **Bahasa Indonesia** | [한국어](./README.ko.md) | [العربية](./README.ar.md)

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 118 bytes (diperkecil dan brotlied). Tidak ada ketergantungan (dependencies) apapun. [Size Limit](https://github.com/ai/size-limit) mengatur ukuran dari generator ini.
- **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.

---

<img src="https://cdn.evilmartians.com/badges/logo-no-label.svg" alt="" width="22" height="16" />  Made at <b><a href="https://evilmartians.com/devtools?utm_source=nanoid&utm_campaign=devtools-button&utm_medium=github">Evil Martians</a></b>, product consulting for <b>developer tools</b>.

---


## Table of Contents

- [Table of Contents](#table-of-contents)
- [Perbandingan dengan UUID](#perbandingan-dengan-uuid)
- [Benchmark](#benchmark)
- [Keamanan](#keamanan)
- [Instalasi](#instalasi)
- [API](#api)
  - [Blocking](#blocking)
  - [Non-Secure](#non-secure)
  - [Alfabet dan Ukuran (Custom)](#alfabet-dan-ukuran-custom)
  - [Generasi Random Bytes (Custom)](#generasi-random-bytes-custom)
- [Penggunaan](#penggunaan)
  - [React](#react)
  - [React Native](#react-native)
  - [PouchDB dan CouchDB](#pouchdb-dan-couchdb)
  - [CLI](#cli)
  - [TypeScript](#typescript)
  - [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 dua 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`: 118 bytes dibanding 423 bytes.


## Benchmark

```rust
$ node ./test/benchmark.js
crypto.randomUUID          7,619,041 ops/sec
uuid v4                    7,436,626 ops/sec
@napi-rs/uuid              4,730,614 ops/sec
uid/secure                 4,729,185 ops/sec
@lukeed/uuid               4,015,673 ops/sec
nanoid                     3,693,964 ops/sec
customAlphabet             2,799,255 ops/sec
nanoid for browser           380,915 ops/sec
secure-random-string         362,316 ops/sec
uid-safe.sync                354,234 ops/sec
shortid                       38,808 ops/sec

Non-secure:
uid                       11,872,105 ops/sec
nanoid/non-secure          2,226,483 ops/sec
rndm                       2,308,044 ops/sec
```

Konfigurasi pengujian: Framework 13 7840U, Fedora 39, Node.js 21.6.


## 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.

  <img src="img/distribution.png" alt="Nano ID uniformity"
    width="340" height="135">

- **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 nanoid
```

Nano ID 5 hanya tersedia untuk proyek, pengujian, atau skrip ESM Node.js.
Untuk CommonJS Anda memerlukan Nano ID 3.x (kami masih mendukungnya):

```bash
npm install nanoid@3
```

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'
```


## API

Nano ID memiliki dua API: normal 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.


### 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://zelark.github.io/nano-id-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 non-secure yang dapat dikustomisasi dengan `customAlphabet` pun tersedia disini:

```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

### 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 (
    <ul>
      {todos.map(todo => (
        /* JANGAN DILAKUKAN! */
        <li key={nanoid()}>{todo.text}</li>
      ))}
    </ul>
  )
}
```

Karena hal tersebut, disarankan untuk menggunakan ID yang stabil pada setiap objek yang di-render oleh React.

```jsx
const todoItems = todos.map(todo => <li key={todo.id}>{todo.text}</li>)
```

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. */
  <li key={index}>{text}</li>
))
```

### 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'
```

### 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(),
  …
})
```


### 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).

### TypeScript

Nano ID memungkinkan untuk mengubah string yang dihasilkan menjadi string opak
dalam TypeScript. Sebagai contoh:

```ts
declare const userIdBrand: unique symbol
type UserId = string & { [userIdBrand]: true }

// Gunakan parameter tipe secara eksplisit:
mockUser(nanoid<UserId>())

interface User {
  id: UserId
  name: string
}

const user: User = {
  // Secara otomatis diubah menjadi UserId:
  id: nanoid(),
  name: 'Alice'
}
```

### 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)
- [Elixir](https://github.com/railsmechanic/nanoid)
- [Gleam](https://github.com/0xca551e/glanoid)
- [Go](https://github.com/jaevor/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](https://github.com/puyuan/py-nanoid) with [dictionaries](https://pypi.org/project/nanoid-dictionary)
- [Postgres Extension](https://github.com/spa5k/uids-postgres)
- [Postgres 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)

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.).


================================================
FILE: README.ja.md
================================================
# Nano ID

<img src="https://ai.github.io/nanoid/logo.svg" align="right"
     alt="Nano ID logo by Anton Lovchikov" width="180" height="94">

[English](./README.md) | **日本語** | [Русский](./README.ru.md) | [简体中文](./README.zh-CN.md) | [Bahasa Indonesia](./README.id-ID.md) | [한국어](./README.ko.md) | [العربية](./README.ar.md)

JavaScriptのための小さく、安全で、URL友好的なユニークな文字列ID生成器。

> 「意味不明なレベルの完璧主義、
> これは尊敬せざるを得ない。」

* **小さい。** 118バイト(圧縮・brotli圧縮後)。依存関係なし。
  [Size Limit]がサイズを管理。
* **安全。** ハードウェア乱数生成器を使用。クラスタでも利用可能。
* **短いID。** UUIDより大きなアルファベット(A-Za-z0-9_-)を使用。
  そのためID長は36から21文字に短縮されています。
* **移植性。** Nano IDは[20以上のプログラミング言語](./README.md#other-programming-languages)に移植されています。

```js
import { nanoid } from 'nanoid'
model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
```

---

<img src="https://cdn.evilmartians.com/badges/logo-no-label.svg" alt="" width="22" height="16" />  Made at <b><a href="https://evilmartians.com/devtools?utm_source=nanoid&utm_campaign=devtools-button&utm_medium=github">Evil Martians</a></b>, product consulting for <b>developer tools</b>.

---

[online tool]: https://gitpod.io/#https://github.com/ai/nanoid/
[with 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との比較)
- [ベンチマーク](#ベンチマーク)
- [セキュリティ](#セキュリティ)
- [インストール](#インストール)
  - [ESM](#esm)
  - [CommonJS](#commonjs)
  - [JSR](#jsr)
  - [CDN](#cdn)
- [API](#api)
  - [ブロッキング](#ブロッキング)
  - [非セキュア](#非セキュア)
  - [カスタムアルファベットまたはサイズ](#カスタムアルファベットまたはサイズ)
  - [カスタムランダムバイト生成器](#カスタムランダムバイト生成器)
- [使用方法](#使用方法)
  - [React](#react)
  - [React Native](#react-native)
  - [PouchDBとCouchDB](#pouchdbとcouchdb)
  - [CLI](#cli)
  - [TypeScript](#typescript)
  - [その他のプログラミング言語](#その他のプログラミング言語)
- [ツール](#ツール)


## UUIDとの比較

Nano IDはUUID v4(ランダムベース)と十分に比較可能です。
ID内のランダムビット数は同様です(Nano IDで126ビット、UUIDで122ビット)、
そのため衝突確率も同様です:

> 10億分の1の確率で重複が発生するには、
> 103兆個のバージョン4 IDを生成する必要があります。

Nano IDとUUID v4の主な違いは2つあります:

1. Nano IDはより大きなアルファベットを使用するため、同様のランダムビット数が
   36文字ではなく21文字に詰め込まれています。
2. Nano IDのコードはuuid/v4パッケージより**4倍小さい**です:
   423バイトではなく118バイトです。


## ベンチマーク

```rust
$ node ./test/benchmark.js
crypto.randomUUID          7,619,041 ops/sec
uuid v4                    7,436,626 ops/sec
@napi-rs/uuid              4,730,614 ops/sec
uid/secure                 4,729,185 ops/sec
@lukeed/uuid               4,015,673 ops/sec
nanoid                     3,693,964 ops/sec
customAlphabet             2,799,255 ops/sec
nanoid for browser           380,915 ops/sec
secure-random-string         362,316 ops/sec
uid-safe.sync                354,234 ops/sec
shortid                       38,808 ops/sec

Non-secure:
uid                       11,872,105 ops/sec
nanoid/non-secure          2,226,483 ops/sec
rndm                       2,308,044 ops/sec
```

テスト構成:Framework 13 7840U, Fedora 39, Node.js 21.6.


## セキュリティ

*乱数生成器の理論に関する良い記事を参照してください:
[Secure random values (in Node.js)]*

* **予測不可能性。** 安全でないMath.random()を使う代わりに、Nano IDは
  Node.jsではcryptoモジュールを、ブラウザではWeb Crypto APIを使用します。
  これらのモジュールは予測不可能なハードウェア乱数生成器を使用します。
* **均一性。** random % alphabetはID生成器をコーディングする際によくある間違いです。
  分布は均一ではなく、一部の記号が他のものより出現確率が低くなります。
  そのため、総当たり攻撃の際に試行回数が減少します。Nano IDは[より良いアルゴリズム]を
  使用し、均一性についてテストされています。

  <img src="img/distribution.png" alt="Nano ID uniformity"
     width="340" height="135">

* **十分に文書化されている:** Nano IDのすべてのハックは文書化されています。
  [ソース]のコメントを参照してください。
* **脆弱性:** セキュリティの脆弱性を報告するには、
  [Tideliftセキュリティ連絡先](https://tidelift.com/security)を使用してください。
  Tideliftが修正と開示を調整します。

[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


## インストール

### ESM

Nano ID 5はESMプロジェクト(importを使用)のテストやNode.jsスクリプトで動作します。

```bash
npm install nanoid
```

### CommonJS

Nano IDは以下のいずれかの方法でCommonJSで使用できます:

- require()を使用してNano IDをインポートできます。最新のNode.js 22.12
  (標準で動作)またはNode.js 20(--experimental-require-moduleオプション付き)が必要です。

- Node.js 18では、次のようにNano IDを動的にインポートできます:

  ```js
  let nanoid
  module.exports.createID = async () => {
    if (!nanoid) ({ nanoid } = await import('nanoid'))
    return nanoid() // => "V1StGXR8_Z5jdHi6B-myT"
  }
  ```

- Nano ID 3.xを使用できます(まだサポートしています):

  ```bash
  npm install nanoid@3
  ```

### JSR

[JSR](https://jsr.io)はオープンなガバナンスと積極的な開発(npmとは対照的に)を持つnpmの代替です。

```bash
npx jsr add @sitnik/nanoid
```

Node.js、Deno、Bunなどで使用できます。

```js
// すべてのインポートで`nanoid`を`@sitnik/nanoid`に置き換える
import { nanoid } from '@sitnik/nanoid'
```

Denoでは、`deno add jsr:@sitnik/nanoid`でインストールするか、
`jsr:@sitnik/nanoid`からインポートします。


### CDN

クイックハックの場合、CDNからNano IDを読み込むことができます。ただし、読み込みパフォーマンスが低いため、本番環境での使用はお勧めしません。

```js
import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'
```

## API

Nano IDには2つのAPI:通常と非セキュアがあります。

デフォルトでは、Nano IDはURL友好的な記号(A-Za-z0-9_-)を使用し、
21文字のID(UUID v4と同様の衝突確率を持つ)を返します。


### ブロッキング

Nano IDを使用する安全で最も簡単な方法です。

まれに、ハードウェア乱数生成器のノイズ収集中にCPUを他の作業からブロックする場合があります。

```js
import { nanoid } from 'nanoid'
model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
```

IDのサイズを小さくしたい場合(衝突確率を高める)、
サイズを引数として渡すことができます。

```js
nanoid(10) //=> "IRFa-VaY2b"
```

IDサイズの安全性を[ID衝突確率]計算機で確認することを忘れないでください。

[カスタムアルファベット](#カスタムアルファベットまたはサイズ)や
[ランダム生成器](#カスタムランダムバイト生成器)も使用できます。

[ID衝突確率]: https://zelark.github.io/nano-id-cc/


### 非セキュア

デフォルトでは、Nano IDはセキュリティと低衝突確率のためにハードウェアランダムバイト生成を使用します。セキュリティにそれほど関心がない場合は、ハードウェア乱数生成器がない環境でも使用できます。

```js
import { nanoid } from 'nanoid/non-secure'
const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
```


### カスタムアルファベットまたはサイズ

customAlphabetは、独自のアルファベットとIDサイズでnanoidを作成できる関数を返します。

```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()
```

カスタムアルファベットとIDサイズの安全性を[ID衝突確率]計算機で確認してください。
より多くのアルファベットについては、[nanoid-dictionary]のオプションを確認してください。

アルファベットは256記号以下でなければなりません。
そうでない場合、内部生成アルゴリズムのセキュリティは保証されません。

デフォルトサイズを設定するだけでなく、関数を呼び出す際にIDサイズを変更することもできます:

```js
import { customAlphabet } from 'nanoid'
const nanoid = customAlphabet('1234567890abcdef', 10)
model.id = nanoid(5) //=> "f01a2"
```

[ID衝突確率]: https://zelark.github.io/nano-id-cc/
[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)
```

なお、Nano IDのバージョン間でランダム生成器の呼び出しシーケンスが変更される場合があります。シードベースの生成器を使用している場合、同じ結果を保証するものではありません。


## 使用方法

### React

Reactの`key` propにNano IDを使用する正しい方法はありません。なぜなら、keyはレンダー間で一貫性がある必要があるからです。

```jsx
function Todos({todos}) {
  return (
    <ul>
      {todos.map(todo => (
        <li key={nanoid()}> /* これはやめましょう */
          {todo.text}
        </li>
      ))}
    </ul>
  )
}
```

代わりに、リストアイテム内で安定したIDを使用するようにしましょう。

```jsx
const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
)
```

安定したIDがない場合は、`nanoid()`の代わりにインデックスを`key`として使用することをお勧めします:

```jsx
const todoItems = todos.map((text, index) =>
  <li key={index}> /* まだ推奨されませんが、nanoid()よりは優先されます。
                       アイテムに安定したIDがない場合のみ行ってください。 */
    {text}
  </li>
)
```

ラベルと入力フィールドのように要素を関連付けるためだけにランダムなIDが必要な場合は、[`useId`]が推奨されます。
このフックはReact 18で追加されました。

[`useId`]: https://react.dev/reference/react/useId


### React Native

React Nativeには組み込みのランダム生成器がありません。次のポリフィルは
プレーンなReact NativeとExpo(`39.x`以降)で動作します。

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


### PouchDBとCouchDB

PouchDBとCouchDBでは、IDはアンダースコア`_`で始めることができません。
Nano IDはデフォルトでIDの先頭に`_`を使用する可能性があるため、
この問題を防ぐためにプレフィックスが必要です。

次のオプションでデフォルトのIDを上書きします:

```js
db.put({
  _id: 'id' + nanoid(),
  …
})
```


### CLI

ターミナルで`npx nanoid`を呼び出すことで、一意のIDを取得できます。
システムにNode.jsがあれば十分で、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
```

### TypeScript

Nano IDでは、生成された文字列をTypeScriptで不透明な文字列(opaque strings)にキャストできます。
例えば:

```ts
declare const userIdBrand: unique symbol
type UserId = string & { [userIdBrand]: true }

// 明示的な型パラメータを使用:
mockUser(nanoid<UserId>())

interface User {
  id: UserId
  name: string
}

const user: User = {
  // 自動的にUserIdにキャストされます:
  id: nanoid(),
  name: 'Alice'
}
```

### その他のプログラミング言語

Nano IDは多くの言語に移植されています。これらのポートを使用して、
クライアント側とサーバー側で同じID生成器を持つことができます。

* [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 [ネイティブ](https://github.com/puyuan/py-nanoid)実装
  [辞書](https://pypi.org/project/nanoid-dictionary)付きと
  [高速](https://github.com/oliverlambson/fastnanoid)実装(Rustで書かれています)
* Postgres [拡張機能](https://github.com/spa5k/uids-postgres)
  と[ネイティブ関数](https://github.com/viascom/nanoid-postgres)
* [R](https://github.com/hrbrmstr/nanoid)(辞書付き)
* [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)

その他の環境では、コマンドラインからIDを生成するための[CLI]が利用可能です。

[CLI]: #cli


## ツール

* [IDサイズ計算機]は、IDのアルファベットやサイズを調整する際の衝突確率を表示します。
* [`nanoid-dictionary`]は[`customAlphabet`]で使用する一般的なアルファベットを提供します。
* [`nanoid-good`]はIDに不適切な単語が含まれていないことを確認します。

[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary
[IDサイズ計算機]:  https://zelark.github.io/nano-id-cc/
[`customAlphabet`]:    #カスタムアルファベットまたはサイズ
[`nanoid-good`]:       https://github.com/y-gagar1n/nanoid-good


================================================
FILE: README.ko.md
================================================
# Nano ID

<img src="https://ai.github.io/nanoid/logo.svg" align="right"
     alt="Nano ID logo by Anton Lovchikov" width="180" height="94">

[English](./README.md) | [日本語](./README.ja.md) | [Русский](./README.ru.md) | [简体中文](./README.zh-CN.md) | [Bahasa Indonesia](./README.id-ID.md) | **한국어** | [العربية](./README.ar.md)

JavaScript를 위한 가볍고 안전하며 URL 친화적인 고유 String ID 생성기

> “대단한 레벨의 무의미한 완벽주의,
> 경의를 표하지 않을 수 없습니다”

* **가볍습니다.** 118 bytes (minified 및 brotli 적용 후). 다른 의존성이 없습니다.
  [Size Limit] 의 기능으로 컨트롤합니다.
* **안전합니다.** 하드웨어의 랜덤 생성기를 사용합니다. 클러스터에서 사용할 수 있습니다.
* **짧은 ID를 생성합니다.** UUID와는 다르게 대소문자를 모두 사용하여 키를 생성하므로, 36 byte를 차지하는 UUID와 다르게 21 byte만으로도 고유 아이디를 생성할 수 있습니다.
  So ID size was reduced from 36 to 21 symbols.
* **이식이 쉽습니다.** Nano ID 는 20개 이상의 언어로 포팅되었습니다 [다른 언어들](#다른-언어들).

```js
import { nanoid } from 'nanoid'
model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
```

---

<img src="https://cdn.evilmartians.com/badges/logo-no-label.svg" alt="" width="22" height="16" />  Made at <b><a href="https://evilmartians.com/devtools?utm_source=nanoid&utm_campaign=devtools-button&utm_medium=github">Evil Martians</a></b>, product consulting for <b>developer tools</b>.

---

[online tool]: https://gitpod.io/#https://github.com/ai/nanoid/
[with 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와-비교)
- [벤치마크](#벤치마크)
- [보안](#보안)
- [설치](#설치)
  - [ESM](#esm)
  - [CommonJS](#commonjs)
  - [JSR](#jsr)
  - [CDN](#cdn)
- [API](#api)
  - [Blocking](#blocking)
  - [Non-Secure](#non-secure)
  - [사용자 커스텀 문자열](#사용자-커스텀-문자열)
  - [사용자 지정 랜덤 바이트 생성기](#사용자-지정-랜덤-바이트-생성기)
- [사용법](#사용법)
  - [React](#react)
  - [React Native](#react-native)
  - [PouchDB 및 CouchDB](#pouchdb-및-couchdb)
  - [CLI](#cli)
  - [TypeScript](#typescript)
  - [다른 언어들](#다른-언어들)
- [도구](#도구)


## UUID와 비교

Nano ID 는 (랜덤 기반의) UUID v4와 비교할 수 있습니다.
아이디로 생성되는 랜덤 비트의 수가 유사하여
(Nano ID는 126개, UUID는 122개), 동일한 아이디가 생성될 수 있는 충돌 확률도 비슷합니다:

> 10억 분의 1의 확률로 충돌이 발생하기 위해서는
> 103조 번의 v4 ID가 생성되어야 합니다.

Nano ID와 UUID v4에는 두 가지의 주요한 차이점이 있습니다:

1. Nano ID는 대문자를 사용합니다. 그래서 유사한 개수의 랜덤 값을 36개가 아닌 21개의 문자로 나타낼 수 있습니다.
2. Nano ID 코드는 `uuid/v4` 패키지보다 **4분의 1 사이즈**입니다:
   UUIDv4는 423 bytes, Nano ID는 118 bytes 입니다.


## 벤치마크

```rust
$ node ./test/benchmark.js
crypto.randomUUID          7,619,041 ops/sec
uuid v4                    7,436,626 ops/sec
@napi-rs/uuid              4,730,614 ops/sec
uid/secure                 4,729,185 ops/sec
@lukeed/uuid               4,015,673 ops/sec
nanoid                     3,693,964 ops/sec
customAlphabet             2,799,255 ops/sec
nanoid for browser           380,915 ops/sec
secure-random-string         362,316 ops/sec
uid-safe.sync                354,234 ops/sec
shortid                       38,808 ops/sec

Non-secure:
uid                       11,872,105 ops/sec
nanoid/non-secure          2,226,483 ops/sec
rndm                       2,308,044 ops/sec
```

테스트 환경: 프레임워크 13 7840U, 페도라 39, Node.js 21.6.


## 보안

*랜덤 생성기에 대한 설명은 다음 기사를 참고하세요:
[Secure random values (in Node.js)]*

* **예측불가성.** 안전하지 않은 `Math.random()`를 사용하는 대신, Nano ID는
  Node.js에서 제공하는 `crypto` 모듈과 브라우저의 Web Crypto API를 사용합니다.
  이 모듈들은 예측이 불가능한 하드웨어 레벨의 랜덤 생성기입니다.
* **균일성.** `random % alphabet` 는 랜덤 아이디 생성기를 만들때 흔히들 하는 실수입니다.
  이 경우 분포(수학)가 일정하지 않게 되며, 일부 기호들은 다른 기호들보다 사용될 확률이 낮아집니다.
  이로 인해 브루트포스를 사용한 시도의 횟수를 줄일 수 있는 결과를 가져옵니다.
  Nano ID는 [이보다 더 좋은 알고리즘]을 사용하며, 균일성 테스트를 수행하였습니다.

  <img src="img/distribution.png" alt="Nano ID uniformity"
     width="340" height="135">

* **문서화:** Nano ID의 모든것이 코드에 문서화되어있습니다. [소스 코드]에서 코멘트를 확인하세요.
* **취약점:** 보안 취약점에 대한 리포트는 아래 링크를 사용해주세요.
  [Tidelift security contact](https://tidelift.com/security).
  Tidelift에서 취약점에 대한 수정 및 알림등을 도와줄 수 있습니다.

[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


## 설치

### ESM

Nano ID 5는 ESM 프로젝트에서 `import`를 사용하여 테스트코드나 Node.js 스크립트에 사용할 수 있습니다.

```bash
npm install nanoid
```

### CommonJS

Nano ID는 아래와 같은 방법으로 CommonJS에 사용할 수 있습니다:

- `require()`를 사용해 Nano ID를 가져올 수 있습니다.
  최신 Node.js 22.12나 Node.js 20에서 `--experimental-require-module`
  플래그를 이용하면 사용할 수 있습니다.

- Node.js 18에서는 아래의 방법으로 동적 임포트를 해주세요:

  ```js
  let nanoid
  module.exports.createID = async () => {
    if (!nanoid) ({ nanoid } = await import('nanoid'))
    return nanoid() // => "V1StGXR8_Z5jdHi6B-myT"
  }
  ```

- Nano ID 3.x 역시 설치할 수 있습니다 (아직 지원중이에요!):

  ```bash
  npm install nanoid@3
  ```

### JSR

[JSR](https://jsr.io) 은 npm을 대체할 수 있는 오픈 거버넌스이며 npm과 달리 현재 활발히 개발중에 있습니다.

```bash
npx jsr add @sitnik/nanoid
```

Node.js, Deno, Bun 등에서 사용할 수 있습니다.

```js
// 모든 `nanoid` import를 `@sitnik/nanoid`로 변경합니다
import { nanoid } from '@sitnik/nanoid'
```

Deno 사용시에는 `deno add jsr:@sitnik/nanoid` 명령어로 설치하고
`jsr:@sitnik/nanoid`로 import 합니다.


### CDN

빠른 적용을 위해 CDN에서 Nano ID를 가져올 수 있습니다.
하지만 로딩 성능이 늦어지므로 프로덕션에서는 사용하는 것을 추천하지 않습니다.

```js
import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'
```

## API

Nano ID는 normal / non-secure의 2가지의 API를 제공합니다.

기본적으로 Nano ID는 URL에 친화적인 기호들을 사용하여 21자리의 랜덤한 문자열을 생성합니다.
(이들은 UUID v4와 유사한 중복생성 확률을 가집니다)


### Blocking

Nano ID를 사용하는 가장 안전하고 쉬운 방법입니다.

드물게 CPU가 하드웨어 랜덤 생성을 위해 노이즈 제거를 수행하는 동안 다른 동작을 못하도록 블로킹 될 수 있습니다.

```js
import { nanoid } from 'nanoid'
model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
```

생성되는 랜덤 아이디의 크기를 줄이고 싶으면 파라미터로 해당 길이 값을 넣어주면 됩니다.
(이렇게 하면 중복 생성이 발생할 확률도 올라갑니다)

```js
nanoid(10) //=> "IRFa-VaY2b"
```

아래의 [아이디 중복확률] 계산기로 여러분의 아이디가 얼마나 안전한지 확인해보세요.

[사용자 커스텀 문자열](#사용자-커스텀-문자열) 이나
[사용자가 만든 랜덤 생성기](#사용자-지정-랜덤-바이트-생성기) 를 사용할 수도 있습니다.

[아이디 중복확률]: https://zelark.github.io/nano-id-cc/


### Non-Secure

기본적으로 Nano ID는 보안과 낮은 충돌 확률을 위해 하드웨어 랜덤 바이트 생성기를 사용합니다.
만약 보안이 중요하지 않다면 하드웨어 랜덤 생성기를 사용하지 않도록 설정할 수 있습니다.

```js
import { nanoid } from 'nanoid/non-secure'
const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
```


### 사용자 커스텀 문자열

`customAlphabet` 함수를 사용하면 지정된 문자열 내에서 지정된 개수로 이루어진
랜덤 아이디를 생성할 수 있는 `nanoid` 함수를 만들 수 있습니다

```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()
```

[아이디 충돌 확률] 계산기를 사용하여 여러분이 지정한 문자와 사이즈에 대한 중복 생성 확률을 확인해보세요.
[`nanoid-dictionary`] 에서 어떤 문자열을 사용할 수 있는지에 대한 옵션을 확인할 수 있습니다.

커스텀 문자열은 256개 이하의 개수를 가져야 합니다.
그 외의 경우 내부의 생성 알고리즘의 보안성을 보장할 수 없습니다.

기본 사이즈를 지정한 후에, 새로 만들어진 함수를 부를 때 생성할 문자열의 개수를 다시 지정하는 것도 가능합니다

```js
import { customAlphabet } from 'nanoid'
const nanoid = customAlphabet('1234567890abcdef', 10)
model.id = nanoid(5) //=> "f01a2"
```

[아이디 충돌 확률]: https://zelark.github.io/nano-id-cc/
[`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` 는 반드시 배열의 크기를 받을 수 있어야 하며, 랜덤 숫자로 이루어진 배열을 리턴해야 합니다.

URL 친화적인 기호들을 사용하여 `customRandom` 을 실행하려면,
`urlAlphabet`을 사용해 기본 문자셋을 가져올 수 있습니다.

```js
const { customRandom, urlAlphabet } = require('nanoid')
const nanoid = customRandom(urlAlphabet, 10, random)
```

참고로, Nano ID 버전이 변경됨에 따라 랜덤 생성기의 호출 시퀀스가 변경될 수 있습니다.
시드기반 생성기를 사용하는 경우 동일한 결과가 나오는 것을 보장할 수 없습니다.


## 사용법

### React

React에서 `key` props에 Nano ID를 사용하는 것은 좋지 않습니다.
이 값은 렌더링 될 때마다 동일한 값을 가지고 있어야 합니다.

```jsx
function Todos({todos}) {
  return (
    <ul>
      {todos.map(todo => (
        <li key={nanoid()}> /* 절대 하지 마세요 */
          {todo.text}
        </li>
      ))}
    </ul>
  )
}
```

랜덤값보다 리스트 내에서 가져올 수 있는 값을 사용하여 안정된 값을 키 값으로 사용하는 것이 좋습니다.

```jsx
const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
)
```

`key` 값으로 사용할 적절한 값이 없는 경우에도 `nanoid()`를 사용하기 보다는 인덱스 값을 사용하세요:

```jsx
const todoItems = todos.map((text, index) =>
  <li key={index}> /* 추천되는 방식은 아니지만 nanoid()를 쓰는것 보단 낫습니다 */
    {text}
  </li>
)
```

랜덤한 아이디를 생성하여 HTML 요소간의 연결 (label과 input 등)에 사용하는 경우에는
React 18에서 추가된 [`useId`] 를 추천합니다.

[`useId`]: https://react.dev/reference/react/useId


### React Native

React Native에는 내장된 랜덤 생성기가 존재하지 않습니다.
아래의 폴리필을 사용하면 순수 React Native와 Expo(`39`버전 이상) 환경에서
Nano ID를 사용할 수 있습니다.

1. [`react-native-get-random-values`] 문서를 확인하고 설치합니다
2. Nano ID를 import하기 전에 이 패키지를 import 해야 합니다.

```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 및 CouchDB

PouchDB와 CouchDB에서는 ID 값을 `_`로 시작할 수 없습니다.
Nano ID는 기본적으로 `_`를 맨 앞에 붙일 수 있기 때문에,
이 문제를 해결하기 위해 접두어 (prefix)가 필요합니다.

아래와 같이 접두어를 붙여서 사용합니다.

```js
db.put({
  _id: 'id' + nanoid(),
  …
})
```


### CLI

터미널에서 `npx nanoid` 명령어를 입력하면 고유 ID를 생성할 수 있습니다.
Node.js가 시스템에 설치되어있어야 하며, Nano ID는 미리 설치되어있지 않아도 됩니다.

```sh
$ npx nanoid
npx: installed 1 in 0.63s
LZfXLFzPPR4NNrgjlWDxn
```

생성할 아이디의 길이를 변경하려면 `--size` (or `-s`) 옵션을 붙여줍니다:

```sh
$ npx nanoid --size 10
L3til0JS4z
```

사용자 커스텀 문자열을 사용하려면 `--alphabet` (or `-a`) 옵션을 사용합니다
(이 때 `--size`도 같이 사용해야 합니다):

```sh
$ npx nanoid --alphabet abc --size 15
bccbcabaabaccab
```

### TypeScript

Nano ID는 생성된 문자열을 TypeScript의 순수 string이 아닌 타입에도 할당할 수 있습니다.
예를 들어 아래와 같이 가능합니다:

```ts
declare const userIdBrand: unique symbol
type UserId = string & { [userIdBrand]: true }

// 명시적으로 타입 파라미터를 사용:
mockUser(nanoid<UserId>())

interface User {
  id: UserId
  name: string
}

const user: User = {
  // 자동으로 UserId 타입으로 캐스팅됨:
  id: nanoid(),
  name: 'Alice'
}
```

### 다른 언어들

Nano ID는 다양한 언어로 포팅되었습니다. 클라이언트/서버에 관계없이 아래의 다양한 포팅된 버전들을 사용할 수 있습니다.

* [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)

이 외의 환경에서는 [CLI]를 사용하여 터미널 환경에서 랜덤 아이디를 생성할 수 있습니다.

[CLI]: #cli


## 도구

* [ID 사이즈 계산기]는 문자열과 생성 사이즈를 변경한 경우 중복된 아이디가 생성될 수 있는 충돌 확률을 알려줍니다.
* [`customAlphabet`]에서 사용할 수 있는 일반적인 문자열들을 [`nanoid-dictionary`]로 찾아볼 수 있습니다.
* 생성된 ID에 이상한 단어가 들어가는 것을 방지하려면 [`nanoid-good`]를 사용할 수 있습니다.

[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary
[ID 사이즈 계산기]:  https://zelark.github.io/nano-id-cc/
[`customAlphabet`]:    #custom-alphabet-or-size
[`nanoid-good`]:       https://github.com/y-gagar1n/nanoid-good


================================================
FILE: README.md
================================================
# Nano ID

<img src="https://ai.github.io/nanoid/logo.svg" align="right"
     alt="Nano ID logo by Anton Lovchikov" width="180" height="94">

**English** | [日本語](./README.ja.md) | [Русский](./README.ru.md) | [简体中文](./README.zh-CN.md) | [Bahasa Indonesia](./README.id-ID.md) | [한국어](./README.ko.md) | [العربية](./README.ar.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.** 118 bytes (minified and brotlied). No dependencies.
  [Size Limit] controls the size.
* **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 over [20 programming languages](./README.md#other-programming-languages).

```js
import { nanoid } from 'nanoid'
model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
```

---

<img src="https://cdn.evilmartians.com/badges/logo-no-label.svg" alt="" width="22" height="16" />  Made at <b><a href="https://evilmartians.com/devtools?utm_source=nanoid&utm_campaign=devtools-button&utm_medium=github">Evil Martians</a></b>, product consulting for <b>developer tools</b>.

---

[online tool]: https://gitpod.io/#https://github.com/ai/nanoid/
[with 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


## 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
crypto.randomUUID          7,619,041 ops/sec
uuid v4                    7,436,626 ops/sec
@napi-rs/uuid              4,730,614 ops/sec
uid/secure                 4,729,185 ops/sec
@lukeed/uuid               4,015,673 ops/sec
nanoid                     3,693,964 ops/sec
customAlphabet             2,799,255 ops/sec
nanoid for browser           380,915 ops/sec
secure-random-string         362,316 ops/sec
uid-safe.sync                354,234 ops/sec
shortid                       38,808 ops/sec

Non-secure:
uid                       11,872,105 ops/sec
nanoid/non-secure          2,226,483 ops/sec
rndm                       2,308,044 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


================================================
FILE: README.ru.md
================================================
# Nano ID

<img src="https://ai.github.io/nanoid/logo.svg" align="right"
     alt="Логотип Nano ID от Антона Ловчикова" width="180" height="94">

[English](./README.md) | [日本語](./README.ja.md) | **Русский** | [简体中文](./README.zh-CN.md) | [Bahasa Indonesia](./README.id-ID.md) | [한국어](./README.ko.md) | [العربية](./README.ar.md)

Генератор уникальных ID для JavaScript — лёгкий, безопасный,
ID можно применять в URL.

> «Поразительный уровень бессмысленного перфекционизма,
> который просто невозможно не уважать»

- **Лёгкий.** 118 байт (после минификации и Brotli). Без зависимостей.
  [Size Limit] следит за размером.
- **Безопасный.** Использует аппаратный генератор случайных чисел.
  Можно использовать в кластерах машин.
- **Короткие 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

---

<img src="https://cdn.evilmartians.com/badges/logo-no-label.svg" alt="" width="22" height="16" />  Сделано в <b><a href="https://evilmartians.com/devtools?utm_source=nanoid&utm_campaign=devtools-button&utm_medium=github">Злых марсианах</a></b>, продуктовом консалтинге для <b>инструментов разработки</b>.

---


## Оглавление

- [Оглавление](#оглавление)
- [Сравнение с UUID](#сравнение-с-uuid)
- [Сравнение производительности](#сравнение-производительности)
- [Безопасность](#безопасность)
- [Подключение](#подключение)
  - [ESM](#esm)
  - [CommonJS](#commonjs)
  - [JSR](#jsr)
  - [CDN](#cdn)
- [API](#api)
  - [Блокирующий](#блокирующий)
  - [Небезопасный](#небезопасный)
  - [Смена алфавита или длины](#смена-алфавита-или-длины)
  - [Смена генератора случайных чисел](#смена-генератора-случайных-чисел)
- [Руководство](#руководство)
  - [React](#react)
  - [React Native](#react-native)
  - [PouchDB и CouchDB](#pouchdb-и-couchdb)
  - [Терминал](#терминал)
  - [TypeScript](#typescript)
  - [Другие языки программирования](#другие-языки-программирования)
- [Инструменты](#инструменты)


## Сравнение с UUID

Nano ID похож на UUID v4 (случайный).
У них сравнимое число битов случайности в ID (126 у Nano ID против 122 у UUID),
поэтому они обладают похожей вероятностью возникновения коллизий
(повторной генерации ранее выданных ID):

> Чтобы вероятность повтора приблизилась к 1 на миллиард,
> нужно сгенерировать 103 триллиона ID.

Но между ними есть 2 важных отличия:

1. Nano ID использует более широкий алфавит, и сравнимое количество
   битов случайности будут упакованы в более короткую строку
   (21 символ, против 36 у UUID).
2. Код Nano ID **в 4 раз меньше**, чем у `uuid/v4` — 118 байт против 423.


## Сравнение производительности

```rust
$ node ./test/benchmark.js
crypto.randomUUID          7,619,041 ops/sec
uuid v4                    7,436,626 ops/sec
@napi-rs/uuid              4,730,614 ops/sec
uid/secure                 4,729,185 ops/sec
@lukeed/uuid               4,015,673 ops/sec
nanoid                     3,693,964 ops/sec
customAlphabet             2,799,255 ops/sec
nanoid for browser           380,915 ops/sec
secure-random-string         362,316 ops/sec
uid-safe.sync                354,234 ops/sec
shortid                       38,808 ops/sec

Non-secure:
uid                       11,872,105 ops/sec
nanoid/non-secure          2,226,483 ops/sec
rndm                       2,308,044 ops/sec
```

Среда сравнения: Framework 13 7840U, Fedora 39, Node.js 21.6.


## Безопасность

_См. также хорошую статью о теориях генераторов случайных чисел:
[Secure random values (in Node.js)]_

- **Непредсказуемость.** Вместо предсказуемого `Math.random()`, Nano ID
  использует модуль `crypto` в Node.js и Web Crypto API в браузере.
  Эти модули дают доступ к аппаратному генератору случайных чисел.
- **Равномерность.** Например, существует популярная ошибка `random % alphabet`,
  которую часто допускают при разработке генератора ID.
  Распределение вероятности для каждого символа может не быть одинаковым.
  Из-за неравномерности использования пространства алфавита, на перебор ID
  потребуется меньше времени, чем ожидается.
  Nano ID использует [более совершенный алгоритм],
  а равномерность распределения символов покрыта тестами.

  <img src="img/distribution.png" alt="Распределение Nano ID"
     width="340" height="135">

- **Документация:** все хитрости 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


## Подключение

### ESM

Nano ID 5 работает с ESM-проектами (`import`) в тестах или скриптах для Node.js.

```bash
npm install nanoid
```

### CommonJS

На проектах с CommonJS вы можете использовать:

- `require()` будет работать в последней версия Node.js 22.12 (из коробки)
  или Node.js 20 (с флагом `--experimental-require-module`).

- В более старых версиях Node.js можно использовать динамический импорт:

  ```js
  let nanoid
  module.exports.createID = async () => {
    if (!nanoid) ({ nanoid } = await import('nanoid'))
    return nanoid() // => "V1StGXR8_Z5jdHi6B-myT"
  }
  ```

- Или можно просто взять Nano ID 3.x (мы его всё ещё поддерживаем):

  ```bash
  npm install nanoid@3
  ```

### JSR

[JSR](https://jsr.io) это замена npm с открытым управлением
и активной разработкой (в отличие от npm).

```bash
npx jsr add @sitnik/nanoid
```

Вы можете использовать пакет с JSR в Node.js, Deno, Bun.

```js
// Replace `nanoid` to `@sitnik/nanoid` in all imports
import { nanoid } from '@sitnik/nanoid'
```

Для Deno установите через `deno add jsr:@sitnik/nanoid`
или импортируйте `jsr:@sitnik/nanoid`.


### CDN

Для быстрого прототипирования вы можете подключить Nano ID с CDN без установки.
Не используйте этот способ на реальном сайте, так как он сильно бьёт
по скорости загрузки сайта.

```js
import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'
```


## 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/).


### Небезопасный

По умолчанию, Nano ID использует аппаратный генератор случайных чисел для
получения непредсказуемых ID и минимизации риска возникновения коллизий
(повторной генерации ранее выданных ID). Но если вам не требуется устойчивость
к подбору ID, то вы можете перейти на небезопасный генератор — это полезно
там, где нет доступа к API аппаратного генератора случайных чисел.

```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/non-secure'
const nanoid = customAlphabet('1234567890abcdef', 10)
user.id = nanoid()
```

Не забудьте проверить риски коллизии вашего алфавита и длины
[на нашем калькуляторе]. [`nanoid-dictionary`] содержит много популярных
примеров альтернативных алфавитов.

Алфавит должен содержать ≤256 символов. Иначе мы не сможем гарантировать
непредсказуемость ID.

Длину ID можно менять не только в `customAlphabet()`, но и при вызове
генератора, который она вернёт:

```js
import { customAlphabet } from 'nanoid'
const nanoid = customAlphabet('1234567890abcdef', 10)
model.id = nanoid(5) //=> "f01a2"
```

[на нашем калькуляторе]: https://zelark.github.io/nano-id-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)
```


## Руководство

### React

Не используйте Nano ID для генерации свойства `key` в JSX. При каждом рендере
`key` будет разный, что плохо скажется на производительности.

```jsx
function Todos({ todos }) {
  return (
    <ul>
      {todos.map(todo => (
        <li key={nanoid()}> /* НЕ ДЕЛАЙТЕ ТАК */
          {todo.text}
        </li>
      ))}
    </ul>
  )
}
```

Для связи `<input>` и `<label>` лучше использовать [`useId`],
который был добавлен в React 18.

[`useId`]: https://react.dev/reference/react/useId


### 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


### PouchDB и CouchDB

В PouchDB и CouchDB, ID не могут начинаться с `_`. Добавьте к ID префикс,
так как иногда Nano ID может сгенерировать ID начинающийся с `_`.

Изменить стандартный ID можно через следующую опцию:

```js
db.put({
  _id: 'id' + nanoid(),
  …
})
```


### Терминал

Можно сгенерировать уникальный 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
```

### TypeScript

Nano ID позволяет приводить сгенерированные строки к непрозрачным строкам в
TypeScript. Например:

```ts
declare const userIdBrand: unique symbol
type UserId = string & { [userIdBrand]: true }

// Используйте явный параметр типа:
mockUser(nanoid<UserId>())

interface User {
  id: UserId
  name: string
}

const user: User = {
  // Автоматически приводится к типу UserId:
  id: nanoid(),
  name: 'Alice'
}
```

### Другие языки программирования

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)
- [Elixir](https://github.com/railsmechanic/nanoid)
- [Gleam](https://github.com/0xca551e/glanoid)
- [Go](https://github.com/jaevor/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)
- [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)
- Postgres: [Rust-расширение](https://github.com/spa5k/uids-postgres)
  и [на чисто pgSQL](https://github.com/viascom/nanoid-postgres)
- [R](https://github.com/hrbrmstr/nanoid) (со словарями)
- [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)

Для остальных сред можно использовать 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


================================================
FILE: README.zh-CN.md
================================================
# Nano ID

<img src="https://ai.github.io/nanoid/logo.svg" align="right"
     alt="Nano ID logo by Anton Lovchikov" width="180" height="94">

[English](./README.md) | [日本語](./README.ja.md) | [Русский](./README.ru.md) | **简体中文** | [Bahasa Indonesia](./README.id-ID.md) | [한국어](./README.ko.md) | [العربية](./README.ar.md)

一个小巧、安全、URL友好、唯一的 JavaScript 字符串ID生成器。

> “一个惊人的无意义的完美主义水平,这简直让人无法不敬佩。”

* **小巧.** 118字节 (经过压缩和Brotli处理)。没有依赖。[Size Limit] 控制大小。
* **安全.** 它使用硬件随机生成器。可在集群中使用。
* **紧凑.** 它使用比 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

---

<img src="https://cdn.evilmartians.com/badges/logo-no-label.svg" alt="" width="22" height="16" />  Made at <b><a href="https://evilmartians.com/devtools?utm_source=nanoid&utm_campaign=devtools-button&utm_medium=github">Evil Martians</a></b>, product consulting for <b>developer tools</b>.

---

## 目录

- [目录](#目录)
- [与 UUID 的比较](#与-uuid-的比较)
- [基准值](#基准值)
- [安全性](#安全性)
- [安装](#安装)
- [API](#api)
  - [阻塞](#阻塞)
  - [不安全](#不安全)
  - [自定义字母或大小](#自定义字母或大小)
  - [自定义随机字节生成器](#自定义随机字节生成器)
- [用法](#用法)
  - [React](#react)
  - [React Native](#react-native)
  - [PouchDB and CouchDB](#pouchdb-and-couchdb)
  - [CLI](#cli)
  - [TypeScript](#typescript)
  - [其他编程语言](#其他编程语言)
- [工具](#工具)


## 与 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倍**: 118字节而不是423字节.


## 基准值

```rust
$ node ./test/benchmark.js
crypto.randomUUID          7,619,041 ops/sec
uuid v4                    7,436,626 ops/sec
@napi-rs/uuid              4,730,614 ops/sec
uid/secure                 4,729,185 ops/sec
@lukeed/uuid               4,015,673 ops/sec
nanoid                     3,693,964 ops/sec
customAlphabet             2,799,255 ops/sec
nanoid for browser           380,915 ops/sec
secure-random-string         362,316 ops/sec
uid-safe.sync                354,234 ops/sec
shortid                       38,808 ops/sec

Non-secure:
uid                       11,872,105 ops/sec
nanoid/non-secure          2,226,483 ops/sec
rndm                       2,308,044 ops/sec
```

测试配置: Framework 13 7840U, Fedora 39, Node.js 21.6.


## 安全性

*请看一篇关于随机生成器理论的好文章:
[安全的随机值 (在 Node.js 中)]*

* **不可预测性.** 不使用不安全的 `Math.random()`, Nano ID
  使用 Node.js 的 `crypto` 模块和浏览器的 Web Crypto API。
  这些模块使用不可预测的硬件随机生成器。
* **统一性.** `random % alphabet` 是编写ID生成器时常犯的一个错误。
  这样做会导致分布不均匀; 一些符号出现的机会较其他符号低。因此,在暴力破解时,尝试的次数会减少。
  Nano ID 使用了一种 [更好的算法],并进行了一致性测试。

  <img src="img/distribution.png" alt="Nano ID uniformity"
     width="340" height="135">

* **有据可查:** 所有的 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 nanoid
```

Nano ID 5 仅适用于 ESM 项目、测试或 Node.js 脚本。
对于 CommonJS,您需要 Nano ID 3.x(我们仍然支持它):

```bash
npm install nanoid@3
```

想要快速上手尝试,你可以从 CDN 加载 Nano ID。但是,它不建议
在生产中使用,因为它的加载性能较低。

```js
import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'
```


## API

Nano ID 有2个 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 大小(但是会增加碰撞概率),
可以将大小作为参数传递

```js
nanoid(10) //=> "IRFa-VaY2b"
```

别忘了在我们的 [ID 碰撞概率] 计算器中检查你的 ID 大小的安全性。

您也可以使用 [自定义字母表](#自定义字母或大小)
或者是 [自定义生成器](#自定义随机字节生成器).

[ID 碰撞概率]: https://zelark.github.io/nano-id-cc/


### 不安全

默认情况下,Nano ID 使用硬件随机字节生成以提供安全性和较低的碰撞概率。如果您对安全性不太担心,您可以在没有硬件随机生成器的环境中使用它

```js
import { nanoid } from 'nanoid/non-secure'
const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
```


### 自定义字母或大小

`customAlphabet` 返回一个函数,允许您使用自定义字母表和ID大小创建 `nanoid`。

```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()
```

在我们的 [ID 碰撞概率] 计算器中检查您的自定义字母表和 ID 大小的安全性。
查看 [`nanoid-dictionary`] 中的选项以获取更多字母表。

字母表必须包含256个或更少的符号。
否则,无法保证内部生成器算法的安全性。

除了设置默认大小外,您还可以在调用函数时更改ID大小:

```js
import { customAlphabet } from 'nanoid'
const nanoid = customAlphabet('1234567890abcdef', 10)
model.id = nanoid(5) //=> "f01a2"
```

[ID collision probability]: https://zelark.github.io/nano-id-cc/
[`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)
```

请注意,在Nano ID的不同版本之间,我们可能会更改随机生成器的调用顺序。如果您正在使用基于种子的生成器,我们不能保证相同的结果。


## 用法

### React

目前还没有将 nanoid 用于 React `key` prop 的正确方法
因为它在不同的渲染中应该是一致的。

```jsx
function Todos({todos}) {
  return (
    <ul>
      {todos.map(todo => (
        <li key={nanoid()}> /* 不要这样做 */
          {todo.text}
        </li>
      ))}
    </ul>
  )
}
```

您应该尝试在列表项中找到稳定的 id。

```jsx
const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
)
```

如果您没有稳定的 ID,您最好使用索引作为 `键` 而不是 `nanoid()`:

```jsx
const todoItems = todos.map((text, index) =>
  <li key={index}> /* 仍然不推荐,但优于 nanoid()。
                      仅当项目没有稳定ID时才执行此操作。 */
    {text}
  </li>
)
```

如果您只需要随机 ID 来将元素(如标签和输入字段)链接在一起,建议使用 [`useId`]。该钩子在 React 18 中添加。

[`useId`]: https://react.dev/reference/react/useId


### React Native

React Native 没有内置的随机生成器。以下polyfill适用于纯 React Native 和 Expo,从39.x版本开始生效。

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


### PouchDB and CouchDB

在 PouchDB 和 CouchDB 中,ID 不能以下划线 `_` 开头。
需要一个前缀来防止这个问题,因为 Nano ID 可能在默认情况下使用 `_` 作为 ID 的开头。
在默认情况下,在 ID 的开头使用 `_`。

用下面的选项覆盖默认的 ID。

```js
db.put({
  _id: 'id' + nanoid(),
  …
})
```


### CLI

你可以通过调用 `npx nanoid` 在终端获得唯一的 ID。你只需要
在系统中安装了 Node.js。你不需要把 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
```

### TypeScript

Nano ID 允许将生成的字符串转换为 TypeScript 中的不透明字符串。 例如:

```ts
declare const userIdBrand: unique symbol
type UserId = string & { [userIdBrand]: true }

// 使用显式类型参数:
mockUser(nanoid<UserId>())

interface User {
  id: UserId
  name: string
}

const user: User = {
  // 自动转换为 UserId:
  id: nanoid(),
  name: 'Alice'
}
```

### 其他编程语言

Nano ID 已被移植到许多语言。 你可以使用下面这些移植,获取在客户端和服务器端相同的ID生成器。

* [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)
* [Elixir](https://github.com/railsmechanic/nanoid)
* [Gleam](https://github.com/0xca551e/glanoid)
* [Go](https://github.com/jaevor/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)
* [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)
* [Postgres Extension](https://github.com/spa5k/uids-postgres)
* [Postgres 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)

此外,[CLI] 还可用于从命令行生成 ID。

[CLI]: #cli


## 工具

* [ID size 计算器] 显示调整时的碰撞概率
  ID的字母或大小。
* [`nanoid-dictionary`] 与常用的字母一起使用 [`自定义字母`]。
* [`nanoid-good`] 以确保你的ID不包含任何淫秽词汇。

[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary
[ID size 计算器]:  https://zelark.github.io/nano-id-cc/
[`自定义字母`]:    #自定义字母或大小
[`nanoid-good`]:       https://github.com/y-gagar1n/nanoid-good


================================================
FILE: bin/nanoid.js
================================================
#!/usr/bin/env node

import { readFileSync } from 'node:fs'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'

import { customAlphabet, nanoid } from '../index.js'

function print(msg) {
  process.stdout.write(msg + '\n')
}

function error(msg) {
  process.stderr.write(msg + '\n')
  process.exit(1)
}

if (process.argv.includes('--version') || process.argv.includes('-v')) {
  let root = dirname(fileURLToPath(import.meta.url))
  let pkg = JSON.parse(readFileSync(join(root, '..', 'package.json'), 'utf8'))
  print(pkg.version)
  process.exit()
}

if (process.argv.includes('--help') || process.argv.includes('-h')) {
  print(`Usage
  $ nanoid [options]

Options
  -s, --size       Generated ID size
  -a, --alphabet   Alphabet to use
  -v, --version    Show version number
  -h, --help       Show this help

Examples
  $ nanoid -s 15
  S9sBF77U6sDB8Yg

  $ nanoid --size 10 --alphabet abc
  bcabababca`)
  process.exit()
}

let alphabet, size
for (let i = 2; i < process.argv.length; i++) {
  let arg = process.argv[i]
  if (arg === '--size' || arg === '-s') {
    size = Number(process.argv[i + 1])
    i += 1
    if (Number.isNaN(size) || size <= 0) {
      error('Size must be positive integer')
    }
  } else if (arg === '--alphabet' || arg === '-a') {
    alphabet = process.argv[i + 1]
    i += 1
  } else {
    error('Unknown argument ' + arg)
  }
}

if (alphabet) {
  let customNanoid = customAlphabet(alphabet, size)
  print(customNanoid())
} else {
  print(nanoid(size))
}


================================================
FILE: eslint.config.js
================================================
import loguxConfig from '@logux/eslint-config'

/** @type {import('eslint').Linter.FlatConfig[]} */
export default [
  { ignores: ['test/demo/build', 'nanoid.js'] },
  ...loguxConfig,
  {
    rules: {
      'n/no-unsupported-features/node-builtins': 'off'
    }
  }
]


================================================
FILE: index.browser.js
================================================
/* @ts-self-types="./index.d.ts" */

// This file replaces `index.js` in bundlers like webpack or Rollup,
// according to `browser` config in `package.json`.

import { urlAlphabet as scopedUrlAlphabet } from './url-alphabet/index.js'

export { urlAlphabet } from './url-alphabet/index.js'

export let random = bytes => crypto.getRandomValues(new Uint8Array(bytes))

export let customRandom = (alphabet, defaultSize, 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.log2(alphabet.length - 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).

  // `-~f => Math.ceil(f)` if f is a float
  // `-~i => i + 1` if i is an integer
  let step = -~((1.6 * mask * defaultSize) / alphabet.length)

  return (size = defaultSize) => {
    let id = ''
    while (true) {
      let bytes = getRandom(step)
      // A compact alternative for `for (var i = 0; i < step; i++)`.
      let j = step | 0
      while (j--) {
        // Adding `|| ''` refuses a random byte that exceeds the alphabet size.
        id += alphabet[bytes[j] & mask] || ''
        if (id.length >= size) return id
      }
    }
  }
}

export let customAlphabet = (alphabet, size = 21) =>
  customRandom(alphabet, size | 0, random)

export let nanoid = (size = 21) => {
  let id = ''
  let bytes = crypto.getRandomValues(new Uint8Array((size |= 0)))
  while (size--) {
    // Using the bitwise AND operator to "cap" the value of
    // the random byte from 255 to 63, in that way we can make sure
    // that the value will be a valid index for the "chars" string.
    id += scopedUrlAlphabet[bytes[size] & 63]
  }
  return id
}


================================================
FILE: index.d.ts
================================================
/**
 * A tiny, secure, URL-friendly, unique string ID generator for JavaScript
 * with hardware random generator.
 *
 * ```js
 * import { nanoid } from 'nanoid'
 * model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
 * ```
 *
 * @module
 */

/**
 * Generate secure URL-friendly unique ID.
 *
 * By default, the ID will have 21 symbols to have a collision probability
 * similar to UUID v4.
 *
 * ```js
 * import { nanoid } from 'nanoid'
 * model.id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqL"
 * ```
 *
 * @param size Size of the ID. The default size is 21.
 * @typeparam Type The ID type to replace `string` with some opaque type.
 * @returns A random string.
 */
export function nanoid<Type extends string>(size?: number): Type

/**
 * Generate secure unique ID with custom alphabet.
 *
 * Alphabet must contain 256 symbols or less. Otherwise, the generator
 * will not be secure.
 *
 * @param alphabet Alphabet used to generate the ID.
 * @param defaultSize Size of the ID. The default size is 21.
 * @typeparam Type The ID type to replace `string` with some opaque type.
 * @returns A random string generator.
 *
 * ```js
 * import { customAlphabet } from 'nanoid'
 * const nanoid = customAlphabet('0123456789абвгдеё', 5)
 * nanoid() //=> "8ё56а"
 * ```
 */
export function customAlphabet<Type extends string>(
  alphabet: string,
  defaultSize?: number
): (size?: number) => Type

/**
 * Generate unique ID with custom random generator and alphabet.
 *
 * Alphabet must contain 256 symbols or less. Otherwise, the generator
 * will not be secure.
 *
 * ```js
 * import { customRandom } from 'nanoid'
 *
 * const nanoid = customRandom('abcdef', 5, size => {
 *   const random = []
 *   for (let i = 0; i < size; i++) {
 *     random.push(randomByte())
 *   }
 *   return random
 * })
 *
 * nanoid() //=> "fbaef"
 * ```
 *
 * @param alphabet Alphabet used to generate a random string.
 * @param size Size of the random string.
 * @param random A random bytes generator.
 * @typeparam Type The ID type to replace `string` with some opaque type.
 * @returns A random string generator.
 */
export function customRandom<Type extends string>(
  alphabet: string,
  size: number,
  random: (bytes: number) => Uint8Array
): (size?: number) => Type

/**
 * URL safe symbols.
 *
 * ```js
 * import { urlAlphabet } from 'nanoid'
 * const nanoid = customAlphabet(urlAlphabet, 10)
 * nanoid() //=> "Uakgb_J5m9"
 * ```
 */
export const urlAlphabet: string

/**
 * Generate an array of random bytes collected from hardware noise.
 *
 * ```js
 * import { customRandom, random } from 'nanoid'
 * const nanoid = customRandom("abcdef", 5, random)
 * ```
 *
 * @param bytes Size of the array.
 * @returns An array of random bytes.
 */
export function random(bytes: number): Uint8Array


================================================
FILE: index.js
================================================
import { webcrypto as crypto } from 'node:crypto'

import { urlAlphabet as scopedUrlAlphabet } from './url-alphabet/index.js'

export { urlAlphabet } from './url-alphabet/index.js'

// 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
let pool, poolOffset

function fillPool(bytes) {
  if (!pool || pool.length < bytes) {
    pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER)
    crypto.getRandomValues(pool)
    poolOffset = 0
  } else if (poolOffset + bytes > pool.length) {
    crypto.getRandomValues(pool)
    poolOffset = 0
  }
  poolOffset += bytes
}

export function random(bytes) {
  // `|=` convert `bytes` to number to prevent `valueOf` abusing and pool pollution
  fillPool((bytes |= 0))
  return pool.subarray(poolOffset - bytes, poolOffset)
}

export function customRandom(alphabet, defaultSize, 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 * defaultSize) / alphabet.length)

  return (size = defaultSize) => {
    if (!size) return ''
    let id = ''
    while (true) {
      let bytes = getRandom(step)
      // A compact alternative for `for (let 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] || ''
        if (id.length >= size) return id
      }
    }
  }
}

export function customAlphabet(alphabet, size = 21) {
  return customRandom(alphabet, size, random)
}

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++) {
    // 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 unnecessary because
    // the bitmask trims bytes down to the alphabet size.
    id += scopedUrlAlphabet[pool[i] & 63]
  }
  return id
}


================================================
FILE: jsr.json
================================================
{
  "name": "@sitnik/nanoid",
  "version": "5.1.7",
  "license": "MIT",
  "exports": {
    ".": "./index.browser.js",
    "./non-secure": "./non-secure/index.js"
  },
  "publish": {
    "include": [
      "LICENSE",
      "README.md",
      "index.d.ts",
      "index.browser.js",
      "non-secure/index.d.ts",
      "non-secure/index.js",
      "url-alphabet/index.js"
    ]
  }
}


================================================
FILE: nanoid.js
================================================
let a="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";export let nanoid=(e=21)=>{let t="",r=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+=a[63&r[e]];return t};

================================================
FILE: non-secure/index.d.ts
================================================
/**
 * 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"
 * ```
 *
 * @module
 */

/**
 * Generate URL-friendly unique ID. This method uses the non-secure
 * predictable random generator with bigger collision probability.
 *
 * ```js
 * import { nanoid } from 'nanoid/non-secure'
 * model.id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqL"
 * ```
 *
 * @param size Size of the ID. The default size is 21.
 * @typeparam Type The ID type to replace `string` with some opaque type.
 * @returns A random string.
 */
export function nanoid<Type extends string>(size?: number): Type

/**
 * Generate a unique ID based on a custom alphabet.
 * This method uses the non-secure predictable random generator
 * with bigger collision probability.
 *
 * @param alphabet Alphabet used to generate the ID.
 * @param defaultSize Size of the ID. The default size is 21.
 * @typeparam Type The ID type to replace `string` with some opaque type.
 * @returns A random string generator.
 *
 * ```js
 * import { customAlphabet } from 'nanoid/non-secure'
 * const nanoid = customAlphabet('0123456789абвгдеё', 5)
 * model.id = nanoid() //=> "8ё56а"
 * ```
 */
export function customAlphabet<Type extends string>(
  alphabet: string,
  defaultSize?: number
): (size?: number) => Type


================================================
FILE: non-secure/index.js
================================================
/* @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 =
  'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'

export let customAlphabet = (alphabet, defaultSize = 21) => {
  return (size = defaultSize) => {
    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]
    }
    return id
  }
}

export let nanoid = (size = 21) => {
  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]
  }
  return id
}


================================================
FILE: package.json
================================================
{
  "name": "nanoid",
  "version": "5.1.7",
  "description": "A tiny (118 bytes), secure URL-friendly unique string ID generator",
  "keywords": [
    "uuid",
    "random",
    "id",
    "url"
  ],
  "scripts": {
    "clean": "rm -rf coverage",
    "start": "vite --host 0.0.0.0 test/demo/",
    "test:coverage": "c8 bnt",
    "test:lint": "eslint .",
    "test:size": "pnpm clean && size-limit",
    "test:versions": "node ./test/check-versions.js",
    "test:prebuild": "node ./test/check-prebuild.js",
    "test": "pnpm run /^test:/"
  },
  "type": "module",
  "engines": {
    "node": "^18 || >=20"
  },
  "funding": [
    {
      "type": "github",
      "url": "https://github.com/sponsors/ai"
    }
  ],
  "author": "Andrey Sitnik <andrey@sitnik.ru>",
  "license": "MIT",
  "repository": "ai/nanoid",
  "exports": {
    ".": {
      "types": "./index.d.ts",
      "browser": "./index.browser.js",
      "react-native": "./index.browser.js",
      "default": "./index.js"
    },
    "./non-secure": {
      "types": "./non-secure/index.d.ts",
      "default": "./non-secure/index.js"
    },
    "./package.json": "./package.json"
  },
  "browser": {
    "./index.js": "./index.browser.js"
  },
  "react-native": {
    "./index.js": "./index.browser.js"
  },
  "bin": "./bin/nanoid.js",
  "sideEffects": false,
  "types": "./index.d.ts",
  "devDependencies": {
    "@babel/core": "^7.29.0",
    "@logux/eslint-config": "^57.1.0",
    "@lukeed/uuid": "^2.0.1",
    "@napi-rs/uuid": "^0.2.2",
    "@originjs/vite-plugin-commonjs": "^1.0.3",
    "@size-limit/file": "^12.0.1",
    "@size-limit/webpack": "^12.0.1",
    "@types/node": "^25.5.0",
    "actions-up": "^1.12.0",
    "better-node-test": "^0.8.3",
    "c8": "^11.0.0",
    "clean-publish": "^6.0.4",
    "eslint": "^10.0.3",
    "rndm": "^1.2.0",
    "secure-random-string": "^1.1.4",
    "shortid": "^2.2.17",
    "simple-git-hooks": "^2.13.1",
    "size-limit": "^12.0.1",
    "terser": "^5.46.0",
    "tinybench": "^6.0.0",
    "uid": "^2.0.2",
    "uid-safe": "^2.1.5",
    "uuid": "^13.0.0",
    "vite": "^8.0.0"
  },
  "size-limit": [
    {
      "name": "nanoid",
      "import": "{ nanoid }",
      "limit": "118 B"
    },
    {
      "name": "customAlphabet",
      "import": "{ customAlphabet }",
      "limit": "165 B"
    },
    {
      "name": "urlAlphabet",
      "import": "{ urlAlphabet }",
      "limit": "47 B"
    },
    {
      "name": "non-secure nanoid",
      "import": "{ nanoid }",
      "path": "non-secure/index.js",
      "limit": "90 B"
    },
    {
      "name": "non-secure customAlphabet",
      "import": "{ customAlphabet }",
      "path": "non-secure/index.js",
      "limit": "53 B"
    }
  ],
  "prettier": {
    "arrowParens": "avoid",
    "jsxSingleQuote": false,
    "quoteProps": "consistent",
    "semi": false,
    "singleQuote": true,
    "trailingComma": "none"
  },
  "clean-publish": {
    "cleanDocs": true,
    "cleanComments": true
  },
  "c8": {
    "exclude": [
      "bin/nanoid.js",
      "**/*.test.*",
      "test/*"
    ],
    "lines": 100,
    "check-coverage": true,
    "reporter": [
      "text",
      "lcov"
    ],
    "skip-full": true,
    "clean": true
  },
  "simple-git-hooks": {
    "pre-commit": "./test/check-versions.js"
  },
  "pnpm": {
    "ignoredBuiltDependencies": [
      "esbuild",
      "unrs-resolver"
    ],
    "onlyBuiltDependencies": [
      "simple-git-hooks"
    ]
  }
}


================================================
FILE: test/benchmark.js
================================================
#!/usr/bin/env node

import { v4 as lukeed4 } from '@lukeed/uuid'
import { v4 as napiV4 } from '@napi-rs/uuid'
import crypto from 'node:crypto'
import { styleText } from 'node:util'
import rndm from 'rndm'
import srs from 'secure-random-string'
import shortid from 'shortid'
import { Bench } from 'tinybench'
import { uid } from 'uid'
import uidSafe from 'uid-safe'
import { uid as uidSecure } from 'uid/secure'
import { v4 as uuid4 } from 'uuid'

import { nanoid as browser } from '../index.browser.js'
import { customAlphabet, nanoid } from '../index.js'
import { nanoid as nonSecure } from '../non-secure/index.js'

let bench = new Bench()

let nanoid2 = customAlphabet('1234567890abcdef-', 10)

bench
  .add('crypto.randomUUID', () => {
    crypto.randomUUID()
  })
  .add('uuid v4', () => {
    uuid4()
  })
  .add('@napi-rs/uuid', () => {
    napiV4()
  })
  .add('uid/secure', () => {
    uidSecure(32)
  })
  .add('@lukeed/uuid', () => {
    lukeed4()
  })
  .add('nanoid', () => {
    nanoid()
  })
  .add('customAlphabet', () => {
    nanoid2()
  })
  .add('nanoid for browser', () => {
    browser()
  })
  .add('secure-random-string', () => {
    srs()
  })
  .add('uid-safe.sync', () => {
    uidSafe.sync(14)
  })
  .add('shortid', () => {
    shortid()
  })
  .add('uid', () => {
    uid(32)
  })
  .add('nanoid/non-secure', () => {
    nonSecure()
  })
  .add('rndm', () => {
    rndm(21)
  })

let longestTask = bench.tasks.reduce((maxLength, task) => {
  return Math.max(maxLength, task.name.length)
}, 0)

bench.addEventListener('cycle', ({ task }) => {
  let hz = (+task.result.throughput.mean.toFixed(0))
    .toLocaleString('en-US')
    .padStart(14)

  let name = task.name.padEnd(longestTask)
  let value = styleText('bold', hz)
  let units = styleText('dim', 'ops/sec')

  if (task.name === 'uid') {
    process.stdout.write('\nNon-secure:\n')
  }

  process.stdout.write(`${name}${value} ${units}\n`)
})

await bench.run({ warmup: true })


================================================
FILE: test/bin.test.js
================================================
import { equal, match, rejects } from 'node:assert'
import child from 'node:child_process'
import { join } from 'node:path'
import { describe, test } from 'node:test'
import { fileURLToPath } from 'node:url'
import { promisify } from 'node:util'

let exec = promisify(child.exec)

const BIN = join(fileURLToPath(import.meta.url), '..', '..', 'bin', 'nanoid.js')

describe('CLI', () => {
  test('prints unique ID', async () => {
    let { stderr, stdout } = await exec(`node "${BIN}"`)
    equal(stderr, '')
    match(stdout, /^[\w-]{21}\n$/)
  })

  test('uses size', async () => {
    let { stderr, stdout } = await exec(`node "${BIN}" --size 10`)
    equal(stderr, '')
    match(stdout, /^[\w-]{10}\n$/)
  })

  test('uses alphabet', async () => {
    let { stderr, stdout } = await exec(
      `node "${BIN}" --alphabet abc --size 15`
    )
    equal(stderr, '')
    match(stdout, /^[abc]{15}\n$/)
  })

  test('shows an error on unknown argument', async () => {
    await rejects(() => exec(`node "${BIN}" -test`), /Unknown argument -test/)
  })

  test('shows an error if size is not a number', async () => {
    await rejects(
      () => exec(`node "${BIN}" -s abc`),
      /Size must be positive integer/
    )
  })

  test('requires error if size is a negative number', async () => {
    await rejects(
      () => exec(`node "${BIN}" --size "-1"`),
      /Size must be positive integer/
    )
  })

  test('displays help', async () => {
    let { stderr, stdout } = await exec(`node "${BIN}" --help`)
    equal(stderr, '')
    match(stdout, /Usage/)
    match(stdout, /\$ nanoid \[options]/)
  })

  test('displays version', async () => {
    let { stderr, stdout } = await exec(`node "${BIN}" --version`)
    equal(stderr, '')
    match(stdout, /^\d+\.\d+\.\d+\n$/)
  })
})


================================================
FILE: test/check-prebuild.js
================================================
#!/usr/bin/env node

import { readFile } from 'node:fs/promises'
import { styleText } from 'node:util'

import { BUILD_PATH, prebuild } from './prebuild.ts'

let [current, expected] = await Promise.all([
  readFile(BUILD_PATH, 'utf8'),
  prebuild()
])

if (current !== expected) {
  process.stderr.write(
    styleText(
      ['red', 'bold'],
      'nanoid.js is outdated, run node test/update-prebuild.js'
    ) + '\n'
  )
  process.exit(1)
}


================================================
FILE: test/check-versions.js
================================================
#!/usr/bin/env node

import { readFileSync } from 'node:fs'
import { join } from 'node:path'
import { styleText } from 'node:util'

const ROOT = join(import.meta.dirname, '..')

let pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8'))
let jsr = JSON.parse(readFileSync(join(ROOT, 'jsr.json'), 'utf8'))

if (pkg.version !== jsr.version) {
  process.stderr.write(
    styleText(
      ['red', 'bold'],
      `Version mismatch: package.json has ${pkg.version}, ` +
        `jsr.json has ${jsr.version}`
    ) + '\n'
  )
  process.exit(1)
}


================================================
FILE: test/demo/index.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Nano ID</title>
    <style>
      body {
        font-family: monospace;
        text-align: center;
        margin: 3rem 2rem;
      }
      main {
        font-size: 120%;
        line-height: 1.5;
        padding-bottom: 3rem;
      }
      section {
        width: 620px;
        margin: 0 auto;
      }
      section + section {
        padding-top: 1rem;
      }
      span {
        float: right;
        font-size: 90%;
      }
      h2 {
        font-size: 90%;
        font-weight: bold;
        text-align: left;
        margin: 0;
        padding-bottom: 0.5rem;
      }
      .dot {
        height: 1.5rem;
        line-height: 1.5rem;
        color: rgba(0, 0, 0, 0.5);
        display: inline-block;
        font-size: 70%;
      }
    </style>
  </head>
  <body>
    <script src="./index.js" type="module"></script>
  </body>
</html>


================================================
FILE: test/demo/index.js
================================================
import shortid from 'shortid'
import { v4 as uuid4 } from 'uuid'

import * as nanoidExport from '../../index.browser.js'
import * as nonSecureExport from '../../non-secure/index.js'

let { customAlphabet, nanoid, random } = nanoidExport
let nonSecure = nonSecureExport.nanoid

const COUNT = 50 * 1000
const ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
const LENGTH = ALPHABET.length

let nanoid2 = customAlphabet(ALPHABET, LENGTH)

function print(number) {
  return String(Math.floor(number * 100))
    .replace(/\d{6}$/, ',$&')
    .replace(/\d{3}$/, ',$&')
}

function printDistr(title, fn) {
  let data = calcDistr(title, fn)
  let keys = Object.keys(data.chars)
  let length = keys.length
  let dots = ''

  let average = keys.reduce((all, l) => all + data.chars[l], 0) / length

  for (let l of keys.sort()) {
    let distribution = data.chars[l] / average
    dots += `<div class="dot" style="
      background: hsl(${200 * distribution}, 100%, 50%);
      width: ${100 / length}%;
    ">${l}</div>`
  }

  document.body.innerHTML += `<section>
    <span>${print((COUNT * 1000) / data.time)} ops/sec</span>
    <h2>${data.title}</h2>
    ${dots}
  </section>`
}

function calcDistr(title, fn) {
  let chars = {}

  let ids = []
  let j

  let start = Date.now()
  for (j = 0; j < COUNT; j++) ids.push(fn())
  let end = Date.now()

  for (j = 0; j < COUNT; j++) {
    let id = ids[j]
    if (title === 'uuid/v4') id = id.replace(/-./g, '')
    for (let char of id) {
      if (!chars[char]) chars[char] = 0
      chars[char] += 1
    }
  }

  return { chars, time: end - start, title }
}

let tasks = [
  () =>
    printDistr('ideal', () => {
      let result = []
      for (let j = 0; j < LENGTH; j++) {
        result.push(ALPHABET[j])
      }
      return result
    }),
  () => printDistr('nanoid', () => nanoid()),
  () => printDistr('nanoid2', () => nanoid2()),
  () => printDistr('uuid/v4', () => uuid4()),
  () => printDistr('shortid', () => shortid()),
  () => printDistr('nanoid/non-secure', () => nonSecure()),
  () =>
    printDistr('random % alphabet', () => {
      return [...random(LENGTH)].map(i => ALPHABET[i % ALPHABET.length])
    })
]

function run() {
  if (tasks.length === 0) return
  let task = tasks.shift()
  task()
  setTimeout(run, 10)
}

let html = ''
for (let i = 0; i < 10; i++) {
  html += `<div>${nanoid()}</div>`
}
document.body.innerHTML = `<main>${html}</main>`

run()


================================================
FILE: test/demo/vite.config.js
================================================
import { viteCommonjs } from '@originjs/vite-plugin-commonjs'

export default {
  plugins: [viteCommonjs()]
}


================================================
FILE: test/index.test.js
================================================
import { equal, match, notEqual, ok } from 'node:assert'
import { after, before, describe, test } from 'node:test'

import * as browser from '../index.browser.js'
import * as node from '../index.js'

for (let type of ['node', 'browser']) {
  let { customAlphabet, customRandom, nanoid, random, urlAlphabet } =
    type === 'node' ? node : browser

  describe(type, () => {
    if (type === 'browser') {
      before(() => {
        Object.defineProperty(global, 'crypto', {
          configurable: true,
          value: {
            getRandomValues(array) {
              for (let i = 0; i < array.length; i++) {
                array[i] = Math.floor(Math.random() * 256)
              }
              return array
            }
          }
        })
      })

      after(() => {
        Object.defineProperty(global, 'crypto', { value: undefined })
      })
    }

    test('is ready for 0 size', () => {
      equal(nanoid(0), '')
    })

    test(`generates URL-friendly IDs`, () => {
      for (let i = 0; i < 100; i++) {
        let id = nanoid()
        equal(id.length, 21)
        equal(typeof id, 'string')
        for (let char of id) {
          match(urlAlphabet, new RegExp(char, 'g'))
        }
      }
    })

    test(`changes ID length`, () => {
      equal(nanoid(10).length, 10)
    })

    test(`generates large IDs`, () => {
      let id = nanoid(1000)
      equal(id.length, 1000)
      for (let char of id) {
        match(urlAlphabet, new RegExp(char, 'g'))
      }
    })

    test(`accepts string`, () => {
      equal(nanoid('10').length, 10)
    })

    test(`has no collisions`, () => {
      let used = {}
      for (let i = 0; i < 50 * 1000; i++) {
        let id = nanoid()
        equal(used[id], undefined)
        used[id] = true
      }
    })

    test(`avoids pool pollution, infinite loop`, () => {
      nanoid(2.1)
      let second = nanoid()
      let third = nanoid()
      notEqual(second, third)
    })

    test(`has flat distribution`, () => {
      let COUNT = 100 * 1000
      let LENGTH = nanoid().length

      let chars = {}
      for (let i = 0; i < COUNT; i++) {
        let id = nanoid()
        for (let char of id) {
          if (!chars[char]) chars[char] = 0
          chars[char] += 1
        }
      }

      equal(Object.keys(chars).length, urlAlphabet.length)

      let max = 0
      let min = Number.MAX_SAFE_INTEGER
      for (let k in chars) {
        let distribution = (chars[k] * urlAlphabet.length) / (COUNT * LENGTH)
        if (distribution > max) max = distribution
        if (distribution < min) min = distribution
      }
      ok(max - min <= 0.05)
    })

    test(`${type} / customAlphabet / has options`, () => {
      let nanoidA = customAlphabet('a', 5)
      equal(nanoidA(), 'aaaaa')
    })

    test(`${type} / customAlphabet / has flat distribution`, () => {
      let COUNT = 50 * 1000
      let LENGTH = 30
      let ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
      let nanoid2 = customAlphabet(ALPHABET, LENGTH)

      let chars = {}
      for (let i = 0; i < COUNT; i++) {
        let id = nanoid2()
        for (let char of id) {
          if (!chars[char]) chars[char] = 0
          chars[char] += 1
        }
      }

      equal(Object.keys(chars).length, ALPHABET.length)

      let max = 0
      let min = Number.MAX_SAFE_INTEGER
      for (let k in chars) {
        let distribution = (chars[k] * ALPHABET.length) / (COUNT * LENGTH)
        if (distribution > max) max = distribution
        if (distribution < min) min = distribution
      }
      ok(max - min <= 0.05)
    })

    test(`${type} / customAlphabet / changes size`, () => {
      let nanoidA = customAlphabet('a')
      equal(nanoidA(10), 'aaaaaaaaaa')
    })

    test(`${type} / customAlphabet / avoids pool pollution, infinite loop`, () => {
      let ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
      let nanoid2 = customAlphabet(ALPHABET)
      nanoid2(2.1)
      let second = nanoid2()
      let third = nanoid2()
      notEqual(second, third)
    })

    test(`${type} / customRandom / supports generator`, () => {
      let sequence = [2, 255, 3, 7, 7, 7, 7, 7, 0, 1]
      function fakeRandom(size) {
        let bytes = []
        for (let i = 0; i < size; i += sequence.length) {
          bytes = bytes.concat(sequence.slice(0, size - i))
        }
        return bytes
      }
      let nanoid4 = customRandom('abcde', 4, fakeRandom)
      let nanoid18 = customRandom('abcde', 18, fakeRandom)
      equal(nanoid4(), 'adca')
      equal(nanoid18(), 'cbadcbadcbadcbadcc')
    })

    test(`${type} / urlAlphabet / is string`, () => {
      equal(typeof urlAlphabet, 'string')
    })

    test(`${type} / urlAlphabet / has 64 symbols`, () => {
      equal(urlAlphabet.length, 64)
    })

    test(`${type} / urlAlphabet / has no duplicates`, () => {
      for (let i = 0; i < urlAlphabet.length; i++) {
        equal(urlAlphabet.lastIndexOf(urlAlphabet[i]), i)
      }
    })

    test(`${type} / random / generates small random buffers`, () => {
      for (let i = 0; i < urlAlphabet.length; i++) {
        equal(random(10).length, 10)
      }
    })

    test(`${type} / random / generates random buffers`, () => {
      let numbers = {}
      let bytes = random(1000)
      equal(bytes.length, 1000)
      for (let byte of bytes) {
        if (!numbers[byte]) numbers[byte] = 0
        numbers[byte] += 1
        equal(typeof byte, 'number')
        ok(byte <= 255)
        ok(byte >= 0)
      }
    })

    if (type === 'node') {
      test(`${type} / proxy number / prevent collision`, () => {
        let makeProxyNumberToReproducePreviousID = () => {
          let step = 0
          return {
            valueOf() {
              // "if (!pool || pool.length < bytes) {"
              if (step === 0) {
                step++
                return 0
              }
              // "} else if (poolOffset + bytes > pool.length) {"
              if (step === 1) {
                step++
                return -Infinity
              }
              // "poolOffset += bytes"
              if (step === 2) {
                step++
                return 0
              }

              return 21
            }
          }
        }

        let id1 = nanoid()
        let id2 = nanoid(makeProxyNumberToReproducePreviousID())
        notEqual(id1, id2)
      })

      test(`${type} / customAlphabet / does not fall in infinite loop`, () => {
        equal(customAlphabet('abc')(0), '')
        equal(customAlphabet('abc', 0)(0), '')
      })
    }
  })
}


================================================
FILE: test/non-secure.test.js
================================================
import { equal, match, notEqual, ok } from 'node:assert'
import { describe, test } from 'node:test'

import { urlAlphabet } from '../index.js'
import { customAlphabet, nanoid } from '../non-secure/index.js'

describe('non secure', () => {
  test('is ready for 0 size', () => {
    equal(nanoid(0), '')
  })

  test('customAlphabet / is ready for 0 size', () => {
    equal(customAlphabet('abc')(0), '')
    equal(customAlphabet('abc', 0)(0), '')
  })

  test('generates URL-friendly IDs', () => {
    for (let i = 0; i < 10; i++) {
      let id = nanoid()
      equal(id.length, 21)
      for (let char of id) {
        match(urlAlphabet, new RegExp(char, 'g'))
      }
    }
  })

  test('changes ID length', () => {
    equal(nanoid(10).length, 10)
  })

  test('accepts string', () => {
    equal(nanoid('10').length, 10)
  })

  test('has no collisions', () => {
    let used = {}
    for (let i = 0; i < 100 * 1000; i++) {
      let id = nanoid()
      equal(used[id], undefined)
      used[id] = true
    }
  })

  test('has flat distribution', () => {
    let COUNT = 100 * 1000
    let LENGTH = nanoid().length

    let chars = {}
    for (let i = 0; i < COUNT; i++) {
      let id = nanoid()
      for (let char of id) {
        if (!chars[char]) chars[char] = 0
        chars[char] += 1
      }
    }

    equal(Object.keys(chars).length, urlAlphabet.length)

    let max = 0
    let min = Number.MAX_SAFE_INTEGER
    for (let k in chars) {
      let distribution = (chars[k] * urlAlphabet.length) / (COUNT * LENGTH)
      if (distribution > max) max = distribution
      if (distribution < min) min = distribution
    }
    ok(max - min <= 0.05)
  })

  test('nanoid / avoids pool pollution, infinite loop', () => {
    nanoid(2.1)
    let second = nanoid()
    let third = nanoid()
    notEqual(second, third)
  })

  test('customAlphabet / has options', () => {
    let nanoidA = customAlphabet('a', 5)
    equal(nanoidA(), 'aaaaa')
  })

  test('customAlphabet / has flat distribution', () => {
    let COUNT = 100 * 1000
    let LENGTH = 5
    let ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
    let nanoid2 = customAlphabet(ALPHABET, LENGTH)

    let chars = {}
    for (let i = 0; i < COUNT; i++) {
      let id = nanoid2()
      for (let char of id) {
        if (!chars[char]) chars[char] = 0
        chars[char] += 1
      }
    }

    equal(Object.keys(chars).length, ALPHABET.length)

    let max = 0
    let min = Number.MAX_SAFE_INTEGER
    for (let k in chars) {
      let distribution = (chars[k] * ALPHABET.length) / (COUNT * LENGTH)
      if (distribution > max) max = distribution
      if (distribution < min) min = distribution
    }
    ok(max - min <= 0.05)
  })

  test('customAlphabet / avoids pool pollution, infinite loop', () => {
    let ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
    let nanoid2 = customAlphabet(ALPHABET)
    nanoid2(2.1)
    let second = nanoid2()
    let third = nanoid2()
    notEqual(second, third)
  })
})


================================================
FILE: test/prebuild.ts
================================================
import { readFile } from 'node:fs/promises'
import { join } from 'node:path'
import { minify } from 'terser'

import { urlAlphabet } from '../url-alphabet/index.js'

export const BUILD_PATH = join(import.meta.dirname, '..', 'nanoid.js')

export async function prebuild(): Promise<string> {
  let js = await readFile(join(import.meta.dirname, '..', 'index.browser.js'))
  let func = js.toString().match(/(export let nanoid [\W\w]*$)/)![1]
  let all =
    `let a = '${urlAlphabet}'\n` +
    `${func.replaceAll('scopedUrlAlphabet', 'a')}`
  let { code } = await minify(all)
  return code!
}


================================================
FILE: test/update-prebuild.js
================================================
#!/usr/bin/env node

import { writeFile } from 'node:fs/promises'

import { BUILD_PATH, prebuild } from './prebuild.ts'

async function build() {
  let code = await prebuild()
  await writeFile(BUILD_PATH, code)
}

build().catch(e => {
  throw e
})


================================================
FILE: url-alphabet/index.js
================================================
// 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'
Download .txt
gitextract_garhu55w/

├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       ├── jsr.yml
│       ├── release.yml
│       └── test.yml
├── .gitignore
├── .npmignore
├── .prettierignore
├── CHANGELOG.md
├── LICENSE
├── README.ar.md
├── README.id-ID.md
├── README.ja.md
├── README.ko.md
├── README.md
├── README.ru.md
├── README.zh-CN.md
├── bin/
│   └── nanoid.js
├── eslint.config.js
├── index.browser.js
├── index.d.ts
├── index.js
├── jsr.json
├── nanoid.js
├── non-secure/
│   ├── index.d.ts
│   └── index.js
├── package.json
├── test/
│   ├── benchmark.js
│   ├── bin.test.js
│   ├── check-prebuild.js
│   ├── check-versions.js
│   ├── demo/
│   │   ├── index.html
│   │   ├── index.js
│   │   └── vite.config.js
│   ├── index.test.js
│   ├── non-secure.test.js
│   ├── prebuild.ts
│   └── update-prebuild.js
└── url-alphabet/
    └── index.js
Download .txt
SYMBOL INDEX (23 symbols across 8 files)

FILE: bin/nanoid.js
  function print (line 9) | function print(msg) {
  function error (line 13) | function error(msg) {

FILE: index.js
  constant POOL_SIZE_MULTIPLIER (line 12) | const POOL_SIZE_MULTIPLIER = 128
  function fillPool (line 15) | function fillPool(bytes) {
  function random (line 27) | function random(bytes) {
  function customRandom (line 33) | function customRandom(alphabet, defaultSize, getRandom) {
  function customAlphabet (line 69) | function customAlphabet(alphabet, size = 21) {
  function nanoid (line 73) | function nanoid(size = 21) {

FILE: test/bin.test.js
  constant BIN (line 10) | const BIN = join(fileURLToPath(import.meta.url), '..', '..', 'bin', 'nan...

FILE: test/check-versions.js
  constant ROOT (line 7) | const ROOT = join(import.meta.dirname, '..')

FILE: test/demo/index.js
  constant COUNT (line 10) | const COUNT = 50 * 1000
  constant ALPHABET (line 11) | const ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
  constant LENGTH (line 12) | const LENGTH = ALPHABET.length
  function print (line 16) | function print(number) {
  function printDistr (line 22) | function printDistr(title, fn) {
  function calcDistr (line 45) | function calcDistr(title, fn) {
  function run (line 87) | function run() {

FILE: test/index.test.js
  method getRandomValues (line 17) | getRandomValues(array) {
  function fakeRandom (line 152) | function fakeRandom(size) {
  method valueOf (line 203) | valueOf() {

FILE: test/prebuild.ts
  constant BUILD_PATH (line 7) | const BUILD_PATH = join(import.meta.dirname, '..', 'nanoid.js')
  function prebuild (line 9) | async function prebuild(): Promise<string> {

FILE: test/update-prebuild.js
  function build (line 7) | async function build() {
Condensed preview — 39 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (150K chars).
[
  {
    "path": ".editorconfig",
    "chars": 189,
    "preview": "root = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ni"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 32,
    "preview": "tidelift: npm/nanoid\ngithub: ai\n"
  },
  {
    "path": ".github/workflows/jsr.yml",
    "chars": 681,
    "preview": "name: Publish to JSR\non:\n  push:\n    tags:\n      - '*'\npermissions:\n  contents: read\n  id-token: write\njobs:\n  jsr:\n    "
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 1479,
    "preview": "name: Release\non:\n  push:\n    tags:\n      - '*'\npermissions:\n  contents: write\njobs:\n  release:\n    name: Release On Tag"
  },
  {
    "path": ".github/workflows/test.yml",
    "chars": 2237,
    "preview": "name: Test\non:\n  push:\n    branches:\n      - main\n      - v3\n  pull_request:\npermissions:\n  contents: read\njobs:\n  full:"
  },
  {
    "path": ".gitignore",
    "chars": 25,
    "preview": "node_modules/\n\ncoverage/\n"
  },
  {
    "path": ".npmignore",
    "chars": 46,
    "preview": "test/\ntsconfig.json\ncoverage/\n\nimg/\n\njsr.json\n"
  },
  {
    "path": ".prettierignore",
    "chars": 10,
    "preview": "nanoid.js\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 8193,
    "preview": "# Change Log\nThis project adheres to [Semantic Versioning](http://semver.org/).\n\n## 5.1.7\n* Added `--version` to CLI (by"
  },
  {
    "path": "LICENSE",
    "chars": 1095,
    "preview": "The MIT License (MIT)\n\nCopyright 2017 Andrey Sitnik <andrey@sitnik.ru>\n\nPermission is hereby granted, free of charge, to"
  },
  {
    "path": "README.ar.md",
    "chars": 15007,
    "preview": "# Nano ID\n\n<img src=\"https://ai.github.io/nanoid/logo.svg\" align=\"right\"\n     alt=\"Nano ID logo by Anton Lovchikov\" widt"
  },
  {
    "path": "README.id-ID.md",
    "chars": 14536,
    "preview": "# Nano ID\n\n<img src=\"https://ai.github.io/nanoid/logo.svg\" align=\"right\"\n     alt=\"Logo Nano ID oleh Anton Lovchikov\" wi"
  },
  {
    "path": "README.ja.md",
    "chars": 11519,
    "preview": "# Nano ID\n\n<img src=\"https://ai.github.io/nanoid/logo.svg\" align=\"right\"\n     alt=\"Nano ID logo by Anton Lovchikov\" widt"
  },
  {
    "path": "README.ko.md",
    "chars": 12319,
    "preview": "# Nano ID\n\n<img src=\"https://ai.github.io/nanoid/logo.svg\" align=\"right\"\n     alt=\"Nano ID logo by Anton Lovchikov\" widt"
  },
  {
    "path": "README.md",
    "chars": 14562,
    "preview": "# Nano ID\n\n<img src=\"https://ai.github.io/nanoid/logo.svg\" align=\"right\"\n     alt=\"Nano ID logo by Anton Lovchikov\" widt"
  },
  {
    "path": "README.ru.md",
    "chars": 14465,
    "preview": "# Nano ID\n\n<img src=\"https://ai.github.io/nanoid/logo.svg\" align=\"right\"\n     alt=\"Логотип Nano ID от Антона Ловчикова\" "
  },
  {
    "path": "README.zh-CN.md",
    "chars": 9802,
    "preview": "# Nano ID\n\n<img src=\"https://ai.github.io/nanoid/logo.svg\" align=\"right\"\n     alt=\"Nano ID logo by Anton Lovchikov\" widt"
  },
  {
    "path": "bin/nanoid.js",
    "chars": 1519,
    "preview": "#!/usr/bin/env node\n\nimport { readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLTo"
  },
  {
    "path": "eslint.config.js",
    "chars": 268,
    "preview": "import loguxConfig from '@logux/eslint-config'\n\n/** @type {import('eslint').Linter.FlatConfig[]} */\nexport default [\n  {"
  },
  {
    "path": "index.browser.js",
    "chars": 2559,
    "preview": "/* @ts-self-types=\"./index.d.ts\" */\n\n// This file replaces `index.js` in bundlers like webpack or Rollup,\n// according t"
  },
  {
    "path": "index.d.ts",
    "chars": 2762,
    "preview": "/**\n * A tiny, secure, URL-friendly, unique string ID generator for JavaScript\n * with hardware random generator.\n *\n * "
  },
  {
    "path": "index.js",
    "chars": 3439,
    "preview": "import { webcrypto as crypto } from 'node:crypto'\n\nimport { urlAlphabet as scopedUrlAlphabet } from './url-alphabet/inde"
  },
  {
    "path": "jsr.json",
    "chars": 383,
    "preview": "{\n  \"name\": \"@sitnik/nanoid\",\n  \"version\": \"5.1.7\",\n  \"license\": \"MIT\",\n  \"exports\": {\n    \".\": \"./index.browser.js\",\n  "
  },
  {
    "path": "nanoid.js",
    "chars": 190,
    "preview": "let a=\"useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict\";export let nanoid=(e=21)=>{let t=\"\",r=crypto.ge"
  },
  {
    "path": "non-secure/index.d.ts",
    "chars": 1532,
    "preview": "/**\n * By default, Nano ID uses hardware random bytes generation for security\n * and low collision probability. If you a"
  },
  {
    "path": "non-secure/index.js",
    "chars": 1120,
    "preview": "/* @ts-self-types=\"./index.d.ts\" */\n\n// This alphabet uses `A-Za-z0-9_-` symbols.\n// The order of characters is optimize"
  },
  {
    "path": "package.json",
    "chars": 3419,
    "preview": "{\n  \"name\": \"nanoid\",\n  \"version\": \"5.1.7\",\n  \"description\": \"A tiny (118 bytes), secure URL-friendly unique string ID g"
  },
  {
    "path": "test/benchmark.js",
    "chars": 1965,
    "preview": "#!/usr/bin/env node\n\nimport { v4 as lukeed4 } from '@lukeed/uuid'\nimport { v4 as napiV4 } from '@napi-rs/uuid'\nimport cr"
  },
  {
    "path": "test/bin.test.js",
    "chars": 1785,
    "preview": "import { equal, match, rejects } from 'node:assert'\nimport child from 'node:child_process'\nimport { join } from 'node:pa"
  },
  {
    "path": "test/check-prebuild.js",
    "chars": 444,
    "preview": "#!/usr/bin/env node\n\nimport { readFile } from 'node:fs/promises'\nimport { styleText } from 'node:util'\n\nimport { BUILD_P"
  },
  {
    "path": "test/check-versions.js",
    "chars": 551,
    "preview": "#!/usr/bin/env node\n\nimport { readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { styleText } from '"
  },
  {
    "path": "test/demo/index.html",
    "chars": 920,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"UTF-8\">\n    <title>Nano ID</title>\n    <style>\n      body {\n        f"
  },
  {
    "path": "test/demo/index.js",
    "chars": 2407,
    "preview": "import shortid from 'shortid'\nimport { v4 as uuid4 } from 'uuid'\n\nimport * as nanoidExport from '../../index.browser.js'"
  },
  {
    "path": "test/demo/vite.config.js",
    "chars": 110,
    "preview": "import { viteCommonjs } from '@originjs/vite-plugin-commonjs'\n\nexport default {\n  plugins: [viteCommonjs()]\n}\n"
  },
  {
    "path": "test/index.test.js",
    "chars": 6534,
    "preview": "import { equal, match, notEqual, ok } from 'node:assert'\nimport { after, before, describe, test } from 'node:test'\n\nimpo"
  },
  {
    "path": "test/non-secure.test.js",
    "chars": 2962,
    "preview": "import { equal, match, notEqual, ok } from 'node:assert'\nimport { describe, test } from 'node:test'\n\nimport { urlAlphabe"
  },
  {
    "path": "test/prebuild.ts",
    "chars": 588,
    "preview": "import { readFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { minify } from 'terser'\n\nimport { u"
  },
  {
    "path": "test/update-prebuild.js",
    "chars": 249,
    "preview": "#!/usr/bin/env node\n\nimport { writeFile } from 'node:fs/promises'\n\nimport { BUILD_PATH, prebuild } from './prebuild.ts'\n"
  },
  {
    "path": "url-alphabet/index.js",
    "chars": 253,
    "preview": "// This alphabet uses `A-Za-z0-9_-` symbols.\n// The order of characters is optimized for better gzip and brotli compress"
  }
]

About this extraction

This page contains the full source code of the ai/nanoid GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 39 files (138.8 KB), approximately 46.8k tokens, and a symbol index with 23 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!