Something went wrong. Try again.
Central platform for European atproto.<cc> country community websites atproto.eu
community atproto
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344// Normalise what people type into the sign-in box before it reaches the OAuth client. The client's// identity resolver only lowercases and then validates strictly, so "@name.bsky.social", a bare// "name", a pasted profile URL or an email address all failed with a raw English// `Invalid handle "..."` error. Pure, so it is unit-tested (handle-input.test.ts).
export type HandleInput = { ok: true; value: string } | { ok: false; reason: 'empty' | 'email' };
const PROFILE_URL = /^https?:\/\/(?:www\.)?bsky\.app\/profile\/([^/?#]+)/i;
export function normalizeHandleInput(raw: string): HandleInput { // Handles never contain whitespace; mobile keyboards and pastes add spaces, NBSP and zero-width chars. let s = raw.replace(/[\s\u00a0\u200b-\u200d\ufeff]/g, ''); if (!s) return { ok: false, reason: 'empty' };
const profile = s.match(PROFILE_URL); if (profile) s = decodeURIComponent(profile[1]); // Any other URL is a PDS / entryway URL, which the OAuth client accepts as-is. else if (/^https?:\/\//i.test(s)) return { ok: true, value: s };
s = s.replace(/^at:\/\//i, ''); // DIDs are case-sensitive identifiers; pass them through untouched. if (/^did:/i.test(s)) return { ok: true, value: s };
s = s.replace(/^@+/, ''); if (s.includes('@')) return { ok: false, reason: 'email' };
s = s.toLowerCase().replace(/\.+$/, ''); if (!s) return { ok: false, reason: 'empty' }; // A bare name is almost always a bsky.social account. if (!s.includes('.')) s = `${s}.bsky.social`; return { ok: true, value: s };}
/** Classify an OAuth sign-in error for a friendly message: identity resolution failed (typo, * handle that doesn't exist, broken custom-domain handle), or anything else. */export function loginErrorKind(err: unknown): 'handle' | 'generic' { const msg = String((err as { message?: unknown })?.message ?? err); return /Invalid handle|does not resolve to a DID|does not include the handle|resolveHandle|atproto-did|DoH/i.test( msg, ) ? 'handle' : 'generic';}