@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/lib/index.js
CHANGED
|
@@ -434,6 +434,23 @@ function deprecationWarn(nameOfFeature, useInstead, docsPath = '/') {
|
|
|
434
434
|
console.warn(`OpenReplay: ${nameOfFeature} is deprecated. ${useInstead ? `Please, use ${useInstead} instead.` : ''} Visit ${DOCS_HOST}${docsPath} for more information.`);
|
|
435
435
|
warnedFeatures[nameOfFeature] = true;
|
|
436
436
|
}
|
|
437
|
+
function getCustomAttributeLabel(e, customAttributes) {
|
|
438
|
+
if (!customAttributes || customAttributes.length === 0)
|
|
439
|
+
return '';
|
|
440
|
+
const parts = [];
|
|
441
|
+
for (const attr of customAttributes) {
|
|
442
|
+
const value = e.getAttribute(attr);
|
|
443
|
+
if (value !== null) {
|
|
444
|
+
parts.push(`[${attr}=${value}]`);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
return parts.join('');
|
|
448
|
+
}
|
|
449
|
+
function getClassSelector(e) {
|
|
450
|
+
if (!e.classList || e.classList.length === 0)
|
|
451
|
+
return '';
|
|
452
|
+
return '.' + Array.from(e.classList).join('.');
|
|
453
|
+
}
|
|
437
454
|
function getLabelAttribute(e) {
|
|
438
455
|
let value = e.getAttribute('data-openreplay-label');
|
|
439
456
|
if (value !== null) {
|
|
@@ -3405,7 +3422,10 @@ class TopObserver extends Observer {
|
|
|
3405
3422
|
this.app.debug.info('doc already observed for', id);
|
|
3406
3423
|
return;
|
|
3407
3424
|
}
|
|
3408
|
-
const observer = new IFrameObserver(this.app, false, {
|
|
3425
|
+
const observer = new IFrameObserver(this.app, false, {
|
|
3426
|
+
disableSprites: this.options.disableSprites,
|
|
3427
|
+
...getInlineOptions(this.options.inlineCss, console.warn),
|
|
3428
|
+
});
|
|
3409
3429
|
this.iframeObservers.set(iframe, observer);
|
|
3410
3430
|
this.docObservers.set(currentDoc, observer);
|
|
3411
3431
|
this.iframeObserversArr.push(observer);
|
|
@@ -3427,7 +3447,10 @@ class TopObserver extends Observer {
|
|
|
3427
3447
|
handle();
|
|
3428
3448
|
}
|
|
3429
3449
|
handleShadowRoot(shRoot) {
|
|
3430
|
-
const observer = new ShadowRootObserver(this.app
|
|
3450
|
+
const observer = new ShadowRootObserver(this.app, false, {
|
|
3451
|
+
disableSprites: this.options.disableSprites,
|
|
3452
|
+
...getInlineOptions(this.options.inlineCss, console.warn),
|
|
3453
|
+
});
|
|
3431
3454
|
this.shadowRootObservers.set(shRoot, observer);
|
|
3432
3455
|
observer.observe(shRoot.host);
|
|
3433
3456
|
}
|
|
@@ -3463,7 +3486,10 @@ class TopObserver extends Observer {
|
|
|
3463
3486
|
};
|
|
3464
3487
|
this.app.nodes.clear();
|
|
3465
3488
|
this.app.nodes.crossdomainMode(frameLevel, frameOder);
|
|
3466
|
-
const iframeObserver = new IFrameObserver(this.app
|
|
3489
|
+
const iframeObserver = new IFrameObserver(this.app, false, {
|
|
3490
|
+
disableSprites: this.options.disableSprites,
|
|
3491
|
+
...getInlineOptions(this.options.inlineCss, console.warn),
|
|
3492
|
+
});
|
|
3467
3493
|
this.iframeObservers.set(window.document, iframeObserver);
|
|
3468
3494
|
iframeObserver.syntheticObserve(rootNodeId, window.document);
|
|
3469
3495
|
}
|
|
@@ -3822,7 +3848,7 @@ class App {
|
|
|
3822
3848
|
this.stopCallbacks = [];
|
|
3823
3849
|
this.commitCallbacks = [];
|
|
3824
3850
|
this.activityState = ActivityState.NotActive;
|
|
3825
|
-
this.version = '17.2.
|
|
3851
|
+
this.version = '17.2.4'; // TODO: version compatability check inside each plugin.
|
|
3826
3852
|
this.socketMode = false;
|
|
3827
3853
|
this.compressionThreshold = 24 * 1000;
|
|
3828
3854
|
this.bc = null;
|
|
@@ -4252,9 +4278,6 @@ class App {
|
|
|
4252
4278
|
window.addEventListener('message', this.parentCrossDomainFrameListener);
|
|
4253
4279
|
window.addEventListener('message', this.crossDomainIframeListener);
|
|
4254
4280
|
setInterval(() => {
|
|
4255
|
-
if (document.hidden) {
|
|
4256
|
-
return;
|
|
4257
|
-
}
|
|
4258
4281
|
window.parent.postMessage({
|
|
4259
4282
|
line: proto.polling,
|
|
4260
4283
|
context: this.contextId,
|
|
@@ -5724,19 +5747,21 @@ const labelElementFor = IN_BROWSER && 'labels' in HTMLInputElement.prototype
|
|
|
5724
5747
|
}
|
|
5725
5748
|
}
|
|
5726
5749
|
};
|
|
5727
|
-
function getInputLabel(node) {
|
|
5728
|
-
|
|
5729
|
-
if (
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5750
|
+
function getInputLabel(node, customAttributes) {
|
|
5751
|
+
const openreplayLabel = getLabelAttribute(node);
|
|
5752
|
+
if (openreplayLabel !== null)
|
|
5753
|
+
return normSpaces(openreplayLabel).slice(0, 100);
|
|
5754
|
+
const customAttributeLabel = getCustomAttributeLabel(node, customAttributes);
|
|
5755
|
+
if (customAttributeLabel)
|
|
5756
|
+
return customAttributeLabel;
|
|
5757
|
+
if (node.id)
|
|
5758
|
+
return `#${node.id}`;
|
|
5759
|
+
const classLabel = getClassSelector(node);
|
|
5760
|
+
if (classLabel)
|
|
5761
|
+
return classLabel;
|
|
5762
|
+
const labelElement = labelElementFor(node);
|
|
5763
|
+
const label = node.name || node.placeholder || (labelElement && labelElement.innerText) || node.type;
|
|
5764
|
+
return normSpaces(label || '').slice(0, 100);
|
|
5740
5765
|
}
|
|
5741
5766
|
const InputMode = {
|
|
5742
5767
|
Plain: 0,
|
|
@@ -5817,7 +5842,7 @@ function Input (app, opts) {
|
|
|
5817
5842
|
}, 3);
|
|
5818
5843
|
function sendInputChange(id, node, hesitationTime, inputTime) {
|
|
5819
5844
|
const { value, mask } = getInputValue(id, node);
|
|
5820
|
-
let label = getInputLabel(node);
|
|
5845
|
+
let label = getInputLabel(node, options.customAttributes);
|
|
5821
5846
|
if (app.sanitizer.privateMode) {
|
|
5822
5847
|
label = label.replaceAll(/./g, '*');
|
|
5823
5848
|
}
|
|
@@ -5926,21 +5951,28 @@ function _getTarget(target, document) {
|
|
|
5926
5951
|
return target === document.documentElement ? null : target;
|
|
5927
5952
|
}
|
|
5928
5953
|
function Mouse (app, options) {
|
|
5929
|
-
const { disableClickmaps = false } = options || {};
|
|
5954
|
+
const { disableClickmaps = false, customAttributes } = options || {};
|
|
5930
5955
|
function getTargetLabel(target) {
|
|
5931
5956
|
const dl = getLabelAttribute(target);
|
|
5932
5957
|
if (dl !== null) {
|
|
5933
5958
|
return dl;
|
|
5934
5959
|
}
|
|
5935
5960
|
if (hasTag(target, 'input')) {
|
|
5936
|
-
return getInputLabel(target);
|
|
5937
|
-
}
|
|
5961
|
+
return getInputLabel(target, customAttributes);
|
|
5962
|
+
}
|
|
5963
|
+
const customAttributeLabel = getCustomAttributeLabel(target, customAttributes);
|
|
5964
|
+
if (customAttributeLabel)
|
|
5965
|
+
return customAttributeLabel;
|
|
5966
|
+
if (target.id)
|
|
5967
|
+
return `#${target.id}`;
|
|
5968
|
+
const classLabel = getClassSelector(target);
|
|
5969
|
+
if (classLabel)
|
|
5970
|
+
return classLabel;
|
|
5938
5971
|
if (isClickable(target)) {
|
|
5939
5972
|
let label = '';
|
|
5940
5973
|
if (target instanceof HTMLElement) {
|
|
5941
5974
|
label = app.sanitizer.getInnerTextSecure(target);
|
|
5942
5975
|
}
|
|
5943
|
-
label = label || target.id || target.className;
|
|
5944
5976
|
return normSpaces(label).slice(0, 100);
|
|
5945
5977
|
}
|
|
5946
5978
|
return '';
|
|
@@ -6084,6 +6116,11 @@ function getCSSPath(el) {
|
|
|
6084
6116
|
return false;
|
|
6085
6117
|
if (el.id)
|
|
6086
6118
|
return `#${cssEscape(el.id)}`;
|
|
6119
|
+
// if has data attributes - use them as they are more likely to be stable and unique
|
|
6120
|
+
const dataAttr = Array.from(el.attributes).find(attr => attr.name.startsWith('data-'));
|
|
6121
|
+
if (dataAttr) {
|
|
6122
|
+
return `[${dataAttr.name}="${cssEscape(dataAttr.value)}"]`;
|
|
6123
|
+
}
|
|
6087
6124
|
const parts = [];
|
|
6088
6125
|
while (el && el.nodeType === 1 && el !== el.ownerDocument) {
|
|
6089
6126
|
if (el.id) {
|
|
@@ -8615,7 +8652,7 @@ class ConstantProperties {
|
|
|
8615
8652
|
user_id: this.user_id,
|
|
8616
8653
|
distinct_id: this.deviceId,
|
|
8617
8654
|
sdk_edition: 'web',
|
|
8618
|
-
sdk_version: '17.2.
|
|
8655
|
+
sdk_version: '17.2.4',
|
|
8619
8656
|
timezone: getUTCOffsetString(),
|
|
8620
8657
|
search_engine: this.searchEngine,
|
|
8621
8658
|
};
|
|
@@ -8948,10 +8985,11 @@ class People {
|
|
|
8948
8985
|
* Creates batches of events, then sends them at intervals.
|
|
8949
8986
|
*/
|
|
8950
8987
|
class Batcher {
|
|
8951
|
-
constructor(backendUrl, getToken, init) {
|
|
8988
|
+
constructor(backendUrl, getToken, init, standalone) {
|
|
8952
8989
|
this.backendUrl = backendUrl;
|
|
8953
8990
|
this.getToken = getToken;
|
|
8954
8991
|
this.init = init;
|
|
8992
|
+
this.standalone = standalone;
|
|
8955
8993
|
this.autosendInterval = 5 * 1000;
|
|
8956
8994
|
this.retryTimeout = 3 * 1000;
|
|
8957
8995
|
this.retryLimit = 3;
|
|
@@ -8961,10 +8999,20 @@ class Batcher {
|
|
|
8961
8999
|
[categories.events]: [],
|
|
8962
9000
|
};
|
|
8963
9001
|
this.intervalId = null;
|
|
9002
|
+
this.stopped = false;
|
|
9003
|
+
this.paused = false;
|
|
9004
|
+
this.onVisibilityChange = () => {
|
|
9005
|
+
this.paused = document.hidden;
|
|
9006
|
+
};
|
|
8964
9007
|
}
|
|
8965
9008
|
getBatches() {
|
|
8966
9009
|
this.batch[categories.people] = this.dedupePeopleEvents();
|
|
8967
|
-
const finalData = {
|
|
9010
|
+
const finalData = {
|
|
9011
|
+
data: {
|
|
9012
|
+
[categories.people]: [...this.batch[categories.people]],
|
|
9013
|
+
[categories.events]: [...this.batch[categories.events]],
|
|
9014
|
+
},
|
|
9015
|
+
};
|
|
8968
9016
|
return finalData;
|
|
8969
9017
|
}
|
|
8970
9018
|
addEvent(event) {
|
|
@@ -9040,6 +9088,9 @@ class Batcher {
|
|
|
9040
9088
|
return Array.from(uniqueEventsByType.values());
|
|
9041
9089
|
}
|
|
9042
9090
|
sendBatch(batch) {
|
|
9091
|
+
if (this.stopped) {
|
|
9092
|
+
return;
|
|
9093
|
+
}
|
|
9043
9094
|
const sentBatch = batch;
|
|
9044
9095
|
let attempts = 0;
|
|
9045
9096
|
const send = () => {
|
|
@@ -9056,8 +9107,21 @@ class Batcher {
|
|
|
9056
9107
|
},
|
|
9057
9108
|
body: JSON.stringify(sentBatch),
|
|
9058
9109
|
})
|
|
9059
|
-
.then((response) => {
|
|
9060
|
-
if (
|
|
9110
|
+
.then(async (response) => {
|
|
9111
|
+
if (response.status === 401) {
|
|
9112
|
+
const body = await response.json().catch(() => null);
|
|
9113
|
+
if (!this.standalone && body?.error === 'token expired') {
|
|
9114
|
+
this.stop();
|
|
9115
|
+
return;
|
|
9116
|
+
}
|
|
9117
|
+
if (attempts < this.retryLimit) {
|
|
9118
|
+
return this.init().then(() => {
|
|
9119
|
+
send();
|
|
9120
|
+
});
|
|
9121
|
+
}
|
|
9122
|
+
return;
|
|
9123
|
+
}
|
|
9124
|
+
if (response.status === 403) {
|
|
9061
9125
|
if (attempts < this.retryLimit) {
|
|
9062
9126
|
return this.init().then(() => {
|
|
9063
9127
|
send();
|
|
@@ -9081,8 +9145,12 @@ class Batcher {
|
|
|
9081
9145
|
if (this.intervalId) {
|
|
9082
9146
|
clearInterval(this.intervalId);
|
|
9083
9147
|
}
|
|
9148
|
+
this.paused = document.hidden;
|
|
9149
|
+
document.addEventListener('visibilitychange', this.onVisibilityChange);
|
|
9084
9150
|
this.intervalId = setInterval(() => {
|
|
9085
|
-
this.
|
|
9151
|
+
if (!this.paused) {
|
|
9152
|
+
this.flush();
|
|
9153
|
+
}
|
|
9086
9154
|
}, this.autosendInterval);
|
|
9087
9155
|
}
|
|
9088
9156
|
flush() {
|
|
@@ -9102,6 +9170,12 @@ class Batcher {
|
|
|
9102
9170
|
clearInterval(this.intervalId);
|
|
9103
9171
|
this.intervalId = null;
|
|
9104
9172
|
}
|
|
9173
|
+
document.removeEventListener('visibilitychange', this.onVisibilityChange);
|
|
9174
|
+
this.stopped = true;
|
|
9175
|
+
}
|
|
9176
|
+
restart() {
|
|
9177
|
+
this.stopped = false;
|
|
9178
|
+
this.startAutosend();
|
|
9105
9179
|
}
|
|
9106
9180
|
}
|
|
9107
9181
|
|
|
@@ -9168,6 +9242,19 @@ class Analytics {
|
|
|
9168
9242
|
}
|
|
9169
9243
|
}
|
|
9170
9244
|
};
|
|
9245
|
+
/**
|
|
9246
|
+
* Used by tracker when running in blundled mode
|
|
9247
|
+
*/
|
|
9248
|
+
this.onStart = () => {
|
|
9249
|
+
if (!this.standalone) {
|
|
9250
|
+
this.batcher.restart();
|
|
9251
|
+
}
|
|
9252
|
+
};
|
|
9253
|
+
this.onStop = () => {
|
|
9254
|
+
if (!this.standalone) {
|
|
9255
|
+
this.batcher.stop();
|
|
9256
|
+
}
|
|
9257
|
+
};
|
|
9171
9258
|
this.reset = () => {
|
|
9172
9259
|
this.people.reset(true);
|
|
9173
9260
|
this.events.reset();
|
|
@@ -9206,7 +9293,7 @@ class Analytics {
|
|
|
9206
9293
|
this.standalone = !options.notStandalone;
|
|
9207
9294
|
this.token = this.sessionStorage.getItem(STORAGEKEY);
|
|
9208
9295
|
this.constantProperties = new ConstantProperties(this.localStorage, this.sessionStorage);
|
|
9209
|
-
this.batcher = new Batcher(this.backendUrl, this._getToken, this.init);
|
|
9296
|
+
this.batcher = new Batcher(this.backendUrl, this._getToken, this.init, this.standalone);
|
|
9210
9297
|
this.events = new Events(this.constantProperties, this._getTimestamp, this.batcher);
|
|
9211
9298
|
this.people = new People(this.constantProperties, this._getTimestamp, this.setUserId, this.batcher);
|
|
9212
9299
|
if (options.notStandalone) {
|
|
@@ -9267,7 +9354,7 @@ class API {
|
|
|
9267
9354
|
this.signalStartIssue = (reason, missingApi) => {
|
|
9268
9355
|
const doNotTrack = this.checkDoNotTrack();
|
|
9269
9356
|
console.log("Tracker couldn't start due to:", JSON.stringify({
|
|
9270
|
-
trackerVersion: '17.2.
|
|
9357
|
+
trackerVersion: '17.2.4',
|
|
9271
9358
|
projectKey: this.options.projectKey,
|
|
9272
9359
|
doNotTrack,
|
|
9273
9360
|
reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
|
|
@@ -9419,6 +9506,12 @@ class API {
|
|
|
9419
9506
|
: (options.analytics?.ingestPoint ?? options.ingestPoint ?? defaultEdp),
|
|
9420
9507
|
projectKey: options.projectKey,
|
|
9421
9508
|
});
|
|
9509
|
+
app.attachStartCallback(() => {
|
|
9510
|
+
this.analytics?.onStart();
|
|
9511
|
+
});
|
|
9512
|
+
app.attachStopCallback(() => {
|
|
9513
|
+
this.analytics?.onStop();
|
|
9514
|
+
});
|
|
9422
9515
|
}
|
|
9423
9516
|
if (!this.crossdomainMode) {
|
|
9424
9517
|
// no need to send iframe viewport data since its a node for us
|
|
@@ -9430,7 +9523,7 @@ class API {
|
|
|
9430
9523
|
// no tabs in iframes yet
|
|
9431
9524
|
Tabs(app);
|
|
9432
9525
|
}
|
|
9433
|
-
Mouse(app, options.mouse);
|
|
9526
|
+
Mouse(app, { ...options.mouse, customAttributes: options.customAttributes });
|
|
9434
9527
|
// inside iframe, we ignore viewport scroll
|
|
9435
9528
|
Scroll(app, this.crossdomainMode);
|
|
9436
9529
|
CSSRules(app, options.css);
|