// bidi controls that ride along on a copied handle: bsky.app wraps handles in // U+202A…U+202C so they render left to right, and a handle can't contain any // of these legitimately (handles are ascii), so they only ever spoof or break a lookup const BIDI_CONTROLS = /[\u200e\u200f\u202a-\u202e\u2066-\u2069]/g; /** * A handle as the legacy appview treated it: bidi controls and surrounding * space removed, a leading `@` dropped, and lowercased (handles are * case-insensitive). A DID passes through with only the cleanup, since DIDs are * case-sensitive. */ export const normalizeHandle = (raw: string): string => { const handle = raw.replace(BIDI_CONTROLS, "").trim().replace(/^@/, ""); return handle.startsWith("did:") ? handle : handle.toLowerCase(); };