@grafana/faro-web-sdk
Version:
Faro instrumentations, metas, transports for web.
130 lines • 6.22 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getUserEventHandler = void 0;
var faro_core_1 = require("@grafana/faro-core");
var const_1 = require("./const");
var domMutationMonitor_1 = require("./domMutationMonitor");
var httpRequestMonitor_1 = require("./httpRequestMonitor");
var performanceEntriesMonitor_1 = require("./performanceEntriesMonitor");
var util_1 = require("./util");
function getUserEventHandler(faro) {
var api = faro.api, config = faro.config;
var httpMonitor = (0, httpRequestMonitor_1.monitorHttpRequests)();
var domMutationsMonitor = (0, domMutationMonitor_1.monitorDomMutations)();
var performanceEntriesMonitor = (0, performanceEntriesMonitor_1.monitorPerformanceEntries)();
var allMonitorsSub;
var allMonitorsObserver;
var timeoutId;
var actionRunning = false;
function processUserEvent(event) {
var _a;
var userActionName = getUserActionName(event.target, (_a = config.trackUserActionsDataAttributeName) !== null && _a !== void 0 ? _a : const_1.userActionDataAttributeParsed);
if (actionRunning || userActionName == null) {
return;
}
actionRunning = true;
var startTime = (0, faro_core_1.dateNow)();
var endTime;
var actionId = (0, faro_core_1.genShortID)();
faro_core_1.apiMessageBus.notify({
type: faro_core_1.USER_ACTION_START_MESSAGE_TYPE,
name: userActionName,
startTime: startTime,
parentId: actionId,
});
// Triggers if no initial action happened within the first 100ms
timeoutId = startTimeout(timeoutId, function () {
endTime = (0, faro_core_1.dateNow)();
// Listening for follow up activities stops once action is cancelled (set to false)
actionRunning = false;
sendUserActionCancelMessage(userActionName, actionId);
});
allMonitorsObserver = (0, faro_core_1.merge)(httpMonitor, domMutationsMonitor, performanceEntriesMonitor);
allMonitorsSub = allMonitorsObserver
.takeWhile(function () { return actionRunning; })
.subscribe(function () {
// A http request, a DOM mutation or a performance entry happened so we have a follow up activity and start the timeout again
// If timeout is triggered the user action is done and we send respective messages and events
timeoutId = startTimeout(timeoutId, function () {
endTime = (0, faro_core_1.dateNow)();
var duration = endTime - startTime;
var eventType = event.type;
// order matters, first emit the user-action-end event and then push the event
faro_core_1.apiMessageBus.notify({
type: faro_core_1.USER_ACTION_END_MESSAGE_TYPE,
name: userActionName,
id: actionId,
startTime: startTime,
endTime: endTime,
duration: duration,
eventType: eventType,
});
// Send the final action parent event
api.pushEvent(userActionName, {
userActionStartTime: startTime.toString(),
userActionEndTime: endTime.toString(),
userActionDuration: duration.toString(),
userActionEventType: eventType,
}, undefined, {
timestampOverwriteMs: startTime,
customPayloadTransformer: function (payload) {
payload.action = {
id: actionId,
name: userActionName,
};
return payload;
},
});
// Ensure action is blocked until it is fully processed.
actionRunning = false;
allMonitorsSub === null || allMonitorsSub === void 0 ? void 0 : allMonitorsSub.unsubscribe();
allMonitorsObserver === null || allMonitorsObserver === void 0 ? void 0 : allMonitorsObserver.unsubscribeAll();
});
});
}
registerVisibilityChangeHandler(allMonitorsSub, allMonitorsObserver);
return processUserEvent;
}
exports.getUserEventHandler = getUserEventHandler;
function getUserActionName(element, dataAttributeName) {
var parsedDataAttributeName = (0, util_1.convertDataAttributeName)(dataAttributeName);
var dataset = element.dataset;
for (var key in dataset) {
if (key === parsedDataAttributeName) {
return dataset[key];
}
}
return undefined;
}
function startTimeout(timeoutId, cb) {
var maxTimeSpanTillUserActionEnd = 100;
if (timeoutId) {
clearTimeout(timeoutId);
}
//@ts-expect-error for some reason vscode is using the node types
timeoutId = setTimeout(function () {
cb();
}, maxTimeSpanTillUserActionEnd);
return timeoutId;
}
function sendUserActionCancelMessage(userActionName, actionId) {
faro_core_1.apiMessageBus.notify({
type: faro_core_1.USER_ACTION_CANCEL_MESSAGE_TYPE,
name: userActionName,
parentId: actionId,
});
}
function registerVisibilityChangeHandler(allMonitorsSub, allMonitorsObserver) {
// stop monitoring in background tabs
document.addEventListener('visibilitychange', function () {
if (document.visibilityState === 'hidden') {
// Unsubscribe from all monitors when the tab goes into the background to free up resources (merge.unsubscribe() also unsubscribes from all inner observables)
// Monitors will be re-subscribed in the processEvent function when the first user action is detected
allMonitorsSub === null || allMonitorsSub === void 0 ? void 0 : allMonitorsSub.unsubscribe();
allMonitorsSub = undefined;
allMonitorsObserver === null || allMonitorsObserver === void 0 ? void 0 : allMonitorsObserver.unsubscribeAll();
allMonitorsObserver = undefined;
}
});
}
//# sourceMappingURL=processUserActionEventHandler.js.map