西藏巴青项目

index.js 1.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import { webcrypto as crypto } from 'node:crypto'
  2. import { urlAlphabet as scopedUrlAlphabet } from './url-alphabet/index.js'
  3. export { urlAlphabet } from './url-alphabet/index.js'
  4. const POOL_SIZE_MULTIPLIER = 128
  5. let pool, poolOffset
  6. function fillPool(bytes) {
  7. if (bytes < 0 || bytes > 1024) throw new RangeError('Wrong ID size')
  8. if (!pool || pool.length < bytes) {
  9. pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER)
  10. crypto.getRandomValues(pool)
  11. poolOffset = 0
  12. } else if (poolOffset + bytes > pool.length) {
  13. crypto.getRandomValues(pool)
  14. poolOffset = 0
  15. }
  16. poolOffset += bytes
  17. }
  18. export function random(bytes) {
  19. fillPool((bytes |= 0))
  20. return pool.subarray(poolOffset - bytes, poolOffset)
  21. }
  22. export function customRandom(alphabet, defaultSize, getRandom) {
  23. let safeByteCutoff = 256 - (256 % alphabet.length)
  24. if (safeByteCutoff === 256) {
  25. let mask = alphabet.length - 1
  26. return (size = defaultSize) => {
  27. if (!size) return ''
  28. let id = ''
  29. while (true) {
  30. let bytes = getRandom(size)
  31. let i = size
  32. while (i--) {
  33. id += alphabet[bytes[i] & mask]
  34. if (id.length >= size) return id
  35. }
  36. }
  37. }
  38. }
  39. let step = Math.ceil((1.6 * 256 * defaultSize) / safeByteCutoff)
  40. return (size = defaultSize) => {
  41. if (!size) return ''
  42. let id = ''
  43. while (true) {
  44. let bytes = getRandom(step)
  45. let i = step
  46. while (i--) {
  47. if (bytes[i] < safeByteCutoff) {
  48. id += alphabet[bytes[i] % alphabet.length]
  49. if (id.length >= size) return id
  50. }
  51. }
  52. }
  53. }
  54. }
  55. export function customAlphabet(alphabet, size = 21) {
  56. return customRandom(alphabet, size, random)
  57. }
  58. export function nanoid(size = 21) {
  59. fillPool((size |= 0))
  60. let id = ''
  61. for (let i = poolOffset - size; i < poolOffset; i++) {
  62. id += scopedUrlAlphabet[pool[i] & 63]
  63. }
  64. return id
  65. }