Something went wrong. Try again.
Monorepo for the nibling.run platform
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738import type { Did, Handle } from '@atcute/lexicons';import { isDid, isHandle } from '@atcute/lexicons/syntax';
/** A handle or a DID: what every actor-accepting entry point in the app, API, and SDK takes. */export type ActorIdentifier = Did | Handle;
/** * `input`, then `decodeURIComponent(input)` when that changes it and succeeds, in that order. A * `did:web` port's `%3A` is part of the DID's own syntax, not transport encoding, so the raw form * is always tried first and the decoded form is a fallback for a handle or DID that arrived * percent-encoded (e.g. from a `%40`-encoded leading `@`). */function decodeCandidates(input: string): string[] { const candidates = [input]; try { const decoded = decodeURIComponent(input); if (decoded !== input) candidates.push(decoded); } catch { // Malformed percent-escapes: the raw candidate is all there is. } return candidates;}
/** * Parses a handle or DID from arbitrary user or URL input: an optional leading `@`, case-insensitive * handles, and either percent-decoded or still-encoded input. Returns undefined rather than throwing, * so callers that need a non-throwing check (route parsing) don't need a try/catch. */export function parseActorIdentifier(identifier: string): ActorIdentifier | undefined { for (const candidate of decodeCandidates(identifier.trim())) { const stripped = candidate.replace(/^@/, ''); if (isDid(stripped)) return stripped; const handle = stripped.toLowerCase(); if (isHandle(handle)) return handle; } return undefined;}