Files
crank/apps/ui/js/auth.js
T
github-ops ba29ac7b94
Deploy / deploy (push) Successful in 2m44s
CI / Rust Checks (push) Successful in 5m31s
CI / UI Checks (push) Successful in 5s
CI / Deployment Manifests (push) Successful in 2s
CI / Frontend E2E (push) Successful in 4m24s
chore: publish clean community baseline
2026-06-19 16:45:51 +00:00

254 lines
7.2 KiB
JavaScript

(function() {
var STORAGE_KEY = 'crank_user';
var sessionCache = null;
var sessionPromise = null;
function tKey(key) {
return typeof t === 'function' ? t(key) : key;
}
function tfKey(key, vars) {
return typeof tf === 'function' ? tf(key, vars) : key;
}
function roleLabel(role) {
var normalized = String(role || 'viewer').toLowerCase();
if (normalized === 'operator') return tKey('workspace_setup.role.operator');
if (normalized === 'owner') return tKey('workspace_setup.role.owner');
if (normalized === 'admin') return tKey('workspace_setup.role.admin');
if (normalized === 'viewer') return tKey('workspace_setup.role.viewer');
return normalized.replace(/^\w/, function(char) { return char.toUpperCase(); });
}
function currentWorkspaceLabel() {
if (window.getCurrentWorkspace) {
var workspace = window.getCurrentWorkspace();
if (workspace && workspace.name) {
return workspace.name;
}
}
try {
return localStorage.getItem('crank_workspace_slug') || tKey('settings.nav.workspace');
} catch (_error) {
return tKey('settings.nav.workspace');
}
}
function isLoginPage() {
return /\/(?:html\/login\.html|login)\/?$/.test(window.location.pathname);
}
function loginUrl() {
return (window.CrankRoutes && window.CrankRoutes.login) || '/login';
}
function homeUrl() {
return (window.CrankRoutes && window.CrankRoutes.home) || '/';
}
function clearUserMirror() {
sessionCache = null;
sessionPromise = null;
try {
localStorage.removeItem(STORAGE_KEY);
} catch (_error) {}
renderShellIdentity(null);
}
function primaryMembership(session) {
if (!(session && session.memberships && session.memberships.length)) {
return null;
}
if (session.current_workspace_id) {
var currentMembership = session.memberships.find(function(item) {
return item.workspace && item.workspace.id === session.current_workspace_id;
});
if (currentMembership) {
return currentMembership;
}
}
if (window.getCurrentWorkspace) {
var currentWorkspace = window.getCurrentWorkspace();
if (currentWorkspace) {
var matched = session.memberships.find(function(item) {
return item.workspace && item.workspace.id === currentWorkspace.id;
});
if (matched) {
return matched;
}
}
}
return session.memberships[0];
}
function initials(displayName, email) {
var source = displayName || email || 'Crank';
return source
.split(/\s+/)
.filter(Boolean)
.slice(0, 2)
.map(function(part) { return part.charAt(0).toUpperCase(); })
.join('') || 'CR';
}
function persistUserMirror(session) {
var membership = primaryMembership(session);
var user = {
id: session.user.id,
name: session.user.display_name,
email: session.user.email,
role: membership ? roleLabel(membership.role) : tKey('workspace_setup.role.viewer'),
workspace: membership ? membership.workspace.slug : '',
workspaceId: membership ? membership.workspace.id : '',
initials: initials(session.user.display_name, session.user.email),
};
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(user));
} catch (_error) {}
}
function mirroredUser() {
try {
return JSON.parse(localStorage.getItem(STORAGE_KEY));
} catch (_error) {
return null;
}
}
function renderShellIdentity(session) {
var membership = primaryMembership(session);
var fallbackUser = mirroredUser();
var displayName = session && session.user
? (session.user.display_name || session.user.email || 'Crank')
: (fallbackUser && fallbackUser.name) || 'Crank';
var email = session && session.user
? session.user.email
: fallbackUser && fallbackUser.email;
var role = membership
? roleLabel(membership.role)
: (fallbackUser && fallbackUser.role) || tKey('workspace_setup.role.viewer');
var workspace = membership && membership.workspace
? (membership.workspace.display_name || membership.workspace.slug || membership.workspace.id)
: currentWorkspaceLabel();
var avatarValue = initials(displayName, email);
document.querySelectorAll('.nav-avatar').forEach(function(element) {
element.textContent = avatarValue;
});
document.querySelectorAll('.user-dropdown-name').forEach(function(element) {
element.textContent = displayName;
});
document.querySelectorAll('.user-dropdown-role').forEach(function(element) {
element.textContent = role + ' · ' + workspace;
});
if (window.CrankDiagnostics && typeof window.CrankDiagnostics.ensureShellTestIds === 'function') {
window.CrankDiagnostics.ensureShellTestIds();
}
}
function replaceSession(session) {
sessionCache = session;
persistUserMirror(session);
renderShellIdentity(session);
window.dispatchEvent(new CustomEvent('crank:sessionchange', { detail: session }));
return session;
}
async function fetchSession(force) {
if (!force && sessionCache) {
return sessionCache;
}
if (!force && sessionPromise) {
return sessionPromise;
}
sessionPromise = window.CrankApi.getSession()
.then(function(session) {
return replaceSession(session);
})
.catch(function(error) {
clearUserMirror();
throw error;
})
.finally(function() {
sessionPromise = null;
});
return sessionPromise;
}
async function guardProtectedPage() {
try {
return await fetchSession(false);
} catch (error) {
if (error && error.status === 401) {
window.location.replace(loginUrl());
return null;
}
throw error;
}
}
async function guardLoginPage() {
try {
await fetchSession(false);
window.location.replace(homeUrl());
} catch (error) {
if (!error || error.status !== 401) {
throw error;
}
}
}
async function login(email, password) {
var session = await window.CrankApi.login({
email: email,
password: password,
});
replaceSession(session);
window.location.href = homeUrl();
}
async function logout() {
try {
await window.CrankApi.logout();
} finally {
clearUserMirror();
window.location.href = loginUrl();
}
}
function handleUnauthorized() {
if (isLoginPage()) {
clearUserMirror();
return;
}
clearUserMirror();
window.location.replace(loginUrl());
}
window.CrankAuth = {
fetchSession: fetchSession,
replaceSession: replaceSession,
getCachedSession: function() { return sessionCache; },
renderShellIdentity: function() {
renderShellIdentity(sessionCache);
},
guardProtectedPage: guardProtectedPage,
guardLoginPage: guardLoginPage,
login: login,
logout: logout,
handleUnauthorized: handleUnauthorized,
};
window.addEventListener('crank:workspacechange', function() {
renderShellIdentity(sessionCache);
});
window.addEventListener('crank:sessionchange', function(event) {
renderShellIdentity(event.detail || sessionCache);
});
document.addEventListener('DOMContentLoaded', function() {
renderShellIdentity(sessionCache);
});
}());