fix(onboarding): handle www. and bare-domain X/Twitter URLs in research extractHandle

The previous extractHandle only stripped exact "https://x.com/" / "https://twitter.com/"
prefixes (and one leading "@"), so common URL formats produced garbage:

  https://www.x.com/vansh        -> "https:"
  x.com/vansh                    -> "x.com"
  https://mobile.twitter.com/foo -> "https:"

That junk handle was then passed straight to the Grok call, wasting an LLM
request and returning unusable research to the user.

Rewrite the parser to use the URL constructor (mirroring the more robust
parseXAccount in apps/web/app/api/onboarding/account-status/route.ts) so any
subdomain or bare-domain form works. Validate the resulting handle against the
1-15 char alphanumeric+underscore rule before invoking the model; fail fast
with a 400 instead of burning a model call on a bad input.
This commit is contained in:
vimzh 2026-05-24 11:44:23 +05:30
parent a8d36df38e
commit 698aa9ea69

View file

@ -7,16 +7,28 @@ interface ResearchRequest {
email?: string
}
function extractHandle(url: string): string {
const cleaned = url
.toLowerCase()
.replace("https://x.com/", "")
.replace("https://twitter.com/", "")
.replace("http://x.com/", "")
.replace("http://twitter.com/", "")
.replace("@", "")
function extractHandle(input: string): string {
const trimmed = input.trim()
if (!trimmed) return ""
return (cleaned.split("/")[0] ?? cleaned).split("?")[0] ?? cleaned
let handle = trimmed.replace(/^@+/, "")
const lower = handle.toLowerCase()
if (lower.includes("x.com") || lower.includes("twitter.com")) {
try {
const parsed = new URL(
handle.startsWith("http://") || handle.startsWith("https://")
? handle
: `https://${handle}`,
)
handle = parsed.pathname.split("/").filter(Boolean)[0] ?? ""
} catch {
handle =
handle.match(/(?:x\.com|twitter\.com)\/([^/\s?#]+)/i)?.[1] ?? ""
}
}
return handle.replace(/^@+/, "").split(/[/?#]/)[0]?.toLowerCase() ?? ""
}
function finalPrompt(handle: string, userContext: string) {
@ -47,6 +59,13 @@ export async function POST(req: Request) {
const handle = extractHandle(xUrl)
if (!/^[A-Za-z0-9_]{1,15}$/.test(handle)) {
return Response.json(
{ error: "Could not parse a valid X/Twitter handle from the input" },
{ status: 400 },
)
}
const contextParts: string[] = []
if (name) contextParts.push(`Name: ${name}`)
if (email) contextParts.push(`Email: ${email}`)