fix(auth): keep login available during session check failures

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
This commit is contained in:
XiaoSeS 2026-09-24 11:39:22 +08:00
parent 8249e84454
commit e4ee6b6d9a
8 changed files with 33 additions and 2 deletions

View file

@ -86,6 +86,18 @@ test.describe('Auth Entry', () => {
await expect(page.getByText('Sign in directly with your existing OAuth account')).toHaveCount(0)
})
test('keeps the login form available when the session status check fails', async ({ page }) => {
await page.route('**/api/v1/auth/me', async (route) => {
await route.fulfill({ status: 503, contentType: 'application/json', body: '{"code":503,"msg":"Unavailable"}' })
})
await page.goto('/login')
await expect(page.getByLabel('Username')).toBeVisible()
await expect(page.getByLabel('Password', { exact: true })).toBeVisible()
await expect(page.getByRole('button', { name: 'Login' })).toBeVisible()
})
test('keeps configured session bootstrap available in the organization view', async ({ page }) => {
await page.route('**/runtime-config.js', async (route) => {
await route.fulfill({

View file

@ -9,6 +9,7 @@ describe('AuthShell', () => {
expect(html).toContain('dark:bg-slate-950')
expect(html).toContain('sticky top-0 hidden h-svh')
expect(html).toContain('authShell.heroTitle')
expect(html).toContain('authShell.shortTagline')
expect(html).toContain('login-skill-art-light.png')
expect(html).toContain('login-skill-art-dark.png')
expect(html).toContain('authShell.backHome')

View file

@ -48,7 +48,7 @@ export function AuthShell({ children, className }: AuthShellProps) {
<img src={withBasePath('/login-skill-art-dark.png')} alt="" width="1484" height="1060" className="hidden h-full w-full object-contain dark:block" />
</div>
<p className="absolute bottom-9 left-12 z-10 text-[10px] font-medium uppercase leading-4 tracking-[0.28em] text-slate-500 dark:text-slate-400 2xl:left-16">Skills<br />Build<br />Together</p>
<p className="absolute bottom-9 left-12 z-10 whitespace-pre-line text-[10px] font-medium uppercase leading-4 tracking-[0.28em] text-slate-500 dark:text-slate-400 2xl:left-16">{t('authShell.shortTagline')}</p>
</aside>
<div className="flex min-h-svh items-start justify-center px-5 pb-8 pt-20 sm:px-10 xl:px-12 xl:py-24">

View file

@ -1503,6 +1503,7 @@
"heroTitle": "Discover, preserve, and reuse\nyour team's skills",
"heroSubtitle": "Start with a SKILL.md.\nTurn experience into a capability your team can share.",
"heroFooter": "Bring team knowledge together and unlock skill value",
"shortTagline": "Skills\nBuild\nTogether",
"capabilities": "What you can do with SkillHub",
"discoverTitle": "Discover skills",
"discoverDescription": "Find reusable skills and practices across your team.",

View file

@ -1614,6 +1614,7 @@
"heroTitle": "Открывайте и сохраняйте\nнавыки вашей команды",
"heroSubtitle": "Начните с SKILL.md.\nПревратите опыт в доступный команде навык.",
"heroFooter": "Собирайте знания команды и раскрывайте ценность навыков",
"shortTagline": "Навыки\nобъединяют\nкоманду",
"capabilities": "Возможности SkillHub",
"discoverTitle": "Поиск навыков",
"discoverDescription": "Находите навыки и практики, которые команда может использовать повторно.",

View file

@ -1503,6 +1503,7 @@
"heroTitle": "让团队的技能\n被发现、被沉淀、被复用",
"heroSubtitle": "从一份 SKILL.md 开始,\n把经验转化为可共享的团队能力。",
"heroFooter": "汇聚团队智慧,释放技能价值",
"shortTagline": "让技能\n连接团队",
"capabilities": "SkillHub 的能力",
"discoverTitle": "发现技能",
"discoverDescription": "找到团队可复用的技能包与实践。",

View file

@ -62,6 +62,14 @@ describe('auth-route', () => {
await expect(redirectAuthenticated({ search: { returnTo: '/dashboard/tokens' } })).resolves.toBeUndefined()
})
it('keeps the login page available when the session status check fails', async () => {
const redirectAuthenticated = createRedirectAuthenticated(async () => {
throw new Error('Session status unavailable')
})
await expect(redirectAuthenticated({ search: { returnTo: '/dashboard/tokens' } })).resolves.toBeUndefined()
})
it('redirects authenticated visitors to the requested local page', async () => {
const redirectAuthenticated = createRedirectAuthenticated(async () => ({ userId: 'user-1' }))

View file

@ -40,7 +40,14 @@ function resolveAuthenticatedReturnTo(value: unknown) {
export function createRedirectAuthenticated(getCurrentUser: () => Promise<unknown>) {
return async function redirectAuthenticated({ search }: { search: { returnTo?: string } }) {
if (await getCurrentUser()) {
let user: unknown
try {
user = await getCurrentUser()
} catch {
// A failed status check must not make the login entry unavailable.
return
}
if (user) {
throw redirect({ to: resolveAuthenticatedReturnTo(search.returnTo), replace: true })
}
}