fix: prefer v1 auth with legacy recovery fallback

This commit is contained in:
Weilong Liao
2026-06-17 23:15:03 +08:00
committed by GitHub
parent 6a85405105
commit d5f5631287
3 changed files with 74 additions and 17 deletions

View File

@@ -180,7 +180,7 @@ function typed<T>(response: Promise<unknown>): V1Response<T> {
return response as unknown as V1Response<T>;
}
function isLegacyFallbackError(error: unknown): boolean {
export function isLegacyFallbackError(error: unknown): boolean {
const axiosError = error as {
response?: { status?: number; data?: { message?: string } | string };
message?: string;
@@ -556,25 +556,40 @@ export const providerApi = {
export const authApi = {
login(payload: LoginRequest) {
return httpClient.post<ApiEnvelope<any>>('/api/auth/login', payload);
return withLegacyFallback<any>(openApiV1.login({ body: payload }), () =>
httpClient.post<ApiEnvelope<any>>('/api/auth/login', payload),
);
},
logout() {
return httpClient.post<ApiEnvelope<OpenConfig>>('/api/auth/logout');
return withLegacyFallback<OpenConfig>(openApiV1.logout(), () =>
httpClient.post<ApiEnvelope<OpenConfig>>('/api/auth/logout'),
);
},
setupStatus() {
return httpClient.get<ApiEnvelope<any>>('/api/auth/setup-status');
return withLegacyFallback<any>(openApiV1.getAuthSetupStatus(), () =>
httpClient.get<ApiEnvelope<any>>('/api/auth/setup-status'),
);
},
setup(payload: SetupAuthRequest) {
return httpClient.post<ApiEnvelope<OpenConfig>>('/api/auth/setup', payload);
return withLegacyFallback<OpenConfig>(openApiV1.setupAuth({ body: payload }), () =>
httpClient.post<ApiEnvelope<OpenConfig>>('/api/auth/setup', payload),
);
},
setupTotp(payload?: TotpSetupRequest) {
return httpClient.post<ApiEnvelope<any>>('/api/auth/totp/setup', payload);
return withLegacyFallback<any>(openApiV1.setupTotp({ body: payload }), () =>
httpClient.post<ApiEnvelope<any>>('/api/auth/totp/setup', payload),
);
},
recoverTotp() {
return httpClient.post<ApiEnvelope<any>>('/api/auth/totp/recovery');
return withLegacyFallback<any>(openApiV1.recoverTotp(), () =>
httpClient.post<ApiEnvelope<any>>('/api/auth/totp/recovery'),
);
},
updateAccount(payload: UpdateAccountRequest) {
return httpClient.post<ApiEnvelope<OpenConfig>>('/api/auth/account/edit', payload);
return withLegacyFallback<OpenConfig>(
openApiV1.updateAuthAccount({ body: payload }),
() => httpClient.post<ApiEnvelope<OpenConfig>>('/api/auth/account/edit', payload),
);
},
};

View File

@@ -48,10 +48,11 @@
</template>
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue';
import axios, { type AxiosRequestConfig } from 'axios';
import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import type { ApiEnvelope, VersionData } from '@/api/v1';
import { httpClient } from '@/api/http';
import { useI18n } from '@/i18n/composables';
type StartTimeData = {
@@ -59,6 +60,7 @@ type StartTimeData = {
};
const { t } = useI18n();
const route = useRoute();
const visible = ref(false);
const restarting = ref(false);
@@ -68,6 +70,8 @@ const dashboardVersion = ref('');
const initialStartTime = ref<number | string | null>(null);
let restartTimer: ReturnType<typeof setInterval> | null = null;
let detecting = false;
const recoveryClient = axios.create();
function normalizeVersion(version?: string | null) {
return (version || '').trim().replace(/^v/i, '');
@@ -102,9 +106,26 @@ function getDismissKey() {
return `astrbot-upgrade-recovery-dismissed:${coreVersion.value}:${dashboardVersion.value}`;
}
function recoveryRequestConfig(validateStatus = false): AxiosRequestConfig {
const headers: Record<string, string> = {};
const token = localStorage.getItem('token');
const locale = localStorage.getItem('astrbot-locale');
if (token) {
headers.Authorization = `Bearer ${token}`;
}
if (locale) {
headers['Accept-Language'] = locale;
}
return {
headers,
...(validateStatus ? { validateStatus: () => true } : {}),
};
}
async function fetchLegacyStartTime() {
const response = await httpClient.get<ApiEnvelope<StartTimeData>>(
const response = await recoveryClient.get<ApiEnvelope<StartTimeData>>(
'/api/stat/start-time',
recoveryRequestConfig(),
);
return response.data?.data?.start_time ?? null;
}
@@ -153,7 +174,11 @@ async function restartCore() {
try {
initialStartTime.value =
initialStartTime.value ?? (await fetchLegacyStartTime());
await httpClient.post<ApiEnvelope<unknown>>('/api/stat/restart-core');
await recoveryClient.post<ApiEnvelope<unknown>>(
'/api/stat/restart-core',
undefined,
recoveryRequestConfig(),
);
statusMessage.value = t('core.common.upgradeRecovery.waiting');
waitForRestart();
} catch (_error) {
@@ -163,18 +188,22 @@ async function restartCore() {
}
async function detectUpgradeMismatch() {
if (detecting || visible.value || restarting.value) {
return;
}
detecting = true;
try {
const v1Response = await httpClient.get<ApiEnvelope<unknown>>(
const v1Response = await recoveryClient.get<ApiEnvelope<unknown>>(
'/api/v1/auth/setup-status',
{ validateStatus: () => true },
recoveryRequestConfig(true),
);
if (!isMissingApiKeyResponse(v1Response)) {
return;
}
const legacyResponse = await httpClient.get<ApiEnvelope<VersionData>>(
const legacyResponse = await recoveryClient.get<ApiEnvelope<VersionData>>(
'/api/stat/version',
{ validateStatus: () => true },
recoveryRequestConfig(true),
);
if (legacyResponse.status === 401 || legacyResponse.status >= 400) {
return;
@@ -195,6 +224,8 @@ async function detectUpgradeMismatch() {
visible.value = true;
} catch (_error) {
// This recovery dialog is best-effort and should never block the app.
} finally {
detecting = false;
}
}
@@ -202,6 +233,13 @@ onMounted(() => {
void detectUpgradeMismatch();
});
watch(
() => route.fullPath,
() => {
void detectUpgradeMismatch();
},
);
onBeforeUnmount(() => {
clearRestartTimer();
});

View File

@@ -17,7 +17,7 @@ import StyledMenu from "@/components/shared/StyledMenu.vue";
import { useLanguageSwitcher } from "@/i18n/composables";
import type { Locale } from "@/i18n/types";
import AboutPage from "@/views/AboutPage.vue";
import { authApi, statsApi, updatesApi } from "@/api/v1";
import { authApi, isLegacyFallbackError, statsApi, updatesApi } from "@/api/v1";
import { getDesktopRuntimeInfo } from "@/utils/desktopRuntime";
enableKatex();
@@ -479,6 +479,10 @@ function checkUpdate() {
: res.data.data.dashboard_has_new_version;
})
.catch((err) => {
if (isLegacyFallbackError(err)) {
console.log(err);
return;
}
if (err.response && err.response.status == 401) {
console.log("401");
const authStore = useAuthStore();