mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-04 21:04:37 +08:00
Fix signups blocked when Emailable validation fails
Move validateVerifyResponse() inside the try/catch in checkEmailWithEmailable so malformed API responses return an error status instead of throwing. Add defensive error handling in createDependencies so any unexpected emailable failure gracefully falls back to emailableScore: null rather than crashing the entire signup flow. https://claude.ai/code/session_01Mheg5YNfD95Rn3786449iA
This commit is contained in:
parent
c062ae62d2
commit
e8743106c9
@ -107,14 +107,14 @@ export async function checkEmailWithEmailable(
|
||||
|
||||
return await traceSpan("checking email address with Emailable", async () => {
|
||||
const client = clientFactory(apiKey);
|
||||
let raw: unknown;
|
||||
let response: ReturnType<typeof validateVerifyResponse>;
|
||||
try {
|
||||
raw = await verifyWithRetries(() => client.verify(email), 4, retryDelayBase);
|
||||
const raw = await verifyWithRetries(() => client.verify(email), 4, retryDelayBase);
|
||||
response = validateVerifyResponse(raw);
|
||||
} catch (error) {
|
||||
captureError("emailable-api-error", error);
|
||||
return { status: "error", error, emailableScore: null };
|
||||
}
|
||||
const response = validateVerifyResponse(raw);
|
||||
|
||||
if (response.state === "undeliverable" || response.disposable) {
|
||||
return { status: "not-deliverable", emailableResponse: response, emailableScore: response.score };
|
||||
@ -165,9 +165,9 @@ import.meta.vitest?.describe("checkEmailWithEmailable(...)", () => {
|
||||
expect(result.status).toBe("error");
|
||||
});
|
||||
|
||||
test("throws on malformed Emailable response bodies", async ({ expect }) => {
|
||||
test("returns error on malformed Emailable response bodies", async ({ expect }) => {
|
||||
const malformedClient = fakeClient(async () => "definitely not an object");
|
||||
await expect(checkEmailWithEmailable("test@gmail.com", { _clientFactory: malformedClient }))
|
||||
.rejects.toThrowError("Emailable returned a non-object response body");
|
||||
const result = await checkEmailWithEmailable("test@gmail.com", { _clientFactory: malformedClient });
|
||||
expect(result.status).toBe("error");
|
||||
});
|
||||
});
|
||||
|
||||
@ -2,6 +2,7 @@ import { getPrismaClientForTenancy, getPrismaSchemaForTenancy, sqlQuoteIdent } f
|
||||
import { signUpRiskEngine } from "@/private";
|
||||
import type { SignUpRiskScoresCrud } from "@stackframe/stack-shared/dist/interface/crud/users";
|
||||
import type { SignUpAuthMethod } from "@stackframe/stack-shared/dist/utils/auth-methods";
|
||||
import { captureError } from "@stackframe/stack-shared/dist/utils/errors";
|
||||
import { checkEmailWithEmailable } from "./emailable";
|
||||
import { type DerivedSignUpHeuristicFacts } from "./sign-up-heuristics";
|
||||
import type { Tenancy } from "./tenancies";
|
||||
@ -98,9 +99,14 @@ async function loadRecentSignUpStats(
|
||||
|
||||
function createDependencies(tenancy: Tenancy) {
|
||||
return {
|
||||
checkPrimaryEmailRisk: async (email: string) => ({
|
||||
emailableScore: (await checkEmailWithEmailable(email)).emailableScore,
|
||||
}),
|
||||
checkPrimaryEmailRisk: async (email: string) => {
|
||||
try {
|
||||
return { emailableScore: (await checkEmailWithEmailable(email)).emailableScore };
|
||||
} catch (error) {
|
||||
captureError("check-primary-email-risk", error);
|
||||
return { emailableScore: null };
|
||||
}
|
||||
},
|
||||
loadRecentSignUpStats: (request: SignUpRiskRecentStatsRequest) => loadRecentSignUpStats(tenancy, request),
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user