v7.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _rng = _interopRequireDefault(require("./rng.js"));
  7. var _stringify = require("./stringify.js");
  8. function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
  9. /**
  10. * UUID V7 - Unix Epoch time-based UUID
  11. *
  12. * The IETF has published RFC9562, introducing 3 new UUID versions (6,7,8). This
  13. * implementation of V7 is based on the accepted, though not yet approved,
  14. * revisions.
  15. *
  16. * RFC 9562:https://www.rfc-editor.org/rfc/rfc9562.html Universally Unique
  17. * IDentifiers (UUIDs)
  18. *
  19. * Sample V7 value:
  20. * https://www.rfc-editor.org/rfc/rfc9562.html#name-example-of-a-uuidv7-value
  21. *
  22. * Monotonic Bit Layout: RFC rfc9562.6.2 Method 1, Dedicated Counter Bits ref:
  23. * https://www.rfc-editor.org/rfc/rfc9562.html#section-6.2-5.1
  24. *
  25. * 0 1 2 3 0 1 2 3 4 5 6
  26. * 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  27. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  28. * | unix_ts_ms |
  29. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  30. * | unix_ts_ms | ver | seq_hi |
  31. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  32. * |var| seq_low | rand |
  33. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  34. * | rand |
  35. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  36. *
  37. * seq is a 31 bit serialized counter; comprised of 12 bit seq_hi and 19 bit
  38. * seq_low, and randomly initialized upon timestamp change. 31 bit counter size
  39. * was selected as any bitwise operations in node are done as _signed_ 32 bit
  40. * ints. we exclude the sign bit.
  41. */
  42. var _seqLow = null;
  43. var _seqHigh = null;
  44. var _msecs = 0;
  45. function v7(options, buf, offset) {
  46. options = options || {};
  47. // initialize buffer and pointer
  48. var i = buf && offset || 0;
  49. var b = buf || new Uint8Array(16);
  50. // rnds is Uint8Array(16) filled with random bytes
  51. var rnds = options.random || (options.rng || _rng.default)();
  52. // milliseconds since unix epoch, 1970-01-01 00:00
  53. var msecs = options.msecs !== undefined ? options.msecs : Date.now();
  54. // seq is user provided 31 bit counter
  55. var seq = options.seq !== undefined ? options.seq : null;
  56. // initialize local seq high/low parts
  57. var seqHigh = _seqHigh;
  58. var seqLow = _seqLow;
  59. // check if clock has advanced and user has not provided msecs
  60. if (msecs > _msecs && options.msecs === undefined) {
  61. _msecs = msecs;
  62. // unless user provided seq, reset seq parts
  63. if (seq !== null) {
  64. seqHigh = null;
  65. seqLow = null;
  66. }
  67. }
  68. // if we have a user provided seq
  69. if (seq !== null) {
  70. // trim provided seq to 31 bits of value, avoiding overflow
  71. if (seq > 0x7fffffff) {
  72. seq = 0x7fffffff;
  73. }
  74. // split provided seq into high/low parts
  75. seqHigh = seq >>> 19 & 0xfff;
  76. seqLow = seq & 0x7ffff;
  77. }
  78. // randomly initialize seq
  79. if (seqHigh === null || seqLow === null) {
  80. seqHigh = rnds[6] & 0x7f;
  81. seqHigh = seqHigh << 8 | rnds[7];
  82. seqLow = rnds[8] & 0x3f; // pad for var
  83. seqLow = seqLow << 8 | rnds[9];
  84. seqLow = seqLow << 5 | rnds[10] >>> 3;
  85. }
  86. // increment seq if within msecs window
  87. if (msecs + 10000 > _msecs && seq === null) {
  88. if (++seqLow > 0x7ffff) {
  89. seqLow = 0;
  90. if (++seqHigh > 0xfff) {
  91. seqHigh = 0;
  92. // increment internal _msecs. this allows us to continue incrementing
  93. // while staying monotonic. Note, once we hit 10k milliseconds beyond system
  94. // clock, we will reset breaking monotonicity (after (2^31)*10000 generations)
  95. _msecs++;
  96. }
  97. }
  98. } else {
  99. // resetting; we have advanced more than
  100. // 10k milliseconds beyond system clock
  101. _msecs = msecs;
  102. }
  103. _seqHigh = seqHigh;
  104. _seqLow = seqLow;
  105. // [bytes 0-5] 48 bits of local timestamp
  106. b[i++] = _msecs / 0x10000000000 & 0xff;
  107. b[i++] = _msecs / 0x100000000 & 0xff;
  108. b[i++] = _msecs / 0x1000000 & 0xff;
  109. b[i++] = _msecs / 0x10000 & 0xff;
  110. b[i++] = _msecs / 0x100 & 0xff;
  111. b[i++] = _msecs & 0xff;
  112. // [byte 6] - set 4 bits of version (7) with first 4 bits seq_hi
  113. b[i++] = seqHigh >>> 4 & 0x0f | 0x70;
  114. // [byte 7] remaining 8 bits of seq_hi
  115. b[i++] = seqHigh & 0xff;
  116. // [byte 8] - variant (2 bits), first 6 bits seq_low
  117. b[i++] = seqLow >>> 13 & 0x3f | 0x80;
  118. // [byte 9] 8 bits seq_low
  119. b[i++] = seqLow >>> 5 & 0xff;
  120. // [byte 10] remaining 5 bits seq_low, 3 bits random
  121. b[i++] = seqLow << 3 & 0xff | rnds[10] & 0x07;
  122. // [bytes 11-15] always random
  123. b[i++] = rnds[11];
  124. b[i++] = rnds[12];
  125. b[i++] = rnds[13];
  126. b[i++] = rnds[14];
  127. b[i++] = rnds[15];
  128. return buf || (0, _stringify.unsafeStringify)(b);
  129. }
  130. var _default = exports.default = v7;