overcentric
Version:
Overcentric watches your website, product, and users - and tells you what matters and what to do about it.
99 lines (98 loc) • 4.03 kB
JavaScript
import { generateUuid } from './identity';
const SESSION_TIMEOUT = 30 * 60 * 1000; // 30 minutes in milliseconds
const COOKIE_MAX_AGE = 30 * 60; // 30 minutes in seconds
function sessionCookieName(projectId) { return `overcentric_session_id_${projectId}`; }
function activityCookieName(projectId) { return `overcentric_session_activity_${projectId}`; }
function sessionKey(projectId) { return `overcentric_session_${projectId}`; }
function setCrossDomainCookie(name, value, maxAge) {
try {
const isSecure = window.location.protocol === 'https:';
const secureFlag = isSecure ? '; Secure' : '';
document.cookie = `${name}=${value}; path=/; max-age=${maxAge}; SameSite=Lax${secureFlag}`;
try {
const domain = window.location.hostname.split('.').slice(-2).join('.');
document.cookie = `${name}=${value}; domain=.${domain}; path=/; max-age=${maxAge}; SameSite=Lax${secureFlag}`;
}
catch (e) {
console.debug('Could not set cookie on parent domain');
}
}
catch (e) {
console.warn(`Failed to set ${name} cookie:`, e);
}
}
function getCookie(name) {
var _a, _b;
try {
const value = (_b = (_a = document.cookie
.split('; ')
.find(row => row.startsWith(`${name}=`))) === null || _a === void 0 ? void 0 : _a.split('=')) === null || _b === void 0 ? void 0 : _b[1];
return value || null;
}
catch (e) {
console.warn(`Failed to get ${name} cookie:`, e);
return null;
}
}
/**
* Get or create a session ID scoped to the given project.
*/
export function getSessionId(projectId) {
const now = Date.now();
const SESSION_COOKIE_NAME = sessionCookieName(projectId);
const ACTIVITY_COOKIE_NAME = activityCookieName(projectId);
const SESSION_KEY = sessionKey(projectId);
const storedSessionId = getCookie(SESSION_COOKIE_NAME);
const lastActivityStr = getCookie(ACTIVITY_COOKIE_NAME);
const lastActivity = lastActivityStr ? parseInt(lastActivityStr, 10) : 0;
if (storedSessionId && lastActivity && (now - lastActivity) < SESSION_TIMEOUT) {
setCrossDomainCookie(ACTIVITY_COOKIE_NAME, String(now), COOKIE_MAX_AGE);
return storedSessionId;
}
// Fallback: Try localStorage for backward compatibility
const stored = localStorage.getItem(SESSION_KEY);
if (stored) {
try {
const session = JSON.parse(stored);
if ((now - session.lastActivity) < SESSION_TIMEOUT) {
setCrossDomainCookie(SESSION_COOKIE_NAME, session.id, COOKIE_MAX_AGE);
setCrossDomainCookie(ACTIVITY_COOKIE_NAME, String(now), COOKIE_MAX_AGE);
session.lastActivity = now;
localStorage.setItem(SESSION_KEY, JSON.stringify(session));
return session.id;
}
}
catch (error) {
console.error('Error parsing stored session:', error);
}
}
const newId = generateUuid();
setCrossDomainCookie(SESSION_COOKIE_NAME, newId, COOKIE_MAX_AGE);
setCrossDomainCookie(ACTIVITY_COOKIE_NAME, String(now), COOKIE_MAX_AGE);
const newSession = {
id: newId,
lastActivity: now
};
localStorage.setItem(SESSION_KEY, JSON.stringify(newSession));
return newId;
}
/**
* Update the last activity timestamp for the current session.
*/
export function updateSessionActivity(projectId) {
const now = Date.now();
const ACTIVITY_COOKIE_NAME = activityCookieName(projectId);
const SESSION_KEY = sessionKey(projectId);
setCrossDomainCookie(ACTIVITY_COOKIE_NAME, String(now), COOKIE_MAX_AGE);
const stored = localStorage.getItem(SESSION_KEY);
if (stored) {
try {
const session = JSON.parse(stored);
session.lastActivity = now;
localStorage.setItem(SESSION_KEY, JSON.stringify(session));
}
catch (error) {
console.error('Error updating session activity:', error);
}
}
}