this repo has no description
1import { api, type Session, type CreateAccountParams, type CreateAccountResult, ApiError } from './api'
2const STORAGE_KEY = 'bspds_session'
3interface AuthState {
4 session: Session | null
5 loading: boolean
6 error: string | null
7}
8let state = $state<AuthState>({
9 session: null,
10 loading: true,
11 error: null,
12})
13function saveSession(session: Session | null) {
14 if (session) {
15 localStorage.setItem(STORAGE_KEY, JSON.stringify(session))
16 } else {
17 localStorage.removeItem(STORAGE_KEY)
18 }
19}
20function loadSession(): Session | null {
21 const stored = localStorage.getItem(STORAGE_KEY)
22 if (stored) {
23 try {
24 return JSON.parse(stored)
25 } catch {
26 return null
27 }
28 }
29 return null
30}
31export async function initAuth() {
32 state.loading = true
33 state.error = null
34 const stored = loadSession()
35 if (stored) {
36 try {
37 const session = await api.getSession(stored.accessJwt)
38 state.session = { ...session, accessJwt: stored.accessJwt, refreshJwt: stored.refreshJwt }
39 } catch (e) {
40 if (e instanceof ApiError && e.status === 401) {
41 try {
42 const refreshed = await api.refreshSession(stored.refreshJwt)
43 state.session = refreshed
44 saveSession(refreshed)
45 } catch {
46 saveSession(null)
47 state.session = null
48 }
49 } else {
50 saveSession(null)
51 state.session = null
52 }
53 }
54 }
55 state.loading = false
56}
57export async function login(identifier: string, password: string): Promise<void> {
58 state.loading = true
59 state.error = null
60 try {
61 const session = await api.createSession(identifier, password)
62 state.session = session
63 saveSession(session)
64 } catch (e) {
65 if (e instanceof ApiError) {
66 state.error = e.message
67 } else {
68 state.error = 'Login failed'
69 }
70 throw e
71 } finally {
72 state.loading = false
73 }
74}
75export async function register(params: CreateAccountParams): Promise<CreateAccountResult> {
76 try {
77 const result = await api.createAccount(params)
78 return result
79 } catch (e) {
80 if (e instanceof ApiError) {
81 state.error = e.message
82 } else {
83 state.error = 'Registration failed'
84 }
85 throw e
86 }
87}
88export async function confirmSignup(did: string, verificationCode: string): Promise<void> {
89 state.loading = true
90 state.error = null
91 try {
92 const result = await api.confirmSignup(did, verificationCode)
93 const session: Session = {
94 did: result.did,
95 handle: result.handle,
96 accessJwt: result.accessJwt,
97 refreshJwt: result.refreshJwt,
98 email: result.email,
99 emailConfirmed: result.emailConfirmed,
100 preferredChannel: result.preferredChannel,
101 preferredChannelVerified: result.preferredChannelVerified,
102 }
103 state.session = session
104 saveSession(session)
105 } catch (e) {
106 if (e instanceof ApiError) {
107 state.error = e.message
108 } else {
109 state.error = 'Verification failed'
110 }
111 throw e
112 } finally {
113 state.loading = false
114 }
115}
116export async function resendVerification(did: string): Promise<void> {
117 try {
118 await api.resendVerification(did)
119 } catch (e) {
120 if (e instanceof ApiError) {
121 throw e
122 }
123 throw new Error('Failed to resend verification code')
124 }
125}
126export async function logout(): Promise<void> {
127 if (state.session) {
128 try {
129 await api.deleteSession(state.session.accessJwt)
130 } catch {
131 // Ignore errors on logout
132 }
133 }
134 state.session = null
135 saveSession(null)
136}
137export function getAuthState() {
138 return state
139}
140export function getToken(): string | null {
141 return state.session?.accessJwt ?? null
142}
143export function isAuthenticated(): boolean {
144 return state.session !== null
145}
146export function _testSetState(newState: { session: Session | null; loading: boolean; error: string | null }) {
147 state.session = newState.session
148 state.loading = newState.loading
149 state.error = newState.error
150}
151export function _testReset() {
152 state.session = null
153 state.loading = true
154 state.error = null
155 localStorage.removeItem(STORAGE_KEY)
156}