From 9cb2795496afbfa4856c847e78c78df4506ab95b Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sun, 1 Jun 2025 11:04:22 -0500 Subject: [PATCH] Add genUserName module --- src/lib/genUserName.test.ts | 33 +++++++++++++++++++++++++++++++++ src/lib/genUserName.ts | 29 +++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 src/lib/genUserName.test.ts create mode 100644 src/lib/genUserName.ts diff --git a/src/lib/genUserName.test.ts b/src/lib/genUserName.test.ts new file mode 100644 index 0000000..b92b52a --- /dev/null +++ b/src/lib/genUserName.test.ts @@ -0,0 +1,33 @@ +import { describe, it, expect } from 'vitest'; +import { genUserName } from './genUserName'; + +describe('genUserName', () => { + it('generates a deterministic name from a seed', () => { + const seed = 'test-seed-123'; + const name1 = genUserName(seed); + const name2 = genUserName(seed); + + expect(name1).toEqual('Brave Whale'); + expect(name1).toEqual(name2); + }); + + it('generates different names for different seeds', () => { + const name1 = genUserName('seed1'); + const name2 = genUserName('seed2'); + const name3 = genUserName('seed3'); + + // While it's theoretically possible for different seeds to generate the same name, + // it's very unlikely with our word lists + expect(name1).not.toBe(name2); + expect(name2).not.toBe(name3); + expect(name1).not.toBe(name3); + }); + + it('handles typical Nostr pubkey format', () => { + // Typical hex pubkey (64 characters) + const pubkey = 'e4690a13290739da123aa17d553851dec4cdd0e9d89aa18de3741c446caf8761'; + const name = genUserName(pubkey); + + expect(name).toEqual('Gentle Hawk'); + }); +}); \ No newline at end of file diff --git a/src/lib/genUserName.ts b/src/lib/genUserName.ts new file mode 100644 index 0000000..0ac13d9 --- /dev/null +++ b/src/lib/genUserName.ts @@ -0,0 +1,29 @@ +/** Generate a deterministic user display name based on a string seed. */ +export function genUserName(seed: string): string { + // Use a simple hash of the pubkey to generate consistent adjective + noun combinations + const adjectives = [ + 'Swift', 'Bright', 'Calm', 'Bold', 'Wise', 'Kind', 'Quick', 'Brave', + 'Cool', 'Sharp', 'Clear', 'Strong', 'Smart', 'Fast', 'Keen', 'Pure', + 'Noble', 'Gentle', 'Fierce', 'Steady', 'Clever', 'Proud', 'Silent', 'Wild' + ]; + + const nouns = [ + 'Fox', 'Eagle', 'Wolf', 'Bear', 'Lion', 'Tiger', 'Hawk', 'Owl', + 'Deer', 'Raven', 'Falcon', 'Lynx', 'Otter', 'Whale', 'Shark', 'Dolphin', + 'Phoenix', 'Dragon', 'Panther', 'Jaguar', 'Cheetah', 'Leopard', 'Puma', 'Cobra' + ]; + + // Create a simple hash from the pubkey + let hash = 0; + for (let i = 0; i < seed.length; i++) { + const char = seed.charCodeAt(i); + hash = ((hash << 5) - hash) + char; + hash = hash & hash; // Convert to 32-bit integer + } + + // Use absolute value to ensure positive index + const adjIndex = Math.abs(hash) % adjectives.length; + const nounIndex = Math.abs(hash >> 8) % nouns.length; + + return [adjectives[adjIndex], nouns[nounIndex]].join(' '); +} \ No newline at end of file