@openreplay/tracker 17.2.2 → 17.2.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/dist/cjs/entry.js +127 -34
- package/dist/cjs/entry.js.map +1 -1
- package/dist/cjs/index.js +127 -34
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/main/index.d.ts +1 -0
- package/dist/cjs/main/modules/analytics/batcher.d.ts +6 -1
- package/dist/cjs/main/modules/analytics/index.d.ts +5 -0
- package/dist/cjs/main/modules/input.d.ts +2 -1
- package/dist/cjs/main/modules/mouse.d.ts +1 -0
- package/dist/cjs/main/utils.d.ts +2 -0
- package/dist/lib/entry.js +127 -34
- package/dist/lib/entry.js.map +1 -1
- package/dist/lib/index.js +127 -34
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/main/index.d.ts +1 -0
- package/dist/lib/main/modules/analytics/batcher.d.ts +6 -1
- package/dist/lib/main/modules/analytics/index.d.ts +5 -0
- package/dist/lib/main/modules/input.d.ts +2 -1
- package/dist/lib/main/modules/mouse.d.ts +1 -0
- package/dist/lib/main/utils.d.ts +2 -0
- package/dist/types/main/index.d.ts +1 -0
- package/dist/types/main/modules/analytics/batcher.d.ts +6 -1
- package/dist/types/main/modules/analytics/index.d.ts +5 -0
- package/dist/types/main/modules/input.d.ts +2 -1
- package/dist/types/main/modules/mouse.d.ts +1 -0
- package/dist/types/main/utils.d.ts +2 -0
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -438,6 +438,23 @@ function deprecationWarn(nameOfFeature, useInstead, docsPath = '/') {
|
|
|
438
438
|
console.warn(`OpenReplay: ${nameOfFeature} is deprecated. ${useInstead ? `Please, use ${useInstead} instead.` : ''} Visit ${DOCS_HOST}${docsPath} for more information.`);
|
|
439
439
|
warnedFeatures[nameOfFeature] = true;
|
|
440
440
|
}
|
|
441
|
+
function getCustomAttributeLabel(e, customAttributes) {
|
|
442
|
+
if (!customAttributes || customAttributes.length === 0)
|
|
443
|
+
return '';
|
|
444
|
+
const parts = [];
|
|
445
|
+
for (const attr of customAttributes) {
|
|
446
|
+
const value = e.getAttribute(attr);
|
|
447
|
+
if (value !== null) {
|
|
448
|
+
parts.push(`[${attr}=${value}]`);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
return parts.join('');
|
|
452
|
+
}
|
|
453
|
+
function getClassSelector(e) {
|
|
454
|
+
if (!e.classList || e.classList.length === 0)
|
|
455
|
+
return '';
|
|
456
|
+
return '.' + Array.from(e.classList).join('.');
|
|
457
|
+
}
|
|
441
458
|
function getLabelAttribute(e) {
|
|
442
459
|
let value = e.getAttribute('data-openreplay-label');
|
|
443
460
|
if (value !== null) {
|
|
@@ -3409,7 +3426,10 @@ class TopObserver extends Observer {
|
|
|
3409
3426
|
this.app.debug.info('doc already observed for', id);
|
|
3410
3427
|
return;
|
|
3411
3428
|
}
|
|
3412
|
-
const observer = new IFrameObserver(this.app, false, {
|
|
3429
|
+
const observer = new IFrameObserver(this.app, false, {
|
|
3430
|
+
disableSprites: this.options.disableSprites,
|
|
3431
|
+
...getInlineOptions(this.options.inlineCss, console.warn),
|
|
3432
|
+
});
|
|
3413
3433
|
this.iframeObservers.set(iframe, observer);
|
|
3414
3434
|
this.docObservers.set(currentDoc, observer);
|
|
3415
3435
|
this.iframeObserversArr.push(observer);
|
|
@@ -3431,7 +3451,10 @@ class TopObserver extends Observer {
|
|
|
3431
3451
|
handle();
|
|
3432
3452
|
}
|
|
3433
3453
|
handleShadowRoot(shRoot) {
|
|
3434
|
-
const observer = new ShadowRootObserver(this.app
|
|
3454
|
+
const observer = new ShadowRootObserver(this.app, false, {
|
|
3455
|
+
disableSprites: this.options.disableSprites,
|
|
3456
|
+
...getInlineOptions(this.options.inlineCss, console.warn),
|
|
3457
|
+
});
|
|
3435
3458
|
this.shadowRootObservers.set(shRoot, observer);
|
|
3436
3459
|
observer.observe(shRoot.host);
|
|
3437
3460
|
}
|
|
@@ -3467,7 +3490,10 @@ class TopObserver extends Observer {
|
|
|
3467
3490
|
};
|
|
3468
3491
|
this.app.nodes.clear();
|
|
3469
3492
|
this.app.nodes.crossdomainMode(frameLevel, frameOder);
|
|
3470
|
-
const iframeObserver = new IFrameObserver(this.app
|
|
3493
|
+
const iframeObserver = new IFrameObserver(this.app, false, {
|
|
3494
|
+
disableSprites: this.options.disableSprites,
|
|
3495
|
+
...getInlineOptions(this.options.inlineCss, console.warn),
|
|
3496
|
+
});
|
|
3471
3497
|
this.iframeObservers.set(window.document, iframeObserver);
|
|
3472
3498
|
iframeObserver.syntheticObserve(rootNodeId, window.document);
|
|
3473
3499
|
}
|
|
@@ -3826,7 +3852,7 @@ class App {
|
|
|
3826
3852
|
this.stopCallbacks = [];
|
|
3827
3853
|
this.commitCallbacks = [];
|
|
3828
3854
|
this.activityState = ActivityState.NotActive;
|
|
3829
|
-
this.version = '17.2.
|
|
3855
|
+
this.version = '17.2.4'; // TODO: version compatability check inside each plugin.
|
|
3830
3856
|
this.socketMode = false;
|
|
3831
3857
|
this.compressionThreshold = 24 * 1000;
|
|
3832
3858
|
this.bc = null;
|
|
@@ -4256,9 +4282,6 @@ class App {
|
|
|
4256
4282
|
window.addEventListener('message', this.parentCrossDomainFrameListener);
|
|
4257
4283
|
window.addEventListener('message', this.crossDomainIframeListener);
|
|
4258
4284
|
setInterval(() => {
|
|
4259
|
-
if (document.hidden) {
|
|
4260
|
-
return;
|
|
4261
|
-
}
|
|
4262
4285
|
window.parent.postMessage({
|
|
4263
4286
|
line: proto.polling,
|
|
4264
4287
|
context: this.contextId,
|
|
@@ -5728,19 +5751,21 @@ const labelElementFor = IN_BROWSER && 'labels' in HTMLInputElement.prototype
|
|
|
5728
5751
|
}
|
|
5729
5752
|
}
|
|
5730
5753
|
};
|
|
5731
|
-
function getInputLabel(node) {
|
|
5732
|
-
|
|
5733
|
-
if (
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5754
|
+
function getInputLabel(node, customAttributes) {
|
|
5755
|
+
const openreplayLabel = getLabelAttribute(node);
|
|
5756
|
+
if (openreplayLabel !== null)
|
|
5757
|
+
return normSpaces(openreplayLabel).slice(0, 100);
|
|
5758
|
+
const customAttributeLabel = getCustomAttributeLabel(node, customAttributes);
|
|
5759
|
+
if (customAttributeLabel)
|
|
5760
|
+
return customAttributeLabel;
|
|
5761
|
+
if (node.id)
|
|
5762
|
+
return `#${node.id}`;
|
|
5763
|
+
const classLabel = getClassSelector(node);
|
|
5764
|
+
if (classLabel)
|
|
5765
|
+
return classLabel;
|
|
5766
|
+
const labelElement = labelElementFor(node);
|
|
5767
|
+
const label = node.name || node.placeholder || (labelElement && labelElement.innerText) || node.type;
|
|
5768
|
+
return normSpaces(label || '').slice(0, 100);
|
|
5744
5769
|
}
|
|
5745
5770
|
const InputMode = {
|
|
5746
5771
|
Plain: 0,
|
|
@@ -5821,7 +5846,7 @@ function Input (app, opts) {
|
|
|
5821
5846
|
}, 3);
|
|
5822
5847
|
function sendInputChange(id, node, hesitationTime, inputTime) {
|
|
5823
5848
|
const { value, mask } = getInputValue(id, node);
|
|
5824
|
-
let label = getInputLabel(node);
|
|
5849
|
+
let label = getInputLabel(node, options.customAttributes);
|
|
5825
5850
|
if (app.sanitizer.privateMode) {
|
|
5826
5851
|
label = label.replaceAll(/./g, '*');
|
|
5827
5852
|
}
|
|
@@ -5930,21 +5955,28 @@ function _getTarget(target, document) {
|
|
|
5930
5955
|
return target === document.documentElement ? null : target;
|
|
5931
5956
|
}
|
|
5932
5957
|
function Mouse (app, options) {
|
|
5933
|
-
const { disableClickmaps = false } = options || {};
|
|
5958
|
+
const { disableClickmaps = false, customAttributes } = options || {};
|
|
5934
5959
|
function getTargetLabel(target) {
|
|
5935
5960
|
const dl = getLabelAttribute(target);
|
|
5936
5961
|
if (dl !== null) {
|
|
5937
5962
|
return dl;
|
|
5938
5963
|
}
|
|
5939
5964
|
if (hasTag(target, 'input')) {
|
|
5940
|
-
return getInputLabel(target);
|
|
5941
|
-
}
|
|
5965
|
+
return getInputLabel(target, customAttributes);
|
|
5966
|
+
}
|
|
5967
|
+
const customAttributeLabel = getCustomAttributeLabel(target, customAttributes);
|
|
5968
|
+
if (customAttributeLabel)
|
|
5969
|
+
return customAttributeLabel;
|
|
5970
|
+
if (target.id)
|
|
5971
|
+
return `#${target.id}`;
|
|
5972
|
+
const classLabel = getClassSelector(target);
|
|
5973
|
+
if (classLabel)
|
|
5974
|
+
return classLabel;
|
|
5942
5975
|
if (isClickable(target)) {
|
|
5943
5976
|
let label = '';
|
|
5944
5977
|
if (target instanceof HTMLElement) {
|
|
5945
5978
|
label = app.sanitizer.getInnerTextSecure(target);
|
|
5946
5979
|
}
|
|
5947
|
-
label = label || target.id || target.className;
|
|
5948
5980
|
return normSpaces(label).slice(0, 100);
|
|
5949
5981
|
}
|
|
5950
5982
|
return '';
|
|
@@ -6088,6 +6120,11 @@ function getCSSPath(el) {
|
|
|
6088
6120
|
return false;
|
|
6089
6121
|
if (el.id)
|
|
6090
6122
|
return `#${cssEscape(el.id)}`;
|
|
6123
|
+
// if has data attributes - use them as they are more likely to be stable and unique
|
|
6124
|
+
const dataAttr = Array.from(el.attributes).find(attr => attr.name.startsWith('data-'));
|
|
6125
|
+
if (dataAttr) {
|
|
6126
|
+
return `[${dataAttr.name}="${cssEscape(dataAttr.value)}"]`;
|
|
6127
|
+
}
|
|
6091
6128
|
const parts = [];
|
|
6092
6129
|
while (el && el.nodeType === 1 && el !== el.ownerDocument) {
|
|
6093
6130
|
if (el.id) {
|
|
@@ -8619,7 +8656,7 @@ class ConstantProperties {
|
|
|
8619
8656
|
user_id: this.user_id,
|
|
8620
8657
|
distinct_id: this.deviceId,
|
|
8621
8658
|
sdk_edition: 'web',
|
|
8622
|
-
sdk_version: '17.2.
|
|
8659
|
+
sdk_version: '17.2.4',
|
|
8623
8660
|
timezone: getUTCOffsetString(),
|
|
8624
8661
|
search_engine: this.searchEngine,
|
|
8625
8662
|
};
|
|
@@ -8952,10 +8989,11 @@ class People {
|
|
|
8952
8989
|
* Creates batches of events, then sends them at intervals.
|
|
8953
8990
|
*/
|
|
8954
8991
|
class Batcher {
|
|
8955
|
-
constructor(backendUrl, getToken, init) {
|
|
8992
|
+
constructor(backendUrl, getToken, init, standalone) {
|
|
8956
8993
|
this.backendUrl = backendUrl;
|
|
8957
8994
|
this.getToken = getToken;
|
|
8958
8995
|
this.init = init;
|
|
8996
|
+
this.standalone = standalone;
|
|
8959
8997
|
this.autosendInterval = 5 * 1000;
|
|
8960
8998
|
this.retryTimeout = 3 * 1000;
|
|
8961
8999
|
this.retryLimit = 3;
|
|
@@ -8965,10 +9003,20 @@ class Batcher {
|
|
|
8965
9003
|
[categories.events]: [],
|
|
8966
9004
|
};
|
|
8967
9005
|
this.intervalId = null;
|
|
9006
|
+
this.stopped = false;
|
|
9007
|
+
this.paused = false;
|
|
9008
|
+
this.onVisibilityChange = () => {
|
|
9009
|
+
this.paused = document.hidden;
|
|
9010
|
+
};
|
|
8968
9011
|
}
|
|
8969
9012
|
getBatches() {
|
|
8970
9013
|
this.batch[categories.people] = this.dedupePeopleEvents();
|
|
8971
|
-
const finalData = {
|
|
9014
|
+
const finalData = {
|
|
9015
|
+
data: {
|
|
9016
|
+
[categories.people]: [...this.batch[categories.people]],
|
|
9017
|
+
[categories.events]: [...this.batch[categories.events]],
|
|
9018
|
+
},
|
|
9019
|
+
};
|
|
8972
9020
|
return finalData;
|
|
8973
9021
|
}
|
|
8974
9022
|
addEvent(event) {
|
|
@@ -9044,6 +9092,9 @@ class Batcher {
|
|
|
9044
9092
|
return Array.from(uniqueEventsByType.values());
|
|
9045
9093
|
}
|
|
9046
9094
|
sendBatch(batch) {
|
|
9095
|
+
if (this.stopped) {
|
|
9096
|
+
return;
|
|
9097
|
+
}
|
|
9047
9098
|
const sentBatch = batch;
|
|
9048
9099
|
let attempts = 0;
|
|
9049
9100
|
const send = () => {
|
|
@@ -9060,8 +9111,21 @@ class Batcher {
|
|
|
9060
9111
|
},
|
|
9061
9112
|
body: JSON.stringify(sentBatch),
|
|
9062
9113
|
})
|
|
9063
|
-
.then((response) => {
|
|
9064
|
-
if (
|
|
9114
|
+
.then(async (response) => {
|
|
9115
|
+
if (response.status === 401) {
|
|
9116
|
+
const body = await response.json().catch(() => null);
|
|
9117
|
+
if (!this.standalone && body?.error === 'token expired') {
|
|
9118
|
+
this.stop();
|
|
9119
|
+
return;
|
|
9120
|
+
}
|
|
9121
|
+
if (attempts < this.retryLimit) {
|
|
9122
|
+
return this.init().then(() => {
|
|
9123
|
+
send();
|
|
9124
|
+
});
|
|
9125
|
+
}
|
|
9126
|
+
return;
|
|
9127
|
+
}
|
|
9128
|
+
if (response.status === 403) {
|
|
9065
9129
|
if (attempts < this.retryLimit) {
|
|
9066
9130
|
return this.init().then(() => {
|
|
9067
9131
|
send();
|
|
@@ -9085,8 +9149,12 @@ class Batcher {
|
|
|
9085
9149
|
if (this.intervalId) {
|
|
9086
9150
|
clearInterval(this.intervalId);
|
|
9087
9151
|
}
|
|
9152
|
+
this.paused = document.hidden;
|
|
9153
|
+
document.addEventListener('visibilitychange', this.onVisibilityChange);
|
|
9088
9154
|
this.intervalId = setInterval(() => {
|
|
9089
|
-
this.
|
|
9155
|
+
if (!this.paused) {
|
|
9156
|
+
this.flush();
|
|
9157
|
+
}
|
|
9090
9158
|
}, this.autosendInterval);
|
|
9091
9159
|
}
|
|
9092
9160
|
flush() {
|
|
@@ -9106,6 +9174,12 @@ class Batcher {
|
|
|
9106
9174
|
clearInterval(this.intervalId);
|
|
9107
9175
|
this.intervalId = null;
|
|
9108
9176
|
}
|
|
9177
|
+
document.removeEventListener('visibilitychange', this.onVisibilityChange);
|
|
9178
|
+
this.stopped = true;
|
|
9179
|
+
}
|
|
9180
|
+
restart() {
|
|
9181
|
+
this.stopped = false;
|
|
9182
|
+
this.startAutosend();
|
|
9109
9183
|
}
|
|
9110
9184
|
}
|
|
9111
9185
|
|
|
@@ -9172,6 +9246,19 @@ class Analytics {
|
|
|
9172
9246
|
}
|
|
9173
9247
|
}
|
|
9174
9248
|
};
|
|
9249
|
+
/**
|
|
9250
|
+
* Used by tracker when running in blundled mode
|
|
9251
|
+
*/
|
|
9252
|
+
this.onStart = () => {
|
|
9253
|
+
if (!this.standalone) {
|
|
9254
|
+
this.batcher.restart();
|
|
9255
|
+
}
|
|
9256
|
+
};
|
|
9257
|
+
this.onStop = () => {
|
|
9258
|
+
if (!this.standalone) {
|
|
9259
|
+
this.batcher.stop();
|
|
9260
|
+
}
|
|
9261
|
+
};
|
|
9175
9262
|
this.reset = () => {
|
|
9176
9263
|
this.people.reset(true);
|
|
9177
9264
|
this.events.reset();
|
|
@@ -9210,7 +9297,7 @@ class Analytics {
|
|
|
9210
9297
|
this.standalone = !options.notStandalone;
|
|
9211
9298
|
this.token = this.sessionStorage.getItem(STORAGEKEY);
|
|
9212
9299
|
this.constantProperties = new ConstantProperties(this.localStorage, this.sessionStorage);
|
|
9213
|
-
this.batcher = new Batcher(this.backendUrl, this._getToken, this.init);
|
|
9300
|
+
this.batcher = new Batcher(this.backendUrl, this._getToken, this.init, this.standalone);
|
|
9214
9301
|
this.events = new Events(this.constantProperties, this._getTimestamp, this.batcher);
|
|
9215
9302
|
this.people = new People(this.constantProperties, this._getTimestamp, this.setUserId, this.batcher);
|
|
9216
9303
|
if (options.notStandalone) {
|
|
@@ -9271,7 +9358,7 @@ class API {
|
|
|
9271
9358
|
this.signalStartIssue = (reason, missingApi) => {
|
|
9272
9359
|
const doNotTrack = this.checkDoNotTrack();
|
|
9273
9360
|
console.log("Tracker couldn't start due to:", JSON.stringify({
|
|
9274
|
-
trackerVersion: '17.2.
|
|
9361
|
+
trackerVersion: '17.2.4',
|
|
9275
9362
|
projectKey: this.options.projectKey,
|
|
9276
9363
|
doNotTrack,
|
|
9277
9364
|
reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
|
|
@@ -9423,6 +9510,12 @@ class API {
|
|
|
9423
9510
|
: (options.analytics?.ingestPoint ?? options.ingestPoint ?? defaultEdp),
|
|
9424
9511
|
projectKey: options.projectKey,
|
|
9425
9512
|
});
|
|
9513
|
+
app.attachStartCallback(() => {
|
|
9514
|
+
this.analytics?.onStart();
|
|
9515
|
+
});
|
|
9516
|
+
app.attachStopCallback(() => {
|
|
9517
|
+
this.analytics?.onStop();
|
|
9518
|
+
});
|
|
9426
9519
|
}
|
|
9427
9520
|
if (!this.crossdomainMode) {
|
|
9428
9521
|
// no need to send iframe viewport data since its a node for us
|
|
@@ -9434,7 +9527,7 @@ class API {
|
|
|
9434
9527
|
// no tabs in iframes yet
|
|
9435
9528
|
Tabs(app);
|
|
9436
9529
|
}
|
|
9437
|
-
Mouse(app, options.mouse);
|
|
9530
|
+
Mouse(app, { ...options.mouse, customAttributes: options.customAttributes });
|
|
9438
9531
|
// inside iframe, we ignore viewport scroll
|
|
9439
9532
|
Scroll(app, this.crossdomainMode);
|
|
9440
9533
|
CSSRules(app, options.css);
|