Skip to content

Instantly share code, notes, and snippets.

@jamesperrin
Last active November 10, 2025 20:38
Show Gist options
  • Select an option

  • Save jamesperrin/37a5879005d3b4c360076380e99597c9 to your computer and use it in GitHub Desktop.

Select an option

Save jamesperrin/37a5879005d3b4c360076380e99597c9 to your computer and use it in GitHub Desktop.
Generates a RFC 4122 version 4 UUID using cryptographically secure random numbers.
/**
* @file uuidv4.js
* @description
* Generates an RFC 4122 version 4 UUID using cryptographically secure random numbers.
* Works in modern browsers and Node.js environments that support the global `crypto` object.
*
* @example
* import { uuidv4 } from './uuidv4.js';
* console.log(uuidv4()); // "e7b4a2c1-4f6e-4cbb-8a14-9e7bcd84f96b"
*/
/**
* Generates cryptographically secure random bytes.
* Falls back to Node.js `crypto.randomFillSync` if `crypto.getRandomValues` is not available.
*
* @param {Uint8Array} arr - A typed array to fill with random values.
* @returns {Uint8Array} The filled array of random bytes.
* @throws {Error} If no cryptographically secure random number generator is available.
*/
function getSecureRandomValues(arr) {
if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {
// Browser or modern Node.js
return crypto.getRandomValues(arr);
} else if (typeof require === 'function') {
// Fallback for older Node.js versions
try {
const { randomFillSync } = require('crypto');
return randomFillSync(arr);
} catch {
throw new Error('No cryptographically secure random number generator available.');
}
} else {
throw new Error('No cryptographically secure random number generator available.');
}
}
/**
* Generates a Version 4 (random) UUID as defined in RFC 4122.
*
* The UUID format is `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`, where:
* - `x` is any hexadecimal digit.
* - `y` is one of `8`, `9`, `A`, or `B`.
*
* @returns {string} A randomly generated UUIDv4 string.
*/
export function uuidv4() {
const bytes = getSecureRandomValues(new Uint8Array(16));
// Set version (4) and variant (10xx)
bytes[6] = (bytes[6] & 0x0f) | 0x40;
bytes[8] = (bytes[8] & 0x3f) | 0x80;
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0'));
return (
`${hex.slice(0, 4).join('')}-` +
`${hex.slice(4, 6).join('')}-` +
`${hex.slice(6, 8).join('')}-` +
`${hex.slice(8, 10).join('')}-` +
`${hex.slice(10).join('')}`
);
}
export default uuidv4;
/**
* @file uuidv4.mjs
* @description
* Generates an RFC 4122 version 4 UUID using cryptographically secure random numbers.
* Works in modern browsers and Node.js environments that support the global `crypto` object.
*
* @example
* import { uuidv4 } from './uuidv4.mjs';
* console.log(uuidv4()); // "e7b4a2c1-4f6e-4cbb-8a14-9e7bcd84f96b"
*/
/**
* Generates cryptographically secure random bytes.
* Falls back to Node.js `crypto.randomFillSync` if `crypto.getRandomValues` is not available.
*
* @param {Uint8Array} arr - A typed array to fill with random values.
* @returns {Uint8Array} The filled array of random bytes.
* @throws {Error} If no cryptographically secure random number generator is available.
*/
function getSecureRandomValues(arr) {
if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {
return crypto.getRandomValues(arr); // Browser or modern Node
} else if (typeof require === 'function') {
// Fallback for older Node.js versions
try {
const { randomFillSync } = require('crypto');
return randomFillSync(arr);
} catch {
throw new Error('No cryptographically secure random number generator available.');
}
} else {
throw new Error('No cryptographically secure random number generator available.');
}
}
/**
* Generates a Version 4 (random) UUID as defined in RFC 4122.
*
* The UUID format is 8-4-4-4-12 hexadecimal digits, such as:
* `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`
*
* @returns {string} A randomly generated UUIDv4 string.
*/
export function uuidv4() {
const bytes = getSecureRandomValues(new Uint8Array(16));
// Set version (4) and variant (10xx)
bytes[6] = (bytes[6] & 0x0f) | 0x40;
bytes[8] = (bytes[8] & 0x3f) | 0x80;
const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0'));
return (
`${hex.slice(0, 4).join('')}-` +
`${hex.slice(4, 6).join('')}-` +
`${hex.slice(6, 8).join('')}-` +
`${hex.slice(8, 10).join('')}-` +
`${hex.slice(10).join('')}`
);
}
export default uuidv4;
/**
* @file uuidv4.ts
* @description
* Generates an RFC 4122 version 4 UUID using cryptographically secure random numbers.
* Works in modern browsers and Node.js environments that support the global `crypto` object.
*
* @example
* import { uuidv4 } from './uuidv4';
* console.log(uuidv4()); // "e7b4a2c1-4f6e-4cbb-8a14-9e7bcd84f96b"
*/
/**
* Generates cryptographically secure random bytes.
* Falls back to Node.js `crypto.randomFillSync` if `crypto.getRandomValues` is not available.
*
* @param arr - A typed array to fill with random values.
* @returns The filled array of random bytes.
* @throws {Error} If no cryptographically secure random number generator is available.
*/
function getSecureRandomValues(arr: Uint8Array): Uint8Array {
if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {
// Browser or modern Node.js
return crypto.getRandomValues(arr);
} else if (typeof require === 'function') {
// Fallback for older Node.js versions
try {
const { randomFillSync } = require('crypto') as typeof import('crypto');
return randomFillSync(arr);
} catch {
throw new Error('No cryptographically secure random number generator available.');
}
} else {
throw new Error('No cryptographically secure random number generator available.');
}
}
/**
* Generates a Version 4 (random) UUID as defined in RFC 4122.
*
* The UUID format is `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`, where:
* - `x` is any hexadecimal digit.
* - `y` is one of `8`, `9`, `A`, or `B`.
*
* @returns A randomly generated UUIDv4 string.
*/
export function uuidv4(): string {
const bytes = getSecureRandomValues(new Uint8Array(16));
// Set version (4) and variant (10xx)
bytes[6] = (bytes[6] & 0x0f) | 0x40;
bytes[8] = (bytes[8] & 0x3f) | 0x80;
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0'));
return (
`${hex.slice(0, 4).join('')}-` +
`${hex.slice(4, 6).join('')}-` +
`${hex.slice(6, 8).join('')}-` +
`${hex.slice(8, 10).join('')}-` +
`${hex.slice(10).join('')}`
);
}
export default uuidv4;
/**
*
* @file uuidv4.js
* @description*
* Generates a RFC 4122 version 4 UUID using cryptographically secure random numbers.
* Falls back to Node.js crypto if not in a browser.
* Throws if no cryptographically secure PRNG is available.
*
* Vibe coding using GitHub CoPilot and ChatGPT.
*
* @example
* import { uuidv4 } from './uuidv4.js';
* console.log(uuidv4()); // "e7b4a2c1-4f6e-4cbb-8a14-9e7bcd84f96b"
*
* @returns {string} The generated UUID string in the standard 8-4-4-4-12 format. // "e7b4a2c1-4f6e-4cbb-8a14-9e7bcd84f96b"
*/
(function (global, factory) {
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
// CommonJS (Node.js)
module.exports = factory(require('crypto'));
} else if (typeof define === 'function' && define.amd) {
// AMD (if needed)
define(['crypto'], factory);
} else {
// Browser global
global.uuidv4 = factory(global.crypto);
}
})(typeof globalThis !== 'undefined' ? globalThis : this, function (cryptoSource) {
function getSecureRandomValues(arr) {
if (cryptoSource && typeof cryptoSource.getRandomValues === 'function') {
return cryptoSource.getRandomValues(arr); // Browser
} else if (cryptoSource && typeof cryptoSource.randomFillSync === 'function') {
return cryptoSource.randomFillSync(arr); // Node.js
} else {
throw new Error('No cryptographically secure random number generator available.');
}
}
function uuidv4() {
const bytes = getSecureRandomValues(new Uint8Array(16));
// Set version and variant bits
bytes[6] = (bytes[6] & 0x0f) | 0x40; // Version 4
bytes[8] = (bytes[8] & 0x3f) | 0x80; // Variant 10xx
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0'));
return (
`${hex.slice(0, 4).join('')}-` +
`${hex.slice(4, 6).join('')}-` +
`${hex.slice(6, 8).join('')}-` +
`${hex.slice(8, 10).join('')}-` +
`${hex.slice(10).join('')}`
);
}
return uuidv4;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment