UNPKG

overcentric

Version:

Overcentric watches your website, product, and users - and tells you what matters and what to do about it.

68 lines (67 loc) 1.94 kB
import { log } from "./config"; // What counts as "real" user activity. These are the signals that should keep a // session (and an in-progress recording) alive. A tab that is merely open and // focused but receives none of these is considered idle. const ACTIVITY_EVENTS = [ "mousedown", "mousemove", "keydown", "scroll", "touchstart", "click", ]; // Coalesce bursts of activity (e.g. mousemove) so we don't run callbacks on // every single event. const THROTTLE_MS = 1000; let initialized = false; let lastActivity = Date.now(); let throttledUntil = 0; const listeners = new Set(); function onActivity() { const now = Date.now(); lastActivity = now; if (now < throttledUntil) return; throttledUntil = now + THROTTLE_MS; listeners.forEach((fn) => { try { fn(); } catch (e) { log.debug(`Activity listener threw: ${e}`); } }); } /** * Start listening for real user-input events. Safe to call multiple times; * listeners are only attached once. */ export function initActivityTracking() { if (initialized || typeof window === "undefined") return; initialized = true; lastActivity = Date.now(); ACTIVITY_EVENTS.forEach((evt) => { document.addEventListener(evt, onActivity, { capture: true, passive: true, }); }); log.debug("Activity tracking initialized"); } /** * Register a callback that fires (throttled) whenever genuine user activity * occurs. Returns an unsubscribe function. */ export function onUserActivity(fn) { listeners.add(fn); return () => listeners.delete(fn); } /** Milliseconds since the last detected user activity. */ export function timeSinceLastActivity() { return Date.now() - lastActivity; } /** Timestamp (ms) of the last detected user activity. */ export function getLastActivity() { return lastActivity; }