@statsig/web-analytics 3.20.2 → 3.20.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statsig/web-analytics",
3
- "version": "3.20.2",
3
+ "version": "3.20.4",
4
4
  "license": "ISC",
5
5
  "homepage": "https://github.com/statsig-io/js-client-monorepo",
6
6
  "repository": {
@@ -9,8 +9,8 @@
9
9
  "directory": "packages/web-analytics"
10
10
  },
11
11
  "dependencies": {
12
- "@statsig/client-core": "3.20.2",
13
- "@statsig/js-client": "3.20.2",
12
+ "@statsig/client-core": "3.20.4",
13
+ "@statsig/js-client": "3.20.4",
14
14
  "web-vitals": "5.0.3"
15
15
  },
16
16
  "jsdelivr": "./build/statsig-web-analytics.min.js",
@@ -21,6 +21,7 @@ export declare class AutoCapture {
21
21
  private _rageClickManager;
22
22
  private _pageViewLogged;
23
23
  private _webVitalsManager;
24
+ private _deadClickManager;
24
25
  constructor(_client: PrecomputedEvaluationsInterface, options?: AutoCaptureOptions);
25
26
  private _addEventHandlers;
26
27
  private _addPageViewTracking;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AutoCapture = exports.runStatsigAutoCapture = exports.StatsigAutoCapturePlugin = void 0;
4
4
  const client_core_1 = require("@statsig/client-core");
5
5
  const AutoCaptureEvent_1 = require("./AutoCaptureEvent");
6
+ const DeadClickManager_1 = require("./DeadClickManager");
6
7
  const EngagementManager_1 = require("./EngagementManager");
7
8
  const RageClickManager_1 = require("./RageClickManager");
8
9
  const WebVitalsManager_1 = require("./WebVitalsManager");
@@ -12,6 +13,8 @@ const metadataUtils_1 = require("./utils/metadataUtils");
12
13
  const AUTO_EVENT_MAPPING = {
13
14
  submit: AutoCaptureEvent_1.AutoCaptureEventName.FORM_SUBMIT,
14
15
  click: AutoCaptureEvent_1.AutoCaptureEventName.CLICK,
16
+ copy: AutoCaptureEvent_1.AutoCaptureEventName.COPY,
17
+ cut: AutoCaptureEvent_1.AutoCaptureEventName.COPY,
15
18
  };
16
19
  class StatsigAutoCapturePlugin {
17
20
  constructor(_options) {
@@ -57,6 +60,7 @@ class AutoCapture {
57
60
  this._engagementManager = new EngagementManager_1.EngagementManager();
58
61
  this._rageClickManager = new RageClickManager_1.default();
59
62
  this._webVitalsManager = new WebVitalsManager_1.WebVitalsManager(this._enqueueAutoCapture.bind(this));
63
+ this._deadClickManager = new DeadClickManager_1.default(this._enqueueAutoCapture.bind(this));
60
64
  this._eventFilterFunc = options === null || options === void 0 ? void 0 : options.eventFilterFunc;
61
65
  const doc = (0, client_core_1._getDocumentSafe)();
62
66
  if (!(0, client_core_1._isServerEnv)()) {
@@ -93,6 +97,8 @@ class AutoCapture {
93
97
  };
94
98
  (0, commonUtils_1._registerEventHandler)(doc, 'click', (e) => eventHandler(e));
95
99
  (0, commonUtils_1._registerEventHandler)(doc, 'submit', (e) => eventHandler(e));
100
+ (0, commonUtils_1._registerEventHandler)(doc, 'copy', (e) => eventHandler(e));
101
+ (0, commonUtils_1._registerEventHandler)(doc, 'cut', (e) => eventHandler(e));
96
102
  (0, commonUtils_1._registerEventHandler)(win, 'error', (e) => eventHandler(e, false));
97
103
  (0, commonUtils_1._registerEventHandler)(win, 'pagehide', () => this._tryLogPageViewEnd());
98
104
  (0, commonUtils_1._registerEventHandler)(win, 'beforeunload', () => this._tryLogPageViewEnd());
@@ -113,7 +119,7 @@ class AutoCapture {
113
119
  this._tryLogPageView();
114
120
  }
115
121
  _autoLogEvent(event) {
116
- var _a;
122
+ var _a, _b, _c;
117
123
  const eventType = (_a = event.type) === null || _a === void 0 ? void 0 : _a.toLowerCase();
118
124
  if (eventType === 'error' && event instanceof ErrorEvent) {
119
125
  this._logError(event);
@@ -123,19 +129,32 @@ class AutoCapture {
123
129
  if (!target) {
124
130
  return;
125
131
  }
126
- if (!(0, commonUtils_1._shouldLogEvent)(event, target)) {
127
- return;
128
- }
129
132
  const eventName = AUTO_EVENT_MAPPING[eventType];
130
133
  if (!eventName) {
131
134
  return;
132
135
  }
133
- const { value, metadata } = (0, eventUtils_1._gatherEventData)(target);
136
+ const isCopyEvent = eventName === AutoCaptureEvent_1.AutoCaptureEventName.COPY;
137
+ if (!(0, commonUtils_1._shouldLogEvent)(event, target, isCopyEvent)) {
138
+ return;
139
+ }
140
+ const metadata = {};
141
+ if (isCopyEvent) {
142
+ const selectedText = (_c = (_b = (0, client_core_1._getWindowSafe)()) === null || _b === void 0 ? void 0 : _b.getSelection()) === null || _c === void 0 ? void 0 : _c.toString();
143
+ if (!selectedText) {
144
+ return;
145
+ }
146
+ metadata['selectedText'] = (0, commonUtils_1._sanitizeString)(selectedText);
147
+ const clipType = event.type || 'clipboard';
148
+ metadata['clipType'] = clipType;
149
+ }
150
+ const { value, metadata: eventMetadata } = (0, eventUtils_1._gatherEventData)(target);
151
+ Object.assign(metadata, eventMetadata);
134
152
  const allMetadata = (0, metadataUtils_1._gatherAllMetadata)((0, commonUtils_1._getSafeUrl)());
135
153
  this._enqueueAutoCapture(eventName, value, Object.assign(Object.assign({}, allMetadata), metadata));
136
154
  }
137
155
  _initialize() {
138
156
  this._webVitalsManager.startTracking();
157
+ this._deadClickManager.startTracking();
139
158
  this._engagementManager.startInactivityTracking(() => this._tryLogPageViewEnd(true));
140
159
  this._addEventHandlers();
141
160
  this._addPageViewTracking();
@@ -9,6 +9,8 @@ export declare const AutoCaptureEventName: {
9
9
  readonly CLICK: "auto_capture::click";
10
10
  readonly RAGE_CLICK: "auto_capture::rage_click";
11
11
  readonly WEB_VITALS: "auto_capture::web_vitals";
12
+ readonly DEAD_CLICK: "auto_capture::dead_click";
13
+ readonly COPY: "auto_capture::copy";
12
14
  };
13
15
  export type AutoCaptureEventName = (typeof AutoCaptureEventName)[keyof typeof AutoCaptureEventName] & string;
14
16
  export type AutoCaptureEvent = StatsigEvent & {
@@ -11,4 +11,6 @@ exports.AutoCaptureEventName = {
11
11
  CLICK: 'auto_capture::click',
12
12
  RAGE_CLICK: 'auto_capture::rage_click',
13
13
  WEB_VITALS: 'auto_capture::web_vitals',
14
+ DEAD_CLICK: 'auto_capture::dead_click',
15
+ COPY: 'auto_capture::copy',
14
16
  };
@@ -0,0 +1,34 @@
1
+ import { AutoCaptureEventName } from './AutoCaptureEvent';
2
+ export declare const DeadClickConfig: {
3
+ CLICK_CHECK_TIMEOUT: number;
4
+ SCROLL_DELAY_MS: number;
5
+ SELECTION_CHANGE_DELAY_MS: number;
6
+ MUTATION_DELAY_MS: number;
7
+ ABSOLUTE_DEAD_CLICK_TIMEOUT: number;
8
+ };
9
+ export interface PossibleDeadClick {
10
+ timestamp: number;
11
+ eventTarget: HTMLElement;
12
+ scrollDelayMs?: number;
13
+ selectionChangeDelayMs?: number;
14
+ mutationDelayMs?: number;
15
+ absoluteDelayMs?: number;
16
+ }
17
+ export default class DeadClickManager {
18
+ private _enqueueFn;
19
+ private _lastMutationTime;
20
+ private _lastSelectionChangeTime;
21
+ private _clickCheckTimer;
22
+ private _observer;
23
+ private _clicks;
24
+ private _deadClickConfig;
25
+ constructor(_enqueueFn: (eventName: AutoCaptureEventName, value: string, metadata: Record<string, unknown>) => void);
26
+ startTracking(): void;
27
+ private _handleClick;
28
+ private _handleScroll;
29
+ private _handleSelectionChange;
30
+ private _setupMutationObserver;
31
+ private _checkForDeadClick;
32
+ private _logDeadClick;
33
+ private _updateClickDelayMs;
34
+ }
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DeadClickConfig = void 0;
4
+ const client_core_1 = require("@statsig/client-core");
5
+ const AutoCaptureEvent_1 = require("./AutoCaptureEvent");
6
+ const commonUtils_1 = require("./utils/commonUtils");
7
+ const eventUtils_1 = require("./utils/eventUtils");
8
+ exports.DeadClickConfig = {
9
+ CLICK_CHECK_TIMEOUT: 1000,
10
+ SCROLL_DELAY_MS: 100,
11
+ SELECTION_CHANGE_DELAY_MS: 100,
12
+ MUTATION_DELAY_MS: 2500,
13
+ ABSOLUTE_DEAD_CLICK_TIMEOUT: 2750,
14
+ };
15
+ // A dead click is a click that fires an event but produces no meaningful change within a set timeframe.
16
+ class DeadClickManager {
17
+ constructor(_enqueueFn) {
18
+ this._enqueueFn = _enqueueFn;
19
+ this._lastMutationTime = 0;
20
+ this._lastSelectionChangeTime = 0;
21
+ this._clicks = [];
22
+ this._deadClickConfig = exports.DeadClickConfig;
23
+ this._handleScroll = (0, commonUtils_1.throttle)(() => {
24
+ const scrollTime = Date.now();
25
+ this._clicks.forEach((click) => {
26
+ if (!click.scrollDelayMs) {
27
+ click.scrollDelayMs = scrollTime - click.timestamp;
28
+ }
29
+ });
30
+ }, 50);
31
+ }
32
+ startTracking() {
33
+ const win = (0, client_core_1._getWindowSafe)();
34
+ if (!win) {
35
+ return;
36
+ }
37
+ // `capture: true` - Needed to listen to scroll events on all scrollable elements, not just the window.
38
+ // docs: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#usecapture
39
+ //
40
+ // `passive: true` - Indicates the scroll handler won’t call preventDefault(),
41
+ // allowing the browser to optimize scrolling performance by not blocking it.
42
+ // docs: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#passive
43
+ win.addEventListener('click', (event) => this._handleClick(event), {
44
+ capture: true,
45
+ });
46
+ win.addEventListener('scroll', () => this._handleScroll(), {
47
+ capture: true,
48
+ passive: true,
49
+ });
50
+ win.addEventListener('selectionchange', () => this._handleSelectionChange());
51
+ this._setupMutationObserver();
52
+ }
53
+ _handleClick(event) {
54
+ var _a, _b;
55
+ const eventTarget = event.target;
56
+ if (!eventTarget) {
57
+ return;
58
+ }
59
+ const click = {
60
+ timestamp: Date.now(),
61
+ eventTarget,
62
+ };
63
+ if (!commonUtils_1.interactiveElements.includes((_a = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.tagName) === null || _a === void 0 ? void 0 : _a.toLowerCase())) {
64
+ this._clicks.push(click);
65
+ }
66
+ if (this._clicks.length && !this._clickCheckTimer) {
67
+ this._clickCheckTimer = (_b = (0, client_core_1._getWindowSafe)()) === null || _b === void 0 ? void 0 : _b.setTimeout(() => {
68
+ this._checkForDeadClick();
69
+ }, this._deadClickConfig.CLICK_CHECK_TIMEOUT);
70
+ }
71
+ }
72
+ _handleSelectionChange() {
73
+ this._lastSelectionChangeTime = Date.now();
74
+ }
75
+ _setupMutationObserver() {
76
+ const doc = (0, client_core_1._getDocumentSafe)();
77
+ if (!doc) {
78
+ return;
79
+ }
80
+ this._observer = new MutationObserver(() => {
81
+ this._lastMutationTime = Date.now();
82
+ });
83
+ this._observer.observe(doc.body, {
84
+ childList: true,
85
+ subtree: true,
86
+ attributes: true,
87
+ characterData: true,
88
+ });
89
+ }
90
+ _checkForDeadClick() {
91
+ var _a;
92
+ if (!this._clicks.length) {
93
+ return;
94
+ }
95
+ clearTimeout(this._clickCheckTimer);
96
+ this._clickCheckTimer = undefined;
97
+ const clicksToCheck = this._clicks;
98
+ this._clicks = [];
99
+ for (const click of clicksToCheck) {
100
+ this._updateClickDelayMs(click);
101
+ const hadScroll = click.scrollDelayMs != null &&
102
+ click.scrollDelayMs < this._deadClickConfig.SCROLL_DELAY_MS;
103
+ const hadSelectionChange = click.selectionChangeDelayMs != null &&
104
+ click.selectionChangeDelayMs <
105
+ this._deadClickConfig.SELECTION_CHANGE_DELAY_MS;
106
+ const hadMutation = click.mutationDelayMs != null &&
107
+ click.mutationDelayMs < this._deadClickConfig.MUTATION_DELAY_MS;
108
+ if (hadScroll || hadSelectionChange || hadMutation) {
109
+ continue;
110
+ }
111
+ const scrollTimeout = click.scrollDelayMs != null &&
112
+ click.scrollDelayMs > this._deadClickConfig.SCROLL_DELAY_MS;
113
+ const selectionChangeTimeout = click.selectionChangeDelayMs != null &&
114
+ click.selectionChangeDelayMs >
115
+ this._deadClickConfig.SELECTION_CHANGE_DELAY_MS;
116
+ const mutationTimeout = click.mutationDelayMs != null &&
117
+ click.mutationDelayMs > this._deadClickConfig.MUTATION_DELAY_MS;
118
+ const absoluteTimeout = click.absoluteDelayMs != null &&
119
+ click.absoluteDelayMs >
120
+ this._deadClickConfig.ABSOLUTE_DEAD_CLICK_TIMEOUT;
121
+ if (scrollTimeout ||
122
+ selectionChangeTimeout ||
123
+ mutationTimeout ||
124
+ absoluteTimeout) {
125
+ this._logDeadClick(click, {
126
+ scrollTimeout,
127
+ selectionChangeTimeout,
128
+ mutationTimeout,
129
+ absoluteTimeout,
130
+ });
131
+ }
132
+ else if (click.absoluteDelayMs != null &&
133
+ click.absoluteDelayMs <
134
+ this._deadClickConfig.ABSOLUTE_DEAD_CLICK_TIMEOUT) {
135
+ this._clicks.push(click);
136
+ }
137
+ }
138
+ if (this._clicks.length && !this._clickCheckTimer) {
139
+ this._clickCheckTimer = (_a = (0, client_core_1._getWindowSafe)()) === null || _a === void 0 ? void 0 : _a.setTimeout(() => {
140
+ this._checkForDeadClick();
141
+ }, this._deadClickConfig.CLICK_CHECK_TIMEOUT);
142
+ }
143
+ }
144
+ _logDeadClick(click, extraMetadata) {
145
+ const { value, metadata } = (0, eventUtils_1._gatherEventData)(click.eventTarget);
146
+ this._enqueueFn(AutoCaptureEvent_1.AutoCaptureEventName.DEAD_CLICK, value, Object.assign(Object.assign(Object.assign({}, metadata), extraMetadata), { scrollDelayMs: click.scrollDelayMs, selectionChangeDelayMs: click.selectionChangeDelayMs, mutationDelayMs: click.mutationDelayMs, absoluteDelayMs: click.absoluteDelayMs }));
147
+ }
148
+ _updateClickDelayMs(click) {
149
+ if (!click.mutationDelayMs &&
150
+ this._lastMutationTime > 0 &&
151
+ click.timestamp <= this._lastMutationTime) {
152
+ click.mutationDelayMs = Date.now() - this._lastMutationTime;
153
+ }
154
+ if (!click.selectionChangeDelayMs &&
155
+ this._lastSelectionChangeTime > 0 &&
156
+ click.timestamp <= this._lastSelectionChangeTime) {
157
+ click.selectionChangeDelayMs = Date.now() - this._lastSelectionChangeTime;
158
+ }
159
+ click.absoluteDelayMs = Date.now() - click.timestamp;
160
+ }
161
+ }
162
+ exports.default = DeadClickManager;
@@ -4,9 +4,10 @@ interface NetworkInformation {
4
4
  rtt: number;
5
5
  saveData: boolean;
6
6
  }
7
+ export declare const interactiveElements: string[];
7
8
  export declare function _stripEmptyValues<T extends Record<string, string | number | null | undefined>>(obj: T): Partial<Record<keyof T, string | number>>;
8
9
  export declare function _getTargetNode(e: Event): Element | null;
9
- export declare function _shouldLogEvent(e: Event, el: Element): boolean;
10
+ export declare function _shouldLogEvent(e: Event, el: Element, isCopyEvent?: boolean): boolean;
10
11
  export declare function _getSafeUrl(): URL;
11
12
  export declare function _getSafeUrlString(): string;
12
13
  export declare function _getSanitizedPageUrl(): string;
@@ -15,4 +16,6 @@ export declare function _getSafeNetworkInformation(): NetworkInformation | null;
15
16
  export declare function _getSafeTimezone(): string | null;
16
17
  export declare function _getSafeTimezoneOffset(): number | null;
17
18
  export declare function _getAnchorNodeInHierarchy(node: Element | null): Element | null;
19
+ export declare function _sanitizeString(maybeString: string | null | undefined): string | null;
20
+ export declare function throttle<T extends (...args: unknown[]) => void>(fn: T, limit: number): T;
18
21
  export {};
@@ -1,7 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._getAnchorNodeInHierarchy = exports._getSafeTimezoneOffset = exports._getSafeTimezone = exports._getSafeNetworkInformation = exports._registerEventHandler = exports._getSanitizedPageUrl = exports._getSafeUrlString = exports._getSafeUrl = exports._shouldLogEvent = exports._getTargetNode = exports._stripEmptyValues = void 0;
3
+ exports.throttle = exports._sanitizeString = exports._getAnchorNodeInHierarchy = exports._getSafeTimezoneOffset = exports._getSafeTimezone = exports._getSafeNetworkInformation = exports._registerEventHandler = exports._getSanitizedPageUrl = exports._getSafeUrlString = exports._getSafeUrl = exports._shouldLogEvent = exports._getTargetNode = exports._stripEmptyValues = exports.interactiveElements = void 0;
4
4
  const client_core_1 = require("@statsig/client-core");
5
+ const coreCCPattern = `(4[0-9]{12}(?:[0-9]{3})?)|(5[1-5][0-9]{14})|(6(?:011|5[0-9]{2})[0-9]{12})|(3[47][0-9]{13})|(3(?:0[0-5]|[68][0-9])[0-9]{11})|((?:2131|1800|35[0-9]{3})[0-9]{11})`;
6
+ const CC_REGEX = new RegExp(`^(?:${coreCCPattern})$`);
7
+ const coreSSNPattern = `\\d{3}-?\\d{2}-?\\d{4}`;
8
+ const SSN_REGEX = new RegExp(`^(${coreSSNPattern})$`);
9
+ exports.interactiveElements = [
10
+ 'button',
11
+ 'a',
12
+ 'input',
13
+ 'select',
14
+ 'textarea',
15
+ 'form',
16
+ 'select',
17
+ 'label',
18
+ ];
5
19
  function _stripEmptyValues(obj) {
6
20
  return Object.fromEntries(Object.entries(obj).filter(([_, value]) => value != null && value !== '' && value !== undefined));
7
21
  }
@@ -20,7 +34,7 @@ function _getTargetNode(e) {
20
34
  return target;
21
35
  }
22
36
  exports._getTargetNode = _getTargetNode;
23
- function _shouldLogEvent(e, el) {
37
+ function _shouldLogEvent(e, el, isCopyEvent = false) {
24
38
  if (!e || !el || el.nodeType !== 1) {
25
39
  return false;
26
40
  }
@@ -30,15 +44,19 @@ function _shouldLogEvent(e, el) {
30
44
  if (classList.contains('statsig-no-capture')) {
31
45
  return false;
32
46
  }
47
+ if (isCopyEvent) {
48
+ // We don't want to force strict event filtering for copy events
49
+ return true;
50
+ }
33
51
  switch (tagName) {
34
52
  case 'html':
35
53
  return false;
36
54
  case 'form':
37
- return eventType === 'submit';
55
+ return ['submit'].indexOf(eventType) >= 0;
38
56
  case 'input':
39
57
  case 'select':
40
58
  case 'textarea':
41
- return ['change'].includes(eventType);
59
+ return ['change', 'click'].indexOf(eventType) >= 0;
42
60
  default:
43
61
  if (eventType === 'click') {
44
62
  if (tagName === 'button') {
@@ -133,3 +151,38 @@ function _getAnchorNodeInHierarchy(node) {
133
151
  return null;
134
152
  }
135
153
  exports._getAnchorNodeInHierarchy = _getAnchorNodeInHierarchy;
154
+ function _sanitizeString(maybeString) {
155
+ if (!maybeString) {
156
+ return null;
157
+ }
158
+ return maybeString
159
+ .replace(/<[^>]*>/g, '')
160
+ .trim()
161
+ .split(/(\s+)/)
162
+ .filter((s) => _shouldCaptureTextValue(s))
163
+ .join('')
164
+ .replace(/[\r\n]/g, ' ')
165
+ .replace(/[ ]+/g, ' ')
166
+ .substring(0, 255);
167
+ }
168
+ exports._sanitizeString = _sanitizeString;
169
+ function _shouldCaptureTextValue(text) {
170
+ if (CC_REGEX.test((text || '').replace(/[- ]/g, ''))) {
171
+ return false;
172
+ }
173
+ if (SSN_REGEX.test((text || '').replace(/[- ]/g, ''))) {
174
+ return false;
175
+ }
176
+ return true;
177
+ }
178
+ function throttle(fn, limit) {
179
+ let lastCall = 0;
180
+ return function (...args) {
181
+ const now = Date.now();
182
+ if (now - lastCall >= limit) {
183
+ lastCall = now;
184
+ fn(...args);
185
+ }
186
+ };
187
+ }
188
+ exports.throttle = throttle;
@@ -2,4 +2,5 @@ export declare function _gatherEventData(target: Element): {
2
2
  value: string;
3
3
  metadata: Record<string, unknown>;
4
4
  };
5
+ export declare function _gatherCopyEventData(e: Event): Record<string, unknown>;
5
6
  export declare function _getMetadataFromElement(target: Element): Record<string, unknown>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._getMetadataFromElement = exports._gatherEventData = void 0;
3
+ exports._getMetadataFromElement = exports._gatherCopyEventData = exports._gatherEventData = void 0;
4
4
  const client_core_1 = require("@statsig/client-core");
5
5
  const commonUtils_1 = require("./commonUtils");
6
6
  const MAX_ATTRIBUTE_LENGTH = 1000;
@@ -30,6 +30,16 @@ function _gatherEventData(target) {
30
30
  return { value, metadata };
31
31
  }
32
32
  exports._gatherEventData = _gatherEventData;
33
+ function _gatherCopyEventData(e) {
34
+ var _a, _b;
35
+ const selectedText = (_b = (_a = (0, client_core_1._getWindowSafe)()) === null || _a === void 0 ? void 0 : _a.getSelection()) === null || _b === void 0 ? void 0 : _b.toString();
36
+ const metadata = {};
37
+ metadata['selectedText'] = (0, commonUtils_1._sanitizeString)(selectedText);
38
+ const clipType = e.type || 'clipboard';
39
+ metadata['clipType'] = clipType;
40
+ return metadata;
41
+ }
42
+ exports._gatherCopyEventData = _gatherCopyEventData;
33
43
  function _getFormMetadata(target) {
34
44
  var _a;
35
45
  const metadata = {};