2026-04-23 15:24:06 +00:00
|
|
|
import * as axios from "axios";
|
2026-03-31 14:52:53 +00:00
|
|
|
import { defineStore } from "pinia";
|
|
|
|
|
import { ref } from "vue";
|
2026-04-28 17:06:21 +00:00
|
|
|
import { SSEManager, type SSEMessageResource } from "@/SSEManager";
|
2026-03-31 14:52:53 +00:00
|
|
|
import {
|
|
|
|
|
Organization,
|
2026-04-02 01:07:55 +00:00
|
|
|
Session,
|
|
|
|
|
SessionNotificationCounts,
|
2026-03-31 14:52:53 +00:00
|
|
|
URLs,
|
|
|
|
|
User,
|
2026-04-09 00:25:21 +00:00
|
|
|
} from "@/type/api";
|
2026-04-23 15:24:06 +00:00
|
|
|
import { apiClient, AxiosErrorJSON } from "@/client";
|
2026-03-31 14:52:53 +00:00
|
|
|
|
2026-04-23 15:24:06 +00:00
|
|
|
export class ErrorNotSignedIn extends Error {
|
|
|
|
|
constructor() {
|
|
|
|
|
super("not signed in");
|
|
|
|
|
this.name = "ErrorNotSignedIn";
|
|
|
|
|
Object.setPrototypeOf(this, ErrorNotSignedIn.prototype);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface SigninResult {
|
|
|
|
|
is_success: boolean;
|
|
|
|
|
status: number;
|
|
|
|
|
}
|
2026-03-31 14:52:53 +00:00
|
|
|
export const useSessionStore = defineStore("session", () => {
|
|
|
|
|
// State
|
2026-04-17 14:52:02 +00:00
|
|
|
const hasSession = ref<boolean>(false);
|
|
|
|
|
const isAuthenticated = ref<boolean>(false);
|
|
|
|
|
const isLoading = ref(true);
|
2026-04-02 21:31:31 +00:00
|
|
|
const impersonating = ref<string | null>(null);
|
2026-03-31 14:52:53 +00:00
|
|
|
const error = ref<string | null>(null);
|
2026-04-02 01:07:55 +00:00
|
|
|
const current = ref<Session | null>(null);
|
|
|
|
|
const notification_counts = ref<SessionNotificationCounts | null>(null);
|
|
|
|
|
const ongoingFetch = ref<Promise<Session> | null>(null);
|
|
|
|
|
const organization = ref<Organization | null>(null);
|
|
|
|
|
const self = ref<User | null>(null);
|
2026-03-31 14:52:53 +00:00
|
|
|
const urls = ref<URLs | null>(null);
|
|
|
|
|
|
|
|
|
|
// Subscription
|
2026-04-28 17:06:21 +00:00
|
|
|
SSEManager.subscribe((msg: SSEMessageResource) => {
|
2026-04-16 07:43:17 +00:00
|
|
|
if (msg.type == "sync:session") {
|
2026-03-31 14:52:53 +00:00
|
|
|
fetchSession();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Actions
|
2026-04-23 15:24:06 +00:00
|
|
|
async function doSignin(
|
|
|
|
|
password: string,
|
|
|
|
|
username: string,
|
|
|
|
|
): Promise<SigninResult> {
|
|
|
|
|
try {
|
2026-04-29 15:04:44 +00:00
|
|
|
console.log("begin signin request");
|
2026-04-23 15:24:06 +00:00
|
|
|
await apiClient.JSONPost("/api/signin", {
|
|
|
|
|
password: password,
|
|
|
|
|
username: username,
|
|
|
|
|
});
|
2026-04-29 15:04:44 +00:00
|
|
|
isAuthenticated.value = true;
|
|
|
|
|
console.log("set authenticated to true after signin request");
|
2026-04-23 15:24:06 +00:00
|
|
|
return {
|
|
|
|
|
is_success: true,
|
|
|
|
|
status: 200,
|
|
|
|
|
};
|
|
|
|
|
} catch (e: any) {
|
|
|
|
|
const data: AxiosErrorJSON =
|
|
|
|
|
e instanceof axios.AxiosError
|
|
|
|
|
? (e.toJSON() as AxiosErrorJSON)
|
|
|
|
|
: { status: 0 };
|
|
|
|
|
if (!data) throw e;
|
|
|
|
|
return {
|
|
|
|
|
is_success: false,
|
|
|
|
|
status: data.status,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-02 01:07:55 +00:00
|
|
|
async function fetchSession(): Promise<Session> {
|
2026-03-31 14:52:53 +00:00
|
|
|
error.value = null;
|
|
|
|
|
|
|
|
|
|
try {
|
2026-04-16 17:14:57 +00:00
|
|
|
const data: Session = await apiClient.JSONGet("/api/session");
|
2026-04-17 14:52:02 +00:00
|
|
|
isAuthenticated.value = true;
|
2026-04-23 15:24:06 +00:00
|
|
|
console.log(
|
|
|
|
|
"set authenticated",
|
|
|
|
|
isAuthenticated.value,
|
|
|
|
|
"due to successful GET /api/session",
|
|
|
|
|
);
|
2026-04-02 21:31:31 +00:00
|
|
|
impersonating.value = data.impersonating || null;
|
2026-04-02 01:07:55 +00:00
|
|
|
notification_counts.value = data.notification_counts;
|
|
|
|
|
organization.value = data.organization;
|
|
|
|
|
self.value = data.self;
|
2026-03-31 14:52:53 +00:00
|
|
|
urls.value = data.urls;
|
|
|
|
|
return data;
|
2026-04-23 15:24:06 +00:00
|
|
|
} catch (e: any) {
|
|
|
|
|
const data: AxiosErrorJSON =
|
|
|
|
|
e instanceof axios.AxiosError
|
|
|
|
|
? (e.toJSON() as AxiosErrorJSON)
|
|
|
|
|
: { status: 0 };
|
|
|
|
|
if (data.status == 401) {
|
|
|
|
|
throw new ErrorNotSignedIn();
|
|
|
|
|
}
|
|
|
|
|
console.error("Error fetching session:", e);
|
|
|
|
|
throw e;
|
2026-03-31 14:52:53 +00:00
|
|
|
} finally {
|
2026-04-17 14:52:02 +00:00
|
|
|
hasSession.value = true;
|
|
|
|
|
isLoading.value = false;
|
2026-04-16 17:14:57 +00:00
|
|
|
console.log("no longer loading session");
|
2026-03-31 14:52:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 14:52:02 +00:00
|
|
|
async function getAuthenticated(): Promise<boolean> {
|
|
|
|
|
await get();
|
|
|
|
|
return isAuthenticated.value;
|
2026-03-31 14:52:53 +00:00
|
|
|
}
|
2026-04-02 01:07:55 +00:00
|
|
|
|
|
|
|
|
async function get(): Promise<Session> {
|
|
|
|
|
if (current.value != null) {
|
|
|
|
|
return current.value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ongoingFetch.value !== null) {
|
|
|
|
|
return ongoingFetch.value;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-02 21:31:31 +00:00
|
|
|
const s = await fetchSession();
|
|
|
|
|
current.value = s;
|
|
|
|
|
ongoingFetch.value = null;
|
|
|
|
|
return s;
|
2026-04-02 01:07:55 +00:00
|
|
|
}
|
2026-04-16 17:14:57 +00:00
|
|
|
async function signout(): Promise<void> {
|
2026-04-17 14:52:02 +00:00
|
|
|
isAuthenticated.value = false;
|
2026-04-23 15:24:06 +00:00
|
|
|
console.log("set authenticated", isAuthenticated.value, "due to signout");
|
2026-04-16 17:14:57 +00:00
|
|
|
apiClient.JSONPost("/api/signout", {});
|
|
|
|
|
}
|
2026-03-31 14:52:53 +00:00
|
|
|
return {
|
|
|
|
|
// State
|
|
|
|
|
error,
|
2026-04-17 14:52:02 +00:00
|
|
|
getAuthenticated,
|
|
|
|
|
hasSession,
|
2026-04-02 21:31:31 +00:00
|
|
|
impersonating,
|
2026-04-17 14:52:02 +00:00
|
|
|
isAuthenticated,
|
|
|
|
|
isLoading,
|
2026-04-02 01:07:55 +00:00
|
|
|
notification_counts,
|
|
|
|
|
organization,
|
|
|
|
|
self,
|
2026-03-31 14:52:53 +00:00
|
|
|
urls,
|
|
|
|
|
// Actions
|
2026-04-23 15:24:06 +00:00
|
|
|
doSignin,
|
2026-03-31 14:52:53 +00:00
|
|
|
fetchSession,
|
2026-04-02 01:07:55 +00:00
|
|
|
get,
|
2026-04-16 17:14:57 +00:00
|
|
|
signout,
|
2026-03-31 14:52:53 +00:00
|
|
|
};
|
|
|
|
|
});
|