/** * Extra personal NIP-05 handles for a profile. * * A kind-0 profile has ONE standard `nip05` field, and other clients editing it * may drop anything non-standard. So the extra handles live in a **separate * NIP-78 record** (kind 30078, `d=skatespots:profile-handles`) authored by the * user — the primary stays in `nip05` (works everywhere), the extras ride here * (SkateSpots-only, but durable against another client re-saving the profile). * * Each handle must resolve (via `/.well-known/nostr.json`) to the **owner's own** * pubkey — verified the same way as a crew handle, just against the profile key. */ import { APP_DATA_KIND } from '@/lib/types'; export { APP_DATA_KIND }; /** `d` identifier for the per-user extra-handles record. */ export const PROFILE_HANDLES_D = 'skatespots:profile-handles'; export const MAX_PROFILE_HANDLES = 5; /** `local@domain.tld` per NIP-05 (local part is `[a-z0-9-_.]`). */ export const NIP05_HANDLE_RE = /^[a-z0-9\-_.]+@[a-z0-9.-]+\.[a-z]{2,}$/; /** Normalise a raw handle; returns null when it isn't a valid `local@domain`. */ export function normalizeHandle(raw: string): string | null { const value = raw.trim().toLowerCase(); return NIP05_HANDLE_RE.test(value) ? value : null; } /** All extra handles stored on a profile-handles event (deduped, ordered, capped). */ export function parseProfileHandles(event: { tags: string[][] }): string[] { const handles = event.tags .filter(([name, value]) => name === 'nip05' && !!value?.trim()) .map(([, value]) => value.trim().toLowerCase()) .filter((value) => NIP05_HANDLE_RE.test(value)); return [...new Set(handles)].slice(0, MAX_PROFILE_HANDLES); } /** Tags for the addressable record. An empty list clears the extras (replace). */ export function profileHandlesTags(handles: string[]): string[][] { const clean = [ ...new Set(handles.map((h) => h.trim().toLowerCase()).filter((h) => NIP05_HANDLE_RE.test(h))), ].slice(0, MAX_PROFILE_HANDLES); const tags: string[][] = [ ['d', PROFILE_HANDLES_D], ['alt', 'SkateSpots profile handles'], ]; for (const handle of clean) tags.push(['nip05', handle]); return tags; }