You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

35 lines
976 B

2 years ago
  1. import crypto from 'crypto'
  2. import { urlAlphabet } from '../url-alphabet/index.js'
  3. let random = bytes =>
  4. new Promise((resolve, reject) => {
  5. crypto.randomFill(Buffer.allocUnsafe(bytes), (err, buf) => {
  6. if (err) {
  7. reject(err)
  8. } else {
  9. resolve(buf)
  10. }
  11. })
  12. })
  13. let customAlphabet = (alphabet, defaultSize = 21) => {
  14. let mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1
  15. let step = Math.ceil((1.6 * mask * defaultSize) / alphabet.length)
  16. let tick = (id, size = defaultSize) =>
  17. random(step).then(bytes => {
  18. let i = step
  19. while (i--) {
  20. id += alphabet[bytes[i] & mask] || ''
  21. if (id.length === size) return id
  22. }
  23. return tick(id, size)
  24. })
  25. return size => tick('', size)
  26. }
  27. let nanoid = (size = 21) =>
  28. random(size).then(bytes => {
  29. let id = ''
  30. while (size--) {
  31. id += urlAlphabet[bytes[size] & 63]
  32. }
  33. return id
  34. })
  35. export { nanoid, customAlphabet, random }