How a feature ships here
The superpowers build loop, with a real shipped feature as evidence: brainstorm → spec → plan → TDD → review → merge-commit PR.
src/lib/server/auth.ts43 lines · login L18–23
Outline 8 symbols
- LoginResponse type
- MfaChallenge type
- post function
- LoginResult type export
- login function export
- verifyMfa function export
- changePassword function export
- logout function export
1import { LQ_API } from './env';
2import type { components } from '$lib/api/backend';
3
4type LoginResponse = components['schemas']['LoginResponse'];
5type MfaChallenge = components['schemas']['MfaChallenge'];
6
7async function post(path: string, body: unknown, token?: string): Promise<Response> {
8 const headers: Record<string, string> = { 'content-type': 'application/json' };
9 if (token) headers.authorization = `Bearer ${token}`;
10 return fetch(`${LQ_API()}${path}`, { method: 'POST', headers, body: JSON.stringify(body) });
11}
12
13export type LoginResult =
14 | { kind: 'ok'; data: LoginResponse }
15 | { kind: 'mfa'; data: MfaChallenge }
16 | { kind: 'invalid' };
17
18export async function login(email: string, password: string): Promise<LoginResult> {
19 const res = await post('/api/v1/auth/login', { email, password });
20 if (res.status === 200) return { kind: 'ok', data: await res.json() };
21 if (res.status === 423) return { kind: 'mfa', data: await res.json() };
22 return { kind: 'invalid' };
23}
24
25export async function verifyMfa(mfa_token: string, code: string): Promise<LoginResult> {
26 const res = await post('/api/v1/auth/mfa/verify', { mfa_token, code });
27 if (res.status === 200) return { kind: 'ok', data: await res.json() };
28 return { kind: 'invalid' };
29}
30
31export async function changePassword(
32 token: string,
33 current_password: string,
34 new_password: string
35): Promise<boolean> {
36 const res = await post('/api/v1/auth/change-password', { current_password, new_password }, token);
37 return res.status === 204;
38}
39
40export async function logout(token: string | undefined): Promise<void> {
41 if (token) await post('/api/v1/auth/logout', {}, token).catch(() => {});
42}
43