identifier.ts 1.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. import { randomBytes } from "crypto"
  2. export namespace Identifier {
  3. const LENGTH = 26
  4. // State for monotonic ID generation
  5. let lastTimestamp = 0
  6. let counter = 0
  7. export function ascending() {
  8. return create(false)
  9. }
  10. export function descending() {
  11. return create(true)
  12. }
  13. function randomBase62(length: number): string {
  14. const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
  15. let result = ""
  16. const bytes = randomBytes(length)
  17. for (let i = 0; i < length; i++) {
  18. result += chars[bytes[i] % 62]
  19. }
  20. return result
  21. }
  22. export function create(descending: boolean, timestamp?: number): string {
  23. const currentTimestamp = timestamp ?? Date.now()
  24. if (currentTimestamp !== lastTimestamp) {
  25. lastTimestamp = currentTimestamp
  26. counter = 0
  27. }
  28. counter++
  29. let now = BigInt(currentTimestamp) * BigInt(0x1000) + BigInt(counter)
  30. now = descending ? ~now : now
  31. const timeBytes = Buffer.alloc(6)
  32. for (let i = 0; i < 6; i++) {
  33. timeBytes[i] = Number((now >> BigInt(40 - 8 * i)) & BigInt(0xff))
  34. }
  35. return timeBytes.toString("hex") + randomBase62(LENGTH - 12)
  36. }
  37. }