feat: add username/password login, account settings, and changelog (#133) (#134)

- Add username/password login as additional auth mechanism alongside existing token
- First login must use token; password can be configured in Settings > Account
- Password login returns the existing static token (no auth middleware changes)
- Add account settings: setup, change password, change username, remove password
- Add logout button to sidebar footer
- Add version changelog popup (click version number in sidebar)
- Support all 8 locales (en, zh, de, es, fr, ja, ko, pt)
- Bump version to 0.4.3

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
ekko
2026-04-22 20:27:33 +08:00
committed by GitHub
parent 6f69c69802
commit 70ddbd0bcd
19 changed files with 1155 additions and 16 deletions
+53
View File
@@ -0,0 +1,53 @@
import { request } from './client'
export interface AuthStatus {
hasPasswordLogin: boolean
username: string | null
}
export async function fetchAuthStatus(): Promise<AuthStatus> {
const res = await fetch('/api/auth/status')
if (!res.ok) throw new Error('Failed to fetch auth status')
return res.json()
}
export async function loginWithPassword(username: string, password: string): Promise<string> {
const res = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
})
if (!res.ok) {
const data = await res.json().catch(() => ({}))
throw new Error(data.error || 'Login failed')
}
const data = await res.json()
return data.token
}
export async function setupPassword(username: string, password: string): Promise<void> {
return request('/api/auth/setup', {
method: 'POST',
body: JSON.stringify({ username, password }),
})
}
export async function changePassword(currentPassword: string, newPassword: string): Promise<void> {
return request('/api/auth/change-password', {
method: 'POST',
body: JSON.stringify({ currentPassword, newPassword }),
})
}
export async function changeUsername(currentPassword: string, newUsername: string): Promise<void> {
return request('/api/auth/change-username', {
method: 'POST',
body: JSON.stringify({ currentPassword, newUsername }),
})
}
export async function removePassword(): Promise<void> {
return request('/api/auth/password', {
method: 'DELETE',
})
}