Files
WRNexusJS/packages/auth/src/normalize.ts
T
2026-07-29 12:51:10 +05:30

56 lines
1.7 KiB
TypeScript

import type { AuthIdentityType, AuthPublicUser, AuthUser } from "./types.ts";
export function normalizeEmail(value: string): string {
return value.trim().toLowerCase();
}
export function normalizeUsername(value: string): string {
return value.trim().toLowerCase();
}
export function normalizePhone(value: string): string {
const trimmed = value.trim();
const prefix = trimmed.startsWith("+") ? "+" : "";
return prefix + trimmed.replace(/\D/g, "");
}
export function normalizeIdentity(type: AuthIdentityType, value: string): string {
if (type === "email") return normalizeEmail(value);
if (type === "phone") return normalizePhone(value);
return normalizeUsername(value);
}
export function inferIdentityType(value: string): AuthIdentityType {
const input = value.trim();
if (input.includes("@")) return "email";
if (/^\+?[0-9 ()-]{7,}$/.test(input)) return "phone";
return "username";
}
export function publicUser(user: AuthUser): AuthPublicUser {
return {
id: user.id,
username: user.username,
displayName: user.displayName,
avatarUrl: user.avatarUrl,
status: user.status,
roles: [...user.roles],
emailVerified: user.emailVerified,
phoneVerified: user.phoneVerified,
mfaEnabled: user.mfaEnabled,
};
}
/** Return a same-origin path for post-authentication navigation. */
export function safeAuthReturnTo(value: string | undefined, origin: string): string | undefined {
if (!value) return undefined;
try {
const base = new URL(origin);
const target = new URL(value, base);
if (target.origin !== base.origin) return undefined;
return `${target.pathname}${target.search}${target.hash}`;
} catch {
return undefined;
}
}