v7.js 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import rng from './rng.js';
  2. import { unsafeStringify } from './stringify.js';
  3. const _state = {};
  4. function v7(options, buf, offset) {
  5. let bytes;
  6. if (options) {
  7. bytes = v7Bytes(options.random ?? options.rng?.() ?? rng(), options.msecs, options.seq, buf, offset);
  8. }
  9. else {
  10. const now = Date.now();
  11. const rnds = rng();
  12. updateV7State(_state, now, rnds);
  13. bytes = v7Bytes(rnds, _state.msecs, _state.seq, buf, offset);
  14. }
  15. return buf ?? unsafeStringify(bytes);
  16. }
  17. export function updateV7State(state, now, rnds) {
  18. state.msecs ??= -Infinity;
  19. state.seq ??= 0;
  20. if (now > state.msecs) {
  21. state.seq = (rnds[6] << 23) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9];
  22. state.msecs = now;
  23. }
  24. else {
  25. state.seq = (state.seq + 1) | 0;
  26. if (state.seq === 0) {
  27. state.msecs++;
  28. }
  29. }
  30. return state;
  31. }
  32. function v7Bytes(rnds, msecs, seq, buf, offset = 0) {
  33. if (rnds.length < 16) {
  34. throw new Error('Random bytes length must be >= 16');
  35. }
  36. if (!buf) {
  37. buf = new Uint8Array(16);
  38. offset = 0;
  39. }
  40. else {
  41. if (offset < 0 || offset + 16 > buf.length) {
  42. throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
  43. }
  44. }
  45. msecs ??= Date.now();
  46. seq ??= ((rnds[6] * 0x7f) << 24) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9];
  47. buf[offset++] = (msecs / 0x10000000000) & 0xff;
  48. buf[offset++] = (msecs / 0x100000000) & 0xff;
  49. buf[offset++] = (msecs / 0x1000000) & 0xff;
  50. buf[offset++] = (msecs / 0x10000) & 0xff;
  51. buf[offset++] = (msecs / 0x100) & 0xff;
  52. buf[offset++] = msecs & 0xff;
  53. buf[offset++] = 0x70 | ((seq >>> 28) & 0x0f);
  54. buf[offset++] = (seq >>> 20) & 0xff;
  55. buf[offset++] = 0x80 | ((seq >>> 14) & 0x3f);
  56. buf[offset++] = (seq >>> 6) & 0xff;
  57. buf[offset++] = ((seq << 2) & 0xff) | (rnds[10] & 0x03);
  58. buf[offset++] = rnds[11];
  59. buf[offset++] = rnds[12];
  60. buf[offset++] = rnds[13];
  61. buf[offset++] = rnds[14];
  62. buf[offset++] = rnds[15];
  63. return buf;
  64. }
  65. export default v7;