uuid-class
Version:
A minimal UUID class for JavaScript.
117 lines • 4.26 kB
JavaScript
import { bufferSourceToUint8Array, bytesToHexArray, concatUint8Arrays, hexStringToBytes, } from "typed-array-utils";
function _bytesToUUIDString(uint8Array) {
const hexArray = bytesToHexArray(uint8Array);
hexArray.splice(4, 0, '-');
hexArray.splice(7, 0, '-');
hexArray.splice(10, 0, '-');
hexArray.splice(13, 0, '-');
return hexArray.join('');
}
function _v4() {
const uuid = crypto.getRandomValues(new Uint8Array(16));
// Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
uuid[6] = (uuid[6] & 0x0f) | 0x40;
uuid[8] = (uuid[8] & 0x3f) | 0x80;
return uuid.buffer;
}
function _fromString(str) {
const hex = str.replace(/[^0-9a-f]/gi, '').slice(0, 32);
if (hex.length < 32)
throw Error('UUID too short');
return hexStringToBytes(hex).buffer;
}
function stringToBytes(str) {
str = unescape(encodeURIComponent(str)); // UTF8 escape
return new TextEncoder().encode(str);
}
async function _v5(value, namespace) {
const valueBytes = typeof value === 'string'
? stringToBytes(value)
: bufferSourceToUint8Array(value);
const namespaceUUID = typeof namespace === 'string'
? new UUID(namespace)
: namespace;
const hashBytes = new Uint8Array(await crypto.subtle.digest('SHA-1', concatUint8Arrays(namespaceUUID, valueBytes)));
hashBytes[6] = (hashBytes[6] & 0x0f) | 0x50; // version
hashBytes[8] = (hashBytes[8] & 0x3f) | 0x80;
return hashBytes.subarray(0, 16);
}
/**
* A better UUID class for JavaScript.
*
* UUID are represented as bytes (`Uint8Array`) and converted to strings on-demand.
*
* This class implements `toString` and `toJSON` for better language integration,
* as well as inspection for node and Deno for a better development experience.
*
* For the most part, `UUID` can be used where UUID strings are used,
* except for equality checks. For those cases, `UUID` provides quick access
* to the string representations via the `id` field.
*/
export class UUID extends Uint8Array {
/**
* Generate a new UUID version 4 (random).
*
* __Note that `crypto.getRandomValues` needs to be available in the global JS object!__
*/
static v4() {
return new UUID(_v4());
}
/**
* Generated a new UUID version 5 (hashed)
*
* __Note that `crypto.subtle` needs to be available in the global JS object (Not the case on non-HTTPS sites)!__
*
* @param value
* @param namespace
*/
static async v5(value, namespace) {
return new UUID(await _v5(value, namespace));
}
// deno-lint-ignore constructor-super
constructor(value, byteOffset) {
if (value == null) {
super(_v4());
}
else if (typeof value === 'string') {
super(_fromString(value));
}
else if (value instanceof UUID) {
super(value.buffer);
}
else {
const u8 = value instanceof ArrayBuffer || value instanceof SharedArrayBuffer
? new Uint8Array(value, byteOffset !== null && byteOffset !== void 0 ? byteOffset : 0, 16)
: 'length' in value ? new Uint8Array(value) : new Uint8Array(value);
if (u8.length < 16)
throw Error('UUID too short');
super(u8.subarray(0, 16));
}
}
/**
* Quick access to the string representation for easier comparison.
* @example if (myUUID.id === otherUUID.id) { ... }
*/
get id() {
return _bytesToUUIDString(this);
}
/**
* Quick access to the UUID string representation for easier comparison.
* @example if (myUUID.uuid === otherUUID.uuid) { ... }
*/
get uuid() {
return _bytesToUUIDString(this);
}
toString() {
return _bytesToUUIDString(this);
}
toJSON() {
return _bytesToUUIDString(this);
}
// We don't operations like `map`, `subarray`, etc. to preserve the UUID class status
static get [Symbol.species]() { return Uint8Array; }
// Custom inspects..
[Symbol.for('nodejs.util.inspect.custom')]() { return `UUID [ ${this.uuid} ]`; }
[Symbol.for('Deno.customInspect')]() { return `UUID [ ${this.uuid} ]`; }
}
//# sourceMappingURL=index.js.map