This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
import { computed, ref } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
import { apiRequest, clearAccessToken, setAccessToken, setRefreshHandler } from '../api'
|
||||
|
||||
export const useAuthStore = defineStore('auth', () => {
|
||||
const user = ref(null)
|
||||
const accessToken = ref('')
|
||||
const status = ref('idle')
|
||||
|
||||
const isAuthenticated = computed(() => Boolean(accessToken.value))
|
||||
|
||||
function applyAccessToken(token) {
|
||||
accessToken.value = token || ''
|
||||
setAccessToken(accessToken.value)
|
||||
}
|
||||
|
||||
function clearSession() {
|
||||
user.value = null
|
||||
accessToken.value = ''
|
||||
clearAccessToken()
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
status.value = 'loading'
|
||||
|
||||
try {
|
||||
const data = await apiRequest('/auth/refresh', {
|
||||
method: 'POST',
|
||||
skipAuth: true,
|
||||
skipRefresh: true,
|
||||
})
|
||||
|
||||
const token = data?.accessToken || ''
|
||||
if (!token) {
|
||||
clearSession()
|
||||
status.value = 'idle'
|
||||
return false
|
||||
}
|
||||
|
||||
applyAccessToken(token)
|
||||
status.value = 'idle'
|
||||
return true
|
||||
} catch {
|
||||
clearSession()
|
||||
status.value = 'idle'
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchMe() {
|
||||
try {
|
||||
const data = await apiRequest('/me', { method: 'GET' })
|
||||
user.value = data?.user || data || null
|
||||
return user.value
|
||||
} catch {
|
||||
user.value = null
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function bootstrap() {
|
||||
// Try to restore session using refresh cookie.
|
||||
const ok = await refresh()
|
||||
if (ok) {
|
||||
await fetchMe()
|
||||
}
|
||||
}
|
||||
|
||||
async function login({ email, password }) {
|
||||
status.value = 'loading'
|
||||
try {
|
||||
const data = await apiRequest('/auth/login', {
|
||||
method: 'POST',
|
||||
skipAuth: true,
|
||||
body: { email, password },
|
||||
})
|
||||
|
||||
applyAccessToken(data?.accessToken || '')
|
||||
user.value = data?.user || null
|
||||
|
||||
status.value = 'idle'
|
||||
return true
|
||||
} catch (err) {
|
||||
clearSession()
|
||||
status.value = 'error'
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async function signup({ email, password, name }) {
|
||||
status.value = 'loading'
|
||||
try {
|
||||
const data = await apiRequest('/auth/signup', {
|
||||
method: 'POST',
|
||||
skipAuth: true,
|
||||
body: { email, password, name },
|
||||
})
|
||||
|
||||
applyAccessToken(data?.accessToken || '')
|
||||
user.value = data?.user || null
|
||||
|
||||
status.value = 'idle'
|
||||
return true
|
||||
} catch (err) {
|
||||
clearSession()
|
||||
status.value = 'error'
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async function logout() {
|
||||
status.value = 'loading'
|
||||
try {
|
||||
await apiRequest('/auth/logout', { method: 'POST', skipRefresh: true })
|
||||
} finally {
|
||||
clearSession()
|
||||
status.value = 'idle'
|
||||
}
|
||||
}
|
||||
|
||||
// Allow apiRequest() to refresh tokens automatically on 401.
|
||||
setRefreshHandler(async () => {
|
||||
const data = await apiRequest('/auth/refresh', {
|
||||
method: 'POST',
|
||||
skipAuth: true,
|
||||
skipRefresh: true,
|
||||
})
|
||||
|
||||
const token = data?.accessToken || ''
|
||||
applyAccessToken(token)
|
||||
return token
|
||||
})
|
||||
|
||||
// Keep api module token in sync if a token was already set.
|
||||
setAccessToken(accessToken.value)
|
||||
|
||||
return {
|
||||
user,
|
||||
accessToken,
|
||||
status,
|
||||
isAuthenticated,
|
||||
bootstrap,
|
||||
fetchMe,
|
||||
refresh,
|
||||
login,
|
||||
signup,
|
||||
logout,
|
||||
clearSession,
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user