Files
OpenSquawk/app/stores/auth.ts
2025-09-18 19:41:31 +02:00

133 lines
3.2 KiB
TypeScript

import { defineStore } from 'pinia'
export const AUTH_TOKEN_STORAGE_KEY = 'os_access_token'
interface Credentials {
email: string
password: string
}
interface RegisterPayload extends Credentials {
name?: string
invitationCode: string
acceptTerms: boolean
acceptPrivacy: boolean
}
type UserRole = 'user' | 'admin' | 'dev'
interface AuthUser {
id: string
email: string
name?: string
role: UserRole
createdAt: string
}
interface AuthState {
accessToken: string
user: AuthUser | null
initialized: boolean
}
function loadToken(): string {
if (typeof window === 'undefined') return ''
return localStorage.getItem(AUTH_TOKEN_STORAGE_KEY) || ''
}
function persistToken(token: string) {
if (typeof window === 'undefined') return
if (token) {
localStorage.setItem(AUTH_TOKEN_STORAGE_KEY, token)
} else {
localStorage.removeItem(AUTH_TOKEN_STORAGE_KEY)
}
}
export const useAuthStore = defineStore('auth', {
state: (): AuthState => ({
accessToken: loadToken(),
user: null,
initialized: false,
}),
getters: {
isAuthenticated: (state) => Boolean(state.accessToken),
},
actions: {
setAccessToken(token: string) {
this.accessToken = token
persistToken(token)
},
setUser(user: AuthUser | null) {
this.user = user
},
async login(payload: Credentials) {
const response = await $fetch<{ accessToken: string; user: AuthUser }>('/api/service/auth/login', {
method: 'POST',
body: payload,
})
this.setAccessToken(response.accessToken)
this.setUser(response.user)
return response.user
},
async register(payload: RegisterPayload) {
const response = await $fetch<{ accessToken: string; user: AuthUser }>('/api/service/auth/register', {
method: 'POST',
body: payload,
})
this.setAccessToken(response.accessToken)
this.setUser(response.user)
return response.user
},
async tryRefresh() {
try {
const response = await $fetch<{ accessToken: string }>('/api/service/auth/refresh', {
method: 'POST',
})
this.setAccessToken(response.accessToken)
return true
} catch {
this.setAccessToken('')
return false
}
},
async fetchUser() {
if (!this.accessToken) {
this.setUser(null)
this.initialized = true
return null
}
try {
const user = await $fetch<AuthUser>('/api/auth/me', {
headers: { Authorization: `Bearer ${this.accessToken}` },
})
this.setUser(user)
this.initialized = true
return user
} catch (err) {
console.warn('Failed to load user session', err)
this.setAccessToken('')
this.setUser(null)
this.initialized = true
return null
}
},
async logout() {
try {
if (this.accessToken) {
await $fetch('/api/auth/logout', {
method: 'POST',
headers: { Authorization: `Bearer ${this.accessToken}` },
})
}
} catch (err) {
console.warn('Logout failed', err)
} finally {
this.setAccessToken('')
this.setUser(null)
}
},
},
})