[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[nanoid.js]\ninsert_final_newline = false\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "tidelift: npm/nanoid\ngithub: ai\n"
  },
  {
    "path": ".github/workflows/jsr.yml",
    "content": "name: Publish to JSR\non:\n  push:\n    tags:\n      - '*'\npermissions:\n  contents: read\n  id-token: write\njobs:\n  jsr:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout the repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      - name: Check tag version\n        id: check\n        run: |\n          TAG=${GITHUB_REF#refs/tags/}\n          MAJOR=$(echo $TAG | cut -d. -f1)\n          if [[ \"$MAJOR\" =~ ^[0-9]+$ && \"$MAJOR\" -gt 3 ]]; then\n            echo \"version_ok=true\" >> $GITHUB_OUTPUT\n          fi\n        shell: bash\n      - name: Publish to JSR\n        if: steps.check.outputs.version_ok == 'true'\n        run: npx jsr publish\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\non:\n  push:\n    tags:\n      - '*'\npermissions:\n  contents: write\njobs:\n  release:\n    name: Release On Tag\n    if: startsWith(github.ref, 'refs/tags/')\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout the repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      - name: Extract the changelog\n        id: changelog\n        run: |\n          TAG_NAME=${GITHUB_REF/refs\\/tags\\//}\n          READ_SECTION=false\n          CHANGELOG=\"\"\n          while IFS= read -r line; do\n            if [[ \"$line\" =~ ^#+\\ +(.*) ]]; then\n              if [[ \"${BASH_REMATCH[1]}\" == \"$TAG_NAME\" ]]; then\n                READ_SECTION=true\n              elif [[ \"$READ_SECTION\" == true ]]; then\n                break\n              fi\n            elif [[ \"$READ_SECTION\" == true ]]; then\n              CHANGELOG+=\"$line\"$'\\n'\n            fi\n          done < \"CHANGELOG.md\"\n          CHANGELOG=$(echo \"$CHANGELOG\" | awk '/./ {$1=$1;print}')\n          echo \"changelog_content<<EOF\" >> $GITHUB_OUTPUT\n          echo \"$CHANGELOG\" >> $GITHUB_OUTPUT\n          echo \"EOF\" >> $GITHUB_OUTPUT\n      - name: Create the release\n        if: steps.changelog.outputs.changelog_content != ''\n        uses: softprops/action-gh-release@1853d73993c8ca1b2c9c1a7fede39682d0ab5c2a # v2.5.3\n        with:\n          name: ${{ github.ref_name }}\n          body: '${{ steps.changelog.outputs.changelog_content }}'\n          draft: false\n          prerelease: false\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Test\non:\n  push:\n    branches:\n      - main\n      - v3\n  pull_request:\npermissions:\n  contents: read\njobs:\n  full:\n    name: Node.js Latest Full\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout the repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      - name: Install pnpm\n        uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0\n        with:\n          version: 10\n      - name: Install Node.js\n        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0\n        with:\n          node-version: 25\n          cache: pnpm\n      - name: Install dependencies\n        run: pnpm install --ignore-scripts\n      - name: Run tests\n        run: pnpm test\n  short:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        node-version:\n          - 24\n          - 22\n          - 20\n          - 18\n    name: Node.js ${{ matrix.node-version }} Quick\n    steps:\n      - name: Checkout the repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      - name: Install pnpm\n        uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0\n        with:\n          version: 10\n      - name: Install Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0\n        with:\n          node-version: ${{ matrix.node-version }}\n          cache: pnpm\n      - name: Install dependencies\n        run: pnpm install --ignore-scripts\n      - name: Run unit tests\n        run: pnpm bnt\n  benchmark:\n    name: Benchmark\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout the repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      - name: Install pnpm\n        uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0\n        with:\n          version: 10\n      - name: Install Node.js\n        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0\n        with:\n          node-version: 22\n          cache: pnpm\n      - name: Install dependencies\n        run: pnpm install --ignore-scripts\n      - name: Run benchmark\n        run: node ./test/benchmark.js\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules/\n\ncoverage/\n"
  },
  {
    "path": ".npmignore",
    "content": "test/\ntsconfig.json\ncoverage/\n\nimg/\n\njsr.json\n"
  },
  {
    "path": ".prettierignore",
    "content": "nanoid.js\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change Log\nThis project adheres to [Semantic Versioning](http://semver.org/).\n\n## 5.1.7\n* Added `--version` to CLI (by @mahmoodhamdi).\n* Updated `nanoid.js` for CDN (by @mahmoodhamdi).\n* Fixed docs (by @mahmoodhamdi).\n* Fixed `customRandom` types (by @oguimbal).\n\n## 5.1.6\n* Fixed infinite loop on 0 size for `customAlphabet`.\n\n## 5.1.5\n* Fixed latest version on npm after 3.x release.\n\n## 5.1.4\n* Fixed latest version on npm after 3.x release.\n\n## 5.1.3\n* Fixed React Native support (by @steida).\n\n## 5.1.2\n* Fixed module docs.\n\n## 5.1.1\n* Fixed opaque types support for non-secure generator.\n* Added JSR support.\n\n## 5.1.0\n* Added opaque types support (by @kossnocorp).\n\n## 5.0.9\n* Fixed a way to break Nano ID by passing non-integer size (by @myndzi).\n\n## 5.0.8\n* Reduced `customAlphabet` size (by @kirillgroshkov).\n\n## 5.0.7\n* Fixed Parcel support (by @WilhelmYakunin).\n\n## 5.0.6\n* Fixed React Native support.\n\n## 5.0.5\n* Make browser’s version faster by increasing size a little (by Samuel Elgozi).\n\n## 5.0.4\n* Fixed CLI docs (by @ilyaboka).\n\n## 5.0.3\n* Fixed CLI docs (by Chris Schmich).\n\n## 5.0.2\n* Fixed `webcrypto` import (by Divyansh Singh).\n\n## 5.0.1\n* Fixed Node.js 18 support.\n\n## 5.0\n* Moved Node.js version to Web Crypto API.\n* Removed async API since Web Crypto API has only sync version.\n* Removed Node.js 14 and 16 support.\n\n## 4.0.2\n* Added [link](https://github.com/sponsors/ai) to Github Sponsors.\n\n## 4.0.1\n* Reduced npm package size (by @HiChen404).\n\n## 4.0\n* Removed CommonJS support. Nano ID 4 will work only with ESM applications.\n  We will support 3.x branch with CommonJS for users who can’t migrate to ESM.\n* Removed Node.js 10 and Node.js 12 support.\n* Reduced npm package size.\n\n## 3.3.11\n* Fixed React Native support.\n\n## 3.3.10\n* Fixed React Native support (by @steida).\n\n## 3.3.9\n* Reduced npm package size.\n\n## 3.3.8\n* Fixed a way to break Nano ID by passing non-integer size (by @myndzi).\n\n## 3.3.7\n* Fixed `node16` TypeScript support (by Saadi Myftija).\n\n## 3.3.6\n* Fixed package.\n\n## 3.3.5\n* Backport funding information.\n\n## 3.3.4\n* Fixed `--help` in CLI (by @Lete114).\n\n## 3.3.3\n* Reduced size (by Anton Khlynovskiy).\n\n## 3.3.2\n* Fixed `enhanced-resolve` support.\n\n## 3.3.1\n* Reduced package size.\n\n## 3.3\n* Added `size` argument to function from `customAlphabet` (by Stefan Sundin).\n\n## 3.2\n* Added `--size` and `--alphabet` arguments to binary (by Vitaly Baev).\n\n## 3.1.32\n* Reduced `async` exports size (by Artyom Arutyunyan).\n* Moved from Jest to uvu (by Vitaly Baev).\n\n## 3.1.31\n* Fixed collision vulnerability on object in `size` (by Artyom Arutyunyan).\n\n## 3.1.30\n* Reduced size for project with `brotli` compression (by Anton Khlynovskiy).\n\n## 3.1.29\n* Reduced npm package size.\n\n## 3.1.28\n* Reduced npm package size.\n\n## 3.1.27\n* Cleaned `dependencies` from development tools.\n\n## 3.1.26\n* Improved performance (by Eitan Har-Shoshanim).\n* Reduced npm package size.\n\n## 3.1.25\n* Fixed `browserify` support.\n\n## 3.1.24\n* Fixed `browserify` support (by Artur Paikin).\n\n## 3.1.23\n* Fixed `esbuild` support.\n\n## 3.1.22\n* Added `default` and `browser.default` to `package.exports`.\n\n## 3.1.21\n* Reduced npm package size.\n\n## 3.1.20\n* Fix ES modules support.\n\n## 3.1.19\n* Reduced `customAlphabet` size (by Enrico Scherlies).\n\n## 3.1.18\n* Fixed `package.exports`.\n\n## 3.1.17\n* Added files without `process`.\n\n## 3.1.16\n* Speeded up Nano ID 4 times (by Peter Boyer).\n\n## 3.1.15\n* Fixed `package.types` path.\n\n## 3.1.14\n* Added `package.types`.\n\n## 3.1.13\n* Removed Node.js 15.0.0 with `randomFillSync` regression from `engines.node`.\n\n## 3.1.12\n* Improved IE 11 docs.\n\n## 3.1.11\n* Fixed asynchronous `customAlphabet` in browser (by @LoneRifle).\n\n## 3.1.10\n* Fix ES modules support.\n\n## 3.1.9\n* Try to fix React Native Expo support.\n\n## 3.1.8\n* Add React Native Expo support.\n\n## 3.1.7\n* Clean up code.\n\n## 3.1.6\n* Avoid `self` using.\n\n## 3.1.5\n* Improve IE docs and warning.\n\n## 3.1.4\n* Restrict old Node.js 13 by `engines.node` (by Cansin Yildiz).\n\n## 3.1.3\n* Fix ES modules issue with CLI.\n\n## 3.1.2\n* Add shebang to CLI.\n\n## 3.1.1\n* Fix CLI.\n\n## 3.1\n* Add `npx nanoid` CLI.\n\n## 3.0.2\n* Fix docs (by Dylan Irlbeck ).\n\n## 3.0.1\n* Fix React Native warning on `non-secure` import (by Jia Huang).\n\n## 3.0\n**Migration guide:** <https://github.com/ai/nanoid/releases/tag/3.0.0>\n* Move to ES2016 syntax. You need to use Babel for IE 11.\n* Move to named exports `import { nanoid } from 'nanoid'`.\n* Move `import url from 'nanoid/url'` to `import { urlAlphabet } from 'nanoid'`.\n* Replace `format()` to `customRandom()`.\n* Replace `generate()` to `customAlphabet()`.\n* Remove `async/format`.\n* Remove React Native support for `nanoid/async`.\n* Add `nanoid.js` to use directly in browser from CDN.\n* Add TypeScript type definitions.\n* Add ES modules support for bundlers, Node.js, and React Native.\n* Fix React Native support.\n* Reduce size.\n* Improve docs (by Dair Aidarkhanov).\n\n## 2.1.11\n* Reduce size (by Anton Evzhakov).\n\n## 2.1.10\n* Reduce size by 10% (by Anton Khlynovskiy).\n\n## 2.1.9\n* Reduce `format` and `async/format` size (by Dair Aidarkhanov).\n\n## 2.1.8\n* Improve React docs (by Nahum Zsilva).\n\n## 2.1.7\n* Reduce `index`, `async` and `non-secure` size (by @polemius).\n\n## 2.1.6\n* Reduce size (by Stas Lashmanov).\n* Return fast mask for Node.js.\n\n## 2.1.5\n* Reduce size (by Max Graey).\n* Fix IE support.\n\n## 2.1.4\n* Reduce `generate` size (by Vsevolod Rodionov).\n* Reduce `format` and `format` size (by Victor).\n* Reduce `async`, `non-secure` and `non-secure/generate` size.\n* Speed up `format` and `async/format` (by Max Graey).\n* Improve development process on Windows (by Stanislav Lashmanov).\n\n## 2.1.3\n* Improve performance (by Stephen Richardson).\n* Reduce size (by Stephen Richardson).\n\n## 2.1.2\n* Improve docs.\n\n## 2.1.1\n* Fix React Native support (by Shawn Hwei).\n\n## 2.1\n* Improve React Native support (by Sebastian Werner).\n\n## 2.0.4\n* Improve error text for React Native (by Sebastian Werner).\n\n## 2.0.3\n* Fix freeze on string in ID length.\n\n## 2.0.2\n* Improve docs (by Sylvanus Kateile and Mark Stosberg).\n\n## 2.0.1\n* Reduce npm package size.\n* Mark package as not having side effects (by @xiaody).\n\n## 2.0\n* Use `-` instead of `~` in default alphabet to by file name safe.\n* Add `nanoid/non-secure/generate`.\n\n## 1.3.4\n* Reduce `non-secure` size.\n* Add `async` callback type check.\n\n## 1.3.3\n* Fix `nanoid/async` performance regression.\n* Fix old Node.js `not seeded` issue in synchronous version too.\n\n## 1.3.2\n* Fix random generator `not seeded` issue of old Node.js.\n\n## 1.3.1\n* Reduce library size.\n\n## 1.3\n* Add `nanoid/async/format` and `nanoid/async/generate`.\n* Improve synchronous API performance.\n* Reduce `url` size (by Daniil Poroshin).\n* Improve React Native docs (by joelgetaction).\n\n## 1.2.6\n* Reduce library size (by rqrqrqrq).\n\n## 1.2.5\n* Fix Node.js 6.11.1 support (by Andrey Belym).\n\n## 1.2.4\n* Speed up Node.js secure generators (by Dmitriy Tsvettsikh).\n\n## 1.2.3\n* Fix JSDoc (by Hendry Sadrak).\n\n## 1.2.2\n* Fix distribution in `nanoid/non-secure` (by Eatall).\n\n## 1.2.1\n* Fix old Node.js support.\n\n## 1.2\n* Add `nanoid/async`.\n* Fix `nanoid/non-secure` JSDoc.\n* Add Chinese documentation (by Wenliang Dai).\n* Speed up and reduce size of `nanoid/non-secure` (by Ori Livni).\n\n## 1.1.1\n* Improve performance and reduce size of non-secure ID generator.\n\n## 1.1\n* Add non-secure ID generator.\n* Suggest to use non-secure ID generator for React Native developers.\n* Reduce size.\n\n## 1.0.7\n* Fix documentation.\n\n## 1.0.6\n* Fix documentation.\n\n## 1.0.5\n* Reduce `nanoid/index` size (by Anton Khlynovskiy).\n\n## 1.0.4\n* Reduce npm package size.\n\n## 1.0.3\n* Reduce npm package size.\n\n## 1.0.2\n* Fix Web Workers support (by Zachary Golba).\n\n## 1.0.1\n* Reduce `nanoid/index` size (by Anton Khlynovskiy).\n\n## 1.0\n* Use 21 symbols by default (by David Klebanoff).\n\n## 0.2.2\n* Reduce `nanoid/generate` size (by Anton Khlynovskiy).\n* Speed up Node.js random generator.\n\n## 0.2.1\n* Fix documentation (by Piper Chester).\n\n## 0.2\n* Add `size` argument to `nanoid()`.\n* Improve performance by 50%.\n* Reduce library size by 26% (by Vsevolod Rodionov and Oleg Mokhov).\n\n## 0.1.1\n* Reduce library size by 5%.\n\n## 0.1\n* Initial release.\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright 2017 Andrey Sitnik <andrey@sitnik.ru>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.ar.md",
    "content": "# Nano ID\n\n<img src=\"https://ai.github.io/nanoid/logo.svg\" align=\"right\"\n     alt=\"Nano ID logo by Anton Lovchikov\" width=\"180\" height=\"94\">\n\n<div dir=\"rtl\">\n\n[English](./README.md) | [日本語](./README.ja.md) | [Русский](./README.ru.md) | [简体中文](./README.zh-CN.md) | [Bahasa Indonesia](./README.id-ID.md) | [한국어](./README.ko.md) | **العربية**\n\nمُولِّد مُعرِّفات فريدة صغير الحجم وآمن ومتوافق مع الروابط (URL) لجافاسكربت.\n\n> \"مستوى مذهل من الكمالية التي لا معنى لها،\n> والتي يستحيل ألّا تحظى بالاحترام.\"\n\n* **صغير الحجم.** 118 بايت فقط (بعد التصغير والضغط ببروتلي). بدون أيّ اعتماديات خارجية.\n  يتم التحكّم بالحجم عبر [Size Limit].\n* **آمن.** يستخدم مُولِّد أرقام عشوائية على مستوى العتاد. يمكن استخدامه في بيئات الكلستر.\n* **مُعرِّفات قصيرة.** يستخدم أبجدية أكبر من UUID وهي (`A-Za-z0-9_-`).\n  لذا تم تقليص حجم المُعرِّف من 36 إلى 21 رمزًا.\n* **قابل للنقل.** تم نقل Nano ID\n  إلى أكثر من [20 لغة برمجة](./README.md#other-programming-languages).\n\n</div>\n\n```js\nimport { nanoid } from 'nanoid'\nmodel.id = nanoid() //=> \"V1StGXR8_Z5jdHi6B-myT\"\n```\n\n---\n\n<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>.\n\n---\n\n[online tool]: https://gitpod.io/#https://github.com/ai/nanoid/\n[with Babel]:  https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/\n[Size Limit]:  https://github.com/ai/size-limit\n\n\n<div dir=\"rtl\">\n\n## جدول المحتويات\n\n- [جدول المحتويات](#جدول-المحتويات)\n- [المقارنة مع UUID](#المقارنة-مع-uuid)\n- [اختبار الأداء](#اختبار-الأداء)\n- [الأمان](#الأمان)\n- [التثبيت](#التثبيت)\n  - [ESM](#esm)\n  - [CommonJS](#commonjs)\n  - [JSR](#jsr)\n  - [CDN](#cdn)\n- [واجهة البرمجة (API)](#واجهة-البرمجة-api)\n  - [متزامن (Blocking)](#متزامن-blocking)\n  - [غير آمن (Non-Secure)](#غير-آمن-non-secure)\n  - [أبجدية أو حجم مخصّص](#أبجدية-أو-حجم-مخصّص)\n  - [مُولِّد بايتات عشوائية مخصّص](#مُولِّد-بايتات-عشوائية-مخصّص)\n- [الاستخدام](#الاستخدام)\n  - [React](#react)\n  - [React Native](#react-native)\n  - [PouchDB و CouchDB](#pouchdb-و-couchdb)\n  - [سطر الأوامر (CLI)](#سطر-الأوامر-cli)\n  - [TypeScript](#typescript)\n  - [لغات البرمجة الأخرى](#لغات-البرمجة-الأخرى)\n- [الأدوات](#الأدوات)\n\n\n## المقارنة مع UUID\n\nNano ID قابل للمقارنة مع UUID v4 (المبني على العشوائية).\nيحتوي على عدد مماثل من البتّات العشوائية في المُعرِّف\n(126 في Nano ID و122 في UUID)، لذا فإنّ احتمالية التكرار متقاربة:\n\n> لكي تكون هناك فرصة واحدة من مليار لحدوث تكرار،\n> يجب توليد 103 تريليون مُعرِّف من النوع v4.\n\nيوجد اختلافان رئيسيان بين Nano ID و UUID v4:\n\n1. يستخدم Nano ID أبجدية أكبر، لذا يتم ضغط عدد مماثل من البتّات العشوائية\n   في 21 رمزًا فقط بدلاً من 36.\n2. كود Nano ID أصغر بـ **4 مرات** من حزمة `uuid/v4`:\n   118 بايت مقابل 423.\n\n\n## اختبار الأداء\n\n</div>\n\n```rust\n$ node ./test/benchmark.js\ncrypto.randomUUID          7,619,041 ops/sec\nuuid v4                    7,436,626 ops/sec\n@napi-rs/uuid              4,730,614 ops/sec\nuid/secure                 4,729,185 ops/sec\n@lukeed/uuid               4,015,673 ops/sec\nnanoid                     3,693,964 ops/sec\ncustomAlphabet             2,799,255 ops/sec\nnanoid for browser           380,915 ops/sec\nsecure-random-string         362,316 ops/sec\nuid-safe.sync                354,234 ops/sec\nshortid                       38,808 ops/sec\n\nNon-secure:\nuid                       11,872,105 ops/sec\nnanoid/non-secure          2,226,483 ops/sec\nrndm                       2,308,044 ops/sec\n```\n\n<div dir=\"rtl\">\n\nبيئة الاختبار: Framework 13 7840U، فيدورا 39، Node.js 21.6.\n\n\n## الأمان\n\n*اقرأ مقالاً جيداً عن نظرية مُولِّدات الأرقام العشوائية:\n[Secure random values (in Node.js)]*\n\n* **عدم القابلية للتنبؤ.** بدلاً من استخدام `Math.random()` غير الآمن، يستخدم Nano ID\n  وحدة `crypto` في Node.js و Web Crypto API في المتصفحات.\n  هذه الوحدات تستخدم مُولِّد أرقام عشوائية على مستوى العتاد لا يمكن التنبؤ به.\n* **التوزيع المنتظم.** `random % alphabet` هو خطأ شائع عند برمجة مُولِّد مُعرِّفات.\n  التوزيع لن يكون متساويًا؛ بعض الرموز ستظهر بتواتر أقل من غيرها.\n  وهذا يقلّل عدد المحاولات اللازمة للكسر بالقوة الغاشمة. يستخدم Nano ID\n  [خوارزمية أفضل] وقد تم اختباره للتحقّق من انتظام التوزيع.\n\n  <img src=\"img/distribution.png\" alt=\"انتظام توزيع Nano ID\"\n     width=\"340\" height=\"135\">\n\n* **موثّق جيداً:** جميع الحيل البرمجية في Nano ID موثّقة. اطّلع على التعليقات\n  في [الكود المصدري].\n* **الثغرات الأمنية:** للإبلاغ عن ثغرة أمنية، يُرجى استخدام\n  [جهة اتصال Tidelift الأمنية](https://tidelift.com/security).\n  سيقوم Tidelift بتنسيق الإصلاح والإفصاح.\n\n[Secure random values (in Node.js)]: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba\n[خوارزمية أفضل]:                  https://github.com/ai/nanoid/blob/main/index.js\n[الكود المصدري]:                        https://github.com/ai/nanoid/blob/main/index.js\n\n\n## التثبيت\n\n### ESM\n\nيعمل Nano ID 5 مع مشاريع ESM (باستخدام `import`) في الاختبارات أو سكربتات Node.js.\n\n</div>\n\n```bash\nnpm install nanoid\n```\n\n<div dir=\"rtl\">\n\n### CommonJS\n\nيمكن استخدام Nano ID مع CommonJS بإحدى الطرق التالية:\n\n- يمكنك استخدام `require()` لاستيراد Nano ID. تحتاج إلى استخدام أحدث إصدار من\n  Node.js 22.12 (يعمل مباشرة) أو Node.js 20\n  (مع علامة `--experimental-require-module`).\n\n- لـ Node.js 18 يمكنك استيراد Nano ID ديناميكيًا كالتالي:\n\n</div>\n\n  ```js\n  let nanoid\n  module.exports.createID = async () => {\n    if (!nanoid) ({ nanoid } = await import('nanoid'))\n    return nanoid() // => \"V1StGXR8_Z5jdHi6B-myT\"\n  }\n  ```\n\n<div dir=\"rtl\">\n\n- يمكنك استخدام Nano ID 3.x (ما زلنا ندعمه):\n\n</div>\n\n  ```bash\n  npm install nanoid@3\n  ```\n\n<div dir=\"rtl\">\n\n### JSR\n\n[JSR](https://jsr.io) هو بديل لـ npm بحوكمة مفتوحة\nوتطوير نشط (على عكس npm).\n\n</div>\n\n```bash\nnpx jsr add @sitnik/nanoid\n```\n\n<div dir=\"rtl\">\n\nيمكنك استخدامه في Node.js و Deno و Bun وغيرها.\n\n</div>\n\n```js\n// استبدل `nanoid` بـ `@sitnik/nanoid` في جميع الاستيرادات\nimport { nanoid } from '@sitnik/nanoid'\n```\n\n<div dir=\"rtl\">\n\nلـ Deno ثبّته عبر `deno add jsr:@sitnik/nanoid` أو استورده\nمن `jsr:@sitnik/nanoid`.\n\n\n### CDN\n\nللتجارب السريعة، يمكنك تحميل Nano ID من CDN. لكن لا يُنصح باستخدامه\nفي الإنتاج بسبب انخفاض أداء التحميل.\n\n</div>\n\n```js\nimport { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'\n```\n\n<div dir=\"rtl\">\n\n## واجهة البرمجة (API)\n\nيمتلك Nano ID واجهتي برمجة: عادية وغير آمنة.\n\nبشكل افتراضي، يستخدم Nano ID رموزًا متوافقة مع الروابط (`A-Za-z0-9_-`) ويُنتج مُعرِّفًا\nمكوّنًا من 21 حرفًا (ليكون احتمال التكرار مماثلاً لـ UUID v4).\n\n\n### متزامن (Blocking)\n\nالطريقة الأسهل والأكثر أمانًا لاستخدام Nano ID.\n\nفي حالات نادرة قد يحجب المعالج عن العمليات الأخرى أثناء جمع الضوضاء\nلمُولِّد الأرقام العشوائية على مستوى العتاد.\n\n</div>\n\n```js\nimport { nanoid } from 'nanoid'\nmodel.id = nanoid() //=> \"V1StGXR8_Z5jdHi6B-myT\"\n```\n\n<div dir=\"rtl\">\n\nإذا أردت تقليل حجم المُعرِّف (وزيادة احتمالية التكرار)،\nيمكنك تمرير الحجم كمعامل.\n\n</div>\n\n```js\nnanoid(10) //=> \"IRFa-VaY2b\"\n```\n\n<div dir=\"rtl\">\n\nلا تنسَ التحقّق من أمان حجم المُعرِّف الخاص بك\nعبر حاسبة [احتمالية تكرار المُعرِّف].\n\nيمكنك أيضًا استخدام [أبجدية مخصّصة](#أبجدية-أو-حجم-مخصّص)\nأو [مُولِّد أرقام عشوائية مخصّص](#مُولِّد-بايتات-عشوائية-مخصّص).\n\n[احتمالية تكرار المُعرِّف]: https://zelark.github.io/nano-id-cc/\n\n\n### غير آمن (Non-Secure)\n\nبشكل افتراضي، يستخدم Nano ID توليد بايتات عشوائية على مستوى العتاد\nمن أجل الأمان وتقليل احتمالية التكرار. إذا لم يكن الأمان مهمًا بالنسبة لك،\nيمكنك استخدامه في بيئات لا تتوفر فيها مُولِّدات أرقام عشوائية على مستوى العتاد.\n\n</div>\n\n```js\nimport { nanoid } from 'nanoid/non-secure'\nconst id = nanoid() //=> \"Uakgb_J5m9g-0JDMbcJqLJ\"\n```\n\n<div dir=\"rtl\">\n\n### أبجدية أو حجم مخصّص\n\nتُرجع `customAlphabet` دالة تتيح لك إنشاء `nanoid`\nبأبجديتك وحجمك الخاصّين.\n\n</div>\n\n```js\nimport { customAlphabet } from 'nanoid'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nmodel.id = nanoid() //=> \"4f90d13a42\"\n```\n\n```js\nimport { customAlphabet } from 'nanoid/non-secure'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nuser.id = nanoid()\n```\n\n<div dir=\"rtl\">\n\nتحقّق من أمان أبجديتك المخصّصة وحجم المُعرِّف عبر\nحاسبة [احتمالية تكرار المُعرِّف]. لمزيد من خيارات الأبجديات، اطّلع على\n[`nanoid-dictionary`].\n\nيجب أن تحتوي الأبجدية على 256 رمزًا أو أقل.\nوإلا فإن أمان خوارزمية المُولِّد الداخلية غير مضمون.\n\nبالإضافة إلى تحديد حجم افتراضي، يمكنك تغيير حجم المُعرِّف عند استدعاء\nالدالة:\n\n</div>\n\n```js\nimport { customAlphabet } from 'nanoid'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nmodel.id = nanoid(5) //=> \"f01a2\"\n```\n\n[احتمالية تكرار المُعرِّف]: https://zelark.github.io/nano-id-cc/\n[`nanoid-dictionary`]:      https://github.com/CyberAP/nanoid-dictionary\n\n<div dir=\"rtl\">\n\n### مُولِّد بايتات عشوائية مخصّص\n\nتتيح لك `customRandom` إنشاء `nanoid` واستبدال الأبجدية\nومُولِّد البايتات العشوائية الافتراضي.\n\nفي هذا المثال، يتم استخدام مُولِّد مبني على بذرة (seed):\n\n</div>\n\n```js\nimport { customRandom } from 'nanoid'\n\nconst rng = seedrandom(seed)\nconst nanoid = customRandom('abcdef', 10, size => {\n  return (new Uint8Array(size)).map(() => 256 * rng())\n})\n\nnanoid() //=> \"fbaefaadeb\"\n```\n\n<div dir=\"rtl\">\n\nيجب أن تقبل دالة `random` حجم المصفوفة وتُرجع مصفوفة\nمن الأرقام العشوائية.\n\nإذا أردت استخدام نفس الرموز المتوافقة مع الروابط مع `customRandom`،\nيمكنك الحصول على الأبجدية الافتراضية عبر `urlAlphabet`.\n\n</div>\n\n```js\nconst { customRandom, urlAlphabet } = require('nanoid')\nconst nanoid = customRandom(urlAlphabet, 10, random)\n```\n\n<div dir=\"rtl\">\n\nملاحظة: بين إصدارات Nano ID قد يتغيّر تسلسل استدعاء مُولِّد الأرقام العشوائية.\nإذا كنت تستخدم مُولِّدات مبنية على بذرة، فإننا لا نضمن نفس النتيجة.\n\n\n## الاستخدام\n\n### React\n\nلا توجد طريقة صحيحة لاستخدام Nano ID كخاصية `key` في React\nلأنها يجب أن تكون ثابتة بين عمليات التصيير (renders).\n\n</div>\n\n```jsx\nfunction Todos({todos}) {\n  return (\n    <ul>\n      {todos.map(todo => (\n        <li key={nanoid()}> /* لا تفعل هذا */\n          {todo.text}\n        </li>\n      ))}\n    </ul>\n  )\n}\n```\n\n<div dir=\"rtl\">\n\nيجب عليك بدلاً من ذلك استخدام مُعرِّف ثابت من داخل عنصر القائمة.\n\n</div>\n\n```jsx\nconst todoItems = todos.map((todo) =>\n  <li key={todo.id}>\n    {todo.text}\n  </li>\n)\n```\n\n<div dir=\"rtl\">\n\nفي حال لم تمتلك مُعرِّفات ثابتة، يُفضّل استخدام الفهرس (index)\nكـ `key` بدلاً من `nanoid()`:\n\n</div>\n\n```jsx\nconst todoItems = todos.map((text, index) =>\n  <li key={index}> /* غير مُوصى به لكنه أفضل من nanoid().\n                      استخدمه فقط إذا لم تكن لديك مُعرِّفات ثابتة. */\n    {text}\n  </li>\n)\n```\n\n<div dir=\"rtl\">\n\nإذا كنت تحتاج فقط إلى مُعرِّفات عشوائية لربط العناصر ببعضها مثل\nlabels وحقول الإدخال، يُنصح باستخدام [`useId`].\nتمت إضافة هذا الـ hook في React 18.\n\n[`useId`]: https://react.dev/reference/react/useId\n\n\n### React Native\n\nلا يحتوي React Native على مُولِّد أرقام عشوائية مدمج. يعمل البوليفِل التالي\nمع React Native العادي و Expo بدءًا من الإصدار `39.x`.\n\n1. اطّلع على توثيق [`react-native-get-random-values`] وثبّتها.\n2. استوردها قبل Nano ID.\n\n</div>\n\n```js\nimport 'react-native-get-random-values'\nimport { nanoid } from 'nanoid'\n```\n\n[`react-native-get-random-values`]: https://github.com/LinusU/react-native-get-random-values\n\n<div dir=\"rtl\">\n\n### PouchDB و CouchDB\n\nفي PouchDB و CouchDB، لا يمكن أن تبدأ المُعرِّفات بشرطة سفلية `_`.\nيلزم إضافة بادئة لتجنّب هذه المشكلة، لأن Nano ID قد يستخدم `_`\nفي بداية المُعرِّف بشكل افتراضي.\n\nأَعِد تعريف المُعرِّف الافتراضي بالخيار التالي:\n\n</div>\n\n```js\ndb.put({\n  _id: 'id' + nanoid(),\n  …\n})\n```\n\n<div dir=\"rtl\">\n\n### سطر الأوامر (CLI)\n\nيمكنك الحصول على مُعرِّف فريد في الطرفية عبر تشغيل `npx nanoid`. تحتاج فقط\nإلى Node.js مثبّتًا على النظام. لا يلزم تثبيت Nano ID مسبقًا.\n\n</div>\n\n```sh\n$ npx nanoid\nnpx: installed 1 in 0.63s\nLZfXLFzPPR4NNrgjlWDxn\n```\n\n<div dir=\"rtl\">\n\nيمكن تحديد حجم المُعرِّف المُولَّد عبر خيار `--size` (أو `-s`):\n\n</div>\n\n```sh\n$ npx nanoid --size 10\nL3til0JS4z\n```\n\n<div dir=\"rtl\">\n\nيمكن تحديد أبجدية مخصّصة عبر خيار `--alphabet` (أو `-a`)\n(لاحظ أن `--size` مطلوب في هذه الحالة):\n\n</div>\n\n```sh\n$ npx nanoid --alphabet abc --size 15\nbccbcabaabaccab\n```\n\n<div dir=\"rtl\">\n\n### TypeScript\n\nيتيح Nano ID تحويل النصوص المُولَّدة إلى أنواع مبهمة (opaque types) في TypeScript.\nمثال:\n\n</div>\n\n```ts\ndeclare const userIdBrand: unique symbol\ntype UserId = string & { [userIdBrand]: true }\n\n// استخدم معامل النوع الصريح:\nmockUser(nanoid<UserId>())\n\ninterface User {\n  id: UserId\n  name: string\n}\n\nconst user: User = {\n  // يتم التحويل تلقائيًا إلى UserId:\n  id: nanoid(),\n  name: 'Alice'\n}\n```\n\n<div dir=\"rtl\">\n\n### لغات البرمجة الأخرى\n\nتم نقل Nano ID إلى العديد من اللغات. يمكنك استخدام هذه الإصدارات للحصول\nعلى نفس مُولِّد المُعرِّفات على جانبَي العميل والخادم.\n\n</div>\n\n* [C](https://github.com/lukateras/nanoid.h)\n* [C#](https://github.com/codeyu/nanoid-net)\n* [C++](https://github.com/mcmikecreations/nanoid_cpp)\n* [Clojure and ClojureScript](https://github.com/zelark/nano-id)\n* [ColdFusion/CFML](https://github.com/JamoCA/cfml-nanoid)\n* [Crystal](https://github.com/mamantoha/nanoid.cr)\n* [Dart & Flutter](https://github.com/pd4d10/nanoid-dart)\n* [Elixir](https://github.com/railsmechanic/nanoid)\n* [Gleam](https://github.com/0xca551e/glanoid)\n* [Go](https://github.com/matoous/go-nanoid)\n* [Haskell](https://github.com/MichelBoucey/NanoID)\n* [Haxe](https://github.com/flashultra/uuid)\n* [Janet](https://sr.ht/~statianzo/janet-nanoid/)\n* [Java](https://github.com/wosherco/jnanoid-enhanced)\n* [Kotlin](https://github.com/viascom/nanoid-kotlin)\n* [MySQL/MariaDB](https://github.com/viascom/nanoid-mysql-mariadb)\n* [Nim](https://github.com/icyphox/nanoid.nim)\n* [OCaml](https://github.com/routineco/ocaml-nanoid)\n* [Perl](https://github.com/tkzwtks/Nanoid-perl)\n* [PHP](https://github.com/hidehalo/nanoid-php)\n* Python [native](https://github.com/puyuan/py-nanoid) implementation\n  with [dictionaries](https://pypi.org/project/nanoid-dictionary)\n  and [fast](https://github.com/oliverlambson/fastnanoid) implementation (written in Rust)\n* Postgres [Extension](https://github.com/spa5k/uids-postgres)\n  and [Native Function](https://github.com/viascom/nanoid-postgres)\n* [R](https://github.com/hrbrmstr/nanoid) (with dictionaries)\n* [Ruby](https://github.com/radeno/nanoid.rb)\n* [Rust](https://github.com/nikolay-govorov/nanoid)\n* [Swift](https://github.com/ShivaHuang/swift-nanoid)\n* [Unison](https://share.unison-lang.org/latest/namespaces/hojberg/nanoid)\n* [V](https://github.com/invipal/nanoid)\n* [Zig](https://github.com/SasLuca/zig-nanoid)\n\n<div dir=\"rtl\">\n\nللبيئات الأخرى، يتوفر [سطر الأوامر] لتوليد المُعرِّفات من الطرفية.\n\n[سطر الأوامر]: #سطر-الأوامر-cli\n\n\n## الأدوات\n\n* [حاسبة حجم المُعرِّف] تعرض احتمالية التكرار عند تعديل\n  أبجدية المُعرِّف أو حجمه.\n* [`nanoid-dictionary`] تحتوي على أبجديات شائعة لاستخدامها مع [`customAlphabet`].\n* [`nanoid-good`] للتأكد من أن المُعرِّف لا يحتوي على كلمات غير لائقة.\n\n[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary\n[حاسبة حجم المُعرِّف]:  https://zelark.github.io/nano-id-cc/\n[`customAlphabet`]:    #أبجدية-أو-حجم-مخصّص\n[`nanoid-good`]:       https://github.com/y-gagar1n/nanoid-good\n\n</div>\n"
  },
  {
    "path": "README.id-ID.md",
    "content": "# Nano ID\n\n<img src=\"https://ai.github.io/nanoid/logo.svg\" align=\"right\"\n     alt=\"Logo Nano ID oleh Anton Lovchikov\" width=\"180\" height=\"94\">\n\n[English](./README.md) | [日本語](./README.ja.md) | [Русский](./README.ru.md) | [简体中文](./README.zh-CN.md) | **Bahasa Indonesia** | [한국어](./README.ko.md) | [العربية](./README.ar.md)\n\nSebuah generator ID yang unik dalam bentuk string yang ringan, aman, serta _URL-friendly_ untuk JavaScript.\n\n> \"Sebuah tingkat kesempurnaan yang luar biasa,\n> yang mana tidak mungkin untuk tidak dihormati.\"\n\n- **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.\n- **Aman.** Nano ID menggunakan RNG yang terdapat pada perangkat keras. Dapat digunakan dalam lingkungan seperti klaster.\n- **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.\n- **Portabel.** Nano ID telah dimigrasi untuk [20 bahasa pemrograman lainnya](#bahasa-pemrograman-lainnya).\n\n```js\nimport { nanoid } from 'nanoid'\nmodel.id = nanoid() //=> \"V1StGXR8_Z5jdHi6B-myT\"\n```\n\nMendukung 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.\n\n---\n\n<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>.\n\n---\n\n\n## Table of Contents\n\n- [Table of Contents](#table-of-contents)\n- [Perbandingan dengan UUID](#perbandingan-dengan-uuid)\n- [Benchmark](#benchmark)\n- [Keamanan](#keamanan)\n- [Instalasi](#instalasi)\n- [API](#api)\n  - [Blocking](#blocking)\n  - [Non-Secure](#non-secure)\n  - [Alfabet dan Ukuran (Custom)](#alfabet-dan-ukuran-custom)\n  - [Generasi Random Bytes (Custom)](#generasi-random-bytes-custom)\n- [Penggunaan](#penggunaan)\n  - [React](#react)\n  - [React Native](#react-native)\n  - [PouchDB dan CouchDB](#pouchdb-dan-couchdb)\n  - [CLI](#cli)\n  - [TypeScript](#typescript)\n  - [Bahasa Pemrograman Lainnya](#bahasa-pemrograman-lainnya)\n- [Alat](#alat)\n\n\n## Perbandingan dengan UUID\n\nNano 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:\n\n> Agar timbul kemungkinan collison / duplikasi ID satu dalam satu miliar, perlu dihasilkan 103 triliun UUID v4.\n\nAda dua buah perbedaan antara Nano ID dan UUID v4:\n\n1. Nano ID menggunakan alfabet yang lebih lebar, karenanya jumlah bita acak dapat 'dikemas' dalam 21 simbol, bukan 36 simbol.\n2. Kode sumber Nano ID **empat kali lebih kecil** ketimbang `uuid/v4`: 118 bytes dibanding 423 bytes.\n\n\n## Benchmark\n\n```rust\n$ node ./test/benchmark.js\ncrypto.randomUUID          7,619,041 ops/sec\nuuid v4                    7,436,626 ops/sec\n@napi-rs/uuid              4,730,614 ops/sec\nuid/secure                 4,729,185 ops/sec\n@lukeed/uuid               4,015,673 ops/sec\nnanoid                     3,693,964 ops/sec\ncustomAlphabet             2,799,255 ops/sec\nnanoid for browser           380,915 ops/sec\nsecure-random-string         362,316 ops/sec\nuid-safe.sync                354,234 ops/sec\nshortid                       38,808 ops/sec\n\nNon-secure:\nuid                       11,872,105 ops/sec\nnanoid/non-secure          2,226,483 ops/sec\nrndm                       2,308,044 ops/sec\n```\n\nKonfigurasi pengujian: Framework 13 7840U, Fedora 39, Node.js 21.6.\n\n\n## Keamanan\n\n_Lihat artikel yang informatif tentang teori angka acak: [Nilai acak yang aman dalam Node.js (English)](https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba)_.\n\n- **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.\n\n- **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.\n\n  <img src=\"img/distribution.png\" alt=\"Nano ID uniformity\"\n    width=\"340\" height=\"135\">\n\n- **Terdokumentasi secara baik.** Seluruh algoritma Nano ID sudah terdokumentasi. Lihat komentar di [kode sumber](https://github.com/ai/nanoid/blob/main/index.js).\n\n- **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.\n\n\n## Instalasi\n\n```bash\nnpm install nanoid\n```\n\nNano ID 5 hanya tersedia untuk proyek, pengujian, atau skrip ESM Node.js.\nUntuk CommonJS Anda memerlukan Nano ID 3.x (kami masih mendukungnya):\n\n```bash\nnpm install nanoid@3\n```\n\nApabila 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.\n\n```js\nimport { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'\n```\n\n\n## API\n\nNano ID memiliki dua API: normal dan _non-secure_.\n\nBawaannya, 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).\n\n\n### Blocking\n\nPenggunaan Nano ID yang aman dan yang paling mudah.\n\nDalam 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).\n\n```js\nimport { nanoid } from 'nanoid'\nmodel.id = nanoid() //=> \"V1StGXR8_Z5jdHi6B-myT\"\n```\n\nApabila ingin mengurangi ukuran ID (dan meningkatkan probabilitas collision), dapat dimasukkan `size` sebagai argumen dari fungsi `nanoid()`.\n\n```js\nnanoid(10) //=> \"IRFa-VaY2b\"\n```\n\nJangan lupa memeriksa tingkat keamanan dari ukuran ID dalam situs [ID collision probability calculator](https://zelark.github.io/nano-id-cc/).\n\nDapat digunakan pula [custom alphabet](#custom-alphabet-or-size) atau [random generator](#custom-random-bytes-generator) yang lain.\n\n\n### Non-Secure\n\nKonfigurasi 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.\n\n```js\nimport { nanoid } from 'nanoid/non-secure'\nconst id = nanoid() //=> \"Uakgb_J5m9g-0JDMbcJqLJ\"\n```\n\n\n### Alfabet dan Ukuran (Custom)\n\n`customAlphabet` digunakan untuk membuat Nano ID dengan alfabet dan ukuran ID yang sesuai dengan kebutuhan (dapat dikustomisasi).\n\n```js\nimport { customAlphabet } from 'nanoid'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nmodel.id = nanoid() //=> \"4f90d13a42\"\n```\n\nKetika 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).\n\nAlfabet harus terbentuk dari 256 simbol atau lebih kecil. Selain itu, keamanan algoritma generasi yang berada di dalam library ini tidak dijamin aman.\n\nAPI non-secure yang dapat dikustomisasi dengan `customAlphabet` pun tersedia disini:\n\n```js\nimport { customAlphabet } from 'nanoid/non-secure'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nuser.id = nanoid()\n```\n\n\n### Generasi Random Bytes (Custom)\n\n`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).\n\nPada contoh berikut, digunakan _seed-based generator_:\n\n```js\nimport { customRandom } from 'nanoid'\n\nconst rng = seedrandom(seed)\nconst nanoid = customRandom('abcdef', 10, size => {\n  return new Uint8Array(size).map(() => 256 * rng())\n})\n\nnanoid() //=> \"fbaefaadeb\"\n```\n\nFungsi _callback_ pada `random` harus menerima ukuran array dan mengembalikan sebuah array dengan angka acak.\n\nApabila ingin menggunakan alfabet bawaan NanoID pada fungsi `customRandom`, dapat menggunakan konstanta `urlAlphabet` seperti berikut:\n\n```js\nconst { customRandom, urlAlphabet } = require('nanoid')\nconst nanoid = customRandom(urlAlphabet, 10, random)\n```\n\nAPI asinkronus dan non-secure tidak tersedia untuk fungsi `customRandom`.\n\n\n## Penggunaan\n\n### React\n\nDalam 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.\n\n```jsx\nfunction Todos({ todos }) {\n  return (\n    <ul>\n      {todos.map(todo => (\n        /* JANGAN DILAKUKAN! */\n        <li key={nanoid()}>{todo.text}</li>\n      ))}\n    </ul>\n  )\n}\n```\n\nKarena hal tersebut, disarankan untuk menggunakan ID yang stabil pada setiap objek yang di-render oleh React.\n\n```jsx\nconst todoItems = todos.map(todo => <li key={todo.id}>{todo.text}</li>)\n```\n\nApabila 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:\n\n```jsx\nconst todoItems = todos.map((text, index) => (\n  /* Tetap tidak direkomendasikan, tetapi lebih disarankan dari 'nanoid()'. Lakukan ini\n    apabila setiap objek / item dalam list tidak ada ID yang stabil. */\n  <li key={index}>{text}</li>\n))\n```\n\n### React Native\n\nReact Native tidak memiliki _built-in random generator_. Digunakan polyfill seperti berikut yang berjalan untuk React Native dan Expo yang bermula dari versi `39.x`.\n\n1. Periksa dokumentasi [`react-native-get-random-values`](https://github.com/LinusU/react-native-get-random-values) dan install di aplikasi.\n2. Import library tersebut sebelum Nano ID.\n\n```js\nimport 'react-native-get-random-values'\nimport { nanoid } from 'nanoid'\n```\n\n### PouchDB dan CouchDB\n\nDalam 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.\n\nID bawaan dapat diubah dengan opsi berikut:\n\n```js\ndb.put({\n  _id: 'id' + nanoid(),\n  …\n})\n```\n\n\n### CLI\n\nNano 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.\n\n```sh\n$ npx nanoid\nnpx: installed 1 in 0.63s\nLZfXLFzPPR4NNrgjlWDxn\n```\n\nBila ingin mengganti alfabet atau ukuran ID, dapat menggunakan [`nanoid-cli`](https://github.com/twhitbeck/nanoid-cli).\n\n### TypeScript\n\nNano ID memungkinkan untuk mengubah string yang dihasilkan menjadi string opak\ndalam TypeScript. Sebagai contoh:\n\n```ts\ndeclare const userIdBrand: unique symbol\ntype UserId = string & { [userIdBrand]: true }\n\n// Gunakan parameter tipe secara eksplisit:\nmockUser(nanoid<UserId>())\n\ninterface User {\n  id: UserId\n  name: string\n}\n\nconst user: User = {\n  // Secara otomatis diubah menjadi UserId:\n  id: nanoid(),\n  name: 'Alice'\n}\n```\n\n### Bahasa Pemrograman Lainnya\n\nNano 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_).\n\n- [C#](https://github.com/codeyu/nanoid-net)\n- [C++](https://github.com/mcmikecreations/nanoid_cpp)\n- [Clojure and ClojureScript](https://github.com/zelark/nano-id)\n- [ColdFusion/CFML](https://github.com/JamoCA/cfml-nanoid)\n- [Crystal](https://github.com/mamantoha/nanoid.cr)\n- [Dart & Flutter](https://github.com/pd4d10/nanoid-dart)\n- [Deno](https://github.com/ianfabs/nanoid)\n- [Elixir](https://github.com/railsmechanic/nanoid)\n- [Gleam](https://github.com/0xca551e/glanoid)\n- [Go](https://github.com/jaevor/go-nanoid)\n- [Haskell](https://github.com/MichelBoucey/NanoID)\n- [Haxe](https://github.com/flashultra/uuid)\n- [Janet](https://sr.ht/~statianzo/janet-nanoid/)\n- [Java](https://github.com/wosherco/jnanoid-enhanced)\n- [Kotlin](https://github.com/viascom/nanoid-kotlin)\n- [MySQL/MariaDB](https://github.com/viascom/nanoid-mysql-mariadb)\n- [Nim](https://github.com/icyphox/nanoid.nim)\n- [OCaml](https://github.com/routineco/ocaml-nanoid)\n- [Perl](https://github.com/tkzwtks/Nanoid-perl)\n- [PHP](https://github.com/hidehalo/nanoid-php)\n- [Python](https://github.com/puyuan/py-nanoid) with [dictionaries](https://pypi.org/project/nanoid-dictionary)\n- [Postgres Extension](https://github.com/spa5k/uids-postgres)\n- [Postgres Native Function](https://github.com/viascom/nanoid-postgres)\n- [R](https://github.com/hrbrmstr/nanoid) (with dictionaries)\n- [Ruby](https://github.com/radeno/nanoid.rb)\n- [Rust](https://github.com/nikolay-govorov/nanoid)\n- [Swift](https://github.com/ShivaHuang/swift-nanoid)\n- [Unison](https://share.unison-lang.org/latest/namespaces/hojberg/nanoid)\n- [V](https://github.com/invipal/nanoid)\n- [Zig](https://github.com/SasLuca/zig-nanoid)\n\nUntuk environment lainnya, [CLI](#cli) tersedia untuk melakukan generasi ID dari command line / Terminal.\n\n\n## Alat\n\n- [ID Size Calculator](https://zelark.github.io/nano-id-cc/) menunjukkan probabilitas collision ketika melakukan konfigurasi alfabet dan ukuran.\n- [`nanoid-dictionary`](https://github.com/CyberAP/nanoid-dictionary) untuk menggunakan alfabet popular dalam fungsi [`customAlphabet`](#custom-alphabet-or-size)\n- [`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.).\n"
  },
  {
    "path": "README.ja.md",
    "content": "# Nano ID\n\n<img src=\"https://ai.github.io/nanoid/logo.svg\" align=\"right\"\n     alt=\"Nano ID logo by Anton Lovchikov\" width=\"180\" height=\"94\">\n\n[English](./README.md) | **日本語** | [Русский](./README.ru.md) | [简体中文](./README.zh-CN.md) | [Bahasa Indonesia](./README.id-ID.md) | [한국어](./README.ko.md) | [العربية](./README.ar.md)\n\nJavaScriptのための小さく、安全で、URL友好的なユニークな文字列ID生成器。\n\n> 「意味不明なレベルの完璧主義、\n> これは尊敬せざるを得ない。」\n\n* **小さい。** 118バイト（圧縮・brotli圧縮後）。依存関係なし。\n  [Size Limit]がサイズを管理。\n* **安全。** ハードウェア乱数生成器を使用。クラスタでも利用可能。\n* **短いID。** UUIDより大きなアルファベット（A-Za-z0-9_-）を使用。\n  そのためID長は36から21文字に短縮されています。\n* **移植性。** Nano IDは[20以上のプログラミング言語](./README.md#other-programming-languages)に移植されています。\n\n```js\nimport { nanoid } from 'nanoid'\nmodel.id = nanoid() //=> \"V1StGXR8_Z5jdHi6B-myT\"\n```\n\n---\n\n<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>.\n\n---\n\n[online tool]: https://gitpod.io/#https://github.com/ai/nanoid/\n[with Babel]:  https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/\n[Size Limit]:  https://github.com/ai/size-limit\n\n\n## 目次\n\n- [目次](#目次)\n- [UUIDとの比較](#uuidとの比較)\n- [ベンチマーク](#ベンチマーク)\n- [セキュリティ](#セキュリティ)\n- [インストール](#インストール)\n  - [ESM](#esm)\n  - [CommonJS](#commonjs)\n  - [JSR](#jsr)\n  - [CDN](#cdn)\n- [API](#api)\n  - [ブロッキング](#ブロッキング)\n  - [非セキュア](#非セキュア)\n  - [カスタムアルファベットまたはサイズ](#カスタムアルファベットまたはサイズ)\n  - [カスタムランダムバイト生成器](#カスタムランダムバイト生成器)\n- [使用方法](#使用方法)\n  - [React](#react)\n  - [React Native](#react-native)\n  - [PouchDBとCouchDB](#pouchdbとcouchdb)\n  - [CLI](#cli)\n  - [TypeScript](#typescript)\n  - [その他のプログラミング言語](#その他のプログラミング言語)\n- [ツール](#ツール)\n\n\n## UUIDとの比較\n\nNano IDはUUID v4（ランダムベース）と十分に比較可能です。\nID内のランダムビット数は同様です（Nano IDで126ビット、UUIDで122ビット）、\nそのため衝突確率も同様です：\n\n> 10億分の1の確率で重複が発生するには、\n> 103兆個のバージョン4 IDを生成する必要があります。\n\nNano IDとUUID v4の主な違いは2つあります：\n\n1. Nano IDはより大きなアルファベットを使用するため、同様のランダムビット数が\n   36文字ではなく21文字に詰め込まれています。\n2. Nano IDのコードはuuid/v4パッケージより**4倍小さい**です：\n   423バイトではなく118バイトです。\n\n\n## ベンチマーク\n\n```rust\n$ node ./test/benchmark.js\ncrypto.randomUUID          7,619,041 ops/sec\nuuid v4                    7,436,626 ops/sec\n@napi-rs/uuid              4,730,614 ops/sec\nuid/secure                 4,729,185 ops/sec\n@lukeed/uuid               4,015,673 ops/sec\nnanoid                     3,693,964 ops/sec\ncustomAlphabet             2,799,255 ops/sec\nnanoid for browser           380,915 ops/sec\nsecure-random-string         362,316 ops/sec\nuid-safe.sync                354,234 ops/sec\nshortid                       38,808 ops/sec\n\nNon-secure:\nuid                       11,872,105 ops/sec\nnanoid/non-secure          2,226,483 ops/sec\nrndm                       2,308,044 ops/sec\n```\n\nテスト構成：Framework 13 7840U, Fedora 39, Node.js 21.6.\n\n\n## セキュリティ\n\n*乱数生成器の理論に関する良い記事を参照してください：\n[Secure random values (in Node.js)]*\n\n* **予測不可能性。** 安全でないMath.random()を使う代わりに、Nano IDは\n  Node.jsではcryptoモジュールを、ブラウザではWeb Crypto APIを使用します。\n  これらのモジュールは予測不可能なハードウェア乱数生成器を使用します。\n* **均一性。** random % alphabetはID生成器をコーディングする際によくある間違いです。\n  分布は均一ではなく、一部の記号が他のものより出現確率が低くなります。\n  そのため、総当たり攻撃の際に試行回数が減少します。Nano IDは[より良いアルゴリズム]を\n  使用し、均一性についてテストされています。\n\n  <img src=\"img/distribution.png\" alt=\"Nano ID uniformity\"\n     width=\"340\" height=\"135\">\n\n* **十分に文書化されている：** Nano IDのすべてのハックは文書化されています。\n  [ソース]のコメントを参照してください。\n* **脆弱性：** セキュリティの脆弱性を報告するには、\n  [Tideliftセキュリティ連絡先](https://tidelift.com/security)を使用してください。\n  Tideliftが修正と開示を調整します。\n\n[Secure random values (in Node.js)]: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba\n[より良いアルゴリズム]:                  https://github.com/ai/nanoid/blob/main/index.js\n[ソース]:                        https://github.com/ai/nanoid/blob/main/index.js\n\n\n## インストール\n\n### ESM\n\nNano ID 5はESMプロジェクト（importを使用）のテストやNode.jsスクリプトで動作します。\n\n```bash\nnpm install nanoid\n```\n\n### CommonJS\n\nNano IDは以下のいずれかの方法でCommonJSで使用できます：\n\n- require()を使用してNano IDをインポートできます。最新のNode.js 22.12\n  （標準で動作）またはNode.js 20（--experimental-require-moduleオプション付き）が必要です。\n\n- Node.js 18では、次のようにNano IDを動的にインポートできます：\n\n  ```js\n  let nanoid\n  module.exports.createID = async () => {\n    if (!nanoid) ({ nanoid } = await import('nanoid'))\n    return nanoid() // => \"V1StGXR8_Z5jdHi6B-myT\"\n  }\n  ```\n\n- Nano ID 3.xを使用できます（まだサポートしています）：\n\n  ```bash\n  npm install nanoid@3\n  ```\n\n### JSR\n\n[JSR](https://jsr.io)はオープンなガバナンスと積極的な開発（npmとは対照的に）を持つnpmの代替です。\n\n```bash\nnpx jsr add @sitnik/nanoid\n```\n\nNode.js、Deno、Bunなどで使用できます。\n\n```js\n// すべてのインポートで`nanoid`を`@sitnik/nanoid`に置き換える\nimport { nanoid } from '@sitnik/nanoid'\n```\n\nDenoでは、`deno add jsr:@sitnik/nanoid`でインストールするか、\n`jsr:@sitnik/nanoid`からインポートします。\n\n\n### CDN\n\nクイックハックの場合、CDNからNano IDを読み込むことができます。ただし、読み込みパフォーマンスが低いため、本番環境での使用はお勧めしません。\n\n```js\nimport { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'\n```\n\n## API\n\nNano IDには2つのAPI：通常と非セキュアがあります。\n\nデフォルトでは、Nano IDはURL友好的な記号（A-Za-z0-9_-）を使用し、\n21文字のID（UUID v4と同様の衝突確率を持つ）を返します。\n\n\n### ブロッキング\n\nNano IDを使用する安全で最も簡単な方法です。\n\nまれに、ハードウェア乱数生成器のノイズ収集中にCPUを他の作業からブロックする場合があります。\n\n```js\nimport { nanoid } from 'nanoid'\nmodel.id = nanoid() //=> \"V1StGXR8_Z5jdHi6B-myT\"\n```\n\nIDのサイズを小さくしたい場合（衝突確率を高める）、\nサイズを引数として渡すことができます。\n\n```js\nnanoid(10) //=> \"IRFa-VaY2b\"\n```\n\nIDサイズの安全性を[ID衝突確率]計算機で確認することを忘れないでください。\n\n[カスタムアルファベット](#カスタムアルファベットまたはサイズ)や\n[ランダム生成器](#カスタムランダムバイト生成器)も使用できます。\n\n[ID衝突確率]: https://zelark.github.io/nano-id-cc/\n\n\n### 非セキュア\n\nデフォルトでは、Nano IDはセキュリティと低衝突確率のためにハードウェアランダムバイト生成を使用します。セキュリティにそれほど関心がない場合は、ハードウェア乱数生成器がない環境でも使用できます。\n\n```js\nimport { nanoid } from 'nanoid/non-secure'\nconst id = nanoid() //=> \"Uakgb_J5m9g-0JDMbcJqLJ\"\n```\n\n\n### カスタムアルファベットまたはサイズ\n\ncustomAlphabetは、独自のアルファベットとIDサイズでnanoidを作成できる関数を返します。\n\n```js\nimport { customAlphabet } from 'nanoid'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nmodel.id = nanoid() //=> \"4f90d13a42\"\n```\n\n```js\nimport { customAlphabet } from 'nanoid/non-secure'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nuser.id = nanoid()\n```\n\nカスタムアルファベットとIDサイズの安全性を[ID衝突確率]計算機で確認してください。\nより多くのアルファベットについては、[nanoid-dictionary]のオプションを確認してください。\n\nアルファベットは256記号以下でなければなりません。\nそうでない場合、内部生成アルゴリズムのセキュリティは保証されません。\n\nデフォルトサイズを設定するだけでなく、関数を呼び出す際にIDサイズを変更することもできます：\n\n```js\nimport { customAlphabet } from 'nanoid'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nmodel.id = nanoid(5) //=> \"f01a2\"\n```\n\n[ID衝突確率]: https://zelark.github.io/nano-id-cc/\n[nanoid-dictionary]:      https://github.com/CyberAP/nanoid-dictionary\n\n\n### カスタムランダムバイト生成器\n\ncustomRandomを使用すると、nanoidを作成し、アルファベットとデフォルトのランダムバイト生成器を置き換えることができます。\n\nこの例では、シードベースの生成器が使用されています：\n\n```js\nimport { customRandom } from 'nanoid'\n\nconst rng = seedrandom(seed)\nconst nanoid = customRandom('abcdef', 10, size => {\n  return (new Uint8Array(size)).map(() => 256 * rng())\n})\n\nnanoid() //=> \"fbaefaadeb\"\n```\n\nrandomコールバックは配列サイズを受け取り、ランダムな数値の配列を返す必要があります。\n\ncustomRandomで同じURL友好的な記号を使用したい場合は、urlAlphabetを使用してデフォルトのアルファベットを取得できます。\n\n```js\nconst { customRandom, urlAlphabet } = require('nanoid')\nconst nanoid = customRandom(urlAlphabet, 10, random)\n```\n\nなお、Nano IDのバージョン間でランダム生成器の呼び出しシーケンスが変更される場合があります。シードベースの生成器を使用している場合、同じ結果を保証するものではありません。\n\n\n## 使用方法\n\n### React\n\nReactの`key` propにNano IDを使用する正しい方法はありません。なぜなら、keyはレンダー間で一貫性がある必要があるからです。\n\n```jsx\nfunction Todos({todos}) {\n  return (\n    <ul>\n      {todos.map(todo => (\n        <li key={nanoid()}> /* これはやめましょう */\n          {todo.text}\n        </li>\n      ))}\n    </ul>\n  )\n}\n```\n\n代わりに、リストアイテム内で安定したIDを使用するようにしましょう。\n\n```jsx\nconst todoItems = todos.map((todo) =>\n  <li key={todo.id}>\n    {todo.text}\n  </li>\n)\n```\n\n安定したIDがない場合は、`nanoid()`の代わりにインデックスを`key`として使用することをお勧めします：\n\n```jsx\nconst todoItems = todos.map((text, index) =>\n  <li key={index}> /* まだ推奨されませんが、nanoid()よりは優先されます。\n                       アイテムに安定したIDがない場合のみ行ってください。 */\n    {text}\n  </li>\n)\n```\n\nラベルと入力フィールドのように要素を関連付けるためだけにランダムなIDが必要な場合は、[`useId`]が推奨されます。\nこのフックはReact 18で追加されました。\n\n[`useId`]: https://react.dev/reference/react/useId\n\n\n### React Native\n\nReact Nativeには組み込みのランダム生成器がありません。次のポリフィルは\nプレーンなReact NativeとExpo（`39.x`以降）で動作します。\n\n1. [`react-native-get-random-values`]のドキュメントを確認し、インストールします。\n2. Nano IDの前にインポートします。\n\n```js\nimport 'react-native-get-random-values'\nimport { nanoid } from 'nanoid'\n```\n\n[`react-native-get-random-values`]: https://github.com/LinusU/react-native-get-random-values\n\n\n### PouchDBとCouchDB\n\nPouchDBとCouchDBでは、IDはアンダースコア`_`で始めることができません。\nNano IDはデフォルトでIDの先頭に`_`を使用する可能性があるため、\nこの問題を防ぐためにプレフィックスが必要です。\n\n次のオプションでデフォルトのIDを上書きします：\n\n```js\ndb.put({\n  _id: 'id' + nanoid(),\n  …\n})\n```\n\n\n### CLI\n\nターミナルで`npx nanoid`を呼び出すことで、一意のIDを取得できます。\nシステムにNode.jsがあれば十分で、Nano IDをどこかにインストールする必要はありません。\n\n```sh\n$ npx nanoid\nnpx: installed 1 in 0.63s\nLZfXLFzPPR4NNrgjlWDxn\n```\n\n生成されるIDのサイズは`--size`（または`-s`）オプションで指定できます：\n\n```sh\n$ npx nanoid --size 10\nL3til0JS4z\n```\n\nカスタムアルファベットは`--alphabet`（または`-a`）オプションで指定できます\n（この場合、`--size`が必須であることに注意してください）：\n\n```sh\n$ npx nanoid --alphabet abc --size 15\nbccbcabaabaccab\n```\n\n### TypeScript\n\nNano IDでは、生成された文字列をTypeScriptで不透明な文字列（opaque strings）にキャストできます。\n例えば：\n\n```ts\ndeclare const userIdBrand: unique symbol\ntype UserId = string & { [userIdBrand]: true }\n\n// 明示的な型パラメータを使用：\nmockUser(nanoid<UserId>())\n\ninterface User {\n  id: UserId\n  name: string\n}\n\nconst user: User = {\n  // 自動的にUserIdにキャストされます：\n  id: nanoid(),\n  name: 'Alice'\n}\n```\n\n### その他のプログラミング言語\n\nNano IDは多くの言語に移植されています。これらのポートを使用して、\nクライアント側とサーバー側で同じID生成器を持つことができます。\n\n* [C](https://github.com/lukateras/nanoid.h)\n* [C#](https://github.com/codeyu/nanoid-net)\n* [C++](https://github.com/mcmikecreations/nanoid_cpp)\n* [Clojure and ClojureScript](https://github.com/zelark/nano-id)\n* [ColdFusion/CFML](https://github.com/JamoCA/cfml-nanoid)\n* [Crystal](https://github.com/mamantoha/nanoid.cr)\n* [Dart & Flutter](https://github.com/pd4d10/nanoid-dart)\n* [Elixir](https://github.com/railsmechanic/nanoid)\n* [Gleam](https://github.com/0xca551e/glanoid)\n* [Go](https://github.com/matoous/go-nanoid)\n* [Haskell](https://github.com/MichelBoucey/NanoID)\n* [Haxe](https://github.com/flashultra/uuid)\n* [Janet](https://sr.ht/~statianzo/janet-nanoid/)\n* [Java](https://github.com/wosherco/jnanoid-enhanced)\n* [Kotlin](https://github.com/viascom/nanoid-kotlin)\n* [MySQL/MariaDB](https://github.com/viascom/nanoid-mysql-mariadb)\n* [Nim](https://github.com/icyphox/nanoid.nim)\n* [OCaml](https://github.com/routineco/ocaml-nanoid)\n* [Perl](https://github.com/tkzwtks/Nanoid-perl)\n* [PHP](https://github.com/hidehalo/nanoid-php)\n* Python [ネイティブ](https://github.com/puyuan/py-nanoid)実装\n  [辞書](https://pypi.org/project/nanoid-dictionary)付きと\n  [高速](https://github.com/oliverlambson/fastnanoid)実装（Rustで書かれています）\n* Postgres [拡張機能](https://github.com/spa5k/uids-postgres)\n  と[ネイティブ関数](https://github.com/viascom/nanoid-postgres)\n* [R](https://github.com/hrbrmstr/nanoid)（辞書付き）\n* [Ruby](https://github.com/radeno/nanoid.rb)\n* [Rust](https://github.com/nikolay-govorov/nanoid)\n* [Swift](https://github.com/ShivaHuang/swift-nanoid)\n* [Unison](https://share.unison-lang.org/latest/namespaces/hojberg/nanoid)\n* [V](https://github.com/invipal/nanoid)\n* [Zig](https://github.com/SasLuca/zig-nanoid)\n\nその他の環境では、コマンドラインからIDを生成するための[CLI]が利用可能です。\n\n[CLI]: #cli\n\n\n## ツール\n\n* [IDサイズ計算機]は、IDのアルファベットやサイズを調整する際の衝突確率を表示します。\n* [`nanoid-dictionary`]は[`customAlphabet`]で使用する一般的なアルファベットを提供します。\n* [`nanoid-good`]はIDに不適切な単語が含まれていないことを確認します。\n\n[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary\n[IDサイズ計算機]:  https://zelark.github.io/nano-id-cc/\n[`customAlphabet`]:    #カスタムアルファベットまたはサイズ\n[`nanoid-good`]:       https://github.com/y-gagar1n/nanoid-good\n"
  },
  {
    "path": "README.ko.md",
    "content": "# Nano ID\n\n<img src=\"https://ai.github.io/nanoid/logo.svg\" align=\"right\"\n     alt=\"Nano ID logo by Anton Lovchikov\" width=\"180\" height=\"94\">\n\n[English](./README.md) | [日本語](./README.ja.md) | [Русский](./README.ru.md) | [简体中文](./README.zh-CN.md) | [Bahasa Indonesia](./README.id-ID.md) | **한국어** | [العربية](./README.ar.md)\n\nJavaScript를 위한 가볍고 안전하며 URL 친화적인 고유 String ID 생성기\n\n> “대단한 레벨의 무의미한 완벽주의,\n> 경의를 표하지 않을 수 없습니다”\n\n* **가볍습니다.** 118 bytes (minified 및 brotli 적용 후). 다른 의존성이 없습니다.\n  [Size Limit] 의 기능으로 컨트롤합니다.\n* **안전합니다.** 하드웨어의 랜덤 생성기를 사용합니다. 클러스터에서 사용할 수 있습니다.\n* **짧은 ID를 생성합니다.** UUID와는 다르게 대소문자를 모두 사용하여 키를 생성하므로, 36 byte를 차지하는 UUID와 다르게 21 byte만으로도 고유 아이디를 생성할 수 있습니다.\n  So ID size was reduced from 36 to 21 symbols.\n* **이식이 쉽습니다.** Nano ID 는 20개 이상의 언어로 포팅되었습니다 [다른 언어들](#다른-언어들).\n\n```js\nimport { nanoid } from 'nanoid'\nmodel.id = nanoid() //=> \"V1StGXR8_Z5jdHi6B-myT\"\n```\n\n---\n\n<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>.\n\n---\n\n[online tool]: https://gitpod.io/#https://github.com/ai/nanoid/\n[with Babel]:  https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/\n[Size Limit]:  https://github.com/ai/size-limit\n\n\n## 목차\n\n- [목차](#목차)\n- [UUID와 비교](#uuid와-비교)\n- [벤치마크](#벤치마크)\n- [보안](#보안)\n- [설치](#설치)\n  - [ESM](#esm)\n  - [CommonJS](#commonjs)\n  - [JSR](#jsr)\n  - [CDN](#cdn)\n- [API](#api)\n  - [Blocking](#blocking)\n  - [Non-Secure](#non-secure)\n  - [사용자 커스텀 문자열](#사용자-커스텀-문자열)\n  - [사용자 지정 랜덤 바이트 생성기](#사용자-지정-랜덤-바이트-생성기)\n- [사용법](#사용법)\n  - [React](#react)\n  - [React Native](#react-native)\n  - [PouchDB 및 CouchDB](#pouchdb-및-couchdb)\n  - [CLI](#cli)\n  - [TypeScript](#typescript)\n  - [다른 언어들](#다른-언어들)\n- [도구](#도구)\n\n\n## UUID와 비교\n\nNano ID 는 (랜덤 기반의) UUID v4와 비교할 수 있습니다.\n아이디로 생성되는 랜덤 비트의 수가 유사하여\n(Nano ID는 126개, UUID는 122개), 동일한 아이디가 생성될 수 있는 충돌 확률도 비슷합니다:\n\n> 10억 분의 1의 확률로 충돌이 발생하기 위해서는\n> 103조 번의 v4 ID가 생성되어야 합니다.\n\nNano ID와 UUID v4에는 두 가지의 주요한 차이점이 있습니다:\n\n1. Nano ID는 대문자를 사용합니다. 그래서 유사한 개수의 랜덤 값을 36개가 아닌 21개의 문자로 나타낼 수 있습니다.\n2. Nano ID 코드는 `uuid/v4` 패키지보다 **4분의 1 사이즈**입니다:\n   UUIDv4는 423 bytes, Nano ID는 118 bytes 입니다.\n\n\n## 벤치마크\n\n```rust\n$ node ./test/benchmark.js\ncrypto.randomUUID          7,619,041 ops/sec\nuuid v4                    7,436,626 ops/sec\n@napi-rs/uuid              4,730,614 ops/sec\nuid/secure                 4,729,185 ops/sec\n@lukeed/uuid               4,015,673 ops/sec\nnanoid                     3,693,964 ops/sec\ncustomAlphabet             2,799,255 ops/sec\nnanoid for browser           380,915 ops/sec\nsecure-random-string         362,316 ops/sec\nuid-safe.sync                354,234 ops/sec\nshortid                       38,808 ops/sec\n\nNon-secure:\nuid                       11,872,105 ops/sec\nnanoid/non-secure          2,226,483 ops/sec\nrndm                       2,308,044 ops/sec\n```\n\n테스트 환경: 프레임워크 13 7840U, 페도라 39, Node.js 21.6.\n\n\n## 보안\n\n*랜덤 생성기에 대한 설명은 다음 기사를 참고하세요:\n[Secure random values (in Node.js)]*\n\n* **예측불가성.** 안전하지 않은 `Math.random()`를 사용하는 대신, Nano ID는\n  Node.js에서 제공하는 `crypto` 모듈과 브라우저의 Web Crypto API를 사용합니다.\n  이 모듈들은 예측이 불가능한 하드웨어 레벨의 랜덤 생성기입니다.\n* **균일성.** `random % alphabet` 는 랜덤 아이디 생성기를 만들때 흔히들 하는 실수입니다.\n  이 경우 분포(수학)가 일정하지 않게 되며, 일부 기호들은 다른 기호들보다 사용될 확률이 낮아집니다.\n  이로 인해 브루트포스를 사용한 시도의 횟수를 줄일 수 있는 결과를 가져옵니다.\n  Nano ID는 [이보다 더 좋은 알고리즘]을 사용하며, 균일성 테스트를 수행하였습니다.\n\n  <img src=\"img/distribution.png\" alt=\"Nano ID uniformity\"\n     width=\"340\" height=\"135\">\n\n* **문서화:** Nano ID의 모든것이 코드에 문서화되어있습니다. [소스 코드]에서 코멘트를 확인하세요.\n* **취약점:** 보안 취약점에 대한 리포트는 아래 링크를 사용해주세요.\n  [Tidelift security contact](https://tidelift.com/security).\n  Tidelift에서 취약점에 대한 수정 및 알림등을 도와줄 수 있습니다.\n\n[Secure random values (in Node.js)]: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba\n[이보다 더 좋은 알고리즘]:                  https://github.com/ai/nanoid/blob/main/index.js\n[소스 코드]:                        https://github.com/ai/nanoid/blob/main/index.js\n\n\n## 설치\n\n### ESM\n\nNano ID 5는 ESM 프로젝트에서 `import`를 사용하여 테스트코드나 Node.js 스크립트에 사용할 수 있습니다.\n\n```bash\nnpm install nanoid\n```\n\n### CommonJS\n\nNano ID는 아래와 같은 방법으로 CommonJS에 사용할 수 있습니다:\n\n- `require()`를 사용해 Nano ID를 가져올 수 있습니다.\n  최신 Node.js 22.12나 Node.js 20에서 `--experimental-require-module`\n  플래그를 이용하면 사용할 수 있습니다.\n\n- Node.js 18에서는 아래의 방법으로 동적 임포트를 해주세요:\n\n  ```js\n  let nanoid\n  module.exports.createID = async () => {\n    if (!nanoid) ({ nanoid } = await import('nanoid'))\n    return nanoid() // => \"V1StGXR8_Z5jdHi6B-myT\"\n  }\n  ```\n\n- Nano ID 3.x 역시 설치할 수 있습니다 (아직 지원중이에요!):\n\n  ```bash\n  npm install nanoid@3\n  ```\n\n### JSR\n\n[JSR](https://jsr.io) 은 npm을 대체할 수 있는 오픈 거버넌스이며 npm과 달리 현재 활발히 개발중에 있습니다.\n\n```bash\nnpx jsr add @sitnik/nanoid\n```\n\nNode.js, Deno, Bun 등에서 사용할 수 있습니다.\n\n```js\n// 모든 `nanoid` import를 `@sitnik/nanoid`로 변경합니다\nimport { nanoid } from '@sitnik/nanoid'\n```\n\nDeno 사용시에는 `deno add jsr:@sitnik/nanoid` 명령어로 설치하고\n`jsr:@sitnik/nanoid`로 import 합니다.\n\n\n### CDN\n\n빠른 적용을 위해 CDN에서 Nano ID를 가져올 수 있습니다.\n하지만 로딩 성능이 늦어지므로 프로덕션에서는 사용하는 것을 추천하지 않습니다.\n\n```js\nimport { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'\n```\n\n## API\n\nNano ID는 normal / non-secure의 2가지의 API를 제공합니다.\n\n기본적으로 Nano ID는 URL에 친화적인 기호들을 사용하여 21자리의 랜덤한 문자열을 생성합니다.\n(이들은 UUID v4와 유사한 중복생성 확률을 가집니다)\n\n\n### Blocking\n\nNano ID를 사용하는 가장 안전하고 쉬운 방법입니다.\n\n드물게 CPU가 하드웨어 랜덤 생성을 위해 노이즈 제거를 수행하는 동안 다른 동작을 못하도록 블로킹 될 수 있습니다.\n\n```js\nimport { nanoid } from 'nanoid'\nmodel.id = nanoid() //=> \"V1StGXR8_Z5jdHi6B-myT\"\n```\n\n생성되는 랜덤 아이디의 크기를 줄이고 싶으면 파라미터로 해당 길이 값을 넣어주면 됩니다.\n(이렇게 하면 중복 생성이 발생할 확률도 올라갑니다)\n\n```js\nnanoid(10) //=> \"IRFa-VaY2b\"\n```\n\n아래의 [아이디 중복확률] 계산기로 여러분의 아이디가 얼마나 안전한지 확인해보세요.\n\n[사용자 커스텀 문자열](#사용자-커스텀-문자열) 이나\n[사용자가 만든 랜덤 생성기](#사용자-지정-랜덤-바이트-생성기) 를 사용할 수도 있습니다.\n\n[아이디 중복확률]: https://zelark.github.io/nano-id-cc/\n\n\n### Non-Secure\n\n기본적으로 Nano ID는 보안과 낮은 충돌 확률을 위해 하드웨어 랜덤 바이트 생성기를 사용합니다.\n만약 보안이 중요하지 않다면 하드웨어 랜덤 생성기를 사용하지 않도록 설정할 수 있습니다.\n\n```js\nimport { nanoid } from 'nanoid/non-secure'\nconst id = nanoid() //=> \"Uakgb_J5m9g-0JDMbcJqLJ\"\n```\n\n\n### 사용자 커스텀 문자열\n\n`customAlphabet` 함수를 사용하면 지정된 문자열 내에서 지정된 개수로 이루어진\n랜덤 아이디를 생성할 수 있는 `nanoid` 함수를 만들 수 있습니다\n\n```js\nimport { customAlphabet } from 'nanoid'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nmodel.id = nanoid() //=> \"4f90d13a42\"\n```\n\n```js\nimport { customAlphabet } from 'nanoid/non-secure'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nuser.id = nanoid()\n```\n\n[아이디 충돌 확률] 계산기를 사용하여 여러분이 지정한 문자와 사이즈에 대한 중복 생성 확률을 확인해보세요.\n[`nanoid-dictionary`] 에서 어떤 문자열을 사용할 수 있는지에 대한 옵션을 확인할 수 있습니다.\n\n커스텀 문자열은 256개 이하의 개수를 가져야 합니다.\n그 외의 경우 내부의 생성 알고리즘의 보안성을 보장할 수 없습니다.\n\n기본 사이즈를 지정한 후에, 새로 만들어진 함수를 부를 때 생성할 문자열의 개수를 다시 지정하는 것도 가능합니다\n\n```js\nimport { customAlphabet } from 'nanoid'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nmodel.id = nanoid(5) //=> \"f01a2\"\n```\n\n[아이디 충돌 확률]: https://zelark.github.io/nano-id-cc/\n[`nanoid-dictionary`]:      https://github.com/CyberAP/nanoid-dictionary\n\n\n### 사용자 지정 랜덤 바이트 생성기\n\n`customRandom` 함수를 사용하면 `nanoid`에서 사용할 문자열과 알고리즘을 지정할 수 있습니다.\n\n아래 예시는 시드 값을 기반으로 하는 랜덤 생성기를 사용하였습니다.\n\n```js\nimport { customRandom } from 'nanoid'\n\nconst rng = seedrandom(seed)\nconst nanoid = customRandom('abcdef', 10, size => {\n  return (new Uint8Array(size)).map(() => 256 * rng())\n})\n\nnanoid() //=> \"fbaefaadeb\"\n```\n\n콜백 함수 `random` 는 반드시 배열의 크기를 받을 수 있어야 하며, 랜덤 숫자로 이루어진 배열을 리턴해야 합니다.\n\nURL 친화적인 기호들을 사용하여 `customRandom` 을 실행하려면,\n`urlAlphabet`을 사용해 기본 문자셋을 가져올 수 있습니다.\n\n```js\nconst { customRandom, urlAlphabet } = require('nanoid')\nconst nanoid = customRandom(urlAlphabet, 10, random)\n```\n\n참고로, Nano ID 버전이 변경됨에 따라 랜덤 생성기의 호출 시퀀스가 변경될 수 있습니다.\n시드기반 생성기를 사용하는 경우 동일한 결과가 나오는 것을 보장할 수 없습니다.\n\n\n## 사용법\n\n### React\n\nReact에서 `key` props에 Nano ID를 사용하는 것은 좋지 않습니다.\n이 값은 렌더링 될 때마다 동일한 값을 가지고 있어야 합니다.\n\n```jsx\nfunction Todos({todos}) {\n  return (\n    <ul>\n      {todos.map(todo => (\n        <li key={nanoid()}> /* 절대 하지 마세요 */\n          {todo.text}\n        </li>\n      ))}\n    </ul>\n  )\n}\n```\n\n랜덤값보다 리스트 내에서 가져올 수 있는 값을 사용하여 안정된 값을 키 값으로 사용하는 것이 좋습니다.\n\n```jsx\nconst todoItems = todos.map((todo) =>\n  <li key={todo.id}>\n    {todo.text}\n  </li>\n)\n```\n\n`key` 값으로 사용할 적절한 값이 없는 경우에도 `nanoid()`를 사용하기 보다는 인덱스 값을 사용하세요:\n\n```jsx\nconst todoItems = todos.map((text, index) =>\n  <li key={index}> /* 추천되는 방식은 아니지만 nanoid()를 쓰는것 보단 낫습니다 */\n    {text}\n  </li>\n)\n```\n\n랜덤한 아이디를 생성하여 HTML 요소간의 연결 (label과 input 등)에 사용하는 경우에는\nReact 18에서 추가된 [`useId`] 를 추천합니다.\n\n[`useId`]: https://react.dev/reference/react/useId\n\n\n### React Native\n\nReact Native에는 내장된 랜덤 생성기가 존재하지 않습니다.\n아래의 폴리필을 사용하면 순수 React Native와 Expo(`39`버전 이상) 환경에서\nNano ID를 사용할 수 있습니다.\n\n1. [`react-native-get-random-values`] 문서를 확인하고 설치합니다\n2. Nano ID를 import하기 전에 이 패키지를 import 해야 합니다.\n\n```js\nimport 'react-native-get-random-values'\nimport { nanoid } from 'nanoid'\n```\n\n[`react-native-get-random-values`]: https://github.com/LinusU/react-native-get-random-values\n\n\n### PouchDB 및 CouchDB\n\nPouchDB와 CouchDB에서는 ID 값을 `_`로 시작할 수 없습니다.\nNano ID는 기본적으로 `_`를 맨 앞에 붙일 수 있기 때문에,\n이 문제를 해결하기 위해 접두어 (prefix)가 필요합니다.\n\n아래와 같이 접두어를 붙여서 사용합니다.\n\n```js\ndb.put({\n  _id: 'id' + nanoid(),\n  …\n})\n```\n\n\n### CLI\n\n터미널에서 `npx nanoid` 명령어를 입력하면 고유 ID를 생성할 수 있습니다.\nNode.js가 시스템에 설치되어있어야 하며, Nano ID는 미리 설치되어있지 않아도 됩니다.\n\n```sh\n$ npx nanoid\nnpx: installed 1 in 0.63s\nLZfXLFzPPR4NNrgjlWDxn\n```\n\n생성할 아이디의 길이를 변경하려면 `--size` (or `-s`) 옵션을 붙여줍니다:\n\n```sh\n$ npx nanoid --size 10\nL3til0JS4z\n```\n\n사용자 커스텀 문자열을 사용하려면 `--alphabet` (or `-a`) 옵션을 사용합니다\n(이 때 `--size`도 같이 사용해야 합니다):\n\n```sh\n$ npx nanoid --alphabet abc --size 15\nbccbcabaabaccab\n```\n\n### TypeScript\n\nNano ID는 생성된 문자열을 TypeScript의 순수 string이 아닌 타입에도 할당할 수 있습니다.\n예를 들어 아래와 같이 가능합니다:\n\n```ts\ndeclare const userIdBrand: unique symbol\ntype UserId = string & { [userIdBrand]: true }\n\n// 명시적으로 타입 파라미터를 사용:\nmockUser(nanoid<UserId>())\n\ninterface User {\n  id: UserId\n  name: string\n}\n\nconst user: User = {\n  // 자동으로 UserId 타입으로 캐스팅됨:\n  id: nanoid(),\n  name: 'Alice'\n}\n```\n\n### 다른 언어들\n\nNano ID는 다양한 언어로 포팅되었습니다. 클라이언트/서버에 관계없이 아래의 다양한 포팅된 버전들을 사용할 수 있습니다.\n\n* [C](https://github.com/lukateras/nanoid.h)\n* [C#](https://github.com/codeyu/nanoid-net)\n* [C++](https://github.com/mcmikecreations/nanoid_cpp)\n* [Clojure and ClojureScript](https://github.com/zelark/nano-id)\n* [ColdFusion/CFML](https://github.com/JamoCA/cfml-nanoid)\n* [Crystal](https://github.com/mamantoha/nanoid.cr)\n* [Dart & Flutter](https://github.com/pd4d10/nanoid-dart)\n* [Elixir](https://github.com/railsmechanic/nanoid)\n* [Gleam](https://github.com/0xca551e/glanoid)\n* [Go](https://github.com/matoous/go-nanoid)\n* [Haskell](https://github.com/MichelBoucey/NanoID)\n* [Haxe](https://github.com/flashultra/uuid)\n* [Janet](https://sr.ht/~statianzo/janet-nanoid/)\n* [Java](https://github.com/wosherco/jnanoid-enhanced)\n* [Kotlin](https://github.com/viascom/nanoid-kotlin)\n* [MySQL/MariaDB](https://github.com/viascom/nanoid-mysql-mariadb)\n* [Nim](https://github.com/icyphox/nanoid.nim)\n* [OCaml](https://github.com/routineco/ocaml-nanoid)\n* [Perl](https://github.com/tkzwtks/Nanoid-perl)\n* [PHP](https://github.com/hidehalo/nanoid-php)\n* Python [native](https://github.com/puyuan/py-nanoid) implementation\n  with [dictionaries](https://pypi.org/project/nanoid-dictionary)\n  and [fast](https://github.com/oliverlambson/fastnanoid) implementation (written in Rust)\n* Postgres [Extension](https://github.com/spa5k/uids-postgres)\n  and [Native Function](https://github.com/viascom/nanoid-postgres)\n* [R](https://github.com/hrbrmstr/nanoid) (with dictionaries)\n* [Ruby](https://github.com/radeno/nanoid.rb)\n* [Rust](https://github.com/nikolay-govorov/nanoid)\n* [Swift](https://github.com/ShivaHuang/swift-nanoid)\n* [Unison](https://share.unison-lang.org/latest/namespaces/hojberg/nanoid)\n* [V](https://github.com/invipal/nanoid)\n* [Zig](https://github.com/SasLuca/zig-nanoid)\n\n이 외의 환경에서는 [CLI]를 사용하여 터미널 환경에서 랜덤 아이디를 생성할 수 있습니다.\n\n[CLI]: #cli\n\n\n## 도구\n\n* [ID 사이즈 계산기]는 문자열과 생성 사이즈를 변경한 경우 중복된 아이디가 생성될 수 있는 충돌 확률을 알려줍니다.\n* [`customAlphabet`]에서 사용할 수 있는 일반적인 문자열들을 [`nanoid-dictionary`]로 찾아볼 수 있습니다.\n* 생성된 ID에 이상한 단어가 들어가는 것을 방지하려면 [`nanoid-good`]를 사용할 수 있습니다.\n\n[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary\n[ID 사이즈 계산기]:  https://zelark.github.io/nano-id-cc/\n[`customAlphabet`]:    #custom-alphabet-or-size\n[`nanoid-good`]:       https://github.com/y-gagar1n/nanoid-good\n"
  },
  {
    "path": "README.md",
    "content": "# Nano ID\n\n<img src=\"https://ai.github.io/nanoid/logo.svg\" align=\"right\"\n     alt=\"Nano ID logo by Anton Lovchikov\" width=\"180\" height=\"94\">\n\n**English** | [日本語](./README.ja.md) | [Русский](./README.ru.md) | [简体中文](./README.zh-CN.md) | [Bahasa Indonesia](./README.id-ID.md) | [한국어](./README.ko.md) | [العربية](./README.ar.md)\n\nA tiny, secure, URL-friendly, unique string ID generator for JavaScript.\n\n> “An amazing level of senseless perfectionism,\n> which is simply impossible not to respect.”\n\n* **Small.** 118 bytes (minified and brotlied). No dependencies.\n  [Size Limit] controls the size.\n* **Safe.** It uses hardware random generator. Can be used in clusters.\n* **Short IDs.** It uses a larger alphabet than UUID (`A-Za-z0-9_-`).\n  So ID size was reduced from 36 to 21 symbols.\n* **Portable.** Nano ID was ported\n  to over [20 programming languages](./README.md#other-programming-languages).\n\n```js\nimport { nanoid } from 'nanoid'\nmodel.id = nanoid() //=> \"V1StGXR8_Z5jdHi6B-myT\"\n```\n\n---\n\n<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>.\n\n---\n\n[online tool]: https://gitpod.io/#https://github.com/ai/nanoid/\n[with Babel]:  https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/\n[Size Limit]:  https://github.com/ai/size-limit\n\n\n## Table of Contents\n\n- [Table of Contents](#table-of-contents)\n- [Comparison with UUID](#comparison-with-uuid)\n- [Benchmark](#benchmark)\n- [Security](#security)\n- [Install](#install)\n  - [ESM](#esm)\n  - [CommonJS](#commonjs)\n  - [JSR](#jsr)\n  - [CDN](#cdn)\n- [API](#api)\n  - [Blocking](#blocking)\n  - [Non-Secure](#non-secure)\n  - [Custom Alphabet or Size](#custom-alphabet-or-size)\n  - [Custom Random Bytes Generator](#custom-random-bytes-generator)\n- [Usage](#usage)\n  - [React](#react)\n  - [React Native](#react-native)\n  - [PouchDB and CouchDB](#pouchdb-and-couchdb)\n  - [CLI](#cli)\n  - [TypeScript](#typescript)\n  - [Other Programming Languages](#other-programming-languages)\n- [Tools](#tools)\n\n\n## Comparison with UUID\n\nNano ID is quite comparable to UUID v4 (random-based).\nIt has a similar number of random bits in the ID\n(126 in Nano ID and 122 in UUID), so it has a similar collision probability:\n\n> For there to be a one in a billion chance of duplication,\n> 103 trillion version 4 IDs must be generated.\n\nThere are two main differences between Nano ID and UUID v4:\n\n1. Nano ID uses a bigger alphabet, so a similar number of random bits\n   are packed in just 21 symbols instead of 36.\n2. Nano ID code is **4 times smaller** than `uuid/v4` package:\n   118 bytes instead of 423.\n\n\n## Benchmark\n\n```rust\n$ node ./test/benchmark.js\ncrypto.randomUUID          7,619,041 ops/sec\nuuid v4                    7,436,626 ops/sec\n@napi-rs/uuid              4,730,614 ops/sec\nuid/secure                 4,729,185 ops/sec\n@lukeed/uuid               4,015,673 ops/sec\nnanoid                     3,693,964 ops/sec\ncustomAlphabet             2,799,255 ops/sec\nnanoid for browser           380,915 ops/sec\nsecure-random-string         362,316 ops/sec\nuid-safe.sync                354,234 ops/sec\nshortid                       38,808 ops/sec\n\nNon-secure:\nuid                       11,872,105 ops/sec\nnanoid/non-secure          2,226,483 ops/sec\nrndm                       2,308,044 ops/sec\n```\n\nTest configuration: Framework 13 7840U, Fedora 39, Node.js 21.6.\n\n\n## Security\n\n*See a good article about random generators theory:\n[Secure random values (in Node.js)]*\n\n* **Unpredictability.** Instead of using the unsafe `Math.random()`, Nano ID\n  uses the `crypto` module in Node.js and the Web Crypto API in browsers.\n  These modules use unpredictable hardware random generator.\n* **Uniformity.** `random % alphabet` is a popular mistake to make when coding\n  an ID generator. The distribution will not be even; there will be a lower\n  chance for some symbols to appear compared to others. So, it will reduce\n  the number of tries when brute-forcing. Nano ID uses a [better algorithm]\n  and is tested for uniformity.\n\n  <img src=\"img/distribution.png\" alt=\"Nano ID uniformity\"\n     width=\"340\" height=\"135\">\n\n* **Well-documented:** all Nano ID hacks are documented. See comments\n  in [the source].\n* **Vulnerabilities:** to report a security vulnerability, please use\n  the [Tidelift security contact](https://tidelift.com/security).\n  Tidelift will coordinate the fix and disclosure.\n\n[Secure random values (in Node.js)]: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba\n[better algorithm]:                  https://github.com/ai/nanoid/blob/main/index.js\n[the source]:                        https://github.com/ai/nanoid/blob/main/index.js\n\n\n## Install\n\n### ESM\n\nNano ID 5 works with ESM projects (with `import`) in tests or Node.js scripts.\n\n```bash\nnpm install nanoid\n```\n\n### CommonJS\n\nNano ID can be used with CommonJS in one of the following ways:\n\n- You can use `require()` to import Nano ID. You need to use latest Node.js\n  22.12 (works out-of-the-box) or Node.js 20\n  (with `--experimental-require-module`).\n\n- For Node.js 18 you can dynamically import Nano ID as follows:\n\n  ```js\n  let nanoid\n  module.exports.createID = async () => {\n    if (!nanoid) ({ nanoid } = await import('nanoid'))\n    return nanoid() // => \"V1StGXR8_Z5jdHi6B-myT\"\n  }\n  ```\n\n- You can use Nano ID 3.x (we still support it):\n\n  ```bash\n  npm install nanoid@3\n  ```\n\n### JSR\n\n[JSR](https://jsr.io) is a replacement for npm with open governance\nand active development (in contrast to npm).\n\n```bash\nnpx jsr add @sitnik/nanoid\n```\n\nYou can use it in Node.js, Deno, Bun, etc.\n\n```js\n// Replace `nanoid` to `@sitnik/nanoid` in all imports\nimport { nanoid } from '@sitnik/nanoid'\n```\n\nFor Deno install it by `deno add jsr:@sitnik/nanoid` or import\nfrom `jsr:@sitnik/nanoid`.\n\n\n### CDN\n\nFor quick hacks, you can load Nano ID from CDN. Though, it is not recommended\nto be used in production because of the lower loading performance.\n\n```js\nimport { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'\n```\n\n## API\n\nNano ID has 2 APIs: normal and non-secure.\n\nBy default, Nano ID uses URL-friendly symbols (`A-Za-z0-9_-`) and returns an ID\nwith 21 characters (to have a collision probability similar to UUID v4).\n\n\n### Blocking\n\nThe safe and easiest way to use Nano ID.\n\nIn rare cases could block CPU from other work while noise collection\nfor hardware random generator.\n\n```js\nimport { nanoid } from 'nanoid'\nmodel.id = nanoid() //=> \"V1StGXR8_Z5jdHi6B-myT\"\n```\n\nIf you want to reduce the ID size (and increase collisions probability),\nyou can pass the size as an argument.\n\n```js\nnanoid(10) //=> \"IRFa-VaY2b\"\n```\n\nDon’t forget to check the safety of your ID size\nin our [ID collision probability] calculator.\n\nYou can also use a [custom alphabet](#custom-alphabet-or-size)\nor a [random generator](#custom-random-bytes-generator).\n\n[ID collision probability]: https://zelark.github.io/nano-id-cc/\n\n\n### Non-Secure\n\nBy default, Nano ID uses hardware random bytes generation for security\nand low collision probability. If you are not so concerned with security,\nyou can use it for environments without hardware random generators.\n\n```js\nimport { nanoid } from 'nanoid/non-secure'\nconst id = nanoid() //=> \"Uakgb_J5m9g-0JDMbcJqLJ\"\n```\n\n\n### Custom Alphabet or Size\n\n`customAlphabet` returns a function that allows you to create `nanoid`\nwith your own alphabet and ID size.\n\n```js\nimport { customAlphabet } from 'nanoid'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nmodel.id = nanoid() //=> \"4f90d13a42\"\n```\n\n```js\nimport { customAlphabet } from 'nanoid/non-secure'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nuser.id = nanoid()\n```\n\nCheck the safety of your custom alphabet and ID size in our\n[ID collision probability] calculator. For more alphabets, check out the options\nin [`nanoid-dictionary`].\n\nAlphabet must contain 256 symbols or less.\nOtherwise, the security of the internal generator algorithm is not guaranteed.\n\nIn addition to setting a default size, you can change the ID size when calling\nthe function:\n\n```js\nimport { customAlphabet } from 'nanoid'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nmodel.id = nanoid(5) //=> \"f01a2\"\n```\n\n[`nanoid-dictionary`]:      https://github.com/CyberAP/nanoid-dictionary\n\n\n### Custom Random Bytes Generator\n\n`customRandom` allows you to create a `nanoid` and replace alphabet\nand the default random bytes generator.\n\nIn this example, a seed-based generator is used:\n\n```js\nimport { customRandom } from 'nanoid'\n\nconst rng = seedrandom(seed)\nconst nanoid = customRandom('abcdef', 10, size => {\n  return (new Uint8Array(size)).map(() => 256 * rng())\n})\n\nnanoid() //=> \"fbaefaadeb\"\n```\n\n`random` callback must accept the array size and return an array\nwith random numbers.\n\nIf you want to use the same URL-friendly symbols with `customRandom`,\nyou can get the default alphabet using the `urlAlphabet`.\n\n```js\nimport { customRandom, urlAlphabet } from 'nanoid'\nconst nanoid = customRandom(urlAlphabet, 10, random)\n```\n\nNote, that between Nano ID versions we may change random generator\ncall sequence. If you are using seed-based generators, we do not guarantee\nthe same result.\n\n\n## Usage\n\n### React\n\nThere’s no correct way to use Nano ID for React `key` prop\nsince it should be consistent among renders.\n\n```jsx\nfunction Todos({todos}) {\n  return (\n    <ul>\n      {todos.map(todo => (\n        <li key={nanoid()}> /* DON’T DO IT */\n          {todo.text}\n        </li>\n      ))}\n    </ul>\n  )\n}\n```\n\nYou should rather try to reach for stable ID inside your list item.\n\n```jsx\nconst todoItems = todos.map((todo) =>\n  <li key={todo.id}>\n    {todo.text}\n  </li>\n)\n```\n\nIn case you don’t have stable IDs you'd rather use index as `key`\ninstead of `nanoid()`:\n\n```jsx\nconst todoItems = todos.map((text, index) =>\n  <li key={index}> /* Still not recommended but preferred over nanoid().\n                      Only do this if items have no stable IDs. */\n    {text}\n  </li>\n)\n```\n\nIn case you just need random IDs to link elements like labels\nand input fields together, [`useId`] is recommended.\nThat hook was added in React 18.\n\n[`useId`]: https://react.dev/reference/react/useId\n\n\n### React Native\n\nReact Native does not have built-in random generator. The following polyfill\nworks for plain React Native and Expo starting with `39.x`.\n\n1. Check [`react-native-get-random-values`] docs and install it.\n2. Import it before Nano ID.\n\n```js\nimport 'react-native-get-random-values'\nimport { nanoid } from 'nanoid'\n```\n\n[`react-native-get-random-values`]: https://github.com/LinusU/react-native-get-random-values\n\n\n### PouchDB and CouchDB\n\nIn PouchDB and CouchDB, IDs can’t start with an underscore `_`.\nA prefix is required to prevent this issue, as Nano ID might use a `_`\nat the start of the ID by default.\n\nOverride the default ID with the following option:\n\n```js\ndb.put({\n  _id: 'id' + nanoid(),\n  …\n})\n```\n\n\n### CLI\n\nYou can get unique ID in terminal by calling `npx nanoid`. You need only\nNode.js in the system. You do not need Nano ID to be installed anywhere.\n\n```sh\n$ npx nanoid\nnpx: installed 1 in 0.63s\nLZfXLFzPPR4NNrgjlWDxn\n```\n\nSize of generated ID can be specified with `--size` (or `-s`) option:\n\n```sh\n$ npx nanoid --size 10\nL3til0JS4z\n```\n\nCustom alphabet can be specified with `--alphabet` (or `-a`) option\n(note that in this case `--size` is required):\n\n```sh\n$ npx nanoid --alphabet abc --size 15\nbccbcabaabaccab\n```\n\n### TypeScript\n\nNano ID allows casting generated strings into opaque strings in TypeScript.\nFor example:\n\n```ts\ndeclare const userIdBrand: unique symbol\ntype UserId = string & { [userIdBrand]: true }\n\n// Use explicit type parameter:\nmockUser(nanoid<UserId>())\n\ninterface User {\n  id: UserId\n  name: string\n}\n\nconst user: User = {\n  // Automatically casts to UserId:\n  id: nanoid(),\n  name: 'Alice'\n}\n```\n\n### Other Programming Languages\n\nNano ID was ported to many languages. You can use these ports to have\nthe same ID generator on the client and server side.\n\n* [C](https://github.com/lukateras/nanoid.h)\n* [C#](https://github.com/codeyu/nanoid-net)\n* [C++](https://github.com/mcmikecreations/nanoid_cpp)\n* [Clojure and ClojureScript](https://github.com/zelark/nano-id)\n* [ColdFusion/CFML](https://github.com/JamoCA/cfml-nanoid)\n* [Crystal](https://github.com/mamantoha/nanoid.cr)\n* [Dart & Flutter](https://github.com/pd4d10/nanoid-dart)\n* [Elixir](https://github.com/railsmechanic/nanoid)\n* [Gleam](https://github.com/0xca551e/glanoid)\n* [Go](https://github.com/matoous/go-nanoid)\n* [Haskell](https://github.com/MichelBoucey/NanoID)\n* [Haxe](https://github.com/flashultra/uuid)\n* [Janet](https://sr.ht/~statianzo/janet-nanoid/)\n* [Java](https://github.com/wosherco/jnanoid-enhanced)\n* [Kotlin](https://github.com/viascom/nanoid-kotlin)\n* [MySQL/MariaDB](https://github.com/viascom/nanoid-mysql-mariadb)\n* [Nim](https://github.com/icyphox/nanoid.nim)\n* [OCaml](https://github.com/routineco/ocaml-nanoid)\n* [Perl](https://github.com/tkzwtks/Nanoid-perl)\n* [PHP](https://github.com/hidehalo/nanoid-php)\n* Python [native](https://github.com/puyuan/py-nanoid) implementation\n  with [dictionaries](https://pypi.org/project/nanoid-dictionary)\n  and [fast](https://github.com/oliverlambson/fastnanoid) implementation (written in Rust)\n* Postgres [Extension](https://github.com/spa5k/uids-postgres)\n  and [Native Function](https://github.com/viascom/nanoid-postgres)\n* [R](https://github.com/hrbrmstr/nanoid) (with dictionaries)\n* [Ruby](https://github.com/radeno/nanoid.rb)\n* [Rust](https://github.com/nikolay-govorov/nanoid)\n* [Swift](https://github.com/ShivaHuang/swift-nanoid)\n* [Unison](https://share.unison-lang.org/latest/namespaces/hojberg/nanoid)\n* [V](https://github.com/invipal/nanoid)\n* [Zig](https://github.com/SasLuca/zig-nanoid)\n\nFor other environments, [CLI] is available to generate IDs from a command line.\n\n[CLI]: #cli\n\n\n## Tools\n\n* [ID size calculator] shows collision probability when adjusting\n  the ID alphabet or size.\n* [`nanoid-dictionary`] with popular alphabets to use with [`customAlphabet`].\n* [`nanoid-good`] to be sure that your ID doesn’t contain any obscene words.\n\n[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary\n[ID size calculator]:  https://zelark.github.io/nano-id-cc/\n[`customAlphabet`]:    #custom-alphabet-or-size\n[`nanoid-good`]:       https://github.com/y-gagar1n/nanoid-good\n"
  },
  {
    "path": "README.ru.md",
    "content": "# Nano ID\n\n<img src=\"https://ai.github.io/nanoid/logo.svg\" align=\"right\"\n     alt=\"Логотип Nano ID от Антона Ловчикова\" width=\"180\" height=\"94\">\n\n[English](./README.md) | [日本語](./README.ja.md) | **Русский** | [简体中文](./README.zh-CN.md) | [Bahasa Indonesia](./README.id-ID.md) | [한국어](./README.ko.md) | [العربية](./README.ar.md)\n\nГенератор уникальных ID для JavaScript — лёгкий, безопасный,\nID можно применять в URL.\n\n> «Поразительный уровень бессмысленного перфекционизма,\n> который просто невозможно не уважать»\n\n- **Лёгкий.** 118 байт (после минификации и Brotli). Без зависимостей.\n  [Size Limit] следит за размером.\n- **Безопасный.** Использует аппаратный генератор случайных чисел.\n  Можно использовать в кластерах машин.\n- **Короткие ID.** Используется больший алфавит, чем у UUID (`A-Za-z0-9_-`).\n  Поэтому длина ID уменьшена с 36 до 21 символа.\n- **Работает везде.** Nano ID уже портировали\n  на [20 языков программирования](#другие-языки-программирования).\n\n```js\nimport { nanoid } from 'nanoid'\nmodel.id = nanoid() //=> \"V1StGXR8_Z5jdHi6B-myT\"\n```\n\nПоддерживает современные браузеры, IE ([с Babel]), Node.js и React Native.\n\n[online tool]: https://gitpod.io/#https://github.com/ai/nanoid/\n[с babel]: https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/\n[size limit]: https://github.com/ai/size-limit\n\n---\n\n<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>.\n\n---\n\n\n## Оглавление\n\n- [Оглавление](#оглавление)\n- [Сравнение с UUID](#сравнение-с-uuid)\n- [Сравнение производительности](#сравнение-производительности)\n- [Безопасность](#безопасность)\n- [Подключение](#подключение)\n  - [ESM](#esm)\n  - [CommonJS](#commonjs)\n  - [JSR](#jsr)\n  - [CDN](#cdn)\n- [API](#api)\n  - [Блокирующий](#блокирующий)\n  - [Небезопасный](#небезопасный)\n  - [Смена алфавита или длины](#смена-алфавита-или-длины)\n  - [Смена генератора случайных чисел](#смена-генератора-случайных-чисел)\n- [Руководство](#руководство)\n  - [React](#react)\n  - [React Native](#react-native)\n  - [PouchDB и CouchDB](#pouchdb-и-couchdb)\n  - [Терминал](#терминал)\n  - [TypeScript](#typescript)\n  - [Другие языки программирования](#другие-языки-программирования)\n- [Инструменты](#инструменты)\n\n\n## Сравнение с UUID\n\nNano ID похож на UUID v4 (случайный).\nУ них сравнимое число битов случайности в ID (126 у Nano ID против 122 у UUID),\nпоэтому они обладают похожей вероятностью возникновения коллизий\n(повторной генерации ранее выданных ID):\n\n> Чтобы вероятность повтора приблизилась к 1 на миллиард,\n> нужно сгенерировать 103 триллиона ID.\n\nНо между ними есть 2 важных отличия:\n\n1. Nano ID использует более широкий алфавит, и сравнимое количество\n   битов случайности будут упакованы в более короткую строку\n   (21 символ, против 36 у UUID).\n2. Код Nano ID **в 4 раз меньше**, чем у `uuid/v4` — 118 байт против 423.\n\n\n## Сравнение производительности\n\n```rust\n$ node ./test/benchmark.js\ncrypto.randomUUID          7,619,041 ops/sec\nuuid v4                    7,436,626 ops/sec\n@napi-rs/uuid              4,730,614 ops/sec\nuid/secure                 4,729,185 ops/sec\n@lukeed/uuid               4,015,673 ops/sec\nnanoid                     3,693,964 ops/sec\ncustomAlphabet             2,799,255 ops/sec\nnanoid for browser           380,915 ops/sec\nsecure-random-string         362,316 ops/sec\nuid-safe.sync                354,234 ops/sec\nshortid                       38,808 ops/sec\n\nNon-secure:\nuid                       11,872,105 ops/sec\nnanoid/non-secure          2,226,483 ops/sec\nrndm                       2,308,044 ops/sec\n```\n\nСреда сравнения: Framework 13 7840U, Fedora 39, Node.js 21.6.\n\n\n## Безопасность\n\n_См. также хорошую статью о теориях генераторов случайных чисел:\n[Secure random values (in Node.js)]_\n\n- **Непредсказуемость.** Вместо предсказуемого `Math.random()`, Nano ID\n  использует модуль `crypto` в Node.js и Web Crypto API в браузере.\n  Эти модули дают доступ к аппаратному генератору случайных чисел.\n- **Равномерность.** Например, существует популярная ошибка `random % alphabet`,\n  которую часто допускают при разработке генератора ID.\n  Распределение вероятности для каждого символа может не быть одинаковым.\n  Из-за неравномерности использования пространства алфавита, на перебор ID\n  потребуется меньше времени, чем ожидается.\n  Nano ID использует [более совершенный алгоритм],\n  а равномерность распределения символов покрыта тестами.\n\n  <img src=\"img/distribution.png\" alt=\"Распределение Nano ID\"\n     width=\"340\" height=\"135\">\n\n- **Документация:** все хитрости Nano ID хорошо документированы — смотрите\n  комментарии [в исходниках].\n- **Уязвимости:** если вы нашли уязвимость в Nano ID, свяжитесь с\n  [командой безопасности Tidelift](https://tidelift.com/security).\n  Они проконтролируют исправление и проинформируют пользователей.\n\n[secure random values (in node.js)]: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba\n[более совершенный алгоритм]: https://github.com/ai/nanoid/blob/main/index.js\n[в исходниках]: https://github.com/ai/nanoid/blob/main/index.js\n\n\n## Подключение\n\n### ESM\n\nNano ID 5 работает с ESM-проектами (`import`) в тестах или скриптах для Node.js.\n\n```bash\nnpm install nanoid\n```\n\n### CommonJS\n\nНа проектах с CommonJS вы можете использовать:\n\n- `require()` будет работать в последней версия Node.js 22.12 (из коробки)\n  или Node.js 20 (с флагом `--experimental-require-module`).\n\n- В более старых версиях Node.js можно использовать динамический импорт:\n\n  ```js\n  let nanoid\n  module.exports.createID = async () => {\n    if (!nanoid) ({ nanoid } = await import('nanoid'))\n    return nanoid() // => \"V1StGXR8_Z5jdHi6B-myT\"\n  }\n  ```\n\n- Или можно просто взять Nano ID 3.x (мы его всё ещё поддерживаем):\n\n  ```bash\n  npm install nanoid@3\n  ```\n\n### JSR\n\n[JSR](https://jsr.io) это замена npm с открытым управлением\nи активной разработкой (в отличие от npm).\n\n```bash\nnpx jsr add @sitnik/nanoid\n```\n\nВы можете использовать пакет с JSR в Node.js, Deno, Bun.\n\n```js\n// Replace `nanoid` to `@sitnik/nanoid` in all imports\nimport { nanoid } from '@sitnik/nanoid'\n```\n\nДля Deno установите через `deno add jsr:@sitnik/nanoid`\nили импортируйте `jsr:@sitnik/nanoid`.\n\n\n### CDN\n\nДля быстрого прототипирования вы можете подключить Nano ID с CDN без установки.\nНе используйте этот способ на реальном сайте, так как он сильно бьёт\nпо скорости загрузки сайта.\n\n```js\nimport { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'\n```\n\n\n## API\n\nNano ID разделён на два модуля: стандартный и небезопасный.\n\nПо умолчанию используются символы, безопасные для URL (`A-Za-z0-9_-`).\nДлина ID по умолчанию — 21 символ\n(чтобы вероятность коллизий была соизмеримой с UUID v4).\n\n\n### Блокирующий\n\nБезопасный и простой в использовании способ использования Nano ID.\n\nИз-за особенностей работы генератора случайных чисел при использовании этого\nспособа ЦПУ может иногда простаивать без работы.\n\n```js\nimport { nanoid } from 'nanoid'\nmodel.id = nanoid() //=> \"V1StGXR8_Z5jdHi6B-myT\"\n```\n\nФункция также принимает необязательный аргумент, задающий длину ID:\n\n```js\nnanoid(10) //=> \"IRFa-VaY2b\"\n```\n\nПри изменении размера, всегда проверяйте риски\nв нашем [калькуляторе коллизий](https://zelark.github.io/nano-id-cc/).\n\n\n### Небезопасный\n\nПо умолчанию, Nano ID использует аппаратный генератор случайных чисел для\nполучения непредсказуемых ID и минимизации риска возникновения коллизий\n(повторной генерации ранее выданных ID). Но если вам не требуется устойчивость\nк подбору ID, то вы можете перейти на небезопасный генератор — это полезно\nтам, где нет доступа к API аппаратного генератора случайных чисел.\n\n```js\nimport { nanoid } from 'nanoid/non-secure'\nconst id = nanoid() //=> \"Uakgb_J5m9g-0JDMbcJqLJ\"\n```\n\nНо учтите, что предсказуемость ID может быть использована для атаки на систему.\n\n\n### Смена алфавита или длины\n\nФункция `customAlphabet` позволяет создать свою функцию `nanoid`\nс нужным вам алфавитом и длиной ID.\n\n```js\nimport { customAlphabet } from 'nanoid'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nuser.id = nanoid() //=> \"4f90d13a42\"\n```\n\n```js\nimport { customAlphabet } from 'nanoid/non-secure'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nuser.id = nanoid()\n```\n\nНе забудьте проверить риски коллизии вашего алфавита и длины\n[на нашем калькуляторе]. [`nanoid-dictionary`] содержит много популярных\nпримеров альтернативных алфавитов.\n\nАлфавит должен содержать ≤256 символов. Иначе мы не сможем гарантировать\nнепредсказуемость ID.\n\nДлину ID можно менять не только в `customAlphabet()`, но и при вызове\nгенератора, который она вернёт:\n\n```js\nimport { customAlphabet } from 'nanoid'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nmodel.id = nanoid(5) //=> \"f01a2\"\n```\n\n[на нашем калькуляторе]: https://zelark.github.io/nano-id-cc/\n[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary\n\n\n### Смена генератора случайных чисел\n\nФункция `customRandom` позволяет создать свою функцию `nanoid` со своими\nгенераторами случайных чисел, алфавитом и длинной ID.\n\nНапример, можно использовать генератор c seed для повторяемости тестов.\n\n```js\nimport { customRandom } from 'nanoid'\n\nconst rng = seedrandom(seed)\nconst nanoid = customRandom('abcdef', 10, size => {\n  return new Uint8Array(size).map(() => 256 * rng())\n})\n\nnanoid() //=> \"fbaefaadeb\"\n```\n\nФункция в третьем аргументе `customRandom` должна принимать длину массива\nи возвращать нужный массив со случайными числами\n\nЕсли вы хотите заменить только генератор случайных чисел, но оставить\nURL-совместимый алфавит, то стандартный алфавит доступен\nв экспорте `urlAlphabet`.\n\n```js\nconst { customRandom, urlAlphabet } = require('nanoid')\nconst nanoid = customRandom(urlAlphabet, 10, random)\n```\n\n\n## Руководство\n\n### React\n\nНе используйте Nano ID для генерации свойства `key` в JSX. При каждом рендере\n`key` будет разный, что плохо скажется на производительности.\n\n```jsx\nfunction Todos({ todos }) {\n  return (\n    <ul>\n      {todos.map(todo => (\n        <li key={nanoid()}> /* НЕ ДЕЛАЙТЕ ТАК */\n          {todo.text}\n        </li>\n      ))}\n    </ul>\n  )\n}\n```\n\nДля связи `<input>` и `<label>` лучше использовать [`useId`],\nкоторый был добавлен в React 18.\n\n[`useId`]: https://react.dev/reference/react/useId\n\n\n### React Native\n\nReact Native не имеет встроенного аппаратного генератора случайных чисел.\nПолифил ниже работает в чистом React Native и в Expo начиная с версии 39.\n\n1. Прочитайте документацию [`react-native-get-random-values`] и установите его.\n2. Импортируйте эту библиотеку до импорта Nano ID.\n\n```js\nimport 'react-native-get-random-values'\nimport { nanoid } from 'nanoid'\n```\n\n[`react-native-get-random-values`]: https://github.com/LinusU/react-native-get-random-values\n\n\n### PouchDB и CouchDB\n\nВ PouchDB и CouchDB, ID не могут начинаться с `_`. Добавьте к ID префикс,\nтак как иногда Nano ID может сгенерировать ID начинающийся с `_`.\n\nИзменить стандартный ID можно через следующую опцию:\n\n```js\ndb.put({\n  _id: 'id' + nanoid(),\n  …\n})\n```\n\n\n### Терминал\n\nМожно сгенерировать уникальный ID прямо из терминала, вызвав `npx nanoid`.\nДля этого в системе должна быть только Node.js. `npx` сама скачает Nano ID,\nесли его нет в системе.\n\n```sh\n$ npx nanoid\nnpx: installed 1 in 0.63s\nLZfXLFzPPR4NNrgjlWDxn\n```\n\nДлину генерируемых ID можно передать в аргументе `--size` (или `-s`):\n\n```sh\n$ npx nanoid --size 10\nL3til0JS4z\n```\n\nИзменить алфавит можно при помощи аргумента `--alphabet` (ли `-a`)\n(в этом случае `--size` обязателен):\n\n```sh\n$ npx nanoid --alphabet abc --size 15\nbccbcabaabaccab\n```\n\n### TypeScript\n\nNano ID позволяет приводить сгенерированные строки к непрозрачным строкам в\nTypeScript. Например:\n\n```ts\ndeclare const userIdBrand: unique symbol\ntype UserId = string & { [userIdBrand]: true }\n\n// Используйте явный параметр типа:\nmockUser(nanoid<UserId>())\n\ninterface User {\n  id: UserId\n  name: string\n}\n\nconst user: User = {\n  // Автоматически приводится к типу UserId:\n  id: nanoid(),\n  name: 'Alice'\n}\n```\n\n### Другие языки программирования\n\nNano ID был портирован на множество языков. Это полезно, чтобы сервер и клиент\nгенерировали ID по одной схеме.\n\n- [C#](https://github.com/codeyu/nanoid-net)\n- [C++](https://github.com/mcmikecreations/nanoid_cpp)\n- [Clojure и ClojureScript](https://github.com/zelark/nano-id)\n- [ColdFusion/CFML](https://github.com/JamoCA/cfml-nanoid)\n- [Crystal](https://github.com/mamantoha/nanoid.cr)\n- [Dart и Flutter](https://github.com/pd4d10/nanoid-dart)\n- [Elixir](https://github.com/railsmechanic/nanoid)\n- [Gleam](https://github.com/0xca551e/glanoid)\n- [Go](https://github.com/jaevor/go-nanoid)\n- [Haskell](https://github.com/MichelBoucey/NanoID)\n- [Haxe](https://github.com/flashultra/uuid)\n- [Janet](https://sr.ht/~statianzo/janet-nanoid/)\n- [Java](https://github.com/wosherco/jnanoid-enhanced)\n- [Kotlin](https://github.com/viascom/nanoid-kotlin)\n- [MySQL/MariaDB](https://github.com/viascom/nanoid-mysql-mariadb)\n- [Nim](https://github.com/icyphox/nanoid.nim)\n- [Perl](https://github.com/tkzwtks/Nanoid-perl)\n- [PHP](https://github.com/hidehalo/nanoid-php)\n- [Python](https://github.com/puyuan/py-nanoid)\n  со [словарями](https://pypi.org/project/nanoid-dictionary)\n- Postgres: [Rust-расширение](https://github.com/spa5k/uids-postgres)\n  и [на чисто pgSQL](https://github.com/viascom/nanoid-postgres)\n- [R](https://github.com/hrbrmstr/nanoid) (со словарями)\n- [Ruby](https://github.com/radeno/nanoid.rb)\n- [Rust](https://github.com/nikolay-govorov/nanoid)\n- [Swift](https://github.com/ShivaHuang/swift-nanoid)\n- [Unison](https://share.unison-lang.org/latest/namespaces/hojberg/nanoid)\n- [V](https://github.com/invipal/nanoid)\n- [Zig](https://github.com/SasLuca/zig-nanoid)\n\nДля остальных сред можно использовать Nano ID [для терминала].\n\n[для терминала]: #терминал\n\n\n## Инструменты\n\n- [Калькулятор длины ID] поможет подобрать оптимальную длину ID,\n  в зависимости от частоты выдачи ID и нужной надёжности системы.\n- [`nanoid-dictionary`] с популярными алфавитами для [`customAlphabet`].\n- [`nanoid-good`] гарантирует, что в случайном ID не будет матерных слов.\n\n[калькулятор длины id]: https://zelark.github.io/nano-id-cc/\n[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary\n[`customalphabet`]: #смена-алфавита-или-длины\n[`nanoid-good`]: https://github.com/y-gagar1n/nanoid-good\n"
  },
  {
    "path": "README.zh-CN.md",
    "content": "# Nano ID\n\n<img src=\"https://ai.github.io/nanoid/logo.svg\" align=\"right\"\n     alt=\"Nano ID logo by Anton Lovchikov\" width=\"180\" height=\"94\">\n\n[English](./README.md) | [日本語](./README.ja.md) | [Русский](./README.ru.md) | **简体中文** | [Bahasa Indonesia](./README.id-ID.md) | [한국어](./README.ko.md) | [العربية](./README.ar.md)\n\n一个小巧、安全、URL友好、唯一的 JavaScript 字符串ID生成器。\n\n> “一个惊人的无意义的完美主义水平，这简直让人无法不敬佩。”\n\n* **小巧.** 118字节 (经过压缩和Brotli处理)。没有依赖。[Size Limit] 控制大小。\n* **安全.** 它使用硬件随机生成器。可在集群中使用。\n* **紧凑.** 它使用比 UUID（`A-Za-z0-9_-`）更大的字母表。因此，ID 大小从36个符号减少到21个符号。\n* **可移植.** Nano ID 已被移植到 [20种编程语言](#其他编程语言)。\n\n```js\nimport { nanoid } from 'nanoid'\nmodel.id = nanoid() //=> \"V1StGXR8_Z5jdHi6B-myT\"\n```\n\n支持现代浏览器、IE [需使用 Babel]、Node.js 和 React Native。\n\n[在线工具]: https://gitpod.io/#https://github.com/ai/nanoid/\n[使用 Babel]:  https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/\n[Size Limit]:  https://github.com/ai/size-limit\n\n---\n\n<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>.\n\n---\n\n## 目录\n\n- [目录](#目录)\n- [与 UUID 的比较](#与-uuid-的比较)\n- [基准值](#基准值)\n- [安全性](#安全性)\n- [安装](#安装)\n- [API](#api)\n  - [阻塞](#阻塞)\n  - [不安全](#不安全)\n  - [自定义字母或大小](#自定义字母或大小)\n  - [自定义随机字节生成器](#自定义随机字节生成器)\n- [用法](#用法)\n  - [React](#react)\n  - [React Native](#react-native)\n  - [PouchDB and CouchDB](#pouchdb-and-couchdb)\n  - [CLI](#cli)\n  - [TypeScript](#typescript)\n  - [其他编程语言](#其他编程语言)\n- [工具](#工具)\n\n\n## 与 UUID 的比较\n\nNano ID 与 UUID v4 (基于随机数) 相当。\n它们在 ID 中有相似数量的随机位\n(Nano ID 为126，UUID 为122),因此它们的碰撞概率相似：:\n\n> 要想有十亿分之一的重复机会,\n> 必须产生103万亿个版本4的ID.\n\nNano ID 和 UUID v4之间有两个主要区别:\n\n1. Nano ID 使用更大的字母表，所以类似数量的随机位\n   被包装在21个符号中，而不是36个。\n2. Nano ID 代码比 `uuid/v4` 包少 **4倍**: 118字节而不是423字节.\n\n\n## 基准值\n\n```rust\n$ node ./test/benchmark.js\ncrypto.randomUUID          7,619,041 ops/sec\nuuid v4                    7,436,626 ops/sec\n@napi-rs/uuid              4,730,614 ops/sec\nuid/secure                 4,729,185 ops/sec\n@lukeed/uuid               4,015,673 ops/sec\nnanoid                     3,693,964 ops/sec\ncustomAlphabet             2,799,255 ops/sec\nnanoid for browser           380,915 ops/sec\nsecure-random-string         362,316 ops/sec\nuid-safe.sync                354,234 ops/sec\nshortid                       38,808 ops/sec\n\nNon-secure:\nuid                       11,872,105 ops/sec\nnanoid/non-secure          2,226,483 ops/sec\nrndm                       2,308,044 ops/sec\n```\n\n测试配置: Framework 13 7840U, Fedora 39, Node.js 21.6.\n\n\n## 安全性\n\n*请看一篇关于随机生成器理论的好文章:\n[安全的随机值 (在 Node.js 中)]*\n\n* **不可预测性.** 不使用不安全的 `Math.random()`, Nano ID\n  使用 Node.js 的 `crypto` 模块和浏览器的 Web Crypto API。\n  这些模块使用不可预测的硬件随机生成器。\n* **统一性.** `random % alphabet` 是编写ID生成器时常犯的一个错误。\n  这样做会导致分布不均匀; 一些符号出现的机会较其他符号低。因此，在暴力破解时，尝试的次数会减少。\n  Nano ID 使用了一种 [更好的算法]，并进行了一致性测试。\n\n  <img src=\"img/distribution.png\" alt=\"Nano ID uniformity\"\n     width=\"340\" height=\"135\">\n\n* **有据可查:** 所有的 Nano ID 的行为都有记录。\n  见 [源代码] 中的注释。\n* **漏洞:** 报告安全漏洞，请使用\n  [安全联系人 Tidelift](https://tidelift.com/security).\n  Tidelift 将协调修复和披露。\n\n[安全的随机值 (在 Node.js 中)]: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba\n[更好的算法]:                  https://github.com/ai/nanoid/blob/main/index.js\n[源代码]:                     https://github.com/ai/nanoid/blob/main/index.js\n\n\n## 安装\n\n```bash\nnpm install nanoid\n```\n\nNano ID 5 仅适用于 ESM 项目、测试或 Node.js 脚本。\n对于 CommonJS，您需要 Nano ID 3.x（我们仍然支持它）：\n\n```bash\nnpm install nanoid@3\n```\n\n想要快速上手尝试，你可以从 CDN 加载 Nano ID。但是，它不建议\n在生产中使用，因为它的加载性能较低。\n\n```js\nimport { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'\n```\n\n\n## API\n\nNano ID 有2个 API：正常(阻塞)，和不安全。\n\n默认情况下，Nano ID 使用 URL 友好的符号（`A-Za-z0-9_-`）并返回一个\n有21个字符（类似 UUID v4 的碰撞概率）的 ID。\n\n\n### 阻塞\n\n使用 Nano ID 最安全、最简单的方法\n\n在极少数情况下，当收集硬件随机生成器的噪声时，可能会阻塞CPU，导致无法进行其他工作。\n\n```js\nimport { nanoid } from 'nanoid'\nmodel.id = nanoid() //=> \"V1StGXR8_Z5jdHi6B-myT\"\n```\n\n如果你想要减小 ID 大小（但是会增加碰撞概率），\n可以将大小作为参数传递\n\n```js\nnanoid(10) //=> \"IRFa-VaY2b\"\n```\n\n别忘了在我们的 [ID 碰撞概率] 计算器中检查你的 ID 大小的安全性。\n\n您也可以使用 [自定义字母表](#自定义字母或大小)\n或者是 [自定义生成器](#自定义随机字节生成器).\n\n[ID 碰撞概率]: https://zelark.github.io/nano-id-cc/\n\n\n### 不安全\n\n默认情况下，Nano ID 使用硬件随机字节生成以提供安全性和较低的碰撞概率。如果您对安全性不太担心，您可以在没有硬件随机生成器的环境中使用它\n\n```js\nimport { nanoid } from 'nanoid/non-secure'\nconst id = nanoid() //=> \"Uakgb_J5m9g-0JDMbcJqLJ\"\n```\n\n\n### 自定义字母或大小\n\n`customAlphabet` 返回一个函数，允许您使用自定义字母表和ID大小创建 `nanoid`。\n\n```js\nimport { customAlphabet } from 'nanoid'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nmodel.id = nanoid() //=> \"4f90d13a42\"\n```\n\n```js\nimport { customAlphabet } from 'nanoid/non-secure'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nuser.id = nanoid()\n```\n\n在我们的 [ID 碰撞概率] 计算器中检查您的自定义字母表和 ID 大小的安全性。\n查看 [`nanoid-dictionary`] 中的选项以获取更多字母表。\n\n字母表必须包含256个或更少的符号。\n否则，无法保证内部生成器算法的安全性。\n\n除了设置默认大小外，您还可以在调用函数时更改ID大小：\n\n```js\nimport { customAlphabet } from 'nanoid'\nconst nanoid = customAlphabet('1234567890abcdef', 10)\nmodel.id = nanoid(5) //=> \"f01a2\"\n```\n\n[ID collision probability]: https://zelark.github.io/nano-id-cc/\n[`nanoid-dictionary`]:      https://github.com/CyberAP/nanoid-dictionary\n\n\n### 自定义随机字节生成器\n\n`customRandom` 允许您创建一个 `nanoid` 并替换字母表\n和默认的随机字节生成器。\n\n在此示例中，使用基于种子的生成器:\n\n```js\nimport { customRandom } from 'nanoid'\n\nconst rng = seedrandom(seed)\nconst nanoid = customRandom('abcdef', 10, size => {\n  return (new Uint8Array(size)).map(() => 256 * rng())\n})\n\nnanoid() //=> \"fbaefaadeb\"\n```\n\n`random` 回调必须接受数组大小并返回随机数的数组。\n\n如果要使用与 `customRandom` 相同的URL友好符号,\n您可以使用 `urlAlphabet` 获取默认字母表。\n\n```js\nconst { customRandom, urlAlphabet } = require('nanoid')\nconst nanoid = customRandom(urlAlphabet, 10, random)\n```\n\n请注意，在Nano ID的不同版本之间，我们可能会更改随机生成器的调用顺序。如果您正在使用基于种子的生成器，我们不能保证相同的结果。\n\n\n## 用法\n\n### React\n\n目前还没有将 nanoid 用于 React `key` prop 的正确方法\n因为它在不同的渲染中应该是一致的。\n\n```jsx\nfunction Todos({todos}) {\n  return (\n    <ul>\n      {todos.map(todo => (\n        <li key={nanoid()}> /* 不要这样做 */\n          {todo.text}\n        </li>\n      ))}\n    </ul>\n  )\n}\n```\n\n您应该尝试在列表项中找到稳定的 id。\n\n```jsx\nconst todoItems = todos.map((todo) =>\n  <li key={todo.id}>\n    {todo.text}\n  </li>\n)\n```\n\n如果您没有稳定的 ID，您最好使用索引作为 `键` 而不是 `nanoid()`：\n\n```jsx\nconst todoItems = todos.map((text, index) =>\n  <li key={index}> /* 仍然不推荐，但优于 nanoid()。\n                      仅当项目没有稳定ID时才执行此操作。 */\n    {text}\n  </li>\n)\n```\n\n如果您只需要随机 ID 来将元素（如标签和输入字段）链接在一起，建议使用 [`useId`]。该钩子在 React 18 中添加。\n\n[`useId`]: https://react.dev/reference/react/useId\n\n\n### React Native\n\nReact Native 没有内置的随机生成器。以下polyfill适用于纯 React Native 和 Expo，从39.x版本开始生效。\n\n1. 检查 [`react-native-get-random-values`] 文档并安装它。\n2. 在 Nano ID 之前导入它。\n\n```js\nimport 'react-native-get-random-values'\nimport { nanoid } from 'nanoid'\n```\n\n[`react-native-get-random-values`]: https://github.com/LinusU/react-native-get-random-values\n\n\n### PouchDB and CouchDB\n\n在 PouchDB 和 CouchDB 中，ID 不能以下划线 `_` 开头。\n需要一个前缀来防止这个问题，因为 Nano ID 可能在默认情况下使用 `_` 作为 ID 的开头。\n在默认情况下，在 ID 的开头使用 `_`。\n\n用下面的选项覆盖默认的 ID。\n\n```js\ndb.put({\n  _id: 'id' + nanoid(),\n  …\n})\n```\n\n\n### CLI\n\n你可以通过调用 `npx nanoid` 在终端获得唯一的 ID。你只需要\n在系统中安装了 Node.js。你不需要把 Nano ID 安装在任何地方。\n\n```sh\n$ npx nanoid\nnpx: installed 1 in 0.63s\nLZfXLFzPPR4NNrgjlWDxn\n```\n\n生成的ID的大小可以使用 `--size`（或 `-s` ）选项指定：\n\n```sh\n$ npx nanoid --size 10\nL3til0JS4z\n```\n\n可以使用 `--alphabet`（或 `-a` ）选项指定自定义字母表（请注意，这种情况下需要 `--size` 选项）。\n\n```sh\n$ npx nanoid --alphabet abc --size 15\nbccbcabaabaccab\n```\n\n### TypeScript\n\nNano ID 允许将生成的字符串转换为 TypeScript 中的不透明字符串。 例如：\n\n```ts\ndeclare const userIdBrand: unique symbol\ntype UserId = string & { [userIdBrand]: true }\n\n// 使用显式类型参数:\nmockUser(nanoid<UserId>())\n\ninterface User {\n  id: UserId\n  name: string\n}\n\nconst user: User = {\n  // 自动转换为 UserId:\n  id: nanoid(),\n  name: 'Alice'\n}\n```\n\n### 其他编程语言\n\nNano ID 已被移植到许多语言。 你可以使用下面这些移植，获取在客户端和服务器端相同的ID生成器。\n\n* [C#](https://github.com/codeyu/nanoid-net)\n* [C++](https://github.com/mcmikecreations/nanoid_cpp)\n* [Clojure and ClojureScript](https://github.com/zelark/nano-id)\n* [ColdFusion/CFML](https://github.com/JamoCA/cfml-nanoid)\n* [Crystal](https://github.com/mamantoha/nanoid.cr)\n* [Dart & Flutter](https://github.com/pd4d10/nanoid-dart)\n* [Deno](https://github.com/ianfabs/nanoid)\n* [Elixir](https://github.com/railsmechanic/nanoid)\n* [Gleam](https://github.com/0xca551e/glanoid)\n* [Go](https://github.com/jaevor/go-nanoid)\n* [Haskell](https://github.com/MichelBoucey/NanoID)\n* [Haxe](https://github.com/flashultra/uuid)\n* [Janet](https://sr.ht/~statianzo/janet-nanoid/)\n* [Java](https://github.com/wosherco/jnanoid-enhanced)\n* [Kotlin](https://github.com/viascom/nanoid-kotlin)\n* [MySQL/MariaDB](https://github.com/viascom/nanoid-mysql-mariadb)\n* [Nim](https://github.com/icyphox/nanoid.nim)\n* [Perl](https://github.com/tkzwtks/Nanoid-perl)\n* [PHP](https://github.com/hidehalo/nanoid-php)\n* [Python](https://github.com/puyuan/py-nanoid)\n  with [dictionaries](https://pypi.org/project/nanoid-dictionary)\n* [Postgres Extension](https://github.com/spa5k/uids-postgres)\n* [Postgres Native Function](https://github.com/viascom/nanoid-postgres)\n* [R](https://github.com/hrbrmstr/nanoid) (with dictionaries)\n* [Ruby](https://github.com/radeno/nanoid.rb)\n* [Rust](https://github.com/nikolay-govorov/nanoid)\n* [Swift](https://github.com/ShivaHuang/swift-nanoid)\n* [Unison](https://share.unison-lang.org/latest/namespaces/hojberg/nanoid)\n* [V](https://github.com/invipal/nanoid)\n* [Zig](https://github.com/SasLuca/zig-nanoid)\n\n此外，[CLI] 还可用于从命令行生成 ID。\n\n[CLI]: #cli\n\n\n## 工具\n\n* [ID size 计算器] 显示调整时的碰撞概率\n  ID的字母或大小。\n* [`nanoid-dictionary`] 与常用的字母一起使用 [`自定义字母`]。\n* [`nanoid-good`] 以确保你的ID不包含任何淫秽词汇。\n\n[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary\n[ID size 计算器]:  https://zelark.github.io/nano-id-cc/\n[`自定义字母`]:    #自定义字母或大小\n[`nanoid-good`]:       https://github.com/y-gagar1n/nanoid-good\n"
  },
  {
    "path": "bin/nanoid.js",
    "content": "#!/usr/bin/env node\n\nimport { readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nimport { customAlphabet, nanoid } from '../index.js'\n\nfunction print(msg) {\n  process.stdout.write(msg + '\\n')\n}\n\nfunction error(msg) {\n  process.stderr.write(msg + '\\n')\n  process.exit(1)\n}\n\nif (process.argv.includes('--version') || process.argv.includes('-v')) {\n  let root = dirname(fileURLToPath(import.meta.url))\n  let pkg = JSON.parse(readFileSync(join(root, '..', 'package.json'), 'utf8'))\n  print(pkg.version)\n  process.exit()\n}\n\nif (process.argv.includes('--help') || process.argv.includes('-h')) {\n  print(`Usage\n  $ nanoid [options]\n\nOptions\n  -s, --size       Generated ID size\n  -a, --alphabet   Alphabet to use\n  -v, --version    Show version number\n  -h, --help       Show this help\n\nExamples\n  $ nanoid -s 15\n  S9sBF77U6sDB8Yg\n\n  $ nanoid --size 10 --alphabet abc\n  bcabababca`)\n  process.exit()\n}\n\nlet alphabet, size\nfor (let i = 2; i < process.argv.length; i++) {\n  let arg = process.argv[i]\n  if (arg === '--size' || arg === '-s') {\n    size = Number(process.argv[i + 1])\n    i += 1\n    if (Number.isNaN(size) || size <= 0) {\n      error('Size must be positive integer')\n    }\n  } else if (arg === '--alphabet' || arg === '-a') {\n    alphabet = process.argv[i + 1]\n    i += 1\n  } else {\n    error('Unknown argument ' + arg)\n  }\n}\n\nif (alphabet) {\n  let customNanoid = customAlphabet(alphabet, size)\n  print(customNanoid())\n} else {\n  print(nanoid(size))\n}\n"
  },
  {
    "path": "eslint.config.js",
    "content": "import loguxConfig from '@logux/eslint-config'\n\n/** @type {import('eslint').Linter.FlatConfig[]} */\nexport default [\n  { ignores: ['test/demo/build', 'nanoid.js'] },\n  ...loguxConfig,\n  {\n    rules: {\n      'n/no-unsupported-features/node-builtins': 'off'\n    }\n  }\n]\n"
  },
  {
    "path": "index.browser.js",
    "content": "/* @ts-self-types=\"./index.d.ts\" */\n\n// This file replaces `index.js` in bundlers like webpack or Rollup,\n// according to `browser` config in `package.json`.\n\nimport { urlAlphabet as scopedUrlAlphabet } from './url-alphabet/index.js'\n\nexport { urlAlphabet } from './url-alphabet/index.js'\n\nexport let random = bytes => crypto.getRandomValues(new Uint8Array(bytes))\n\nexport let customRandom = (alphabet, defaultSize, getRandom) => {\n  // First, a bitmask is necessary to generate the ID. The bitmask makes bytes\n  // values closer to the alphabet size. The bitmask calculates the closest\n  // `2^31 - 1` number, which exceeds the alphabet size.\n  // For example, the bitmask for the alphabet size 30 is 31 (00011111).\n  // `Math.clz32` is not used, because it is not available in browsers.\n  let mask = (2 << Math.log2(alphabet.length - 1)) - 1\n  // Though, the bitmask solution is not perfect since the bytes exceeding\n  // the alphabet size are refused. Therefore, to reliably generate the ID,\n  // the random bytes redundancy has to be satisfied.\n\n  // Note: every hardware random generator call is performance expensive,\n  // because the system call for entropy collection takes a lot of time.\n  // So, to avoid additional system calls, extra bytes are requested in advance.\n\n  // Next, a step determines how many random bytes to generate.\n  // The number of random bytes gets decided upon the ID size, mask,\n  // alphabet size, and magic number 1.6 (using 1.6 peaks at performance\n  // according to benchmarks).\n\n  // `-~f => Math.ceil(f)` if f is a float\n  // `-~i => i + 1` if i is an integer\n  let step = -~((1.6 * mask * defaultSize) / alphabet.length)\n\n  return (size = defaultSize) => {\n    let id = ''\n    while (true) {\n      let bytes = getRandom(step)\n      // A compact alternative for `for (var i = 0; i < step; i++)`.\n      let j = step | 0\n      while (j--) {\n        // Adding `|| ''` refuses a random byte that exceeds the alphabet size.\n        id += alphabet[bytes[j] & mask] || ''\n        if (id.length >= size) return id\n      }\n    }\n  }\n}\n\nexport let customAlphabet = (alphabet, size = 21) =>\n  customRandom(alphabet, size | 0, random)\n\nexport let nanoid = (size = 21) => {\n  let id = ''\n  let bytes = crypto.getRandomValues(new Uint8Array((size |= 0)))\n  while (size--) {\n    // Using the bitwise AND operator to \"cap\" the value of\n    // the random byte from 255 to 63, in that way we can make sure\n    // that the value will be a valid index for the \"chars\" string.\n    id += scopedUrlAlphabet[bytes[size] & 63]\n  }\n  return id\n}\n"
  },
  {
    "path": "index.d.ts",
    "content": "/**\n * A tiny, secure, URL-friendly, unique string ID generator for JavaScript\n * with hardware random generator.\n *\n * ```js\n * import { nanoid } from 'nanoid'\n * model.id = nanoid() //=> \"V1StGXR8_Z5jdHi6B-myT\"\n * ```\n *\n * @module\n */\n\n/**\n * Generate secure URL-friendly unique ID.\n *\n * By default, the ID will have 21 symbols to have a collision probability\n * similar to UUID v4.\n *\n * ```js\n * import { nanoid } from 'nanoid'\n * model.id = nanoid() //=> \"Uakgb_J5m9g-0JDMbcJqL\"\n * ```\n *\n * @param size Size of the ID. The default size is 21.\n * @typeparam Type The ID type to replace `string` with some opaque type.\n * @returns A random string.\n */\nexport function nanoid<Type extends string>(size?: number): Type\n\n/**\n * Generate secure unique ID with custom alphabet.\n *\n * Alphabet must contain 256 symbols or less. Otherwise, the generator\n * will not be secure.\n *\n * @param alphabet Alphabet used to generate the ID.\n * @param defaultSize Size of the ID. The default size is 21.\n * @typeparam Type The ID type to replace `string` with some opaque type.\n * @returns A random string generator.\n *\n * ```js\n * import { customAlphabet } from 'nanoid'\n * const nanoid = customAlphabet('0123456789абвгдеё', 5)\n * nanoid() //=> \"8ё56а\"\n * ```\n */\nexport function customAlphabet<Type extends string>(\n  alphabet: string,\n  defaultSize?: number\n): (size?: number) => Type\n\n/**\n * Generate unique ID with custom random generator and alphabet.\n *\n * Alphabet must contain 256 symbols or less. Otherwise, the generator\n * will not be secure.\n *\n * ```js\n * import { customRandom } from 'nanoid'\n *\n * const nanoid = customRandom('abcdef', 5, size => {\n *   const random = []\n *   for (let i = 0; i < size; i++) {\n *     random.push(randomByte())\n *   }\n *   return random\n * })\n *\n * nanoid() //=> \"fbaef\"\n * ```\n *\n * @param alphabet Alphabet used to generate a random string.\n * @param size Size of the random string.\n * @param random A random bytes generator.\n * @typeparam Type The ID type to replace `string` with some opaque type.\n * @returns A random string generator.\n */\nexport function customRandom<Type extends string>(\n  alphabet: string,\n  size: number,\n  random: (bytes: number) => Uint8Array\n): (size?: number) => Type\n\n/**\n * URL safe symbols.\n *\n * ```js\n * import { urlAlphabet } from 'nanoid'\n * const nanoid = customAlphabet(urlAlphabet, 10)\n * nanoid() //=> \"Uakgb_J5m9\"\n * ```\n */\nexport const urlAlphabet: string\n\n/**\n * Generate an array of random bytes collected from hardware noise.\n *\n * ```js\n * import { customRandom, random } from 'nanoid'\n * const nanoid = customRandom(\"abcdef\", 5, random)\n * ```\n *\n * @param bytes Size of the array.\n * @returns An array of random bytes.\n */\nexport function random(bytes: number): Uint8Array\n"
  },
  {
    "path": "index.js",
    "content": "import { webcrypto as crypto } from 'node:crypto'\n\nimport { urlAlphabet as scopedUrlAlphabet } from './url-alphabet/index.js'\n\nexport { urlAlphabet } from './url-alphabet/index.js'\n\n// It is best to make fewer, larger requests to the crypto module to\n// avoid system call overhead. So, random numbers are generated in a\n// pool. The pool is a Buffer that is larger than the initial random\n// request size by this multiplier. The pool is enlarged if subsequent\n// requests exceed the maximum buffer size.\nconst POOL_SIZE_MULTIPLIER = 128\nlet pool, poolOffset\n\nfunction fillPool(bytes) {\n  if (!pool || pool.length < bytes) {\n    pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER)\n    crypto.getRandomValues(pool)\n    poolOffset = 0\n  } else if (poolOffset + bytes > pool.length) {\n    crypto.getRandomValues(pool)\n    poolOffset = 0\n  }\n  poolOffset += bytes\n}\n\nexport function random(bytes) {\n  // `|=` convert `bytes` to number to prevent `valueOf` abusing and pool pollution\n  fillPool((bytes |= 0))\n  return pool.subarray(poolOffset - bytes, poolOffset)\n}\n\nexport function customRandom(alphabet, defaultSize, getRandom) {\n  // First, a bitmask is necessary to generate the ID. The bitmask makes bytes\n  // values closer to the alphabet size. The bitmask calculates the closest\n  // `2^31 - 1` number, which exceeds the alphabet size.\n  // For example, the bitmask for the alphabet size 30 is 31 (00011111).\n  let mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1\n  // Though, the bitmask solution is not perfect since the bytes exceeding\n  // the alphabet size are refused. Therefore, to reliably generate the ID,\n  // the random bytes redundancy has to be satisfied.\n\n  // Note: every hardware random generator call is performance expensive,\n  // because the system call for entropy collection takes a lot of time.\n  // So, to avoid additional system calls, extra bytes are requested in advance.\n\n  // Next, a step determines how many random bytes to generate.\n  // The number of random bytes gets decided upon the ID size, mask,\n  // alphabet size, and magic number 1.6 (using 1.6 peaks at performance\n  // according to benchmarks).\n  let step = Math.ceil((1.6 * mask * defaultSize) / alphabet.length)\n\n  return (size = defaultSize) => {\n    if (!size) return ''\n    let id = ''\n    while (true) {\n      let bytes = getRandom(step)\n      // A compact alternative for `for (let i = 0; i < step; i++)`.\n      let i = step\n      while (i--) {\n        // Adding `|| ''` refuses a random byte that exceeds the alphabet size.\n        id += alphabet[bytes[i] & mask] || ''\n        if (id.length >= size) return id\n      }\n    }\n  }\n}\n\nexport function customAlphabet(alphabet, size = 21) {\n  return customRandom(alphabet, size, random)\n}\n\nexport function nanoid(size = 21) {\n  // `|=` convert `size` to number to prevent `valueOf` abusing and pool pollution\n  fillPool((size |= 0))\n  let id = ''\n  // We are reading directly from the random pool to avoid creating new array\n  for (let i = poolOffset - size; i < poolOffset; i++) {\n    // It is incorrect to use bytes exceeding the alphabet size.\n    // The following mask reduces the random byte in the 0-255 value\n    // range to the 0-63 value range. Therefore, adding hacks, such\n    // as empty string fallback or magic numbers, is unnecessary because\n    // the bitmask trims bytes down to the alphabet size.\n    id += scopedUrlAlphabet[pool[i] & 63]\n  }\n  return id\n}\n"
  },
  {
    "path": "jsr.json",
    "content": "{\n  \"name\": \"@sitnik/nanoid\",\n  \"version\": \"5.1.7\",\n  \"license\": \"MIT\",\n  \"exports\": {\n    \".\": \"./index.browser.js\",\n    \"./non-secure\": \"./non-secure/index.js\"\n  },\n  \"publish\": {\n    \"include\": [\n      \"LICENSE\",\n      \"README.md\",\n      \"index.d.ts\",\n      \"index.browser.js\",\n      \"non-secure/index.d.ts\",\n      \"non-secure/index.js\",\n      \"url-alphabet/index.js\"\n    ]\n  }\n}\n"
  },
  {
    "path": "nanoid.js",
    "content": "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};"
  },
  {
    "path": "non-secure/index.d.ts",
    "content": "/**\n * By default, Nano ID uses hardware random bytes generation for security\n * and low collision probability. If you are not so concerned with security,\n * you can use it for environments without hardware random generators.\n *\n * ```js\n * import { nanoid } from 'nanoid/non-secure'\n * const id = nanoid() //=> \"Uakgb_J5m9g-0JDMbcJqLJ\"\n * ```\n *\n * @module\n */\n\n/**\n * Generate URL-friendly unique ID. This method uses the non-secure\n * predictable random generator with bigger collision probability.\n *\n * ```js\n * import { nanoid } from 'nanoid/non-secure'\n * model.id = nanoid() //=> \"Uakgb_J5m9g-0JDMbcJqL\"\n * ```\n *\n * @param size Size of the ID. The default size is 21.\n * @typeparam Type The ID type to replace `string` with some opaque type.\n * @returns A random string.\n */\nexport function nanoid<Type extends string>(size?: number): Type\n\n/**\n * Generate a unique ID based on a custom alphabet.\n * This method uses the non-secure predictable random generator\n * with bigger collision probability.\n *\n * @param alphabet Alphabet used to generate the ID.\n * @param defaultSize Size of the ID. The default size is 21.\n * @typeparam Type The ID type to replace `string` with some opaque type.\n * @returns A random string generator.\n *\n * ```js\n * import { customAlphabet } from 'nanoid/non-secure'\n * const nanoid = customAlphabet('0123456789абвгдеё', 5)\n * model.id = nanoid() //=> \"8ё56а\"\n * ```\n */\nexport function customAlphabet<Type extends string>(\n  alphabet: string,\n  defaultSize?: number\n): (size?: number) => Type\n"
  },
  {
    "path": "non-secure/index.js",
    "content": "/* @ts-self-types=\"./index.d.ts\" */\n\n// This alphabet uses `A-Za-z0-9_-` symbols.\n// The order of characters is optimized for better gzip and brotli compression.\n// References to the same file (works both for gzip and brotli):\n// `'use`, `andom`, and `rict'`\n// References to the brotli default dictionary:\n// `-26T`, `1983`, `40px`, `75px`, `bush`, `jack`, `mind`, `very`, and `wolf`\nlet urlAlphabet =\n  'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'\n\nexport let customAlphabet = (alphabet, defaultSize = 21) => {\n  return (size = defaultSize) => {\n    let id = ''\n    // A compact alternative for `for (var i = 0; i < step; i++)`.\n    let i = size | 0\n    while (i--) {\n      // `| 0` is more compact and faster than `Math.floor()`.\n      id += alphabet[(Math.random() * alphabet.length) | 0]\n    }\n    return id\n  }\n}\n\nexport let nanoid = (size = 21) => {\n  let id = ''\n  // A compact alternative for `for (var i = 0; i < step; i++)`.\n  let i = size | 0\n  while (i--) {\n    // `| 0` is more compact and faster than `Math.floor()`.\n    id += urlAlphabet[(Math.random() * 64) | 0]\n  }\n  return id\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"nanoid\",\n  \"version\": \"5.1.7\",\n  \"description\": \"A tiny (118 bytes), secure URL-friendly unique string ID generator\",\n  \"keywords\": [\n    \"uuid\",\n    \"random\",\n    \"id\",\n    \"url\"\n  ],\n  \"scripts\": {\n    \"clean\": \"rm -rf coverage\",\n    \"start\": \"vite --host 0.0.0.0 test/demo/\",\n    \"test:coverage\": \"c8 bnt\",\n    \"test:lint\": \"eslint .\",\n    \"test:size\": \"pnpm clean && size-limit\",\n    \"test:versions\": \"node ./test/check-versions.js\",\n    \"test:prebuild\": \"node ./test/check-prebuild.js\",\n    \"test\": \"pnpm run /^test:/\"\n  },\n  \"type\": \"module\",\n  \"engines\": {\n    \"node\": \"^18 || >=20\"\n  },\n  \"funding\": [\n    {\n      \"type\": \"github\",\n      \"url\": \"https://github.com/sponsors/ai\"\n    }\n  ],\n  \"author\": \"Andrey Sitnik <andrey@sitnik.ru>\",\n  \"license\": \"MIT\",\n  \"repository\": \"ai/nanoid\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./index.d.ts\",\n      \"browser\": \"./index.browser.js\",\n      \"react-native\": \"./index.browser.js\",\n      \"default\": \"./index.js\"\n    },\n    \"./non-secure\": {\n      \"types\": \"./non-secure/index.d.ts\",\n      \"default\": \"./non-secure/index.js\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"browser\": {\n    \"./index.js\": \"./index.browser.js\"\n  },\n  \"react-native\": {\n    \"./index.js\": \"./index.browser.js\"\n  },\n  \"bin\": \"./bin/nanoid.js\",\n  \"sideEffects\": false,\n  \"types\": \"./index.d.ts\",\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.29.0\",\n    \"@logux/eslint-config\": \"^57.1.0\",\n    \"@lukeed/uuid\": \"^2.0.1\",\n    \"@napi-rs/uuid\": \"^0.2.2\",\n    \"@originjs/vite-plugin-commonjs\": \"^1.0.3\",\n    \"@size-limit/file\": \"^12.0.1\",\n    \"@size-limit/webpack\": \"^12.0.1\",\n    \"@types/node\": \"^25.5.0\",\n    \"actions-up\": \"^1.12.0\",\n    \"better-node-test\": \"^0.8.3\",\n    \"c8\": \"^11.0.0\",\n    \"clean-publish\": \"^6.0.4\",\n    \"eslint\": \"^10.0.3\",\n    \"rndm\": \"^1.2.0\",\n    \"secure-random-string\": \"^1.1.4\",\n    \"shortid\": \"^2.2.17\",\n    \"simple-git-hooks\": \"^2.13.1\",\n    \"size-limit\": \"^12.0.1\",\n    \"terser\": \"^5.46.0\",\n    \"tinybench\": \"^6.0.0\",\n    \"uid\": \"^2.0.2\",\n    \"uid-safe\": \"^2.1.5\",\n    \"uuid\": \"^13.0.0\",\n    \"vite\": \"^8.0.0\"\n  },\n  \"size-limit\": [\n    {\n      \"name\": \"nanoid\",\n      \"import\": \"{ nanoid }\",\n      \"limit\": \"118 B\"\n    },\n    {\n      \"name\": \"customAlphabet\",\n      \"import\": \"{ customAlphabet }\",\n      \"limit\": \"165 B\"\n    },\n    {\n      \"name\": \"urlAlphabet\",\n      \"import\": \"{ urlAlphabet }\",\n      \"limit\": \"47 B\"\n    },\n    {\n      \"name\": \"non-secure nanoid\",\n      \"import\": \"{ nanoid }\",\n      \"path\": \"non-secure/index.js\",\n      \"limit\": \"90 B\"\n    },\n    {\n      \"name\": \"non-secure customAlphabet\",\n      \"import\": \"{ customAlphabet }\",\n      \"path\": \"non-secure/index.js\",\n      \"limit\": \"53 B\"\n    }\n  ],\n  \"prettier\": {\n    \"arrowParens\": \"avoid\",\n    \"jsxSingleQuote\": false,\n    \"quoteProps\": \"consistent\",\n    \"semi\": false,\n    \"singleQuote\": true,\n    \"trailingComma\": \"none\"\n  },\n  \"clean-publish\": {\n    \"cleanDocs\": true,\n    \"cleanComments\": true\n  },\n  \"c8\": {\n    \"exclude\": [\n      \"bin/nanoid.js\",\n      \"**/*.test.*\",\n      \"test/*\"\n    ],\n    \"lines\": 100,\n    \"check-coverage\": true,\n    \"reporter\": [\n      \"text\",\n      \"lcov\"\n    ],\n    \"skip-full\": true,\n    \"clean\": true\n  },\n  \"simple-git-hooks\": {\n    \"pre-commit\": \"./test/check-versions.js\"\n  },\n  \"pnpm\": {\n    \"ignoredBuiltDependencies\": [\n      \"esbuild\",\n      \"unrs-resolver\"\n    ],\n    \"onlyBuiltDependencies\": [\n      \"simple-git-hooks\"\n    ]\n  }\n}\n"
  },
  {
    "path": "test/benchmark.js",
    "content": "#!/usr/bin/env node\n\nimport { v4 as lukeed4 } from '@lukeed/uuid'\nimport { v4 as napiV4 } from '@napi-rs/uuid'\nimport crypto from 'node:crypto'\nimport { styleText } from 'node:util'\nimport rndm from 'rndm'\nimport srs from 'secure-random-string'\nimport shortid from 'shortid'\nimport { Bench } from 'tinybench'\nimport { uid } from 'uid'\nimport uidSafe from 'uid-safe'\nimport { uid as uidSecure } from 'uid/secure'\nimport { v4 as uuid4 } from 'uuid'\n\nimport { nanoid as browser } from '../index.browser.js'\nimport { customAlphabet, nanoid } from '../index.js'\nimport { nanoid as nonSecure } from '../non-secure/index.js'\n\nlet bench = new Bench()\n\nlet nanoid2 = customAlphabet('1234567890abcdef-', 10)\n\nbench\n  .add('crypto.randomUUID', () => {\n    crypto.randomUUID()\n  })\n  .add('uuid v4', () => {\n    uuid4()\n  })\n  .add('@napi-rs/uuid', () => {\n    napiV4()\n  })\n  .add('uid/secure', () => {\n    uidSecure(32)\n  })\n  .add('@lukeed/uuid', () => {\n    lukeed4()\n  })\n  .add('nanoid', () => {\n    nanoid()\n  })\n  .add('customAlphabet', () => {\n    nanoid2()\n  })\n  .add('nanoid for browser', () => {\n    browser()\n  })\n  .add('secure-random-string', () => {\n    srs()\n  })\n  .add('uid-safe.sync', () => {\n    uidSafe.sync(14)\n  })\n  .add('shortid', () => {\n    shortid()\n  })\n  .add('uid', () => {\n    uid(32)\n  })\n  .add('nanoid/non-secure', () => {\n    nonSecure()\n  })\n  .add('rndm', () => {\n    rndm(21)\n  })\n\nlet longestTask = bench.tasks.reduce((maxLength, task) => {\n  return Math.max(maxLength, task.name.length)\n}, 0)\n\nbench.addEventListener('cycle', ({ task }) => {\n  let hz = (+task.result.throughput.mean.toFixed(0))\n    .toLocaleString('en-US')\n    .padStart(14)\n\n  let name = task.name.padEnd(longestTask)\n  let value = styleText('bold', hz)\n  let units = styleText('dim', 'ops/sec')\n\n  if (task.name === 'uid') {\n    process.stdout.write('\\nNon-secure:\\n')\n  }\n\n  process.stdout.write(`${name}${value} ${units}\\n`)\n})\n\nawait bench.run({ warmup: true })\n"
  },
  {
    "path": "test/bin.test.js",
    "content": "import { equal, match, rejects } from 'node:assert'\nimport child from 'node:child_process'\nimport { join } from 'node:path'\nimport { describe, test } from 'node:test'\nimport { fileURLToPath } from 'node:url'\nimport { promisify } from 'node:util'\n\nlet exec = promisify(child.exec)\n\nconst BIN = join(fileURLToPath(import.meta.url), '..', '..', 'bin', 'nanoid.js')\n\ndescribe('CLI', () => {\n  test('prints unique ID', async () => {\n    let { stderr, stdout } = await exec(`node \"${BIN}\"`)\n    equal(stderr, '')\n    match(stdout, /^[\\w-]{21}\\n$/)\n  })\n\n  test('uses size', async () => {\n    let { stderr, stdout } = await exec(`node \"${BIN}\" --size 10`)\n    equal(stderr, '')\n    match(stdout, /^[\\w-]{10}\\n$/)\n  })\n\n  test('uses alphabet', async () => {\n    let { stderr, stdout } = await exec(\n      `node \"${BIN}\" --alphabet abc --size 15`\n    )\n    equal(stderr, '')\n    match(stdout, /^[abc]{15}\\n$/)\n  })\n\n  test('shows an error on unknown argument', async () => {\n    await rejects(() => exec(`node \"${BIN}\" -test`), /Unknown argument -test/)\n  })\n\n  test('shows an error if size is not a number', async () => {\n    await rejects(\n      () => exec(`node \"${BIN}\" -s abc`),\n      /Size must be positive integer/\n    )\n  })\n\n  test('requires error if size is a negative number', async () => {\n    await rejects(\n      () => exec(`node \"${BIN}\" --size \"-1\"`),\n      /Size must be positive integer/\n    )\n  })\n\n  test('displays help', async () => {\n    let { stderr, stdout } = await exec(`node \"${BIN}\" --help`)\n    equal(stderr, '')\n    match(stdout, /Usage/)\n    match(stdout, /\\$ nanoid \\[options]/)\n  })\n\n  test('displays version', async () => {\n    let { stderr, stdout } = await exec(`node \"${BIN}\" --version`)\n    equal(stderr, '')\n    match(stdout, /^\\d+\\.\\d+\\.\\d+\\n$/)\n  })\n})\n"
  },
  {
    "path": "test/check-prebuild.js",
    "content": "#!/usr/bin/env node\n\nimport { readFile } from 'node:fs/promises'\nimport { styleText } from 'node:util'\n\nimport { BUILD_PATH, prebuild } from './prebuild.ts'\n\nlet [current, expected] = await Promise.all([\n  readFile(BUILD_PATH, 'utf8'),\n  prebuild()\n])\n\nif (current !== expected) {\n  process.stderr.write(\n    styleText(\n      ['red', 'bold'],\n      'nanoid.js is outdated, run node test/update-prebuild.js'\n    ) + '\\n'\n  )\n  process.exit(1)\n}\n"
  },
  {
    "path": "test/check-versions.js",
    "content": "#!/usr/bin/env node\n\nimport { readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { styleText } from 'node:util'\n\nconst ROOT = join(import.meta.dirname, '..')\n\nlet pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8'))\nlet jsr = JSON.parse(readFileSync(join(ROOT, 'jsr.json'), 'utf8'))\n\nif (pkg.version !== jsr.version) {\n  process.stderr.write(\n    styleText(\n      ['red', 'bold'],\n      `Version mismatch: package.json has ${pkg.version}, ` +\n        `jsr.json has ${jsr.version}`\n    ) + '\\n'\n  )\n  process.exit(1)\n}\n"
  },
  {
    "path": "test/demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"UTF-8\">\n    <title>Nano ID</title>\n    <style>\n      body {\n        font-family: monospace;\n        text-align: center;\n        margin: 3rem 2rem;\n      }\n      main {\n        font-size: 120%;\n        line-height: 1.5;\n        padding-bottom: 3rem;\n      }\n      section {\n        width: 620px;\n        margin: 0 auto;\n      }\n      section + section {\n        padding-top: 1rem;\n      }\n      span {\n        float: right;\n        font-size: 90%;\n      }\n      h2 {\n        font-size: 90%;\n        font-weight: bold;\n        text-align: left;\n        margin: 0;\n        padding-bottom: 0.5rem;\n      }\n      .dot {\n        height: 1.5rem;\n        line-height: 1.5rem;\n        color: rgba(0, 0, 0, 0.5);\n        display: inline-block;\n        font-size: 70%;\n      }\n    </style>\n  </head>\n  <body>\n    <script src=\"./index.js\" type=\"module\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "test/demo/index.js",
    "content": "import shortid from 'shortid'\nimport { v4 as uuid4 } from 'uuid'\n\nimport * as nanoidExport from '../../index.browser.js'\nimport * as nonSecureExport from '../../non-secure/index.js'\n\nlet { customAlphabet, nanoid, random } = nanoidExport\nlet nonSecure = nonSecureExport.nanoid\n\nconst COUNT = 50 * 1000\nconst ALPHABET = 'abcdefghijklmnopqrstuvwxyz'\nconst LENGTH = ALPHABET.length\n\nlet nanoid2 = customAlphabet(ALPHABET, LENGTH)\n\nfunction print(number) {\n  return String(Math.floor(number * 100))\n    .replace(/\\d{6}$/, ',$&')\n    .replace(/\\d{3}$/, ',$&')\n}\n\nfunction printDistr(title, fn) {\n  let data = calcDistr(title, fn)\n  let keys = Object.keys(data.chars)\n  let length = keys.length\n  let dots = ''\n\n  let average = keys.reduce((all, l) => all + data.chars[l], 0) / length\n\n  for (let l of keys.sort()) {\n    let distribution = data.chars[l] / average\n    dots += `<div class=\"dot\" style=\"\n      background: hsl(${200 * distribution}, 100%, 50%);\n      width: ${100 / length}%;\n    \">${l}</div>`\n  }\n\n  document.body.innerHTML += `<section>\n    <span>${print((COUNT * 1000) / data.time)} ops/sec</span>\n    <h2>${data.title}</h2>\n    ${dots}\n  </section>`\n}\n\nfunction calcDistr(title, fn) {\n  let chars = {}\n\n  let ids = []\n  let j\n\n  let start = Date.now()\n  for (j = 0; j < COUNT; j++) ids.push(fn())\n  let end = Date.now()\n\n  for (j = 0; j < COUNT; j++) {\n    let id = ids[j]\n    if (title === 'uuid/v4') id = id.replace(/-./g, '')\n    for (let char of id) {\n      if (!chars[char]) chars[char] = 0\n      chars[char] += 1\n    }\n  }\n\n  return { chars, time: end - start, title }\n}\n\nlet tasks = [\n  () =>\n    printDistr('ideal', () => {\n      let result = []\n      for (let j = 0; j < LENGTH; j++) {\n        result.push(ALPHABET[j])\n      }\n      return result\n    }),\n  () => printDistr('nanoid', () => nanoid()),\n  () => printDistr('nanoid2', () => nanoid2()),\n  () => printDistr('uuid/v4', () => uuid4()),\n  () => printDistr('shortid', () => shortid()),\n  () => printDistr('nanoid/non-secure', () => nonSecure()),\n  () =>\n    printDistr('random % alphabet', () => {\n      return [...random(LENGTH)].map(i => ALPHABET[i % ALPHABET.length])\n    })\n]\n\nfunction run() {\n  if (tasks.length === 0) return\n  let task = tasks.shift()\n  task()\n  setTimeout(run, 10)\n}\n\nlet html = ''\nfor (let i = 0; i < 10; i++) {\n  html += `<div>${nanoid()}</div>`\n}\ndocument.body.innerHTML = `<main>${html}</main>`\n\nrun()\n"
  },
  {
    "path": "test/demo/vite.config.js",
    "content": "import { viteCommonjs } from '@originjs/vite-plugin-commonjs'\n\nexport default {\n  plugins: [viteCommonjs()]\n}\n"
  },
  {
    "path": "test/index.test.js",
    "content": "import { equal, match, notEqual, ok } from 'node:assert'\nimport { after, before, describe, test } from 'node:test'\n\nimport * as browser from '../index.browser.js'\nimport * as node from '../index.js'\n\nfor (let type of ['node', 'browser']) {\n  let { customAlphabet, customRandom, nanoid, random, urlAlphabet } =\n    type === 'node' ? node : browser\n\n  describe(type, () => {\n    if (type === 'browser') {\n      before(() => {\n        Object.defineProperty(global, 'crypto', {\n          configurable: true,\n          value: {\n            getRandomValues(array) {\n              for (let i = 0; i < array.length; i++) {\n                array[i] = Math.floor(Math.random() * 256)\n              }\n              return array\n            }\n          }\n        })\n      })\n\n      after(() => {\n        Object.defineProperty(global, 'crypto', { value: undefined })\n      })\n    }\n\n    test('is ready for 0 size', () => {\n      equal(nanoid(0), '')\n    })\n\n    test(`generates URL-friendly IDs`, () => {\n      for (let i = 0; i < 100; i++) {\n        let id = nanoid()\n        equal(id.length, 21)\n        equal(typeof id, 'string')\n        for (let char of id) {\n          match(urlAlphabet, new RegExp(char, 'g'))\n        }\n      }\n    })\n\n    test(`changes ID length`, () => {\n      equal(nanoid(10).length, 10)\n    })\n\n    test(`generates large IDs`, () => {\n      let id = nanoid(1000)\n      equal(id.length, 1000)\n      for (let char of id) {\n        match(urlAlphabet, new RegExp(char, 'g'))\n      }\n    })\n\n    test(`accepts string`, () => {\n      equal(nanoid('10').length, 10)\n    })\n\n    test(`has no collisions`, () => {\n      let used = {}\n      for (let i = 0; i < 50 * 1000; i++) {\n        let id = nanoid()\n        equal(used[id], undefined)\n        used[id] = true\n      }\n    })\n\n    test(`avoids pool pollution, infinite loop`, () => {\n      nanoid(2.1)\n      let second = nanoid()\n      let third = nanoid()\n      notEqual(second, third)\n    })\n\n    test(`has flat distribution`, () => {\n      let COUNT = 100 * 1000\n      let LENGTH = nanoid().length\n\n      let chars = {}\n      for (let i = 0; i < COUNT; i++) {\n        let id = nanoid()\n        for (let char of id) {\n          if (!chars[char]) chars[char] = 0\n          chars[char] += 1\n        }\n      }\n\n      equal(Object.keys(chars).length, urlAlphabet.length)\n\n      let max = 0\n      let min = Number.MAX_SAFE_INTEGER\n      for (let k in chars) {\n        let distribution = (chars[k] * urlAlphabet.length) / (COUNT * LENGTH)\n        if (distribution > max) max = distribution\n        if (distribution < min) min = distribution\n      }\n      ok(max - min <= 0.05)\n    })\n\n    test(`${type} / customAlphabet / has options`, () => {\n      let nanoidA = customAlphabet('a', 5)\n      equal(nanoidA(), 'aaaaa')\n    })\n\n    test(`${type} / customAlphabet / has flat distribution`, () => {\n      let COUNT = 50 * 1000\n      let LENGTH = 30\n      let ALPHABET = 'abcdefghijklmnopqrstuvwxyz'\n      let nanoid2 = customAlphabet(ALPHABET, LENGTH)\n\n      let chars = {}\n      for (let i = 0; i < COUNT; i++) {\n        let id = nanoid2()\n        for (let char of id) {\n          if (!chars[char]) chars[char] = 0\n          chars[char] += 1\n        }\n      }\n\n      equal(Object.keys(chars).length, ALPHABET.length)\n\n      let max = 0\n      let min = Number.MAX_SAFE_INTEGER\n      for (let k in chars) {\n        let distribution = (chars[k] * ALPHABET.length) / (COUNT * LENGTH)\n        if (distribution > max) max = distribution\n        if (distribution < min) min = distribution\n      }\n      ok(max - min <= 0.05)\n    })\n\n    test(`${type} / customAlphabet / changes size`, () => {\n      let nanoidA = customAlphabet('a')\n      equal(nanoidA(10), 'aaaaaaaaaa')\n    })\n\n    test(`${type} / customAlphabet / avoids pool pollution, infinite loop`, () => {\n      let ALPHABET = 'abcdefghijklmnopqrstuvwxyz'\n      let nanoid2 = customAlphabet(ALPHABET)\n      nanoid2(2.1)\n      let second = nanoid2()\n      let third = nanoid2()\n      notEqual(second, third)\n    })\n\n    test(`${type} / customRandom / supports generator`, () => {\n      let sequence = [2, 255, 3, 7, 7, 7, 7, 7, 0, 1]\n      function fakeRandom(size) {\n        let bytes = []\n        for (let i = 0; i < size; i += sequence.length) {\n          bytes = bytes.concat(sequence.slice(0, size - i))\n        }\n        return bytes\n      }\n      let nanoid4 = customRandom('abcde', 4, fakeRandom)\n      let nanoid18 = customRandom('abcde', 18, fakeRandom)\n      equal(nanoid4(), 'adca')\n      equal(nanoid18(), 'cbadcbadcbadcbadcc')\n    })\n\n    test(`${type} / urlAlphabet / is string`, () => {\n      equal(typeof urlAlphabet, 'string')\n    })\n\n    test(`${type} / urlAlphabet / has 64 symbols`, () => {\n      equal(urlAlphabet.length, 64)\n    })\n\n    test(`${type} / urlAlphabet / has no duplicates`, () => {\n      for (let i = 0; i < urlAlphabet.length; i++) {\n        equal(urlAlphabet.lastIndexOf(urlAlphabet[i]), i)\n      }\n    })\n\n    test(`${type} / random / generates small random buffers`, () => {\n      for (let i = 0; i < urlAlphabet.length; i++) {\n        equal(random(10).length, 10)\n      }\n    })\n\n    test(`${type} / random / generates random buffers`, () => {\n      let numbers = {}\n      let bytes = random(1000)\n      equal(bytes.length, 1000)\n      for (let byte of bytes) {\n        if (!numbers[byte]) numbers[byte] = 0\n        numbers[byte] += 1\n        equal(typeof byte, 'number')\n        ok(byte <= 255)\n        ok(byte >= 0)\n      }\n    })\n\n    if (type === 'node') {\n      test(`${type} / proxy number / prevent collision`, () => {\n        let makeProxyNumberToReproducePreviousID = () => {\n          let step = 0\n          return {\n            valueOf() {\n              // \"if (!pool || pool.length < bytes) {\"\n              if (step === 0) {\n                step++\n                return 0\n              }\n              // \"} else if (poolOffset + bytes > pool.length) {\"\n              if (step === 1) {\n                step++\n                return -Infinity\n              }\n              // \"poolOffset += bytes\"\n              if (step === 2) {\n                step++\n                return 0\n              }\n\n              return 21\n            }\n          }\n        }\n\n        let id1 = nanoid()\n        let id2 = nanoid(makeProxyNumberToReproducePreviousID())\n        notEqual(id1, id2)\n      })\n\n      test(`${type} / customAlphabet / does not fall in infinite loop`, () => {\n        equal(customAlphabet('abc')(0), '')\n        equal(customAlphabet('abc', 0)(0), '')\n      })\n    }\n  })\n}\n"
  },
  {
    "path": "test/non-secure.test.js",
    "content": "import { equal, match, notEqual, ok } from 'node:assert'\nimport { describe, test } from 'node:test'\n\nimport { urlAlphabet } from '../index.js'\nimport { customAlphabet, nanoid } from '../non-secure/index.js'\n\ndescribe('non secure', () => {\n  test('is ready for 0 size', () => {\n    equal(nanoid(0), '')\n  })\n\n  test('customAlphabet / is ready for 0 size', () => {\n    equal(customAlphabet('abc')(0), '')\n    equal(customAlphabet('abc', 0)(0), '')\n  })\n\n  test('generates URL-friendly IDs', () => {\n    for (let i = 0; i < 10; i++) {\n      let id = nanoid()\n      equal(id.length, 21)\n      for (let char of id) {\n        match(urlAlphabet, new RegExp(char, 'g'))\n      }\n    }\n  })\n\n  test('changes ID length', () => {\n    equal(nanoid(10).length, 10)\n  })\n\n  test('accepts string', () => {\n    equal(nanoid('10').length, 10)\n  })\n\n  test('has no collisions', () => {\n    let used = {}\n    for (let i = 0; i < 100 * 1000; i++) {\n      let id = nanoid()\n      equal(used[id], undefined)\n      used[id] = true\n    }\n  })\n\n  test('has flat distribution', () => {\n    let COUNT = 100 * 1000\n    let LENGTH = nanoid().length\n\n    let chars = {}\n    for (let i = 0; i < COUNT; i++) {\n      let id = nanoid()\n      for (let char of id) {\n        if (!chars[char]) chars[char] = 0\n        chars[char] += 1\n      }\n    }\n\n    equal(Object.keys(chars).length, urlAlphabet.length)\n\n    let max = 0\n    let min = Number.MAX_SAFE_INTEGER\n    for (let k in chars) {\n      let distribution = (chars[k] * urlAlphabet.length) / (COUNT * LENGTH)\n      if (distribution > max) max = distribution\n      if (distribution < min) min = distribution\n    }\n    ok(max - min <= 0.05)\n  })\n\n  test('nanoid / avoids pool pollution, infinite loop', () => {\n    nanoid(2.1)\n    let second = nanoid()\n    let third = nanoid()\n    notEqual(second, third)\n  })\n\n  test('customAlphabet / has options', () => {\n    let nanoidA = customAlphabet('a', 5)\n    equal(nanoidA(), 'aaaaa')\n  })\n\n  test('customAlphabet / has flat distribution', () => {\n    let COUNT = 100 * 1000\n    let LENGTH = 5\n    let ALPHABET = 'abcdefghijklmnopqrstuvwxyz'\n    let nanoid2 = customAlphabet(ALPHABET, LENGTH)\n\n    let chars = {}\n    for (let i = 0; i < COUNT; i++) {\n      let id = nanoid2()\n      for (let char of id) {\n        if (!chars[char]) chars[char] = 0\n        chars[char] += 1\n      }\n    }\n\n    equal(Object.keys(chars).length, ALPHABET.length)\n\n    let max = 0\n    let min = Number.MAX_SAFE_INTEGER\n    for (let k in chars) {\n      let distribution = (chars[k] * ALPHABET.length) / (COUNT * LENGTH)\n      if (distribution > max) max = distribution\n      if (distribution < min) min = distribution\n    }\n    ok(max - min <= 0.05)\n  })\n\n  test('customAlphabet / avoids pool pollution, infinite loop', () => {\n    let ALPHABET = 'abcdefghijklmnopqrstuvwxyz'\n    let nanoid2 = customAlphabet(ALPHABET)\n    nanoid2(2.1)\n    let second = nanoid2()\n    let third = nanoid2()\n    notEqual(second, third)\n  })\n})\n"
  },
  {
    "path": "test/prebuild.ts",
    "content": "import { readFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { minify } from 'terser'\n\nimport { urlAlphabet } from '../url-alphabet/index.js'\n\nexport const BUILD_PATH = join(import.meta.dirname, '..', 'nanoid.js')\n\nexport async function prebuild(): Promise<string> {\n  let js = await readFile(join(import.meta.dirname, '..', 'index.browser.js'))\n  let func = js.toString().match(/(export let nanoid [\\W\\w]*$)/)![1]\n  let all =\n    `let a = '${urlAlphabet}'\\n` +\n    `${func.replaceAll('scopedUrlAlphabet', 'a')}`\n  let { code } = await minify(all)\n  return code!\n}\n"
  },
  {
    "path": "test/update-prebuild.js",
    "content": "#!/usr/bin/env node\n\nimport { writeFile } from 'node:fs/promises'\n\nimport { BUILD_PATH, prebuild } from './prebuild.ts'\n\nasync function build() {\n  let code = await prebuild()\n  await writeFile(BUILD_PATH, code)\n}\n\nbuild().catch(e => {\n  throw e\n})\n"
  },
  {
    "path": "url-alphabet/index.js",
    "content": "// This alphabet uses `A-Za-z0-9_-` symbols.\n// The order of characters is optimized for better gzip and brotli compression.\n// Same as in non-secure/index.js\nexport let urlAlphabet =\n  'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'\n"
  }
]