返回 DeepSeek-Reasonix
handle.ts
根目录 / workers / accounts / src / lib / handle.ts
1 import { randomSuffix } from "../auth/crypto";
2
3 // Names that must never become a public handle (routes, infra, impersonation).
4 const RESERVED = new Set([
5 "admin", "administrator", "root", "system", "support", "help", "about", "api",
6 "auth", "login", "logout", "register", "signup", "signin", "reset", "verify",
7 "forgot", "account", "settings", "me", "u", "user", "users", "profile",
8 "reasonix", "www", "mail", "no-reply", "noreply", "null", "undefined", "anonymous",
9 ]);
10
11 // Lowercase, collapse runs of disallowed characters to single underscores, and
12 // trim underscores from the ends.
13 export function normalizeHandle(raw: string): string {
14 return raw
15 .toLowerCase()
16 .replace(/[^a-z0-9_]+/g, "_")
17 .replace(/_+/g, "_")
18 .replace(/^_+|_+$/g, "");
19 }
20
21 // 3–30 chars, [a-z0-9_], must start and end with an alphanumeric, not reserved.
22 export function isValidHandle(handle: string): boolean {
23 if (handle.length < 3 || handle.length > 30) return false;
24 if (!/^[a-z0-9](?:[a-z0-9_]*[a-z0-9])?$/.test(handle)) return false;
25 return !RESERVED.has(handle);
26 }
27
28 // A normalized, valid starting handle derived from the email local-part. Falls
29 // back to a random "user…" handle when the local-part can't yield a valid one.
30 export function deriveHandleBase(email: string): string {
31 let base = normalizeHandle(email.split("@")[0] ?? "");
32 if (base.length > 24) base = base.slice(0, 24).replace(/_+$/g, "");
33 if (base.length < 3 || RESERVED.has(base)) base = `user${randomSuffix(4)}`;
34 return base;
35 }
36
36 lines TYPESCRIPT