UNPKG

nhb-toolbox

Version:

A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.

144 lines (143 loc) 5.22 kB
import { isUUID } from '../guards/specials.js'; import { md5, sha1 } from './core.js'; import { _bytesToRandomHex, _checkUUIDVersion, _clockSeq14, _formatUUID, _isOptionV3V5, _randomNode48, _uuidTimestamp, } from './helpers.js'; import { randomHex } from './utils.js'; export function uuid(options) { const { version = 'v4', uppercase = false } = options || {}; switch (version) { case 'v1': { const timestamp = _uuidTimestamp().toString(16).padStart(15, '0'); const vTimeHigh = (parseInt(timestamp.slice(0, -12).padStart(3, '0'), 16) | 0x1000) .toString(16) .padStart(4, '0'); const clockSeq = _clockSeq14(); const clockSeqHi = ((parseInt(clockSeq.slice(0, 2), 16) & 0x3f) | 0x80) .toString(16) .padStart(2, '0'); const raw = timestamp.slice(-8) + timestamp.slice(-12, -8) + vTimeHigh + clockSeqHi + clockSeq.slice(2) + _randomNode48(); return _formatUUID(raw, 1, uppercase); } case 'v3': { if (_isOptionV3V5(options)) { const hash = md5(options.namespace + options.name); return _formatUUID(hash, 3, uppercase); } throw new Error('v3 requires valid namespace (uuid) and name!'); } case 'v4': { const hex = _bytesToRandomHex(new Uint8Array(16)); return _formatUUID(hex, 4, uppercase); } case 'v5': { if (_isOptionV3V5(options)) { const hash = sha1(options.namespace + options.name).slice(0, 32); return _formatUUID(hash, 5, uppercase); } throw new Error('v5 requires valid namespace (uuid) and name!'); } case 'v6': { const timestamp = _uuidTimestamp().toString(16).padStart(15, '0'); const vTimeLow = (parseInt(timestamp.slice(12).padStart(3, '0'), 16) | 0x6000) .toString(16) .padStart(4, '0'); const clockSeq = _clockSeq14(); const clockSeqHi = ((parseInt(clockSeq.slice(0, 2), 16) & 0x3f) | 0x80) .toString(16) .padStart(2, '0'); const raw = timestamp.slice(0, 8) + timestamp.slice(8, 12) + vTimeLow + clockSeqHi + clockSeq.slice(2) + _randomNode48(); return _formatUUID(raw, 6, uppercase); } case 'v7': { const tsHex = Date.now().toString(16).padStart(12, '0'); return _formatUUID(tsHex + randomHex(20), 7, uppercase); } case 'v8': { const ts = BigInt(Date.now()); const bytes = new Uint8Array(16); let temp = ts; for (let i = 5; i >= 0; i--) { bytes[i] = Number(temp & 0xffn); temp >>= 8n; } const hex = _bytesToRandomHex(bytes); return _formatUUID(hex, 8, uppercase); } default: throw new RangeError('Unsupported UUID version!'); } } export function decodeUUID(uuid) { if (!isUUID(uuid)) return null; const plain = uuid.replace(/-/g, ''); const parts = uuid.toLowerCase().split('-'); const version = parseInt(parts[2][0], 16); const variantNibble = parseInt(parts[3][0], 16); let variant = 'RFC4122'; if ((variantNibble & 0b1000) === 0) variant = 'NCS'; else if ((variantNibble & 0b1100) === 0b1000) variant = 'RFC4122'; else if ((variantNibble & 0b1110) === 0b1100) variant = 'Microsoft'; else variant = 'Future'; const decoded = { version, variant, raw: uuid, plain, singleInt: BigInt('0x' + plain), }; const UUID_EPOCH_DIFF = 122192928000000000n; if (version === 1 || version === 6) { let tsHex = parts[2].slice(1) + parts[1] + parts[0]; if (version === 6) tsHex = parts[0] + parts[1] + parts[2].slice(1); const unixMs = Number((BigInt('0x' + tsHex) - UUID_EPOCH_DIFF) / 10000n); decoded.timestamp = unixMs; decoded.node = parts[4]; return decoded; } if (version === 7 || version === 8) { const tsHex = parts.join('').slice(0, 12); decoded.variant = version === 7 ? 'RFC4122' : 'Future'; decoded.timestamp = parseInt(tsHex, 16); return decoded; } return decoded; } export function isUUIDv1(value) { return _checkUUIDVersion(value, '1'); } export function isUUIDv2(value) { return _checkUUIDVersion(value, '2'); } export function isUUIDv3(value) { return _checkUUIDVersion(value, '3'); } export function isUUIDv4(value) { return _checkUUIDVersion(value, '4'); } export function isUUIDv5(value) { return _checkUUIDVersion(value, '5'); } export function isUUIDv6(value) { return _checkUUIDVersion(value, '6'); } export function isUUIDv7(value) { return _checkUUIDVersion(value, '7'); } export function isUUIDv8(value) { return _checkUUIDVersion(value, '8'); }