Changeset 0c6b92a for imaps-frontend/node_modules/nanoid/index.cjs
- Timestamp:
- 12/12/24 17:06:06 (5 weeks ago)
- Branches:
- main
- Parents:
- d565449
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
imaps-frontend/node_modules/nanoid/index.cjs
rd565449 r0c6b92a 1 1 let crypto = require('crypto') 2 2 3 let { urlAlphabet } = require('./url-alphabet/index.cjs') 4 5 // It is best to make fewer, larger requests to the crypto module to 6 // avoid system call overhead. So, random numbers are generated in a 7 // pool. The pool is a Buffer that is larger than the initial random 8 // request size by this multiplier. The pool is enlarged if subsequent 9 // requests exceed the maximum buffer size. 3 10 const POOL_SIZE_MULTIPLIER = 128 4 11 let pool, poolOffset 12 5 13 let fillPool = bytes => { 6 14 if (!pool || pool.length < bytes) { … … 14 22 poolOffset += bytes 15 23 } 24 16 25 let random = bytes => { 17 fillPool((bytes -= 0)) 26 // `|=` convert `bytes` to number to prevent `valueOf` abusing and pool pollution 27 fillPool((bytes |= 0)) 18 28 return pool.subarray(poolOffset - bytes, poolOffset) 19 29 } 30 20 31 let customRandom = (alphabet, defaultSize, getRandom) => { 32 // First, a bitmask is necessary to generate the ID. The bitmask makes bytes 33 // values closer to the alphabet size. The bitmask calculates the closest 34 // `2^31 - 1` number, which exceeds the alphabet size. 35 // For example, the bitmask for the alphabet size 30 is 31 (00011111). 21 36 let mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1 37 // Though, the bitmask solution is not perfect since the bytes exceeding 38 // the alphabet size are refused. Therefore, to reliably generate the ID, 39 // the random bytes redundancy has to be satisfied. 40 41 // Note: every hardware random generator call is performance expensive, 42 // because the system call for entropy collection takes a lot of time. 43 // So, to avoid additional system calls, extra bytes are requested in advance. 44 45 // Next, a step determines how many random bytes to generate. 46 // The number of random bytes gets decided upon the ID size, mask, 47 // alphabet size, and magic number 1.6 (using 1.6 peaks at performance 48 // according to benchmarks). 22 49 let step = Math.ceil((1.6 * mask * defaultSize) / alphabet.length) 50 23 51 return (size = defaultSize) => { 24 52 let id = '' 25 53 while (true) { 26 54 let bytes = getRandom(step) 55 // A compact alternative for `for (let i = 0; i < step; i++)`. 27 56 let i = step 28 57 while (i--) { 58 // Adding `|| ''` refuses a random byte that exceeds the alphabet size. 29 59 id += alphabet[bytes[i] & mask] || '' 30 60 if (id.length === size) return id … … 33 63 } 34 64 } 65 35 66 let customAlphabet = (alphabet, size = 21) => 36 67 customRandom(alphabet, size, random) 68 37 69 let nanoid = (size = 21) => { 38 fillPool((size -= 0)) 70 // `|=` convert `size` to number to prevent `valueOf` abusing and pool pollution 71 fillPool((size |= 0)) 39 72 let id = '' 73 // We are reading directly from the random pool to avoid creating new array 40 74 for (let i = poolOffset - size; i < poolOffset; i++) { 75 // It is incorrect to use bytes exceeding the alphabet size. 76 // The following mask reduces the random byte in the 0-255 value 77 // range to the 0-63 value range. Therefore, adding hacks, such 78 // as empty string fallback or magic numbers, is unneccessary because 79 // the bitmask trims bytes down to the alphabet size. 41 80 id += urlAlphabet[pool[i] & 63] 42 81 } 43 82 return id 44 83 } 84 45 85 module.exports = { nanoid, customAlphabet, customRandom, urlAlphabet, random }
Note:
See TracChangeset
for help on using the changeset viewer.