fix(v7): align default seq formula in v7Bytes with updateV7State (#965)

---------

Co-authored-by: JSap0914 <[email protected]>
Co-authored-by: Robert Kieffer <[email protected]>
This commit is contained in:
JSap0914
2026-07-02 08:20:04 -10:00
committed by GitHub
co-authored by JSap0914 Robert Kieffer
parent 4e72d5fce4
commit cf641d9433
2 changed files with 43 additions and 3 deletions
+37 -1
View File
@@ -173,7 +173,7 @@ describe('v7', () => {
now: 2, now: 2,
expected: { expected: {
msecs: 2, // time interval should update msecs: 2, // time interval should update
seq: 0x6c318c4, // sequence should be randomized seq: 0xcc318c4, // sequence should be randomized
}, },
}, },
{ {
@@ -297,4 +297,40 @@ describe('v7', () => {
assert.throws(() => v7({}, buf30, -1), RangeError); assert.throws(() => v7({}, buf30, -1), RangeError);
assert.throws(() => v7({}, buf30, 15), RangeError); assert.throws(() => v7({}, buf30, 15), RangeError);
}); });
test('default seq (no explicit seq option) is consistent with updateV7State formula', () => {
// When v7() is called with random bytes and msecs but no explicit seq, the
// default seq should use the same formula as updateV7State() –
// ((rnds[6] & 0x7f) << 24) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9].
//
// Regression: the formula was `(rnds[6] * 0x7f) << 24`, which should have
// been `(rnds[6] & 0x7f) << 24`, producing a seq inconsistent with
// updateV7State.
const rnds = Uint8Array.of(
0x02,
0x91,
0x56,
0xbe,
0xc4,
0xfb,
0x02,
0xc3,
0x18,
0xc4,
0x6c,
0x0c,
0x0c,
0x07,
0x39,
0x8f,
);
const state = updateV7State({}, RFC_MSECS, rnds);
const uuidWithExplicitSeq = v7({
random: rnds,
msecs: RFC_MSECS,
seq: state.seq,
});
const uuidWithDefaultSeq = v7({ random: rnds, msecs: RFC_MSECS });
assert.strictEqual(uuidWithDefaultSeq, uuidWithExplicitSeq);
});
}); });
+6 -2
View File
@@ -56,7 +56,7 @@ export function updateV7State(state: V7State, now: number, rnds: Uint8Array) {
if (now > state.msecs) { if (now > state.msecs) {
// Time has moved on! Pick a new random sequence number // Time has moved on! Pick a new random sequence number
state.seq = (rnds[6] << 23) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9]; state.seq = v7Sequence(rnds);
state.msecs = now; state.msecs = now;
} else { } else {
// Bump sequence counter w/ 32-bit rollover // Bump sequence counter w/ 32-bit rollover
@@ -97,7 +97,7 @@ function v7Bytes(
// Defaults // Defaults
msecs ??= Date.now(); msecs ??= Date.now();
seq ??= ((rnds[6] * 0x7f) << 24) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9]; seq ??= v7Sequence(rnds);
// byte 0-5: timestamp (48 bits) // byte 0-5: timestamp (48 bits)
buf[offset++] = (msecs / 0x10000000000) & 0xff; buf[offset++] = (msecs / 0x10000000000) & 0xff;
@@ -132,4 +132,8 @@ function v7Bytes(
return buf; return buf;
} }
function v7Sequence(rnds: Uint8Array) {
return ((rnds[6] & 0x7f) << 24) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9];
}
export default v7; export default v7;