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
41 const stored = loadSession()
42 if (stored) {
43 try {
44 const session = await api.getSession(stored.accessJwt)
45 state.session = { ...session, accessJwt: stored.accessJwt, refreshJwt: stored.refreshJwt }
46 } catch (e) {
47 if (e instanceof ApiError && e.status === 401) {
48 try {
49 const refreshed = await api.refreshSession(stored.refreshJwt)
50 state.session = refreshed
51 saveSession(refreshed)
52 } catch {
53 saveSession(null)
54 state.session = null
55 }
56 } else {
57 saveSession(null)
58 state.session = null
59 }
60 }
61 }
62
63 state.loading = false
64}
65
66export async function login(identifier: string, password: string): Promise<void> {
67 state.loading = true
68 state.error = null
69
70 try {
71 const session = await api.createSession(identifier, password)
72 state.session = session
73 saveSession(session)
74 } catch (e) {
75 if (e instanceof ApiError) {
76 state.error = e.message
77 } else {
78 state.error = 'Login failed'
79 }
80 throw e
81 } finally {
82 state.loading = false
83 }
84}
85
86export async function register(params: CreateAccountParams): Promise<CreateAccountResult> {
87 try {
88 const result = await api.createAccount(params)
89 return result
90 } catch (e) {
91 if (e instanceof ApiError) {
92 state.error = e.message
93 } else {
94 state.error = 'Registration failed'
95 }
96 throw e
97 }
98}
99
100export async function confirmSignup(did: string, verificationCode: string): Promise<void> {
101 state.loading = true
102 state.error = null
103
104 try {
105 const result = await api.confirmSignup(did, verificationCode)
106 const session: Session = {
107 did: result.did,
108 handle: result.handle,
109 accessJwt: result.accessJwt,
110 refreshJwt: result.refreshJwt,
111 email: result.email,
112 emailConfirmed: result.emailConfirmed,
113 preferredChannel: result.preferredChannel,
114 preferredChannelVerified: result.preferredChannelVerified,
115 }
116 state.session = session
117 saveSession(session)
118 } catch (e) {
119 if (e instanceof ApiError) {
120 state.error = e.message
121 } else {
122 state.error = 'Verification failed'
123 }
124 throw e
125 } finally {
126 state.loading = false
127 }
128}
129
130export async function resendVerification(did: string): Promise<void> {
131 try {
132 await api.resendVerification(did)
133 } catch (e) {
134 if (e instanceof ApiError) {
135 throw e
136 }
137 throw new Error('Failed to resend verification code')
138 }
139}
140
141export async function logout(): Promise<void> {
142 if (state.session) {
143 try {
144 await api.deleteSession(state.session.accessJwt)
145 } catch {
146 // Ignore errors on logout
147 }
148 }
149 state.session = null
150 saveSession(null)
151}
152
153export function getAuthState() {
154 return state
155}
156
157export function getToken(): string | null {
158 return state.session?.accessJwt ?? null
159}
160
161export function isAuthenticated(): boolean {
162 return state.session !== null
163}
164
165export function _testSetState(newState: { session: Session | null; loading: boolean; error: string | null }) {
166 state.session = newState.session
167 state.loading = newState.loading
168 state.error = newState.error
169}
170
171export function _testReset() {
172 state.session = null
173 state.loading = true
174 state.error = null
175 localStorage.removeItem(STORAGE_KEY)
176}