# Nano ID Логотип Nano ID от Антона Ловчикова [English](./README.md) | [日本語](./README.ja.md) | **Русский** | [简体中文](./README.zh-CN.md) | [Bahasa Indonesia](./README.id-ID.md) | [한국어](./README.ko.md) | [العربية](./README.ar.md) Генератор уникальных ID для JavaScript — лёгкий, безопасный, ID можно применять в URL. > «Поразительный уровень бессмысленного перфекционизма, > который просто невозможно не уважать» - **Лёгкий.** 118 байт (после минификации и Brotli). Без зависимостей. [Size Limit] следит за размером. - **Безопасный.** Использует аппаратный генератор случайных чисел. Можно использовать в кластерах машин. - **Короткие ID.** Используется больший алфавит, чем у UUID (`A-Za-z0-9_-`). Поэтому длина ID уменьшена с 36 до 21 символа. - **Работает везде.** Nano ID уже портировали на [20 языков программирования](#другие-языки-программирования). ```js import { nanoid } from 'nanoid' model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT" ``` Поддерживает современные браузеры, IE ([с Babel]), Node.js и React Native. [online tool]: https://gitpod.io/#https://github.com/ai/nanoid/ [с babel]: https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/ [size limit]: https://github.com/ai/size-limit ---   Сделано в Злых марсианах, продуктовом консалтинге для инструментов разработки. --- ## Оглавление - [Оглавление](#оглавление) - [Сравнение с UUID](#сравнение-с-uuid) - [Сравнение производительности](#сравнение-производительности) - [Безопасность](#безопасность) - [Подключение](#подключение) - [ESM](#esm) - [CommonJS](#commonjs) - [JSR](#jsr) - [CDN](#cdn) - [API](#api) - [Блокирующий](#блокирующий) - [Небезопасный](#небезопасный) - [Смена алфавита или длины](#смена-алфавита-или-длины) - [Смена генератора случайных чисел](#смена-генератора-случайных-чисел) - [Руководство](#руководство) - [React](#react) - [React Native](#react-native) - [PouchDB и CouchDB](#pouchdb-и-couchdb) - [Терминал](#терминал) - [TypeScript](#typescript) - [Другие языки программирования](#другие-языки-программирования) - [Инструменты](#инструменты) ## Сравнение с UUID Nano ID похож на UUID v4 (случайный). У них сравнимое число битов случайности в ID (126 у Nano ID против 122 у UUID), поэтому они обладают похожей вероятностью возникновения коллизий (повторной генерации ранее выданных ID): > Чтобы вероятность повтора приблизилась к 1 на миллиард, > нужно сгенерировать 103 триллиона ID. Но между ними есть 2 важных отличия: 1. Nano ID использует более широкий алфавит, и сравнимое количество битов случайности будут упакованы в более короткую строку (21 символ, против 36 у UUID). 2. Код Nano ID **в 4 раз меньше**, чем у `uuid/v4` — 118 байт против 423. ## Сравнение производительности ```rust $ node ./test/benchmark.js crypto.randomUUID 21,741,317 ops/sec uuid v4 21,204,378 ops/sec @napi-rs/uuid 10,236,615 ops/sec uid/secure 10,567,676 ops/sec @lukeed/uuid 8,647,481 ops/sec nanoid 7,800,308 ops/sec customAlphabet 9,697,350 ops/sec nanoid for browser 576,759 ops/sec secure-random-string 529,253 ops/sec uid-safe.sync 526,459 ops/sec Non-secure: uid 31,379,525 ops/sec nanoid/non-secure 3,678,505 ops/sec rndm 3,767,185 ops/sec ``` Среда сравнения: Framework 13 7840U, Fedora 39, Node.js 21.6. ## Безопасность _См. также хорошую статью о теориях генераторов случайных чисел: [Secure random values (in Node.js)]_ - **Непредсказуемость.** Вместо предсказуемого `Math.random()`, Nano ID использует модуль `crypto` в Node.js и Web Crypto API в браузере. Эти модули дают доступ к аппаратному генератору случайных чисел. - **Равномерность.** Например, существует популярная ошибка `random % alphabet`, которую часто допускают при разработке генератора ID. Распределение вероятности для каждого символа может не быть одинаковым. Из-за неравномерности использования пространства алфавита, на перебор ID потребуется меньше времени, чем ожидается. Nano ID использует [более совершенный алгоритм], а равномерность распределения символов покрыта тестами. Распределение Nano ID - **Документация:** все хитрости Nano ID хорошо документированы — смотрите комментарии [в исходниках]. - **Уязвимости:** если вы нашли уязвимость в Nano ID, свяжитесь с [командой безопасности Tidelift](https://tidelift.com/security). Они проконтролируют исправление и проинформируют пользователей. [secure random values (in node.js)]: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba [более совершенный алгоритм]: https://github.com/ai/nanoid/blob/main/index.js [в исходниках]: https://github.com/ai/nanoid/blob/main/index.js ## Подключение ### ESM Nano ID 5 работает с ESM-проектами (`import`) в тестах или скриптах для Node.js. ```bash npm install nanoid ``` ### CommonJS На проектах с CommonJS вы можете использовать: - `require()` будет работать в последней версия Node.js 22.12 (из коробки) или Node.js 20 (с флагом `--experimental-require-module`). - В более старых версиях Node.js можно использовать динамический импорт: ```js let nanoid module.exports.createID = async () => { if (!nanoid) ({ nanoid } = await import('nanoid')) return nanoid() // => "V1StGXR8_Z5jdHi6B-myT" } ``` - Или можно просто взять Nano ID 3.x (мы его всё ещё поддерживаем): ```bash npm install nanoid@3 ``` ### JSR [JSR](https://jsr.io) это замена npm с открытым управлением и активной разработкой (в отличие от npm). ```bash npx jsr add @sitnik/nanoid ``` Вы можете использовать пакет с JSR в Node.js, Deno, Bun. ```js // Replace `nanoid` to `@sitnik/nanoid` in all imports import { nanoid } from '@sitnik/nanoid' ``` Для Deno установите через `deno add jsr:@sitnik/nanoid` или импортируйте `jsr:@sitnik/nanoid`. ### CDN Для быстрого прототипирования вы можете подключить Nano ID с CDN без установки. Не используйте этот способ на реальном сайте, так как он сильно бьёт по скорости загрузки сайта. ```js import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js' ``` ## API Nano ID разделён на два модуля: стандартный и небезопасный. По умолчанию используются символы, безопасные для URL (`A-Za-z0-9_-`). Длина ID по умолчанию — 21 символ (чтобы вероятность коллизий была соизмеримой с UUID v4). ### Блокирующий Безопасный и простой в использовании способ использования Nano ID. Из-за особенностей работы генератора случайных чисел при использовании этого способа ЦПУ может иногда простаивать без работы. ```js import { nanoid } from 'nanoid' model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT" ``` Функция также принимает необязательный аргумент, задающий длину ID: ```js nanoid(10) //=> "IRFa-VaY2b" ``` При изменении размера, всегда проверяйте риски в нашем [калькуляторе коллизий](https://zelark.github.io/nano-id-cc/). ### Небезопасный По умолчанию, Nano ID использует аппаратный генератор случайных чисел для получения непредсказуемых ID и минимизации риска возникновения коллизий (повторной генерации ранее выданных ID). Но если вам не требуется устойчивость к подбору ID, то вы можете перейти на небезопасный генератор — это полезно там, где нет доступа к API аппаратного генератора случайных чисел. ```js import { nanoid } from 'nanoid/non-secure' const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ" ``` Но учтите, что предсказуемость ID может быть использована для атаки на систему. ### Смена алфавита или длины Функция `customAlphabet` позволяет создать свою функцию `nanoid` с нужным вам алфавитом и длиной ID. ```js import { customAlphabet } from 'nanoid' const nanoid = customAlphabet('1234567890abcdef', 10) user.id = nanoid() //=> "4f90d13a42" ``` ```js import { customAlphabet } from 'nanoid/non-secure' const nanoid = customAlphabet('1234567890abcdef', 10) user.id = nanoid() ``` Не забудьте проверить риски коллизии вашего алфавита и длины [на нашем калькуляторе]. [`nanoid-dictionary`] содержит много популярных примеров альтернативных алфавитов. Алфавит должен содержать ≤256 символов. Иначе мы не сможем гарантировать непредсказуемость ID. Длину ID можно менять не только в `customAlphabet()`, но и при вызове генератора, который она вернёт: ```js import { customAlphabet } from 'nanoid' const nanoid = customAlphabet('1234567890abcdef', 10) model.id = nanoid(5) //=> "f01a2" ``` [на нашем калькуляторе]: https://zelark.github.io/nano-id-cc/ [`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary ### Смена генератора случайных чисел Функция `customRandom` позволяет создать свою функцию `nanoid` со своими генераторами случайных чисел, алфавитом и длинной ID. Например, можно использовать генератор c seed для повторяемости тестов. ```js import { customRandom } from 'nanoid' const rng = seedrandom(seed) const nanoid = customRandom('abcdef', 10, size => { return new Uint8Array(size).map(() => 256 * rng()) }) nanoid() //=> "fbaefaadeb" ``` Функция в третьем аргументе `customRandom` должна принимать длину массива и возвращать нужный массив со случайными числами Если вы хотите заменить только генератор случайных чисел, но оставить URL-совместимый алфавит, то стандартный алфавит доступен в экспорте `urlAlphabet`. ```js const { customRandom, urlAlphabet } = require('nanoid') const nanoid = customRandom(urlAlphabet, 10, random) ``` ## Руководство ### React Не используйте Nano ID для генерации свойства `key` в JSX. При каждом рендере `key` будет разный, что плохо скажется на производительности. ```jsx function Todos({ todos }) { return ( ) } ``` Для связи `` и `