@posthog/browser-common 0.9.7 → 0.9.9

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.
@@ -0,0 +1,467 @@
1
+ import { addEventListener, each, extend } from "./utils/general-utils.mjs";
2
+ import { DEFAULT_AUTOCAPTURE_IGNORE_LIST, MAX_DOM_ANCESTOR_DEPTH, autocaptureCompatibleElements, elementMatchesCSSSelector, getClassNames, getDirectAndNestedSpanText, getElementsChainString, getEventTarget, getSafeText, isAngularStyleAttr, isSensitiveElement, makeSafeText, shouldCaptureDomEvent, shouldCaptureElement, shouldCaptureRageclick, shouldCaptureValue, splitClassString } from "./utils/autocapture-utils.mjs";
3
+ import rageclick from "./rageclick.mjs";
4
+ import { AUTOCAPTURE_DISABLED_SERVER_SIDE } from "./constants.mjs";
5
+ import { includes, isBoolean, isFunction, isNull, stripUrlHash } from "@posthog/core";
6
+ import { createLogger } from "./utils/logger.mjs";
7
+ import { convertToURL } from "./utils/convert-to-url.mjs";
8
+ import { isElementNode, isShadowRoot, isTag, isTextNode } from "./utils/element-utils.mjs";
9
+ const getWindow = ()=>"u" < typeof window ? void 0 : window;
10
+ const getDocument = ()=>"u" < typeof document ? void 0 : document;
11
+ const COPY_AUTOCAPTURE_EVENT = '$copy_autocapture';
12
+ const logger = createLogger('[AutoCapture]');
13
+ function limitText(length, text) {
14
+ if (text.length > length) return text.slice(0, length) + '...';
15
+ return text;
16
+ }
17
+ function getAugmentPropertiesFromElement(elem) {
18
+ const shouldCaptureEl = shouldCaptureElement(elem);
19
+ if (!shouldCaptureEl) return {};
20
+ const props = {};
21
+ each(elem.attributes, function(attr) {
22
+ if (attr.name && 0 === attr.name.indexOf('data-ph-capture-attribute')) {
23
+ const propertyKey = attr.name.replace('data-ph-capture-attribute-', '');
24
+ const propertyValue = attr.value;
25
+ if (propertyKey && propertyValue && shouldCaptureValue(propertyValue)) props[propertyKey] = propertyValue;
26
+ }
27
+ });
28
+ return props;
29
+ }
30
+ function previousElementSibling(el) {
31
+ if (el.previousElementSibling) return el.previousElementSibling;
32
+ let _el = el;
33
+ do _el = _el.previousSibling;
34
+ while (_el && !isElementNode(_el));
35
+ return _el;
36
+ }
37
+ function getDefaultProperties(eventType) {
38
+ return {
39
+ $event_type: eventType,
40
+ $ce_version: 1
41
+ };
42
+ }
43
+ function getPropertiesFromElement(elem, maskAllAttributes, maskText, elementAttributeIgnorelist, disableCaptureUrlHashes = false) {
44
+ const tag_name = elem.tagName.toLowerCase();
45
+ const props = {
46
+ tag_name: tag_name
47
+ };
48
+ if (autocaptureCompatibleElements.indexOf(tag_name) > -1 && !maskText) if ('a' === tag_name.toLowerCase() || 'button' === tag_name.toLowerCase()) props['$el_text'] = limitText(1024, getDirectAndNestedSpanText(elem));
49
+ else props['$el_text'] = limitText(1024, getSafeText(elem));
50
+ const classes = getClassNames(elem);
51
+ if (!maskAllAttributes && !elementAttributeIgnorelist?.includes('class') && classes.length > 0) props['classes'] = classes.filter(function(c) {
52
+ return '' !== c;
53
+ });
54
+ each(elem.attributes, function(attr) {
55
+ if (isSensitiveElement(elem) && -1 === [
56
+ 'name',
57
+ 'id',
58
+ 'class',
59
+ 'aria-label'
60
+ ].indexOf(attr.name)) return;
61
+ if (elementAttributeIgnorelist?.includes(attr.name)) return;
62
+ if (!maskAllAttributes && shouldCaptureValue(attr.value) && !isAngularStyleAttr(attr.name)) {
63
+ let value = attr.value;
64
+ if ('class' === attr.name) value = splitClassString(value).join(' ');
65
+ props['attr__' + attr.name] = limitText(1024, 'href' === attr.name && disableCaptureUrlHashes ? stripUrlHash(value) : value);
66
+ }
67
+ });
68
+ let nthChild = 1;
69
+ let nthOfType = 1;
70
+ let currentElem = elem;
71
+ while(currentElem = previousElementSibling(currentElem)){
72
+ nthChild++;
73
+ if (currentElem.tagName === elem.tagName) nthOfType++;
74
+ }
75
+ props['nth_child'] = nthChild;
76
+ props['nth_of_type'] = nthOfType;
77
+ return props;
78
+ }
79
+ function autocapturePropertiesForElement(target, { e, maskAllElementAttributes, maskAllText, elementAttributeIgnoreList, elementsChainAsString, disableCaptureUrlHashes }) {
80
+ if (!isElementNode(target)) return {
81
+ props: {}
82
+ };
83
+ const targetElementList = [
84
+ target
85
+ ];
86
+ const seen = new Set([
87
+ target
88
+ ]);
89
+ let curEl = target;
90
+ while(curEl.parentNode && !isTag(curEl, 'body')){
91
+ if (targetElementList.length >= MAX_DOM_ANCESTOR_DEPTH) break;
92
+ if (isShadowRoot(curEl.parentNode)) {
93
+ const host = curEl.parentNode.host;
94
+ if (seen.has(host)) break;
95
+ seen.add(host);
96
+ targetElementList.push(host);
97
+ curEl = host;
98
+ continue;
99
+ }
100
+ if (!isElementNode(curEl.parentNode)) break;
101
+ if (seen.has(curEl.parentNode)) break;
102
+ seen.add(curEl.parentNode);
103
+ targetElementList.push(curEl.parentNode);
104
+ curEl = curEl.parentNode;
105
+ }
106
+ const controlIndex = 'click' === e.type && 'http://www.w3.org/2000/svg' === target.namespaceURI ? targetElementList.findIndex((el)=>isTag(el, 'button') || isTag(el, 'a')) : -1;
107
+ if (controlIndex > 0) maskAllText = maskAllText || targetElementList.slice(0, controlIndex + 1).some((el)=>!shouldCaptureElement(el) || isSensitiveElement(el));
108
+ const elementsJson = [];
109
+ const autocaptureAugmentProperties = {};
110
+ let href = false;
111
+ let explicitNoCapture = false;
112
+ each(targetElementList, (el)=>{
113
+ const shouldCaptureEl = shouldCaptureElement(el);
114
+ if (isTag(el, 'a') && !maskAllElementAttributes && !elementAttributeIgnoreList?.includes('href')) {
115
+ const hrefAttr = el.getAttribute('href');
116
+ href = shouldCaptureEl && !!hrefAttr && shouldCaptureValue(hrefAttr) ? disableCaptureUrlHashes ? stripUrlHash(hrefAttr) : hrefAttr : false;
117
+ }
118
+ const classes = getClassNames(el);
119
+ if (includes(classes, 'ph-no-capture')) explicitNoCapture = true;
120
+ elementsJson.push(getPropertiesFromElement(el, maskAllElementAttributes, maskAllText, elementAttributeIgnoreList, disableCaptureUrlHashes));
121
+ const augmentProperties = getAugmentPropertiesFromElement(el);
122
+ each(augmentProperties, (value, key)=>{
123
+ if (!Object.prototype.hasOwnProperty.call(autocaptureAugmentProperties, key)) autocaptureAugmentProperties[key] = value;
124
+ });
125
+ });
126
+ if (explicitNoCapture) return {
127
+ props: {},
128
+ explicitNoCapture
129
+ };
130
+ if (controlIndex > 0) {
131
+ target = targetElementList[controlIndex];
132
+ elementsJson.splice(0, controlIndex);
133
+ }
134
+ if (!maskAllText) if (isTag(target, 'a') || isTag(target, 'button')) elementsJson[0]['$el_text'] = getDirectAndNestedSpanText(target);
135
+ else elementsJson[0]['$el_text'] = getSafeText(target);
136
+ let externalHref;
137
+ if (href) {
138
+ elementsJson[0]['attr__href'] = href;
139
+ const hrefHost = convertToURL(href)?.host;
140
+ const locationHost = getWindow()?.location?.host;
141
+ if (hrefHost && locationHost && hrefHost !== locationHost) externalHref = href;
142
+ }
143
+ const props = extend(getDefaultProperties(e.type), elementsChainAsString ? {} : {
144
+ $elements: elementsJson
145
+ }, {
146
+ $elements_chain: getElementsChainString(elementsJson)
147
+ }, elementsJson[0]?.['$el_text'] ? {
148
+ $el_text: elementsJson[0]?.['$el_text']
149
+ } : {}, externalHref && 'click' === e.type ? {
150
+ $external_click_url: externalHref
151
+ } : {}, autocaptureAugmentProperties);
152
+ return {
153
+ props,
154
+ target
155
+ };
156
+ }
157
+ const AutocaptureExtension = 'autocapture';
158
+ class Autocapture {
159
+ _clearPointer() {
160
+ this._pointerDown = void 0;
161
+ clearTimeout(this._pointerExpiry);
162
+ this._pointerExpiry = void 0;
163
+ }
164
+ _isExcludedPointerTarget(target) {
165
+ if (!shouldCaptureElement(target)) return true;
166
+ const ignorelist = this._refreshConfig().css_selector_ignorelist ?? DEFAULT_AUTOCAPTURE_IGNORE_LIST;
167
+ const seen = new Set();
168
+ let el = target;
169
+ while(el){
170
+ if (seen.size >= MAX_DOM_ANCESTOR_DEPTH || seen.has(el)) return true;
171
+ seen.add(el);
172
+ const current = el;
173
+ const classes = getClassNames(current);
174
+ if (includes(classes, 'ph-no-capture') || includes(classes, 'ph-sensitive') || isSensitiveElement(current) || ignorelist.some((selector)=>elementMatchesCSSSelector(current, selector))) return true;
175
+ const parent = el.parentNode;
176
+ el = isShadowRoot(parent) ? parent.host : parent && isElementNode(parent) ? parent : null;
177
+ }
178
+ return false;
179
+ }
180
+ _trackPointer(e) {
181
+ if (!this.isEnabled || 'pointercancel' === e.type) return void this._clearPointer();
182
+ if ('pointerdown' === e.type) {
183
+ this._clearPointer();
184
+ const target = getEventTarget(e);
185
+ if (e.isPrimary && 0 === e.button && !e.ctrlKey && target && isElementNode(target)) this._pointerDown = {
186
+ target,
187
+ excluded: this._isExcludedPointerTarget(target),
188
+ id: e.pointerId,
189
+ x: e.clientX,
190
+ y: e.clientY,
191
+ released: false,
192
+ distinctId: this._client?.distinctId
193
+ };
194
+ return;
195
+ }
196
+ const down = this._pointerDown;
197
+ if (!down) return;
198
+ if (e.pointerId !== down.id || Math.abs(e.clientX - down.x) > 5 || Math.abs(e.clientY - down.y) > 5) this._clearPointer();
199
+ else if ('pointerup' === e.type) {
200
+ down.released = true;
201
+ this._pointerExpiry = setTimeout(()=>this._clearPointer(), 0);
202
+ }
203
+ }
204
+ _recoverClickTarget(e) {
205
+ const down = this._pointerDown;
206
+ this._clearPointer();
207
+ const target = getEventTarget(e);
208
+ if (down?.released && down.target.isConnected && down.distinctId === this._client?.distinctId && e.pointerId === down.id && (e.detail > 0 || 'touch' === e.pointerType || 'pen' === e.pointerType) && 0 === e.button && Math.abs(e.clientX - down.x) <= 5 && Math.abs(e.clientY - down.y) <= 5 && target && (isTag(target, 'html') || isTag(target, 'body'))) {
209
+ if (down.excluded) return null;
210
+ const ignorelist = this._refreshConfig().css_selector_ignorelist ?? DEFAULT_AUTOCAPTURE_IGNORE_LIST;
211
+ const excludedRoot = [
212
+ target,
213
+ getDocument()?.documentElement,
214
+ getDocument()?.body
215
+ ].some((root)=>{
216
+ if (!root) return false;
217
+ const classes = getClassNames(root);
218
+ return includes(classes, 'ph-no-capture') || includes(classes, 'ph-sensitive') || !shouldCaptureElement(root) || isSensitiveElement(root) || ignorelist.some((selector)=>elementMatchesCSSSelector(root, selector));
219
+ });
220
+ if (excludedRoot) return null;
221
+ return down.target;
222
+ }
223
+ }
224
+ constructor(_configSource){
225
+ this._configSource = _configSource;
226
+ this.name = AutocaptureExtension;
227
+ this._initialized = false;
228
+ this._isDisabledServerSide = null;
229
+ this._hasReceivedConfigResponse = false;
230
+ this._elementSelectorsByOwner = new Map();
231
+ this._elementsChainAsString = false;
232
+ this._config = {
233
+ enabled: false,
234
+ rageclick: false,
235
+ maskAllElementAttributes: false,
236
+ maskAllText: false,
237
+ disableCaptureUrlHashes: false,
238
+ remoteRequestsDisabled: false
239
+ };
240
+ this._disposed = false;
241
+ this._configSource.refresh(this._config);
242
+ this.rageclicks = new rageclick(this._config.rageclick);
243
+ this._elementSelectors = null;
244
+ }
245
+ setup(client) {
246
+ this._compileUrlPatterns();
247
+ this._client = client;
248
+ const subscription = client.onRemoteConfig(this.onRemoteConfig.bind(this));
249
+ if (this._disposed) return void subscription.dispose();
250
+ this._remoteConfigSubscription = subscription;
251
+ this.startIfEnabled();
252
+ }
253
+ dispose() {
254
+ if (this._disposed) return;
255
+ this._disposed = true;
256
+ this._client = void 0;
257
+ this._remoteConfigSubscription?.dispose();
258
+ this._remoteConfigSubscription = void 0;
259
+ this._elementSelectorsByOwner.clear();
260
+ this._elementSelectors = null;
261
+ this._removeDomEventHandlers();
262
+ }
263
+ _refreshConfig() {
264
+ this._configSource.refresh(this._config);
265
+ return this._config;
266
+ }
267
+ _compileUrlPatterns() {
268
+ this._refreshConfig();
269
+ this._config.url_allowlist = this._config.url_allowlist?.map((url)=>new RegExp(url));
270
+ this._config.url_ignorelist = this._config.url_ignorelist?.map((url)=>new RegExp(url));
271
+ return this._config;
272
+ }
273
+ _addDomEventHandlers() {
274
+ const window1 = getWindow();
275
+ const document1 = getDocument();
276
+ if (!this.isBrowserSupported()) return void logger.info('Disabling Automatic Event Collection because this browser is not supported');
277
+ if (!window1 || !document1) return;
278
+ this._listenerWindow = window1;
279
+ this._listenerDocument = document1;
280
+ const handler = this._domEventHandler = (e)=>{
281
+ e = e || window1?.event;
282
+ try {
283
+ if ('blur' === e.type) return void this._clearPointer();
284
+ if (0 === e.type.indexOf('pointer')) return void this._trackPointer(e);
285
+ const target = 'click' === e.type ? this._recoverClickTarget(e) : void 0;
286
+ if (isNull(target)) return;
287
+ this._captureEvent(e, '$autocapture', target);
288
+ } catch (error) {
289
+ logger.error('Failed to capture event', error);
290
+ }
291
+ };
292
+ addEventListener(window1, 'blur', handler);
293
+ addEventListener(document1, 'submit', handler, {
294
+ capture: true
295
+ });
296
+ addEventListener(document1, 'change', handler, {
297
+ capture: true
298
+ });
299
+ addEventListener(document1, 'click', handler, {
300
+ capture: true
301
+ });
302
+ each([
303
+ 'pointerdown',
304
+ 'pointermove',
305
+ 'pointerup',
306
+ 'pointercancel'
307
+ ], (type)=>{
308
+ addEventListener(document1, type, handler, {
309
+ capture: true
310
+ });
311
+ });
312
+ if (this._refreshConfig().capture_copied_text) {
313
+ const copiedTextHandler = this._copiedTextHandler = (e)=>{
314
+ e = e || window1?.event;
315
+ try {
316
+ this._captureEvent(e, COPY_AUTOCAPTURE_EVENT);
317
+ } catch (error) {
318
+ logger.error('Failed to capture clipboard event', error);
319
+ }
320
+ };
321
+ addEventListener(document1, 'copy', copiedTextHandler, {
322
+ capture: true
323
+ });
324
+ addEventListener(document1, 'cut', copiedTextHandler, {
325
+ capture: true
326
+ });
327
+ addEventListener(document1, 'paste', copiedTextHandler, {
328
+ capture: true
329
+ });
330
+ }
331
+ }
332
+ _removeDomEventHandlers() {
333
+ const window1 = this._listenerWindow;
334
+ const document1 = this._listenerDocument;
335
+ this._clearPointer();
336
+ if (this._domEventHandler) {
337
+ window1?.removeEventListener('blur', this._domEventHandler);
338
+ each([
339
+ 'pointerdown',
340
+ 'pointermove',
341
+ 'pointerup',
342
+ 'pointercancel'
343
+ ], (type)=>{
344
+ document1?.removeEventListener(type, this._domEventHandler, true);
345
+ });
346
+ document1?.removeEventListener('submit', this._domEventHandler, true);
347
+ document1?.removeEventListener('change', this._domEventHandler, true);
348
+ document1?.removeEventListener('click', this._domEventHandler, true);
349
+ this._domEventHandler = void 0;
350
+ }
351
+ if (this._copiedTextHandler) {
352
+ document1?.removeEventListener('copy', this._copiedTextHandler, true);
353
+ document1?.removeEventListener('cut', this._copiedTextHandler, true);
354
+ document1?.removeEventListener('paste', this._copiedTextHandler, true);
355
+ this._copiedTextHandler = void 0;
356
+ }
357
+ this._listenerWindow = void 0;
358
+ this._listenerDocument = void 0;
359
+ this._initialized = false;
360
+ }
361
+ startIfEnabled() {
362
+ if (!this.isEnabled) this._clearPointer();
363
+ if (!this._disposed && this._client && this.isEnabled && !this._initialized) {
364
+ this._addDomEventHandlers();
365
+ this._initialized = true;
366
+ }
367
+ }
368
+ onRemoteConfig(result) {
369
+ if (this._disposed) return;
370
+ this._hasReceivedConfigResponse = true;
371
+ if (!result.ok) return void this.startIfEnabled();
372
+ const response = result.config;
373
+ if (response.elementsChainAsString) this._elementsChainAsString = response.elementsChainAsString;
374
+ const optOut = response['autocapture_opt_out'];
375
+ if (isBoolean(optOut)) {
376
+ this._client?.kv.set(AUTOCAPTURE_DISABLED_SERVER_SIDE, optOut);
377
+ this._isDisabledServerSide = optOut;
378
+ }
379
+ this.startIfEnabled();
380
+ }
381
+ setElementSelectors(selectors, owner = this) {
382
+ if (this._disposed) return;
383
+ if (selectors.size) this._elementSelectorsByOwner.set(owner, new Set(selectors));
384
+ else this._elementSelectorsByOwner.delete(owner);
385
+ const combined = new Set();
386
+ this._elementSelectorsByOwner.forEach((contribution)=>{
387
+ contribution.forEach((selector)=>combined.add(selector));
388
+ });
389
+ this._elementSelectors = combined;
390
+ }
391
+ getElementSelectors(element, additionalElement) {
392
+ const elementSelectors = [];
393
+ this._elementSelectors?.forEach((selector)=>{
394
+ const matchedElements = getDocument()?.querySelectorAll(selector);
395
+ matchedElements?.forEach((matchedElement)=>{
396
+ if ((element === matchedElement || additionalElement === matchedElement) && !includes(elementSelectors, selector)) elementSelectors.push(selector);
397
+ });
398
+ });
399
+ return elementSelectors;
400
+ }
401
+ get isEnabled() {
402
+ if (this._disposed) return false;
403
+ const persistedServerDisabled = this._client?.kv.get(AUTOCAPTURE_DISABLED_SERVER_SIDE);
404
+ const memoryDisabled = this._isDisabledServerSide;
405
+ const config = this._refreshConfig();
406
+ if (!config.remoteRequestsDisabled && !this._hasReceivedConfigResponse) return false;
407
+ const clientConfigOnly = config.remoteRequestsDisabled && !this._hasReceivedConfigResponse;
408
+ if (isNull(memoryDisabled) && !isBoolean(persistedServerDisabled) && !clientConfigOnly) return false;
409
+ const disabledServer = this._isDisabledServerSide ?? !!persistedServerDisabled;
410
+ const disabledClient = !config.enabled;
411
+ return !disabledClient && !disabledServer;
412
+ }
413
+ _captureEvent(e, eventName = '$autocapture', targetOverride) {
414
+ if (!this.isEnabled) return void this._clearPointer();
415
+ let target = targetOverride || getEventTarget(e);
416
+ if (isTextNode(target)) target = target.parentNode || null;
417
+ const config = this._compileUrlPatterns();
418
+ if ('$autocapture' === eventName && 'click' === e.type && e instanceof MouseEvent) {
419
+ if (!!config.rageclick && this.rageclicks?.isRageClick(e.clientX, e.clientY, e.timeStamp || new Date().getTime())) {
420
+ if (shouldCaptureRageclick(target, config.rageclick)) this._captureEvent(e, '$rageclick', targetOverride);
421
+ }
422
+ }
423
+ const isClipboardAutocapture = eventName === COPY_AUTOCAPTURE_EVENT;
424
+ const eventConfig = isClipboardAutocapture ? {
425
+ ...config,
426
+ dom_event_allowlist: void 0
427
+ } : config;
428
+ if (target && shouldCaptureDomEvent(target, e, eventConfig, isClipboardAutocapture, isClipboardAutocapture ? [
429
+ 'copy',
430
+ 'cut',
431
+ 'paste'
432
+ ] : void 0, {
433
+ config: {
434
+ get_current_url: config.getCurrentUrl
435
+ }
436
+ })) {
437
+ const { props, explicitNoCapture, target: attributedTarget } = autocapturePropertiesForElement(target, {
438
+ e,
439
+ maskAllElementAttributes: config.maskAllElementAttributes,
440
+ maskAllText: config.maskAllText,
441
+ elementAttributeIgnoreList: config.element_attribute_ignorelist,
442
+ elementsChainAsString: this._elementsChainAsString,
443
+ disableCaptureUrlHashes: config.disableCaptureUrlHashes
444
+ });
445
+ if (explicitNoCapture) return false;
446
+ const elementSelectors = this.getElementSelectors(target, attributedTarget);
447
+ if (elementSelectors && elementSelectors.length > 0) props['$element_selectors'] = elementSelectors;
448
+ if (eventName === COPY_AUTOCAPTURE_EVENT) {
449
+ const clipType = e.type || 'clipboard';
450
+ if ('paste' !== clipType) {
451
+ const selectedText = getWindow()?.getSelection()?.toString();
452
+ const selectedContent = makeSafeText(selectedText);
453
+ if (!selectedContent) return false;
454
+ props['$selected_content'] = selectedContent;
455
+ props['$clipboard_text_length'] = selectedText?.length ?? 0;
456
+ }
457
+ props['$copy_type'] = clipType;
458
+ }
459
+ this._client?.capture(eventName, props);
460
+ return true;
461
+ }
462
+ }
463
+ isBrowserSupported() {
464
+ return isFunction(getDocument()?.querySelectorAll);
465
+ }
466
+ }
467
+ export { Autocapture, AutocaptureExtension, autocapturePropertiesForElement, getAugmentPropertiesFromElement, getDefaultProperties, getPropertiesFromElement, previousElementSibling };
package/dist/config.js CHANGED
@@ -27,7 +27,7 @@ var __webpack_require__ = {};
27
27
  })();
28
28
  var __webpack_exports__ = {};
29
29
  __webpack_require__.r(__webpack_exports__);
30
- const packageVersion = "0.9.7";
30
+ const packageVersion = "0.9.9";
31
31
  const Config = {
32
32
  DEBUG: false,
33
33
  LIB_VERSION: packageVersion,
package/dist/config.mjs CHANGED
@@ -1,4 +1,4 @@
1
- const packageVersion = "0.9.7";
1
+ const packageVersion = "0.9.9";
2
2
  const Config = {
3
3
  DEBUG: false,
4
4
  LIB_VERSION: packageVersion,
@@ -17,3 +17,4 @@ export declare const PERSISTENCE_FEATURE_FLAG_PAYLOADS = "$feature_flag_payloads
17
17
  export declare const PERSISTENCE_OVERRIDE_FEATURE_FLAGS = "$override_feature_flags";
18
18
  export declare const PERSISTENCE_OVERRIDE_FEATURE_FLAG_PAYLOADS = "$override_feature_flag_payloads";
19
19
  export declare const DOM_EVENT_VISIBILITYCHANGE = "visibilitychange";
20
+ export declare const AUTOCAPTURE_DISABLED_SERVER_SIDE = "$autocapture_disabled_server_side";
package/dist/constants.js CHANGED
@@ -46,7 +46,9 @@ const PERSISTENCE_FEATURE_FLAG_PAYLOADS = '$feature_flag_payloads';
46
46
  const PERSISTENCE_OVERRIDE_FEATURE_FLAGS = '$override_feature_flags';
47
47
  const PERSISTENCE_OVERRIDE_FEATURE_FLAG_PAYLOADS = '$override_feature_flag_payloads';
48
48
  const DOM_EVENT_VISIBILITYCHANGE = 'visibilitychange';
49
+ const AUTOCAPTURE_DISABLED_SERVER_SIDE = '$autocapture_disabled_server_side';
49
50
  __webpack_require__.d(__webpack_exports__, {}, {
51
+ AUTOCAPTURE_DISABLED_SERVER_SIDE: AUTOCAPTURE_DISABLED_SERVER_SIDE,
50
52
  DOM_EVENT_VISIBILITYCHANGE: DOM_EVENT_VISIBILITYCHANGE,
51
53
  ENABLED_FEATURE_FLAGS: ENABLED_FEATURE_FLAGS,
52
54
  FLAG_CALL_REPORTED: FLAG_CALL_REPORTED,
@@ -67,6 +69,7 @@ __webpack_require__.d(__webpack_exports__, {}, {
67
69
  TOOLBAR_CONTAINER_CLASS: TOOLBAR_CONTAINER_CLASS,
68
70
  TOOLBAR_ID: TOOLBAR_ID
69
71
  });
72
+ exports.AUTOCAPTURE_DISABLED_SERVER_SIDE = __webpack_exports__.AUTOCAPTURE_DISABLED_SERVER_SIDE;
70
73
  exports.DOM_EVENT_VISIBILITYCHANGE = __webpack_exports__.DOM_EVENT_VISIBILITYCHANGE;
71
74
  exports.ENABLED_FEATURE_FLAGS = __webpack_exports__.ENABLED_FEATURE_FLAGS;
72
75
  exports.FLAG_CALL_REPORTED = __webpack_exports__.FLAG_CALL_REPORTED;
@@ -87,6 +90,7 @@ exports.STORED_PERSON_PROPERTIES_KEY = __webpack_exports__.STORED_PERSON_PROPERT
87
90
  exports.TOOLBAR_CONTAINER_CLASS = __webpack_exports__.TOOLBAR_CONTAINER_CLASS;
88
91
  exports.TOOLBAR_ID = __webpack_exports__.TOOLBAR_ID;
89
92
  for(var __rspack_i in __webpack_exports__)if (-1 === [
93
+ "AUTOCAPTURE_DISABLED_SERVER_SIDE",
90
94
  "DOM_EVENT_VISIBILITYCHANGE",
91
95
  "ENABLED_FEATURE_FLAGS",
92
96
  "FLAG_CALL_REPORTED",
@@ -17,4 +17,5 @@ const PERSISTENCE_FEATURE_FLAG_PAYLOADS = '$feature_flag_payloads';
17
17
  const PERSISTENCE_OVERRIDE_FEATURE_FLAGS = '$override_feature_flags';
18
18
  const PERSISTENCE_OVERRIDE_FEATURE_FLAG_PAYLOADS = '$override_feature_flag_payloads';
19
19
  const DOM_EVENT_VISIBILITYCHANGE = 'visibilitychange';
20
- export { DOM_EVENT_VISIBILITYCHANGE, ENABLED_FEATURE_FLAGS, FLAG_CALL_REPORTED, FLAG_CALL_REPORTED_SESSION_ID, PERSISTENCE_ACTIVE_FEATURE_FLAGS, PERSISTENCE_EARLY_ACCESS_FEATURES, PERSISTENCE_FEATURE_FLAG_DETAILS, PERSISTENCE_FEATURE_FLAG_ERRORS, PERSISTENCE_FEATURE_FLAG_EVALUATED_AT, PERSISTENCE_FEATURE_FLAG_PAYLOADS, PERSISTENCE_FEATURE_FLAG_REQUEST_ID, PERSISTENCE_MINIMAL_FLAG_CALLED_EVENTS, PERSISTENCE_OVERRIDE_FEATURE_FLAGS, PERSISTENCE_OVERRIDE_FEATURE_FLAG_PAYLOADS, SDK_DIST_CHANNEL, STORED_GROUP_PROPERTIES_KEY, STORED_PERSON_PROPERTIES_KEY, TOOLBAR_CONTAINER_CLASS, TOOLBAR_ID };
20
+ const AUTOCAPTURE_DISABLED_SERVER_SIDE = '$autocapture_disabled_server_side';
21
+ export { AUTOCAPTURE_DISABLED_SERVER_SIDE, DOM_EVENT_VISIBILITYCHANGE, ENABLED_FEATURE_FLAGS, FLAG_CALL_REPORTED, FLAG_CALL_REPORTED_SESSION_ID, PERSISTENCE_ACTIVE_FEATURE_FLAGS, PERSISTENCE_EARLY_ACCESS_FEATURES, PERSISTENCE_FEATURE_FLAG_DETAILS, PERSISTENCE_FEATURE_FLAG_ERRORS, PERSISTENCE_FEATURE_FLAG_EVALUATED_AT, PERSISTENCE_FEATURE_FLAG_PAYLOADS, PERSISTENCE_FEATURE_FLAG_REQUEST_ID, PERSISTENCE_MINIMAL_FLAG_CALLED_EVENTS, PERSISTENCE_OVERRIDE_FEATURE_FLAGS, PERSISTENCE_OVERRIDE_FEATURE_FLAG_PAYLOADS, SDK_DIST_CHANNEL, STORED_GROUP_PROPERTIES_KEY, STORED_PERSON_PROPERTIES_KEY, TOOLBAR_CONTAINER_CLASS, TOOLBAR_ID };
@@ -811,46 +811,53 @@ class PostHogFeatureFlags {
811
811
  [external_constants_js_namespaceObject.FLAG_CALL_REPORTED]: flagCallReported,
812
812
  [external_constants_js_namespaceObject.FLAG_CALL_REPORTED_SESSION_ID]: sessionIdToPersist
813
813
  });
814
- } else if (key in flagCallReported && flagCallReported[key].includes(flagReportValue)) {
815
- if (sessionIdToPersist) this._set({
816
- [external_constants_js_namespaceObject.FLAG_CALL_REPORTED]: flagCallReported,
817
- [external_constants_js_namespaceObject.FLAG_CALL_REPORTED_SESSION_ID]: sessionIdToPersist
818
- });
819
814
  } else {
820
- if ((0, core_namespaceObject.isArray)(flagCallReported[key])) flagCallReported[key].push(flagReportValue);
821
- else flagCallReported[key] = [
822
- flagReportValue
823
- ];
824
- this._set({
815
+ const canCapture = this._client?.canCapture;
816
+ if (!canCapture && Object.keys(flagCallReported).length > 0) {
817
+ flagCallReported = {};
818
+ this._set({
819
+ [external_constants_js_namespaceObject.FLAG_CALL_REPORTED]: flagCallReported
820
+ });
821
+ }
822
+ if (canCapture && !flagCallReported[key]?.includes(flagReportValue)) {
823
+ if ((0, core_namespaceObject.isArray)(flagCallReported[key])) flagCallReported[key].push(flagReportValue);
824
+ else flagCallReported[key] = [
825
+ flagReportValue
826
+ ];
827
+ this._set({
828
+ [external_constants_js_namespaceObject.FLAG_CALL_REPORTED]: flagCallReported,
829
+ ...sessionIdToPersist ? {
830
+ [external_constants_js_namespaceObject.FLAG_CALL_REPORTED_SESSION_ID]: sessionIdToPersist
831
+ } : {}
832
+ });
833
+ const flagDetails = this.getFeatureFlagDetails(key);
834
+ const errors = [
835
+ ...this._prop(external_constants_js_namespaceObject.PERSISTENCE_FEATURE_FLAG_ERRORS) ?? []
836
+ ];
837
+ if ((0, core_namespaceObject.isUndefined)(flagValue)) errors.push(FeatureFlagError.FLAG_MISSING);
838
+ const properties = {
839
+ $feature_flag: key,
840
+ $feature_flag_response: flagValue,
841
+ $feature_flag_payload: payload ?? null,
842
+ $feature_flag_request_id: requestId,
843
+ $feature_flag_evaluated_at: evaluatedAt,
844
+ $feature_flag_bootstrapped_response: this._config.bootstrap?.featureFlags?.[key] ?? null,
845
+ $feature_flag_bootstrapped_payload: this._config.bootstrap?.featureFlagPayloads?.[key] ?? null,
846
+ $used_bootstrap_value: !this._flagsLoadedFromRemote
847
+ };
848
+ if (!(0, core_namespaceObject.isUndefined)(flagDetails?.metadata?.has_experiment)) properties.$feature_flag_has_experiment = flagDetails.metadata.has_experiment;
849
+ if (!(0, core_namespaceObject.isUndefined)(flagDetails?.metadata?.version)) properties.$feature_flag_version = flagDetails.metadata.version;
850
+ const reason = flagDetails?.reason?.description ?? flagDetails?.reason?.code;
851
+ if (reason) properties.$feature_flag_reason = reason;
852
+ if (flagDetails?.metadata?.id) properties.$feature_flag_id = flagDetails.metadata.id;
853
+ if (!(0, core_namespaceObject.isUndefined)(flagDetails?.original_variant) || !(0, core_namespaceObject.isUndefined)(flagDetails?.original_enabled)) properties.$feature_flag_original_response = (0, core_namespaceObject.isUndefined)(flagDetails.original_variant) ? flagDetails.original_enabled : flagDetails.original_variant;
854
+ if (flagDetails?.metadata?.original_payload) properties.$feature_flag_original_payload = flagDetails?.metadata?.original_payload;
855
+ if (errors.length) properties.$feature_flag_error = errors.join(',');
856
+ this._captureFeatureFlagCalled(properties);
857
+ } else if (sessionIdToPersist) this._set({
825
858
  [external_constants_js_namespaceObject.FLAG_CALL_REPORTED]: flagCallReported,
826
- ...sessionIdToPersist ? {
827
- [external_constants_js_namespaceObject.FLAG_CALL_REPORTED_SESSION_ID]: sessionIdToPersist
828
- } : {}
859
+ [external_constants_js_namespaceObject.FLAG_CALL_REPORTED_SESSION_ID]: sessionIdToPersist
829
860
  });
830
- const flagDetails = this.getFeatureFlagDetails(key);
831
- const errors = [
832
- ...this._prop(external_constants_js_namespaceObject.PERSISTENCE_FEATURE_FLAG_ERRORS) ?? []
833
- ];
834
- if ((0, core_namespaceObject.isUndefined)(flagValue)) errors.push(FeatureFlagError.FLAG_MISSING);
835
- const properties = {
836
- $feature_flag: key,
837
- $feature_flag_response: flagValue,
838
- $feature_flag_payload: payload ?? null,
839
- $feature_flag_request_id: requestId,
840
- $feature_flag_evaluated_at: evaluatedAt,
841
- $feature_flag_bootstrapped_response: this._config.bootstrap?.featureFlags?.[key] ?? null,
842
- $feature_flag_bootstrapped_payload: this._config.bootstrap?.featureFlagPayloads?.[key] ?? null,
843
- $used_bootstrap_value: !this._flagsLoadedFromRemote
844
- };
845
- if (!(0, core_namespaceObject.isUndefined)(flagDetails?.metadata?.has_experiment)) properties.$feature_flag_has_experiment = flagDetails.metadata.has_experiment;
846
- if (!(0, core_namespaceObject.isUndefined)(flagDetails?.metadata?.version)) properties.$feature_flag_version = flagDetails.metadata.version;
847
- const reason = flagDetails?.reason?.description ?? flagDetails?.reason?.code;
848
- if (reason) properties.$feature_flag_reason = reason;
849
- if (flagDetails?.metadata?.id) properties.$feature_flag_id = flagDetails.metadata.id;
850
- if (!(0, core_namespaceObject.isUndefined)(flagDetails?.original_variant) || !(0, core_namespaceObject.isUndefined)(flagDetails?.original_enabled)) properties.$feature_flag_original_response = (0, core_namespaceObject.isUndefined)(flagDetails.original_variant) ? flagDetails.original_enabled : flagDetails.original_variant;
851
- if (flagDetails?.metadata?.original_payload) properties.$feature_flag_original_payload = flagDetails?.metadata?.original_payload;
852
- if (errors.length) properties.$feature_flag_error = errors.join(',');
853
- this._captureFeatureFlagCalled(properties);
854
861
  }
855
862
  if (!flagExists) return;
856
863
  return {