import { createRouter, createWebHistory, type RouteLocationNormalized, type RouteLocationRaw, } from 'vue-router' import { useSessionStore } from '@/stores/session' export type AuthRequirement = 'public' | 'session' | 'verified' | 'any' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', component: () => import('@/views/RootView.vue'), meta: { auth: 'any' }, }, { path: '/login', component: () => import('@/views/LoginView.vue'), meta: { auth: 'public' }, }, { path: '/register', component: () => import('@/views/RegisterView.vue'), meta: { auth: 'public' }, }, { path: '/register/pending', component: () => import('@/views/PendingView.vue'), meta: { auth: 'session' }, }, { path: '/register/validate', component: () => import('@/views/VerifyView.vue'), meta: { auth: 'public' }, }, { path: '/register/reset/request', component: () => import('@/views/ResetRequestView.vue'), meta: { auth: 'public' }, }, { path: '/register/reset/validate', component: () => import('@/views/ResetConfirmView.vue'), meta: { auth: 'public' }, }, { path: '/invite/accept', component: () => import('@/views/AcceptInviteView.vue'), meta: { auth: 'public' }, }, { path: '/home', component: () => import('@/views/HomeView.vue'), meta: { auth: 'verified', title: 'Home' }, }, { path: '/article', component: () => import('@/views/ArticleView.vue'), meta: { auth: 'verified', title: 'Articles' }, }, { path: '/article/new', component: () => import('@/views/ArticleView.vue'), meta: { auth: 'verified', title: 'Articles' }, }, { path: '/article/:id/edit', component: () => import('@/views/EditorView.vue'), meta: { auth: 'verified', title: 'Editor' }, }, { path: '/users', component: () => import('@/views/UsersView.vue'), meta: { auth: 'verified', title: 'Users' }, }, { path: '/integration', component: () => import('@/views/IntegrationView.vue'), meta: { auth: 'verified', title: 'Integration' }, }, { path: '/:pathMatch(.*)*', component: () => import('@/views/NotFoundView.vue'), meta: { auth: 'any' }, }, ], }) export function resolveAuthRedirect( to: RouteLocationNormalized, session: ReturnType, ): RouteLocationRaw | true { const auth = to.meta.auth as AuthRequirement if (auth === 'public') { return true } if (session.status !== 'ready') { return true } const account = session.session if (!account) { if (auth === 'any') { return { path: '/login' } } return { path: '/login', query: { redirect: to.fullPath, reason: 'expired' }, } } if (!account.verified) { if (auth === 'verified' || auth === 'any') { return { path: '/register/pending' } } return true } if (auth === 'any') { return { path: '/home' } } return true } router.beforeEach((to) => { if (to.meta.auth === 'public') { return true } const session = useSessionStore() if (session.status === 'idle') { session.check() return true } if (session.status === 'checking') { return true } return resolveAuthRedirect(to, session) }) router.afterEach((to) => { if (to.meta.auth === 'public') { return } const session = useSessionStore() const settled = session.status === 'idle' || session.status === 'checking' ? session.check() : Promise.resolve() settled.then(() => { const destination = resolveAuthRedirect(router.currentRoute.value, session) if (destination !== true) { router.replace(destination) } }) }) export default router