76 lines
2.5 KiB
TypeScript
76 lines
2.5 KiB
TypeScript
import { createHash } from 'crypto';
|
|
|
|
/**
|
|
* Generates a deterministic UUID v4 from a seed string.
|
|
*
|
|
* This is used for postgres seeding to ensure all IDs are valid UUIDs
|
|
* while maintaining determinism across runs (important for tests and reproducible seeds).
|
|
*
|
|
* The function uses SHA-256 hash of the seed, then formats it as a UUID v4
|
|
* with proper version (0100) and variant (10xx) bits.
|
|
*
|
|
* @param seedKey - The deterministic seed string (e.g., "team-3", "driver-1")
|
|
* @returns A valid UUID v4 string
|
|
*
|
|
* @example
|
|
* stableUuidFromSeedKey("team-3")
|
|
* // Returns: "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" (deterministic)
|
|
*/
|
|
export function stableUuidFromSeedKey(seedKey: string): string {
|
|
// Create a deterministic hash from the seed
|
|
const hash = createHash('sha256').update(seedKey).digest('hex');
|
|
|
|
// Take first 32 characters for UUID
|
|
const uuidHex = hash.substring(0, 32);
|
|
|
|
// Format as UUID v4 with proper version and variant bits
|
|
// UUID v4 format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
|
// where x is any hex digit, y is one of [8, 9, a, b]
|
|
|
|
// Build the UUID step by step
|
|
const part1 = uuidHex.substring(0, 8);
|
|
const part2 = uuidHex.substring(8, 12);
|
|
const part3 = '4' + uuidHex.substring(13, 16); // Version 4
|
|
const variantChar = ['8', '9', 'a', 'b'][parseInt(uuidHex.charAt(16), 16) % 4];
|
|
const part4 = variantChar + uuidHex.substring(17, 20);
|
|
const part5 = uuidHex.substring(20, 32);
|
|
|
|
return `${part1}-${part2}-${part3}-${part4}-${part5}`;
|
|
}
|
|
|
|
/**
|
|
* Returns an ID appropriate for the current persistence mode.
|
|
*
|
|
* For postgres mode: returns a deterministic UUID
|
|
* For inmemory mode: returns the original deterministic string ID
|
|
*
|
|
* @param seedKey - The deterministic seed string (e.g., "team-3")
|
|
* @param mode - The persistence mode
|
|
* @returns Either a UUID (postgres) or the original string (inmemory)
|
|
*
|
|
* @example
|
|
* seedId("team-3", "postgres") // Returns UUID
|
|
* seedId("team-3", "inmemory") // Returns "team-3"
|
|
*/
|
|
export function seedId(seedKey: string, mode: 'postgres' | 'inmemory'): string {
|
|
if (mode === 'postgres') {
|
|
return stableUuidFromSeedKey(seedKey);
|
|
}
|
|
return seedKey;
|
|
}
|
|
|
|
/**
|
|
* Returns a UUID for postgres seeding.
|
|
*
|
|
* Convenience wrapper around seedId with mode already set to 'postgres'.
|
|
* Use this when you know you're in postgres mode.
|
|
*
|
|
* @param seedKey - The deterministic seed string
|
|
* @returns A valid UUID v4 string
|
|
*
|
|
* @example
|
|
* seedUuid("driver-1") // Returns UUID
|
|
*/
|
|
export function seedUuid(seedKey: string): string {
|
|
return stableUuidFromSeedKey(seedKey);
|
|
} |