({
// Fallback if the user does not pass in a CSPRNG. This should be OK
// because we don't rely solely on the random number generator for entropy.
// We also use the host fingerprint, current time, and a session counter.
random: rand = random,
counter = createCounter(Math.floor(rand() * initialCountMax)),
length = defaultLength,
fingerprint = createFingerprint({ random: rand }),
} = {})
| 100 | const initialCountMax = 476782367; |
| 101 | |
| 102 | const init = ({ |
| 103 | // Fallback if the user does not pass in a CSPRNG. This should be OK |
| 104 | // because we don't rely solely on the random number generator for entropy. |
| 105 | // We also use the host fingerprint, current time, and a session counter. |
| 106 | random: rand = random, |
| 107 | counter = createCounter(Math.floor(rand() * initialCountMax)), |
| 108 | length = defaultLength, |
| 109 | fingerprint = createFingerprint({ random: rand }), |
| 110 | } = {}) => { |
| 111 | if (length > bigLength) { |
| 112 | throw new Error( |
| 113 | `Length must be between 2 and ${bigLength}. Received: ${length}`, |
| 114 | ); |
| 115 | } |
| 116 | return function cuid2() { |
| 117 | const firstLetter = randomLetter(rand); |
| 118 | |
| 119 | // If we're lucky, the `.toString(36)` calls may reduce hashing rounds |
| 120 | // by shortening the input to the hash function a little. |
| 121 | const time = Date.now().toString(36); |
| 122 | const count = counter().toString(36); |
| 123 | |
| 124 | // The salt should be long enough to be globally unique across the full |
| 125 | // length of the hash. For simplicity, we use the same length as the |
| 126 | // intended id output. |
| 127 | const salt = createEntropy(length, rand); |
| 128 | const hashInput = `${time + salt + count + fingerprint}`; |
| 129 | |
| 130 | return `${firstLetter + hash(hashInput).substring(1, length)}`; |
| 131 | }; |
| 132 | }; |
| 133 | |
| 134 | const createId = lazy(init); |
| 135 | function lazy(fn) { |
no test coverage detected
searching dependent graphs…