Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@datadog/browser-rum-core

Package Overview
Dependencies
Maintainers
1
Versions
183
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@datadog/browser-rum-core - npm Package Compare versions

Comparing version 4.43.0 to 4.44.0

cjs/browser/scroll.d.ts

1

cjs/boot/startRum.d.ts

@@ -23,3 +23,2 @@ import type { Observable, RawError, ContextManager } from '@datadog/browser-core';

viewContexts: import("../domain/contexts/viewContexts").ViewContexts;
foregroundContexts: import("../domain/contexts/foregroundContexts").ForegroundContexts;
pageStateHistory: import("../domain/contexts/pageStateHistory").PageStateHistory;

@@ -26,0 +25,0 @@ urlContexts: {

@@ -8,3 +8,2 @@ "use strict";

var assembly_1 = require("../domain/assembly");
var foregroundContexts_1 = require("../domain/contexts/foregroundContexts");
var internalContext_1 = require("../domain/contexts/internalContext");

@@ -68,8 +67,8 @@ var lifeCycle_1 = require("../domain/lifeCycle");

var locationChangeObservable = (0, locationChangeObservable_1.createLocationChangeObservable)(location);
var _a = startRumEventCollection(lifeCycle, configuration, location, session, locationChangeObservable, domMutationObservable, function () { return (0, commonContext_1.buildCommonContext)(globalContextManager, userContextManager, recorderApi); }, reportError), viewContexts = _a.viewContexts, foregroundContexts = _a.foregroundContexts, pageStateHistory = _a.pageStateHistory, urlContexts = _a.urlContexts, actionContexts = _a.actionContexts, addAction = _a.addAction;
var _a = startRumEventCollection(lifeCycle, configuration, location, session, locationChangeObservable, domMutationObservable, function () { return (0, commonContext_1.buildCommonContext)(globalContextManager, userContextManager, recorderApi); }, reportError), viewContexts = _a.viewContexts, pageStateHistory = _a.pageStateHistory, urlContexts = _a.urlContexts, actionContexts = _a.actionContexts, addAction = _a.addAction;
(0, browser_core_1.addTelemetryConfiguration)((0, configuration_1.serializeRumConfiguration)(initConfiguration));
(0, longTaskCollection_1.startLongTaskCollection)(lifeCycle, session);
(0, resourceCollection_1.startResourceCollection)(lifeCycle, configuration, session, pageStateHistory);
var _b = (0, viewCollection_1.startViewCollection)(lifeCycle, configuration, location, domMutationObservable, locationChangeObservable, foregroundContexts, featureFlagContexts, pageStateHistory, recorderApi, initialViewOptions), addTiming = _b.addTiming, startView = _b.startView;
var addError = (0, errorCollection_1.startErrorCollection)(lifeCycle, foregroundContexts, featureFlagContexts).addError;
var _b = (0, viewCollection_1.startViewCollection)(lifeCycle, configuration, location, domMutationObservable, locationChangeObservable, featureFlagContexts, pageStateHistory, recorderApi, initialViewOptions), addTiming = _b.addTiming, startView = _b.startView;
var addError = (0, errorCollection_1.startErrorCollection)(lifeCycle, pageStateHistory, featureFlagContexts).addError;
(0, requestCollection_1.startRequestCollection)(lifeCycle, configuration, session);

@@ -103,9 +102,7 @@ (0, performanceCollection_1.startPerformanceCollection)(lifeCycle, configuration);

var urlContexts = (0, urlContexts_1.startUrlContexts)(lifeCycle, locationChangeObservable, location);
var foregroundContexts = (0, foregroundContexts_1.startForegroundContexts)();
var pageStateHistory = (0, pageStateHistory_1.startPageStateHistory)();
var _a = (0, actionCollection_1.startActionCollection)(lifeCycle, domMutationObservable, configuration, foregroundContexts), addAction = _a.addAction, actionContexts = _a.actionContexts;
var _a = (0, actionCollection_1.startActionCollection)(lifeCycle, domMutationObservable, configuration, pageStateHistory), addAction = _a.addAction, actionContexts = _a.actionContexts;
(0, assembly_1.startRumAssembly)(configuration, lifeCycle, sessionManager, viewContexts, urlContexts, actionContexts, buildCommonContext, reportError);
return {
viewContexts: viewContexts,
foregroundContexts: foregroundContexts,
pageStateHistory: pageStateHistory,

@@ -117,3 +114,3 @@ urlContexts: urlContexts,

viewContexts.stop();
foregroundContexts.stop();
pageStateHistory.stop();
},

@@ -120,0 +117,0 @@ };

@@ -56,3 +56,3 @@ "use strict";

},
browser_sdk_version: (0, browser_core_1.canUseEventBridge)() ? "4.43.0" : undefined,
browser_sdk_version: (0, browser_core_1.canUseEventBridge)() ? "4.44.0" : undefined,
},

@@ -59,0 +59,0 @@ application: {

import type { RelativeTime, Duration } from '@datadog/browser-core';
import type { InForegroundPeriod } from '../../rawRumEvent.types';
export declare const MAX_NUMBER_OF_SELECTABLE_FOREGROUND_PERIODS = 500;
export declare const MAX_NUMBER_OF_STORED_FOREGROUND_PERIODS = 2500;
export interface ForegroundContexts {
isInForegroundAt: (startTime: RelativeTime) => boolean | undefined;
selectInForegroundPeriodsFor: (startTime: RelativeTime, duration: Duration) => InForegroundPeriod[] | undefined;
stop: () => void;
}
import type { InForegroundPeriod, PageStateServerEntry } from '../../rawRumEvent.types';
export interface ForegroundPeriod {

@@ -14,4 +7,2 @@ start: RelativeTime;

}
export declare function startForegroundContexts(): ForegroundContexts;
export declare function addNewForegroundPeriod(): void;
export declare function closeForegroundPeriod(): void;
export declare function mapToForegroundPeriods(pageStateServerEntries: PageStateServerEntry[], duration: Duration): InForegroundPeriod[];
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.closeForegroundPeriod = exports.addNewForegroundPeriod = exports.startForegroundContexts = exports.MAX_NUMBER_OF_STORED_FOREGROUND_PERIODS = exports.MAX_NUMBER_OF_SELECTABLE_FOREGROUND_PERIODS = void 0;
exports.mapToForegroundPeriods = void 0;
var browser_core_1 = require("@datadog/browser-core");
// Arbitrary value to cap number of element mostly for backend & to save bandwidth
exports.MAX_NUMBER_OF_SELECTABLE_FOREGROUND_PERIODS = 500;
// Arbitrary value to cap number of element mostly for memory consumption in the browser
exports.MAX_NUMBER_OF_STORED_FOREGROUND_PERIODS = 2500;
var foregroundPeriods = [];
function startForegroundContexts() {
if (document.hasFocus()) {
addNewForegroundPeriod();
}
var stopForegroundTracking = trackFocus(addNewForegroundPeriod).stop;
var stopBlurTracking = trackBlur(closeForegroundPeriod).stop;
return {
isInForegroundAt: isInForegroundAt,
selectInForegroundPeriodsFor: selectInForegroundPeriodsFor,
stop: function () {
foregroundPeriods = [];
stopForegroundTracking();
stopBlurTracking();
},
};
}
exports.startForegroundContexts = startForegroundContexts;
function addNewForegroundPeriod() {
if (foregroundPeriods.length > exports.MAX_NUMBER_OF_STORED_FOREGROUND_PERIODS) {
return;
}
var currentForegroundPeriod = foregroundPeriods[foregroundPeriods.length - 1];
var now = (0, browser_core_1.relativeNow)();
if (currentForegroundPeriod !== undefined && currentForegroundPeriod.end === undefined) {
return;
}
foregroundPeriods.push({
start: now,
});
}
exports.addNewForegroundPeriod = addNewForegroundPeriod;
function closeForegroundPeriod() {
if (foregroundPeriods.length === 0) {
return;
}
var currentForegroundPeriod = foregroundPeriods[foregroundPeriods.length - 1];
var now = (0, browser_core_1.relativeNow)();
if (currentForegroundPeriod.end !== undefined) {
return;
}
currentForegroundPeriod.end = now;
}
exports.closeForegroundPeriod = closeForegroundPeriod;
function trackFocus(onFocusChange) {
return (0, browser_core_1.addEventListener)(window, "focus" /* DOM_EVENT.FOCUS */, function (event) {
if (!event.isTrusted) {
return;
// Todo: Remove in the next major release
function mapToForegroundPeriods(pageStateServerEntries, duration) {
var foregroundPeriods = [];
for (var i = 0; i < pageStateServerEntries.length; i++) {
var current = pageStateServerEntries[i];
var next = pageStateServerEntries[i + 1];
if (current.state === "active" /* PageState.ACTIVE */) {
var start = current.start >= 0 ? current.start : 0;
var end = next ? next.start : (0, browser_core_1.toServerDuration)(duration);
foregroundPeriods.push({
start: start,
duration: (end - start),
});
}
onFocusChange();
});
}
function trackBlur(onBlurChange) {
return (0, browser_core_1.addEventListener)(window, "blur" /* DOM_EVENT.BLUR */, function (event) {
if (!event.isTrusted) {
return;
}
onBlurChange();
});
}
function isInForegroundAt(startTime) {
for (var i = foregroundPeriods.length - 1; i >= 0; i--) {
var foregroundPeriod = foregroundPeriods[i];
if (foregroundPeriod.end !== undefined && startTime > foregroundPeriod.end) {
break;
}
if (startTime > foregroundPeriod.start &&
(foregroundPeriod.end === undefined || startTime < foregroundPeriod.end)) {
return true;
}
}
return false;
return foregroundPeriods;
}
function selectInForegroundPeriodsFor(eventStartTime, duration) {
var eventEndTime = (0, browser_core_1.addDuration)(eventStartTime, duration);
var filteredForegroundPeriods = [];
var earliestIndex = Math.max(0, foregroundPeriods.length - exports.MAX_NUMBER_OF_SELECTABLE_FOREGROUND_PERIODS);
for (var i = foregroundPeriods.length - 1; i >= earliestIndex; i--) {
var foregroundPeriod = foregroundPeriods[i];
if (foregroundPeriod.end !== undefined && eventStartTime > foregroundPeriod.end) {
// event starts after the end of the current focus period
// since the array is sorted, we can stop looking for foreground periods
break;
}
if (eventEndTime < foregroundPeriod.start) {
// event ends before the start of the current focus period
// continue to previous one
continue;
}
var startTime = eventStartTime > foregroundPeriod.start ? eventStartTime : foregroundPeriod.start;
var startDuration = (0, browser_core_1.elapsed)(eventStartTime, startTime);
var endTime = foregroundPeriod.end === undefined || eventEndTime < foregroundPeriod.end ? eventEndTime : foregroundPeriod.end;
var endDuration = (0, browser_core_1.elapsed)(startTime, endTime);
filteredForegroundPeriods.unshift({
start: (0, browser_core_1.toServerDuration)(startDuration),
duration: (0, browser_core_1.toServerDuration)(endDuration),
});
}
return filteredForegroundPeriods;
}
exports.mapToForegroundPeriods = mapToForegroundPeriods;
//# sourceMappingURL=foregroundContexts.js.map

@@ -19,2 +19,3 @@ import type { Duration, RelativeTime } from '@datadog/browser-core';

findAll: (startTime: RelativeTime, duration: Duration) => PageStateServerEntry[] | undefined;
isInActivePageStateAt: (startTime: RelativeTime) => boolean;
addPageState(nextPageState: PageState, startTime?: RelativeTime): void;

@@ -21,0 +22,0 @@ stop: () => void;

@@ -60,2 +60,6 @@ "use strict";

},
isInActivePageStateAt: function (startTime) {
var pageStateEntry = pageStateHistory.find(startTime);
return pageStateEntry !== undefined && pageStateEntry.state === "active" /* PageState.ACTIVE */;
},
addPageState: addPageState,

@@ -62,0 +66,0 @@ stop: function () {

import type { ClocksState, Context, Observable } from '@datadog/browser-core';
import { ActionType } from '../../../rawRumEvent.types';
import type { LifeCycle } from '../../lifeCycle';
import type { ForegroundContexts } from '../../contexts/foregroundContexts';
import type { RumConfiguration } from '../../configuration';
import type { CommonContext } from '../../contexts/commonContext';
import type { PageStateHistory } from '../../contexts/pageStateHistory';
import type { ActionContexts, ClickAction } from './trackClickActions';

@@ -16,5 +16,5 @@ export type { ActionContexts };

export type AutoAction = ClickAction;
export declare function startActionCollection(lifeCycle: LifeCycle, domMutationObservable: Observable<void>, configuration: RumConfiguration, foregroundContexts: ForegroundContexts): {
export declare function startActionCollection(lifeCycle: LifeCycle, domMutationObservable: Observable<void>, configuration: RumConfiguration, pageStateHistory: PageStateHistory): {
addAction: (action: CustomAction, savedCommonContext?: CommonContext) => void;
actionContexts: ActionContexts;
};

@@ -6,5 +6,5 @@ "use strict";

var trackClickActions_1 = require("./trackClickActions");
function startActionCollection(lifeCycle, domMutationObservable, configuration, foregroundContexts) {
function startActionCollection(lifeCycle, domMutationObservable, configuration, pageStateHistory) {
lifeCycle.subscribe(1 /* LifeCycleEventType.AUTO_ACTION_COMPLETED */, function (action) {
return lifeCycle.notify(10 /* LifeCycleEventType.RAW_RUM_EVENT_COLLECTED */, processAction(action, foregroundContexts));
return lifeCycle.notify(10 /* LifeCycleEventType.RAW_RUM_EVENT_COLLECTED */, processAction(action, pageStateHistory));
});

@@ -19,3 +19,3 @@ var actionContexts = { findActionId: browser_core_1.noop };

savedCommonContext: savedCommonContext,
}, processAction(action, foregroundContexts)));
}, processAction(action, pageStateHistory)));
},

@@ -26,3 +26,3 @@ actionContexts: actionContexts,

exports.startActionCollection = startActionCollection;
function processAction(action, foregroundContexts) {
function processAction(action, pageStateHistory) {
var autoActionProperties = isAutoAction(action)

@@ -65,7 +65,4 @@ ? {

type: "action" /* RumEventType.ACTION */,
view: { in_foreground: pageStateHistory.isInActivePageStateAt(action.startClocks.relative) },
}, autoActionProperties);
var inForeground = foregroundContexts.isInForegroundAt(action.startClocks.relative);
if (inForeground !== undefined) {
actionEvent.view = { in_foreground: inForeground };
}
return {

@@ -72,0 +69,0 @@ customerContext: customerContext,

import type { Context, ClocksState } from '@datadog/browser-core';
import type { LifeCycle } from '../../lifeCycle';
import type { ForegroundContexts } from '../../contexts/foregroundContexts';
import type { FeatureFlagContexts } from '../../contexts/featureFlagContext';
import type { CommonContext } from '../../contexts/commonContext';
import type { PageStateHistory } from '../../contexts/pageStateHistory';
export interface ProvidedError {

@@ -12,7 +12,7 @@ startClocks: ClocksState;

}
export declare function startErrorCollection(lifeCycle: LifeCycle, foregroundContexts: ForegroundContexts, featureFlagContexts: FeatureFlagContexts): {
export declare function startErrorCollection(lifeCycle: LifeCycle, pageStateHistory: PageStateHistory, featureFlagContexts: FeatureFlagContexts): {
addError: ({ error, handlingStack, startClocks, context: customerContext }: ProvidedError, savedCommonContext?: CommonContext | undefined) => void;
};
export declare function doStartErrorCollection(lifeCycle: LifeCycle, foregroundContexts: ForegroundContexts, featureFlagContexts: FeatureFlagContexts): {
export declare function doStartErrorCollection(lifeCycle: LifeCycle, pageStateHistory: PageStateHistory, featureFlagContexts: FeatureFlagContexts): {
addError: ({ error, handlingStack, startClocks, context: customerContext }: ProvidedError, savedCommonContext?: CommonContext) => void;
};

@@ -7,3 +7,3 @@ "use strict";

var trackReportError_1 = require("./trackReportError");
function startErrorCollection(lifeCycle, foregroundContexts, featureFlagContexts) {
function startErrorCollection(lifeCycle, pageStateHistory, featureFlagContexts) {
var errorObservable = new browser_core_1.Observable();

@@ -14,6 +14,6 @@ (0, trackConsoleError_1.trackConsoleError)(errorObservable);

errorObservable.subscribe(function (error) { return lifeCycle.notify(12 /* LifeCycleEventType.RAW_ERROR_COLLECTED */, { error: error }); });
return doStartErrorCollection(lifeCycle, foregroundContexts, featureFlagContexts);
return doStartErrorCollection(lifeCycle, pageStateHistory, featureFlagContexts);
}
exports.startErrorCollection = startErrorCollection;
function doStartErrorCollection(lifeCycle, foregroundContexts, featureFlagContexts) {
function doStartErrorCollection(lifeCycle, pageStateHistory, featureFlagContexts) {
lifeCycle.subscribe(12 /* LifeCycleEventType.RAW_ERROR_COLLECTED */, function (_a) {

@@ -24,3 +24,3 @@ var error = _a.error, customerContext = _a.customerContext, savedCommonContext = _a.savedCommonContext;

savedCommonContext: savedCommonContext,
}, processError(error, foregroundContexts, featureFlagContexts)));
}, processError(error, pageStateHistory, featureFlagContexts)));
});

@@ -49,3 +49,3 @@ return {

exports.doStartErrorCollection = doStartErrorCollection;
function processError(error, foregroundContexts, featureFlagContexts) {
function processError(error, pageStateHistory, featureFlagContexts) {
var rawRumEvent = {

@@ -66,7 +66,4 @@ date: error.startClocks.timeStamp,

type: "error" /* RumEventType.ERROR */,
view: { in_foreground: pageStateHistory.isInActivePageStateAt(error.startClocks.relative) },
};
var inForeground = foregroundContexts.isInForegroundAt(error.startClocks.relative);
if (inForeground) {
rawRumEvent.view = { in_foreground: inForeground };
}
var featureFlagContext = featureFlagContexts.findFeatureFlagEvaluations(error.startClocks.relative);

@@ -73,0 +70,0 @@ if (featureFlagContext && !(0, browser_core_1.isEmptyObject)(featureFlagContext)) {

@@ -1,5 +0,14 @@

import type { Duration, Observable, ClocksState } from '@datadog/browser-core';
import type { ClocksState, Duration, Observable } from '@datadog/browser-core';
import { noop } from '@datadog/browser-core';
import { ViewLoadingType } from '../../../rawRumEvent.types';
import type { RumConfiguration } from '../../configuration';
import type { LifeCycle } from '../../lifeCycle';
export interface ScrollMetrics {
maxDepth: number;
maxDepthScrollHeight: number;
maxDepthScrollTop: number;
maxDepthTime: Duration;
}
/** Arbitrary scroll throttle duration */
export declare const THROTTLE_SCROLL_DURATION = 1000;
export interface ViewMetrics {

@@ -13,2 +22,12 @@ loadingTime?: Duration;

viewMetrics: ViewMetrics;
getScrollMetrics: () => ScrollMetrics | undefined;
};
export declare function trackScrollMetrics(viewStart: ClocksState, callback: (scrollMetrics: ScrollMetrics) => void, getScrollValues?: typeof computeScrollValues): {
stop: typeof noop;
};
declare function computeScrollValues(): {
scrollHeight: number;
scrollDepth: number;
scrollTop: number;
};
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.trackViewMetrics = void 0;
exports.trackScrollMetrics = exports.trackViewMetrics = exports.THROTTLE_SCROLL_DURATION = void 0;
var browser_core_1 = require("@datadog/browser-core");
var performanceCollection_1 = require("../../../browser/performanceCollection");
var waitPageActivityEnd_1 = require("../../waitPageActivityEnd");
var scroll_1 = require("../../../browser/scroll");
var viewportObservable_1 = require("../../../browser/viewportObservable");
/** Arbitrary scroll throttle duration */
exports.THROTTLE_SCROLL_DURATION = browser_core_1.ONE_SECOND;
function trackViewMetrics(lifeCycle, domMutationObservable, configuration, scheduleViewUpdate, loadingType, viewStart) {
var viewMetrics = {};
var scrollMetrics;
var _a = trackLoadingTime(lifeCycle, domMutationObservable, configuration, loadingType, viewStart, function (newLoadingTime) {
viewMetrics.loadingTime = newLoadingTime;
// We compute scroll metrics at loading time to ensure we have scroll data when loading the view initially
// This is to ensure that we have the depth data even if the user didn't scroll or if the view is not scrollable.
if ((0, browser_core_1.isExperimentalFeatureEnabled)(browser_core_1.ExperimentalFeature.SCROLLMAP)) {
var _a = computeScrollValues(), scrollHeight = _a.scrollHeight, scrollDepth = _a.scrollDepth, scrollTop = _a.scrollTop;
scrollMetrics = {
maxDepth: scrollDepth,
maxDepthScrollHeight: scrollHeight,
maxDepthTime: newLoadingTime,
maxDepthScrollTop: scrollTop,
};
}
scheduleViewUpdate();
}), stopLoadingTimeTracking = _a.stop, setLoadEvent = _a.setLoadEvent;
var stopScrollMetricsTracking = trackScrollMetrics(viewStart, function (newScrollMetrics) {
scrollMetrics = newScrollMetrics;
}, computeScrollValues).stop;
var stopCLSTracking;

@@ -28,8 +47,50 @@ if (isLayoutShiftSupported()) {

stopCLSTracking();
stopScrollMetricsTracking();
},
setLoadEvent: setLoadEvent,
viewMetrics: viewMetrics,
getScrollMetrics: function () { return scrollMetrics; },
};
}
exports.trackViewMetrics = trackViewMetrics;
function trackScrollMetrics(viewStart, callback, getScrollValues) {
if (getScrollValues === void 0) { getScrollValues = computeScrollValues; }
if (!(0, browser_core_1.isExperimentalFeatureEnabled)(browser_core_1.ExperimentalFeature.SCROLLMAP)) {
return { stop: browser_core_1.noop };
}
var maxDepth = 0;
var handleScrollEvent = (0, browser_core_1.throttle)(function () {
var _a = getScrollValues(), scrollHeight = _a.scrollHeight, scrollDepth = _a.scrollDepth, scrollTop = _a.scrollTop;
if (scrollDepth > maxDepth) {
var now = (0, browser_core_1.relativeNow)();
var maxDepthTime = (0, browser_core_1.elapsed)(viewStart.relative, now);
maxDepth = scrollDepth;
callback({
maxDepth: maxDepth,
maxDepthScrollHeight: scrollHeight,
maxDepthTime: maxDepthTime,
maxDepthScrollTop: scrollTop,
});
}
}, exports.THROTTLE_SCROLL_DURATION, { leading: false, trailing: true });
var stop = (0, browser_core_1.addEventListener)(window, "scroll" /* DOM_EVENT.SCROLL */, handleScrollEvent.throttled, { passive: true }).stop;
return {
stop: function () {
handleScrollEvent.cancel();
stop();
},
};
}
exports.trackScrollMetrics = trackScrollMetrics;
function computeScrollValues() {
var scrollTop = (0, scroll_1.getScrollY)();
var height = (0, viewportObservable_1.getViewportDimension)().height;
var scrollHeight = Math.round((document.scrollingElement || document.documentElement).scrollHeight);
var scrollDepth = Math.round(height + scrollTop);
return {
scrollHeight: scrollHeight,
scrollDepth: scrollDepth,
scrollTop: scrollTop,
};
}
function trackLoadingTime(lifeCycle, domMutationObservable, configuration, loadType, viewStart, callback) {

@@ -36,0 +97,0 @@ var isWaitingForLoadEvent = loadType === "initial_load" /* ViewLoadingType.INITIAL_LOAD */;

@@ -9,2 +9,3 @@ import type { Duration, ClocksState, TimeStamp, Observable, RelativeTime } from '@datadog/browser-core';

import type { Timings } from './trackInitialViewTimings';
import type { ScrollMetrics } from './trackViewMetrics';
export interface ViewEvent {

@@ -27,2 +28,3 @@ id: string;

cumulativeLayoutShift?: number;
scrollMetrics?: ScrollMetrics;
}

@@ -29,0 +31,0 @@ export interface ViewCreatedEvent {

@@ -92,3 +92,3 @@ "use strict";

}), scheduleViewUpdate = _a.throttled, cancelScheduleViewUpdate = _a.cancel;
var _b = (0, trackViewMetrics_1.trackViewMetrics)(lifeCycle, domMutationObservable, configuration, scheduleViewUpdate, loadingType, startClocks), setLoadEvent = _b.setLoadEvent, stopViewMetricsTracking = _b.stop, viewMetrics = _b.viewMetrics;
var _b = (0, trackViewMetrics_1.trackViewMetrics)(lifeCycle, domMutationObservable, configuration, scheduleViewUpdate, loadingType, startClocks), setLoadEvent = _b.setLoadEvent, stopViewMetricsTracking = _b.stop, viewMetrics = _b.viewMetrics, getScrollMetrics = _b.getScrollMetrics;
var _c = loadingType === "initial_load" /* ViewLoadingType.INITIAL_LOAD */

@@ -121,2 +121,3 @@ ? (0, trackInitialViewTimings_1.trackInitialViewTimings)(lifeCycle, setLoadEvent, scheduleViewUpdate)

eventCounts: eventCounts,
scrollMetrics: getScrollMetrics(),
}, viewMetrics));

@@ -123,0 +124,0 @@ }

import type { Observable } from '@datadog/browser-core';
import type { RecorderApi } from '../../../boot/rumPublicApi';
import type { LifeCycle } from '../../lifeCycle';
import type { ForegroundContexts } from '../../contexts/foregroundContexts';
import type { LocationChange } from '../../../browser/locationChangeObservable';

@@ -10,3 +9,3 @@ import type { RumConfiguration } from '../../configuration';

import type { ViewOptions } from './trackViews';
export declare function startViewCollection(lifeCycle: LifeCycle, configuration: RumConfiguration, location: Location, domMutationObservable: Observable<void>, locationChangeObservable: Observable<LocationChange>, foregroundContexts: ForegroundContexts, featureFlagContexts: FeatureFlagContexts, pageStateHistory: PageStateHistory, recorderApi: RecorderApi, initialViewOptions?: ViewOptions): {
export declare function startViewCollection(lifeCycle: LifeCycle, configuration: RumConfiguration, location: Location, domMutationObservable: Observable<void>, locationChangeObservable: Observable<LocationChange>, featureFlagContexts: FeatureFlagContexts, pageStateHistory: PageStateHistory, recorderApi: RecorderApi, initialViewOptions?: ViewOptions): {
addTiming: (name: string, time?: import("@datadog/browser-core").TimeStamp | import("@datadog/browser-core").RelativeTime) => void;

@@ -13,0 +12,0 @@ startView: (options?: ViewOptions | undefined, startClocks?: import("@datadog/browser-core").ClocksState | undefined) => void;

@@ -5,6 +5,7 @@ "use strict";

var browser_core_1 = require("@datadog/browser-core");
var foregroundContexts_1 = require("../../contexts/foregroundContexts");
var trackViews_1 = require("./trackViews");
function startViewCollection(lifeCycle, configuration, location, domMutationObservable, locationChangeObservable, foregroundContexts, featureFlagContexts, pageStateHistory, recorderApi, initialViewOptions) {
function startViewCollection(lifeCycle, configuration, location, domMutationObservable, locationChangeObservable, featureFlagContexts, pageStateHistory, recorderApi, initialViewOptions) {
lifeCycle.subscribe(3 /* LifeCycleEventType.VIEW_UPDATED */, function (view) {
return lifeCycle.notify(10 /* LifeCycleEventType.RAW_RUM_EVENT_COLLECTED */, processViewUpdate(view, foregroundContexts, featureFlagContexts, recorderApi, pageStateHistory));
return lifeCycle.notify(10 /* LifeCycleEventType.RAW_RUM_EVENT_COLLECTED */, processViewUpdate(view, configuration, featureFlagContexts, recorderApi, pageStateHistory));
});

@@ -15,6 +16,7 @@ var trackViewResult = (0, trackViews_1.trackViews)(location, lifeCycle, domMutationObservable, configuration, locationChangeObservable, !configuration.trackViewsManually, initialViewOptions);

exports.startViewCollection = startViewCollection;
function processViewUpdate(view, foregroundContexts, featureFlagContexts, recorderApi, pageStateHistory) {
function processViewUpdate(view, configuration, featureFlagContexts, recorderApi, pageStateHistory) {
var replayStats = recorderApi.getReplayStats(view.id);
var featureFlagContext = featureFlagContexts.findFeatureFlagEvaluations(view.startClocks.relative);
var pageStatesEnabled = (0, browser_core_1.isExperimentalFeatureEnabled)(browser_core_1.ExperimentalFeature.PAGE_STATES);
var pageStates = pageStateHistory.findAll(view.startClocks.relative, view.duration);
var viewEvent = {

@@ -24,3 +26,3 @@ _dd: {

replay_stats: replayStats,
page_states: pageStatesEnabled ? pageStateHistory.findAll(view.startClocks.relative, view.duration) : undefined,
page_states: pageStatesEnabled ? pageStates : undefined,
},

@@ -60,7 +62,15 @@ date: view.startClocks.timeStamp,

time_spent: (0, browser_core_1.toServerDuration)(view.duration),
in_foreground_periods: !pageStatesEnabled
? foregroundContexts.selectInForegroundPeriodsFor(view.startClocks.relative, view.duration)
: undefined,
in_foreground_periods: !pageStatesEnabled && pageStates ? (0, foregroundContexts_1.mapToForegroundPeriods)(pageStates, view.duration) : undefined, // Todo: Remove in the next major release
},
feature_flags: featureFlagContext && !(0, browser_core_1.isEmptyObject)(featureFlagContext) ? featureFlagContext : undefined,
display: view.scrollMetrics
? {
scroll: {
max_depth: view.scrollMetrics.maxDepth,
max_depth_scroll_height: view.scrollMetrics.maxDepthScrollHeight,
max_depth_scroll_top: view.scrollMetrics.maxDepthScrollTop,
max_depth_time: (0, browser_core_1.toServerDuration)(view.scrollMetrics.maxDepthTime),
},
}
: undefined,
session: {

@@ -70,2 +80,5 @@ has_replay: replayStats ? true : undefined,

},
privacy: {
replay_level: configuration.defaultPrivacyLevel,
},
};

@@ -72,0 +85,0 @@ if (!(0, browser_core_1.isEmptyObject)(view.customTimings)) {

@@ -12,2 +12,3 @@ export { RumPublicApi, makeRumPublicApi, RecorderApi, StartRum } from './boot/rumPublicApi';

export { initViewportObservable, getViewportDimension } from './browser/viewportObservable';
export { getScrollX, getScrollY } from './browser/scroll';
export { RumInitConfiguration, RumConfiguration } from './domain/configuration';

@@ -14,0 +15,0 @@ export { DEFAULT_PROGRAMMATIC_ACTION_NAME_ATTRIBUTE } from './domain/rumEventsCollection/action/getActionNameFromElement';

@@ -17,3 +17,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.getSessionReplayUrl = exports.STABLE_ATTRIBUTES = exports.DEFAULT_PROGRAMMATIC_ACTION_NAME_ATTRIBUTE = exports.getViewportDimension = exports.initViewportObservable = exports.getMutationObserverConstructor = exports.LifeCycle = exports.startRum = exports.makeRumPublicApi = void 0;
exports.getSessionReplayUrl = exports.STABLE_ATTRIBUTES = exports.DEFAULT_PROGRAMMATIC_ACTION_NAME_ATTRIBUTE = exports.getScrollY = exports.getScrollX = exports.getViewportDimension = exports.initViewportObservable = exports.getMutationObserverConstructor = exports.LifeCycle = exports.startRum = exports.makeRumPublicApi = void 0;
var rumPublicApi_1 = require("./boot/rumPublicApi");

@@ -30,2 +30,5 @@ Object.defineProperty(exports, "makeRumPublicApi", { enumerable: true, get: function () { return rumPublicApi_1.makeRumPublicApi; } });

Object.defineProperty(exports, "getViewportDimension", { enumerable: true, get: function () { return viewportObservable_1.getViewportDimension; } });
var scroll_1 = require("./browser/scroll");
Object.defineProperty(exports, "getScrollX", { enumerable: true, get: function () { return scroll_1.getScrollX; } });
Object.defineProperty(exports, "getScrollY", { enumerable: true, get: function () { return scroll_1.getScrollY; } });
var getActionNameFromElement_1 = require("./domain/rumEventsCollection/action/getActionNameFromElement");

@@ -32,0 +35,0 @@ Object.defineProperty(exports, "DEFAULT_PROGRAMMATIC_ACTION_NAME_ATTRIBUTE", { enumerable: true, get: function () { return getActionNameFromElement_1.DEFAULT_PROGRAMMATIC_ACTION_NAME_ATTRIBUTE; } });

@@ -1,2 +0,2 @@

import type { Context, Duration, ErrorSource, ErrorHandling, ResourceType, ServerDuration, TimeStamp, RawErrorCause } from '@datadog/browser-core';
import type { Context, Duration, ErrorSource, ErrorHandling, ResourceType, ServerDuration, TimeStamp, RawErrorCause, DefaultPrivacyLevel } from '@datadog/browser-core';
import type { PageState } from './domain/contexts/pageStateHistory';

@@ -95,2 +95,6 @@ import type { RumSessionPlan } from './domain/rumSessionManager';

feature_flags?: Context;
display?: ViewDisplay;
privacy?: {
replay_level: DefaultPrivacyLevel;
};
_dd: {

@@ -102,2 +106,10 @@ document_version: number;

}
interface ViewDisplay {
scroll: {
max_depth?: number;
max_depth_scroll_height?: number;
max_depth_scroll_top?: number;
max_depth_time?: ServerDuration;
};
}
export interface InForegroundPeriod {

@@ -104,0 +116,0 @@ start: ServerDuration;

@@ -711,2 +711,12 @@ /**

/**
* Privacy properties
*/
readonly privacy?: {
/**
* The replay privacy level
*/
readonly replay_level: 'allow' | 'mask' | 'mask-user-input';
[k: string]: unknown;
};
/**
* Internal properties

@@ -733,4 +743,50 @@ */

}[];
/**
* Debug metadata for Replay Sessions
*/
replay_stats?: {
/**
* The number of records produced during this view lifetime
*/
records_count?: number;
/**
* The number of segments sent during this view lifetime
*/
segments_count?: number;
/**
* The total size in bytes of the segments sent during this view lifetime
*/
segments_total_raw_size?: number;
[k: string]: unknown;
};
[k: string]: unknown;
};
/**
* Display properties
*/
readonly display?: {
/**
* Scroll properties
*/
readonly scroll?: {
/**
* Distance between the top and the lowest point reached on this view (in pixels)
*/
readonly max_depth: number;
/**
* Page scroll height (total height) when the maximum scroll depth was reached for this view (in pixels)
*/
readonly max_depth_scroll_height: number;
/**
* Page scroll top (scrolled distance) when the maximum scroll depth was reached for this view (in pixels)
*/
readonly max_depth_scroll_top: number;
/**
* Duration between the view start and the scroll event that reached the maximum scroll depth for this view (in nanoseconds)
*/
readonly max_depth_time: number;
[k: string]: unknown;
};
[k: string]: unknown;
};
[k: string]: unknown;

@@ -915,2 +971,6 @@ };

/**
* Operating system build number, e.g. 15D21
*/
readonly build?: string;
/**
* Major operating system version, e.g. 8

@@ -917,0 +977,0 @@ */

@@ -23,3 +23,2 @@ import type { Observable, RawError, ContextManager } from '@datadog/browser-core';

viewContexts: import("../domain/contexts/viewContexts").ViewContexts;
foregroundContexts: import("../domain/contexts/foregroundContexts").ForegroundContexts;
pageStateHistory: import("../domain/contexts/pageStateHistory").PageStateHistory;

@@ -26,0 +25,0 @@ urlContexts: {

@@ -5,3 +5,2 @@ import { sendToExtension, createPageExitObservable, addTelemetryConfiguration, startTelemetry, canUseEventBridge, getEventBridge, } from '@datadog/browser-core';

import { startRumAssembly } from '../domain/assembly';
import { startForegroundContexts } from '../domain/contexts/foregroundContexts';
import { startInternalContext } from '../domain/contexts/internalContext';

@@ -65,8 +64,8 @@ import { LifeCycle } from '../domain/lifeCycle';

var locationChangeObservable = createLocationChangeObservable(location);
var _a = startRumEventCollection(lifeCycle, configuration, location, session, locationChangeObservable, domMutationObservable, function () { return buildCommonContext(globalContextManager, userContextManager, recorderApi); }, reportError), viewContexts = _a.viewContexts, foregroundContexts = _a.foregroundContexts, pageStateHistory = _a.pageStateHistory, urlContexts = _a.urlContexts, actionContexts = _a.actionContexts, addAction = _a.addAction;
var _a = startRumEventCollection(lifeCycle, configuration, location, session, locationChangeObservable, domMutationObservable, function () { return buildCommonContext(globalContextManager, userContextManager, recorderApi); }, reportError), viewContexts = _a.viewContexts, pageStateHistory = _a.pageStateHistory, urlContexts = _a.urlContexts, actionContexts = _a.actionContexts, addAction = _a.addAction;
addTelemetryConfiguration(serializeRumConfiguration(initConfiguration));
startLongTaskCollection(lifeCycle, session);
startResourceCollection(lifeCycle, configuration, session, pageStateHistory);
var _b = startViewCollection(lifeCycle, configuration, location, domMutationObservable, locationChangeObservable, foregroundContexts, featureFlagContexts, pageStateHistory, recorderApi, initialViewOptions), addTiming = _b.addTiming, startView = _b.startView;
var addError = startErrorCollection(lifeCycle, foregroundContexts, featureFlagContexts).addError;
var _b = startViewCollection(lifeCycle, configuration, location, domMutationObservable, locationChangeObservable, featureFlagContexts, pageStateHistory, recorderApi, initialViewOptions), addTiming = _b.addTiming, startView = _b.startView;
var addError = startErrorCollection(lifeCycle, pageStateHistory, featureFlagContexts).addError;
startRequestCollection(lifeCycle, configuration, session);

@@ -99,9 +98,7 @@ startPerformanceCollection(lifeCycle, configuration);

var urlContexts = startUrlContexts(lifeCycle, locationChangeObservable, location);
var foregroundContexts = startForegroundContexts();
var pageStateHistory = startPageStateHistory();
var _a = startActionCollection(lifeCycle, domMutationObservable, configuration, foregroundContexts), addAction = _a.addAction, actionContexts = _a.actionContexts;
var _a = startActionCollection(lifeCycle, domMutationObservable, configuration, pageStateHistory), addAction = _a.addAction, actionContexts = _a.actionContexts;
startRumAssembly(configuration, lifeCycle, sessionManager, viewContexts, urlContexts, actionContexts, buildCommonContext, reportError);
return {
viewContexts: viewContexts,
foregroundContexts: foregroundContexts,
pageStateHistory: pageStateHistory,

@@ -113,3 +110,3 @@ urlContexts: urlContexts,

viewContexts.stop();
foregroundContexts.stop();
pageStateHistory.stop();
},

@@ -116,0 +113,0 @@ };

@@ -53,3 +53,3 @@ import { combine, isEmptyObject, timeStampNow, currentDrift, display, createEventRateLimiter, canUseEventBridge, assign, } from '@datadog/browser-core';

},
browser_sdk_version: canUseEventBridge() ? "4.43.0" : undefined,
browser_sdk_version: canUseEventBridge() ? "4.44.0" : undefined,
},

@@ -56,0 +56,0 @@ application: {

import type { RelativeTime, Duration } from '@datadog/browser-core';
import type { InForegroundPeriod } from '../../rawRumEvent.types';
export declare const MAX_NUMBER_OF_SELECTABLE_FOREGROUND_PERIODS = 500;
export declare const MAX_NUMBER_OF_STORED_FOREGROUND_PERIODS = 2500;
export interface ForegroundContexts {
isInForegroundAt: (startTime: RelativeTime) => boolean | undefined;
selectInForegroundPeriodsFor: (startTime: RelativeTime, duration: Duration) => InForegroundPeriod[] | undefined;
stop: () => void;
}
import type { InForegroundPeriod, PageStateServerEntry } from '../../rawRumEvent.types';
export interface ForegroundPeriod {

@@ -14,4 +7,2 @@ start: RelativeTime;

}
export declare function startForegroundContexts(): ForegroundContexts;
export declare function addNewForegroundPeriod(): void;
export declare function closeForegroundPeriod(): void;
export declare function mapToForegroundPeriods(pageStateServerEntries: PageStateServerEntry[], duration: Duration): InForegroundPeriod[];

@@ -1,103 +0,19 @@

import { addDuration, addEventListener, elapsed, relativeNow, toServerDuration } from '@datadog/browser-core';
// Arbitrary value to cap number of element mostly for backend & to save bandwidth
export var MAX_NUMBER_OF_SELECTABLE_FOREGROUND_PERIODS = 500;
// Arbitrary value to cap number of element mostly for memory consumption in the browser
export var MAX_NUMBER_OF_STORED_FOREGROUND_PERIODS = 2500;
var foregroundPeriods = [];
export function startForegroundContexts() {
if (document.hasFocus()) {
addNewForegroundPeriod();
}
var stopForegroundTracking = trackFocus(addNewForegroundPeriod).stop;
var stopBlurTracking = trackBlur(closeForegroundPeriod).stop;
return {
isInForegroundAt: isInForegroundAt,
selectInForegroundPeriodsFor: selectInForegroundPeriodsFor,
stop: function () {
foregroundPeriods = [];
stopForegroundTracking();
stopBlurTracking();
},
};
}
export function addNewForegroundPeriod() {
if (foregroundPeriods.length > MAX_NUMBER_OF_STORED_FOREGROUND_PERIODS) {
return;
}
var currentForegroundPeriod = foregroundPeriods[foregroundPeriods.length - 1];
var now = relativeNow();
if (currentForegroundPeriod !== undefined && currentForegroundPeriod.end === undefined) {
return;
}
foregroundPeriods.push({
start: now,
});
}
export function closeForegroundPeriod() {
if (foregroundPeriods.length === 0) {
return;
}
var currentForegroundPeriod = foregroundPeriods[foregroundPeriods.length - 1];
var now = relativeNow();
if (currentForegroundPeriod.end !== undefined) {
return;
}
currentForegroundPeriod.end = now;
}
function trackFocus(onFocusChange) {
return addEventListener(window, "focus" /* DOM_EVENT.FOCUS */, function (event) {
if (!event.isTrusted) {
return;
import { toServerDuration } from '@datadog/browser-core';
// Todo: Remove in the next major release
export function mapToForegroundPeriods(pageStateServerEntries, duration) {
var foregroundPeriods = [];
for (var i = 0; i < pageStateServerEntries.length; i++) {
var current = pageStateServerEntries[i];
var next = pageStateServerEntries[i + 1];
if (current.state === "active" /* PageState.ACTIVE */) {
var start = current.start >= 0 ? current.start : 0;
var end = next ? next.start : toServerDuration(duration);
foregroundPeriods.push({
start: start,
duration: (end - start),
});
}
onFocusChange();
});
}
function trackBlur(onBlurChange) {
return addEventListener(window, "blur" /* DOM_EVENT.BLUR */, function (event) {
if (!event.isTrusted) {
return;
}
onBlurChange();
});
}
function isInForegroundAt(startTime) {
for (var i = foregroundPeriods.length - 1; i >= 0; i--) {
var foregroundPeriod = foregroundPeriods[i];
if (foregroundPeriod.end !== undefined && startTime > foregroundPeriod.end) {
break;
}
if (startTime > foregroundPeriod.start &&
(foregroundPeriod.end === undefined || startTime < foregroundPeriod.end)) {
return true;
}
}
return false;
return foregroundPeriods;
}
function selectInForegroundPeriodsFor(eventStartTime, duration) {
var eventEndTime = addDuration(eventStartTime, duration);
var filteredForegroundPeriods = [];
var earliestIndex = Math.max(0, foregroundPeriods.length - MAX_NUMBER_OF_SELECTABLE_FOREGROUND_PERIODS);
for (var i = foregroundPeriods.length - 1; i >= earliestIndex; i--) {
var foregroundPeriod = foregroundPeriods[i];
if (foregroundPeriod.end !== undefined && eventStartTime > foregroundPeriod.end) {
// event starts after the end of the current focus period
// since the array is sorted, we can stop looking for foreground periods
break;
}
if (eventEndTime < foregroundPeriod.start) {
// event ends before the start of the current focus period
// continue to previous one
continue;
}
var startTime = eventStartTime > foregroundPeriod.start ? eventStartTime : foregroundPeriod.start;
var startDuration = elapsed(eventStartTime, startTime);
var endTime = foregroundPeriod.end === undefined || eventEndTime < foregroundPeriod.end ? eventEndTime : foregroundPeriod.end;
var endDuration = elapsed(startTime, endTime);
filteredForegroundPeriods.unshift({
start: toServerDuration(startDuration),
duration: toServerDuration(endDuration),
});
}
return filteredForegroundPeriods;
}
//# sourceMappingURL=foregroundContexts.js.map

@@ -19,2 +19,3 @@ import type { Duration, RelativeTime } from '@datadog/browser-core';

findAll: (startTime: RelativeTime, duration: Duration) => PageStateServerEntry[] | undefined;
isInActivePageStateAt: (startTime: RelativeTime) => boolean;
addPageState(nextPageState: PageState, startTime?: RelativeTime): void;

@@ -21,0 +22,0 @@ stop: () => void;

@@ -57,2 +57,6 @@ import { elapsed, ValueHistory, SESSION_TIME_OUT_DELAY, toServerDuration, addEventListeners, relativeNow, } from '@datadog/browser-core';

},
isInActivePageStateAt: function (startTime) {
var pageStateEntry = pageStateHistory.find(startTime);
return pageStateEntry !== undefined && pageStateEntry.state === "active" /* PageState.ACTIVE */;
},
addPageState: addPageState,

@@ -59,0 +63,0 @@ stop: function () {

import type { ClocksState, Context, Observable } from '@datadog/browser-core';
import { ActionType } from '../../../rawRumEvent.types';
import type { LifeCycle } from '../../lifeCycle';
import type { ForegroundContexts } from '../../contexts/foregroundContexts';
import type { RumConfiguration } from '../../configuration';
import type { CommonContext } from '../../contexts/commonContext';
import type { PageStateHistory } from '../../contexts/pageStateHistory';
import type { ActionContexts, ClickAction } from './trackClickActions';

@@ -16,5 +16,5 @@ export type { ActionContexts };

export type AutoAction = ClickAction;
export declare function startActionCollection(lifeCycle: LifeCycle, domMutationObservable: Observable<void>, configuration: RumConfiguration, foregroundContexts: ForegroundContexts): {
export declare function startActionCollection(lifeCycle: LifeCycle, domMutationObservable: Observable<void>, configuration: RumConfiguration, pageStateHistory: PageStateHistory): {
addAction: (action: CustomAction, savedCommonContext?: CommonContext) => void;
actionContexts: ActionContexts;
};
import { noop, assign, combine, toServerDuration, generateUUID } from '@datadog/browser-core';
import { trackClickActions } from './trackClickActions';
export function startActionCollection(lifeCycle, domMutationObservable, configuration, foregroundContexts) {
export function startActionCollection(lifeCycle, domMutationObservable, configuration, pageStateHistory) {
lifeCycle.subscribe(1 /* LifeCycleEventType.AUTO_ACTION_COMPLETED */, function (action) {
return lifeCycle.notify(10 /* LifeCycleEventType.RAW_RUM_EVENT_COLLECTED */, processAction(action, foregroundContexts));
return lifeCycle.notify(10 /* LifeCycleEventType.RAW_RUM_EVENT_COLLECTED */, processAction(action, pageStateHistory));
});

@@ -15,3 +15,3 @@ var actionContexts = { findActionId: noop };

savedCommonContext: savedCommonContext,
}, processAction(action, foregroundContexts)));
}, processAction(action, pageStateHistory)));
},

@@ -21,3 +21,3 @@ actionContexts: actionContexts,

}
function processAction(action, foregroundContexts) {
function processAction(action, pageStateHistory) {
var autoActionProperties = isAutoAction(action)

@@ -60,7 +60,4 @@ ? {

type: "action" /* RumEventType.ACTION */,
view: { in_foreground: pageStateHistory.isInActivePageStateAt(action.startClocks.relative) },
}, autoActionProperties);
var inForeground = foregroundContexts.isInForegroundAt(action.startClocks.relative);
if (inForeground !== undefined) {
actionEvent.view = { in_foreground: inForeground };
}
return {

@@ -67,0 +64,0 @@ customerContext: customerContext,

import type { Context, ClocksState } from '@datadog/browser-core';
import type { LifeCycle } from '../../lifeCycle';
import type { ForegroundContexts } from '../../contexts/foregroundContexts';
import type { FeatureFlagContexts } from '../../contexts/featureFlagContext';
import type { CommonContext } from '../../contexts/commonContext';
import type { PageStateHistory } from '../../contexts/pageStateHistory';
export interface ProvidedError {

@@ -12,7 +12,7 @@ startClocks: ClocksState;

}
export declare function startErrorCollection(lifeCycle: LifeCycle, foregroundContexts: ForegroundContexts, featureFlagContexts: FeatureFlagContexts): {
export declare function startErrorCollection(lifeCycle: LifeCycle, pageStateHistory: PageStateHistory, featureFlagContexts: FeatureFlagContexts): {
addError: ({ error, handlingStack, startClocks, context: customerContext }: ProvidedError, savedCommonContext?: CommonContext | undefined) => void;
};
export declare function doStartErrorCollection(lifeCycle: LifeCycle, foregroundContexts: ForegroundContexts, featureFlagContexts: FeatureFlagContexts): {
export declare function doStartErrorCollection(lifeCycle: LifeCycle, pageStateHistory: PageStateHistory, featureFlagContexts: FeatureFlagContexts): {
addError: ({ error, handlingStack, startClocks, context: customerContext }: ProvidedError, savedCommonContext?: CommonContext) => void;
};
import { isEmptyObject, assign, ErrorSource, generateUUID, computeRawError, computeStackTrace, Observable, trackRuntimeError, } from '@datadog/browser-core';
import { trackConsoleError } from './trackConsoleError';
import { trackReportError } from './trackReportError';
export function startErrorCollection(lifeCycle, foregroundContexts, featureFlagContexts) {
export function startErrorCollection(lifeCycle, pageStateHistory, featureFlagContexts) {
var errorObservable = new Observable();

@@ -10,5 +10,5 @@ trackConsoleError(errorObservable);

errorObservable.subscribe(function (error) { return lifeCycle.notify(12 /* LifeCycleEventType.RAW_ERROR_COLLECTED */, { error: error }); });
return doStartErrorCollection(lifeCycle, foregroundContexts, featureFlagContexts);
return doStartErrorCollection(lifeCycle, pageStateHistory, featureFlagContexts);
}
export function doStartErrorCollection(lifeCycle, foregroundContexts, featureFlagContexts) {
export function doStartErrorCollection(lifeCycle, pageStateHistory, featureFlagContexts) {
lifeCycle.subscribe(12 /* LifeCycleEventType.RAW_ERROR_COLLECTED */, function (_a) {

@@ -19,3 +19,3 @@ var error = _a.error, customerContext = _a.customerContext, savedCommonContext = _a.savedCommonContext;

savedCommonContext: savedCommonContext,
}, processError(error, foregroundContexts, featureFlagContexts)));
}, processError(error, pageStateHistory, featureFlagContexts)));
});

@@ -43,3 +43,3 @@ return {

}
function processError(error, foregroundContexts, featureFlagContexts) {
function processError(error, pageStateHistory, featureFlagContexts) {
var rawRumEvent = {

@@ -60,7 +60,4 @@ date: error.startClocks.timeStamp,

type: "error" /* RumEventType.ERROR */,
view: { in_foreground: pageStateHistory.isInActivePageStateAt(error.startClocks.relative) },
};
var inForeground = foregroundContexts.isInForegroundAt(error.startClocks.relative);
if (inForeground) {
rawRumEvent.view = { in_foreground: inForeground };
}
var featureFlagContext = featureFlagContexts.findFeatureFlagEvaluations(error.startClocks.relative);

@@ -67,0 +64,0 @@ if (featureFlagContext && !isEmptyObject(featureFlagContext)) {

@@ -1,5 +0,14 @@

import type { Duration, Observable, ClocksState } from '@datadog/browser-core';
import type { ClocksState, Duration, Observable } from '@datadog/browser-core';
import { noop } from '@datadog/browser-core';
import { ViewLoadingType } from '../../../rawRumEvent.types';
import type { RumConfiguration } from '../../configuration';
import type { LifeCycle } from '../../lifeCycle';
export interface ScrollMetrics {
maxDepth: number;
maxDepthScrollHeight: number;
maxDepthScrollTop: number;
maxDepthTime: Duration;
}
/** Arbitrary scroll throttle duration */
export declare const THROTTLE_SCROLL_DURATION = 1000;
export interface ViewMetrics {

@@ -13,2 +22,12 @@ loadingTime?: Duration;

viewMetrics: ViewMetrics;
getScrollMetrics: () => ScrollMetrics | undefined;
};
export declare function trackScrollMetrics(viewStart: ClocksState, callback: (scrollMetrics: ScrollMetrics) => void, getScrollValues?: typeof computeScrollValues): {
stop: typeof noop;
};
declare function computeScrollValues(): {
scrollHeight: number;
scrollDepth: number;
scrollTop: number;
};
export {};

@@ -1,10 +0,29 @@

import { noop, round, ONE_SECOND, elapsed } from '@datadog/browser-core';
import { ExperimentalFeature, isExperimentalFeatureEnabled, ONE_SECOND, addEventListener, elapsed, noop, relativeNow, round, throttle, } from '@datadog/browser-core';
import { supportPerformanceTimingEvent } from '../../../browser/performanceCollection';
import { waitPageActivityEnd } from '../../waitPageActivityEnd';
import { getScrollY } from '../../../browser/scroll';
import { getViewportDimension } from '../../../browser/viewportObservable';
/** Arbitrary scroll throttle duration */
export var THROTTLE_SCROLL_DURATION = ONE_SECOND;
export function trackViewMetrics(lifeCycle, domMutationObservable, configuration, scheduleViewUpdate, loadingType, viewStart) {
var viewMetrics = {};
var scrollMetrics;
var _a = trackLoadingTime(lifeCycle, domMutationObservable, configuration, loadingType, viewStart, function (newLoadingTime) {
viewMetrics.loadingTime = newLoadingTime;
// We compute scroll metrics at loading time to ensure we have scroll data when loading the view initially
// This is to ensure that we have the depth data even if the user didn't scroll or if the view is not scrollable.
if (isExperimentalFeatureEnabled(ExperimentalFeature.SCROLLMAP)) {
var _a = computeScrollValues(), scrollHeight = _a.scrollHeight, scrollDepth = _a.scrollDepth, scrollTop = _a.scrollTop;
scrollMetrics = {
maxDepth: scrollDepth,
maxDepthScrollHeight: scrollHeight,
maxDepthTime: newLoadingTime,
maxDepthScrollTop: scrollTop,
};
}
scheduleViewUpdate();
}), stopLoadingTimeTracking = _a.stop, setLoadEvent = _a.setLoadEvent;
var stopScrollMetricsTracking = trackScrollMetrics(viewStart, function (newScrollMetrics) {
scrollMetrics = newScrollMetrics;
}, computeScrollValues).stop;
var stopCLSTracking;

@@ -25,7 +44,48 @@ if (isLayoutShiftSupported()) {

stopCLSTracking();
stopScrollMetricsTracking();
},
setLoadEvent: setLoadEvent,
viewMetrics: viewMetrics,
getScrollMetrics: function () { return scrollMetrics; },
};
}
export function trackScrollMetrics(viewStart, callback, getScrollValues) {
if (getScrollValues === void 0) { getScrollValues = computeScrollValues; }
if (!isExperimentalFeatureEnabled(ExperimentalFeature.SCROLLMAP)) {
return { stop: noop };
}
var maxDepth = 0;
var handleScrollEvent = throttle(function () {
var _a = getScrollValues(), scrollHeight = _a.scrollHeight, scrollDepth = _a.scrollDepth, scrollTop = _a.scrollTop;
if (scrollDepth > maxDepth) {
var now = relativeNow();
var maxDepthTime = elapsed(viewStart.relative, now);
maxDepth = scrollDepth;
callback({
maxDepth: maxDepth,
maxDepthScrollHeight: scrollHeight,
maxDepthTime: maxDepthTime,
maxDepthScrollTop: scrollTop,
});
}
}, THROTTLE_SCROLL_DURATION, { leading: false, trailing: true });
var stop = addEventListener(window, "scroll" /* DOM_EVENT.SCROLL */, handleScrollEvent.throttled, { passive: true }).stop;
return {
stop: function () {
handleScrollEvent.cancel();
stop();
},
};
}
function computeScrollValues() {
var scrollTop = getScrollY();
var height = getViewportDimension().height;
var scrollHeight = Math.round((document.scrollingElement || document.documentElement).scrollHeight);
var scrollDepth = Math.round(height + scrollTop);
return {
scrollHeight: scrollHeight,
scrollDepth: scrollDepth,
scrollTop: scrollTop,
};
}
function trackLoadingTime(lifeCycle, domMutationObservable, configuration, loadType, viewStart, callback) {

@@ -32,0 +92,0 @@ var isWaitingForLoadEvent = loadType === "initial_load" /* ViewLoadingType.INITIAL_LOAD */;

@@ -9,2 +9,3 @@ import type { Duration, ClocksState, TimeStamp, Observable, RelativeTime } from '@datadog/browser-core';

import type { Timings } from './trackInitialViewTimings';
import type { ScrollMetrics } from './trackViewMetrics';
export interface ViewEvent {

@@ -27,2 +28,3 @@ id: string;

cumulativeLayoutShift?: number;
scrollMetrics?: ScrollMetrics;
}

@@ -29,0 +31,0 @@ export interface ViewCreatedEvent {

@@ -88,3 +88,3 @@ import { noop, PageExitReason, shallowClone, assign, elapsed, generateUUID, ONE_MINUTE, throttle, clocksNow, clocksOrigin, timeStampNow, display, looksLikeRelativeTime, setInterval, clearInterval, } from '@datadog/browser-core';

}), scheduleViewUpdate = _a.throttled, cancelScheduleViewUpdate = _a.cancel;
var _b = trackViewMetrics(lifeCycle, domMutationObservable, configuration, scheduleViewUpdate, loadingType, startClocks), setLoadEvent = _b.setLoadEvent, stopViewMetricsTracking = _b.stop, viewMetrics = _b.viewMetrics;
var _b = trackViewMetrics(lifeCycle, domMutationObservable, configuration, scheduleViewUpdate, loadingType, startClocks), setLoadEvent = _b.setLoadEvent, stopViewMetricsTracking = _b.stop, viewMetrics = _b.viewMetrics, getScrollMetrics = _b.getScrollMetrics;
var _c = loadingType === "initial_load" /* ViewLoadingType.INITIAL_LOAD */

@@ -117,2 +117,3 @@ ? trackInitialViewTimings(lifeCycle, setLoadEvent, scheduleViewUpdate)

eventCounts: eventCounts,
scrollMetrics: getScrollMetrics(),
}, viewMetrics));

@@ -119,0 +120,0 @@ }

import type { Observable } from '@datadog/browser-core';
import type { RecorderApi } from '../../../boot/rumPublicApi';
import type { LifeCycle } from '../../lifeCycle';
import type { ForegroundContexts } from '../../contexts/foregroundContexts';
import type { LocationChange } from '../../../browser/locationChangeObservable';

@@ -10,3 +9,3 @@ import type { RumConfiguration } from '../../configuration';

import type { ViewOptions } from './trackViews';
export declare function startViewCollection(lifeCycle: LifeCycle, configuration: RumConfiguration, location: Location, domMutationObservable: Observable<void>, locationChangeObservable: Observable<LocationChange>, foregroundContexts: ForegroundContexts, featureFlagContexts: FeatureFlagContexts, pageStateHistory: PageStateHistory, recorderApi: RecorderApi, initialViewOptions?: ViewOptions): {
export declare function startViewCollection(lifeCycle: LifeCycle, configuration: RumConfiguration, location: Location, domMutationObservable: Observable<void>, locationChangeObservable: Observable<LocationChange>, featureFlagContexts: FeatureFlagContexts, pageStateHistory: PageStateHistory, recorderApi: RecorderApi, initialViewOptions?: ViewOptions): {
addTiming: (name: string, time?: import("@datadog/browser-core").TimeStamp | import("@datadog/browser-core").RelativeTime) => void;

@@ -13,0 +12,0 @@ startView: (options?: ViewOptions | undefined, startClocks?: import("@datadog/browser-core").ClocksState | undefined) => void;

import { isExperimentalFeatureEnabled, ExperimentalFeature, isEmptyObject, mapValues, toServerDuration, isNumber, } from '@datadog/browser-core';
import { mapToForegroundPeriods } from '../../contexts/foregroundContexts';
import { trackViews } from './trackViews';
export function startViewCollection(lifeCycle, configuration, location, domMutationObservable, locationChangeObservable, foregroundContexts, featureFlagContexts, pageStateHistory, recorderApi, initialViewOptions) {
export function startViewCollection(lifeCycle, configuration, location, domMutationObservable, locationChangeObservable, featureFlagContexts, pageStateHistory, recorderApi, initialViewOptions) {
lifeCycle.subscribe(3 /* LifeCycleEventType.VIEW_UPDATED */, function (view) {
return lifeCycle.notify(10 /* LifeCycleEventType.RAW_RUM_EVENT_COLLECTED */, processViewUpdate(view, foregroundContexts, featureFlagContexts, recorderApi, pageStateHistory));
return lifeCycle.notify(10 /* LifeCycleEventType.RAW_RUM_EVENT_COLLECTED */, processViewUpdate(view, configuration, featureFlagContexts, recorderApi, pageStateHistory));
});

@@ -10,6 +11,7 @@ var trackViewResult = trackViews(location, lifeCycle, domMutationObservable, configuration, locationChangeObservable, !configuration.trackViewsManually, initialViewOptions);

}
function processViewUpdate(view, foregroundContexts, featureFlagContexts, recorderApi, pageStateHistory) {
function processViewUpdate(view, configuration, featureFlagContexts, recorderApi, pageStateHistory) {
var replayStats = recorderApi.getReplayStats(view.id);
var featureFlagContext = featureFlagContexts.findFeatureFlagEvaluations(view.startClocks.relative);
var pageStatesEnabled = isExperimentalFeatureEnabled(ExperimentalFeature.PAGE_STATES);
var pageStates = pageStateHistory.findAll(view.startClocks.relative, view.duration);
var viewEvent = {

@@ -19,3 +21,3 @@ _dd: {

replay_stats: replayStats,
page_states: pageStatesEnabled ? pageStateHistory.findAll(view.startClocks.relative, view.duration) : undefined,
page_states: pageStatesEnabled ? pageStates : undefined,
},

@@ -55,7 +57,15 @@ date: view.startClocks.timeStamp,

time_spent: toServerDuration(view.duration),
in_foreground_periods: !pageStatesEnabled
? foregroundContexts.selectInForegroundPeriodsFor(view.startClocks.relative, view.duration)
: undefined,
in_foreground_periods: !pageStatesEnabled && pageStates ? mapToForegroundPeriods(pageStates, view.duration) : undefined, // Todo: Remove in the next major release
},
feature_flags: featureFlagContext && !isEmptyObject(featureFlagContext) ? featureFlagContext : undefined,
display: view.scrollMetrics
? {
scroll: {
max_depth: view.scrollMetrics.maxDepth,
max_depth_scroll_height: view.scrollMetrics.maxDepthScrollHeight,
max_depth_scroll_top: view.scrollMetrics.maxDepthScrollTop,
max_depth_time: toServerDuration(view.scrollMetrics.maxDepthTime),
},
}
: undefined,
session: {

@@ -65,2 +75,5 @@ has_replay: replayStats ? true : undefined,

},
privacy: {
replay_level: configuration.defaultPrivacyLevel,
},
};

@@ -67,0 +80,0 @@ if (!isEmptyObject(view.customTimings)) {

@@ -12,2 +12,3 @@ export { RumPublicApi, makeRumPublicApi, RecorderApi, StartRum } from './boot/rumPublicApi';

export { initViewportObservable, getViewportDimension } from './browser/viewportObservable';
export { getScrollX, getScrollY } from './browser/scroll';
export { RumInitConfiguration, RumConfiguration } from './domain/configuration';

@@ -14,0 +15,0 @@ export { DEFAULT_PROGRAMMATIC_ACTION_NAME_ATTRIBUTE } from './domain/rumEventsCollection/action/getActionNameFromElement';

@@ -6,2 +6,3 @@ export { makeRumPublicApi } from './boot/rumPublicApi';

export { initViewportObservable, getViewportDimension } from './browser/viewportObservable';
export { getScrollX, getScrollY } from './browser/scroll';
export { DEFAULT_PROGRAMMATIC_ACTION_NAME_ATTRIBUTE } from './domain/rumEventsCollection/action/getActionNameFromElement';

@@ -8,0 +9,0 @@ export { STABLE_ATTRIBUTES } from './domain/rumEventsCollection/action/getSelectorFromElement';

@@ -1,2 +0,2 @@

import type { Context, Duration, ErrorSource, ErrorHandling, ResourceType, ServerDuration, TimeStamp, RawErrorCause } from '@datadog/browser-core';
import type { Context, Duration, ErrorSource, ErrorHandling, ResourceType, ServerDuration, TimeStamp, RawErrorCause, DefaultPrivacyLevel } from '@datadog/browser-core';
import type { PageState } from './domain/contexts/pageStateHistory';

@@ -95,2 +95,6 @@ import type { RumSessionPlan } from './domain/rumSessionManager';

feature_flags?: Context;
display?: ViewDisplay;
privacy?: {
replay_level: DefaultPrivacyLevel;
};
_dd: {

@@ -102,2 +106,10 @@ document_version: number;

}
interface ViewDisplay {
scroll: {
max_depth?: number;
max_depth_scroll_height?: number;
max_depth_scroll_top?: number;
max_depth_time?: ServerDuration;
};
}
export interface InForegroundPeriod {

@@ -104,0 +116,0 @@ start: ServerDuration;

@@ -711,2 +711,12 @@ /**

/**
* Privacy properties
*/
readonly privacy?: {
/**
* The replay privacy level
*/
readonly replay_level: 'allow' | 'mask' | 'mask-user-input';
[k: string]: unknown;
};
/**
* Internal properties

@@ -733,4 +743,50 @@ */

}[];
/**
* Debug metadata for Replay Sessions
*/
replay_stats?: {
/**
* The number of records produced during this view lifetime
*/
records_count?: number;
/**
* The number of segments sent during this view lifetime
*/
segments_count?: number;
/**
* The total size in bytes of the segments sent during this view lifetime
*/
segments_total_raw_size?: number;
[k: string]: unknown;
};
[k: string]: unknown;
};
/**
* Display properties
*/
readonly display?: {
/**
* Scroll properties
*/
readonly scroll?: {
/**
* Distance between the top and the lowest point reached on this view (in pixels)
*/
readonly max_depth: number;
/**
* Page scroll height (total height) when the maximum scroll depth was reached for this view (in pixels)
*/
readonly max_depth_scroll_height: number;
/**
* Page scroll top (scrolled distance) when the maximum scroll depth was reached for this view (in pixels)
*/
readonly max_depth_scroll_top: number;
/**
* Duration between the view start and the scroll event that reached the maximum scroll depth for this view (in nanoseconds)
*/
readonly max_depth_time: number;
[k: string]: unknown;
};
[k: string]: unknown;
};
[k: string]: unknown;

@@ -915,2 +971,6 @@ };

/**
* Operating system build number, e.g. 15D21
*/
readonly build?: string;
/**
* Major operating system version, e.g. 8

@@ -917,0 +977,0 @@ */

{
"name": "@datadog/browser-rum-core",
"version": "4.43.0",
"version": "4.44.0",
"license": "Apache-2.0",

@@ -15,3 +15,3 @@ "main": "cjs/index.js",

"dependencies": {
"@datadog/browser-core": "4.43.0"
"@datadog/browser-core": "4.44.0"
},

@@ -29,3 +29,3 @@ "devDependencies": {

},
"gitHead": "27baf6471a3e48028c52af9c6282e00662687cc2"
"gitHead": "1d179b104265a2f149433026918f757eccc1bdd8"
}

@@ -14,3 +14,2 @@ import type { Observable, TelemetryEvent, RawError, ContextManager } from '@datadog/browser-core'

import { startRumAssembly } from '../domain/assembly'
import { startForegroundContexts } from '../domain/contexts/foregroundContexts'
import { startInternalContext } from '../domain/contexts/internalContext'

@@ -106,13 +105,12 @@ import { LifeCycle, LifeCycleEventType } from '../domain/lifeCycle'

const { viewContexts, foregroundContexts, pageStateHistory, urlContexts, actionContexts, addAction } =
startRumEventCollection(
lifeCycle,
configuration,
location,
session,
locationChangeObservable,
domMutationObservable,
() => buildCommonContext(globalContextManager, userContextManager, recorderApi),
reportError
)
const { viewContexts, pageStateHistory, urlContexts, actionContexts, addAction } = startRumEventCollection(
lifeCycle,
configuration,
location,
session,
locationChangeObservable,
domMutationObservable,
() => buildCommonContext(globalContextManager, userContextManager, recorderApi),
reportError
)

@@ -129,3 +127,2 @@ addTelemetryConfiguration(serializeRumConfiguration(initConfiguration))

locationChangeObservable,
foregroundContexts,
featureFlagContexts,

@@ -136,3 +133,3 @@ pageStateHistory,

)
const { addError } = startErrorCollection(lifeCycle, foregroundContexts, featureFlagContexts)
const { addError } = startErrorCollection(lifeCycle, pageStateHistory, featureFlagContexts)

@@ -186,3 +183,2 @@ startRequestCollection(lifeCycle, configuration, session)

const foregroundContexts = startForegroundContexts()
const pageStateHistory = startPageStateHistory()

@@ -194,3 +190,3 @@

configuration,
foregroundContexts
pageStateHistory
)

@@ -211,3 +207,2 @@

viewContexts,
foregroundContexts,
pageStateHistory,

@@ -219,5 +214,5 @@ urlContexts,

viewContexts.stop()
foregroundContexts.stop()
pageStateHistory.stop()
},
}
}

@@ -1,16 +0,6 @@

import type { RelativeTime, Duration } from '@datadog/browser-core'
import { addDuration, addEventListener, DOM_EVENT, elapsed, relativeNow, toServerDuration } from '@datadog/browser-core'
import type { InForegroundPeriod } from '../../rawRumEvent.types'
import type { RelativeTime, Duration, ServerDuration } from '@datadog/browser-core'
import { toServerDuration } from '@datadog/browser-core'
import type { InForegroundPeriod, PageStateServerEntry } from '../../rawRumEvent.types'
import { PageState } from './pageStateHistory'
// Arbitrary value to cap number of element mostly for backend & to save bandwidth
export const MAX_NUMBER_OF_SELECTABLE_FOREGROUND_PERIODS = 500
// Arbitrary value to cap number of element mostly for memory consumption in the browser
export const MAX_NUMBER_OF_STORED_FOREGROUND_PERIODS = 2500
export interface ForegroundContexts {
isInForegroundAt: (startTime: RelativeTime) => boolean | undefined
selectInForegroundPeriodsFor: (startTime: RelativeTime, duration: Duration) => InForegroundPeriod[] | undefined
stop: () => void
}
export interface ForegroundPeriod {

@@ -21,110 +11,23 @@ start: RelativeTime

let foregroundPeriods: ForegroundPeriod[] = []
// Todo: Remove in the next major release
export function mapToForegroundPeriods(
pageStateServerEntries: PageStateServerEntry[],
duration: Duration
): InForegroundPeriod[] {
const foregroundPeriods: InForegroundPeriod[] = []
for (let i = 0; i < pageStateServerEntries.length; i++) {
const current = pageStateServerEntries[i]
const next = pageStateServerEntries[i + 1]
export function startForegroundContexts(): ForegroundContexts {
if (document.hasFocus()) {
addNewForegroundPeriod()
}
const { stop: stopForegroundTracking } = trackFocus(addNewForegroundPeriod)
const { stop: stopBlurTracking } = trackBlur(closeForegroundPeriod)
return {
isInForegroundAt,
selectInForegroundPeriodsFor,
stop: () => {
foregroundPeriods = []
stopForegroundTracking()
stopBlurTracking()
},
}
}
export function addNewForegroundPeriod() {
if (foregroundPeriods.length > MAX_NUMBER_OF_STORED_FOREGROUND_PERIODS) {
return
}
const currentForegroundPeriod = foregroundPeriods[foregroundPeriods.length - 1]
const now = relativeNow()
if (currentForegroundPeriod !== undefined && currentForegroundPeriod.end === undefined) {
return
}
foregroundPeriods.push({
start: now,
})
}
export function closeForegroundPeriod() {
if (foregroundPeriods.length === 0) {
return
}
const currentForegroundPeriod = foregroundPeriods[foregroundPeriods.length - 1]
const now = relativeNow()
if (currentForegroundPeriod.end !== undefined) {
return
}
currentForegroundPeriod.end = now
}
function trackFocus(onFocusChange: () => void) {
return addEventListener(window, DOM_EVENT.FOCUS, (event) => {
if (!event.isTrusted) {
return
if (current.state === PageState.ACTIVE) {
const start = current.start >= 0 ? current.start : (0 as ServerDuration)
const end = next ? next.start : toServerDuration(duration)
foregroundPeriods.push({
start,
duration: (end - start) as ServerDuration,
})
}
onFocusChange()
})
}
function trackBlur(onBlurChange: () => void) {
return addEventListener(window, DOM_EVENT.BLUR, (event) => {
if (!event.isTrusted) {
return
}
onBlurChange()
})
}
function isInForegroundAt(startTime: RelativeTime): boolean {
for (let i = foregroundPeriods.length - 1; i >= 0; i--) {
const foregroundPeriod = foregroundPeriods[i]
if (foregroundPeriod.end !== undefined && startTime > foregroundPeriod.end) {
break
}
if (
startTime > foregroundPeriod.start &&
(foregroundPeriod.end === undefined || startTime < foregroundPeriod.end)
) {
return true
}
}
return false
}
function selectInForegroundPeriodsFor(eventStartTime: RelativeTime, duration: Duration): InForegroundPeriod[] {
const eventEndTime = addDuration(eventStartTime, duration)
const filteredForegroundPeriods: InForegroundPeriod[] = []
const earliestIndex = Math.max(0, foregroundPeriods.length - MAX_NUMBER_OF_SELECTABLE_FOREGROUND_PERIODS)
for (let i = foregroundPeriods.length - 1; i >= earliestIndex; i--) {
const foregroundPeriod = foregroundPeriods[i]
if (foregroundPeriod.end !== undefined && eventStartTime > foregroundPeriod.end) {
// event starts after the end of the current focus period
// since the array is sorted, we can stop looking for foreground periods
break
}
if (eventEndTime < foregroundPeriod.start) {
// event ends before the start of the current focus period
// continue to previous one
continue
}
const startTime = eventStartTime > foregroundPeriod.start ? eventStartTime : foregroundPeriod.start
const startDuration = elapsed(eventStartTime, startTime)
const endTime =
foregroundPeriod.end === undefined || eventEndTime < foregroundPeriod.end ? eventEndTime : foregroundPeriod.end
const endDuration = elapsed(startTime, endTime)
filteredForegroundPeriods.unshift({
start: toServerDuration(startDuration),
duration: toServerDuration(endDuration),
})
}
return filteredForegroundPeriods
return foregroundPeriods
}

@@ -32,2 +32,3 @@ import type { Duration, RelativeTime } from '@datadog/browser-core'

findAll: (startTime: RelativeTime, duration: Duration) => PageStateServerEntry[] | undefined
isInActivePageStateAt: (startTime: RelativeTime) => boolean
addPageState(nextPageState: PageState, startTime?: RelativeTime): void

@@ -102,2 +103,6 @@ stop: () => void

},
isInActivePageStateAt: (startTime: RelativeTime) => {
const pageStateEntry = pageStateHistory.find(startTime)
return pageStateEntry !== undefined && pageStateEntry.state === PageState.ACTIVE
},
addPageState,

@@ -104,0 +109,0 @@ stop: () => {

@@ -8,5 +8,5 @@ import type { ClocksState, Context, Observable } from '@datadog/browser-core'

import { LifeCycleEventType } from '../../lifeCycle'
import type { ForegroundContexts } from '../../contexts/foregroundContexts'
import type { RumConfiguration } from '../../configuration'
import type { CommonContext } from '../../contexts/commonContext'
import type { PageStateHistory } from '../../contexts/pageStateHistory'
import type { ActionContexts, ClickAction } from './trackClickActions'

@@ -30,6 +30,6 @@ import { trackClickActions } from './trackClickActions'

configuration: RumConfiguration,
foregroundContexts: ForegroundContexts
pageStateHistory: PageStateHistory
) {
lifeCycle.subscribe(LifeCycleEventType.AUTO_ACTION_COMPLETED, (action) =>
lifeCycle.notify(LifeCycleEventType.RAW_RUM_EVENT_COLLECTED, processAction(action, foregroundContexts))
lifeCycle.notify(LifeCycleEventType.RAW_RUM_EVENT_COLLECTED, processAction(action, pageStateHistory))
)

@@ -50,3 +50,3 @@

},
processAction(action, foregroundContexts)
processAction(action, pageStateHistory)
)

@@ -61,3 +61,3 @@ )

action: AutoAction | CustomAction,
foregroundContexts: ForegroundContexts
pageStateHistory: PageStateHistory
): RawRumEventCollectedData<RawRumActionEvent> {

@@ -102,9 +102,7 @@ const autoActionProperties = isAutoAction(action)

type: RumEventType.ACTION as const,
view: { in_foreground: pageStateHistory.isInActivePageStateAt(action.startClocks.relative) },
},
autoActionProperties
)
const inForeground = foregroundContexts.isInForegroundAt(action.startClocks.relative)
if (inForeground !== undefined) {
actionEvent.view = { in_foreground: inForeground }
}
return {

@@ -111,0 +109,0 @@ customerContext,

@@ -18,5 +18,5 @@ import type { Context, RawError, ClocksState } from '@datadog/browser-core'

import { LifeCycleEventType } from '../../lifeCycle'
import type { ForegroundContexts } from '../../contexts/foregroundContexts'
import type { FeatureFlagContexts } from '../../contexts/featureFlagContext'
import type { CommonContext } from '../../contexts/commonContext'
import type { PageStateHistory } from '../../contexts/pageStateHistory'
import { trackConsoleError } from './trackConsoleError'

@@ -34,3 +34,3 @@ import { trackReportError } from './trackReportError'

lifeCycle: LifeCycle,
foregroundContexts: ForegroundContexts,
pageStateHistory: PageStateHistory,
featureFlagContexts: FeatureFlagContexts

@@ -46,3 +46,3 @@ ) {

return doStartErrorCollection(lifeCycle, foregroundContexts, featureFlagContexts)
return doStartErrorCollection(lifeCycle, pageStateHistory, featureFlagContexts)
}

@@ -52,3 +52,3 @@

lifeCycle: LifeCycle,
foregroundContexts: ForegroundContexts,
pageStateHistory: PageStateHistory,
featureFlagContexts: FeatureFlagContexts

@@ -64,3 +64,3 @@ ) {

},
processError(error, foregroundContexts, featureFlagContexts)
processError(error, pageStateHistory, featureFlagContexts)
)

@@ -97,3 +97,3 @@ )

error: RawError,
foregroundContexts: ForegroundContexts,
pageStateHistory: PageStateHistory,
featureFlagContexts: FeatureFlagContexts

@@ -116,9 +116,5 @@ ): RawRumEventCollectedData<RawRumErrorEvent> {

type: RumEventType.ERROR as const,
view: { in_foreground: pageStateHistory.isInActivePageStateAt(error.startClocks.relative) },
}
const inForeground = foregroundContexts.isInForegroundAt(error.startClocks.relative)
if (inForeground) {
rawRumEvent.view = { in_foreground: inForeground }
}
const featureFlagContext = featureFlagContexts.findFeatureFlagEvaluations(error.startClocks.relative)

@@ -125,0 +121,0 @@ if (featureFlagContext && !isEmptyObject(featureFlagContext)) {

@@ -1,3 +0,14 @@

import type { Duration, RelativeTime, Observable, ClocksState } from '@datadog/browser-core'
import { noop, round, ONE_SECOND, elapsed } from '@datadog/browser-core'
import type { ClocksState, Duration, Observable, RelativeTime } from '@datadog/browser-core'
import {
ExperimentalFeature,
isExperimentalFeatureEnabled,
DOM_EVENT,
ONE_SECOND,
addEventListener,
elapsed,
noop,
relativeNow,
round,
throttle,
} from '@datadog/browser-core'
import type { RumLayoutShiftTiming } from '../../../browser/performanceCollection'

@@ -11,2 +22,15 @@ import { supportPerformanceTimingEvent } from '../../../browser/performanceCollection'

import { getScrollY } from '../../../browser/scroll'
import { getViewportDimension } from '../../../browser/viewportObservable'
export interface ScrollMetrics {
maxDepth: number
maxDepthScrollHeight: number
maxDepthScrollTop: number
maxDepthTime: Duration
}
/** Arbitrary scroll throttle duration */
export const THROTTLE_SCROLL_DURATION = ONE_SECOND
export interface ViewMetrics {

@@ -27,2 +51,4 @@ loadingTime?: Duration

let scrollMetrics: ScrollMetrics | undefined
const { stop: stopLoadingTimeTracking, setLoadEvent } = trackLoadingTime(

@@ -36,2 +62,15 @@ lifeCycle,

viewMetrics.loadingTime = newLoadingTime
// We compute scroll metrics at loading time to ensure we have scroll data when loading the view initially
// This is to ensure that we have the depth data even if the user didn't scroll or if the view is not scrollable.
if (isExperimentalFeatureEnabled(ExperimentalFeature.SCROLLMAP)) {
const { scrollHeight, scrollDepth, scrollTop } = computeScrollValues()
scrollMetrics = {
maxDepth: scrollDepth,
maxDepthScrollHeight: scrollHeight,
maxDepthTime: newLoadingTime,
maxDepthScrollTop: scrollTop,
}
}
scheduleViewUpdate()

@@ -41,2 +80,10 @@ }

const { stop: stopScrollMetricsTracking } = trackScrollMetrics(
viewStart,
(newScrollMetrics) => {
scrollMetrics = newScrollMetrics
},
computeScrollValues
)
let stopCLSTracking: () => void

@@ -52,2 +99,3 @@ if (isLayoutShiftSupported()) {

}
return {

@@ -57,8 +105,64 @@ stop: () => {

stopCLSTracking()
stopScrollMetricsTracking()
},
setLoadEvent,
viewMetrics,
getScrollMetrics: () => scrollMetrics,
}
}
export function trackScrollMetrics(
viewStart: ClocksState,
callback: (scrollMetrics: ScrollMetrics) => void,
getScrollValues = computeScrollValues
) {
if (!isExperimentalFeatureEnabled(ExperimentalFeature.SCROLLMAP)) {
return { stop: noop }
}
let maxDepth = 0
const handleScrollEvent = throttle(
() => {
const { scrollHeight, scrollDepth, scrollTop } = getScrollValues()
if (scrollDepth > maxDepth) {
const now = relativeNow()
const maxDepthTime = elapsed(viewStart.relative, now)
maxDepth = scrollDepth
callback({
maxDepth,
maxDepthScrollHeight: scrollHeight,
maxDepthTime,
maxDepthScrollTop: scrollTop,
})
}
},
THROTTLE_SCROLL_DURATION,
{ leading: false, trailing: true }
)
const { stop } = addEventListener(window, DOM_EVENT.SCROLL, handleScrollEvent.throttled, { passive: true })
return {
stop: () => {
handleScrollEvent.cancel()
stop()
},
}
}
function computeScrollValues() {
const scrollTop = getScrollY()
const { height } = getViewportDimension()
const scrollHeight = Math.round((document.scrollingElement || document.documentElement).scrollHeight)
const scrollDepth = Math.round(height + scrollTop)
return {
scrollHeight,
scrollDepth,
scrollTop,
}
}
function trackLoadingTime(

@@ -65,0 +169,0 @@ lifeCycle: LifeCycle,

@@ -30,2 +30,3 @@ import type { Duration, ClocksState, TimeStamp, Observable, Subscription, RelativeTime } from '@datadog/browser-core'

import { trackInitialViewTimings } from './trackInitialViewTimings'
import type { ScrollMetrics } from './trackViewMetrics'
import { trackViewMetrics } from './trackViewMetrics'

@@ -51,2 +52,3 @@ import { trackViewEventCounts } from './trackViewEventCounts'

cumulativeLayoutShift?: number
scrollMetrics?: ScrollMetrics
}

@@ -190,2 +192,3 @@

viewMetrics,
getScrollMetrics,
} = trackViewMetrics(lifeCycle, domMutationObservable, configuration, scheduleViewUpdate, loadingType, startClocks)

@@ -212,5 +215,5 @@

cancelScheduleViewUpdate()
documentVersion += 1
const currentEnd = endClocks === undefined ? timeStampNow() : endClocks.timeStamp
lifeCycle.notify(

@@ -234,2 +237,3 @@ LifeCycleEventType.VIEW_UPDATED,

eventCounts,
scrollMetrics: getScrollMetrics(),
},

@@ -236,0 +240,0 @@ viewMetrics

@@ -15,3 +15,3 @@ import type { Duration, ServerDuration, Observable } from '@datadog/browser-core'

import { LifeCycleEventType } from '../../lifeCycle'
import type { ForegroundContexts } from '../../contexts/foregroundContexts'
import { mapToForegroundPeriods } from '../../contexts/foregroundContexts'
import type { LocationChange } from '../../../browser/locationChangeObservable'

@@ -30,3 +30,2 @@ import type { RumConfiguration } from '../../configuration'

locationChangeObservable: Observable<LocationChange>,
foregroundContexts: ForegroundContexts,
featureFlagContexts: FeatureFlagContexts,

@@ -40,3 +39,3 @@ pageStateHistory: PageStateHistory,

LifeCycleEventType.RAW_RUM_EVENT_COLLECTED,
processViewUpdate(view, foregroundContexts, featureFlagContexts, recorderApi, pageStateHistory)
processViewUpdate(view, configuration, featureFlagContexts, recorderApi, pageStateHistory)
)

@@ -59,3 +58,3 @@ )

view: ViewEvent,
foregroundContexts: ForegroundContexts,
configuration: RumConfiguration,
featureFlagContexts: FeatureFlagContexts,

@@ -68,2 +67,3 @@ recorderApi: RecorderApi,

const pageStatesEnabled = isExperimentalFeatureEnabled(ExperimentalFeature.PAGE_STATES)
const pageStates = pageStateHistory.findAll(view.startClocks.relative, view.duration)
const viewEvent: RawRumViewEvent = {

@@ -73,3 +73,3 @@ _dd: {

replay_stats: replayStats,
page_states: pageStatesEnabled ? pageStateHistory.findAll(view.startClocks.relative, view.duration) : undefined,
page_states: pageStatesEnabled ? pageStates : undefined,
},

@@ -109,7 +109,16 @@ date: view.startClocks.timeStamp,

time_spent: toServerDuration(view.duration),
in_foreground_periods: !pageStatesEnabled
? foregroundContexts.selectInForegroundPeriodsFor(view.startClocks.relative, view.duration)
: undefined,
in_foreground_periods:
!pageStatesEnabled && pageStates ? mapToForegroundPeriods(pageStates, view.duration) : undefined, // Todo: Remove in the next major release
},
feature_flags: featureFlagContext && !isEmptyObject(featureFlagContext) ? featureFlagContext : undefined,
display: view.scrollMetrics
? {
scroll: {
max_depth: view.scrollMetrics.maxDepth,
max_depth_scroll_height: view.scrollMetrics.maxDepthScrollHeight,
max_depth_scroll_top: view.scrollMetrics.maxDepthScrollTop,
max_depth_time: toServerDuration(view.scrollMetrics.maxDepthTime),
},
}
: undefined,
session: {

@@ -119,2 +128,5 @@ has_replay: replayStats ? true : undefined,

},
privacy: {
replay_level: configuration.defaultPrivacyLevel,
},
}

@@ -121,0 +133,0 @@ if (!isEmptyObject(view.customTimings)) {

@@ -29,2 +29,3 @@ export { RumPublicApi, makeRumPublicApi, RecorderApi, StartRum } from './boot/rumPublicApi'

export { initViewportObservable, getViewportDimension } from './browser/viewportObservable'
export { getScrollX, getScrollY } from './browser/scroll'
export { RumInitConfiguration, RumConfiguration } from './domain/configuration'

@@ -31,0 +32,0 @@ export { DEFAULT_PROGRAMMATIC_ACTION_NAME_ATTRIBUTE } from './domain/rumEventsCollection/action/getActionNameFromElement'

@@ -10,2 +10,3 @@ import type {

RawErrorCause,
DefaultPrivacyLevel,
} from '@datadog/browser-core'

@@ -111,2 +112,6 @@ import type { PageState } from './domain/contexts/pageStateHistory'

feature_flags?: Context
display?: ViewDisplay
privacy?: {
replay_level: DefaultPrivacyLevel
}
_dd: {

@@ -119,2 +124,11 @@ document_version: number

interface ViewDisplay {
scroll: {
max_depth?: number
max_depth_scroll_height?: number
max_depth_scroll_top?: number
max_depth_time?: ServerDuration
}
}
export interface InForegroundPeriod {

@@ -121,0 +135,0 @@ start: ServerDuration

@@ -768,2 +768,12 @@ /* eslint-disable */

/**
* Privacy properties
*/
readonly privacy?: {
/**
* The replay privacy level
*/
readonly replay_level: 'allow' | 'mask' | 'mask-user-input'
[k: string]: unknown
}
/**
* Internal properties

@@ -790,4 +800,50 @@ */

}[]
/**
* Debug metadata for Replay Sessions
*/
replay_stats?: {
/**
* The number of records produced during this view lifetime
*/
records_count?: number
/**
* The number of segments sent during this view lifetime
*/
segments_count?: number
/**
* The total size in bytes of the segments sent during this view lifetime
*/
segments_total_raw_size?: number
[k: string]: unknown
}
[k: string]: unknown
}
/**
* Display properties
*/
readonly display?: {
/**
* Scroll properties
*/
readonly scroll?: {
/**
* Distance between the top and the lowest point reached on this view (in pixels)
*/
readonly max_depth: number
/**
* Page scroll height (total height) when the maximum scroll depth was reached for this view (in pixels)
*/
readonly max_depth_scroll_height: number
/**
* Page scroll top (scrolled distance) when the maximum scroll depth was reached for this view (in pixels)
*/
readonly max_depth_scroll_top: number
/**
* Duration between the view start and the scroll event that reached the maximum scroll depth for this view (in nanoseconds)
*/
readonly max_depth_time: number
[k: string]: unknown
}
[k: string]: unknown
}
[k: string]: unknown

@@ -983,2 +1039,6 @@ }

/**
* Operating system build number, e.g. 15D21
*/
readonly build?: string
/**
* Major operating system version, e.g. 8

@@ -985,0 +1045,0 @@ */

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc