mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-08 00:02:20 +03:00
Integrated into release/v3.8.41 — Antigravity Token Expired badge: set tokenExpiresAt at creation + surface no-refresh-token as expired (#5326). Tests green (2 + 3).
This commit is contained in:
committed by
GitHub
parent
98c9f5b136
commit
cd9a9abbf5
@@ -9,7 +9,10 @@ import {
|
||||
pollForToken,
|
||||
resolveBrowserOAuthRedirectUri,
|
||||
} from "@/lib/oauth/providers";
|
||||
import { persistOAuthConnection } from "@/lib/oauth/connectionPersistence";
|
||||
import {
|
||||
persistOAuthConnection,
|
||||
buildOAuthConnectionCreatePayload,
|
||||
} from "@/lib/oauth/connectionPersistence";
|
||||
import { createDeviceFlowTicket, getDeviceFlowTicketStatus } from "@/lib/oauth/deviceFlowTickets";
|
||||
import {
|
||||
createProviderConnection,
|
||||
@@ -497,13 +500,9 @@ export async function POST(
|
||||
}
|
||||
}
|
||||
if (!connection) {
|
||||
connection = await createProviderConnection({
|
||||
provider,
|
||||
authType: "oauth",
|
||||
...tokenData,
|
||||
expiresAt,
|
||||
testStatus: "active",
|
||||
});
|
||||
connection = await createProviderConnection(
|
||||
buildOAuthConnectionCreatePayload(provider, tokenData, expiresAt)
|
||||
);
|
||||
}
|
||||
|
||||
// Auto sync to Cloud if enabled
|
||||
@@ -589,13 +588,9 @@ export async function POST(
|
||||
}
|
||||
}
|
||||
if (!connection) {
|
||||
connection = await createProviderConnection({
|
||||
provider,
|
||||
authType: "oauth",
|
||||
...result.tokens,
|
||||
expiresAt,
|
||||
testStatus: "active",
|
||||
});
|
||||
connection = await createProviderConnection(
|
||||
buildOAuthConnectionCreatePayload(provider, result.tokens, expiresAt)
|
||||
);
|
||||
}
|
||||
|
||||
// Auto sync to Cloud if enabled
|
||||
@@ -722,13 +717,9 @@ export async function POST(
|
||||
}
|
||||
}
|
||||
if (!connection) {
|
||||
connection = await createProviderConnection({
|
||||
provider,
|
||||
authType: "oauth",
|
||||
...tokenData,
|
||||
expiresAt,
|
||||
testStatus: "active",
|
||||
});
|
||||
connection = await createProviderConnection(
|
||||
buildOAuthConnectionCreatePayload(provider, tokenData, expiresAt)
|
||||
);
|
||||
}
|
||||
|
||||
await syncToCloudIfEnabled();
|
||||
@@ -796,13 +787,9 @@ export async function POST(
|
||||
}
|
||||
}
|
||||
if (!connection) {
|
||||
connection = await createProviderConnection({
|
||||
provider,
|
||||
authType: "oauth",
|
||||
...tokenData,
|
||||
expiresAt,
|
||||
testStatus: "active",
|
||||
});
|
||||
connection = await createProviderConnection(
|
||||
buildOAuthConnectionCreatePayload(provider, tokenData, expiresAt)
|
||||
);
|
||||
}
|
||||
|
||||
await syncToCloudIfEnabled();
|
||||
|
||||
@@ -27,6 +27,34 @@ function safeEqual(a: string | null | undefined, b: string | null | undefined):
|
||||
return timingSafeEqual(ba, bb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the create payload for a brand-new OAuth connection.
|
||||
*
|
||||
* #5326: mirror the freshly computed `expiresAt` into `tokenExpiresAt` at creation
|
||||
* time. The dashboard token-health badge prefers `tokenExpiresAt` over `expiresAt`
|
||||
* (ConnectionRow.tsx: `connection.tokenExpiresAt || connection.expiresAt`). If
|
||||
* `tokenExpiresAt` stays null on a freshly created connection, the badge falls back
|
||||
* to the original grant clock and can flash a false amber/"Token Expired" until the
|
||||
* first background refresh writes both fields together. All refresh paths already
|
||||
* persist `expiresAt` and `tokenExpiresAt` in lockstep
|
||||
* (tokenHealthCheck onPersist, tokenRefresh.updateProviderCredentials); this makes
|
||||
* creation consistent with them.
|
||||
*/
|
||||
export function buildOAuthConnectionCreatePayload(
|
||||
provider: string,
|
||||
tokenData: Record<string, any>,
|
||||
expiresAt: string | null
|
||||
) {
|
||||
return {
|
||||
provider,
|
||||
authType: "oauth" as const,
|
||||
...tokenData,
|
||||
expiresAt,
|
||||
tokenExpiresAt: expiresAt,
|
||||
testStatus: "active" as const,
|
||||
};
|
||||
}
|
||||
|
||||
async function syncToCloudIfEnabled(): Promise<void> {
|
||||
try {
|
||||
const cloudEnabled = await isCloudEnabled();
|
||||
@@ -76,13 +104,9 @@ export async function persistOAuthConnection(
|
||||
}
|
||||
}
|
||||
if (!connection) {
|
||||
connection = await createProviderConnection({
|
||||
provider,
|
||||
authType: "oauth",
|
||||
...tokenData,
|
||||
expiresAt,
|
||||
testStatus: "active",
|
||||
});
|
||||
connection = await createProviderConnection(
|
||||
buildOAuthConnectionCreatePayload(provider, tokenData, expiresAt)
|
||||
);
|
||||
}
|
||||
|
||||
await syncToCloudIfEnabled();
|
||||
|
||||
@@ -341,7 +341,36 @@ export async function checkConnection(conn) {
|
||||
const intervalMin = conn.healthCheckInterval ?? DEFAULT_HEALTH_CHECK_INTERVAL_MIN;
|
||||
if (intervalMin <= 0) return;
|
||||
if (!conn.isActive) return;
|
||||
if (!conn.refreshToken || typeof conn.refreshToken !== "string") return;
|
||||
if (!conn.refreshToken || typeof conn.refreshToken !== "string") {
|
||||
// #5326: a refresh-CAPABLE provider (e.g. antigravity/gemini) with no usable
|
||||
// refresh token can never self-heal via the sweep — it genuinely needs re-auth.
|
||||
// Silently skipping here left the row at testStatus="active" while the dashboard
|
||||
// badge (which derives expiry from tokenExpiresAt||expiresAt) showed a confusing
|
||||
// cosmetic "Token Expired". Surface reality as a terminal "expired" status instead.
|
||||
// Guard tightly so we do NOT clobber:
|
||||
// - providers that simply don't use refresh tokens (supportsTokenRefresh=false)
|
||||
// - connections already in a terminal/specific state (expired/banned/credits_exhausted)
|
||||
// - transient cooldown state (unavailable) owned by the request path
|
||||
const refreshCapableNeedsReauth =
|
||||
supportsTokenRefresh(conn.provider) &&
|
||||
(!conn.testStatus || conn.testStatus === "active");
|
||||
if (refreshCapableNeedsReauth) {
|
||||
const now = new Date().toISOString();
|
||||
await updateProviderConnection(conn.id, {
|
||||
testStatus: "expired",
|
||||
lastHealthCheckAt: now,
|
||||
lastError: "No refresh token available — re-authenticate this account.",
|
||||
lastErrorAt: now,
|
||||
lastErrorType: "no_refresh_token",
|
||||
lastErrorSource: "oauth",
|
||||
errorCode: "no_refresh_token",
|
||||
});
|
||||
log(
|
||||
`${LOG_PREFIX} ${conn.provider}/${getConnectionLogLabel(conn)} has no refresh token; marking expired (needs re-auth)`
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Retry expired connections with exponential backoff up to EXPIRED_RETRY_MAX times.
|
||||
if (conn.testStatus === "expired") {
|
||||
|
||||
Reference in New Issue
Block a user