Skip to content

Instantly share code, notes, and snippets.

@SMJSGaming
Last active September 14, 2025 17:46
Show Gist options
  • Select an option

  • Save SMJSGaming/766a68aea7435f7fdbe19829de867f00 to your computer and use it in GitHub Desktop.

Select an option

Save SMJSGaming/766a68aea7435f7fdbe19829de867f00 to your computer and use it in GitHub Desktop.
TypeScript UUIDv7 Implement based on the rfc9562 standard
interface OverlapConfig {
bits: number;
overlap: number;
}
interface WriteConfig {
length: number;
value: bigint;
}
export class UUIDv7 {
private static RANDOM_ALGORITHM: () => number = Math.random;
public static setRandomAlgorithm(randomAlgorithm: () => number): void {
UUIDv7.RANDOM_ALGORITHM = randomAlgorithm;
}
public static create(): UUIDv7 {
return new UUIDv7();
}
/**
* @warning Does not consider reserved UUID variants as valid
*/
public static isValid(uuid: UUIDv7 | string) {
const stringUUID = uuid.toString();
const hasDashes = stringUUID.includes("-");
return (!hasDashes || stringUUID.split("-").length == 5) &&
stringUUID.length == 32 + 4 * +hasDashes &&
UUIDv7.getTimestamp(uuid) <= Date.now() &&
UUIDv7.getVersion(uuid) == 7 &&
UUIDv7.getVariant(uuid) == 2;
}
public static getTimestamp(uuid: UUIDv7 | string): number {
const stringUUID = uuid.toString();
return parseInt(stringUUID.slice(0, 12 + +stringUUID.includes("-")).replace("-", ""), 16);
}
public static getVersion(uuid: UUIDv7 | string): number {
const stringUUID = uuid.toString();
return parseInt(stringUUID.charAt(12 + 2 * +stringUUID.includes("-")), 16);
}
public static getVariant(uuid: UUIDv7 | string): number {
const stringUUID = uuid.toString();
return parseInt(stringUUID.charAt(16 + 3 * +stringUUID.includes("-")), 16) >> 2;
}
private readonly uuid: Buffer;
private constructor() {
this.uuid = this.generate();
}
public toString(withDashes: boolean = true): string {
const string = this.uuid.toString("hex");
if (withDashes) {
return string.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, (_, timeHigh, timeLow, version, variant, random) => [
timeHigh,
timeLow,
version,
variant,
random
].join("-"));
} else {
return string;
}
}
/**
* @see {@link https://www.rfc-editor.org/rfc/rfc9562.html#section-5.7}
*/
private generate(): Buffer {
const byteSize = 8;
const versionByte = 0x7n;
const variantByte = 0b10n;
const randomAOverlap: OverlapConfig = {
bits: 12,
overlap: 4,
};
const randomBOverlap: OverlapConfig = {
bits: 62,
overlap: 6
};
const randomA = this.createRandom(randomAOverlap.bits);
const randomB = this.createRandom(randomBOverlap.bits);
return this.writer([
{ value: BigInt(Date.now()), length: 6 },
{ value: this.overlap(versionByte, randomA, randomAOverlap), length: 1 },
{ value: this.removeOverlap(randomA, randomAOverlap), length: (randomAOverlap.bits - randomAOverlap.overlap) / byteSize },
{ value: this.overlap(variantByte, randomB, randomBOverlap), length: 1 },
{ value: this.removeOverlap(randomB, randomBOverlap), length: (randomBOverlap.bits - randomBOverlap.overlap) / byteSize }
]);
}
private writer(configs: WriteConfig[]): Buffer {
const buffer = Buffer.alloc(configs.reduce((acc, { length }) => acc + length, 0));
configs.reduce((offset, { value, length }) => {
for (let i = BigInt(length - 1); i >= 0; i--) {
buffer.writeUint8(Number(value >> i * 8n & 0xFFn), offset++);
}
return offset;
}, 0);
return buffer;
}
private overlap(high: bigint, low: bigint, overlapConfig: OverlapConfig): bigint {
return high << BigInt(overlapConfig.overlap) | low >> BigInt(overlapConfig.bits - overlapConfig.overlap);
}
private removeOverlap(number: bigint, overlapConfig: OverlapConfig): bigint {
return number & this.createMax(overlapConfig.bits - overlapConfig.overlap);
}
private createRandom(size: number): bigint {
return Array(size).fill(0)
.map(() => BigInt(Math.round(UUIDv7.RANDOM_ALGORITHM())))
.reduce((acc, bit) => (acc << 1n) | bit, 0n);
}
private createMax(size: number): bigint {
return (1n << BigInt(size)) - 1n;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment