@amplitude/plugin-autocapture-browser 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/autocapture/track-rage-click.d.ts +0 -1
- package/lib/cjs/autocapture/track-rage-click.d.ts.map +1 -1
- package/lib/cjs/autocapture/track-rage-click.js +39 -31
- package/lib/cjs/autocapture/track-rage-click.js.map +1 -1
- package/lib/cjs/frustration-plugin.d.ts +1 -1
- package/lib/cjs/frustration-plugin.d.ts.map +1 -1
- package/lib/cjs/frustration-plugin.js +1 -0
- package/lib/cjs/frustration-plugin.js.map +1 -1
- package/lib/cjs/version.d.ts +1 -1
- package/lib/cjs/version.js +1 -1
- package/lib/cjs/version.js.map +1 -1
- package/lib/esm/autocapture/track-rage-click.d.ts +0 -1
- package/lib/esm/autocapture/track-rage-click.d.ts.map +1 -1
- package/lib/esm/autocapture/track-rage-click.js +39 -30
- package/lib/esm/autocapture/track-rage-click.js.map +1 -1
- package/lib/esm/frustration-plugin.d.ts +1 -1
- package/lib/esm/frustration-plugin.d.ts.map +1 -1
- package/lib/esm/frustration-plugin.js +1 -0
- package/lib/esm/frustration-plugin.js.map +1 -1
- package/lib/esm/version.d.ts +1 -1
- package/lib/esm/version.js +1 -1
- package/lib/esm/version.js.map +1 -1
- package/lib/scripts/amplitude-min.js +1 -1
- package/lib/scripts/amplitude-min.js.gz +0 -0
- package/lib/scripts/amplitude-min.js.map +1 -1
- package/lib/scripts/amplitude-min.umd.js +1 -1
- package/lib/scripts/amplitude-min.umd.js.gz +0 -0
- package/lib/scripts/autocapture/track-rage-click.d.ts +0 -1
- package/lib/scripts/autocapture/track-rage-click.d.ts.map +1 -1
- package/lib/scripts/frustration-plugin.d.ts +1 -1
- package/lib/scripts/frustration-plugin.d.ts.map +1 -1
- package/lib/scripts/version.d.ts +1 -1
- package/package.json +3 -3
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { AllWindowObservables } from 'src/autocapture-plugin';
|
|
2
2
|
import { BrowserClient } from '@amplitude/analytics-core';
|
|
3
3
|
import { shouldTrackEvent } from '../helpers';
|
|
4
|
-
export declare function _overrideRageClickConfig(rageClickThreshold: number, rageClickWindowMs: number): void;
|
|
5
4
|
export declare function trackRageClicks({ amplitude, allObservables, shouldTrackRageClick, }: {
|
|
6
5
|
amplitude: BrowserClient;
|
|
7
6
|
allObservables: AllWindowObservables;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"track-rage-click.d.ts","sourceRoot":"","sources":["../../../src/autocapture/track-rage-click.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAA+B,gBAAgB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"track-rage-click.d.ts","sourceRoot":"","sources":["../../../src/autocapture/track-rage-click.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAA+B,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA4B3E,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,cAAc,EACd,oBAAoB,GACrB,EAAE;IACD,SAAS,EAAE,aAAa,CAAC;IACzB,cAAc,EAAE,oBAAoB,CAAC;IACrC,oBAAoB,EAAE,gBAAgB,CAAC;CACxC,+BAyEA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.trackRageClicks =
|
|
3
|
+
exports.trackRageClicks = void 0;
|
|
4
4
|
var tslib_1 = require("tslib");
|
|
5
5
|
var rxjs_1 = require("rxjs");
|
|
6
6
|
var helpers_1 = require("../helpers");
|
|
@@ -8,47 +8,55 @@ var constants_1 = require("../constants");
|
|
|
8
8
|
var analytics_core_1 = require("@amplitude/analytics-core");
|
|
9
9
|
var RAGE_CLICK_THRESHOLD = analytics_core_1.DEFAULT_RAGE_CLICK_THRESHOLD;
|
|
10
10
|
var RAGE_CLICK_WINDOW_MS = analytics_core_1.DEFAULT_RAGE_CLICK_WINDOW_MS;
|
|
11
|
-
// allow override of rage click config for testing only
|
|
12
|
-
function _overrideRageClickConfig(rageClickThreshold, rageClickWindowMs) {
|
|
13
|
-
RAGE_CLICK_THRESHOLD = rageClickThreshold;
|
|
14
|
-
RAGE_CLICK_WINDOW_MS = rageClickWindowMs;
|
|
15
|
-
}
|
|
16
|
-
exports._overrideRageClickConfig = _overrideRageClickConfig;
|
|
17
11
|
function trackRageClicks(_a) {
|
|
18
12
|
var amplitude = _a.amplitude, allObservables = _a.allObservables, shouldTrackRageClick = _a.shouldTrackRageClick;
|
|
19
13
|
var clickObservable = allObservables.clickObservable;
|
|
20
|
-
//
|
|
21
|
-
var
|
|
14
|
+
// Keep track of all clicks within the sliding window
|
|
15
|
+
var clickWindow = [];
|
|
16
|
+
return clickObservable
|
|
17
|
+
.pipe((0, rxjs_1.filter)(helpers_1.filterOutNonTrackableEvents), (0, rxjs_1.filter)(function (click) {
|
|
22
18
|
return shouldTrackRageClick('click', click.closestTrackedAncestor);
|
|
23
|
-
}), (0, rxjs_1.
|
|
24
|
-
|
|
25
|
-
if
|
|
26
|
-
|
|
19
|
+
}), (0, rxjs_1.map)(function (click) {
|
|
20
|
+
var now = click.timestamp;
|
|
21
|
+
// if the current click isn't on the same element as the most recent click,
|
|
22
|
+
// clear the sliding window and start over
|
|
23
|
+
if (clickWindow.length > 0 &&
|
|
24
|
+
clickWindow[clickWindow.length - 1].closestTrackedAncestor !== click.closestTrackedAncestor) {
|
|
25
|
+
clickWindow.splice(0, clickWindow.length);
|
|
27
26
|
}
|
|
28
|
-
//
|
|
29
|
-
var
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return false;
|
|
27
|
+
// remove past clicks that are outside the sliding window
|
|
28
|
+
var clickPtr = 0;
|
|
29
|
+
for (; clickPtr < clickWindow.length; clickPtr++) {
|
|
30
|
+
if (now - clickWindow[clickPtr].timestamp < RAGE_CLICK_WINDOW_MS) {
|
|
31
|
+
break;
|
|
34
32
|
}
|
|
35
33
|
}
|
|
36
|
-
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
clickWindow.splice(0, clickPtr);
|
|
35
|
+
// add the current click to the window
|
|
36
|
+
clickWindow.push(click);
|
|
37
|
+
// if there's not enough clicks to be a rage click, return null
|
|
38
|
+
if (clickWindow.length < RAGE_CLICK_THRESHOLD) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
// if we've made it here, we have enough trailing clicks on the same element
|
|
42
|
+
// for it to be a rage click
|
|
43
|
+
var firstClick = clickWindow[0];
|
|
44
|
+
var lastClick = clickWindow[clickWindow.length - 1];
|
|
45
|
+
var rageClickEvent = tslib_1.__assign({ '[Amplitude] Begin Time': new Date(firstClick.timestamp).toISOString(), '[Amplitude] End Time': new Date(lastClick.timestamp).toISOString(), '[Amplitude] Duration': lastClick.timestamp - firstClick.timestamp, '[Amplitude] Clicks': clickWindow.map(function (click) { return ({
|
|
43
46
|
X: click.event.clientX,
|
|
44
47
|
Y: click.event.clientY,
|
|
45
48
|
Time: click.timestamp,
|
|
46
|
-
}); }), '[Amplitude] Click Count':
|
|
49
|
+
}); }), '[Amplitude] Click Count': clickWindow.length }, firstClick.targetElementProperties);
|
|
50
|
+
// restart the sliding window
|
|
51
|
+
clickWindow.splice(0, clickWindow.length);
|
|
47
52
|
return { rageClickEvent: rageClickEvent, time: firstClick.timestamp };
|
|
48
|
-
}));
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
}), (0, rxjs_1.filter)(function (result) { return result !== null; }))
|
|
54
|
+
.subscribe(function (data) {
|
|
55
|
+
/* istanbul ignore if */
|
|
56
|
+
if (data === null) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
amplitude.track(constants_1.AMPLITUDE_ELEMENT_RAGE_CLICKED_EVENT, data.rageClickEvent, { time: data.time });
|
|
52
60
|
});
|
|
53
61
|
}
|
|
54
62
|
exports.trackRageClicks = trackRageClicks;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"track-rage-click.js","sourceRoot":"","sources":["../../../src/autocapture/track-rage-click.ts"],"names":[],"mappings":";;;;AACA,
|
|
1
|
+
{"version":3,"file":"track-rage-click.js","sourceRoot":"","sources":["../../../src/autocapture/track-rage-click.ts"],"names":[],"mappings":"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","sourcesContent":["import { AllWindowObservables } from 'src/autocapture-plugin';\nimport { filter, map } from 'rxjs';\nimport { BrowserClient } from '@amplitude/analytics-core';\nimport { filterOutNonTrackableEvents, shouldTrackEvent } from '../helpers';\nimport { AMPLITUDE_ELEMENT_RAGE_CLICKED_EVENT } from '../constants';\nimport { DEFAULT_RAGE_CLICK_THRESHOLD, DEFAULT_RAGE_CLICK_WINDOW_MS } from '@amplitude/analytics-core';\n\nconst RAGE_CLICK_THRESHOLD = DEFAULT_RAGE_CLICK_THRESHOLD;\nconst RAGE_CLICK_WINDOW_MS = DEFAULT_RAGE_CLICK_WINDOW_MS;\n\ntype Click = {\n X: number;\n Y: number;\n Time: number;\n};\n\ntype EventRageClick = {\n '[Amplitude] Begin Time': string; // ISO-8601\n '[Amplitude] End Time': string; // ISO-8601\n '[Amplitude] Duration': number;\n '[Amplitude] Clicks': Array<Click>;\n '[Amplitude] Click Count': number;\n};\n\ntype ClickEvent = {\n event: MouseEvent | Event;\n timestamp: number;\n targetElementProperties: Record<string, any>;\n closestTrackedAncestor: Element | null;\n};\n\nexport function trackRageClicks({\n amplitude,\n allObservables,\n shouldTrackRageClick,\n}: {\n amplitude: BrowserClient;\n allObservables: AllWindowObservables;\n shouldTrackRageClick: shouldTrackEvent;\n}) {\n const { clickObservable } = allObservables;\n\n // Keep track of all clicks within the sliding window\n const clickWindow: ClickEvent[] = [];\n\n return clickObservable\n .pipe(\n filter(filterOutNonTrackableEvents),\n filter((click) => {\n return shouldTrackRageClick('click', click.closestTrackedAncestor);\n }),\n map((click) => {\n const now = click.timestamp;\n\n // if the current click isn't on the same element as the most recent click,\n // clear the sliding window and start over\n if (\n clickWindow.length > 0 &&\n clickWindow[clickWindow.length - 1].closestTrackedAncestor !== click.closestTrackedAncestor\n ) {\n clickWindow.splice(0, clickWindow.length);\n }\n\n // remove past clicks that are outside the sliding window\n let clickPtr = 0;\n for (; clickPtr < clickWindow.length; clickPtr++) {\n if (now - clickWindow[clickPtr].timestamp < RAGE_CLICK_WINDOW_MS) {\n break;\n }\n }\n clickWindow.splice(0, clickPtr);\n\n // add the current click to the window\n clickWindow.push(click);\n\n // if there's not enough clicks to be a rage click, return null\n if (clickWindow.length < RAGE_CLICK_THRESHOLD) {\n return null;\n }\n\n // if we've made it here, we have enough trailing clicks on the same element\n // for it to be a rage click\n const firstClick = clickWindow[0];\n const lastClick = clickWindow[clickWindow.length - 1];\n\n const rageClickEvent: EventRageClick = {\n '[Amplitude] Begin Time': new Date(firstClick.timestamp).toISOString(),\n '[Amplitude] End Time': new Date(lastClick.timestamp).toISOString(),\n '[Amplitude] Duration': lastClick.timestamp - firstClick.timestamp,\n '[Amplitude] Clicks': clickWindow.map((click) => ({\n X: (click.event as MouseEvent).clientX,\n Y: (click.event as MouseEvent).clientY,\n Time: click.timestamp,\n })),\n '[Amplitude] Click Count': clickWindow.length,\n ...firstClick.targetElementProperties,\n };\n\n // restart the sliding window\n clickWindow.splice(0, clickWindow.length);\n\n return { rageClickEvent, time: firstClick.timestamp };\n }),\n filter((result) => result !== null),\n )\n .subscribe((data: { rageClickEvent: EventRageClick; time: number } | null) => {\n /* istanbul ignore if */\n if (data === null) {\n return;\n }\n amplitude.track(AMPLITUDE_ELEMENT_RAGE_CLICKED_EVENT, data.rageClickEvent, { time: data.time });\n });\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BrowserClient, BrowserConfig, EnrichmentPlugin, FrustrationInteractionsOptions } from '@amplitude/analytics-core';
|
|
2
2
|
type BrowserEnrichmentPlugin = EnrichmentPlugin<BrowserClient, BrowserConfig>;
|
|
3
|
-
export declare const frustrationPlugin: (options
|
|
3
|
+
export declare const frustrationPlugin: (options?: FrustrationInteractionsOptions) => BrowserEnrichmentPlugin;
|
|
4
4
|
export {};
|
|
5
5
|
//# sourceMappingURL=frustration-plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frustration-plugin.d.ts","sourceRoot":"","sources":["../../src/frustration-plugin.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,8BAA8B,EAI/B,MAAM,2BAA2B,CAAC;AAenC,KAAK,uBAAuB,GAAG,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AAE9E,eAAO,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"frustration-plugin.d.ts","sourceRoot":"","sources":["../../src/frustration-plugin.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,8BAA8B,EAI/B,MAAM,2BAA2B,CAAC;AAenC,KAAK,uBAAuB,GAAG,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AAE9E,eAAO,MAAM,iBAAiB,aAAa,8BAA8B,KAAQ,uBA0GhF,CAAC"}
|
|
@@ -13,6 +13,7 @@ var autocapture_plugin_1 = require("./autocapture-plugin");
|
|
|
13
13
|
var observables_1 = require("./observables");
|
|
14
14
|
var frustrationPlugin = function (options) {
|
|
15
15
|
var _a, _b, _c, _d, _e;
|
|
16
|
+
if (options === void 0) { options = {}; }
|
|
16
17
|
var name = constants.FRUSTRATION_PLUGIN_NAME;
|
|
17
18
|
var type = 'enrichment';
|
|
18
19
|
var subscriptions = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frustration-plugin.js","sourceRoot":"","sources":["../../src/frustration-plugin.ts"],"names":[],"mappings":";;;;AAAA,0CAA0C;AAC1C,4DAQmC;AACnC,6DAAyC;AACzC,6BAAuE;AACvE,qCAMmB;AACnB,mEAAgE;AAChE,mEAAiE;AACjE,2DAA6E;AAC7E,6CAAgF;AAIzE,IAAM,iBAAiB,GAAG,UAAC,
|
|
1
|
+
{"version":3,"file":"frustration-plugin.js","sourceRoot":"","sources":["../../src/frustration-plugin.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable no-restricted-globals */\nimport {\n BrowserClient,\n BrowserConfig,\n EnrichmentPlugin,\n FrustrationInteractionsOptions,\n DEFAULT_DATA_ATTRIBUTE_PREFIX,\n DEFAULT_RAGE_CLICK_ALLOWLIST,\n DEFAULT_DEAD_CLICK_ALLOWLIST,\n} from '@amplitude/analytics-core';\nimport * as constants from './constants';\nimport { fromEvent, map, Observable, Subscription, share } from 'rxjs';\nimport {\n addAdditionalEventProperties,\n createShouldTrackEvent,\n ElementBasedTimestampedEvent,\n getEventProperties,\n NavigateEvent,\n} from './helpers';\nimport { trackDeadClick } from './autocapture/track-dead-click';\nimport { trackRageClicks } from './autocapture/track-rage-click';\nimport { AllWindowObservables, ObservablesEnum } from './autocapture-plugin';\nimport { createClickObservable, createMutationObservable } from './observables';\n\ntype BrowserEnrichmentPlugin = EnrichmentPlugin<BrowserClient, BrowserConfig>;\n\nexport const frustrationPlugin = (options: FrustrationInteractionsOptions = {}): BrowserEnrichmentPlugin => {\n const name = constants.FRUSTRATION_PLUGIN_NAME;\n const type = 'enrichment';\n\n const subscriptions: Subscription[] = [];\n\n const rageCssSelectors = options.rageClicks?.cssSelectorAllowlist ?? DEFAULT_RAGE_CLICK_ALLOWLIST;\n const deadCssSelectors = options.deadClicks?.cssSelectorAllowlist ?? DEFAULT_DEAD_CLICK_ALLOWLIST;\n\n const dataAttributePrefix = options.dataAttributePrefix ?? DEFAULT_DATA_ATTRIBUTE_PREFIX;\n\n // combine the two selector lists to determine which clicked elements should be filtered\n const combinedCssSelectors = [...new Set([...rageCssSelectors, ...deadCssSelectors])];\n\n // Create observables on events on the window\n const createObservables = (): AllWindowObservables => {\n // Create Observables from direct user events\n const clickObservable = createClickObservable().pipe(\n map((click) => {\n return addAdditionalEventProperties(\n click,\n 'click',\n combinedCssSelectors,\n dataAttributePrefix,\n true, // capture when cursor is pointer\n );\n }),\n share(),\n );\n\n // Create observable for URL changes\n let navigateObservable;\n /* istanbul ignore next */\n if (window.navigation) {\n navigateObservable = fromEvent<NavigateEvent>(window.navigation, 'navigate').pipe(\n map((navigate) =>\n addAdditionalEventProperties(navigate, 'navigate', combinedCssSelectors, dataAttributePrefix),\n ),\n share(),\n );\n }\n\n // Track DOM Mutations\n const enrichedMutationObservable = createMutationObservable().pipe(\n map((mutation) => addAdditionalEventProperties(mutation, 'mutation', combinedCssSelectors, dataAttributePrefix)),\n share(),\n );\n\n return {\n [ObservablesEnum.ClickObservable]: clickObservable as Observable<ElementBasedTimestampedEvent<MouseEvent>>,\n [ObservablesEnum.ChangeObservable]: new Observable<ElementBasedTimestampedEvent<Event>>(), // Empty observable since we don't need change events\n [ObservablesEnum.NavigateObservable]: navigateObservable,\n [ObservablesEnum.MutationObservable]: enrichedMutationObservable,\n };\n };\n\n const setup: BrowserEnrichmentPlugin['setup'] = async (config, amplitude) => {\n /* istanbul ignore if */\n if (typeof document === 'undefined') {\n return;\n }\n\n // Create should track event functions for the different allowlists\n const shouldTrackRageClick = createShouldTrackEvent(options, rageCssSelectors);\n const shouldTrackDeadClick = createShouldTrackEvent(options, deadCssSelectors);\n\n // Create observables for events on the window\n const allObservables = createObservables();\n\n // Create subscriptions\n const rageClickSubscription = trackRageClicks({\n allObservables,\n amplitude,\n shouldTrackRageClick,\n });\n subscriptions.push(rageClickSubscription);\n\n const deadClickSubscription = trackDeadClick({\n amplitude,\n allObservables,\n getEventProperties: (actionType, element) => getEventProperties(actionType, element, dataAttributePrefix),\n shouldTrackDeadClick,\n });\n subscriptions.push(deadClickSubscription);\n\n /* istanbul ignore next */\n config?.loggerProvider?.log(`${name} has been successfully added.`);\n };\n\n const execute: BrowserEnrichmentPlugin['execute'] = async (event) => {\n return event;\n };\n\n const teardown = async () => {\n for (const subscription of subscriptions) {\n subscription.unsubscribe();\n }\n };\n\n return {\n name,\n type,\n setup,\n execute,\n teardown,\n };\n};\n"]}
|
package/lib/cjs/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "1.
|
|
1
|
+
export declare const VERSION = "1.7.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/lib/cjs/version.js
CHANGED
package/lib/cjs/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":";;;AAAa,QAAA,OAAO,GAAG,OAAO,CAAC","sourcesContent":["export const VERSION = '1.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":";;;AAAa,QAAA,OAAO,GAAG,OAAO,CAAC","sourcesContent":["export const VERSION = '1.7.0';\n"]}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { AllWindowObservables } from 'src/autocapture-plugin';
|
|
2
2
|
import { BrowserClient } from '@amplitude/analytics-core';
|
|
3
3
|
import { shouldTrackEvent } from '../helpers';
|
|
4
|
-
export declare function _overrideRageClickConfig(rageClickThreshold: number, rageClickWindowMs: number): void;
|
|
5
4
|
export declare function trackRageClicks({ amplitude, allObservables, shouldTrackRageClick, }: {
|
|
6
5
|
amplitude: BrowserClient;
|
|
7
6
|
allObservables: AllWindowObservables;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"track-rage-click.d.ts","sourceRoot":"","sources":["../../../src/autocapture/track-rage-click.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAA+B,gBAAgB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"track-rage-click.d.ts","sourceRoot":"","sources":["../../../src/autocapture/track-rage-click.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAA+B,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA4B3E,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,cAAc,EACd,oBAAoB,GACrB,EAAE;IACD,SAAS,EAAE,aAAa,CAAC;IACzB,cAAc,EAAE,oBAAoB,CAAC;IACrC,oBAAoB,EAAE,gBAAgB,CAAC;CACxC,+BAyEA"}
|
|
@@ -1,50 +1,59 @@
|
|
|
1
1
|
import { __assign } from "tslib";
|
|
2
|
-
import { filter, map
|
|
2
|
+
import { filter, map } from 'rxjs';
|
|
3
3
|
import { filterOutNonTrackableEvents } from '../helpers';
|
|
4
4
|
import { AMPLITUDE_ELEMENT_RAGE_CLICKED_EVENT } from '../constants';
|
|
5
5
|
import { DEFAULT_RAGE_CLICK_THRESHOLD, DEFAULT_RAGE_CLICK_WINDOW_MS } from '@amplitude/analytics-core';
|
|
6
6
|
var RAGE_CLICK_THRESHOLD = DEFAULT_RAGE_CLICK_THRESHOLD;
|
|
7
7
|
var RAGE_CLICK_WINDOW_MS = DEFAULT_RAGE_CLICK_WINDOW_MS;
|
|
8
|
-
// allow override of rage click config for testing only
|
|
9
|
-
export function _overrideRageClickConfig(rageClickThreshold, rageClickWindowMs) {
|
|
10
|
-
RAGE_CLICK_THRESHOLD = rageClickThreshold;
|
|
11
|
-
RAGE_CLICK_WINDOW_MS = rageClickWindowMs;
|
|
12
|
-
}
|
|
13
8
|
export function trackRageClicks(_a) {
|
|
14
9
|
var amplitude = _a.amplitude, allObservables = _a.allObservables, shouldTrackRageClick = _a.shouldTrackRageClick;
|
|
15
10
|
var clickObservable = allObservables.clickObservable;
|
|
16
|
-
//
|
|
17
|
-
var
|
|
11
|
+
// Keep track of all clicks within the sliding window
|
|
12
|
+
var clickWindow = [];
|
|
13
|
+
return clickObservable
|
|
14
|
+
.pipe(filter(filterOutNonTrackableEvents), filter(function (click) {
|
|
18
15
|
return shouldTrackRageClick('click', click.closestTrackedAncestor);
|
|
19
|
-
}),
|
|
20
|
-
|
|
21
|
-
if
|
|
22
|
-
|
|
16
|
+
}), map(function (click) {
|
|
17
|
+
var now = click.timestamp;
|
|
18
|
+
// if the current click isn't on the same element as the most recent click,
|
|
19
|
+
// clear the sliding window and start over
|
|
20
|
+
if (clickWindow.length > 0 &&
|
|
21
|
+
clickWindow[clickWindow.length - 1].closestTrackedAncestor !== click.closestTrackedAncestor) {
|
|
22
|
+
clickWindow.splice(0, clickWindow.length);
|
|
23
23
|
}
|
|
24
|
-
//
|
|
25
|
-
var
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return false;
|
|
24
|
+
// remove past clicks that are outside the sliding window
|
|
25
|
+
var clickPtr = 0;
|
|
26
|
+
for (; clickPtr < clickWindow.length; clickPtr++) {
|
|
27
|
+
if (now - clickWindow[clickPtr].timestamp < RAGE_CLICK_WINDOW_MS) {
|
|
28
|
+
break;
|
|
30
29
|
}
|
|
31
30
|
}
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
clickWindow.splice(0, clickPtr);
|
|
32
|
+
// add the current click to the window
|
|
33
|
+
clickWindow.push(click);
|
|
34
|
+
// if there's not enough clicks to be a rage click, return null
|
|
35
|
+
if (clickWindow.length < RAGE_CLICK_THRESHOLD) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
// if we've made it here, we have enough trailing clicks on the same element
|
|
39
|
+
// for it to be a rage click
|
|
40
|
+
var firstClick = clickWindow[0];
|
|
41
|
+
var lastClick = clickWindow[clickWindow.length - 1];
|
|
42
|
+
var rageClickEvent = __assign({ '[Amplitude] Begin Time': new Date(firstClick.timestamp).toISOString(), '[Amplitude] End Time': new Date(lastClick.timestamp).toISOString(), '[Amplitude] Duration': lastClick.timestamp - firstClick.timestamp, '[Amplitude] Clicks': clickWindow.map(function (click) { return ({
|
|
39
43
|
X: click.event.clientX,
|
|
40
44
|
Y: click.event.clientY,
|
|
41
45
|
Time: click.timestamp,
|
|
42
|
-
}); }), '[Amplitude] Click Count':
|
|
46
|
+
}); }), '[Amplitude] Click Count': clickWindow.length }, firstClick.targetElementProperties);
|
|
47
|
+
// restart the sliding window
|
|
48
|
+
clickWindow.splice(0, clickWindow.length);
|
|
43
49
|
return { rageClickEvent: rageClickEvent, time: firstClick.timestamp };
|
|
44
|
-
}));
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
}), filter(function (result) { return result !== null; }))
|
|
51
|
+
.subscribe(function (data) {
|
|
52
|
+
/* istanbul ignore if */
|
|
53
|
+
if (data === null) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
amplitude.track(AMPLITUDE_ELEMENT_RAGE_CLICKED_EVENT, data.rageClickEvent, { time: data.time });
|
|
48
57
|
});
|
|
49
58
|
}
|
|
50
59
|
//# sourceMappingURL=track-rage-click.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"track-rage-click.js","sourceRoot":"","sources":["../../../src/autocapture/track-rage-click.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"track-rage-click.js","sourceRoot":"","sources":["../../../src/autocapture/track-rage-click.ts"],"names":[],"mappings":"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","sourcesContent":["import { AllWindowObservables } from 'src/autocapture-plugin';\nimport { filter, map } from 'rxjs';\nimport { BrowserClient } from '@amplitude/analytics-core';\nimport { filterOutNonTrackableEvents, shouldTrackEvent } from '../helpers';\nimport { AMPLITUDE_ELEMENT_RAGE_CLICKED_EVENT } from '../constants';\nimport { DEFAULT_RAGE_CLICK_THRESHOLD, DEFAULT_RAGE_CLICK_WINDOW_MS } from '@amplitude/analytics-core';\n\nconst RAGE_CLICK_THRESHOLD = DEFAULT_RAGE_CLICK_THRESHOLD;\nconst RAGE_CLICK_WINDOW_MS = DEFAULT_RAGE_CLICK_WINDOW_MS;\n\ntype Click = {\n X: number;\n Y: number;\n Time: number;\n};\n\ntype EventRageClick = {\n '[Amplitude] Begin Time': string; // ISO-8601\n '[Amplitude] End Time': string; // ISO-8601\n '[Amplitude] Duration': number;\n '[Amplitude] Clicks': Array<Click>;\n '[Amplitude] Click Count': number;\n};\n\ntype ClickEvent = {\n event: MouseEvent | Event;\n timestamp: number;\n targetElementProperties: Record<string, any>;\n closestTrackedAncestor: Element | null;\n};\n\nexport function trackRageClicks({\n amplitude,\n allObservables,\n shouldTrackRageClick,\n}: {\n amplitude: BrowserClient;\n allObservables: AllWindowObservables;\n shouldTrackRageClick: shouldTrackEvent;\n}) {\n const { clickObservable } = allObservables;\n\n // Keep track of all clicks within the sliding window\n const clickWindow: ClickEvent[] = [];\n\n return clickObservable\n .pipe(\n filter(filterOutNonTrackableEvents),\n filter((click) => {\n return shouldTrackRageClick('click', click.closestTrackedAncestor);\n }),\n map((click) => {\n const now = click.timestamp;\n\n // if the current click isn't on the same element as the most recent click,\n // clear the sliding window and start over\n if (\n clickWindow.length > 0 &&\n clickWindow[clickWindow.length - 1].closestTrackedAncestor !== click.closestTrackedAncestor\n ) {\n clickWindow.splice(0, clickWindow.length);\n }\n\n // remove past clicks that are outside the sliding window\n let clickPtr = 0;\n for (; clickPtr < clickWindow.length; clickPtr++) {\n if (now - clickWindow[clickPtr].timestamp < RAGE_CLICK_WINDOW_MS) {\n break;\n }\n }\n clickWindow.splice(0, clickPtr);\n\n // add the current click to the window\n clickWindow.push(click);\n\n // if there's not enough clicks to be a rage click, return null\n if (clickWindow.length < RAGE_CLICK_THRESHOLD) {\n return null;\n }\n\n // if we've made it here, we have enough trailing clicks on the same element\n // for it to be a rage click\n const firstClick = clickWindow[0];\n const lastClick = clickWindow[clickWindow.length - 1];\n\n const rageClickEvent: EventRageClick = {\n '[Amplitude] Begin Time': new Date(firstClick.timestamp).toISOString(),\n '[Amplitude] End Time': new Date(lastClick.timestamp).toISOString(),\n '[Amplitude] Duration': lastClick.timestamp - firstClick.timestamp,\n '[Amplitude] Clicks': clickWindow.map((click) => ({\n X: (click.event as MouseEvent).clientX,\n Y: (click.event as MouseEvent).clientY,\n Time: click.timestamp,\n })),\n '[Amplitude] Click Count': clickWindow.length,\n ...firstClick.targetElementProperties,\n };\n\n // restart the sliding window\n clickWindow.splice(0, clickWindow.length);\n\n return { rageClickEvent, time: firstClick.timestamp };\n }),\n filter((result) => result !== null),\n )\n .subscribe((data: { rageClickEvent: EventRageClick; time: number } | null) => {\n /* istanbul ignore if */\n if (data === null) {\n return;\n }\n amplitude.track(AMPLITUDE_ELEMENT_RAGE_CLICKED_EVENT, data.rageClickEvent, { time: data.time });\n });\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BrowserClient, BrowserConfig, EnrichmentPlugin, FrustrationInteractionsOptions } from '@amplitude/analytics-core';
|
|
2
2
|
type BrowserEnrichmentPlugin = EnrichmentPlugin<BrowserClient, BrowserConfig>;
|
|
3
|
-
export declare const frustrationPlugin: (options
|
|
3
|
+
export declare const frustrationPlugin: (options?: FrustrationInteractionsOptions) => BrowserEnrichmentPlugin;
|
|
4
4
|
export {};
|
|
5
5
|
//# sourceMappingURL=frustration-plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frustration-plugin.d.ts","sourceRoot":"","sources":["../../src/frustration-plugin.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,8BAA8B,EAI/B,MAAM,2BAA2B,CAAC;AAenC,KAAK,uBAAuB,GAAG,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AAE9E,eAAO,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"frustration-plugin.d.ts","sourceRoot":"","sources":["../../src/frustration-plugin.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,8BAA8B,EAI/B,MAAM,2BAA2B,CAAC;AAenC,KAAK,uBAAuB,GAAG,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AAE9E,eAAO,MAAM,iBAAiB,aAAa,8BAA8B,KAAQ,uBA0GhF,CAAC"}
|
|
@@ -10,6 +10,7 @@ import { ObservablesEnum } from './autocapture-plugin';
|
|
|
10
10
|
import { createClickObservable, createMutationObservable } from './observables';
|
|
11
11
|
export var frustrationPlugin = function (options) {
|
|
12
12
|
var _a, _b, _c, _d, _e;
|
|
13
|
+
if (options === void 0) { options = {}; }
|
|
13
14
|
var name = constants.FRUSTRATION_PLUGIN_NAME;
|
|
14
15
|
var type = 'enrichment';
|
|
15
16
|
var subscriptions = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frustration-plugin.js","sourceRoot":"","sources":["../../src/frustration-plugin.ts"],"names":[],"mappings":";AAAA,0CAA0C;AAC1C,OAAO,EAKL,6BAA6B,EAC7B,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,SAAS,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAgB,KAAK,EAAE,MAAM,MAAM,CAAC;AACvE,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EAEtB,kBAAkB,GAEnB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAwB,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAIhF,MAAM,CAAC,IAAM,iBAAiB,GAAG,UAAC,
|
|
1
|
+
{"version":3,"file":"frustration-plugin.js","sourceRoot":"","sources":["../../src/frustration-plugin.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable no-restricted-globals */\nimport {\n BrowserClient,\n BrowserConfig,\n EnrichmentPlugin,\n FrustrationInteractionsOptions,\n DEFAULT_DATA_ATTRIBUTE_PREFIX,\n DEFAULT_RAGE_CLICK_ALLOWLIST,\n DEFAULT_DEAD_CLICK_ALLOWLIST,\n} from '@amplitude/analytics-core';\nimport * as constants from './constants';\nimport { fromEvent, map, Observable, Subscription, share } from 'rxjs';\nimport {\n addAdditionalEventProperties,\n createShouldTrackEvent,\n ElementBasedTimestampedEvent,\n getEventProperties,\n NavigateEvent,\n} from './helpers';\nimport { trackDeadClick } from './autocapture/track-dead-click';\nimport { trackRageClicks } from './autocapture/track-rage-click';\nimport { AllWindowObservables, ObservablesEnum } from './autocapture-plugin';\nimport { createClickObservable, createMutationObservable } from './observables';\n\ntype BrowserEnrichmentPlugin = EnrichmentPlugin<BrowserClient, BrowserConfig>;\n\nexport const frustrationPlugin = (options: FrustrationInteractionsOptions = {}): BrowserEnrichmentPlugin => {\n const name = constants.FRUSTRATION_PLUGIN_NAME;\n const type = 'enrichment';\n\n const subscriptions: Subscription[] = [];\n\n const rageCssSelectors = options.rageClicks?.cssSelectorAllowlist ?? DEFAULT_RAGE_CLICK_ALLOWLIST;\n const deadCssSelectors = options.deadClicks?.cssSelectorAllowlist ?? DEFAULT_DEAD_CLICK_ALLOWLIST;\n\n const dataAttributePrefix = options.dataAttributePrefix ?? DEFAULT_DATA_ATTRIBUTE_PREFIX;\n\n // combine the two selector lists to determine which clicked elements should be filtered\n const combinedCssSelectors = [...new Set([...rageCssSelectors, ...deadCssSelectors])];\n\n // Create observables on events on the window\n const createObservables = (): AllWindowObservables => {\n // Create Observables from direct user events\n const clickObservable = createClickObservable().pipe(\n map((click) => {\n return addAdditionalEventProperties(\n click,\n 'click',\n combinedCssSelectors,\n dataAttributePrefix,\n true, // capture when cursor is pointer\n );\n }),\n share(),\n );\n\n // Create observable for URL changes\n let navigateObservable;\n /* istanbul ignore next */\n if (window.navigation) {\n navigateObservable = fromEvent<NavigateEvent>(window.navigation, 'navigate').pipe(\n map((navigate) =>\n addAdditionalEventProperties(navigate, 'navigate', combinedCssSelectors, dataAttributePrefix),\n ),\n share(),\n );\n }\n\n // Track DOM Mutations\n const enrichedMutationObservable = createMutationObservable().pipe(\n map((mutation) => addAdditionalEventProperties(mutation, 'mutation', combinedCssSelectors, dataAttributePrefix)),\n share(),\n );\n\n return {\n [ObservablesEnum.ClickObservable]: clickObservable as Observable<ElementBasedTimestampedEvent<MouseEvent>>,\n [ObservablesEnum.ChangeObservable]: new Observable<ElementBasedTimestampedEvent<Event>>(), // Empty observable since we don't need change events\n [ObservablesEnum.NavigateObservable]: navigateObservable,\n [ObservablesEnum.MutationObservable]: enrichedMutationObservable,\n };\n };\n\n const setup: BrowserEnrichmentPlugin['setup'] = async (config, amplitude) => {\n /* istanbul ignore if */\n if (typeof document === 'undefined') {\n return;\n }\n\n // Create should track event functions for the different allowlists\n const shouldTrackRageClick = createShouldTrackEvent(options, rageCssSelectors);\n const shouldTrackDeadClick = createShouldTrackEvent(options, deadCssSelectors);\n\n // Create observables for events on the window\n const allObservables = createObservables();\n\n // Create subscriptions\n const rageClickSubscription = trackRageClicks({\n allObservables,\n amplitude,\n shouldTrackRageClick,\n });\n subscriptions.push(rageClickSubscription);\n\n const deadClickSubscription = trackDeadClick({\n amplitude,\n allObservables,\n getEventProperties: (actionType, element) => getEventProperties(actionType, element, dataAttributePrefix),\n shouldTrackDeadClick,\n });\n subscriptions.push(deadClickSubscription);\n\n /* istanbul ignore next */\n config?.loggerProvider?.log(`${name} has been successfully added.`);\n };\n\n const execute: BrowserEnrichmentPlugin['execute'] = async (event) => {\n return event;\n };\n\n const teardown = async () => {\n for (const subscription of subscriptions) {\n subscription.unsubscribe();\n }\n };\n\n return {\n name,\n type,\n setup,\n execute,\n teardown,\n };\n};\n"]}
|
package/lib/esm/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "1.
|
|
1
|
+
export declare const VERSION = "1.7.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/lib/esm/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export var VERSION = '1.
|
|
1
|
+
export var VERSION = '1.7.0';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
package/lib/esm/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,IAAM,OAAO,GAAG,OAAO,CAAC","sourcesContent":["export const VERSION = '1.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,IAAM,OAAO,GAAG,OAAO,CAAC","sourcesContent":["export const VERSION = '1.7.0';\n"]}
|