UNPKG

4.72 kBJavaScriptView Raw
1"use strict";
2/*
3
4This file is "vendored" from Nanoid, all credit is to Nanoid authors:
5https://github.com/ai/nanoid/
6
7 */
8Object.defineProperty(exports, "__esModule", { value: true });
9exports.nanoid = exports.nanoIdCustomAlphabet = exports.ALPHABET_BASE64_URL = exports.ALPHABET_BASE64 = exports.ALPHABET_ALPHANUMERIC = exports.ALPHABET_ALPHANUMERIC_UPPERCASE = exports.ALPHABET_ALPHANUMERIC_LOWERCASE = exports.ALPHABET_UPPERCASE = exports.ALPHABET_LOWERCASE = exports.ALPHABET_NUMBER = void 0;
10/* eslint-disable */
11const node_crypto_1 = require("node:crypto");
12exports.ALPHABET_NUMBER = '0123456789';
13exports.ALPHABET_LOWERCASE = 'abcdefghijklmnopqrstuvwxyz';
14exports.ALPHABET_UPPERCASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
15exports.ALPHABET_ALPHANUMERIC_LOWERCASE = [exports.ALPHABET_NUMBER, exports.ALPHABET_LOWERCASE].join('');
16exports.ALPHABET_ALPHANUMERIC_UPPERCASE = [exports.ALPHABET_NUMBER, exports.ALPHABET_UPPERCASE].join('');
17exports.ALPHABET_ALPHANUMERIC = [exports.ALPHABET_NUMBER, exports.ALPHABET_LOWERCASE, exports.ALPHABET_UPPERCASE].join('');
18exports.ALPHABET_BASE64 = [exports.ALPHABET_ALPHANUMERIC, '+/'].join('');
19exports.ALPHABET_BASE64_URL = [exports.ALPHABET_ALPHANUMERIC, '-_'].join('');
20// It is best to make fewer, larger requests to the crypto module to
21// avoid system call overhead. So, random numbers are generated in a
22// pool. The pool is a Buffer that is larger than the initial random
23// request size by this multiplier. The pool is enlarged if subsequent
24// requests exceed the maximum buffer size.
25const POOL_SIZE_MULTIPLIER = 128;
26let pool;
27let poolOffset;
28function fillPool(bytes) {
29 if (!pool || pool.length < bytes) {
30 pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
31 (0, node_crypto_1.randomFillSync)(pool);
32 poolOffset = 0;
33 }
34 else if (poolOffset + bytes > pool.length) {
35 (0, node_crypto_1.randomFillSync)(pool);
36 poolOffset = 0;
37 }
38 poolOffset += bytes;
39}
40function random(bytes) {
41 // `-=` convert `bytes` to number to prevent `valueOf` abusing
42 fillPool((bytes -= 0));
43 return pool.subarray(poolOffset - bytes, poolOffset);
44}
45function customRandom(alphabet, defaultSize, getRandom) {
46 // First, a bitmask is necessary to generate the ID. The bitmask makes bytes
47 // values closer to the alphabet size. The bitmask calculates the closest
48 // `2^31 - 1` number, which exceeds the alphabet size.
49 // For example, the bitmask for the alphabet size 30 is 31 (00011111).
50 const mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1;
51 // Though, the bitmask solution is not perfect since the bytes exceeding
52 // the alphabet size are refused. Therefore, to reliably generate the ID,
53 // the random bytes redundancy has to be satisfied.
54 // Note: every hardware random generator call is performance expensive,
55 // because the system call for entropy collection takes a lot of time.
56 // So, to avoid additional system calls, extra bytes are requested in advance.
57 // Next, a step determines how many random bytes to generate.
58 // The number of random bytes gets decided upon the ID size, mask,
59 // alphabet size, and magic number 1.6 (using 1.6 peaks at performance
60 // according to benchmarks).
61 const step = Math.ceil((1.6 * mask * defaultSize) / alphabet.length);
62 return (size = defaultSize) => {
63 let id = '';
64 while (true) {
65 const bytes = getRandom(step);
66 // A compact alternative for `for (let i = 0; i < step; i++)`.
67 let i = step;
68 while (i--) {
69 // Adding `|| ''` refuses a random byte that exceeds the alphabet size.
70 id += alphabet[bytes[i] & mask] || '';
71 if (id.length === size)
72 return id;
73 }
74 }
75 };
76}
77function nanoIdCustomAlphabet(alphabet, size = 21) {
78 return customRandom(alphabet, size, random);
79}
80exports.nanoIdCustomAlphabet = nanoIdCustomAlphabet;
81function nanoid(size = 21) {
82 // `-=` convert `size` to number to prevent `valueOf` abusing
83 fillPool((size -= 0));
84 let id = '';
85 // We are reading directly from the random pool to avoid creating new array
86 for (let i = poolOffset - size; i < poolOffset; i++) {
87 // It is incorrect to use bytes exceeding the alphabet size.
88 // The following mask reduces the random byte in the 0-255 value
89 // range to the 0-63 value range. Therefore, adding hacks, such
90 // as empty string fallback or magic numbers, is unneccessary because
91 // the bitmask trims bytes down to the alphabet size.
92 id += exports.ALPHABET_BASE64_URL[pool[i] & 63];
93 }
94 return id;
95}
96exports.nanoid = nanoid;