68 lines
2.0 KiB
TypeScript
68 lines
2.0 KiB
TypeScript
import type { AdminUserDto, AuthResponse, LoginInput } from "@imen/shared";
|
|||
|
|
import { defineStore } from "pinia";
|
||
|
|
import { rawApi, setAuthHooks } from "@/api/http";
|
||
|
|
import { router } from "@/router";
|
||
|
|
|
||
|
|
let refreshing: Promise<boolean> | null = null;
|
||
|
|
|
||
|
|
export const useAuthStore = defineStore("auth", {
|
||
|
|
state: () => ({
|
||
|
|
/** short-lived access token, kept in memory only */
|
||
|
|
token: "",
|
||
|
|
user: null as AdminUserDto | null,
|
||
|
|
/** true once the initial session check has run */
|
||
|
|
ready: false,
|
||
|
|
}),
|
||
|
|
getters: {
|
||
|
|
isAdmin: (s) => s.user?.role === "ADMIN",
|
||
|
|
},
|
||
|
|
actions: {
|
||
|
|
setSession(r: AuthResponse) {
|
||
|
|
this.token = r.accessToken;
|
||
|
|
this.user = r.user;
|
||
|
|
},
|
||
|
|
clear() {
|
||
|
|
this.token = "";
|
||
|
|
this.user = null;
|
||
|
|
},
|
||
|
|
async login(input: LoginInput) {
|
||
|
|
this.setSession(await rawApi<AuthResponse>("/admin/auth/login", { method: "POST", body: input }));
|
||
|
|
},
|
||
|
|
/** Exchanges the refresh cookie for a new access token; concurrent calls share one request */
|
||
|
|
refresh(): Promise<boolean> {
|
||
|
|
refreshing ??= rawApi<AuthResponse>("/admin/auth/refresh", { method: "POST" })
|
||
|
|
.then((r) => {
|
||
|
|
this.setSession(r);
|
||
|
|
return true;
|
||
|
|
})
|
||
|
|
.catch(() => {
|
||
|
|
this.clear();
|
||
|
|
return false;
|
||
|
|
})
|
||
|
|
.finally(() => {
|
||
|
|
refreshing = null;
|
||
|
|
});
|
||
|
|
return refreshing;
|
||
|
|
},
|
||
|
|
/** Restores the session after a page load (the refresh cookie survives reloads) */
|
||
|
|
async init() {
|
||
|
|
if (this.ready) return;
|
||
|
|
setAuthHooks({
|
||
|
|
token: () => this.token,
|
||
|
|
refresh: () => this.refresh(),
|
||
|
|
onExpired: () => {
|
||
|
|
this.clear();
|
||
|
|
void router.push({ name: "login", query: { redirect: router.currentRoute.value.fullPath } });
|
||
|
|
},
|
||
|
|
});
|
||
|
|
await this.refresh();
|
||
|
|
this.ready = true;
|
||
|
|
},
|
||
|
|
async logout() {
|
||
|
|
await rawApi("/admin/auth/logout", { method: "POST" }).catch(() => undefined);
|
||
|
|
this.clear();
|
||
|
|
await router.push({ name: "login" });
|
||
|
|
},
|
||
|
|
},
|
||
|
|
});
|