UNPKG

@grafana/faro-web-sdk

Version:

Faro instrumentations, metas, transports for web.

121 lines 5.24 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.UserActionController = void 0; // packages/web-sdk/src/instrumentations/userActions/userActionController.ts const faro_core_1 = require("@grafana/faro-core"); const domMutationMonitor_1 = require("../_internal/monitors/domMutationMonitor"); const httpRequestMonitor_1 = require("../_internal/monitors/httpRequestMonitor"); const performanceEntriesMonitor_1 = require("../_internal/monitors/performanceEntriesMonitor"); const util_1 = require("./util"); const defaultFollowUpActionTimeRange = 100; const defaultHaltTimeout = 10 * 1000; class UserActionController { constructor(userAction) { this.userAction = userAction; this.http = (0, httpRequestMonitor_1.monitorHttpRequests)(); this.dom = (0, domMutationMonitor_1.monitorDomMutations)(); this.perf = (0, performanceEntriesMonitor_1.monitorPerformanceEntries)(); this.isValid = false; this.runningRequests = new Map(); } attach() { // Subscribe to monitors while action is active/halting this.allMonitorsSub = new faro_core_1.Observable() .merge(this.http, this.dom, this.perf) .takeWhile(() => [faro_core_1.UserActionState.Started, faro_core_1.UserActionState.Halted].includes(this.userAction.getState())) .filter((msg) => { // If the user action is in halt state, we only keep listening to ended http requests if (this.userAction.getState() === faro_core_1.UserActionState.Halted && !((0, util_1.isRequestEndMessage)(msg) && this.runningRequests.has(msg.request.requestId))) { return false; } return true; }) .subscribe((msg) => { if ((0, util_1.isRequestStartMessage)(msg)) { // An action is on halt if it has pending items, like pending HTTP requests. // In this case we start a separate timeout to wait for the requests to finish // If in the halt state, we stop adding Faro signals to the action's buffer (see userActionLifecycleHandler.ts) // But we are still subscribed to this.runningRequests.set(msg.request.requestId, msg.request); } if ((0, util_1.isRequestEndMessage)(msg)) { this.runningRequests.delete(msg.request.requestId); } if (!(0, util_1.isRequestEndMessage)(msg)) { if (!this.isValid) { this.isValid = true; } this.scheduleFollowUp(); } else if (this.userAction.getState() === faro_core_1.UserActionState.Halted && this.runningRequests.size === 0) { this.endAction(); } }); // When UA ends or cancels, cleanup timers/subscriptions this.stateSub = this.userAction .filter((s) => [faro_core_1.UserActionState.Ended, faro_core_1.UserActionState.Cancelled].includes(s)) .first() .subscribe(() => this.cleanup()); // initial follow-up window in case nothing else happens this.scheduleFollowUp(); } scheduleFollowUp() { this.clearTimer(this.followUpTid); this.followUpTid = setTimeout(() => { // If action just started and there's pending work, go to halted if (this.userAction.getState() === faro_core_1.UserActionState.Started && this.runningRequests.size > 0) { this.haltAction(); return; } // If we saw any relevant activity in the window, finish as ended if (this.isValid) { this.endAction(); return; } // Otherwise, no signals => cancel this.cancelAction(); }, defaultFollowUpActionTimeRange); } haltAction() { if (this.userAction.getState() !== faro_core_1.UserActionState.Started) { return; } this.userAction.halt(); this.startHaltTimeout(); } startHaltTimeout() { this.clearTimer(this.haltTid); this.haltTid = (0, util_1.startTimeout)(this.haltTid, () => { // If still halted after timeout, end if (this.userAction.getState() === faro_core_1.UserActionState.Halted) { this.endAction(); } }, defaultHaltTimeout); } endAction() { this.userAction.end(); this.cleanup(); } cancelAction() { this.userAction.cancel(); this.cleanup(); } cleanup() { var _a, _b; this.clearTimer(this.followUpTid); this.clearTimer(this.haltTid); (_a = this.allMonitorsSub) === null || _a === void 0 ? void 0 : _a.unsubscribe(); (_b = this.stateSub) === null || _b === void 0 ? void 0 : _b.unsubscribe(); this.allMonitorsSub = undefined; this.stateSub = undefined; this.runningRequests.clear(); } clearTimer(id) { if (id) { clearTimeout(id); } } } exports.UserActionController = UserActionController; //# sourceMappingURL=userActionController.js.map