feat: roles SPA foundations

This commit is contained in:
Florian Sylvain committed 2026-10-27 22:21:12 +01:00
1 parent 80f7037d3a
commit 907949aa12
180 files changed
+4308 -835

No files matched your search

+38 -9
View File
@@ -1,6 +1,10 @@
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
import { ApiError, useApi, type MeAuthor, type UserRole } from '@/composables/useApi'
import { ref } from 'vue'
import { ApiError, useApi, type MeAuthor } from '@/composables/useApi'
import type { Access } from '@/lib/permissions'
const REFUSAL_REFRESH_GAP_MS = 5000
const STALE_AFTER_MS = 30000
export type SessionStatus = 'idle' | 'checking' | 'ready' | 'error'
@@ -10,7 +14,7 @@ export interface Session {
username?: string
email?: string
displayName: string
role?: UserRole
access?: Access
author?: MeAuthor
}
@@ -19,10 +23,8 @@ export const useSessionStore = defineStore('session', () => {
const session = ref<Session | null>(null)
let pending: Promise<void> | null = null
const isOwner = computed(() => session.value?.role === 'owner')
const canManageContent = computed(
() => session.value?.role === 'owner' || session.value?.role === 'admin',
)
let lastAnswerAt: number | null = null
let lastAttemptAt: number | null = null
function check() {
if (pending) {
@@ -36,6 +38,7 @@ export const useSessionStore = defineStore('session', () => {
.then((result) => {
session.value = result
status.value = 'ready'
lastAnswerAt = Date.now()
})
.catch((error) => {
if (error instanceof ApiError && error.status === 401) {
@@ -59,13 +62,31 @@ export const useSessionStore = defineStore('session', () => {
async function refresh() {
const { getMe } = useApi()
lastAttemptAt = Date.now()
try {
session.value = await getMe()
lastAnswerAt = Date.now()
} catch {
return
}
}
async function refreshAfterRefusal() {
if (lastAttemptAt !== null && Date.now() - lastAttemptAt < REFUSAL_REFRESH_GAP_MS) {
return
}
await refresh()
}
async function refreshIfStale() {
if (!session.value || lastAnswerAt === null) {
return
}
if (Date.now() - lastAnswerAt > STALE_AFTER_MS) {
await refresh()
}
}
function setAuthor(author: MeAuthor | undefined) {
if (!session.value) {
return
@@ -87,13 +108,21 @@ export const useSessionStore = defineStore('session', () => {
return {
status,
session,
isOwner,
canManageContent,
check,
retry,
refresh,
refreshAfterRefusal,
refreshIfStale,
clear,
setAuthor,
setDisplayName,
}
})
export function refreshSessionWhenVisible() {
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
void useSessionStore().refreshIfStale()
}
})
}