@mtdt.temp/browser-core
Version:
Datadog browser core utilities.
183 lines • 8.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.VISIBILITY_CHECK_DELAY = void 0;
exports.startSessionManager = startSessionManager;
exports.stopSessionManager = stopSessionManager;
const observable_1 = require("../../tools/observable");
const valueHistory_1 = require("../../tools/valueHistory");
const timeUtils_1 = require("../../tools/utils/timeUtils");
const addEventListener_1 = require("../../browser/addEventListener");
const timer_1 = require("../../tools/timer");
const telemetry_1 = require("../telemetry");
const syntheticsWorkerValues_1 = require("../synthetics/syntheticsWorkerValues");
const cookie_1 = require("../../browser/cookie");
const experimentalFeatures_1 = require("../../tools/experimentalFeatures");
const polyfills_1 = require("../../tools/utils/polyfills");
const monitor_1 = require("../../tools/monitor");
const sessionConstants_1 = require("./sessionConstants");
const sessionStore_1 = require("./sessionStore");
const sessionState_1 = require("./sessionState");
const sessionInCookie_1 = require("./storeStrategies/sessionInCookie");
const sessionStoreStrategy_1 = require("./storeStrategies/sessionStoreStrategy");
exports.VISIBILITY_CHECK_DELAY = timeUtils_1.ONE_MINUTE;
const SESSION_CONTEXT_TIMEOUT_DELAY = sessionConstants_1.SESSION_TIME_OUT_DELAY;
let stopCallbacks = [];
function startSessionManager(configuration, productKey, computeTrackingType, trackingConsentState) {
const renewObservable = new observable_1.Observable();
const expireObservable = new observable_1.Observable();
// TODO - Improve configuration type and remove assertion
const sessionStore = (0, sessionStore_1.startSessionStore)(configuration.sessionStoreStrategyType, configuration, productKey, computeTrackingType);
stopCallbacks.push(() => sessionStore.stop());
const sessionContextHistory = (0, valueHistory_1.createValueHistory)({
expireDelay: SESSION_CONTEXT_TIMEOUT_DELAY,
});
stopCallbacks.push(() => sessionContextHistory.stop());
sessionStore.renewObservable.subscribe(() => {
sessionContextHistory.add(buildSessionContext(), (0, timeUtils_1.relativeNow)());
renewObservable.notify();
});
sessionStore.expireObservable.subscribe(() => {
expireObservable.notify();
sessionContextHistory.closeActive((0, timeUtils_1.relativeNow)());
});
// We expand/renew session unconditionally as tracking consent is always granted when the session
// manager is started.
sessionStore.expandOrRenewSession();
sessionContextHistory.add(buildSessionContext(), (0, timeUtils_1.clocksOrigin)().relative);
if ((0, experimentalFeatures_1.isExperimentalFeatureEnabled)(experimentalFeatures_1.ExperimentalFeature.SHORT_SESSION_INVESTIGATION)) {
const session = sessionStore.getSession();
if (session) {
detectSessionIdChange(configuration, session);
}
}
trackingConsentState.observable.subscribe(() => {
if (trackingConsentState.isGranted()) {
sessionStore.expandOrRenewSession();
}
else {
sessionStore.expire();
}
});
trackActivity(configuration, () => {
if (trackingConsentState.isGranted()) {
sessionStore.expandOrRenewSession();
}
});
trackVisibility(configuration, () => sessionStore.expandSession());
trackResume(configuration, () => sessionStore.restartSession());
function buildSessionContext() {
const session = sessionStore.getSession();
if (!session) {
reportUnexpectedSessionState().catch(() => void 0); // Ignore errors
return {
id: 'invalid',
trackingType: sessionConstants_1.SESSION_NOT_TRACKED,
isReplayForced: false,
anonymousId: undefined,
};
}
return {
id: session.id,
trackingType: session[productKey],
isReplayForced: !!session.forcedReplay,
anonymousId: session.anonymousId,
};
}
return {
findSession: (startTime, options) => sessionContextHistory.find(startTime, options),
renewObservable,
expireObservable,
sessionStateUpdateObservable: sessionStore.sessionStateUpdateObservable,
expire: sessionStore.expire,
updateSessionState: sessionStore.updateSessionState,
};
}
function stopSessionManager() {
stopCallbacks.forEach((e) => e());
stopCallbacks = [];
}
function trackActivity(configuration, expandOrRenewSession) {
const { stop } = (0, addEventListener_1.addEventListeners)(configuration, window, ["click" /* DOM_EVENT.CLICK */, "touchstart" /* DOM_EVENT.TOUCH_START */, "keydown" /* DOM_EVENT.KEY_DOWN */, "scroll" /* DOM_EVENT.SCROLL */], expandOrRenewSession, { capture: true, passive: true });
stopCallbacks.push(stop);
}
function trackVisibility(configuration, expandSession) {
const expandSessionWhenVisible = () => {
if (document.visibilityState === 'visible') {
expandSession();
}
};
const { stop } = (0, addEventListener_1.addEventListener)(configuration, document, "visibilitychange" /* DOM_EVENT.VISIBILITY_CHANGE */, expandSessionWhenVisible);
stopCallbacks.push(stop);
const visibilityCheckInterval = (0, timer_1.setInterval)(expandSessionWhenVisible, exports.VISIBILITY_CHECK_DELAY);
stopCallbacks.push(() => {
(0, timer_1.clearInterval)(visibilityCheckInterval);
});
}
function trackResume(configuration, cb) {
const { stop } = (0, addEventListener_1.addEventListener)(configuration, window, "resume" /* DOM_EVENT.RESUME */, cb, { capture: true });
stopCallbacks.push(stop);
}
async function reportUnexpectedSessionState() {
const rawSession = (0, sessionInCookie_1.retrieveSessionCookie)();
(0, telemetry_1.addTelemetryDebug)('Unexpected session state', {
session: rawSession,
isSyntheticsTest: (0, syntheticsWorkerValues_1.isSyntheticsTest)(),
createdTimestamp: rawSession === null || rawSession === void 0 ? void 0 : rawSession.created,
expireTimestamp: rawSession === null || rawSession === void 0 ? void 0 : rawSession.expire,
cookie: await getSessionCookies(),
currentDomain: `${window.location.protocol}//${window.location.hostname}`,
});
}
function detectSessionIdChange(configuration, initialSessionState) {
if (!window.cookieStore || !initialSessionState.created) {
return;
}
const sessionCreatedTime = Number(initialSessionState.created);
const sdkInitTime = (0, timeUtils_1.dateNow)();
const { stop } = (0, addEventListener_1.addEventListener)(configuration, cookieStore, "change" /* DOM_EVENT.CHANGE */, listener);
stopCallbacks.push(stop);
function listener(event) {
const changed = (0, polyfills_1.findLast)(event.changed, (change) => change.name === sessionStoreStrategy_1.SESSION_STORE_KEY);
if (!changed) {
return;
}
const sessionAge = (0, timeUtils_1.dateNow)() - sessionCreatedTime;
if (sessionAge > 14 * timeUtils_1.ONE_MINUTE) {
// The session might have expired just because it's too old or lack activity
stop();
}
else {
const newSessionState = (0, sessionState_1.toSessionState)(changed.value);
if (newSessionState.id && newSessionState.id !== initialSessionState.id) {
stop();
const time = (0, timeUtils_1.dateNow)() - sdkInitTime;
getSessionCookies()
.then((cookie) => {
(0, telemetry_1.addTelemetryDebug)('Session cookie changed', {
time,
session_age: sessionAge,
old: initialSessionState,
new: newSessionState,
cookie,
});
})
.catch(monitor_1.monitorError);
}
}
}
}
async function getSessionCookies() {
let sessionCookies;
if ('cookieStore' in window) {
sessionCookies = await window.cookieStore.getAll(sessionStoreStrategy_1.SESSION_STORE_KEY);
}
else {
sessionCookies = document.cookie.split(/\s*;\s*/).filter((cookie) => cookie.startsWith(sessionStoreStrategy_1.SESSION_STORE_KEY));
}
return {
count: sessionCookies.length,
domain: (0, cookie_1.getCurrentSite)(),
...sessionCookies,
};
}
//# sourceMappingURL=sessionManager.js.map