Development #24
@@ -39,9 +39,10 @@ export const Route = createFileRoute("/api/events/$")({
|
|||||||
serverEvents.on(type, handleEvent);
|
serverEvents.on(type, handleEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Under the shortest idle timeout observed on proxies/PWA paths.
|
||||||
const pingInterval = setInterval(() => {
|
const pingInterval = setInterval(() => {
|
||||||
send({ type: "ping", timestamp: Date.now() });
|
send({ type: "ping", timestamp: Date.now() });
|
||||||
}, 15000);
|
}, 8000);
|
||||||
|
|
||||||
cleanup = () => {
|
cleanup = () => {
|
||||||
if (cleanedUp) return;
|
if (cleanedUp) return;
|
||||||
|
|||||||
@@ -17,19 +17,37 @@ const recentErrors = new Map<string, number>();
|
|||||||
|
|
||||||
const isEnabled = (): boolean => typeof window !== "undefined";
|
const isEnabled = (): boolean => typeof window !== "undefined";
|
||||||
|
|
||||||
const getSessionId = (): string => {
|
// A session ends after 30 idle minutes, not when the tab closes — installed
|
||||||
|
// PWAs keep sessionStorage alive for days.
|
||||||
|
const SESSION_IDLE_MS = 30 * 60 * 1000;
|
||||||
|
const SESSION_KEY = "flxn-tsid";
|
||||||
|
|
||||||
|
const readSession = (): { id: string; t: number } | null => {
|
||||||
try {
|
try {
|
||||||
let id = sessionStorage.getItem("flxn-tsid");
|
const raw = sessionStorage.getItem(SESSION_KEY);
|
||||||
if (!id) {
|
if (!raw) return null;
|
||||||
id = crypto.randomUUID();
|
const parsed = JSON.parse(raw);
|
||||||
sessionStorage.setItem("flxn-tsid", id);
|
if (typeof parsed?.id === "string" && typeof parsed?.t === "number") {
|
||||||
|
return parsed;
|
||||||
}
|
}
|
||||||
return id;
|
return null;
|
||||||
} catch {
|
} catch {
|
||||||
return "anon-session";
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const touchSession = () => {
|
||||||
|
try {
|
||||||
|
const now = Date.now();
|
||||||
|
const current = readSession();
|
||||||
|
const id =
|
||||||
|
current && now - current.t <= SESSION_IDLE_MS ? current.id : crypto.randomUUID();
|
||||||
|
sessionStorage.setItem(SESSION_KEY, JSON.stringify({ id, t: now }));
|
||||||
|
} catch {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSessionId = (): string => readSession()?.id ?? "anon-session";
|
||||||
|
|
||||||
const location = (): { path: string; routeId?: string } => ({
|
const location = (): { path: string; routeId?: string } => ({
|
||||||
path: window.location.pathname,
|
path: window.location.pathname,
|
||||||
routeId: lastRouteId,
|
routeId: lastRouteId,
|
||||||
@@ -64,6 +82,7 @@ const flush = (useBeacon = false) => {
|
|||||||
|
|
||||||
const enqueue = (event: QueuedEvent) => {
|
const enqueue = (event: QueuedEvent) => {
|
||||||
if (!isEnabled()) return;
|
if (!isEnabled()) return;
|
||||||
|
touchSession();
|
||||||
queue.push(event);
|
queue.push(event);
|
||||||
if (queue.length >= FLUSH_AT) {
|
if (queue.length >= FLUSH_AT) {
|
||||||
flush();
|
flush();
|
||||||
|
|||||||
Reference in New Issue
Block a user