@openreplay/tracker 16.4.10 → 16.4.11-beta.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/dist/cjs/common/messages.gen.d.ts +57 -7
- package/dist/cjs/entry.js +502 -252
- package/dist/cjs/entry.js.map +1 -1
- package/dist/cjs/index.js +502 -252
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/main/app/guards.d.ts +1 -0
- package/dist/cjs/main/app/index.d.ts +5 -6
- package/dist/cjs/main/app/messages.gen.d.ts +7 -2
- package/dist/cjs/main/app/nodes/index.d.ts +1 -2
- package/dist/cjs/main/app/observer/observer.d.ts +4 -0
- package/dist/cjs/main/app/observer/top_observer.d.ts +3 -2
- package/dist/cjs/main/index.d.ts +9 -1
- package/dist/cjs/main/modules/longAnimationTask.d.ts +25 -0
- package/dist/cjs/main/modules/tagWatcher.d.ts +1 -1
- package/dist/cjs/main/modules/webAnimations.d.ts +9 -0
- package/dist/cjs/main/utils.d.ts +3 -0
- package/dist/lib/common/messages.gen.d.ts +57 -7
- package/dist/lib/entry.js +502 -252
- package/dist/lib/entry.js.map +1 -1
- package/dist/lib/index.js +502 -252
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/main/app/guards.d.ts +1 -0
- package/dist/lib/main/app/index.d.ts +5 -6
- package/dist/lib/main/app/messages.gen.d.ts +7 -2
- package/dist/lib/main/app/nodes/index.d.ts +1 -2
- package/dist/lib/main/app/observer/observer.d.ts +4 -0
- package/dist/lib/main/app/observer/top_observer.d.ts +3 -2
- package/dist/lib/main/index.d.ts +9 -1
- package/dist/lib/main/modules/longAnimationTask.d.ts +25 -0
- package/dist/lib/main/modules/tagWatcher.d.ts +1 -1
- package/dist/lib/main/modules/webAnimations.d.ts +9 -0
- package/dist/lib/main/utils.d.ts +3 -0
- package/dist/types/common/messages.gen.d.ts +57 -7
- package/dist/types/main/app/guards.d.ts +1 -0
- package/dist/types/main/app/index.d.ts +5 -6
- package/dist/types/main/app/messages.gen.d.ts +7 -2
- package/dist/types/main/app/nodes/index.d.ts +1 -2
- package/dist/types/main/app/observer/observer.d.ts +4 -0
- package/dist/types/main/app/observer/top_observer.d.ts +3 -2
- package/dist/types/main/index.d.ts +9 -1
- package/dist/types/main/modules/longAnimationTask.d.ts +25 -0
- package/dist/types/main/modules/tagWatcher.d.ts +1 -1
- package/dist/types/main/modules/webAnimations.d.ts +9 -0
- package/dist/types/main/utils.d.ts +3 -0
- package/package.json +2 -2
- package/dist/cjs/main/app/nodes/idSeq.d.ts +0 -14
- package/dist/lib/main/app/nodes/idSeq.d.ts +0 -14
- package/dist/types/main/app/nodes/idSeq.d.ts +0 -14
package/dist/cjs/index.js
CHANGED
|
@@ -1469,6 +1469,43 @@ function simpleMerge(defaultObj, givenObj) {
|
|
|
1469
1469
|
}
|
|
1470
1470
|
return result;
|
|
1471
1471
|
}
|
|
1472
|
+
function throttleWithTrailing(fn, interval) {
|
|
1473
|
+
const lastCalls = new Map();
|
|
1474
|
+
const timeouts = new Map();
|
|
1475
|
+
const lastArgs = new Map();
|
|
1476
|
+
const throttled = function (key, ...args) {
|
|
1477
|
+
const now = Date.now();
|
|
1478
|
+
const lastCall = lastCalls.get(key) ?? 0;
|
|
1479
|
+
const remaining = interval - (now - lastCall);
|
|
1480
|
+
lastArgs.set(key, args);
|
|
1481
|
+
if (remaining <= 0) {
|
|
1482
|
+
if (timeouts.has(key)) {
|
|
1483
|
+
clearTimeout(timeouts.get(key));
|
|
1484
|
+
timeouts.delete(key);
|
|
1485
|
+
}
|
|
1486
|
+
lastCalls.set(key, now);
|
|
1487
|
+
fn(key, ...args);
|
|
1488
|
+
}
|
|
1489
|
+
else if (!timeouts.has(key)) {
|
|
1490
|
+
const timeoutId = setTimeout(() => {
|
|
1491
|
+
lastCalls.set(key, Date.now());
|
|
1492
|
+
timeouts.delete(key);
|
|
1493
|
+
const finalArgs = lastArgs.get(key);
|
|
1494
|
+
fn(key, ...finalArgs);
|
|
1495
|
+
}, remaining);
|
|
1496
|
+
timeouts.set(key, timeoutId);
|
|
1497
|
+
}
|
|
1498
|
+
};
|
|
1499
|
+
throttled.clear = () => {
|
|
1500
|
+
for (const timeout of timeouts.values()) {
|
|
1501
|
+
clearTimeout(timeout);
|
|
1502
|
+
}
|
|
1503
|
+
timeouts.clear();
|
|
1504
|
+
lastArgs.clear();
|
|
1505
|
+
lastCalls.clear();
|
|
1506
|
+
};
|
|
1507
|
+
return throttled;
|
|
1508
|
+
}
|
|
1472
1509
|
|
|
1473
1510
|
// Auto-generated, do not edit
|
|
1474
1511
|
/* eslint-disable */
|
|
@@ -1679,6 +1716,13 @@ function SetNodeAttributeDictGlobal(id, name, value) {
|
|
|
1679
1716
|
value,
|
|
1680
1717
|
];
|
|
1681
1718
|
}
|
|
1719
|
+
function NodeAnimationResult(id, styles) {
|
|
1720
|
+
return [
|
|
1721
|
+
36 /* Messages.Type.NodeAnimationResult */,
|
|
1722
|
+
id,
|
|
1723
|
+
styles,
|
|
1724
|
+
];
|
|
1725
|
+
}
|
|
1682
1726
|
function CSSInsertRule(id, rule, index) {
|
|
1683
1727
|
return [
|
|
1684
1728
|
37 /* Messages.Type.CSSInsertRule */,
|
|
@@ -1807,9 +1851,9 @@ function SetNodeAttributeDict(id, name, value) {
|
|
|
1807
1851
|
value,
|
|
1808
1852
|
];
|
|
1809
1853
|
}
|
|
1810
|
-
function
|
|
1854
|
+
function ResourceTimingDeprecatedDeprecated(timestamp, duration, ttfb, headerSize, encodedBodySize, decodedBodySize, url, initiator) {
|
|
1811
1855
|
return [
|
|
1812
|
-
53 /* Messages.Type.
|
|
1856
|
+
53 /* Messages.Type.ResourceTimingDeprecatedDeprecated */,
|
|
1813
1857
|
timestamp,
|
|
1814
1858
|
duration,
|
|
1815
1859
|
ttfb,
|
|
@@ -1891,6 +1935,13 @@ function CustomIssue(name, payload) {
|
|
|
1891
1935
|
payload,
|
|
1892
1936
|
];
|
|
1893
1937
|
}
|
|
1938
|
+
function SetNodeSlot(id, slotID) {
|
|
1939
|
+
return [
|
|
1940
|
+
65 /* Messages.Type.SetNodeSlot */,
|
|
1941
|
+
id,
|
|
1942
|
+
slotID,
|
|
1943
|
+
];
|
|
1944
|
+
}
|
|
1894
1945
|
function CSSInsertRuleURLBased(id, rule, index, baseURL) {
|
|
1895
1946
|
return [
|
|
1896
1947
|
67 /* Messages.Type.CSSInsertRuleURLBased */,
|
|
@@ -2023,6 +2074,47 @@ function WSChannel(chType, channelName, data, timestamp, dir, messageType) {
|
|
|
2023
2074
|
messageType,
|
|
2024
2075
|
];
|
|
2025
2076
|
}
|
|
2077
|
+
function ResourceTiming(timestamp, duration, ttfb, headerSize, encodedBodySize, decodedBodySize, url, initiator, transferredSize, cached, queueing, dnsLookup, initialConnection, ssl, contentDownload, total, stalled) {
|
|
2078
|
+
return [
|
|
2079
|
+
85 /* Messages.Type.ResourceTiming */,
|
|
2080
|
+
timestamp,
|
|
2081
|
+
duration,
|
|
2082
|
+
ttfb,
|
|
2083
|
+
headerSize,
|
|
2084
|
+
encodedBodySize,
|
|
2085
|
+
decodedBodySize,
|
|
2086
|
+
url,
|
|
2087
|
+
initiator,
|
|
2088
|
+
transferredSize,
|
|
2089
|
+
cached,
|
|
2090
|
+
queueing,
|
|
2091
|
+
dnsLookup,
|
|
2092
|
+
initialConnection,
|
|
2093
|
+
ssl,
|
|
2094
|
+
contentDownload,
|
|
2095
|
+
total,
|
|
2096
|
+
stalled,
|
|
2097
|
+
];
|
|
2098
|
+
}
|
|
2099
|
+
function Incident(label, startTime, endTime) {
|
|
2100
|
+
return [
|
|
2101
|
+
87 /* Messages.Type.Incident */,
|
|
2102
|
+
label,
|
|
2103
|
+
startTime,
|
|
2104
|
+
endTime,
|
|
2105
|
+
];
|
|
2106
|
+
}
|
|
2107
|
+
function LongAnimationTask$1(name, duration, blockingDuration, firstUIEventTimestamp, startTime, scripts) {
|
|
2108
|
+
return [
|
|
2109
|
+
89 /* Messages.Type.LongAnimationTask */,
|
|
2110
|
+
name,
|
|
2111
|
+
duration,
|
|
2112
|
+
blockingDuration,
|
|
2113
|
+
firstUIEventTimestamp,
|
|
2114
|
+
startTime,
|
|
2115
|
+
scripts,
|
|
2116
|
+
];
|
|
2117
|
+
}
|
|
2026
2118
|
function InputChange(id, value, valueMasked, label, hesitationTime, inputDuration) {
|
|
2027
2119
|
return [
|
|
2028
2120
|
112 /* Messages.Type.InputChange */,
|
|
@@ -2054,9 +2146,9 @@ function UnbindNodes(totalRemovedPercent) {
|
|
|
2054
2146
|
totalRemovedPercent,
|
|
2055
2147
|
];
|
|
2056
2148
|
}
|
|
2057
|
-
function
|
|
2149
|
+
function ResourceTimingDeprecated(timestamp, duration, ttfb, headerSize, encodedBodySize, decodedBodySize, url, initiator, transferredSize, cached) {
|
|
2058
2150
|
return [
|
|
2059
|
-
116 /* Messages.Type.
|
|
2151
|
+
116 /* Messages.Type.ResourceTimingDeprecated */,
|
|
2060
2152
|
timestamp,
|
|
2061
2153
|
duration,
|
|
2062
2154
|
ttfb,
|
|
@@ -2153,9 +2245,11 @@ var _Messages = /*#__PURE__*/Object.freeze({
|
|
|
2153
2245
|
Fetch: Fetch,
|
|
2154
2246
|
GraphQL: GraphQL,
|
|
2155
2247
|
GraphQLDeprecated: GraphQLDeprecated,
|
|
2248
|
+
Incident: Incident,
|
|
2156
2249
|
InputChange: InputChange,
|
|
2157
2250
|
JSException: JSException,
|
|
2158
2251
|
LoadFontFace: LoadFontFace,
|
|
2252
|
+
LongAnimationTask: LongAnimationTask$1,
|
|
2159
2253
|
LongTask: LongTask,
|
|
2160
2254
|
Metadata: Metadata,
|
|
2161
2255
|
MobX: MobX,
|
|
@@ -2167,6 +2261,7 @@ var _Messages = /*#__PURE__*/Object.freeze({
|
|
|
2167
2261
|
NetworkRequest: NetworkRequest,
|
|
2168
2262
|
NetworkRequestDeprecated: NetworkRequestDeprecated,
|
|
2169
2263
|
NgRx: NgRx,
|
|
2264
|
+
NodeAnimationResult: NodeAnimationResult,
|
|
2170
2265
|
OTable: OTable,
|
|
2171
2266
|
PageLoadTiming: PageLoadTiming,
|
|
2172
2267
|
PageRenderTiming: PageRenderTiming,
|
|
@@ -2179,6 +2274,7 @@ var _Messages = /*#__PURE__*/Object.freeze({
|
|
|
2179
2274
|
RemoveNodeAttribute: RemoveNodeAttribute,
|
|
2180
2275
|
ResourceTiming: ResourceTiming,
|
|
2181
2276
|
ResourceTimingDeprecated: ResourceTimingDeprecated,
|
|
2277
|
+
ResourceTimingDeprecatedDeprecated: ResourceTimingDeprecatedDeprecated,
|
|
2182
2278
|
SelectionChange: SelectionChange,
|
|
2183
2279
|
SetCSSDataURLBased: SetCSSDataURLBased,
|
|
2184
2280
|
SetInputChecked: SetInputChecked,
|
|
@@ -2192,6 +2288,7 @@ var _Messages = /*#__PURE__*/Object.freeze({
|
|
|
2192
2288
|
SetNodeData: SetNodeData,
|
|
2193
2289
|
SetNodeFocus: SetNodeFocus,
|
|
2194
2290
|
SetNodeScroll: SetNodeScroll,
|
|
2291
|
+
SetNodeSlot: SetNodeSlot,
|
|
2195
2292
|
SetPageLocation: SetPageLocation,
|
|
2196
2293
|
SetPageLocationDeprecated: SetPageLocationDeprecated,
|
|
2197
2294
|
SetPageVisibility: SetPageVisibility,
|
|
@@ -2266,7 +2363,7 @@ function Performance (app, opts) {
|
|
|
2266
2363
|
const WATCHED_TAGS_KEY = '__or__watched_tags__';
|
|
2267
2364
|
class TagWatcher {
|
|
2268
2365
|
constructor(params) {
|
|
2269
|
-
this.
|
|
2366
|
+
this.interval = null;
|
|
2270
2367
|
this.tags = [];
|
|
2271
2368
|
this.sessionStorage = params.sessionStorage;
|
|
2272
2369
|
this.errLog = params.errLog;
|
|
@@ -2308,9 +2405,12 @@ class TagWatcher {
|
|
|
2308
2405
|
}
|
|
2309
2406
|
setTags(tags) {
|
|
2310
2407
|
this.tags = tags;
|
|
2311
|
-
this.
|
|
2312
|
-
|
|
2313
|
-
this.
|
|
2408
|
+
if (this.interval) {
|
|
2409
|
+
clearInterval(this.interval);
|
|
2410
|
+
this.interval = null;
|
|
2411
|
+
}
|
|
2412
|
+
this.interval = setInterval(() => {
|
|
2413
|
+
this.tags.forEach((tag) => {
|
|
2314
2414
|
const possibleEls = document.querySelectorAll(tag.selector);
|
|
2315
2415
|
if (possibleEls.length > 0) {
|
|
2316
2416
|
const el = possibleEls[0];
|
|
@@ -2318,21 +2418,21 @@ class TagWatcher {
|
|
|
2318
2418
|
el.__or_watcher_tagname = tag.id;
|
|
2319
2419
|
this.observer.observe(el);
|
|
2320
2420
|
}
|
|
2321
|
-
}
|
|
2322
|
-
});
|
|
2421
|
+
});
|
|
2422
|
+
}, 500);
|
|
2323
2423
|
}
|
|
2324
2424
|
onTagRendered(tagId) {
|
|
2325
|
-
if (this.
|
|
2326
|
-
|
|
2425
|
+
if (this.tags.findIndex(t => t.id === tagId)) {
|
|
2426
|
+
this.tags = this.tags.filter((tag) => tag.id !== tagId);
|
|
2327
2427
|
}
|
|
2328
2428
|
this.onTag(tagId);
|
|
2329
2429
|
}
|
|
2330
2430
|
clear() {
|
|
2331
|
-
this.tags.forEach((tag) => {
|
|
2332
|
-
clearInterval(this.intervals[tag.id]);
|
|
2333
|
-
});
|
|
2334
2431
|
this.tags = [];
|
|
2335
|
-
this.
|
|
2432
|
+
if (this.interval) {
|
|
2433
|
+
clearInterval(this.interval);
|
|
2434
|
+
this.interval = null;
|
|
2435
|
+
}
|
|
2336
2436
|
this.observer.disconnect();
|
|
2337
2437
|
}
|
|
2338
2438
|
}
|
|
@@ -3649,27 +3749,6 @@ class Maintainer {
|
|
|
3649
3749
|
}
|
|
3650
3750
|
}
|
|
3651
3751
|
|
|
3652
|
-
// 4 levels, 128 frames between each level, 8_388_608 nodes per page
|
|
3653
|
-
// lets hope no one will need more :D
|
|
3654
|
-
const BITS_LEVEL = 2; // 4
|
|
3655
|
-
const BITS_ORDER = 7; // 128
|
|
3656
|
-
const BITS_NODE = 22; // 8_388_608
|
|
3657
|
-
const SHIFT_ORDER = BITS_NODE;
|
|
3658
|
-
const SHIFT_LEVEL = BITS_NODE + BITS_ORDER;
|
|
3659
|
-
const MASK_NODE = (1 << BITS_NODE) - 1;
|
|
3660
|
-
const MASK_ORDER = (1 << BITS_ORDER) - 1;
|
|
3661
|
-
const MASK_LEVEL = (1 << BITS_LEVEL) - 1;
|
|
3662
|
-
function pack(level, order, nodeId) {
|
|
3663
|
-
if (level < 0 || level > MASK_LEVEL)
|
|
3664
|
-
throw new RangeError('OR: nesting level overflow, max 4');
|
|
3665
|
-
if (order < 0 || order > MASK_ORDER)
|
|
3666
|
-
throw new RangeError('OR: frame order overflow, max 128');
|
|
3667
|
-
const v = ((level & MASK_LEVEL) << SHIFT_LEVEL) |
|
|
3668
|
-
((order & MASK_ORDER) << SHIFT_ORDER) |
|
|
3669
|
-
(nodeId & MASK_NODE);
|
|
3670
|
-
return v >>> 0;
|
|
3671
|
-
}
|
|
3672
|
-
|
|
3673
3752
|
class Nodes {
|
|
3674
3753
|
constructor(params) {
|
|
3675
3754
|
this.nodes = new Map();
|
|
@@ -3697,9 +3776,6 @@ class Nodes {
|
|
|
3697
3776
|
}
|
|
3698
3777
|
listeners.push([type, listener, useCapture]);
|
|
3699
3778
|
};
|
|
3700
|
-
this.createFrameId = (level, frameOrder) => {
|
|
3701
|
-
return pack(level, frameOrder, 0);
|
|
3702
|
-
};
|
|
3703
3779
|
this.unregisterNode = (node) => {
|
|
3704
3780
|
const id = node[this.node_id];
|
|
3705
3781
|
if (id !== undefined) {
|
|
@@ -3720,8 +3796,16 @@ class Nodes {
|
|
|
3720
3796
|
this.maintainer = new Maintainer(this.nodes, this.unregisterNode, params.maintainer);
|
|
3721
3797
|
this.maintainer.start();
|
|
3722
3798
|
}
|
|
3723
|
-
|
|
3724
|
-
|
|
3799
|
+
syntheticMode(frameOrder) {
|
|
3800
|
+
const maxSafeNumber = Number.MAX_SAFE_INTEGER;
|
|
3801
|
+
const placeholderSize = 99999999;
|
|
3802
|
+
const nextFrameId = placeholderSize * frameOrder;
|
|
3803
|
+
// I highly doubt that this will ever happen,
|
|
3804
|
+
// but it will be easier to debug if it does
|
|
3805
|
+
if (nextFrameId > maxSafeNumber) {
|
|
3806
|
+
throw new Error('Placeholder id overflow');
|
|
3807
|
+
}
|
|
3808
|
+
this.nextNodeId = nextFrameId;
|
|
3725
3809
|
}
|
|
3726
3810
|
registerNode(node) {
|
|
3727
3811
|
let id = node[this.node_id];
|
|
@@ -4156,6 +4240,13 @@ async function parseUseEl(useElement, mode, domParser) {
|
|
|
4156
4240
|
return;
|
|
4157
4241
|
}
|
|
4158
4242
|
let [url, symbolId] = href.split('#');
|
|
4243
|
+
if (!url && !symbolId) {
|
|
4244
|
+
console.warn('Openreplay: Invalid xlink:href or href found on <use>.');
|
|
4245
|
+
return;
|
|
4246
|
+
}
|
|
4247
|
+
if (iconCache[symbolId]) {
|
|
4248
|
+
return iconCache[symbolId];
|
|
4249
|
+
}
|
|
4159
4250
|
// happens if svg spritemap is local, fastest case for us
|
|
4160
4251
|
if (!url && symbolId) {
|
|
4161
4252
|
const hasHashtag = href.startsWith('#');
|
|
@@ -4181,13 +4272,6 @@ async function parseUseEl(useElement, mode, domParser) {
|
|
|
4181
4272
|
return;
|
|
4182
4273
|
}
|
|
4183
4274
|
}
|
|
4184
|
-
if (!url && !symbolId) {
|
|
4185
|
-
console.warn('Openreplay: Invalid xlink:href or href found on <use>.');
|
|
4186
|
-
return;
|
|
4187
|
-
}
|
|
4188
|
-
if (iconCache[symbolId]) {
|
|
4189
|
-
return iconCache[symbolId];
|
|
4190
|
-
}
|
|
4191
4275
|
let svgDoc;
|
|
4192
4276
|
if (svgUrlCache[url]) {
|
|
4193
4277
|
if (svgUrlCache[url] === 1) {
|
|
@@ -4287,6 +4371,7 @@ class Observer {
|
|
|
4287
4371
|
this.indexes = [];
|
|
4288
4372
|
this.attributesMap = new Map();
|
|
4289
4373
|
this.textSet = new Set();
|
|
4374
|
+
this.slotMap = new Map();
|
|
4290
4375
|
this.disableSprites = false;
|
|
4291
4376
|
/**
|
|
4292
4377
|
* this option means that, instead of using link element with href to load css,
|
|
@@ -4296,6 +4381,9 @@ class Observer {
|
|
|
4296
4381
|
this.inlineRemoteCss = false;
|
|
4297
4382
|
this.inlinerOptions = undefined;
|
|
4298
4383
|
this.domParser = new DOMParser();
|
|
4384
|
+
this.throttling = true;
|
|
4385
|
+
this.throttledSetNodeData = throttleWithTrailing((id, parentElement, data) => this.sendNodeData(id, parentElement, data), 30);
|
|
4386
|
+
this.throttling = !Boolean(options.disableThrottling);
|
|
4299
4387
|
this.disableSprites = Boolean(options.disableSprites);
|
|
4300
4388
|
this.inlineRemoteCss = Boolean(options.inlineRemoteCss);
|
|
4301
4389
|
this.inlinerOptions = options.inlinerOptions;
|
|
@@ -4476,6 +4564,18 @@ class Observer {
|
|
|
4476
4564
|
}
|
|
4477
4565
|
bindNode(node) {
|
|
4478
4566
|
const [id, isNew] = this.app.nodes.registerNode(node);
|
|
4567
|
+
if (isElementNode(node) && hasTag(node, 'slot')) {
|
|
4568
|
+
this.app.nodes.attachNodeListener(node, 'slotchange', () => {
|
|
4569
|
+
const sl = node;
|
|
4570
|
+
sl.assignedNodes({ flatten: true }).forEach((n) => {
|
|
4571
|
+
const nid = this.app.nodes.getID(n);
|
|
4572
|
+
if (nid !== undefined) {
|
|
4573
|
+
this.recents.set(nid, RecentsType.Removed);
|
|
4574
|
+
this.commitNode(nid);
|
|
4575
|
+
}
|
|
4576
|
+
});
|
|
4577
|
+
});
|
|
4578
|
+
}
|
|
4479
4579
|
if (isNew) {
|
|
4480
4580
|
this.recents.set(id, RecentsType.New);
|
|
4481
4581
|
}
|
|
@@ -4506,6 +4606,9 @@ class Observer {
|
|
|
4506
4606
|
}
|
|
4507
4607
|
unbindTree(node) {
|
|
4508
4608
|
const id = this.app.nodes.unregisterNode(node);
|
|
4609
|
+
if (id !== undefined) {
|
|
4610
|
+
this.slotMap.delete(id);
|
|
4611
|
+
}
|
|
4509
4612
|
if (id !== undefined && this.recents.get(id) === RecentsType.Removed) {
|
|
4510
4613
|
// Sending RemoveNode only for parent to maintain
|
|
4511
4614
|
this.app.send(RemoveNode(id));
|
|
@@ -4534,8 +4637,15 @@ class Observer {
|
|
|
4534
4637
|
if (isRootNode(node)) {
|
|
4535
4638
|
return true;
|
|
4536
4639
|
}
|
|
4537
|
-
|
|
4538
|
-
|
|
4640
|
+
let slot = node.assignedSlot;
|
|
4641
|
+
let isLightDom = false;
|
|
4642
|
+
if (slot) {
|
|
4643
|
+
// Check if the node is in light DOM (not in shadow DOM)
|
|
4644
|
+
// This is a workaround for the issue with shadow DOM and slots
|
|
4645
|
+
// where the slot is not assigned to the node in shadow DOM.
|
|
4646
|
+
isLightDom = node.getRootNode() instanceof ShadowRoot;
|
|
4647
|
+
}
|
|
4648
|
+
const parent = node.parentNode;
|
|
4539
4649
|
let parentID;
|
|
4540
4650
|
// Disable parent check for the upper context HTMLHtmlElement, because it is root there... (before)
|
|
4541
4651
|
// TODO: get rid of "special" cases (there is an issue with CreateDocument altered behaviour though)
|
|
@@ -4547,7 +4657,15 @@ class Observer {
|
|
|
4547
4657
|
this.unbindTree(node);
|
|
4548
4658
|
return false;
|
|
4549
4659
|
}
|
|
4550
|
-
|
|
4660
|
+
if (isLightDom && slot) {
|
|
4661
|
+
parentID = this.app.nodes.getID(slot);
|
|
4662
|
+
// in light dom, we don't "slot" the node,
|
|
4663
|
+
// but rather use the slot as a parent
|
|
4664
|
+
slot = null;
|
|
4665
|
+
}
|
|
4666
|
+
else {
|
|
4667
|
+
parentID = this.app.nodes.getID(parent);
|
|
4668
|
+
}
|
|
4551
4669
|
if (parentID === undefined) {
|
|
4552
4670
|
this.unbindTree(node);
|
|
4553
4671
|
return false;
|
|
@@ -4607,12 +4725,35 @@ class Observer {
|
|
|
4607
4725
|
else if (isTextNode(node)) {
|
|
4608
4726
|
// for text node id != 0, hence parentID !== undefined and parent is Element
|
|
4609
4727
|
this.app.send(CreateTextNode(id, parentID, index));
|
|
4610
|
-
this.
|
|
4728
|
+
if (this.throttling) {
|
|
4729
|
+
this.throttledSetNodeData(id, parent, node.data);
|
|
4730
|
+
}
|
|
4731
|
+
else {
|
|
4732
|
+
this.sendNodeData(id, parent, node.data);
|
|
4733
|
+
}
|
|
4734
|
+
}
|
|
4735
|
+
if (slot) {
|
|
4736
|
+
const slotID = this.app.nodes.getID(slot);
|
|
4737
|
+
if (slotID !== undefined) {
|
|
4738
|
+
this.slotMap.set(id, slotID);
|
|
4739
|
+
this.app.send(SetNodeSlot(id, slotID));
|
|
4740
|
+
}
|
|
4611
4741
|
}
|
|
4612
4742
|
return true;
|
|
4613
4743
|
}
|
|
4614
4744
|
if (recentsType === RecentsType.Removed && parentID !== undefined) {
|
|
4615
4745
|
this.app.send(MoveNode(id, parentID, index));
|
|
4746
|
+
if (slot) {
|
|
4747
|
+
const slotID = this.app.nodes.getID(slot);
|
|
4748
|
+
if (slotID !== undefined && this.slotMap.get(id) !== slotID) {
|
|
4749
|
+
this.slotMap.set(id, slotID);
|
|
4750
|
+
this.app.send(SetNodeSlot(id, slotID));
|
|
4751
|
+
}
|
|
4752
|
+
}
|
|
4753
|
+
else if (this.slotMap.has(id)) {
|
|
4754
|
+
this.slotMap.delete(id);
|
|
4755
|
+
this.app.send(SetNodeSlot(id, 0));
|
|
4756
|
+
}
|
|
4616
4757
|
}
|
|
4617
4758
|
const attr = this.attributesMap.get(id);
|
|
4618
4759
|
if (attr !== undefined) {
|
|
@@ -4628,7 +4769,12 @@ class Observer {
|
|
|
4628
4769
|
throw 'commitNode: node is not a text';
|
|
4629
4770
|
}
|
|
4630
4771
|
// for text node id != 0, hence parent is Element
|
|
4631
|
-
this.
|
|
4772
|
+
if (this.throttling) {
|
|
4773
|
+
this.throttledSetNodeData(id, parent, node.data);
|
|
4774
|
+
}
|
|
4775
|
+
else {
|
|
4776
|
+
this.sendNodeData(id, parent, node.data);
|
|
4777
|
+
}
|
|
4632
4778
|
}
|
|
4633
4779
|
return true;
|
|
4634
4780
|
}
|
|
@@ -4671,6 +4817,7 @@ class Observer {
|
|
|
4671
4817
|
disconnect() {
|
|
4672
4818
|
this.observer.disconnect();
|
|
4673
4819
|
this.clear();
|
|
4820
|
+
this.throttledSetNodeData.clear();
|
|
4674
4821
|
}
|
|
4675
4822
|
}
|
|
4676
4823
|
|
|
@@ -4778,7 +4925,7 @@ var InlineCssMode;
|
|
|
4778
4925
|
InlineCssMode[InlineCssMode["Disabled"] = 0] = "Disabled";
|
|
4779
4926
|
/** will attempt to record the linked css file as AdoptedStyleSheet object */
|
|
4780
4927
|
InlineCssMode[InlineCssMode["Inline"] = 1] = "Inline";
|
|
4781
|
-
/** will fetch the file, then
|
|
4928
|
+
/** will fetch the file, then simulate AdoptedStyleSheets behavior programmaticaly for the replay */
|
|
4782
4929
|
InlineCssMode[InlineCssMode["InlineFetched"] = 2] = "InlineFetched";
|
|
4783
4930
|
/** will fetch the file, then save it as plain css inside <style> node */
|
|
4784
4931
|
InlineCssMode[InlineCssMode["PlainFetched"] = 3] = "PlainFetched";
|
|
@@ -4830,6 +4977,7 @@ class TopObserver extends Observer {
|
|
|
4830
4977
|
}, params.options);
|
|
4831
4978
|
const observerOptions = {
|
|
4832
4979
|
disableSprites: opts.disableSprites,
|
|
4980
|
+
disableThrottling: opts.disableThrottling,
|
|
4833
4981
|
...getInlineOptions(opts.inlineCss)
|
|
4834
4982
|
};
|
|
4835
4983
|
super(params.app, true, observerOptions);
|
|
@@ -4929,7 +5077,7 @@ class TopObserver extends Observer {
|
|
|
4929
5077
|
this.app.nodes.callNodeCallbacks(document, true);
|
|
4930
5078
|
}, window.document.documentElement);
|
|
4931
5079
|
}
|
|
4932
|
-
crossdomainObserve(rootNodeId, frameOder
|
|
5080
|
+
crossdomainObserve(rootNodeId, frameOder) {
|
|
4933
5081
|
const observer = this;
|
|
4934
5082
|
Element.prototype.attachShadow = function () {
|
|
4935
5083
|
// eslint-disable-next-line
|
|
@@ -4938,7 +5086,7 @@ class TopObserver extends Observer {
|
|
|
4938
5086
|
return shadow;
|
|
4939
5087
|
};
|
|
4940
5088
|
this.app.nodes.clear();
|
|
4941
|
-
this.app.nodes.
|
|
5089
|
+
this.app.nodes.syntheticMode(frameOder);
|
|
4942
5090
|
const iframeObserver = new IFrameObserver(this.app);
|
|
4943
5091
|
this.iframeObservers.set(window.document, iframeObserver);
|
|
4944
5092
|
iframeObserver.syntheticObserve(rootNodeId, window.document);
|
|
@@ -5238,7 +5386,7 @@ class Ticker {
|
|
|
5238
5386
|
* this value is injected during build time via rollup
|
|
5239
5387
|
* */
|
|
5240
5388
|
// @ts-ignore
|
|
5241
|
-
const workerBodyFn = "!function(){\"use strict\";class t{constructor(t,s,i,e=10,n=250,h,r){this.onUnauthorised=s,this.onFailure=i,this.MAX_ATTEMPTS_COUNT=e,this.ATTEMPT_TIMEOUT=n,this.onCompress=h,this.pageNo=r,this.attemptsCount=0,this.busy=!1,this.queue=[],this.token=null,this.lastBatchNum=0,this.ingestURL=t+\"/v1/web/i\",this.isCompressing=void 0!==h}getQueueStatus(){return 0===this.queue.length&&!this.busy}authorise(t){this.token=t,this.busy||this.sendNext()}push(t){if(this.busy||!this.token)this.queue.push(t);else if(this.busy=!0,this.isCompressing&&this.onCompress)this.onCompress(t);else{const s=++this.lastBatchNum;this.sendBatch(t,!1,s)}}sendNext(){const t=this.queue.shift();if(t)if(this.busy=!0,this.isCompressing&&this.onCompress)this.onCompress(t);else{const s=++this.lastBatchNum;this.sendBatch(t,!1,s)}else this.busy=!1}retry(t,s,i){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`):(this.attemptsCount++,setTimeout((()=>this.sendBatch(t,s,i)),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t,s,i){var e;const n=null==i?void 0:i.toString().replace(/^([^_]+)_([^_]+).*/,\"$1_$2_$3\");this.busy=!0;const h={Authorization:`Bearer ${this.token}`};s&&(h[\"Content-Encoding\"]=\"gzip\"),null!==this.token?fetch(`${this.ingestURL}?batch=${null!==(e=this.pageNo)&&void 0!==e?e:\"noPageNum\"}_${null!=n?n:\"noBatchNum\"}`,{body:t,method:\"POST\",headers:h,keepalive:t.length<65536}).then((e=>{if(401===e.status)return this.busy=!1,void this.onUnauthorised();e.status>=400?this.retry(t,s,`${null!=i?i:\"noBatchNum\"}_network:${e.status}`):(this.attemptsCount=0,this.sendNext())})).catch((e=>{console.warn(\"OpenReplay:\",e),this.retry(t,s,`${null!=i?i:\"noBatchNum\"}_reject:${e.message}`)})):setTimeout((()=>{this.sendBatch(t,s,`${null!=i?i:\"noBatchNum\"}_newToken`)}),500)}sendCompressed(t){const s=++this.lastBatchNum;this.sendBatch(t,!0,s)}sendUncompressed(t){const s=++this.lastBatchNum;this.sendBatch(t,!1,s)}clean(){this.sendNext(),setTimeout((()=>{this.token=null,this.queue.length=0}),10)}}const s=\"function\"==typeof TextEncoder?new TextEncoder:{encode(t){const s=t.length,i=new Uint8Array(3*s);let e=-1;for(let n=0,h=0,r=0;r!==s;){if(n=t.charCodeAt(r),r+=1,n>=55296&&n<=56319){if(r===s){i[e+=1]=239,i[e+=1]=191,i[e+=1]=189;break}if(h=t.charCodeAt(r),!(h>=56320&&h<=57343)){i[e+=1]=239,i[e+=1]=191,i[e+=1]=189;continue}if(n=1024*(n-55296)+h-56320+65536,r+=1,n>65535){i[e+=1]=240|n>>>18,i[e+=1]=128|n>>>12&63,i[e+=1]=128|n>>>6&63,i[e+=1]=128|63&n;continue}}n<=127?i[e+=1]=0|n:n<=2047?(i[e+=1]=192|n>>>6,i[e+=1]=128|63&n):(i[e+=1]=224|n>>>12,i[e+=1]=128|n>>>6&63,i[e+=1]=128|63&n)}return i.subarray(0,e+1)}};class i{constructor(t){this.size=t,this.offset=0,this.checkpointOffset=0,this.data=new Uint8Array(t)}getCurrentOffset(){return this.offset}checkpoint(){this.checkpointOffset=this.offset}get isEmpty(){return 0===this.offset}skip(t){return this.offset+=t,this.offset<=this.size}set(t,s){this.data.set(t,s)}boolean(t){return this.data[this.offset++]=+t,this.offset<=this.size}uint(t){for((t<0||t>Number.MAX_SAFE_INTEGER)&&(t=0);t>=128;)this.data[this.offset++]=t%256|128,t=Math.floor(t/128);return this.data[this.offset++]=t,this.offset<=this.size}int(t){return t=Math.round(t),this.uint(t>=0?2*t:-2*t-1)}string(t){const i=s.encode(t),e=i.byteLength;return!(!this.uint(e)||this.offset+e>this.size)&&(this.data.set(i,this.offset),this.offset+=e,!0)}reset(){this.offset=0,this.checkpointOffset=0}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}class e extends i{encode(t){switch(t[0]){case 0:case 11:case 114:case 115:return this.uint(t[1]);case 4:case 44:case 47:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 5:case 20:case 38:case 70:case 75:case 76:case 77:case 82:return this.uint(t[1])&&this.uint(t[2]);case 6:return this.int(t[1])&&this.int(t[2]);case 7:return!0;case 8:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.string(t[4])&&this.boolean(t[5]);case 9:case 10:case 24:case 35:case 51:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 12:case 52:case 61:case 71:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 13:case 14:case 17:case 34:case 50:case 54:return this.uint(t[1])&&this.string(t[2]);case 16:return this.uint(t[1])&&this.int(t[2])&&this.int(t[3]);case 18:return this.uint(t[1])&&this.string(t[2])&&this.int(t[3]);case 19:return this.uint(t[1])&&this.boolean(t[2]);case 21:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.string(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8]);case 22:case 27:case 30:case 41:case 45:case 46:case 43:case 63:case 64:case 79:case 124:return this.string(t[1])&&this.string(t[2]);case 23:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8])&&this.uint(t[9]);case 28:case 29:case 42:case 117:case 118:return this.string(t[1]);case 37:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3]);case 39:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7]);case 40:return this.string(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 48:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.int(t[5]);case 49:return this.int(t[1])&&this.int(t[2])&&this.uint(t[3])&&this.uint(t[4]);case 53:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8]);case 55:return this.boolean(t[1]);case 57:case 60:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 58:case 120:return this.int(t[1]);case 59:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.string(t[5])&&this.string(t[6])&&this.string(t[7]);case 67:case 73:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 68:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])&&this.uint(t[6]);case 69:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 78:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 81:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.int(t[4])&&this.string(t[5]);case 83:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.string(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8])&&this.uint(t[9]);case 84:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.uint(t[4])&&this.string(t[5])&&this.string(t[6]);case 112:return this.uint(t[1])&&this.string(t[2])&&this.boolean(t[3])&&this.string(t[4])&&this.int(t[5])&&this.int(t[6]);case 113:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3]);case 116:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8])&&this.uint(t[9])&&this.boolean(t[10]);case 119:return this.string(t[1])&&this.uint(t[2]);case 121:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.uint(t[4]);case 122:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 123:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])}}}class n{constructor(t,s,i,n,h,r){this.pageNo=t,this.timestamp=s,this.url=i,this.onBatch=n,this.tabId=h,this.onOfflineEnd=r,this.nextIndex=0,this.beaconSize=2e5,this.encoder=new e(this.beaconSize),this.sizeBuffer=new Uint8Array(3),this.isEmpty=!0,this.checkpoints=[],this.beaconSizeLimit=1e6,this.prepare()}writeType(t){return this.encoder.uint(t[0])}writeFields(t){return this.encoder.encode(t)}writeSizeAt(t,s){for(let s=0;s<3;s++)this.sizeBuffer[s]=t>>8*s;this.encoder.set(this.sizeBuffer,s)}prepare(){if(!this.encoder.isEmpty)return;this.checkpoints.length=0;const t=[81,1,this.pageNo,this.nextIndex,this.timestamp,this.url],s=[0,this.timestamp],i=[118,this.tabId];this.writeType(t),this.writeFields(t),this.writeWithSize(s),this.writeWithSize(i),this.isEmpty=!0}writeWithSize(t){const s=this.encoder;if(!this.writeType(t)||!s.skip(3))return!1;const i=s.getCurrentOffset(),e=this.writeFields(t);if(e){const e=s.getCurrentOffset()-i;if(e>16777215)return console.warn(\"OpenReplay: max message size overflow.\"),!1;this.writeSizeAt(e,i-3),s.checkpoint(),this.checkpoints.push(s.getCurrentOffset()),this.isEmpty=this.isEmpty&&0===t[0],this.nextIndex++}return e}setBeaconSizeLimit(t){this.beaconSizeLimit=t}writeMessage(t){if(\"q_end\"===t[0])return this.finaliseBatch(),this.onOfflineEnd();0===t[0]&&(this.timestamp=t[1]),122===t[0]&&(this.url=t[1]),this.writeWithSize(t)||(this.finaliseBatch(),this.writeWithSize(t)||(this.encoder=new e(this.beaconSizeLimit),this.prepare(),this.writeWithSize(t)?this.finaliseBatch():console.warn(\"OpenReplay: beacon size overflow. Skipping large message.\",t,this),this.encoder=new e(this.beaconSize),this.prepare()))}finaliseBatch(t=!1){if(this.isEmpty)return;const s=this.encoder.flush();this.onBatch(s,t),this.prepare()}clean(){this.encoder.reset(),this.checkpoints.length=0}}var h;!function(t){t[t.NotActive=0]=\"NotActive\",t[t.Starting=1]=\"Starting\",t[t.Stopping=2]=\"Stopping\",t[t.Active=3]=\"Active\",t[t.Stopped=4]=\"Stopped\"}(h||(h={}));let r=null,a=null,u=h.NotActive;function o(t){a&&a.finaliseBatch(t)}function c(){return new Promise((t=>{u=h.Stopping,null!==p&&(clearInterval(p),p=null),a&&(a.clean(),a=null),r&&(r.clean(),setTimeout((()=>{r=null}),20)),setTimeout((()=>{u=h.NotActive,t(null)}),100)}))}function g(){[h.Stopped,h.Stopping].includes(u)||(postMessage(\"a_stop\"),c().then((()=>{postMessage(\"a_start\")})))}let l,p=null;self.onmessage=({data:s})=>{if(\"stop\"===s)return o(),void c().then((()=>{u=h.Stopped}));if(\"forceFlushBatch\"!==s)if(\"closing\"!==s){if(!Array.isArray(s)){if(\"compressed\"===s.type){if(!r)return console.debug(\"OR WebWorker: sender not initialised. Compressed batch.\"),void g();s.batch&&r.sendCompressed(s.batch)}if(\"uncompressed\"===s.type){if(!r)return console.debug(\"OR WebWorker: sender not initialised. Uncompressed batch.\"),void g();s.batch&&r.sendUncompressed(s.batch)}return\"start\"===s.type?(u=h.Starting,r=new t(s.ingestPoint,(()=>{g()}),(t=>{!function(t){postMessage({type:\"failure\",reason:t}),c()}(t)}),s.connAttemptCount,s.connAttemptGap,(t=>{postMessage({type:\"compress\",batch:t},[t.buffer])}),s.pageNo),a=new n(s.pageNo,s.timestamp,s.url,((t,s)=>{r&&(s?r.sendUncompressed(t):r.push(t))}),s.tabId,(()=>postMessage({type:\"queue_empty\"}))),null===p&&(p=setInterval(o,3e4)),u=h.Active):\"auth\"===s.type?r?a?(r.authorise(s.token),void(s.beaconSizeLimit&&a.setBeaconSizeLimit(s.beaconSizeLimit))):(console.debug(\"OR WebWorker: writer not initialised. Received auth.\"),void g()):(console.debug(\"OR WebWorker: sender not initialised. Received auth.\"),void g()):void 0}if(a){const t=a;s.forEach((s=>{55===s[0]&&(s[1]?l=setTimeout((()=>g()),18e5):clearTimeout(l)),t.writeMessage(s)}))}else postMessage(\"not_init\"),g()}else o(!0);else o()}}();\n";
|
|
5389
|
+
const workerBodyFn = "!function(){\"use strict\";class t{constructor(t,s,i,e=10,n=250,h,r){this.onUnauthorised=s,this.onFailure=i,this.MAX_ATTEMPTS_COUNT=e,this.ATTEMPT_TIMEOUT=n,this.onCompress=h,this.pageNo=r,this.attemptsCount=0,this.busy=!1,this.queue=[],this.token=null,this.lastBatchNum=0,this.ingestURL=t+\"/v1/web/i\",this.isCompressing=void 0!==h}getQueueStatus(){return 0===this.queue.length&&!this.busy}authorise(t){this.token=t,this.busy||this.sendNext()}push(t){if(this.busy||!this.token)this.queue.push(t);else if(this.busy=!0,this.isCompressing&&this.onCompress)this.onCompress(t);else{const s=++this.lastBatchNum;this.sendBatch(t,!1,s)}}sendNext(){const t=this.queue.shift();if(t)if(this.busy=!0,this.isCompressing&&this.onCompress)this.onCompress(t);else{const s=++this.lastBatchNum;this.sendBatch(t,!1,s)}else this.busy=!1}retry(t,s,i){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`):(this.attemptsCount++,setTimeout((()=>this.sendBatch(t,s,i)),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t,s,i){var e;const n=null==i?void 0:i.toString().replace(/^([^_]+)_([^_]+).*/,\"$1_$2_$3\");this.busy=!0;const h={Authorization:`Bearer ${this.token}`};s&&(h[\"Content-Encoding\"]=\"gzip\"),null!==this.token?fetch(`${this.ingestURL}?batch=${null!==(e=this.pageNo)&&void 0!==e?e:\"noPageNum\"}_${null!=n?n:\"noBatchNum\"}`,{body:t,method:\"POST\",headers:h,keepalive:t.length<65536}).then((e=>{if(401===e.status)return this.busy=!1,void this.onUnauthorised();e.status>=400?this.retry(t,s,`${null!=i?i:\"noBatchNum\"}_network:${e.status}`):(this.attemptsCount=0,this.sendNext())})).catch((e=>{console.warn(\"OpenReplay:\",e),this.retry(t,s,`${null!=i?i:\"noBatchNum\"}_reject:${e.message}`)})):setTimeout((()=>{this.sendBatch(t,s,`${null!=i?i:\"noBatchNum\"}_newToken`)}),500)}sendCompressed(t){const s=++this.lastBatchNum;this.sendBatch(t,!0,s)}sendUncompressed(t){const s=++this.lastBatchNum;this.sendBatch(t,!1,s)}clean(){this.sendNext(),setTimeout((()=>{this.token=null,this.queue.length=0}),10)}}const s=\"function\"==typeof TextEncoder?new TextEncoder:{encode(t){const s=t.length,i=new Uint8Array(3*s);let e=-1;for(let n=0,h=0,r=0;r!==s;){if(n=t.charCodeAt(r),r+=1,n>=55296&&n<=56319){if(r===s){i[e+=1]=239,i[e+=1]=191,i[e+=1]=189;break}if(h=t.charCodeAt(r),!(h>=56320&&h<=57343)){i[e+=1]=239,i[e+=1]=191,i[e+=1]=189;continue}if(n=1024*(n-55296)+h-56320+65536,r+=1,n>65535){i[e+=1]=240|n>>>18,i[e+=1]=128|n>>>12&63,i[e+=1]=128|n>>>6&63,i[e+=1]=128|63&n;continue}}n<=127?i[e+=1]=0|n:n<=2047?(i[e+=1]=192|n>>>6,i[e+=1]=128|63&n):(i[e+=1]=224|n>>>12,i[e+=1]=128|n>>>6&63,i[e+=1]=128|63&n)}return i.subarray(0,e+1)}};class i{constructor(t){this.size=t,this.offset=0,this.checkpointOffset=0,this.data=new Uint8Array(t)}getCurrentOffset(){return this.offset}checkpoint(){this.checkpointOffset=this.offset}get isEmpty(){return 0===this.offset}skip(t){return this.offset+=t,this.offset<=this.size}set(t,s){this.data.set(t,s)}boolean(t){return this.data[this.offset++]=+t,this.offset<=this.size}uint(t){for((t<0||t>Number.MAX_SAFE_INTEGER)&&(t=0);t>=128;)this.data[this.offset++]=t%256|128,t=Math.floor(t/128);return this.data[this.offset++]=t,this.offset<=this.size}int(t){return t=Math.round(t),this.uint(t>=0?2*t:-2*t-1)}string(t){const i=s.encode(t),e=i.byteLength;return!(!this.uint(e)||this.offset+e>this.size)&&(this.data.set(i,this.offset),this.offset+=e,!0)}reset(){this.offset=0,this.checkpointOffset=0}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}class e extends i{encode(t){switch(t[0]){case 0:case 11:case 114:case 115:return this.uint(t[1]);case 4:case 44:case 47:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 5:case 20:case 38:case 65:case 70:case 75:case 76:case 77:case 82:return this.uint(t[1])&&this.uint(t[2]);case 6:return this.int(t[1])&&this.int(t[2]);case 7:return!0;case 8:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.string(t[4])&&this.boolean(t[5]);case 9:case 10:case 24:case 35:case 51:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 12:case 52:case 61:case 71:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 13:case 14:case 17:case 34:case 36:case 50:case 54:return this.uint(t[1])&&this.string(t[2]);case 16:return this.uint(t[1])&&this.int(t[2])&&this.int(t[3]);case 18:return this.uint(t[1])&&this.string(t[2])&&this.int(t[3]);case 19:return this.uint(t[1])&&this.boolean(t[2]);case 21:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.string(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8]);case 22:case 27:case 30:case 41:case 45:case 46:case 43:case 63:case 64:case 79:case 124:return this.string(t[1])&&this.string(t[2]);case 23:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8])&&this.uint(t[9]);case 28:case 29:case 42:case 117:case 118:return this.string(t[1]);case 37:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3]);case 39:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7]);case 40:return this.string(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 48:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.int(t[5]);case 49:return this.int(t[1])&&this.int(t[2])&&this.uint(t[3])&&this.uint(t[4]);case 53:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8]);case 55:return this.boolean(t[1]);case 57:case 60:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 58:case 120:return this.int(t[1]);case 59:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.string(t[5])&&this.string(t[6])&&this.string(t[7]);case 67:case 73:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 68:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])&&this.uint(t[6]);case 69:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 78:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 81:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.int(t[4])&&this.string(t[5]);case 83:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.string(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8])&&this.uint(t[9]);case 84:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.uint(t[4])&&this.string(t[5])&&this.string(t[6]);case 85:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8])&&this.uint(t[9])&&this.boolean(t[10])&&this.uint(t[11])&&this.uint(t[12])&&this.uint(t[13])&&this.uint(t[14])&&this.uint(t[15])&&this.uint(t[16])&&this.uint(t[17]);case 87:return this.string(t[1])&&this.int(t[2])&&this.int(t[3]);case 89:return this.string(t[1])&&this.int(t[2])&&this.int(t[3])&&this.int(t[4])&&this.int(t[5])&&this.string(t[6]);case 112:return this.uint(t[1])&&this.string(t[2])&&this.boolean(t[3])&&this.string(t[4])&&this.int(t[5])&&this.int(t[6]);case 113:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3]);case 116:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8])&&this.uint(t[9])&&this.boolean(t[10]);case 119:return this.string(t[1])&&this.uint(t[2]);case 121:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.uint(t[4]);case 122:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 123:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])}}}class n{constructor(t,s,i,n,h,r){this.pageNo=t,this.timestamp=s,this.url=i,this.onBatch=n,this.tabId=h,this.onOfflineEnd=r,this.nextIndex=0,this.beaconSize=2e5,this.encoder=new e(this.beaconSize),this.sizeBuffer=new Uint8Array(3),this.isEmpty=!0,this.checkpoints=[],this.beaconSizeLimit=1e6,this.prepare()}writeType(t){return this.encoder.uint(t[0])}writeFields(t){return this.encoder.encode(t)}writeSizeAt(t,s){for(let s=0;s<3;s++)this.sizeBuffer[s]=t>>8*s;this.encoder.set(this.sizeBuffer,s)}prepare(){if(!this.encoder.isEmpty)return;this.checkpoints.length=0;const t=[81,1,this.pageNo,this.nextIndex,this.timestamp,this.url],s=[0,this.timestamp],i=[118,this.tabId];this.writeType(t),this.writeFields(t),this.writeWithSize(s),this.writeWithSize(i),this.isEmpty=!0}writeWithSize(t){const s=this.encoder;if(!this.writeType(t)||!s.skip(3))return!1;const i=s.getCurrentOffset(),e=this.writeFields(t);if(e){const e=s.getCurrentOffset()-i;if(e>16777215)return console.warn(\"OpenReplay: max message size overflow.\"),!1;this.writeSizeAt(e,i-3),s.checkpoint(),this.checkpoints.push(s.getCurrentOffset()),this.isEmpty=this.isEmpty&&0===t[0],this.nextIndex++}return e}setBeaconSizeLimit(t){this.beaconSizeLimit=t}writeMessage(t){if(-1===t[0])return this.finaliseBatch(),this.onOfflineEnd();0===t[0]&&(this.timestamp=t[1]),122===t[0]&&(this.url=t[1]),this.writeWithSize(t)||(this.finaliseBatch(),this.writeWithSize(t)||(this.encoder=new e(this.beaconSizeLimit),this.prepare(),this.writeWithSize(t)?this.finaliseBatch():console.warn(\"OpenReplay: beacon size overflow. Skipping large message.\",t,this),this.encoder=new e(this.beaconSize),this.prepare()))}finaliseBatch(t=!1){if(this.isEmpty)return;const s=this.encoder.flush();this.onBatch(s,t),this.prepare()}clean(){this.encoder.reset(),this.checkpoints.length=0}}var h;!function(t){t[t.NotActive=0]=\"NotActive\",t[t.Starting=1]=\"Starting\",t[t.Stopping=2]=\"Stopping\",t[t.Active=3]=\"Active\",t[t.Stopped=4]=\"Stopped\"}(h||(h={}));let r=null,u=null,a=h.NotActive;function o(t){u&&u.finaliseBatch(t)}function c(){return new Promise((t=>{a=h.Stopping,null!==p&&(clearInterval(p),p=null),u&&(u.clean(),u=null),r&&(r.clean(),setTimeout((()=>{r=null}),20)),setTimeout((()=>{a=h.NotActive,t(null)}),100)}))}function g(){[h.Stopped,h.Stopping].includes(a)||(postMessage(\"a_stop\"),c().then((()=>{postMessage(\"a_start\")})))}let l,p=null;self.onmessage=({data:s})=>{if(\"stop\"===s)return o(),void c().then((()=>{a=h.Stopped}));if(\"forceFlushBatch\"!==s)if(\"closing\"!==s){if(!Array.isArray(s)){if(\"compressed\"===s.type){if(!r)return console.debug(\"OR WebWorker: sender not initialised. Compressed batch.\"),void g();s.batch&&r.sendCompressed(s.batch)}if(\"uncompressed\"===s.type){if(!r)return console.debug(\"OR WebWorker: sender not initialised. Uncompressed batch.\"),void g();s.batch&&r.sendUncompressed(s.batch)}return\"start\"===s.type?(a=h.Starting,r=new t(s.ingestPoint,(()=>{g()}),(t=>{!function(t){postMessage({type:\"failure\",reason:t}),c()}(t)}),s.connAttemptCount,s.connAttemptGap,(t=>{postMessage({type:\"compress\",batch:t},[t.buffer])}),s.pageNo),u=new n(s.pageNo,s.timestamp,s.url,((t,s)=>{r&&(s?r.sendUncompressed(t):r.push(t))}),s.tabId,(()=>postMessage({type:\"queue_empty\"}))),null===p&&(p=setInterval(o,3e4)),a=h.Active):\"auth\"===s.type?r?u?(r.authorise(s.token),void(s.beaconSizeLimit&&u.setBeaconSizeLimit(s.beaconSizeLimit))):(console.debug(\"OR WebWorker: writer not initialised. Received auth.\"),void g()):(console.debug(\"OR WebWorker: sender not initialised. Received auth.\"),void g()):void 0}if(u){const t=u;s.forEach((s=>{55===s[0]&&(s[1]?l=setTimeout((()=>g()),18e5):clearTimeout(l)),t.writeMessage(s)}))}else postMessage(\"not_init\"),g()}else o(!0);else o()}}();\n";
|
|
5242
5390
|
const CANCELED = 'canceled';
|
|
5243
5391
|
const uxtStorageKey = 'or_uxt_active';
|
|
5244
5392
|
const bufferStorageKey = 'or_buffer_1';
|
|
@@ -5292,7 +5440,7 @@ class App {
|
|
|
5292
5440
|
this.stopCallbacks = [];
|
|
5293
5441
|
this.commitCallbacks = [];
|
|
5294
5442
|
this.activityState = ActivityState.NotActive;
|
|
5295
|
-
this.version = '16.4.
|
|
5443
|
+
this.version = '16.4.11-beta.0'; // TODO: version compatability check inside each plugin.
|
|
5296
5444
|
this.socketMode = false;
|
|
5297
5445
|
this.compressionThreshold = 24 * 1000;
|
|
5298
5446
|
this.bc = null;
|
|
@@ -5302,8 +5450,10 @@ class App {
|
|
|
5302
5450
|
this.rootId = null;
|
|
5303
5451
|
this.pageFrames = [];
|
|
5304
5452
|
this.frameOderNumber = 0;
|
|
5305
|
-
this.
|
|
5306
|
-
|
|
5453
|
+
this.features = {
|
|
5454
|
+
'feature-flags': true,
|
|
5455
|
+
'usability-test': true,
|
|
5456
|
+
};
|
|
5307
5457
|
this.emptyBatchCounter = 0;
|
|
5308
5458
|
/** used by child iframes for crossdomain only */
|
|
5309
5459
|
this.parentActive = false;
|
|
@@ -5333,7 +5483,6 @@ class App {
|
|
|
5333
5483
|
this.rootId = data.id;
|
|
5334
5484
|
this.session.setSessionToken(data.token, this.projectKey);
|
|
5335
5485
|
this.frameOderNumber = data.frameOrderNumber;
|
|
5336
|
-
this.frameLevel = data.frameLevel;
|
|
5337
5486
|
this.debug.log('starting iframe tracking', data);
|
|
5338
5487
|
this.allowAppStart();
|
|
5339
5488
|
}
|
|
@@ -5383,8 +5532,8 @@ class App {
|
|
|
5383
5532
|
line: proto.iframeId,
|
|
5384
5533
|
id,
|
|
5385
5534
|
token,
|
|
5535
|
+
// since indexes go from 0 we +1
|
|
5386
5536
|
frameOrderNumber: order,
|
|
5387
|
-
frameLevel: this.frameLevel + 1,
|
|
5388
5537
|
};
|
|
5389
5538
|
this.debug.log('Got child frame signal; nodeId', id, event.source, iframeData);
|
|
5390
5539
|
// @ts-ignore
|
|
@@ -5395,13 +5544,6 @@ class App {
|
|
|
5395
5544
|
}
|
|
5396
5545
|
};
|
|
5397
5546
|
void signalId();
|
|
5398
|
-
if (this.active()) {
|
|
5399
|
-
// @ts-ignore
|
|
5400
|
-
event.source?.postMessage({ line: proto.startIframe }, '*');
|
|
5401
|
-
}
|
|
5402
|
-
else {
|
|
5403
|
-
this.addCommand(proto.startIframe);
|
|
5404
|
-
}
|
|
5405
5547
|
}
|
|
5406
5548
|
/**
|
|
5407
5549
|
* proxying messages from iframe to main body, so they can be in one batch (same indexes, etc)
|
|
@@ -5586,170 +5728,9 @@ class App {
|
|
|
5586
5728
|
this.orderNumber = 0;
|
|
5587
5729
|
this.coldStartTs = 0;
|
|
5588
5730
|
this.singleBuffer = false;
|
|
5589
|
-
/**
|
|
5590
|
-
* start buffering messages without starting the actual session, which gives
|
|
5591
|
-
* user 30 seconds to "activate" and record session by calling `start()` on conditional trigger,
|
|
5592
|
-
* and we will then send buffered batch, so it won't get lost
|
|
5593
|
-
* */
|
|
5594
|
-
this.coldStart = async (startOpts = {}, conditional) => {
|
|
5595
|
-
this.singleBuffer = false;
|
|
5596
|
-
const second = 1000;
|
|
5597
|
-
const isNewSession = this.checkSessionToken(startOpts.forceNew);
|
|
5598
|
-
if (conditional) {
|
|
5599
|
-
await this.setupConditionalStart(startOpts);
|
|
5600
|
-
}
|
|
5601
|
-
const cycle = () => {
|
|
5602
|
-
this.orderNumber += 1;
|
|
5603
|
-
adjustTimeOrigin();
|
|
5604
|
-
this.coldStartTs = now();
|
|
5605
|
-
if (this.orderNumber % 2 === 0) {
|
|
5606
|
-
this.bufferedMessages1.length = 0;
|
|
5607
|
-
this.bufferedMessages1.push(Timestamp(this.timestamp()));
|
|
5608
|
-
this.bufferedMessages1.push(TabData(this.session.getTabId()));
|
|
5609
|
-
}
|
|
5610
|
-
else {
|
|
5611
|
-
this.bufferedMessages2.length = 0;
|
|
5612
|
-
this.bufferedMessages2.push(Timestamp(this.timestamp()));
|
|
5613
|
-
this.bufferedMessages2.push(TabData(this.session.getTabId()));
|
|
5614
|
-
}
|
|
5615
|
-
this.stop(false);
|
|
5616
|
-
this.activityState = ActivityState.ColdStart;
|
|
5617
|
-
if (startOpts.sessionHash) {
|
|
5618
|
-
this.session.applySessionHash(startOpts.sessionHash);
|
|
5619
|
-
}
|
|
5620
|
-
if (startOpts.forceNew) {
|
|
5621
|
-
this.session.reset();
|
|
5622
|
-
}
|
|
5623
|
-
this.session.assign({
|
|
5624
|
-
userID: startOpts.userID,
|
|
5625
|
-
metadata: startOpts.metadata,
|
|
5626
|
-
});
|
|
5627
|
-
if (!isNewSession) {
|
|
5628
|
-
this.debug.log('continuing session on new tab', this.session.getTabId());
|
|
5629
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
5630
|
-
this.send(TabChange(this.session.getTabId()));
|
|
5631
|
-
}
|
|
5632
|
-
this.observer.observe();
|
|
5633
|
-
this.ticker.start();
|
|
5634
|
-
};
|
|
5635
|
-
this.coldInterval = setInterval(() => {
|
|
5636
|
-
cycle();
|
|
5637
|
-
}, 30 * second);
|
|
5638
|
-
cycle();
|
|
5639
|
-
};
|
|
5640
|
-
this.setupConditionalStart = async (startOpts) => {
|
|
5641
|
-
this.conditionsManager = new ConditionsManager(this, startOpts);
|
|
5642
|
-
const r = await fetch(this.options.ingestPoint + '/v1/web/start', {
|
|
5643
|
-
method: 'POST',
|
|
5644
|
-
headers: {
|
|
5645
|
-
'Content-Type': 'application/json',
|
|
5646
|
-
},
|
|
5647
|
-
body: JSON.stringify({
|
|
5648
|
-
...this.getTrackerInfo(),
|
|
5649
|
-
timestamp: now(),
|
|
5650
|
-
doNotRecord: true,
|
|
5651
|
-
bufferDiff: 0,
|
|
5652
|
-
userID: this.session.getInfo().userID,
|
|
5653
|
-
token: undefined,
|
|
5654
|
-
deviceMemory,
|
|
5655
|
-
jsHeapSizeLimit,
|
|
5656
|
-
timezone: getTimezone(),
|
|
5657
|
-
width: window.screen.width,
|
|
5658
|
-
height: window.screen.height,
|
|
5659
|
-
}),
|
|
5660
|
-
});
|
|
5661
|
-
const {
|
|
5662
|
-
// this token is needed to fetch conditions and flags,
|
|
5663
|
-
// but it can't be used to record a session
|
|
5664
|
-
token, userBrowser, userCity, userCountry, userDevice, userOS, userState, projectID, features, } = await r.json();
|
|
5665
|
-
this.features = features ? features : this.features;
|
|
5666
|
-
this.session.assign({ projectID });
|
|
5667
|
-
this.session.setUserInfo({
|
|
5668
|
-
userBrowser,
|
|
5669
|
-
userCity,
|
|
5670
|
-
userCountry,
|
|
5671
|
-
userDevice,
|
|
5672
|
-
userOS,
|
|
5673
|
-
userState,
|
|
5674
|
-
});
|
|
5675
|
-
const onStartInfo = { sessionToken: token, userUUID: '', sessionID: '' };
|
|
5676
|
-
this.startCallbacks.forEach((cb) => cb(onStartInfo));
|
|
5677
|
-
await this.conditionsManager?.fetchConditions(projectID, token);
|
|
5678
|
-
if (this.features['feature-flags']) {
|
|
5679
|
-
await this.featureFlags.reloadFlags(token);
|
|
5680
|
-
this.conditionsManager?.processFlags(this.featureFlags.flags);
|
|
5681
|
-
}
|
|
5682
|
-
await this.tagWatcher.fetchTags(this.options.ingestPoint, token);
|
|
5683
|
-
};
|
|
5684
5731
|
this.onSessionSent = () => {
|
|
5685
5732
|
return;
|
|
5686
5733
|
};
|
|
5687
|
-
/**
|
|
5688
|
-
* Starts offline session recording
|
|
5689
|
-
* @param {Object} startOpts - options for session start, same as .start()
|
|
5690
|
-
* @param {Function} onSessionSent - callback that will be called once session is fully sent
|
|
5691
|
-
* */
|
|
5692
|
-
this.offlineRecording = (startOpts = {}, onSessionSent) => {
|
|
5693
|
-
this.onSessionSent = onSessionSent;
|
|
5694
|
-
this.singleBuffer = true;
|
|
5695
|
-
const isNewSession = this.checkSessionToken(startOpts.forceNew);
|
|
5696
|
-
adjustTimeOrigin();
|
|
5697
|
-
this.coldStartTs = now();
|
|
5698
|
-
const saverBuffer = this.localStorage.getItem(bufferStorageKey);
|
|
5699
|
-
if (saverBuffer) {
|
|
5700
|
-
const data = JSON.parse(saverBuffer);
|
|
5701
|
-
this.bufferedMessages1 = Array.isArray(data) ? data : this.bufferedMessages1;
|
|
5702
|
-
this.localStorage.removeItem(bufferStorageKey);
|
|
5703
|
-
}
|
|
5704
|
-
this.bufferedMessages1.push(Timestamp(this.timestamp()));
|
|
5705
|
-
this.bufferedMessages1.push(TabData(this.session.getTabId()));
|
|
5706
|
-
this.activityState = ActivityState.ColdStart;
|
|
5707
|
-
if (startOpts.sessionHash) {
|
|
5708
|
-
this.session.applySessionHash(startOpts.sessionHash);
|
|
5709
|
-
}
|
|
5710
|
-
if (startOpts.forceNew) {
|
|
5711
|
-
this.session.reset();
|
|
5712
|
-
}
|
|
5713
|
-
this.session.assign({
|
|
5714
|
-
userID: startOpts.userID,
|
|
5715
|
-
metadata: startOpts.metadata,
|
|
5716
|
-
});
|
|
5717
|
-
const onStartInfo = { sessionToken: '', userUUID: '', sessionID: '' };
|
|
5718
|
-
this.startCallbacks.forEach((cb) => cb(onStartInfo));
|
|
5719
|
-
if (!isNewSession) {
|
|
5720
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
5721
|
-
this.send(TabChange(this.session.getTabId()));
|
|
5722
|
-
}
|
|
5723
|
-
this.observer.observe();
|
|
5724
|
-
this.ticker.start();
|
|
5725
|
-
return {
|
|
5726
|
-
saveBuffer: this.saveBuffer,
|
|
5727
|
-
getBuffer: this.getBuffer,
|
|
5728
|
-
setBuffer: this.setBuffer,
|
|
5729
|
-
};
|
|
5730
|
-
};
|
|
5731
|
-
/**
|
|
5732
|
-
* Saves the captured messages in localStorage (or whatever is used in its place)
|
|
5733
|
-
*
|
|
5734
|
-
* Then, when this.offlineRecording is called, it will preload this messages and clear the storage item
|
|
5735
|
-
*
|
|
5736
|
-
* Keeping the size of local storage reasonable is up to the end users of this library
|
|
5737
|
-
* */
|
|
5738
|
-
this.saveBuffer = () => {
|
|
5739
|
-
this.localStorage.setItem(bufferStorageKey, JSON.stringify(this.bufferedMessages1));
|
|
5740
|
-
};
|
|
5741
|
-
/**
|
|
5742
|
-
* @returns buffer with stored messages for offline recording
|
|
5743
|
-
* */
|
|
5744
|
-
this.getBuffer = () => {
|
|
5745
|
-
return this.bufferedMessages1;
|
|
5746
|
-
};
|
|
5747
|
-
/**
|
|
5748
|
-
* Used to set a buffer with messages array
|
|
5749
|
-
* */
|
|
5750
|
-
this.setBuffer = (buffer) => {
|
|
5751
|
-
this.bufferedMessages1 = buffer;
|
|
5752
|
-
};
|
|
5753
5734
|
this.prevOpts = {};
|
|
5754
5735
|
this.restartCanvasTracking = () => {
|
|
5755
5736
|
this.canvasRecorder?.restartTracking();
|
|
@@ -5816,6 +5797,7 @@ class App {
|
|
|
5816
5797
|
forceNgOff: false,
|
|
5817
5798
|
inlineCss: 0,
|
|
5818
5799
|
disableSprites: false,
|
|
5800
|
+
disableThrottling: false,
|
|
5819
5801
|
};
|
|
5820
5802
|
this.options = simpleMerge(defaultOptions, options);
|
|
5821
5803
|
if (!this.insideIframe &&
|
|
@@ -5871,11 +5853,7 @@ class App {
|
|
|
5871
5853
|
* listen for messages from parent window, so we can signal that we're alive
|
|
5872
5854
|
* */
|
|
5873
5855
|
window.addEventListener('message', this.parentCrossDomainFrameListener);
|
|
5874
|
-
window.addEventListener('message', this.crossDomainIframeListener);
|
|
5875
5856
|
setInterval(() => {
|
|
5876
|
-
if (document.hidden) {
|
|
5877
|
-
return;
|
|
5878
|
-
}
|
|
5879
5857
|
window.parent.postMessage({
|
|
5880
5858
|
line: proto.polling,
|
|
5881
5859
|
context: this.contextId,
|
|
@@ -6258,6 +6236,167 @@ class App {
|
|
|
6258
6236
|
const sessionToken = this.session.getSessionToken(this.projectKey);
|
|
6259
6237
|
return needNewSessionID || !sessionToken;
|
|
6260
6238
|
}
|
|
6239
|
+
/**
|
|
6240
|
+
* start buffering messages without starting the actual session, which gives
|
|
6241
|
+
* user 30 seconds to "activate" and record session by calling `start()` on conditional trigger,
|
|
6242
|
+
* and we will then send buffered batch, so it won't get lost
|
|
6243
|
+
* */
|
|
6244
|
+
async coldStart(startOpts = {}, conditional) {
|
|
6245
|
+
this.singleBuffer = false;
|
|
6246
|
+
const second = 1000;
|
|
6247
|
+
const isNewSession = this.checkSessionToken(startOpts.forceNew);
|
|
6248
|
+
if (conditional) {
|
|
6249
|
+
await this.setupConditionalStart(startOpts);
|
|
6250
|
+
}
|
|
6251
|
+
const cycle = () => {
|
|
6252
|
+
this.orderNumber += 1;
|
|
6253
|
+
adjustTimeOrigin();
|
|
6254
|
+
this.coldStartTs = now();
|
|
6255
|
+
if (this.orderNumber % 2 === 0) {
|
|
6256
|
+
this.bufferedMessages1.length = 0;
|
|
6257
|
+
this.bufferedMessages1.push(Timestamp(this.timestamp()));
|
|
6258
|
+
this.bufferedMessages1.push(TabData(this.session.getTabId()));
|
|
6259
|
+
}
|
|
6260
|
+
else {
|
|
6261
|
+
this.bufferedMessages2.length = 0;
|
|
6262
|
+
this.bufferedMessages2.push(Timestamp(this.timestamp()));
|
|
6263
|
+
this.bufferedMessages2.push(TabData(this.session.getTabId()));
|
|
6264
|
+
}
|
|
6265
|
+
this.stop(false);
|
|
6266
|
+
this.activityState = ActivityState.ColdStart;
|
|
6267
|
+
if (startOpts.sessionHash) {
|
|
6268
|
+
this.session.applySessionHash(startOpts.sessionHash);
|
|
6269
|
+
}
|
|
6270
|
+
if (startOpts.forceNew) {
|
|
6271
|
+
this.session.reset();
|
|
6272
|
+
}
|
|
6273
|
+
this.session.assign({
|
|
6274
|
+
userID: startOpts.userID,
|
|
6275
|
+
metadata: startOpts.metadata,
|
|
6276
|
+
});
|
|
6277
|
+
if (!isNewSession) {
|
|
6278
|
+
this.debug.log('continuing session on new tab', this.session.getTabId());
|
|
6279
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
6280
|
+
this.send(TabChange(this.session.getTabId()));
|
|
6281
|
+
}
|
|
6282
|
+
this.observer.observe();
|
|
6283
|
+
this.ticker.start();
|
|
6284
|
+
};
|
|
6285
|
+
this.coldInterval = setInterval(() => {
|
|
6286
|
+
cycle();
|
|
6287
|
+
}, 30 * second);
|
|
6288
|
+
cycle();
|
|
6289
|
+
}
|
|
6290
|
+
async setupConditionalStart(startOpts) {
|
|
6291
|
+
this.conditionsManager = new ConditionsManager(this, startOpts);
|
|
6292
|
+
const r = await fetch(this.options.ingestPoint + '/v1/web/start', {
|
|
6293
|
+
method: 'POST',
|
|
6294
|
+
headers: {
|
|
6295
|
+
'Content-Type': 'application/json',
|
|
6296
|
+
},
|
|
6297
|
+
body: JSON.stringify({
|
|
6298
|
+
...this.getTrackerInfo(),
|
|
6299
|
+
timestamp: now(),
|
|
6300
|
+
doNotRecord: true,
|
|
6301
|
+
bufferDiff: 0,
|
|
6302
|
+
userID: this.session.getInfo().userID,
|
|
6303
|
+
token: undefined,
|
|
6304
|
+
deviceMemory,
|
|
6305
|
+
jsHeapSizeLimit,
|
|
6306
|
+
timezone: getTimezone(),
|
|
6307
|
+
width: window.screen.width,
|
|
6308
|
+
height: window.screen.height,
|
|
6309
|
+
}),
|
|
6310
|
+
});
|
|
6311
|
+
const {
|
|
6312
|
+
// this token is needed to fetch conditions and flags,
|
|
6313
|
+
// but it can't be used to record a session
|
|
6314
|
+
token, userBrowser, userCity, userCountry, userDevice, userOS, userState, projectID, features, } = await r.json();
|
|
6315
|
+
this.features = features ? features : this.features;
|
|
6316
|
+
this.session.assign({ projectID });
|
|
6317
|
+
this.session.setUserInfo({
|
|
6318
|
+
userBrowser,
|
|
6319
|
+
userCity,
|
|
6320
|
+
userCountry,
|
|
6321
|
+
userDevice,
|
|
6322
|
+
userOS,
|
|
6323
|
+
userState,
|
|
6324
|
+
});
|
|
6325
|
+
const onStartInfo = { sessionToken: token, userUUID: '', sessionID: '' };
|
|
6326
|
+
this.startCallbacks.forEach((cb) => cb(onStartInfo));
|
|
6327
|
+
await this.conditionsManager?.fetchConditions(projectID, token);
|
|
6328
|
+
if (this.features['feature-flags']) {
|
|
6329
|
+
await this.featureFlags.reloadFlags(token);
|
|
6330
|
+
this.conditionsManager?.processFlags(this.featureFlags.flags);
|
|
6331
|
+
}
|
|
6332
|
+
await this.tagWatcher.fetchTags(this.options.ingestPoint, token);
|
|
6333
|
+
}
|
|
6334
|
+
/**
|
|
6335
|
+
* Starts offline session recording
|
|
6336
|
+
* @param {Object} startOpts - options for session start, same as .start()
|
|
6337
|
+
* @param {Function} onSessionSent - callback that will be called once session is fully sent
|
|
6338
|
+
* */
|
|
6339
|
+
offlineRecording(startOpts = {}, onSessionSent) {
|
|
6340
|
+
this.onSessionSent = onSessionSent;
|
|
6341
|
+
this.singleBuffer = true;
|
|
6342
|
+
const isNewSession = this.checkSessionToken(startOpts.forceNew);
|
|
6343
|
+
adjustTimeOrigin();
|
|
6344
|
+
this.coldStartTs = now();
|
|
6345
|
+
const saverBuffer = this.localStorage.getItem(bufferStorageKey);
|
|
6346
|
+
if (saverBuffer) {
|
|
6347
|
+
const data = JSON.parse(saverBuffer);
|
|
6348
|
+
this.bufferedMessages1 = Array.isArray(data) ? data : this.bufferedMessages1;
|
|
6349
|
+
this.localStorage.removeItem(bufferStorageKey);
|
|
6350
|
+
}
|
|
6351
|
+
this.bufferedMessages1.push(Timestamp(this.timestamp()));
|
|
6352
|
+
this.bufferedMessages1.push(TabData(this.session.getTabId()));
|
|
6353
|
+
this.activityState = ActivityState.ColdStart;
|
|
6354
|
+
if (startOpts.sessionHash) {
|
|
6355
|
+
this.session.applySessionHash(startOpts.sessionHash);
|
|
6356
|
+
}
|
|
6357
|
+
if (startOpts.forceNew) {
|
|
6358
|
+
this.session.reset();
|
|
6359
|
+
}
|
|
6360
|
+
this.session.assign({
|
|
6361
|
+
userID: startOpts.userID,
|
|
6362
|
+
metadata: startOpts.metadata,
|
|
6363
|
+
});
|
|
6364
|
+
const onStartInfo = { sessionToken: '', userUUID: '', sessionID: '' };
|
|
6365
|
+
this.startCallbacks.forEach((cb) => cb(onStartInfo));
|
|
6366
|
+
if (!isNewSession) {
|
|
6367
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
6368
|
+
this.send(TabChange(this.session.getTabId()));
|
|
6369
|
+
}
|
|
6370
|
+
this.observer.observe();
|
|
6371
|
+
this.ticker.start();
|
|
6372
|
+
return {
|
|
6373
|
+
saveBuffer: this.saveBuffer,
|
|
6374
|
+
getBuffer: this.getBuffer,
|
|
6375
|
+
setBuffer: this.setBuffer,
|
|
6376
|
+
};
|
|
6377
|
+
}
|
|
6378
|
+
/**
|
|
6379
|
+
* Saves the captured messages in localStorage (or whatever is used in its place)
|
|
6380
|
+
*
|
|
6381
|
+
* Then, when this.offlineRecording is called, it will preload this messages and clear the storage item
|
|
6382
|
+
*
|
|
6383
|
+
* Keeping the size of local storage reasonable is up to the end users of this library
|
|
6384
|
+
* */
|
|
6385
|
+
saveBuffer() {
|
|
6386
|
+
this.localStorage.setItem(bufferStorageKey, JSON.stringify(this.bufferedMessages1));
|
|
6387
|
+
}
|
|
6388
|
+
/**
|
|
6389
|
+
* @returns buffer with stored messages for offline recording
|
|
6390
|
+
* */
|
|
6391
|
+
getBuffer() {
|
|
6392
|
+
return this.bufferedMessages1;
|
|
6393
|
+
}
|
|
6394
|
+
/**
|
|
6395
|
+
* Used to set a buffer with messages array
|
|
6396
|
+
* */
|
|
6397
|
+
setBuffer(buffer) {
|
|
6398
|
+
this.bufferedMessages1 = buffer;
|
|
6399
|
+
}
|
|
6261
6400
|
/**
|
|
6262
6401
|
* Uploads the stored session buffer to backend
|
|
6263
6402
|
* @returns promise that resolves once messages are loaded, it has to be awaited
|
|
@@ -6313,7 +6452,7 @@ class App {
|
|
|
6313
6452
|
while (this.bufferedMessages1.length > 0) {
|
|
6314
6453
|
await this.flushBuffer(this.bufferedMessages1);
|
|
6315
6454
|
}
|
|
6316
|
-
this.postToWorker([[
|
|
6455
|
+
this.postToWorker([[-1]]);
|
|
6317
6456
|
this.clearBuffers();
|
|
6318
6457
|
}
|
|
6319
6458
|
async _start(startOpts = {}, resetByWorker = false, conditionName) {
|
|
@@ -6465,7 +6604,7 @@ class App {
|
|
|
6465
6604
|
}
|
|
6466
6605
|
await this.tagWatcher.fetchTags(this.options.ingestPoint, token);
|
|
6467
6606
|
this.activityState = ActivityState.Active;
|
|
6468
|
-
if (this.options.crossdomain?.enabled) {
|
|
6607
|
+
if (this.options.crossdomain?.enabled && !this.insideIframe) {
|
|
6469
6608
|
void this.bootChildrenFrames();
|
|
6470
6609
|
}
|
|
6471
6610
|
if (canvasEnabled && !this.options.canvas.disableCanvas) {
|
|
@@ -6491,15 +6630,13 @@ class App {
|
|
|
6491
6630
|
this.commit();
|
|
6492
6631
|
/** --------------- COLD START BUFFER ------------------*/
|
|
6493
6632
|
}
|
|
6633
|
+
if (this.insideIframe && this.rootId) {
|
|
6634
|
+
this.observer.crossdomainObserve(this.rootId, this.frameOderNumber);
|
|
6635
|
+
}
|
|
6494
6636
|
else {
|
|
6495
|
-
|
|
6496
|
-
this.observer.crossdomainObserve(this.rootId, this.frameOderNumber, this.frameLevel);
|
|
6497
|
-
}
|
|
6498
|
-
else {
|
|
6499
|
-
this.observer.observe();
|
|
6500
|
-
}
|
|
6501
|
-
this.ticker.start();
|
|
6637
|
+
this.observer.observe();
|
|
6502
6638
|
}
|
|
6639
|
+
this.ticker.start();
|
|
6503
6640
|
this.canvasRecorder?.startTracking();
|
|
6504
6641
|
if (this.features['usability-test'] && !this.insideIframe) {
|
|
6505
6642
|
this.uxtManager = this.uxtManager
|
|
@@ -6647,7 +6784,7 @@ class App {
|
|
|
6647
6784
|
stop(stopWorker = true) {
|
|
6648
6785
|
if (this.activityState !== ActivityState.NotActive) {
|
|
6649
6786
|
try {
|
|
6650
|
-
if (this.options.crossdomain?.enabled) {
|
|
6787
|
+
if (!this.insideIframe && this.options.crossdomain?.enabled) {
|
|
6651
6788
|
this.killChildrenFrames();
|
|
6652
6789
|
}
|
|
6653
6790
|
this.attributeSender.clear();
|
|
@@ -7102,7 +7239,7 @@ function Img (app) {
|
|
|
7102
7239
|
const sendImgError = app.safe(function (img) {
|
|
7103
7240
|
const resolvedSrc = resolveURL(img.src || ''); // Src type is null sometimes. - is it true?
|
|
7104
7241
|
if (isURL(resolvedSrc)) {
|
|
7105
|
-
app.send(ResourceTiming(app.timestamp(), 0, 0, 0, 0, 0, resolvedSrc, 'img', 0, false));
|
|
7242
|
+
app.send(ResourceTiming(app.timestamp(), 0, 0, 0, 0, 0, resolvedSrc, 'img', 0, false, 0, 0, 0, 0, 0, 0, 0));
|
|
7106
7243
|
}
|
|
7107
7244
|
});
|
|
7108
7245
|
const sendImgAttrs = app.safe(function (img) {
|
|
@@ -7706,18 +7843,38 @@ function Timing (app, opts) {
|
|
|
7706
7843
|
if (shouldSkip) {
|
|
7707
7844
|
return;
|
|
7708
7845
|
}
|
|
7846
|
+
// will probably require custom header added to responses for tracked requests:
|
|
7847
|
+
// Timing-Allow-Origin: *
|
|
7848
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Timing-Allow-Origin
|
|
7849
|
+
let stalled = 0;
|
|
7850
|
+
if (entry.connectEnd && entry.connectEnd > entry.domainLookupEnd) {
|
|
7851
|
+
// Usual case stalled is time between connection establishment and request start
|
|
7852
|
+
stalled = Math.max(0, entry.requestStart - entry.connectEnd);
|
|
7853
|
+
}
|
|
7854
|
+
else {
|
|
7855
|
+
// Connection reuse case - stalled is time between domain lookup and request start
|
|
7856
|
+
stalled = Math.max(0, entry.requestStart - entry.domainLookupEnd);
|
|
7857
|
+
}
|
|
7858
|
+
const timings = {
|
|
7859
|
+
queueing: entry.requestStart - entry.fetchStart,
|
|
7860
|
+
dnsLookup: entry.domainLookupEnd - entry.domainLookupStart,
|
|
7861
|
+
initialConnection: entry.connectEnd - entry.connectStart,
|
|
7862
|
+
ssl: entry.secureConnectionStart > 0 ? entry.connectEnd - entry.secureConnectionStart : 0,
|
|
7863
|
+
ttfb: entry.responseStart - entry.requestStart,
|
|
7864
|
+
contentDownload: entry.responseEnd - entry.responseStart,
|
|
7865
|
+
total: entry.duration ?? entry.responseEnd - entry.startTime,
|
|
7866
|
+
stalled,
|
|
7867
|
+
};
|
|
7709
7868
|
const entryName = options.resourceNameSanitizer
|
|
7710
7869
|
? options.resourceNameSanitizer(entry.name)
|
|
7711
7870
|
: entry.name;
|
|
7712
|
-
const cached =
|
|
7713
|
-
// @ts-ignore
|
|
7714
|
-
(entry.responseStatus && entry.responseStatus === 304) ||
|
|
7871
|
+
const cached = (entry.responseStatus && entry.responseStatus === 304) ||
|
|
7715
7872
|
// @ts-ignore
|
|
7716
7873
|
(entry.deliveryType && entry.deliveryType === 'cache') ||
|
|
7717
7874
|
(entry.transferSize === 0 && entry.decodedBodySize > 0);
|
|
7718
7875
|
const requestFailed = entry.responseStatus && entry.responseStatus >= 400;
|
|
7719
7876
|
const decodedBodySize = requestFailed ? -111 : entry.decodedBodySize || 0;
|
|
7720
|
-
app.send(ResourceTiming(entry.startTime + getTimeOrigin(), entry.duration,
|
|
7877
|
+
app.send(ResourceTiming(entry.startTime + getTimeOrigin(), entry.duration, timings.ttfb, entry.transferSize > entry.encodedBodySize ? entry.transferSize - entry.encodedBodySize : 0, entry.encodedBodySize || 0, decodedBodySize, app.sanitizer.privateMode ? entry.name.replaceAll(/./g, '*') : entryName, entry.initiatorType, entry.transferSize, cached, timings.queueing, timings.dnsLookup, timings.initialConnection, timings.ssl, timings.contentDownload, timings.total, timings.stalled));
|
|
7721
7878
|
}
|
|
7722
7879
|
const observer = new PerformanceObserver((list) => list.getEntries().forEach(resourceTiming));
|
|
7723
7880
|
function onVitalsSignal(msg) {
|
|
@@ -9664,8 +9821,86 @@ function Tabs (app) {
|
|
|
9664
9821
|
app.attachEventListener(window, 'focus', changeTab, false, false);
|
|
9665
9822
|
}
|
|
9666
9823
|
|
|
9824
|
+
function LongAnimationTask (app, opts) {
|
|
9825
|
+
if (!opts.longTasks || !('PerformanceObserver' in window)) {
|
|
9826
|
+
return;
|
|
9827
|
+
}
|
|
9828
|
+
const onEntry = (entry) => {
|
|
9829
|
+
app.send(LongAnimationTask$1(entry.name, entry.duration, entry.blockingDuration, entry.firstUIEventTimestamp, entry.startTime, JSON.stringify(entry.scripts ?? [])));
|
|
9830
|
+
};
|
|
9831
|
+
const observer = new PerformanceObserver((entryList) => {
|
|
9832
|
+
entryList.getEntries().forEach((entry) => {
|
|
9833
|
+
if (entry.entryType === 'long-animation-frame') {
|
|
9834
|
+
onEntry(entry);
|
|
9835
|
+
}
|
|
9836
|
+
});
|
|
9837
|
+
});
|
|
9838
|
+
app.attachStartCallback(() => {
|
|
9839
|
+
performance.getEntriesByType('long-animation-frame').forEach((lat) => {
|
|
9840
|
+
onEntry(lat);
|
|
9841
|
+
});
|
|
9842
|
+
observer.observe({
|
|
9843
|
+
entryTypes: ['long-animation-frame'],
|
|
9844
|
+
});
|
|
9845
|
+
});
|
|
9846
|
+
app.attachStopCallback(() => {
|
|
9847
|
+
observer.disconnect();
|
|
9848
|
+
});
|
|
9849
|
+
}
|
|
9850
|
+
|
|
9851
|
+
const toIgnore = ["composite", "computedOffset", "easing", "offset"];
|
|
9852
|
+
function webAnimations(app, options = {}) {
|
|
9853
|
+
const { allElements = false } = options;
|
|
9854
|
+
let listening = new WeakSet();
|
|
9855
|
+
let handled = new WeakSet();
|
|
9856
|
+
function wire(anim, el, nodeId) {
|
|
9857
|
+
if (handled.has(anim))
|
|
9858
|
+
return;
|
|
9859
|
+
handled.add(anim);
|
|
9860
|
+
anim.addEventListener('finish', () => {
|
|
9861
|
+
const lastKF = anim.effect.getKeyframes().at(-1);
|
|
9862
|
+
const computedStyle = getComputedStyle(el);
|
|
9863
|
+
const keys = Object.keys(lastKF).filter((p) => !toIgnore.includes(p));
|
|
9864
|
+
// @ts-ignore
|
|
9865
|
+
const finalStyle = {};
|
|
9866
|
+
keys.forEach((key) => {
|
|
9867
|
+
finalStyle[key] = computedStyle[key];
|
|
9868
|
+
});
|
|
9869
|
+
app.send(NodeAnimationResult(nodeId, JSON.stringify(finalStyle)));
|
|
9870
|
+
}, { once: true });
|
|
9871
|
+
}
|
|
9872
|
+
function scanElement(el, nodeId) {
|
|
9873
|
+
el.getAnimations({ subtree: false }).forEach((anim) => wire(anim, el, nodeId));
|
|
9874
|
+
}
|
|
9875
|
+
app.nodes.attachNodeCallback((node) => {
|
|
9876
|
+
if ((allElements || node.nodeName.includes('-')) && 'getAnimations' in node) {
|
|
9877
|
+
const animations = node.getAnimations({ subtree: false });
|
|
9878
|
+
const id = app.nodes.getID(node);
|
|
9879
|
+
if (animations.length > 0 && !listening.has(node) && id) {
|
|
9880
|
+
listening.add(node);
|
|
9881
|
+
scanElement(node, id);
|
|
9882
|
+
node.addEventListener('animationstart', () => scanElement(node, id));
|
|
9883
|
+
}
|
|
9884
|
+
}
|
|
9885
|
+
});
|
|
9886
|
+
const origAnimate = Element.prototype.animate;
|
|
9887
|
+
Element.prototype.animate = function (...args) {
|
|
9888
|
+
const anim = origAnimate.apply(this, args);
|
|
9889
|
+
const id = app.nodes.getID(this);
|
|
9890
|
+
if (!id)
|
|
9891
|
+
return anim;
|
|
9892
|
+
wire(anim, this, id);
|
|
9893
|
+
return anim;
|
|
9894
|
+
};
|
|
9895
|
+
app.attachStopCallback(() => {
|
|
9896
|
+
Element.prototype.animate = origAnimate; // Restore original animate method
|
|
9897
|
+
listening = new WeakSet();
|
|
9898
|
+
handled = new WeakSet();
|
|
9899
|
+
});
|
|
9900
|
+
}
|
|
9901
|
+
|
|
9667
9902
|
const Messages = _Messages;
|
|
9668
|
-
const DOCS_SETUP = '/en/sdk
|
|
9903
|
+
const DOCS_SETUP = '/en/sdk';
|
|
9669
9904
|
function processOptions(obj) {
|
|
9670
9905
|
if (obj == null) {
|
|
9671
9906
|
console.error(`OpenReplay: invalid options argument type. Please, check documentation on ${DOCS_HOST}${DOCS_SETUP}`);
|
|
@@ -9715,7 +9950,7 @@ class API {
|
|
|
9715
9950
|
this.signalStartIssue = (reason, missingApi) => {
|
|
9716
9951
|
const doNotTrack = this.checkDoNotTrack();
|
|
9717
9952
|
console.log("Tracker couldn't start due to:", JSON.stringify({
|
|
9718
|
-
trackerVersion: '16.4.
|
|
9953
|
+
trackerVersion: '16.4.11-beta.0',
|
|
9719
9954
|
projectKey: this.options.projectKey,
|
|
9720
9955
|
doNotTrack,
|
|
9721
9956
|
reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
|
|
@@ -9743,6 +9978,12 @@ class API {
|
|
|
9743
9978
|
}
|
|
9744
9979
|
}
|
|
9745
9980
|
};
|
|
9981
|
+
this.incident = (options) => {
|
|
9982
|
+
if (this.app === null) {
|
|
9983
|
+
return;
|
|
9984
|
+
}
|
|
9985
|
+
this.app.send(Incident(options.label ?? '', options.startTime, options.endTime ?? options.startTime));
|
|
9986
|
+
};
|
|
9746
9987
|
this.crossdomainMode = Boolean(inIframe() && options.crossdomain?.enabled);
|
|
9747
9988
|
if (!IN_BROWSER || !processOptions(options)) {
|
|
9748
9989
|
return;
|
|
@@ -9821,6 +10062,7 @@ class API {
|
|
|
9821
10062
|
Img(app);
|
|
9822
10063
|
Input(app, options);
|
|
9823
10064
|
Timing(app, options);
|
|
10065
|
+
LongAnimationTask(app, options);
|
|
9824
10066
|
Focus(app);
|
|
9825
10067
|
Fonts(app);
|
|
9826
10068
|
const skipNetwork = options.network?.disabled;
|
|
@@ -9828,6 +10070,7 @@ class API {
|
|
|
9828
10070
|
Network(app, options.network);
|
|
9829
10071
|
}
|
|
9830
10072
|
selection(app);
|
|
10073
|
+
webAnimations(app, options.webAnimations);
|
|
9831
10074
|
window.__OPENREPLAY__ = this;
|
|
9832
10075
|
if (options.flags && options.flags.onFlagsLoad) {
|
|
9833
10076
|
this.onFlagsLoad(options.flags.onFlagsLoad);
|
|
@@ -10052,6 +10295,13 @@ class API {
|
|
|
10052
10295
|
}
|
|
10053
10296
|
else {
|
|
10054
10297
|
try {
|
|
10298
|
+
if ('or_timestamp' in payload) {
|
|
10299
|
+
const startTs = this.getSessionInfo()?.timestamp ?? 0;
|
|
10300
|
+
const diff = payload.or_timestamp - startTs;
|
|
10301
|
+
if (diff < 0) {
|
|
10302
|
+
console.error(`OpenReplay: event ${key} has or_timestamp (${payload.or_timestamp}) before session start (${startTs}). It will be ignored.`);
|
|
10303
|
+
}
|
|
10304
|
+
}
|
|
10055
10305
|
payload = JSON.stringify(payload);
|
|
10056
10306
|
}
|
|
10057
10307
|
catch (e) {
|