export const EMAIL_UNVERIFIED = "email_unverified";
export const EMAIL_UNVERIFIED_MESSAGE =
"Verify your email address before making changes. Check your inbox for the link, or resend it from Settings.";
/** Where the resend button lives; the error detail and the banner both link here. */
export const VERIFY_EMAIL_PATH = "/settings";
const HTTP_FORBIDDEN = 403;
/** Whether a thrown server error (server function or JSON API) is the unverified-email refusal. */
export function isEmailUnverifiedError(error: unknown): boolean {
if (!(error instanceof Error)) return false;
const { status, detail } = error as Error & { status?: number; detail?: Record<string, unknown> | null };
return status === HTTP_FORBIDDEN && detail?.code === EMAIL_UNVERIFIED;
}
/** Site admins and viewers counted as verified (see toViewer) may write and pay. */
export function canWriteAsViewer(viewer: { isAdmin: boolean; emailVerified: boolean } | null | undefined): boolean {
return Boolean(viewer && (viewer.isAdmin || viewer.emailVerified));
}
/**
* The refusal text for a write by this viewer, or null when it may write. Deploy, scratch and CI job tokens
* resolve to no viewer: they act for their own repository and only a verified admin can mint them.
*/
export function writeRefusal(viewer: { isAdmin: boolean; emailVerified: boolean } | null): string | null {
return viewer && !canWriteAsViewer(viewer) ? EMAIL_UNVERIFIED_MESSAGE : null;
}