/** * Plain-language copy for OAuth callback outcomes. Kept out of `mcp-oauth.ts` * so the direct session route loads it only when a callback actually failed. */ const CALLBACK_STAGE_LABELS: Record = { state_verify: "validating the connection attempt", client_lookup: "loading the OAuth client", token_exchange: "finishing provider authorization", tools_list: "verifying the MCP server", persist: "saving the connection", }; const RETRY = " Select Connect to try again."; const STALE_LINK = "This connection link is no longer valid or was already used."; /** * Plain-language copy for the callback reasons every integration flow shares: * the user cancelling at the provider, and a stale or reused callback link. * Returns null for anything flow-specific so callers keep their own wording. */ export function oauthCallbackReasonMessage(reason: string | null): string | null { switch (reason) { case "access_denied": case "provider_denied": return `You cancelled at the provider, so nothing was connected.${RETRY}`; case "provider_error": return `The provider didn't approve the connection.${RETRY}`; case "missing_code": return `The provider didn't finish authorization.${RETRY}`; case "state_expired": return `This connection link expired. Links last 10 minutes.${RETRY}`; case "state_invalid": case "state_replayed": return `${STALE_LINK}${RETRY}`; default: return null; } } /** * A failed OAuth callback with no flow-specific copy. A reason we have no * words for stays visible (as support needs it) after the generic line. */ export function oauthCallbackFailureMessage(reason: string | null): string { const shared = oauthCallbackReasonMessage(reason); if (shared) return shared; const code = reason?.trim().slice(0, 120); return code ? `Couldn't connect. Please try again. Reason: ${code}.` : "Couldn't connect. Please try again."; } export function mcpOAuthCallbackFailureMessage( stage: string | null, reason: string | null, ): string { const shared = oauthCallbackReasonMessage(reason); if (shared) return shared; if (stage === "state_verify") { return "This connection attempt expired or was already used. Try connecting again."; } if (stage === "client_lookup") { return "The OAuth client registration changed while connecting. Try again."; } if (stage === "token_exchange" && reason === "invalid_client") { return "The provider rejected the OAuth client registration. Try again; if it continues, the provider configuration needs attention."; } if (stage === "persist") { return reason === "timeout" ? "Authorization succeeded, but saving the connection timed out. Nothing was committed; try again." : "Authorization succeeded, but Opengeni couldn't save the connection. Try again."; } if (reason === "timeout") { const label = stage ? CALLBACK_STAGE_LABELS[stage] : null; return label ? `Connection timed out while ${label}. Try again.` : "Connection timed out. Try again."; } const label = stage ? CALLBACK_STAGE_LABELS[stage] : null; return label ? `Connection failed while ${label}. Try again.` : "Couldn't connect. Please try again."; }