Uuidv47
Reversible UUID v4/v7 transformation using SipHash-2-4 cryptography. Hide time-ordering from external APIs while maintaining internal chronological benefits.
Install / Use
/learn @ali-master/Uuidv47README
<div align="center">
<img src="assets/logo.svg" alt="UUIDv47 TypeScript Logo" width="120" height="120" />
<h1>UUIDv47</h1>
<p><strong>Reversible UUID v4/v7 transformation using SipHash-2-4</strong></p>
<p><em>⚡ Ultra-lightweight • 🚀 Zero dependencies • 📦 Just 2.25KB gzipped</em></p>
</div>
🚀 What is UUIDv47?
UUIDv47 is a revolutionary approach to UUID management that allows you to reversibly transform UUIDs between v7 (time-ordered) and v4 (random-appearing) formats. This enables you to:
- 🔒 Hide time-ordering from external APIs while maintaining internal chronological benefits
- 🎭 Present v4 facades to clients while storing efficient v7 UUIDs internally
- 🔐 Cryptographically secure transformations using SipHash-2-4 algorithm
- ⚡ High performance with >10,000 operations per second
- 🔄 Perfect reversibility - no data loss in transformations
- 📦 Tiny footprint - only 2.25KB gzipped with zero dependencies
🎯 Why Choose UUIDv47?
UUIDv47 is a lightweight library at just 5.71KB (2.25KB gzipped) that provides enterprise-grade UUID transformation capabilities with zero dependencies.
📋 Table of Contents
- Installation
- Quick Start
- Core Concepts
- Usage Examples
- API Reference
- Performance
- Security
- Contributing
📦 Installation
# Using Bun (recommended)
bun add @usex/uuidv47
# Using npm
npm install @usex/uuidv47
# Using yarn
yarn add @usex/uuidv47
# Using pnpm
pnpm add @usex/uuidv47
Requirements
- Node.js: 16.0.0+
- TypeScript: 5.0+ (for TypeScript projects)
- Runtime: Works with Node.js, Bun, Deno, and modern browsers
⚡ Quick Start
import { generateRandomKey, parseUUID, formatUUID, encodeV4Facade, decodeV4Facade } from '@usex/uuidv47';
// 1. Generate a secure transformation key
const key = generateRandomKey();
// 2. Parse your UUIDv7 (from your UUID generator)
const originalV7 = parseUUID('018f4e7c-3c4a-7000-8000-123456789abc');
// 3. Transform to v4 facade (for external APIs)
const v4Facade = encodeV4Facade(originalV7, key);
console.log(formatUUID(v4Facade));
// Output: "a1b2c3d4-e5f6-4789-9abc-def012345678" (appears random)
// 4. Transform back to original v7 (for internal use)
const decodedV7 = decodeV4Facade(v4Facade, key);
console.log(formatUUID(decodedV7));
// Output: "018f4e7c-3c4a-7000-8000-123456789abc" (original restored)
🧠 Core Concepts
The Problem UUIDv47 Solves
UUIDv7 provides excellent time-ordering properties but reveals creation timestamps to anyone who can parse them. UUIDv4 appears random but lacks useful ordering. UUIDv47 gives you both:
// Internal storage: UUIDv7 (time-ordered, efficient)
const internalId = "018f4e7c-3c4a-7000-8000-123456789abc"; // Created at specific timestamp
// External API: UUIDv4 facade (random-appearing, private)
const publicId = "a1b2c3d4-e5f6-4789-9abc-def012345678"; // Hides creation time
// They're the SAME identifier, just different representations!
How It Works
- Timestamp Encryption: The 48-bit timestamp in UUIDv7 is XORed with a SipHash-2-4 derived mask
- Random Bits Preserved: The random portion remains unchanged, maintaining uniqueness
- Version Swap: Version bits are changed between 4 and 7 during transformation
- Perfect Reversibility: Using the same key, transformations are completely reversible
Key Components
- SipHash-2-4: Cryptographically secure hash function for generating encryption masks
- 48-bit Timestamp: The time component that gets encrypted/decrypted
- Transformation Key: 128-bit key (two 64-bit values) for secure transformations
- UUID128: Buffer representation of 16-byte UUIDs for efficient processing
💡 Usage Examples
1. Basic Encode/Decode Operations
import { generateRandomKey, parseUUID, formatUUID, getUUIDVersion, encodeV4Facade, decodeV4Facade } from '@usex/uuidv47';
const key = generateRandomKey();
const v7UUID = parseUUID("018f4e7c-3c4a-7000-8000-123456789abc");
console.log(`Original UUIDv7: ${formatUUID(v7UUID)}`);
console.log(`Version: ${getUUIDVersion(v7UUID)}`); // 7
const v4Facade = encodeV4Facade(v7UUID, key);
console.log(`UUIDv4 Facade: ${formatUUID(v4Facade)}`);
console.log(`Version: ${getUUIDVersion(v4Facade)}`); // 4
const decodedV7 = decodeV4Facade(v4Facade, key);
console.log(`Decoded UUIDv7: ${formatUUID(decodedV7)}`);
console.log(`Matches original: ${decodedV7.equals(v7UUID)}`); // true
2. Service Integration Pattern
class UUIDTransformationService {
private readonly key: UUIDv47Key;
constructor(keyMaterial?: Buffer) {
this.key = keyMaterial
? createKeyFromBuffer(keyMaterial)
: generateRandomKey();
}
// For external APIs - hide time ordering
toPublicId(internalV7: string): string {
const uuid = parseUUID(internalV7);
const facade = encodeV4Facade(uuid, this.key);
return formatUUID(facade);
}
// For internal processing - restore time ordering
toInternalId(publicV4: string): string {
const uuid = parseUUID(publicV4);
const original = decodeV4Facade(uuid, this.key);
return formatUUID(original);
}
}
// Usage
const service = new UUIDTransformationService();
const internalId = "018f4e7c-3c4a-7000-8000-123456789abc";
const publicId = service.toPublicId(internalId);
const recoveredId = service.toInternalId(publicId);
console.log({ internalId, publicId, recoveredId });
// {
// internalId: "018f4e7c-3c4a-7000-8000-123456789abc",
// publicId: "a1b2c3d4-e5f6-4789-9abc-def012345678",
// recoveredId: "018f4e7c-3c4a-7000-8000-123456789abc"
// }
3. Multi-Tenant Key Management
class MultiTenantUUIDService {
private readonly tenantKeys = new Map<string, UUIDv47Key>();
setTenantKey(tenantId: string, keyMaterial: Buffer): void {
this.tenantKeys.set(tenantId, createKeyFromBuffer(keyMaterial));
}
encodeForTenant(tenantId: string, v7UUID: string): string {
const key = this.tenantKeys.get(tenantId);
if (!key) throw new Error(`No key found for tenant: ${tenantId}`);
const uuid = parseUUID(v7UUID);
const facade = encodeV4Facade(uuid, key);
return formatUUID(facade);
}
decodeForTenant(tenantId: string, v4Facade: string): string {
const key = this.tenantKeys.get(tenantId);
if (!key) throw new Error(`No key found for tenant: ${tenantId}`);
const uuid = parseUUID(v4Facade);
const original = decodeV4Facade(uuid, key);
return formatUUID(original);
}
}
4. Batch Processing
// Process 1000 UUIDs efficiently
const key = generateRandomKey();
const v7UUIDs = generateV7UUIDs(1000); // Your UUID generation
console.time('Batch Encode');
const facades = v7UUIDs.map(uuid => encodeV4Facade(uuid, key));
console.timeEnd('Batch Encode'); // ~10ms for 1000 UUIDs
console.time('Batch Decode');
const decoded = facades.map(facade => decodeV4Facade(facade, key));
console.timeEnd('Batch Decode'); // ~10ms for 1000 UUIDs
// Verify all transformations are perfect
const allMatch = decoded.every((uuid, i) => uuid.equals(v7UUIDs[i]));
console.log(`All roundtrips successful: ${allMatch}`); // true
5. Error Handling
const key = generateRandomKey();
try {
// This will throw - can only encode v7 UUIDs
const v4UUID = parseUUID("a1b2c3d4-e5f6-4000-8000-123456789abc");
encodeV4Facade(v4UUID, key);
} catch (error) {
console.log(error.message); // "Input UUID must be version 7"
}
try {
// This will throw - can only decode v4 UUIDs
const v7UUID = parseUUID("018f4e7c-3c4a-7000-8000-123456789abc");
decodeV4Facade(v7UUID, key);
} catch (error) {
console.log(error.message); // "Input UUID must be version 4"
}
try {
// This will throw - invalid UUID format
parseUUID("invalid-uuid-string");
} catch (error) {
console.log(error.message); // "Invalid UUID string length: expected 36, got 19"
}
6. UUID v7 Timestamp Extraction
import { parseUUID, extractTimestampFromV7, formatUUID } from '@usex/uuidv47';
// Extract timestamp from a UUID v7
const v7UUID = parseUUID("018f4e7c-3c4a-7000-8000-123456789abc");
const timestamp = extractTimestampFromV7(v7UUID);
console.log(`UUID v7: ${formatUUID(v7UUID)}`);
console.log(`Timestamp: ${timestamp.getTime()} ms`);
console.log(`Date: ${timestamp.toISOString()}`); // "2024-10-07T23:15:45.610Z"
console.log(`Local: ${timestamp.toLocaleString()}`);
// Compare creation times of multiple UUIDs
const uuid1 = parseUUID("018f4e7c-3c4a-7000-8000-111111111111");
const uuid2 = parseUUID("018f4e7c-4000-7000-8000-222222222222");
const uuid3 = parseUUID("018f4e7c-5000-7000-8000-333333333333");
const date1 = extractTimestampFromV7(uuid1);
const date2 = extractTimestampFromV7(uuid2);
const date3 = extractTimestampFromV7(uuid3);
console.log("UUIDs in chronological order:");
console.log(` ${formatUUID(uuid1)}: ${date1.toISOString()}`);
console.log(` ${formatUUID(uuid2)}: ${date2.toISOString()}`);
console.log(` ${formatUUID(uuid3)}: ${date3.
