Send sign-in mail as HTML so quoted-printable wrapping cannot break the verify URL.

Staging was delivering magic links that looked expired because the token query string was encoded and wrapped in plaintext MIME. Also read rate-limit retry from the API error body, mention spam in the success copy, and document SES relay DNS.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
adilallo
2026-09-01 10:01:25 -06:00
co-authored by Cursor
parent 511c3efb4c
commit d920e39f09
10 changed files with 258 additions and 112 deletions
+23 -36
View File
@@ -27,6 +27,26 @@ function readApiErrorMessage(data: unknown): string {
return "Request failed";
}
function retryAfterFromResponse(
res: Response,
data: unknown,
): number | undefined {
if (res.status !== 429) return undefined;
if (data && typeof data === "object" && "details" in data) {
const d = (data as { details?: unknown }).details;
if (d && typeof d === "object" && "retryAfterMs" in d) {
const ms = (d as { retryAfterMs?: unknown }).retryAfterMs;
if (typeof ms === "number" && ms > 0) return ms;
}
}
const h = res.headers.get("retry-after");
if (h) {
const sec = Number.parseInt(h, 10);
if (!Number.isNaN(sec)) return sec * 1000;
}
return undefined;
}
export async function fetchAuthSession(): Promise<{
user: { id: string; email: string } | null;
}> {
@@ -54,13 +74,12 @@ export async function requestMagicLink(
...(draft && Object.keys(draft).length > 0 ? { draft } : {}),
}),
});
const data = await parseJson<{ error?: string; retryAfterMs?: number }>(res);
const data: unknown = await parseJson(res);
if (!res.ok) {
return {
ok: false,
error: readApiErrorMessage(data),
retryAfterMs:
typeof data.retryAfterMs === "number" ? data.retryAfterMs : undefined,
retryAfterMs: retryAfterFromResponse(res, data),
};
}
return { ok: true };
@@ -85,22 +104,10 @@ export async function requestEmailChange(
});
const data: unknown = await res.json().catch(() => ({}));
if (!res.ok) {
let retryAfterMs: number | undefined;
if (
res.status === 429 &&
data &&
typeof data === "object" &&
"details" in data
) {
const d = (data as { details?: { retryAfterMs?: unknown } }).details;
if (d && typeof d.retryAfterMs === "number") {
retryAfterMs = d.retryAfterMs;
}
}
return {
ok: false,
error: readApiErrorMessage(data),
retryAfterMs,
retryAfterMs: retryAfterFromResponse(res, data),
};
}
return { ok: true };
@@ -438,26 +445,6 @@ export type RuleStakeholderMutationResult =
| { ok: true }
| { ok: false; error: string; status: number; retryAfterMs?: number };
function retryAfterFromResponse(
res: Response,
data: unknown,
): number | undefined {
if (res.status !== 429) return undefined;
if (data && typeof data === "object" && "details" in data) {
const d = (data as { details?: unknown }).details;
if (d && typeof d === "object" && "retryAfterMs" in d) {
const ms = (d as { retryAfterMs?: unknown }).retryAfterMs;
if (typeof ms === "number" && ms > 0) return ms;
}
}
const h = res.headers.get("retry-after");
if (h) {
const sec = Number.parseInt(h, 10);
if (!Number.isNaN(sec)) return sec * 1000;
}
return undefined;
}
export async function addRuleStakeholder(
ruleId: string,
email: string,