const STORAGE_KEY = "aurask.portal.session";
const TAB_KEY = "aurask.portal.activeTab";
const app = document.querySelector("#app");
const state = {
config: null,
sessionToken: window.localStorage.getItem(STORAGE_KEY) || "",
profile: null,
activeTab: window.localStorage.getItem(TAB_KEY) || "workflows",
lyFormOpen: false,
loading: true,
error: "",
};
function detectApiBase() {
if (window.location.protocol === "file:") return "http://127.0.0.1:8080";
if (["127.0.0.1", "localhost"].includes(window.location.hostname)) return "http://127.0.0.1:8080";
return `${window.location.origin}/api`;
}
function normalizeApiBase(url) {
return (url || detectApiBase()).replace(/\/$/, "");
}
async function request(path, options = {}) {
const headers = new Headers(options.headers || {});
headers.set("Accept", "application/json");
if (options.body !== undefined) headers.set("Content-Type", "application/json");
if (state.sessionToken) headers.set("Authorization", `Bearer ${state.sessionToken}`);
const response = await fetch(`${normalizeApiBase(state.config?.public_api_base_url)}${path}`, {
...options,
headers,
body: options.body !== undefined ? JSON.stringify(options.body) : undefined,
});
const payload = await response.json().catch(() => ({}));
if (!response.ok) {
const message = payload?.error?.message || payload?.message || "Request failed";
const error = new Error(message);
error.status = response.status;
error.payload = payload;
throw error;
}
return payload;
}
function persistSession(token) {
state.sessionToken = token || "";
if (state.sessionToken) {
window.localStorage.setItem(STORAGE_KEY, state.sessionToken);
} else {
window.localStorage.removeItem(STORAGE_KEY);
}
}
function setTab(tab) {
state.activeTab = tab;
window.localStorage.setItem(TAB_KEY, tab);
render();
}
function initials(label) {
return (label || "AU")
.split(/\s+/)
.filter(Boolean)
.slice(0, 2)
.map((part) => part[0]?.toUpperCase())
.join("");
}
function escapeHtml(value) {
return String(value || "")
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
function withEmbedContext(baseUrl) {
if (!baseUrl) return "";
const url = new URL(baseUrl, window.location.origin);
if (state.profile?.tenant?.id) url.searchParams.set("tenant_id", state.profile.tenant.id);
if (state.profile?.workspace?.id) url.searchParams.set("workspace_id", state.profile.workspace.id);
url.searchParams.set("source", "aurask-protal");
return url.toString();
}
function ensureSigninRoute() {
if (state.profile) return;
if (window.location.pathname !== "/signin") {
window.history.replaceState({}, "", "/signin");
}
}
function ensureDashboardRoute() {
if (!state.profile) return;
if (!window.location.pathname.startsWith("/app")) {
window.history.replaceState({}, "", "/app");
}
}
async function bootstrap() {
state.loading = true;
render();
try {
const activeApiBase = detectApiBase();
const localHost = window.location.protocol === "file:" || ["127.0.0.1", "localhost"].includes(window.location.hostname);
state.config = await fetch(`${activeApiBase}/auth/config`).then((response) => response.json());
state.config.public_api_base_url = normalizeApiBase(localHost ? activeApiBase : state.config.public_api_base_url || activeApiBase);
if (state.sessionToken) {
try {
state.profile = await request("/auth/session");
ensureDashboardRoute();
} catch (error) {
persistSession("");
state.profile = null;
}
}
if (!state.profile) ensureSigninRoute();
} catch (error) {
state.error = error.message || "Failed to load Aurask configuration";
} finally {
state.loading = false;
render();
mountGoogleButton();
}
}
async function submitLySso(event) {
event.preventDefault();
state.error = "";
render();
const form = new FormData(event.currentTarget);
try {
const payload = await request("/auth/ly-sso/login", {
method: "POST",
body: {
username: String(form.get("username") || "").trim(),
password: String(form.get("password") || ""),
},
});
persistSession(payload.token);
state.profile = payload;
state.lyFormOpen = false;
ensureDashboardRoute();
} catch (error) {
state.error = error.message || "LY SSO sign-in failed";
} finally {
render();
mountGoogleButton();
}
}
async function signInWithGoogle(idToken) {
state.error = "";
render();
try {
const payload = await request("/auth/google/login", {
method: "POST",
body: { id_token: idToken },
});
persistSession(payload.token);
state.profile = payload;
ensureDashboardRoute();
} catch (error) {
state.error = error.message || "Google sign-in failed";
render();
}
}
async function logout() {
try {
await request("/auth/logout", { method: "POST" });
} catch (error) {
console.warn("Logout request failed", error);
}
persistSession("");
state.profile = null;
state.lyFormOpen = false;
ensureSigninRoute();
render();
mountGoogleButton();
}
function mountGoogleButton() {
const googleBox = document.querySelector("#googleButton");
if (!googleBox || !state.config?.auth?.google?.enabled || !state.config?.auth?.google?.client_id) return;
if (!window.google?.accounts?.id) return;
googleBox.innerHTML = "";
window.google.accounts.id.initialize({
client_id: state.config.auth.google.client_id,
callback: ({ credential }) => signInWithGoogle(credential),
});
window.google.accounts.id.renderButton(googleBox, {
theme: "outline",
size: "large",
shape: "pill",
text: "signup_with",
width: 320,
});
}
function renderStatusPills() {
if (!state.config) return "";
return `
API: ${escapeHtml(state.config.public_api_base_url)}
Web: ${escapeHtml(state.config.public_base_url)}
DevCloud API Image Ready
`;
}
function renderSignin() {
const lyConfig = state.config?.auth?.ly_sso || {};
const googleConfig = state.config?.auth?.google || {};
const googleEnabled = Boolean(googleConfig.enabled && googleConfig.client_id);
app.innerHTML = `
A
Aurask
Ship AI workflows with private knowledge, safer by default.
Sign in to open your personal workspace, manage Langflow workflows, and use AnythingLLM knowledge bases from one portal.
${renderStatusPills()}
${
googleEnabled
? 'Google new-user login provisions a dedicated Aurask workspace on first sign-in.
'
: 'Set `AURASK_GOOGLE_CLIENT_ID` to enable Google one-tap registration.
'
}
${
state.lyFormOpen
? `
`
: ""
}
${state.error ? `${escapeHtml(state.error)}
` : ""}
`;
document.querySelector("#lyButton")?.addEventListener("click", () => {
if (lyConfig.login_url) {
window.location.href = lyConfig.login_url;
return;
}
state.lyFormOpen = !state.lyFormOpen;
render();
mountGoogleButton();
});
document.querySelector("#lyForm")?.addEventListener("submit", submitLySso);
document.querySelector("#googleFallbackButton")?.addEventListener("click", () => {
document.querySelector("#googleButton")?.scrollIntoView({ behavior: "smooth", block: "center" });
});
}
function renderDashboard() {
const user = state.profile?.user || {};
const tenant = state.profile?.tenant || {};
const workspace = state.profile?.workspace || {};
const quota = state.profile?.quota || {};
const config = state.profile?.config || state.config || {};
const langflowUrl = withEmbedContext(config.embeds?.langflow_url);
const anythingllmUrl = withEmbedContext(config.embeds?.anythingllm_url);
app.innerHTML = `
A
Aurask Workspace
${escapeHtml(tenant.name || "Aurask")}
${state.error ? `${escapeHtml(state.error)}
` : ""}
`;
document.querySelectorAll("[data-tab]").forEach((button) => {
button.addEventListener("click", () => setTab(button.dataset.tab));
});
document.querySelector("#logoutButton")?.addEventListener("click", logout);
}
function renderLoading() {
app.innerHTML = `
Loading Aurask...
`;
}
function render() {
if (state.loading) {
renderLoading();
return;
}
if (state.profile) {
renderDashboard();
return;
}
renderSignin();
}
window.addEventListener("popstate", render);
if (state.sessionToken) {
document.addEventListener("visibilitychange", async () => {
if (document.visibilityState !== "visible" || !state.profile) return;
try {
state.profile = await request("/auth/session");
render();
} catch (error) {
persistSession("");
state.profile = null;
state.error = "Your Aurask session has expired. Please sign in again.";
ensureSigninRoute();
render();
mountGoogleButton();
}
});
}
const googleScript = document.createElement("script");
googleScript.src = "https://accounts.google.com/gsi/client";
googleScript.async = true;
googleScript.defer = true;
googleScript.onload = mountGoogleButton;
document.head.appendChild(googleScript);
bootstrap();