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