@openreplay/tracker 17.0.0-beta.0 → 17.0.1
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/interaction.d.ts +1 -1
- package/dist/cjs/common/messages.gen.d.ts +13 -1
- package/dist/cjs/entry.js +625 -1795
- package/dist/cjs/entry.js.map +1 -1
- package/dist/cjs/index.js +625 -1753
- 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 +1 -7
- package/dist/cjs/main/app/messages.gen.d.ts +2 -0
- package/dist/cjs/main/app/nodes/idSeq.d.ts +14 -0
- package/dist/cjs/main/app/nodes/index.d.ts +2 -1
- package/dist/cjs/main/app/observer/observer.d.ts +4 -0
- package/dist/cjs/main/app/observer/top_observer.d.ts +4 -2
- package/dist/cjs/main/app/session.d.ts +3 -2
- package/dist/cjs/main/index.d.ts +4 -12
- package/dist/cjs/main/modules/conditionsManager.d.ts +6 -1
- package/dist/cjs/main/modules/mouse.d.ts +2 -20
- package/dist/cjs/main/modules/timing.d.ts +1 -0
- package/dist/cjs/main/modules/viewport.d.ts +5 -1
- package/dist/cjs/main/modules/webAnimations.d.ts +9 -0
- package/dist/cjs/main/singleton.d.ts +0 -7
- package/dist/lib/common/interaction.d.ts +1 -1
- package/dist/lib/common/messages.gen.d.ts +13 -1
- package/dist/lib/entry.js +625 -1795
- package/dist/lib/entry.js.map +1 -1
- package/dist/lib/index.js +625 -1753
- 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 +1 -7
- package/dist/lib/main/app/messages.gen.d.ts +2 -0
- package/dist/lib/main/app/nodes/idSeq.d.ts +14 -0
- package/dist/lib/main/app/nodes/index.d.ts +2 -1
- package/dist/lib/main/app/observer/observer.d.ts +4 -0
- package/dist/lib/main/app/observer/top_observer.d.ts +4 -2
- package/dist/lib/main/app/session.d.ts +3 -2
- package/dist/lib/main/index.d.ts +4 -12
- package/dist/lib/main/modules/conditionsManager.d.ts +6 -1
- package/dist/lib/main/modules/mouse.d.ts +2 -20
- package/dist/lib/main/modules/timing.d.ts +1 -0
- package/dist/lib/main/modules/viewport.d.ts +5 -1
- package/dist/lib/main/modules/webAnimations.d.ts +9 -0
- package/dist/lib/main/singleton.d.ts +0 -7
- package/dist/types/common/interaction.d.ts +1 -1
- package/dist/types/common/messages.gen.d.ts +13 -1
- package/dist/types/main/app/guards.d.ts +1 -0
- package/dist/types/main/app/index.d.ts +1 -7
- package/dist/types/main/app/messages.gen.d.ts +2 -0
- package/dist/types/main/app/nodes/idSeq.d.ts +14 -0
- package/dist/types/main/app/nodes/index.d.ts +2 -1
- package/dist/types/main/app/observer/observer.d.ts +4 -0
- package/dist/types/main/app/observer/top_observer.d.ts +4 -2
- package/dist/types/main/app/session.d.ts +3 -2
- package/dist/types/main/index.d.ts +4 -12
- package/dist/types/main/modules/conditionsManager.d.ts +6 -1
- package/dist/types/main/modules/mouse.d.ts +2 -20
- package/dist/types/main/modules/timing.d.ts +1 -0
- package/dist/types/main/modules/viewport.d.ts +5 -1
- package/dist/types/main/modules/webAnimations.d.ts +9 -0
- package/dist/types/main/singleton.d.ts +0 -7
- package/package.json +13 -14
- package/dist/cjs/main/modules/featureFlags.d.ts +0 -25
- package/dist/cjs/main/modules/userTesting/SignalManager.d.ts +0 -29
- package/dist/cjs/main/modules/userTesting/dnd.d.ts +0 -1
- package/dist/cjs/main/modules/userTesting/index.d.ts +0 -45
- package/dist/cjs/main/modules/userTesting/recorder.d.ts +0 -24
- package/dist/cjs/main/modules/userTesting/styles.d.ts +0 -277
- package/dist/cjs/main/modules/userTesting/utils.d.ts +0 -9
- package/dist/lib/main/modules/featureFlags.d.ts +0 -25
- package/dist/lib/main/modules/userTesting/SignalManager.d.ts +0 -29
- package/dist/lib/main/modules/userTesting/dnd.d.ts +0 -1
- package/dist/lib/main/modules/userTesting/index.d.ts +0 -45
- package/dist/lib/main/modules/userTesting/recorder.d.ts +0 -24
- package/dist/lib/main/modules/userTesting/styles.d.ts +0 -277
- package/dist/lib/main/modules/userTesting/utils.d.ts +0 -9
- package/dist/types/main/modules/featureFlags.d.ts +0 -25
- package/dist/types/main/modules/userTesting/SignalManager.d.ts +0 -29
- package/dist/types/main/modules/userTesting/dnd.d.ts +0 -1
- package/dist/types/main/modules/userTesting/index.d.ts +0 -45
- package/dist/types/main/modules/userTesting/recorder.d.ts +0 -24
- package/dist/types/main/modules/userTesting/styles.d.ts +0 -277
- package/dist/types/main/modules/userTesting/utils.d.ts +0 -9
package/dist/lib/entry.js
CHANGED
|
@@ -56,12 +56,12 @@ fl[28] = 258, revfl[258] = 28;
|
|
|
56
56
|
var _b = freb(fdeb, 0), revfd = _b.r;
|
|
57
57
|
// map of value to reverse (assuming 16 bits)
|
|
58
58
|
var rev = new u16(32768);
|
|
59
|
-
for (var i = 0; i < 32768; ++i) {
|
|
59
|
+
for (var i$1 = 0; i$1 < 32768; ++i$1) {
|
|
60
60
|
// reverse table algorithm from SO
|
|
61
|
-
var x$1 = ((i & 0xAAAA) >> 1) | ((i & 0x5555) << 1);
|
|
61
|
+
var x$1 = ((i$1 & 0xAAAA) >> 1) | ((i$1 & 0x5555) << 1);
|
|
62
62
|
x$1 = ((x$1 & 0xCCCC) >> 2) | ((x$1 & 0x3333) << 2);
|
|
63
63
|
x$1 = ((x$1 & 0xF0F0) >> 4) | ((x$1 & 0x0F0F) << 4);
|
|
64
|
-
rev[i] = (((x$1 & 0xFF00) >> 8) | ((x$1 & 0x00FF) << 8)) >> 1;
|
|
64
|
+
rev[i$1] = (((x$1 & 0xFF00) >> 8) | ((x$1 & 0x00FF) << 8)) >> 1;
|
|
65
65
|
}
|
|
66
66
|
// create huffman tree from u8 "map": index -> code length for code index
|
|
67
67
|
// mb (max bits) must be at most 15
|
|
@@ -117,18 +117,18 @@ var hMap = (function (cd, mb, r) {
|
|
|
117
117
|
});
|
|
118
118
|
// fixed length tree
|
|
119
119
|
var flt = new u8(288);
|
|
120
|
-
for (var i = 0; i < 144; ++i)
|
|
121
|
-
flt[i] = 8;
|
|
122
|
-
for (var i = 144; i < 256; ++i)
|
|
123
|
-
flt[i] = 9;
|
|
124
|
-
for (var i = 256; i < 280; ++i)
|
|
125
|
-
flt[i] = 7;
|
|
126
|
-
for (var i = 280; i < 288; ++i)
|
|
127
|
-
flt[i] = 8;
|
|
120
|
+
for (var i$1 = 0; i$1 < 144; ++i$1)
|
|
121
|
+
flt[i$1] = 8;
|
|
122
|
+
for (var i$1 = 144; i$1 < 256; ++i$1)
|
|
123
|
+
flt[i$1] = 9;
|
|
124
|
+
for (var i$1 = 256; i$1 < 280; ++i$1)
|
|
125
|
+
flt[i$1] = 7;
|
|
126
|
+
for (var i$1 = 280; i$1 < 288; ++i$1)
|
|
127
|
+
flt[i$1] = 8;
|
|
128
128
|
// fixed distance tree
|
|
129
129
|
var fdt = new u8(32);
|
|
130
|
-
for (var i = 0; i < 32; ++i)
|
|
131
|
-
fdt[i] = 5;
|
|
130
|
+
for (var i$1 = 0; i$1 < 32; ++i$1)
|
|
131
|
+
fdt[i$1] = 5;
|
|
132
132
|
// fixed length map
|
|
133
133
|
var flm = /*#__PURE__*/ hMap(flt, 9, 0);
|
|
134
134
|
// fixed distance map
|
|
@@ -1110,93 +1110,6 @@ const mapCondition = (condition) => {
|
|
|
1110
1110
|
return con;
|
|
1111
1111
|
};
|
|
1112
1112
|
|
|
1113
|
-
class FeatureFlags {
|
|
1114
|
-
constructor(app) {
|
|
1115
|
-
this.app = app;
|
|
1116
|
-
this.flags = [];
|
|
1117
|
-
this.storageKey = '__openreplay_flags';
|
|
1118
|
-
const persistFlags = this.app.sessionStorage.getItem(this.storageKey);
|
|
1119
|
-
if (persistFlags) {
|
|
1120
|
-
const persistFlagsStrArr = persistFlags.split(';').filter(Boolean);
|
|
1121
|
-
this.flags = persistFlagsStrArr.map((flag) => JSON.parse(flag));
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
getFeatureFlag(flagName) {
|
|
1125
|
-
return this.flags.find((flag) => flag.key === flagName);
|
|
1126
|
-
}
|
|
1127
|
-
isFlagEnabled(flagName) {
|
|
1128
|
-
return this.flags.findIndex((flag) => flag.key === flagName) !== -1;
|
|
1129
|
-
}
|
|
1130
|
-
onFlagsLoad(cb) {
|
|
1131
|
-
this.onFlagsCb = cb;
|
|
1132
|
-
}
|
|
1133
|
-
async reloadFlags(token) {
|
|
1134
|
-
const persistFlagsStr = this.app.sessionStorage.getItem(this.storageKey);
|
|
1135
|
-
const persistFlags = {};
|
|
1136
|
-
if (persistFlagsStr) {
|
|
1137
|
-
const persistArray = persistFlagsStr.split(';').filter(Boolean);
|
|
1138
|
-
persistArray.forEach((flag) => {
|
|
1139
|
-
const flagObj = JSON.parse(flag);
|
|
1140
|
-
persistFlags[flagObj.key] = { key: flagObj.key, value: flagObj.value };
|
|
1141
|
-
});
|
|
1142
|
-
}
|
|
1143
|
-
const sessionInfo = this.app.session.getInfo();
|
|
1144
|
-
const userInfo = this.app.session.userInfo;
|
|
1145
|
-
const requestObject = {
|
|
1146
|
-
projectID: sessionInfo.projectID,
|
|
1147
|
-
userID: sessionInfo.userID,
|
|
1148
|
-
metadata: sessionInfo.metadata,
|
|
1149
|
-
referrer: document.referrer,
|
|
1150
|
-
os: userInfo.userOS,
|
|
1151
|
-
device: userInfo.userDevice,
|
|
1152
|
-
country: userInfo.userCountry,
|
|
1153
|
-
state: userInfo.userState,
|
|
1154
|
-
city: userInfo.userCity,
|
|
1155
|
-
browser: userInfo.userBrowser,
|
|
1156
|
-
persistFlags: persistFlags,
|
|
1157
|
-
};
|
|
1158
|
-
const authToken = token ?? this.app.session.getSessionToken();
|
|
1159
|
-
const resp = await fetch(this.app.options.ingestPoint + '/v1/web/feature-flags', {
|
|
1160
|
-
method: 'POST',
|
|
1161
|
-
headers: {
|
|
1162
|
-
'Content-Type': 'application/json',
|
|
1163
|
-
Authorization: `Bearer ${authToken}`,
|
|
1164
|
-
},
|
|
1165
|
-
body: JSON.stringify(requestObject),
|
|
1166
|
-
});
|
|
1167
|
-
if (resp.status === 200) {
|
|
1168
|
-
const data = await resp.json();
|
|
1169
|
-
return this.handleFlags(data.flags);
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
handleFlags(flags) {
|
|
1173
|
-
const persistFlags = [];
|
|
1174
|
-
flags.forEach((flag) => {
|
|
1175
|
-
if (flag.is_persist)
|
|
1176
|
-
persistFlags.push(flag);
|
|
1177
|
-
});
|
|
1178
|
-
let str = '';
|
|
1179
|
-
const uniquePersistFlags = this.diffPersist(persistFlags);
|
|
1180
|
-
uniquePersistFlags.forEach((flag) => {
|
|
1181
|
-
str += `${JSON.stringify(flag)};`;
|
|
1182
|
-
});
|
|
1183
|
-
this.app.sessionStorage.setItem(this.storageKey, str);
|
|
1184
|
-
this.flags = flags;
|
|
1185
|
-
return this.onFlagsCb?.(flags);
|
|
1186
|
-
}
|
|
1187
|
-
clearPersistFlags() {
|
|
1188
|
-
this.app.sessionStorage.removeItem(this.storageKey);
|
|
1189
|
-
}
|
|
1190
|
-
diffPersist(flags) {
|
|
1191
|
-
const persistFlags = this.app.sessionStorage.getItem(this.storageKey);
|
|
1192
|
-
if (!persistFlags)
|
|
1193
|
-
return flags;
|
|
1194
|
-
const persistFlagsStrArr = persistFlags.split(';').filter(Boolean);
|
|
1195
|
-
const persistFlagsArr = persistFlagsStrArr.map((flag) => JSON.parse(flag));
|
|
1196
|
-
return flags.filter((flag) => persistFlagsArr.findIndex((pf) => pf.key === flag.key) === -1);
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
1113
|
const DEPRECATED_ATTRS = { htmlmasked: 'hidden', masked: 'obscured' };
|
|
1201
1114
|
const IN_BROWSER = !(typeof window === 'undefined');
|
|
1202
1115
|
const IS_FIREFOX = IN_BROWSER && navigator.userAgent.match(/firefox|fxios/i);
|
|
@@ -1712,6 +1625,13 @@ function SetNodeAttributeDictGlobal(id, name, value) {
|
|
|
1712
1625
|
value,
|
|
1713
1626
|
];
|
|
1714
1627
|
}
|
|
1628
|
+
function NodeAnimationResult(id, styles) {
|
|
1629
|
+
return [
|
|
1630
|
+
36 /* Messages.Type.NodeAnimationResult */,
|
|
1631
|
+
id,
|
|
1632
|
+
styles,
|
|
1633
|
+
];
|
|
1634
|
+
}
|
|
1715
1635
|
function CSSInsertRule(id, rule, index) {
|
|
1716
1636
|
return [
|
|
1717
1637
|
37 /* Messages.Type.CSSInsertRule */,
|
|
@@ -1924,6 +1844,13 @@ function CustomIssue(name, payload) {
|
|
|
1924
1844
|
payload,
|
|
1925
1845
|
];
|
|
1926
1846
|
}
|
|
1847
|
+
function SetNodeSlot(id, slotID) {
|
|
1848
|
+
return [
|
|
1849
|
+
65 /* Messages.Type.SetNodeSlot */,
|
|
1850
|
+
id,
|
|
1851
|
+
slotID,
|
|
1852
|
+
];
|
|
1853
|
+
}
|
|
1927
1854
|
function CSSInsertRuleURLBased(id, rule, index, baseURL) {
|
|
1928
1855
|
return [
|
|
1929
1856
|
67 /* Messages.Type.CSSInsertRuleURLBased */,
|
|
@@ -2243,6 +2170,7 @@ var _Messages = /*#__PURE__*/Object.freeze({
|
|
|
2243
2170
|
NetworkRequest: NetworkRequest,
|
|
2244
2171
|
NetworkRequestDeprecated: NetworkRequestDeprecated,
|
|
2245
2172
|
NgRx: NgRx,
|
|
2173
|
+
NodeAnimationResult: NodeAnimationResult,
|
|
2246
2174
|
OTable: OTable,
|
|
2247
2175
|
PageLoadTiming: PageLoadTiming,
|
|
2248
2176
|
PageRenderTiming: PageRenderTiming,
|
|
@@ -2269,6 +2197,7 @@ var _Messages = /*#__PURE__*/Object.freeze({
|
|
|
2269
2197
|
SetNodeData: SetNodeData,
|
|
2270
2198
|
SetNodeFocus: SetNodeFocus,
|
|
2271
2199
|
SetNodeScroll: SetNodeScroll,
|
|
2200
|
+
SetNodeSlot: SetNodeSlot,
|
|
2272
2201
|
SetPageLocation: SetPageLocation,
|
|
2273
2202
|
SetPageLocationDeprecated: SetPageLocationDeprecated,
|
|
2274
2203
|
SetPageVisibility: SetPageVisibility,
|
|
@@ -2417,986 +2346,6 @@ class TagWatcher {
|
|
|
2417
2346
|
}
|
|
2418
2347
|
}
|
|
2419
2348
|
|
|
2420
|
-
const bgStyle = {
|
|
2421
|
-
position: 'fixed',
|
|
2422
|
-
top: 0,
|
|
2423
|
-
left: 0,
|
|
2424
|
-
width: '100vw',
|
|
2425
|
-
height: '100vh',
|
|
2426
|
-
background: 'rgba(0, 0, 0, 0.40)',
|
|
2427
|
-
display: 'flex',
|
|
2428
|
-
alignItems: 'center',
|
|
2429
|
-
justifyContent: 'center',
|
|
2430
|
-
zIndex: 999999,
|
|
2431
|
-
fontFamily: `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`,
|
|
2432
|
-
};
|
|
2433
|
-
const containerStyle = {
|
|
2434
|
-
display: 'flex',
|
|
2435
|
-
flexDirection: 'column',
|
|
2436
|
-
gap: '2rem',
|
|
2437
|
-
alignItems: 'center',
|
|
2438
|
-
padding: '1.5rem',
|
|
2439
|
-
borderRadius: '2px',
|
|
2440
|
-
border: '1px solid rgb(255 255 255 / var(--tw-bg-opacity, 1))',
|
|
2441
|
-
background: '#FFF',
|
|
2442
|
-
width: '22rem',
|
|
2443
|
-
};
|
|
2444
|
-
const containerWidgetStyle = {
|
|
2445
|
-
display: 'flex',
|
|
2446
|
-
'flex-direction': 'column',
|
|
2447
|
-
gap: 'unset',
|
|
2448
|
-
'align-items': 'center',
|
|
2449
|
-
padding: 'unset',
|
|
2450
|
-
fontFamily: `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`,
|
|
2451
|
-
'border-radius': '2px',
|
|
2452
|
-
border: '1px solid rgb(255 255 255 / var(--tw-bg-opacity, 1))',
|
|
2453
|
-
background: 'rgba(255, 255, 255, 0.75)',
|
|
2454
|
-
width: '22rem',
|
|
2455
|
-
};
|
|
2456
|
-
const titleStyle = {
|
|
2457
|
-
fontFamily: 'Verdana, sans-serif',
|
|
2458
|
-
fontSize: '1.25rem',
|
|
2459
|
-
fontStyle: 'normal',
|
|
2460
|
-
fontWeight: '500',
|
|
2461
|
-
lineHeight: '1.75rem',
|
|
2462
|
-
color: 'rgba(0, 0, 0, 0.85)',
|
|
2463
|
-
};
|
|
2464
|
-
const descriptionStyle = {
|
|
2465
|
-
borderTop: '1px solid rgba(0, 0, 0, 0.06)',
|
|
2466
|
-
borderBottom: '1px solid rgba(0, 0, 0, 0.06)',
|
|
2467
|
-
padding: '1.25rem 0rem',
|
|
2468
|
-
color: 'rgba(0, 0, 0, 0.85)',
|
|
2469
|
-
fontFamily: 'Verdana, sans-serif',
|
|
2470
|
-
fontSize: '13px',
|
|
2471
|
-
fontStyle: 'normal',
|
|
2472
|
-
fontWeight: '400',
|
|
2473
|
-
lineHeight: 'auto',
|
|
2474
|
-
whiteSpace: 'pre-wrap',
|
|
2475
|
-
};
|
|
2476
|
-
const buttonStyle = {
|
|
2477
|
-
display: 'flex',
|
|
2478
|
-
padding: '0.4rem 0.9375rem',
|
|
2479
|
-
justifyContent: 'center',
|
|
2480
|
-
alignItems: 'center',
|
|
2481
|
-
gap: '0.625rem',
|
|
2482
|
-
borderRadius: '0.25rem',
|
|
2483
|
-
border: '1px solid #394EFF',
|
|
2484
|
-
background: '#394EFF',
|
|
2485
|
-
boxShadow: '0px 2px 0px 0px rgba(0, 0, 0, 0.04)',
|
|
2486
|
-
color: '#FFF',
|
|
2487
|
-
textAlign: 'center',
|
|
2488
|
-
fontFamily: 'Verdana, sans-serif',
|
|
2489
|
-
fontSize: '1rem',
|
|
2490
|
-
fontStyle: 'normal',
|
|
2491
|
-
fontWeight: '500',
|
|
2492
|
-
lineHeight: '1.5rem',
|
|
2493
|
-
cursor: 'pointer',
|
|
2494
|
-
};
|
|
2495
|
-
const sectionTitleStyle = {
|
|
2496
|
-
fontFamily: 'Verdana, sans-serif',
|
|
2497
|
-
fontSize: '13px',
|
|
2498
|
-
fontWeight: '500',
|
|
2499
|
-
lineHeight: 'auto',
|
|
2500
|
-
display: 'flex',
|
|
2501
|
-
justifyContent: 'space-between',
|
|
2502
|
-
width: '100%',
|
|
2503
|
-
cursor: 'pointer',
|
|
2504
|
-
};
|
|
2505
|
-
const contentStyle = {
|
|
2506
|
-
display: 'flex',
|
|
2507
|
-
flexDirection: 'column',
|
|
2508
|
-
alignItems: 'flex-start',
|
|
2509
|
-
gap: '0.625rem',
|
|
2510
|
-
fontSize: '13px',
|
|
2511
|
-
lineHeight: 'auto',
|
|
2512
|
-
};
|
|
2513
|
-
// New widget styles
|
|
2514
|
-
const titleWidgetStyle = {
|
|
2515
|
-
padding: '0.5rem',
|
|
2516
|
-
gap: '0.5rem',
|
|
2517
|
-
fontFamily: 'Verdana, sans-serif',
|
|
2518
|
-
fontSize: '16px',
|
|
2519
|
-
fontStyle: 'normal',
|
|
2520
|
-
fontWeight: '500',
|
|
2521
|
-
lineHeight: 'auto',
|
|
2522
|
-
color: 'white',
|
|
2523
|
-
display: 'flex',
|
|
2524
|
-
alignItems: 'center',
|
|
2525
|
-
width: '100%',
|
|
2526
|
-
borderRadius: '2px',
|
|
2527
|
-
background: 'rgba(0, 0, 0, 0.75)',
|
|
2528
|
-
boxSizing: 'border-box',
|
|
2529
|
-
};
|
|
2530
|
-
const descriptionWidgetStyle = {
|
|
2531
|
-
boxSizing: 'border-box',
|
|
2532
|
-
display: 'block',
|
|
2533
|
-
width: '100%',
|
|
2534
|
-
borderBottom: '1px solid rgb(255 255 255 / var(--tw-bg-opacity, 1))',
|
|
2535
|
-
background: '#FFF',
|
|
2536
|
-
padding: '0.65rem',
|
|
2537
|
-
alignSelf: 'stretch',
|
|
2538
|
-
color: '#000',
|
|
2539
|
-
fontFamily: 'Verdana, sans-serif',
|
|
2540
|
-
// fontSize: '0.875rem',
|
|
2541
|
-
fontStyle: 'normal',
|
|
2542
|
-
fontWeight: '400',
|
|
2543
|
-
// lineHeight: '1.375rem',
|
|
2544
|
-
};
|
|
2545
|
-
const endSectionStyle = {
|
|
2546
|
-
...descriptionWidgetStyle,
|
|
2547
|
-
display: 'flex',
|
|
2548
|
-
flexDirection: 'column',
|
|
2549
|
-
alignItems: 'center',
|
|
2550
|
-
gap: '0.625rem',
|
|
2551
|
-
};
|
|
2552
|
-
const symbolIcon = {
|
|
2553
|
-
fontSize: '1.25rem',
|
|
2554
|
-
fontWeight: '500',
|
|
2555
|
-
cursor: 'pointer',
|
|
2556
|
-
color: '#394EFF',
|
|
2557
|
-
};
|
|
2558
|
-
const buttonWidgetStyle = {
|
|
2559
|
-
display: 'flex',
|
|
2560
|
-
padding: '0.4rem 0.9375rem',
|
|
2561
|
-
justifyContent: 'center',
|
|
2562
|
-
alignItems: 'center',
|
|
2563
|
-
gap: '0.625rem',
|
|
2564
|
-
borderRadius: '0.25rem',
|
|
2565
|
-
border: '1px solid #394EFF',
|
|
2566
|
-
background: '#394EFF',
|
|
2567
|
-
boxShadow: '0px 2px 0px 0px rgba(0, 0, 0, 0.04)',
|
|
2568
|
-
color: '#FFF',
|
|
2569
|
-
textAlign: 'center',
|
|
2570
|
-
fontFamily: 'Verdana, sans-serif',
|
|
2571
|
-
fontSize: '1rem',
|
|
2572
|
-
fontStyle: 'normal',
|
|
2573
|
-
fontWeight: '500',
|
|
2574
|
-
lineHeight: '1.5rem',
|
|
2575
|
-
width: '100%',
|
|
2576
|
-
boxSizing: 'border-box',
|
|
2577
|
-
cursor: 'pointer',
|
|
2578
|
-
};
|
|
2579
|
-
const stopWidgetStyle = {
|
|
2580
|
-
marginTop: '1rem',
|
|
2581
|
-
marginBottom: '1rem',
|
|
2582
|
-
cursor: 'pointer',
|
|
2583
|
-
display: 'block',
|
|
2584
|
-
fontWeight: '500',
|
|
2585
|
-
fontSize: '13px!important',
|
|
2586
|
-
lineHeight: 'auto',
|
|
2587
|
-
};
|
|
2588
|
-
const paginationStyle = {
|
|
2589
|
-
display: 'flex',
|
|
2590
|
-
justifyContent: 'space-between',
|
|
2591
|
-
alignItems: 'center',
|
|
2592
|
-
gap: '1rem',
|
|
2593
|
-
padding: '0.5rem',
|
|
2594
|
-
width: '100%',
|
|
2595
|
-
boxSizing: 'border-box',
|
|
2596
|
-
};
|
|
2597
|
-
const taskNumberActive = {
|
|
2598
|
-
display: 'flex',
|
|
2599
|
-
flexDirection: 'column',
|
|
2600
|
-
alignItems: 'center',
|
|
2601
|
-
justifyContent: 'center',
|
|
2602
|
-
borderRadius: '6.25em',
|
|
2603
|
-
outline: '1px solid #394EFF',
|
|
2604
|
-
fontSize: '13px',
|
|
2605
|
-
height: '24px',
|
|
2606
|
-
width: '24px',
|
|
2607
|
-
};
|
|
2608
|
-
const taskNumberDone = {
|
|
2609
|
-
display: 'flex',
|
|
2610
|
-
flexDirection: 'column',
|
|
2611
|
-
alignItems: 'center',
|
|
2612
|
-
justifyContent: 'center',
|
|
2613
|
-
borderRadius: '6.25em',
|
|
2614
|
-
outline: '1px solid #D2DFFF',
|
|
2615
|
-
boxShadow: '0px 2px 0px 0px rgba(0, 0, 0, 0.04)',
|
|
2616
|
-
background: '#D2DFFF',
|
|
2617
|
-
fontSize: '13px',
|
|
2618
|
-
height: '24px',
|
|
2619
|
-
width: '24px',
|
|
2620
|
-
};
|
|
2621
|
-
const taskDescriptionCard = {
|
|
2622
|
-
borderRadius: '0.375rem',
|
|
2623
|
-
border: '1px solid rgba(0, 0, 0, 0.06)',
|
|
2624
|
-
background: '#F5F7FF',
|
|
2625
|
-
boxShadow: '0px 2px 0px 0px rgba(0, 0, 0, 0.04)',
|
|
2626
|
-
display: 'flex',
|
|
2627
|
-
flexDirection: 'column',
|
|
2628
|
-
padding: '0.625rem 0.9375rem',
|
|
2629
|
-
gap: '0.5rem',
|
|
2630
|
-
alignSelf: 'stretch',
|
|
2631
|
-
};
|
|
2632
|
-
const taskTextStyle = {
|
|
2633
|
-
fontWeight: 'bold',
|
|
2634
|
-
};
|
|
2635
|
-
const taskDescriptionStyle = {
|
|
2636
|
-
fontSize: '13px',
|
|
2637
|
-
lineHeight: 'auto',
|
|
2638
|
-
};
|
|
2639
|
-
const taskButtonStyle = {
|
|
2640
|
-
marginRight: '0.5rem',
|
|
2641
|
-
cursor: 'pointer',
|
|
2642
|
-
color: '#394EFF',
|
|
2643
|
-
textAlign: 'center',
|
|
2644
|
-
fontFamily: 'Verdana, sans-serif',
|
|
2645
|
-
fontSize: '13px',
|
|
2646
|
-
fontStyle: 'normal',
|
|
2647
|
-
fontWeight: '500',
|
|
2648
|
-
lineHeight: 'auto',
|
|
2649
|
-
};
|
|
2650
|
-
const taskButtonBorderedStyle = {
|
|
2651
|
-
...taskButtonStyle,
|
|
2652
|
-
display: 'flex',
|
|
2653
|
-
padding: '0.25rem 0.9375rem',
|
|
2654
|
-
justifyContent: 'center',
|
|
2655
|
-
alignItems: 'center',
|
|
2656
|
-
gap: '0.5rem',
|
|
2657
|
-
borderRadius: '0.25rem',
|
|
2658
|
-
border: '1px solid #394EFF',
|
|
2659
|
-
};
|
|
2660
|
-
const taskButtonsRow = {
|
|
2661
|
-
display: 'flex',
|
|
2662
|
-
justifyContent: 'space-between',
|
|
2663
|
-
alignItems: 'center',
|
|
2664
|
-
width: '100%',
|
|
2665
|
-
boxSizing: 'border-box',
|
|
2666
|
-
};
|
|
2667
|
-
const spinnerStyles = {
|
|
2668
|
-
border: '4px solid rgba(255, 255, 255, 0.4)',
|
|
2669
|
-
width: '16px',
|
|
2670
|
-
height: '16px',
|
|
2671
|
-
borderRadius: '50%',
|
|
2672
|
-
borderLeftColor: '#fff',
|
|
2673
|
-
animation: 'spin 0.5s linear infinite',
|
|
2674
|
-
};
|
|
2675
|
-
|
|
2676
|
-
const Quality = {
|
|
2677
|
-
Standard: { width: 1280, height: 720 }};
|
|
2678
|
-
class Recorder {
|
|
2679
|
-
constructor(app) {
|
|
2680
|
-
this.app = app;
|
|
2681
|
-
this.mediaRecorder = null;
|
|
2682
|
-
this.recordedChunks = [];
|
|
2683
|
-
this.stream = null;
|
|
2684
|
-
this.recStartTs = null;
|
|
2685
|
-
}
|
|
2686
|
-
async startRecording(fps, quality, micReq, camReq) {
|
|
2687
|
-
this.recStartTs = this.app.timestamp();
|
|
2688
|
-
const videoConstraints = quality;
|
|
2689
|
-
try {
|
|
2690
|
-
this.stream = await navigator.mediaDevices.getUserMedia({
|
|
2691
|
-
video: camReq ? { ...videoConstraints, frameRate: { ideal: fps } } : false,
|
|
2692
|
-
audio: micReq,
|
|
2693
|
-
});
|
|
2694
|
-
this.mediaRecorder = new MediaRecorder(this.stream, {
|
|
2695
|
-
mimeType: 'video/webm;codecs=vp9',
|
|
2696
|
-
});
|
|
2697
|
-
this.recordedChunks = [];
|
|
2698
|
-
this.mediaRecorder.ondataavailable = (event) => {
|
|
2699
|
-
if (event.data.size > 0) {
|
|
2700
|
-
this.recordedChunks.push(event.data);
|
|
2701
|
-
}
|
|
2702
|
-
};
|
|
2703
|
-
this.mediaRecorder.start();
|
|
2704
|
-
}
|
|
2705
|
-
catch (error) {
|
|
2706
|
-
console.error(error);
|
|
2707
|
-
}
|
|
2708
|
-
}
|
|
2709
|
-
async stopRecording() {
|
|
2710
|
-
return new Promise((resolve) => {
|
|
2711
|
-
if (!this.mediaRecorder)
|
|
2712
|
-
return;
|
|
2713
|
-
this.mediaRecorder.onstop = () => {
|
|
2714
|
-
const blob = new Blob(this.recordedChunks, {
|
|
2715
|
-
type: 'video/webm',
|
|
2716
|
-
});
|
|
2717
|
-
resolve(blob);
|
|
2718
|
-
};
|
|
2719
|
-
this.mediaRecorder.stop();
|
|
2720
|
-
});
|
|
2721
|
-
}
|
|
2722
|
-
async sendToAPI() {
|
|
2723
|
-
const blob = await this.stopRecording();
|
|
2724
|
-
// const formData = new FormData()
|
|
2725
|
-
// formData.append('file', blob, 'record.webm')
|
|
2726
|
-
// formData.append('start', this.recStartTs?.toString() ?? '')
|
|
2727
|
-
return fetch(`${this.app.options.ingestPoint}/v1/web/uxt/upload-url`, {
|
|
2728
|
-
headers: {
|
|
2729
|
-
Authorization: `Bearer ${this.app.session.getSessionToken()}`,
|
|
2730
|
-
},
|
|
2731
|
-
})
|
|
2732
|
-
.then((r) => {
|
|
2733
|
-
if (r.ok) {
|
|
2734
|
-
return r.json();
|
|
2735
|
-
}
|
|
2736
|
-
else {
|
|
2737
|
-
throw new Error('Failed to get upload url');
|
|
2738
|
-
}
|
|
2739
|
-
})
|
|
2740
|
-
.then(({ url }) => {
|
|
2741
|
-
return fetch(url, {
|
|
2742
|
-
method: 'PUT',
|
|
2743
|
-
headers: {
|
|
2744
|
-
'Content-Type': 'video/webm',
|
|
2745
|
-
},
|
|
2746
|
-
body: blob,
|
|
2747
|
-
});
|
|
2748
|
-
})
|
|
2749
|
-
.catch(console.error)
|
|
2750
|
-
.finally(() => {
|
|
2751
|
-
this.discard();
|
|
2752
|
-
});
|
|
2753
|
-
}
|
|
2754
|
-
async saveToFile(fileName = 'recorded-video.webm') {
|
|
2755
|
-
const blob = await this.stopRecording();
|
|
2756
|
-
const url = URL.createObjectURL(blob);
|
|
2757
|
-
const a = document.createElement('a');
|
|
2758
|
-
a.style.display = 'none';
|
|
2759
|
-
a.href = url;
|
|
2760
|
-
a.download = fileName;
|
|
2761
|
-
document.body.appendChild(a);
|
|
2762
|
-
a.click();
|
|
2763
|
-
window.URL.revokeObjectURL(url);
|
|
2764
|
-
document.body.removeChild(a);
|
|
2765
|
-
}
|
|
2766
|
-
discard() {
|
|
2767
|
-
this.mediaRecorder?.stop();
|
|
2768
|
-
this.stream?.getTracks().forEach((track) => track.stop());
|
|
2769
|
-
}
|
|
2770
|
-
}
|
|
2771
|
-
|
|
2772
|
-
// @ts-nocheck
|
|
2773
|
-
function attachDND(element, dragTarget) {
|
|
2774
|
-
dragTarget.onmousedown = function (event) {
|
|
2775
|
-
const clientRect = element.getBoundingClientRect();
|
|
2776
|
-
const shiftX = event.clientX - clientRect.left;
|
|
2777
|
-
const shiftY = event.clientY - clientRect.top;
|
|
2778
|
-
element.style.position = 'fixed';
|
|
2779
|
-
element.style.zIndex = 99999999999999;
|
|
2780
|
-
moveAt(event.pageX, event.pageY);
|
|
2781
|
-
function moveAt(pageX, pageY) {
|
|
2782
|
-
let leftC = pageX - shiftX;
|
|
2783
|
-
let topC = pageY - shiftY;
|
|
2784
|
-
if (leftC <= 5)
|
|
2785
|
-
leftC = 5;
|
|
2786
|
-
if (topC <= 5)
|
|
2787
|
-
topC = 5;
|
|
2788
|
-
if (leftC >= window.innerWidth - clientRect.width)
|
|
2789
|
-
leftC = window.innerWidth - clientRect.width;
|
|
2790
|
-
if (topC >= window.innerHeight - clientRect.height)
|
|
2791
|
-
topC = window.innerHeight - clientRect.height;
|
|
2792
|
-
element.style.left = `${leftC}px`;
|
|
2793
|
-
element.style.top = `${topC}px`;
|
|
2794
|
-
}
|
|
2795
|
-
function onMouseMove(event) {
|
|
2796
|
-
moveAt(event.pageX, event.pageY);
|
|
2797
|
-
}
|
|
2798
|
-
document.addEventListener('mousemove', onMouseMove);
|
|
2799
|
-
const clearAll = () => {
|
|
2800
|
-
document.removeEventListener('mousemove', onMouseMove);
|
|
2801
|
-
document.removeEventListener('mouseup', clearAll);
|
|
2802
|
-
};
|
|
2803
|
-
document.addEventListener('mouseup', clearAll);
|
|
2804
|
-
};
|
|
2805
|
-
dragTarget.ondragstart = function () {
|
|
2806
|
-
return false;
|
|
2807
|
-
};
|
|
2808
|
-
}
|
|
2809
|
-
|
|
2810
|
-
function generateGrid() {
|
|
2811
|
-
const grid = document.createElement('div');
|
|
2812
|
-
grid.className = 'grid';
|
|
2813
|
-
for (let i = 0; i < 16; i++) {
|
|
2814
|
-
const cell = document.createElement('div');
|
|
2815
|
-
Object.assign(cell.style, {
|
|
2816
|
-
width: '2px',
|
|
2817
|
-
height: '2px',
|
|
2818
|
-
borderRadius: '10px',
|
|
2819
|
-
background: 'white',
|
|
2820
|
-
});
|
|
2821
|
-
cell.className = 'cell';
|
|
2822
|
-
grid.appendChild(cell);
|
|
2823
|
-
}
|
|
2824
|
-
Object.assign(grid.style, {
|
|
2825
|
-
display: 'grid',
|
|
2826
|
-
gridTemplateColumns: 'repeat(4, 1fr)',
|
|
2827
|
-
gridTemplateRows: 'repeat(4, 1fr)',
|
|
2828
|
-
gap: '2px',
|
|
2829
|
-
cursor: 'grab',
|
|
2830
|
-
});
|
|
2831
|
-
return grid;
|
|
2832
|
-
}
|
|
2833
|
-
function generateChevron() {
|
|
2834
|
-
const triangle = document.createElement('div');
|
|
2835
|
-
Object.assign(triangle.style, {
|
|
2836
|
-
width: '0',
|
|
2837
|
-
height: '0',
|
|
2838
|
-
borderLeft: '7px solid transparent',
|
|
2839
|
-
borderRight: '7px solid transparent',
|
|
2840
|
-
borderBottom: '7px solid white',
|
|
2841
|
-
});
|
|
2842
|
-
const container = document.createElement('div');
|
|
2843
|
-
container.appendChild(triangle);
|
|
2844
|
-
Object.assign(container.style, {
|
|
2845
|
-
display: 'flex',
|
|
2846
|
-
alignItems: 'center',
|
|
2847
|
-
justifyContent: 'center',
|
|
2848
|
-
width: '16px',
|
|
2849
|
-
height: '16px',
|
|
2850
|
-
cursor: 'pointer',
|
|
2851
|
-
marginLeft: 'auto',
|
|
2852
|
-
transform: 'rotate(180deg)',
|
|
2853
|
-
});
|
|
2854
|
-
return container;
|
|
2855
|
-
}
|
|
2856
|
-
function addKeyframes() {
|
|
2857
|
-
const styleSheet = document.createElement('style');
|
|
2858
|
-
styleSheet.type = 'text/css';
|
|
2859
|
-
styleSheet.innerText = `@keyframes spin {
|
|
2860
|
-
0% { transform: rotate(0deg); }
|
|
2861
|
-
100% { transform: rotate(360deg); }
|
|
2862
|
-
}`;
|
|
2863
|
-
document.head.appendChild(styleSheet);
|
|
2864
|
-
}
|
|
2865
|
-
function createSpinner() {
|
|
2866
|
-
addKeyframes();
|
|
2867
|
-
const spinner = document.createElement('div');
|
|
2868
|
-
spinner.classList.add('spinner');
|
|
2869
|
-
Object.assign(spinner.style, spinnerStyles);
|
|
2870
|
-
return spinner;
|
|
2871
|
-
}
|
|
2872
|
-
function createElement(tag, className, styles, textContent, id) {
|
|
2873
|
-
const element = document.createElement(tag);
|
|
2874
|
-
element.className = className;
|
|
2875
|
-
Object.assign(element.style, styles);
|
|
2876
|
-
if (textContent) {
|
|
2877
|
-
element.textContent = textContent;
|
|
2878
|
-
}
|
|
2879
|
-
if (id) {
|
|
2880
|
-
element.id = id;
|
|
2881
|
-
}
|
|
2882
|
-
return element;
|
|
2883
|
-
}
|
|
2884
|
-
const TEST_START = 'or_uxt_test_start';
|
|
2885
|
-
const TASK_IND = 'or_uxt_task_index';
|
|
2886
|
-
const SESSION_ID = 'or_uxt_session_id';
|
|
2887
|
-
const TEST_ID = 'or_uxt_test_id';
|
|
2888
|
-
|
|
2889
|
-
class SignalManager {
|
|
2890
|
-
constructor(ingestPoint, getTimestamp, token, testId, storageKey, setStorageKey, removeStorageKey, getStorageKey, getSessionId) {
|
|
2891
|
-
this.ingestPoint = ingestPoint;
|
|
2892
|
-
this.getTimestamp = getTimestamp;
|
|
2893
|
-
this.token = token;
|
|
2894
|
-
this.testId = testId;
|
|
2895
|
-
this.storageKey = storageKey;
|
|
2896
|
-
this.setStorageKey = setStorageKey;
|
|
2897
|
-
this.removeStorageKey = removeStorageKey;
|
|
2898
|
-
this.getStorageKey = getStorageKey;
|
|
2899
|
-
this.getSessionId = getSessionId;
|
|
2900
|
-
this.durations = {
|
|
2901
|
-
testStart: 0,
|
|
2902
|
-
tasks: [],
|
|
2903
|
-
};
|
|
2904
|
-
this.getDurations = () => {
|
|
2905
|
-
return this.durations;
|
|
2906
|
-
};
|
|
2907
|
-
this.setDurations = (durations) => {
|
|
2908
|
-
this.durations.testStart = durations.testStart;
|
|
2909
|
-
this.durations.tasks = durations.tasks;
|
|
2910
|
-
};
|
|
2911
|
-
this.signalTask = (taskId, status, taskAnswer) => {
|
|
2912
|
-
if (!taskId)
|
|
2913
|
-
return console.error('User Testing: No Task ID Given');
|
|
2914
|
-
const taskStart = this.durations.tasks.find((t) => t.taskId === taskId);
|
|
2915
|
-
const timestamp = this.getTimestamp();
|
|
2916
|
-
const duration = taskStart ? timestamp - taskStart.started : 0;
|
|
2917
|
-
return fetch(`${this.ingestPoint}/v1/web/uxt/signals/task`, {
|
|
2918
|
-
method: 'POST',
|
|
2919
|
-
headers: {
|
|
2920
|
-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
2921
|
-
Authorization: `Bearer ${this.token}`,
|
|
2922
|
-
},
|
|
2923
|
-
body: JSON.stringify({
|
|
2924
|
-
testId: this.testId,
|
|
2925
|
-
taskId,
|
|
2926
|
-
status,
|
|
2927
|
-
duration,
|
|
2928
|
-
timestamp,
|
|
2929
|
-
taskAnswer,
|
|
2930
|
-
}),
|
|
2931
|
-
});
|
|
2932
|
-
};
|
|
2933
|
-
this.signalTest = (status) => {
|
|
2934
|
-
const timestamp = this.getTimestamp();
|
|
2935
|
-
if (status === 'begin' && this.testId) {
|
|
2936
|
-
const sessionId = this.getSessionId();
|
|
2937
|
-
this.setStorageKey(SESSION_ID, sessionId);
|
|
2938
|
-
this.setStorageKey(this.storageKey, this.testId.toString());
|
|
2939
|
-
this.setStorageKey(TEST_START, timestamp.toString());
|
|
2940
|
-
}
|
|
2941
|
-
else {
|
|
2942
|
-
this.removeStorageKey(this.storageKey);
|
|
2943
|
-
this.removeStorageKey(TASK_IND);
|
|
2944
|
-
this.removeStorageKey(TEST_START);
|
|
2945
|
-
}
|
|
2946
|
-
const start = this.durations.testStart || timestamp;
|
|
2947
|
-
const duration = timestamp - start;
|
|
2948
|
-
return fetch(`${this.ingestPoint}/v1/web/uxt/signals/test`, {
|
|
2949
|
-
method: 'POST',
|
|
2950
|
-
headers: {
|
|
2951
|
-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
2952
|
-
Authorization: `Bearer ${this.token}`,
|
|
2953
|
-
},
|
|
2954
|
-
body: JSON.stringify({
|
|
2955
|
-
testId: this.testId,
|
|
2956
|
-
status,
|
|
2957
|
-
duration,
|
|
2958
|
-
timestamp,
|
|
2959
|
-
}),
|
|
2960
|
-
});
|
|
2961
|
-
};
|
|
2962
|
-
const possibleStart = this.getStorageKey(TEST_START);
|
|
2963
|
-
if (possibleStart) {
|
|
2964
|
-
this.durations.testStart = parseInt(possibleStart, 10);
|
|
2965
|
-
}
|
|
2966
|
-
}
|
|
2967
|
-
}
|
|
2968
|
-
|
|
2969
|
-
class UserTestManager {
|
|
2970
|
-
constructor(app, storageKey) {
|
|
2971
|
-
this.app = app;
|
|
2972
|
-
this.storageKey = storageKey;
|
|
2973
|
-
this.bg = createElement('div', 'bg', bgStyle, undefined, '__or_ut_bg');
|
|
2974
|
-
this.container = createElement('div', 'container', containerStyle, undefined, '__or_ut_ct');
|
|
2975
|
-
this.widgetGuidelinesVisible = true;
|
|
2976
|
-
this.widgetTasksVisible = false;
|
|
2977
|
-
this.widgetVisible = true;
|
|
2978
|
-
this.isActive = false;
|
|
2979
|
-
this.descriptionSection = null;
|
|
2980
|
-
this.taskSection = null;
|
|
2981
|
-
this.endSection = null;
|
|
2982
|
-
this.stopButton = null;
|
|
2983
|
-
this.stopButtonContainer = null;
|
|
2984
|
-
this.test = null;
|
|
2985
|
-
this.testId = null;
|
|
2986
|
-
this.signalManager = null;
|
|
2987
|
-
this.getTest = (id, token, inProgress) => {
|
|
2988
|
-
this.testId = id;
|
|
2989
|
-
const ingest = this.app.options.ingestPoint;
|
|
2990
|
-
return fetch(`${ingest}/v1/web/uxt/test/${id}`, {
|
|
2991
|
-
headers: {
|
|
2992
|
-
Authorization: `Bearer ${token}`,
|
|
2993
|
-
},
|
|
2994
|
-
})
|
|
2995
|
-
.then((res) => res.json())
|
|
2996
|
-
.then(({ test }) => {
|
|
2997
|
-
this.isActive = true;
|
|
2998
|
-
this.test = test;
|
|
2999
|
-
this.signalManager = new SignalManager(this.app.options.ingestPoint, () => this.app.timestamp(), token, id, this.storageKey, (k, v) => this.app.localStorage.setItem(k, v), (k) => this.app.localStorage.removeItem(k), (k) => this.app.localStorage.getItem(k), () => this.app.getSessionID());
|
|
3000
|
-
this.createGreeting(test.title, test.reqMic, test.reqCamera);
|
|
3001
|
-
if (inProgress) {
|
|
3002
|
-
if (test.reqMic || test.reqCamera) {
|
|
3003
|
-
void this.userRecorder.startRecording(30, Quality.Standard, test.reqMic, test.reqCamera);
|
|
3004
|
-
}
|
|
3005
|
-
this.showWidget(test.description, test.tasks, true);
|
|
3006
|
-
this.showTaskSection();
|
|
3007
|
-
}
|
|
3008
|
-
})
|
|
3009
|
-
.then(() => id)
|
|
3010
|
-
.catch((err) => {
|
|
3011
|
-
console.log('OR: Error fetching test', err);
|
|
3012
|
-
});
|
|
3013
|
-
};
|
|
3014
|
-
this.hideTaskSection = () => false;
|
|
3015
|
-
this.showTaskSection = () => true;
|
|
3016
|
-
this.collapseWidget = () => false;
|
|
3017
|
-
this.removeGreeting = () => false;
|
|
3018
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
3019
|
-
this.toggleDescriptionVisibility = () => { };
|
|
3020
|
-
this.currentTaskIndex = 0;
|
|
3021
|
-
this.userRecorder = new Recorder(app);
|
|
3022
|
-
const sessionId = this.app.getSessionID();
|
|
3023
|
-
const savedSessionId = this.app.localStorage.getItem(SESSION_ID);
|
|
3024
|
-
if (sessionId !== savedSessionId) {
|
|
3025
|
-
this.app.localStorage.removeItem(this.storageKey);
|
|
3026
|
-
this.app.localStorage.removeItem(SESSION_ID);
|
|
3027
|
-
this.app.localStorage.removeItem(TEST_ID);
|
|
3028
|
-
this.app.localStorage.removeItem(TASK_IND);
|
|
3029
|
-
this.app.localStorage.removeItem(TEST_START);
|
|
3030
|
-
}
|
|
3031
|
-
const taskIndex = this.app.localStorage.getItem(TASK_IND);
|
|
3032
|
-
if (taskIndex) {
|
|
3033
|
-
this.currentTaskIndex = parseInt(taskIndex, 10);
|
|
3034
|
-
}
|
|
3035
|
-
}
|
|
3036
|
-
getTestId() {
|
|
3037
|
-
return this.testId;
|
|
3038
|
-
}
|
|
3039
|
-
createGreeting(title, micRequired, cameraRequired) {
|
|
3040
|
-
const titleElement = createElement('div', 'title', titleStyle, title);
|
|
3041
|
-
const descriptionElement = createElement('div', 'description', descriptionStyle, `Welcome, you're here to help us improve, not to be judged. Your insights matter!\n
|
|
3042
|
-
📹 We're recording this browser tab to learn from your experience.
|
|
3043
|
-
🎤 Please enable mic and camera if asked, to give us a complete picture.`);
|
|
3044
|
-
const buttonElement = createElement('div', 'button', buttonStyle, 'Read guidelines to begin');
|
|
3045
|
-
this.removeGreeting = () => {
|
|
3046
|
-
// this.container.innerHTML = ''
|
|
3047
|
-
if (micRequired || cameraRequired) {
|
|
3048
|
-
void this.userRecorder.startRecording(30, Quality.Standard, micRequired, cameraRequired);
|
|
3049
|
-
}
|
|
3050
|
-
this.container.removeChild(buttonElement);
|
|
3051
|
-
this.container.removeChild(descriptionElement);
|
|
3052
|
-
this.container.removeChild(titleElement);
|
|
3053
|
-
return false;
|
|
3054
|
-
};
|
|
3055
|
-
buttonElement.onclick = () => {
|
|
3056
|
-
this.removeGreeting();
|
|
3057
|
-
const durations = this.signalManager?.getDurations();
|
|
3058
|
-
if (durations && this.signalManager) {
|
|
3059
|
-
durations.testStart = this.app.timestamp();
|
|
3060
|
-
this.signalManager.setDurations(durations);
|
|
3061
|
-
}
|
|
3062
|
-
void this.signalManager?.signalTest('begin');
|
|
3063
|
-
this.container.style.fontFamily = `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`;
|
|
3064
|
-
Object.assign(this.container.style, containerWidgetStyle);
|
|
3065
|
-
this.showWidget(this.test?.guidelines || '', this.test?.tasks || []);
|
|
3066
|
-
};
|
|
3067
|
-
this.container.append(titleElement, descriptionElement, buttonElement);
|
|
3068
|
-
this.bg.appendChild(this.container);
|
|
3069
|
-
document.body.appendChild(this.bg);
|
|
3070
|
-
}
|
|
3071
|
-
showWidget(guidelines, tasks, inProgress) {
|
|
3072
|
-
this.container.innerHTML = '';
|
|
3073
|
-
Object.assign(this.bg.style, {
|
|
3074
|
-
position: 'fixed',
|
|
3075
|
-
zIndex: 99999999999999,
|
|
3076
|
-
right: '8px',
|
|
3077
|
-
left: 'unset',
|
|
3078
|
-
width: 'fit-content',
|
|
3079
|
-
top: '8px',
|
|
3080
|
-
height: 'fit-content',
|
|
3081
|
-
background: 'unset',
|
|
3082
|
-
display: 'unset',
|
|
3083
|
-
alignItems: 'unset',
|
|
3084
|
-
justifyContent: 'unset',
|
|
3085
|
-
});
|
|
3086
|
-
// Create title section
|
|
3087
|
-
const titleSection = this.createTitleSection();
|
|
3088
|
-
this.container.style.fontFamily = `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`;
|
|
3089
|
-
Object.assign(this.container.style, containerWidgetStyle);
|
|
3090
|
-
const descriptionSection = this.createDescriptionSection(guidelines);
|
|
3091
|
-
const tasksSection = this.createTasksSection(tasks);
|
|
3092
|
-
const stopButton = createElement('div', 'stop_bn_or', stopWidgetStyle, 'Abort Session');
|
|
3093
|
-
const stopContainer = createElement('div', 'stop_ct_or', { fontSize: '13px!important' });
|
|
3094
|
-
stopContainer.style.fontSize = '13px';
|
|
3095
|
-
stopContainer.append(stopButton);
|
|
3096
|
-
this.container.append(titleSection, descriptionSection, tasksSection, stopContainer);
|
|
3097
|
-
this.taskSection = tasksSection;
|
|
3098
|
-
this.descriptionSection = descriptionSection;
|
|
3099
|
-
this.stopButton = stopButton;
|
|
3100
|
-
this.stopButtonContainer = stopContainer;
|
|
3101
|
-
stopButton.onclick = () => {
|
|
3102
|
-
this.userRecorder.discard();
|
|
3103
|
-
void this.signalManager?.signalTest('skipped');
|
|
3104
|
-
document.body.removeChild(this.bg);
|
|
3105
|
-
window.close();
|
|
3106
|
-
};
|
|
3107
|
-
if (!inProgress) {
|
|
3108
|
-
this.hideTaskSection();
|
|
3109
|
-
}
|
|
3110
|
-
else {
|
|
3111
|
-
this.toggleDescriptionVisibility();
|
|
3112
|
-
}
|
|
3113
|
-
}
|
|
3114
|
-
createTitleSection() {
|
|
3115
|
-
const title = createElement('div', 'title', titleWidgetStyle);
|
|
3116
|
-
const leftIcon = generateGrid();
|
|
3117
|
-
const titleText = createElement('div', 'title_text', {
|
|
3118
|
-
maxWidth: '19rem',
|
|
3119
|
-
overflow: 'hidden',
|
|
3120
|
-
textOverflow: 'ellipsis',
|
|
3121
|
-
width: '100%',
|
|
3122
|
-
fontSize: 16,
|
|
3123
|
-
lineHeight: 'auto',
|
|
3124
|
-
cursor: 'pointer',
|
|
3125
|
-
}, this.test?.title);
|
|
3126
|
-
const rightIcon = generateChevron();
|
|
3127
|
-
title.append(leftIcon, titleText, rightIcon);
|
|
3128
|
-
const toggleWidget = (isVisible) => {
|
|
3129
|
-
this.widgetVisible = isVisible;
|
|
3130
|
-
this.container.style.fontFamily = `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`;
|
|
3131
|
-
Object.assign(this.container.style, this.widgetVisible
|
|
3132
|
-
? containerWidgetStyle
|
|
3133
|
-
: { border: 'none', background: 'none', padding: 0 });
|
|
3134
|
-
if (this.taskSection) {
|
|
3135
|
-
Object.assign(this.taskSection.style, this.widgetVisible ? descriptionWidgetStyle : { display: 'none' });
|
|
3136
|
-
}
|
|
3137
|
-
if (this.descriptionSection) {
|
|
3138
|
-
Object.assign(this.descriptionSection.style, this.widgetVisible ? descriptionWidgetStyle : { display: 'none' });
|
|
3139
|
-
}
|
|
3140
|
-
if (this.endSection) {
|
|
3141
|
-
Object.assign(this.endSection.style, this.widgetVisible ? descriptionWidgetStyle : { display: 'none' });
|
|
3142
|
-
}
|
|
3143
|
-
if (this.stopButton) {
|
|
3144
|
-
Object.assign(this.stopButton.style, this.widgetVisible ? stopWidgetStyle : { display: 'none' });
|
|
3145
|
-
}
|
|
3146
|
-
return isVisible;
|
|
3147
|
-
};
|
|
3148
|
-
const collapseWidget = () => {
|
|
3149
|
-
Object.assign(rightIcon.style, {
|
|
3150
|
-
transform: this.widgetVisible ? 'rotate(0deg)' : 'rotate(180deg)',
|
|
3151
|
-
});
|
|
3152
|
-
toggleWidget(!this.widgetVisible);
|
|
3153
|
-
};
|
|
3154
|
-
titleText.onclick = collapseWidget;
|
|
3155
|
-
rightIcon.onclick = collapseWidget;
|
|
3156
|
-
attachDND(this.bg, leftIcon);
|
|
3157
|
-
this.collapseWidget = () => toggleWidget(false);
|
|
3158
|
-
return title;
|
|
3159
|
-
}
|
|
3160
|
-
createDescriptionSection(guidelines) {
|
|
3161
|
-
const section = createElement('div', 'description_section_or', descriptionWidgetStyle);
|
|
3162
|
-
const titleContainer = createElement('div', 'description_s_title_or', sectionTitleStyle);
|
|
3163
|
-
const title = createElement('div', 'title', {
|
|
3164
|
-
fontSize: 13,
|
|
3165
|
-
fontWeight: 500,
|
|
3166
|
-
lineHeight: 'auto',
|
|
3167
|
-
}, 'Introduction & Guidelines');
|
|
3168
|
-
const icon = createElement('div', 'icon', symbolIcon, '-');
|
|
3169
|
-
const content = createElement('div', 'content', contentStyle);
|
|
3170
|
-
const descriptionC = createElement('div', 'text_description', {
|
|
3171
|
-
maxHeight: '250px',
|
|
3172
|
-
overflowY: 'auto',
|
|
3173
|
-
whiteSpace: 'pre-wrap',
|
|
3174
|
-
fontSize: 13,
|
|
3175
|
-
color: '#454545',
|
|
3176
|
-
lineHeight: 'auto',
|
|
3177
|
-
});
|
|
3178
|
-
descriptionC.innerHTML = guidelines;
|
|
3179
|
-
const button = createElement('div', 'button_begin_or', buttonWidgetStyle, 'Begin Test');
|
|
3180
|
-
titleContainer.append(title, icon);
|
|
3181
|
-
content.append(descriptionC, button);
|
|
3182
|
-
section.append(titleContainer, content);
|
|
3183
|
-
const toggleDescriptionVisibility = () => {
|
|
3184
|
-
this.widgetGuidelinesVisible = !this.widgetGuidelinesVisible;
|
|
3185
|
-
icon.textContent = this.widgetGuidelinesVisible ? '-' : '+';
|
|
3186
|
-
Object.assign(content.style, this.widgetGuidelinesVisible ? contentStyle : { display: 'none' });
|
|
3187
|
-
};
|
|
3188
|
-
titleContainer.onclick = toggleDescriptionVisibility;
|
|
3189
|
-
this.toggleDescriptionVisibility = () => {
|
|
3190
|
-
this.widgetGuidelinesVisible = false;
|
|
3191
|
-
icon.textContent = this.widgetGuidelinesVisible ? '-' : '+';
|
|
3192
|
-
Object.assign(content.style, this.widgetGuidelinesVisible ? contentStyle : { display: 'none' });
|
|
3193
|
-
content.removeChild(button);
|
|
3194
|
-
};
|
|
3195
|
-
button.onclick = () => {
|
|
3196
|
-
toggleDescriptionVisibility();
|
|
3197
|
-
if (this.test) {
|
|
3198
|
-
const durations = this.signalManager?.getDurations();
|
|
3199
|
-
const taskDurationInd = durations
|
|
3200
|
-
? durations.tasks.findIndex((t) => this.test && t.taskId === this.test.tasks[0].task_id)
|
|
3201
|
-
: null;
|
|
3202
|
-
if (durations && taskDurationInd === -1) {
|
|
3203
|
-
durations.tasks.push({
|
|
3204
|
-
taskId: this.test.tasks[0].task_id,
|
|
3205
|
-
started: this.app.timestamp(),
|
|
3206
|
-
});
|
|
3207
|
-
this.signalManager?.setDurations(durations);
|
|
3208
|
-
}
|
|
3209
|
-
void this.signalManager?.signalTask(this.test.tasks[0].task_id, 'begin');
|
|
3210
|
-
}
|
|
3211
|
-
this.showTaskSection();
|
|
3212
|
-
content.removeChild(button);
|
|
3213
|
-
};
|
|
3214
|
-
return section;
|
|
3215
|
-
}
|
|
3216
|
-
createTasksSection(tasks) {
|
|
3217
|
-
this.container.style.fontFamily = `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`;
|
|
3218
|
-
Object.assign(this.container.style, containerWidgetStyle);
|
|
3219
|
-
const section = createElement('div', 'task_section_or', descriptionWidgetStyle);
|
|
3220
|
-
const titleContainer = createElement('div', 'description_t_title_or', sectionTitleStyle);
|
|
3221
|
-
const title = createElement('div', 'title', {
|
|
3222
|
-
fontSize: '13px',
|
|
3223
|
-
fontWeight: '500',
|
|
3224
|
-
lineHeight: 'auto',
|
|
3225
|
-
}, 'Tasks');
|
|
3226
|
-
const icon = createElement('div', 'icon', symbolIcon, '-');
|
|
3227
|
-
const content = createElement('div', 'content', contentStyle);
|
|
3228
|
-
const pagination = createElement('div', 'pagination', paginationStyle);
|
|
3229
|
-
// const leftArrow = createElement('span', 'leftArrow', {}, '<')
|
|
3230
|
-
// const rightArrow = createElement('span', 'rightArrow', {}, '>')
|
|
3231
|
-
const taskCard = createElement('div', 'taskCard', taskDescriptionCard);
|
|
3232
|
-
const taskText = createElement('div', 'taskText', taskTextStyle);
|
|
3233
|
-
const taskDescription = createElement('div', 'taskDescription', taskDescriptionStyle);
|
|
3234
|
-
const taskButtons = createElement('div', 'taskButtons', taskButtonsRow);
|
|
3235
|
-
const inputTitle = createElement('div', 'taskText', taskTextStyle);
|
|
3236
|
-
inputTitle.textContent = 'Your answer';
|
|
3237
|
-
const inputArea = createElement('textarea', 'taskDescription', {
|
|
3238
|
-
resize: 'vertical',
|
|
3239
|
-
});
|
|
3240
|
-
const inputContainer = createElement('div', 'inputArea', taskDescriptionCard);
|
|
3241
|
-
inputContainer.append(inputTitle, inputArea);
|
|
3242
|
-
const closePanelButton = createElement('div', 'closePanelButton', taskButtonStyle, 'Collapse Panel');
|
|
3243
|
-
const nextButton = createElement('div', 'nextButton', taskButtonBorderedStyle, 'Done, Next');
|
|
3244
|
-
titleContainer.append(title, icon);
|
|
3245
|
-
taskCard.append(taskText, taskDescription);
|
|
3246
|
-
taskButtons.append(closePanelButton, nextButton);
|
|
3247
|
-
content.append(pagination, taskCard, inputContainer, taskButtons);
|
|
3248
|
-
section.append(titleContainer, content);
|
|
3249
|
-
const updateTaskContent = () => {
|
|
3250
|
-
const task = tasks[this.currentTaskIndex];
|
|
3251
|
-
taskText.textContent = task.title;
|
|
3252
|
-
taskDescription.textContent = task.description;
|
|
3253
|
-
if (task.allow_typing) {
|
|
3254
|
-
inputContainer.style.display = 'flex';
|
|
3255
|
-
}
|
|
3256
|
-
else {
|
|
3257
|
-
inputContainer.style.display = 'none';
|
|
3258
|
-
}
|
|
3259
|
-
};
|
|
3260
|
-
// pagination.appendChild(leftArrow)
|
|
3261
|
-
tasks.forEach((_, index) => {
|
|
3262
|
-
const pageNumber = createElement('span', `or_task_${index}`, {
|
|
3263
|
-
outline: '1px solid #efefef',
|
|
3264
|
-
fontSize: '13px',
|
|
3265
|
-
height: '24px',
|
|
3266
|
-
width: '24px',
|
|
3267
|
-
display: 'flex',
|
|
3268
|
-
flexDirection: 'column',
|
|
3269
|
-
alignItems: 'center',
|
|
3270
|
-
justifyContent: 'center',
|
|
3271
|
-
borderRadius: '6.25em',
|
|
3272
|
-
}, (index + 1).toString());
|
|
3273
|
-
pageNumber.id = `or_task_${index}`;
|
|
3274
|
-
pagination.append(pageNumber);
|
|
3275
|
-
});
|
|
3276
|
-
// pagination.appendChild(rightArrow)
|
|
3277
|
-
const toggleTasksVisibility = () => {
|
|
3278
|
-
this.widgetTasksVisible = !this.widgetTasksVisible;
|
|
3279
|
-
icon.textContent = this.widgetTasksVisible ? '-' : '+';
|
|
3280
|
-
Object.assign(content.style, this.widgetTasksVisible ? contentStyle : { display: 'none' });
|
|
3281
|
-
};
|
|
3282
|
-
this.hideTaskSection = () => {
|
|
3283
|
-
icon.textContent = '+';
|
|
3284
|
-
Object.assign(content.style, {
|
|
3285
|
-
display: 'none',
|
|
3286
|
-
});
|
|
3287
|
-
this.widgetTasksVisible = false;
|
|
3288
|
-
return false;
|
|
3289
|
-
};
|
|
3290
|
-
this.showTaskSection = () => {
|
|
3291
|
-
icon.textContent = '-';
|
|
3292
|
-
Object.assign(content.style, contentStyle);
|
|
3293
|
-
this.widgetTasksVisible = true;
|
|
3294
|
-
return true;
|
|
3295
|
-
};
|
|
3296
|
-
const highlightActive = () => {
|
|
3297
|
-
const activeTaskEl = document.getElementById(`or_task_${this.currentTaskIndex}`);
|
|
3298
|
-
if (activeTaskEl) {
|
|
3299
|
-
Object.assign(activeTaskEl.style, taskNumberActive);
|
|
3300
|
-
}
|
|
3301
|
-
for (let i = 0; i < this.currentTaskIndex; i++) {
|
|
3302
|
-
const taskEl = document.getElementById(`or_task_${i}`);
|
|
3303
|
-
if (taskEl) {
|
|
3304
|
-
Object.assign(taskEl.style, taskNumberDone);
|
|
3305
|
-
}
|
|
3306
|
-
}
|
|
3307
|
-
};
|
|
3308
|
-
titleContainer.onclick = toggleTasksVisibility;
|
|
3309
|
-
closePanelButton.onclick = this.collapseWidget;
|
|
3310
|
-
nextButton.onclick = () => {
|
|
3311
|
-
const textAnswer = tasks[this.currentTaskIndex].allow_typing ? inputArea.value : undefined;
|
|
3312
|
-
inputArea.value = '';
|
|
3313
|
-
void this.signalManager?.signalTask(tasks[this.currentTaskIndex].task_id, 'done', textAnswer);
|
|
3314
|
-
if (this.currentTaskIndex < tasks.length - 1) {
|
|
3315
|
-
this.currentTaskIndex++;
|
|
3316
|
-
updateTaskContent();
|
|
3317
|
-
const durations = this.signalManager?.getDurations();
|
|
3318
|
-
if (durations &&
|
|
3319
|
-
durations.tasks.findIndex((t) => t.taskId === tasks[this.currentTaskIndex].task_id) === -1) {
|
|
3320
|
-
durations.tasks.push({
|
|
3321
|
-
taskId: tasks[this.currentTaskIndex].task_id,
|
|
3322
|
-
started: this.app.timestamp(),
|
|
3323
|
-
});
|
|
3324
|
-
this.signalManager?.setDurations(durations);
|
|
3325
|
-
}
|
|
3326
|
-
void this.signalManager?.signalTask(tasks[this.currentTaskIndex].task_id, 'begin');
|
|
3327
|
-
highlightActive();
|
|
3328
|
-
}
|
|
3329
|
-
else {
|
|
3330
|
-
this.showEndSection();
|
|
3331
|
-
}
|
|
3332
|
-
this.app.localStorage.setItem('or_uxt_task_index', this.currentTaskIndex.toString());
|
|
3333
|
-
};
|
|
3334
|
-
setTimeout(() => {
|
|
3335
|
-
const firstTaskEl = document.getElementById('or_task_0');
|
|
3336
|
-
if (firstTaskEl) {
|
|
3337
|
-
Object.assign(firstTaskEl.style, taskNumberActive);
|
|
3338
|
-
}
|
|
3339
|
-
updateTaskContent();
|
|
3340
|
-
highlightActive();
|
|
3341
|
-
}, 1);
|
|
3342
|
-
return section;
|
|
3343
|
-
}
|
|
3344
|
-
showEndSection() {
|
|
3345
|
-
let isLoading = true;
|
|
3346
|
-
void this.signalManager?.signalTest('done');
|
|
3347
|
-
const section = createElement('div', 'end_section_or', endSectionStyle);
|
|
3348
|
-
const title = createElement('div', 'end_title_or', {
|
|
3349
|
-
fontSize: '1.25rem',
|
|
3350
|
-
fontWeight: '500',
|
|
3351
|
-
}, 'Thank you! 👍');
|
|
3352
|
-
const description = createElement('div', 'end_description_or', {}, this.test?.conclusion ??
|
|
3353
|
-
'Thank you for participating in our usability test. Your feedback has been captured and will be used to enhance our website. \n' +
|
|
3354
|
-
'\n' +
|
|
3355
|
-
'We appreciate your time and valuable input.');
|
|
3356
|
-
const button = createElement('div', 'end_button_or', buttonWidgetStyle, 'Submitting Feedback');
|
|
3357
|
-
const spinner = createSpinner();
|
|
3358
|
-
button.appendChild(spinner);
|
|
3359
|
-
if (this.test?.reqMic || this.test?.reqCamera) {
|
|
3360
|
-
void this.userRecorder
|
|
3361
|
-
.sendToAPI()
|
|
3362
|
-
.then(() => {
|
|
3363
|
-
button.removeChild(spinner);
|
|
3364
|
-
button.textContent = 'End Session';
|
|
3365
|
-
isLoading = false;
|
|
3366
|
-
})
|
|
3367
|
-
.catch((err) => {
|
|
3368
|
-
console.error(err);
|
|
3369
|
-
button.removeChild(spinner);
|
|
3370
|
-
button.textContent = 'End Session';
|
|
3371
|
-
isLoading = false;
|
|
3372
|
-
});
|
|
3373
|
-
}
|
|
3374
|
-
else {
|
|
3375
|
-
button.removeChild(spinner);
|
|
3376
|
-
button.textContent = 'End Session';
|
|
3377
|
-
isLoading = false;
|
|
3378
|
-
}
|
|
3379
|
-
if (this.taskSection) {
|
|
3380
|
-
this.container.removeChild(this.taskSection);
|
|
3381
|
-
}
|
|
3382
|
-
if (this.descriptionSection) {
|
|
3383
|
-
this.container.removeChild(this.descriptionSection);
|
|
3384
|
-
}
|
|
3385
|
-
if (this.stopButton && this.stopButtonContainer) {
|
|
3386
|
-
this.container.removeChild(this.stopButtonContainer);
|
|
3387
|
-
}
|
|
3388
|
-
button.onclick = () => {
|
|
3389
|
-
if (isLoading)
|
|
3390
|
-
return;
|
|
3391
|
-
window.close();
|
|
3392
|
-
document.body.removeChild(this.bg);
|
|
3393
|
-
};
|
|
3394
|
-
section.append(title, description, button);
|
|
3395
|
-
this.endSection = section;
|
|
3396
|
-
this.container.append(section);
|
|
3397
|
-
}
|
|
3398
|
-
}
|
|
3399
|
-
|
|
3400
2349
|
//@ts-ignore
|
|
3401
2350
|
function isNode(sth) {
|
|
3402
2351
|
return !!sth && sth.nodeType != null;
|
|
@@ -3729,6 +2678,27 @@ class Maintainer {
|
|
|
3729
2678
|
}
|
|
3730
2679
|
}
|
|
3731
2680
|
|
|
2681
|
+
// 4 levels, 128 frames between each level, 8_388_608 nodes per page
|
|
2682
|
+
// lets hope no one will need more :D
|
|
2683
|
+
const BITS_LEVEL = 2; // 4
|
|
2684
|
+
const BITS_ORDER = 7; // 128
|
|
2685
|
+
const BITS_NODE = 22; // 8_388_608
|
|
2686
|
+
const SHIFT_ORDER = BITS_NODE;
|
|
2687
|
+
const SHIFT_LEVEL = BITS_NODE + BITS_ORDER;
|
|
2688
|
+
const MASK_NODE = (1 << BITS_NODE) - 1;
|
|
2689
|
+
const MASK_ORDER = (1 << BITS_ORDER) - 1;
|
|
2690
|
+
const MASK_LEVEL = (1 << BITS_LEVEL) - 1;
|
|
2691
|
+
function pack(level, order, nodeId) {
|
|
2692
|
+
if (level < 0 || level > MASK_LEVEL)
|
|
2693
|
+
throw new RangeError('OR: nesting level overflow, max 4');
|
|
2694
|
+
if (order < 0 || order > MASK_ORDER)
|
|
2695
|
+
throw new RangeError('OR: frame order overflow, max 128');
|
|
2696
|
+
const v = ((level & MASK_LEVEL) << SHIFT_LEVEL) |
|
|
2697
|
+
((order & MASK_ORDER) << SHIFT_ORDER) |
|
|
2698
|
+
(nodeId & MASK_NODE);
|
|
2699
|
+
return v >>> 0;
|
|
2700
|
+
}
|
|
2701
|
+
|
|
3732
2702
|
class Nodes {
|
|
3733
2703
|
constructor(params) {
|
|
3734
2704
|
this.nodes = new Map();
|
|
@@ -3756,6 +2726,9 @@ class Nodes {
|
|
|
3756
2726
|
}
|
|
3757
2727
|
listeners.push([type, listener, useCapture]);
|
|
3758
2728
|
};
|
|
2729
|
+
this.createFrameId = (level, frameOrder) => {
|
|
2730
|
+
return pack(level, frameOrder, 0);
|
|
2731
|
+
};
|
|
3759
2732
|
this.unregisterNode = (node) => {
|
|
3760
2733
|
const id = node[this.node_id];
|
|
3761
2734
|
if (id !== undefined) {
|
|
@@ -3776,16 +2749,8 @@ class Nodes {
|
|
|
3776
2749
|
this.maintainer = new Maintainer(this.nodes, this.unregisterNode, params.maintainer);
|
|
3777
2750
|
this.maintainer.start();
|
|
3778
2751
|
}
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
const placeholderSize = 99999999;
|
|
3782
|
-
const nextFrameId = placeholderSize * frameOrder;
|
|
3783
|
-
// I highly doubt that this will ever happen,
|
|
3784
|
-
// but it will be easier to debug if it does
|
|
3785
|
-
if (nextFrameId > maxSafeNumber) {
|
|
3786
|
-
throw new Error('Placeholder id overflow');
|
|
3787
|
-
}
|
|
3788
|
-
this.nextNodeId = nextFrameId;
|
|
2752
|
+
crossdomainMode(level, frameOrder) {
|
|
2753
|
+
this.nextNodeId = this.createFrameId(level, frameOrder);
|
|
3789
2754
|
}
|
|
3790
2755
|
registerNode(node) {
|
|
3791
2756
|
let id = node[this.node_id];
|
|
@@ -4220,9 +3185,24 @@ async function parseUseEl(useElement, mode, domParser) {
|
|
|
4220
3185
|
return;
|
|
4221
3186
|
}
|
|
4222
3187
|
let [url, symbolId] = href.split('#');
|
|
3188
|
+
if (!url && !symbolId) {
|
|
3189
|
+
console.warn('Openreplay: Invalid xlink:href or href found on <use>.');
|
|
3190
|
+
return;
|
|
3191
|
+
}
|
|
3192
|
+
if (iconCache[symbolId]) {
|
|
3193
|
+
return iconCache[symbolId];
|
|
3194
|
+
}
|
|
4223
3195
|
// happens if svg spritemap is local, fastest case for us
|
|
4224
3196
|
if (!url && symbolId) {
|
|
4225
|
-
const
|
|
3197
|
+
const hasHashtag = href.startsWith('#');
|
|
3198
|
+
let escapedURL;
|
|
3199
|
+
if (hasHashtag) {
|
|
3200
|
+
escapedURL = `#${CSS.escape(href.substring(1))}`;
|
|
3201
|
+
}
|
|
3202
|
+
else {
|
|
3203
|
+
escapedURL = CSS.escape(href);
|
|
3204
|
+
}
|
|
3205
|
+
const symbol = document.querySelector(escapedURL);
|
|
4226
3206
|
if (symbol) {
|
|
4227
3207
|
const inlineSvg = `
|
|
4228
3208
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="${symbol.getAttribute('viewBox') || '0 0 24 24'}">
|
|
@@ -4237,13 +3217,6 @@ async function parseUseEl(useElement, mode, domParser) {
|
|
|
4237
3217
|
return;
|
|
4238
3218
|
}
|
|
4239
3219
|
}
|
|
4240
|
-
if (!url && !symbolId) {
|
|
4241
|
-
console.warn('Openreplay: Invalid xlink:href or href found on <use>.');
|
|
4242
|
-
return;
|
|
4243
|
-
}
|
|
4244
|
-
if (iconCache[symbolId]) {
|
|
4245
|
-
return iconCache[symbolId];
|
|
4246
|
-
}
|
|
4247
3220
|
let svgDoc;
|
|
4248
3221
|
if (svgUrlCache[url]) {
|
|
4249
3222
|
if (svgUrlCache[url] === 1) {
|
|
@@ -4343,6 +3316,7 @@ class Observer {
|
|
|
4343
3316
|
this.indexes = [];
|
|
4344
3317
|
this.attributesMap = new Map();
|
|
4345
3318
|
this.textSet = new Set();
|
|
3319
|
+
this.slotMap = new Map();
|
|
4346
3320
|
this.disableSprites = false;
|
|
4347
3321
|
/**
|
|
4348
3322
|
* this option means that, instead of using link element with href to load css,
|
|
@@ -4352,7 +3326,9 @@ class Observer {
|
|
|
4352
3326
|
this.inlineRemoteCss = false;
|
|
4353
3327
|
this.inlinerOptions = undefined;
|
|
4354
3328
|
this.domParser = new DOMParser();
|
|
3329
|
+
this.throttling = true;
|
|
4355
3330
|
this.throttledSetNodeData = throttleWithTrailing((id, parentElement, data) => this.sendNodeData(id, parentElement, data), 30);
|
|
3331
|
+
this.throttling = !Boolean(options.disableThrottling);
|
|
4356
3332
|
this.disableSprites = Boolean(options.disableSprites);
|
|
4357
3333
|
this.inlineRemoteCss = Boolean(options.inlineRemoteCss);
|
|
4358
3334
|
this.inlinerOptions = options.inlinerOptions;
|
|
@@ -4533,6 +3509,17 @@ class Observer {
|
|
|
4533
3509
|
}
|
|
4534
3510
|
bindNode(node) {
|
|
4535
3511
|
const [id, isNew] = this.app.nodes.registerNode(node);
|
|
3512
|
+
if (isElementNode(node) && hasTag(node, 'slot')) {
|
|
3513
|
+
this.app.nodes.attachNodeListener(node, 'slotchange', () => {
|
|
3514
|
+
const sl = node;
|
|
3515
|
+
sl.assignedNodes({ flatten: true }).forEach((n) => {
|
|
3516
|
+
const nid = this.app.nodes.getID(n);
|
|
3517
|
+
if (nid !== undefined) {
|
|
3518
|
+
this.recents.set(nid, RecentsType.Changed);
|
|
3519
|
+
}
|
|
3520
|
+
});
|
|
3521
|
+
});
|
|
3522
|
+
}
|
|
4536
3523
|
if (isNew) {
|
|
4537
3524
|
this.recents.set(id, RecentsType.New);
|
|
4538
3525
|
}
|
|
@@ -4563,6 +3550,9 @@ class Observer {
|
|
|
4563
3550
|
}
|
|
4564
3551
|
unbindTree(node) {
|
|
4565
3552
|
const id = this.app.nodes.unregisterNode(node);
|
|
3553
|
+
if (id !== undefined) {
|
|
3554
|
+
this.slotMap.delete(id);
|
|
3555
|
+
}
|
|
4566
3556
|
if (id !== undefined && this.recents.get(id) === RecentsType.Removed) {
|
|
4567
3557
|
// Sending RemoveNode only for parent to maintain
|
|
4568
3558
|
this.app.send(RemoveNode(id));
|
|
@@ -4591,8 +3581,8 @@ class Observer {
|
|
|
4591
3581
|
if (isRootNode(node)) {
|
|
4592
3582
|
return true;
|
|
4593
3583
|
}
|
|
4594
|
-
|
|
4595
|
-
const parent = node.
|
|
3584
|
+
let slot = node.assignedSlot;
|
|
3585
|
+
const parent = node.parentNode;
|
|
4596
3586
|
let parentID;
|
|
4597
3587
|
// Disable parent check for the upper context HTMLHtmlElement, because it is root there... (before)
|
|
4598
3588
|
// TODO: get rid of "special" cases (there is an issue with CreateDocument altered behaviour though)
|
|
@@ -4664,12 +3654,35 @@ class Observer {
|
|
|
4664
3654
|
else if (isTextNode(node)) {
|
|
4665
3655
|
// for text node id != 0, hence parentID !== undefined and parent is Element
|
|
4666
3656
|
this.app.send(CreateTextNode(id, parentID, index));
|
|
4667
|
-
this.
|
|
3657
|
+
if (this.throttling) {
|
|
3658
|
+
this.throttledSetNodeData(id, parent, node.data);
|
|
3659
|
+
}
|
|
3660
|
+
else {
|
|
3661
|
+
this.sendNodeData(id, parent, node.data);
|
|
3662
|
+
}
|
|
3663
|
+
}
|
|
3664
|
+
if (slot) {
|
|
3665
|
+
const slotID = this.app.nodes.getID(slot);
|
|
3666
|
+
if (slotID !== undefined) {
|
|
3667
|
+
this.slotMap.set(id, slotID);
|
|
3668
|
+
this.app.send(SetNodeSlot(id, slotID));
|
|
3669
|
+
}
|
|
4668
3670
|
}
|
|
4669
3671
|
return true;
|
|
4670
3672
|
}
|
|
4671
3673
|
if (recentsType === RecentsType.Removed && parentID !== undefined) {
|
|
4672
3674
|
this.app.send(MoveNode(id, parentID, index));
|
|
3675
|
+
if (slot) {
|
|
3676
|
+
const slotID = this.app.nodes.getID(slot);
|
|
3677
|
+
if (slotID !== undefined && this.slotMap.get(id) !== slotID) {
|
|
3678
|
+
this.slotMap.set(id, slotID);
|
|
3679
|
+
this.app.send(SetNodeSlot(id, slotID));
|
|
3680
|
+
}
|
|
3681
|
+
}
|
|
3682
|
+
else if (this.slotMap.has(id)) {
|
|
3683
|
+
this.slotMap.delete(id);
|
|
3684
|
+
this.app.send(SetNodeSlot(id, 0));
|
|
3685
|
+
}
|
|
4673
3686
|
}
|
|
4674
3687
|
const attr = this.attributesMap.get(id);
|
|
4675
3688
|
if (attr !== undefined) {
|
|
@@ -4685,7 +3698,12 @@ class Observer {
|
|
|
4685
3698
|
throw 'commitNode: node is not a text';
|
|
4686
3699
|
}
|
|
4687
3700
|
// for text node id != 0, hence parent is Element
|
|
4688
|
-
this.
|
|
3701
|
+
if (this.throttling) {
|
|
3702
|
+
this.throttledSetNodeData(id, parent, node.data);
|
|
3703
|
+
}
|
|
3704
|
+
else {
|
|
3705
|
+
this.sendNodeData(id, parent, node.data);
|
|
3706
|
+
}
|
|
4689
3707
|
}
|
|
4690
3708
|
return true;
|
|
4691
3709
|
}
|
|
@@ -4832,16 +3850,18 @@ class IFrameOffsets {
|
|
|
4832
3850
|
|
|
4833
3851
|
var InlineCssMode;
|
|
4834
3852
|
(function (InlineCssMode) {
|
|
3853
|
+
InlineCssMode[InlineCssMode["Unset"] = -1] = "Unset";
|
|
4835
3854
|
/** default behavior -- will parse and cache the css file on backend */
|
|
4836
3855
|
InlineCssMode[InlineCssMode["Disabled"] = 0] = "Disabled";
|
|
4837
3856
|
/** will attempt to record the linked css file as AdoptedStyleSheet object */
|
|
4838
3857
|
InlineCssMode[InlineCssMode["Inline"] = 1] = "Inline";
|
|
4839
|
-
/** will fetch the file, then
|
|
3858
|
+
/** will fetch the file, then simulate AdoptedStyleSheets behavior programmaticaly for the replay */
|
|
4840
3859
|
InlineCssMode[InlineCssMode["InlineFetched"] = 2] = "InlineFetched";
|
|
4841
3860
|
/** will fetch the file, then save it as plain css inside <style> node */
|
|
4842
3861
|
InlineCssMode[InlineCssMode["PlainFetched"] = 3] = "PlainFetched";
|
|
4843
3862
|
})(InlineCssMode || (InlineCssMode = {}));
|
|
4844
|
-
|
|
3863
|
+
const localhostStylesDoc = 'https://docs.openreplay.com/en/troubleshooting/localhost/';
|
|
3864
|
+
function getInlineOptions(mode, logger) {
|
|
4845
3865
|
switch (mode) {
|
|
4846
3866
|
case InlineCssMode.Inline:
|
|
4847
3867
|
return {
|
|
@@ -4867,6 +3887,27 @@ function getInlineOptions(mode) {
|
|
|
4867
3887
|
forcePlain: true,
|
|
4868
3888
|
},
|
|
4869
3889
|
};
|
|
3890
|
+
case InlineCssMode.Unset:
|
|
3891
|
+
const isLocalhost = /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?\/?/.test(window.location.href);
|
|
3892
|
+
if (isLocalhost) {
|
|
3893
|
+
logger(`Enabling InlineCssMode by default on localhost to preserve css styles, refer to ${localhostStylesDoc} for details, set InlineCssMode to 0 to skip this behavior`);
|
|
3894
|
+
return {
|
|
3895
|
+
inlineRemoteCss: true,
|
|
3896
|
+
inlinerOptions: {
|
|
3897
|
+
forceFetch: false,
|
|
3898
|
+
forcePlain: false,
|
|
3899
|
+
},
|
|
3900
|
+
};
|
|
3901
|
+
}
|
|
3902
|
+
else {
|
|
3903
|
+
return {
|
|
3904
|
+
inlineRemoteCss: false,
|
|
3905
|
+
inlinerOptions: {
|
|
3906
|
+
forceFetch: false,
|
|
3907
|
+
forcePlain: false,
|
|
3908
|
+
},
|
|
3909
|
+
};
|
|
3910
|
+
}
|
|
4870
3911
|
case InlineCssMode.Disabled:
|
|
4871
3912
|
default:
|
|
4872
3913
|
return {
|
|
@@ -4888,7 +3929,8 @@ class TopObserver extends Observer {
|
|
|
4888
3929
|
}, params.options);
|
|
4889
3930
|
const observerOptions = {
|
|
4890
3931
|
disableSprites: opts.disableSprites,
|
|
4891
|
-
|
|
3932
|
+
disableThrottling: opts.disableThrottling,
|
|
3933
|
+
...getInlineOptions(opts.inlineCss, console.warn),
|
|
4892
3934
|
};
|
|
4893
3935
|
super(params.app, true, observerOptions);
|
|
4894
3936
|
this.iframeOffsets = new IFrameOffsets();
|
|
@@ -4987,7 +4029,7 @@ class TopObserver extends Observer {
|
|
|
4987
4029
|
this.app.nodes.callNodeCallbacks(document, true);
|
|
4988
4030
|
}, window.document.documentElement);
|
|
4989
4031
|
}
|
|
4990
|
-
crossdomainObserve(rootNodeId, frameOder) {
|
|
4032
|
+
crossdomainObserve(rootNodeId, frameOder, frameLevel) {
|
|
4991
4033
|
const observer = this;
|
|
4992
4034
|
Element.prototype.attachShadow = function () {
|
|
4993
4035
|
// eslint-disable-next-line
|
|
@@ -4996,7 +4038,7 @@ class TopObserver extends Observer {
|
|
|
4996
4038
|
return shadow;
|
|
4997
4039
|
};
|
|
4998
4040
|
this.app.nodes.clear();
|
|
4999
|
-
this.app.nodes.
|
|
4041
|
+
this.app.nodes.crossdomainMode(frameLevel, frameOder);
|
|
5000
4042
|
const iframeObserver = new IFrameObserver(this.app);
|
|
5001
4043
|
this.iframeObservers.set(window.document, iframeObserver);
|
|
5002
4044
|
iframeObserver.syntheticObserve(rootNodeId, window.document);
|
|
@@ -5101,6 +4143,7 @@ class Sanitizer {
|
|
|
5101
4143
|
}
|
|
5102
4144
|
}
|
|
5103
4145
|
|
|
4146
|
+
const tokenSeparator = '_$_';
|
|
5104
4147
|
class Session {
|
|
5105
4148
|
constructor(params) {
|
|
5106
4149
|
this.metadata = {};
|
|
@@ -5125,6 +4168,26 @@ class Session {
|
|
|
5125
4168
|
this.app.sessionStorage.setItem(this.options.session_pageno_key, pageNo.toString());
|
|
5126
4169
|
return pageNo;
|
|
5127
4170
|
};
|
|
4171
|
+
this.getSessionToken = (projectKey) => {
|
|
4172
|
+
const tokenWithProject = this.token || this.app.sessionStorage.getItem(this.options.session_token_key);
|
|
4173
|
+
if (projectKey && tokenWithProject) {
|
|
4174
|
+
const savedProject = tokenWithProject.split(tokenSeparator)[1];
|
|
4175
|
+
if (!savedProject || savedProject !== projectKey) {
|
|
4176
|
+
this.app.sessionStorage.removeItem(this.options.session_token_key);
|
|
4177
|
+
this.token = undefined;
|
|
4178
|
+
return undefined;
|
|
4179
|
+
}
|
|
4180
|
+
}
|
|
4181
|
+
const token = tokenWithProject ? tokenWithProject.split(tokenSeparator)[0] : null;
|
|
4182
|
+
return token || undefined;
|
|
4183
|
+
};
|
|
4184
|
+
this.getRawTokenWithProject = () => {
|
|
4185
|
+
return this.token || this.app.sessionStorage.getItem(this.options.session_token_key);
|
|
4186
|
+
};
|
|
4187
|
+
this.setSessionToken = (token, projectKey) => {
|
|
4188
|
+
this.token = `${token}${tokenSeparator}${projectKey}`;
|
|
4189
|
+
this.app.sessionStorage.setItem(this.options.session_token_key, `${token}${tokenSeparator}${projectKey}`);
|
|
4190
|
+
};
|
|
5128
4191
|
this.app = params.app;
|
|
5129
4192
|
this.options = params.options;
|
|
5130
4193
|
this.createTabId();
|
|
@@ -5171,14 +4234,6 @@ class Session {
|
|
|
5171
4234
|
setUserInfo(userInfo) {
|
|
5172
4235
|
this.userInfo = userInfo;
|
|
5173
4236
|
}
|
|
5174
|
-
getSessionToken() {
|
|
5175
|
-
const token = this.token || this.app.sessionStorage.getItem(this.options.session_token_key);
|
|
5176
|
-
return token || undefined;
|
|
5177
|
-
}
|
|
5178
|
-
setSessionToken(token) {
|
|
5179
|
-
this.token = token;
|
|
5180
|
-
this.app.sessionStorage.setItem(this.options.session_token_key, token);
|
|
5181
|
-
}
|
|
5182
4237
|
applySessionHash(hash) {
|
|
5183
4238
|
const hashParts = decodeURI(hash).split('&');
|
|
5184
4239
|
let token = hash;
|
|
@@ -5194,7 +4249,7 @@ class Session {
|
|
|
5194
4249
|
}
|
|
5195
4250
|
getSessionHash() {
|
|
5196
4251
|
const pageNo = this.getPageNumber();
|
|
5197
|
-
const token = this.
|
|
4252
|
+
const token = this.getRawTokenWithProject();
|
|
5198
4253
|
if (pageNo === undefined || token === undefined) {
|
|
5199
4254
|
return;
|
|
5200
4255
|
}
|
|
@@ -5237,7 +4292,7 @@ class Session {
|
|
|
5237
4292
|
}
|
|
5238
4293
|
}
|
|
5239
4294
|
|
|
5240
|
-
function wrap(callback, n) {
|
|
4295
|
+
function wrap$1(callback, n) {
|
|
5241
4296
|
let t = 0;
|
|
5242
4297
|
return () => {
|
|
5243
4298
|
if (t++ >= n) {
|
|
@@ -5265,7 +4320,7 @@ class Ticker {
|
|
|
5265
4320
|
if (useSafe) {
|
|
5266
4321
|
callback = this.app.safe(callback);
|
|
5267
4322
|
}
|
|
5268
|
-
this.callbacks.unshift(n ? wrap(callback, n) : callback) - 1;
|
|
4323
|
+
this.callbacks.unshift(n ? wrap$1(callback, n) : callback) - 1;
|
|
5269
4324
|
}
|
|
5270
4325
|
start() {
|
|
5271
4326
|
if (this.timer === null) {
|
|
@@ -5287,9 +4342,8 @@ class Ticker {
|
|
|
5287
4342
|
* this value is injected during build time via rollup
|
|
5288
4343
|
* */
|
|
5289
4344
|
// @ts-ignore
|
|
5290
|
-
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 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.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;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.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(){if(this.isEmpty)return;const t=this.encoder.flush();this.onBatch(t),this.prepare()}clean(){this.encoder.reset()}}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(){u&&u.finaliseBatch()}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(null!=s){if(\"stop\"===s)return o(),void c().then((()=>{a=h.Stopped}));if(\"forceFlushBatch\"!==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=>{r&&r.push(t)}),s.tabId,(()=>postMessage({type:\"queue_empty\"}))),null===p&&(p=setInterval(o,1e4)),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()}else o()}}();\n";
|
|
4345
|
+
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";
|
|
5291
4346
|
const CANCELED = 'canceled';
|
|
5292
|
-
const uxtStorageKey = 'or_uxt_active';
|
|
5293
4347
|
const bufferStorageKey = 'or_buffer_1';
|
|
5294
4348
|
const UnsuccessfulStart = (reason) => ({ reason, success: false });
|
|
5295
4349
|
const SuccessfulStart = (body) => ({ ...body, success: true });
|
|
@@ -5341,7 +4395,7 @@ class App {
|
|
|
5341
4395
|
this.stopCallbacks = [];
|
|
5342
4396
|
this.commitCallbacks = [];
|
|
5343
4397
|
this.activityState = ActivityState.NotActive;
|
|
5344
|
-
this.version = '17.0.
|
|
4398
|
+
this.version = '17.0.1'; // TODO: version compatability check inside each plugin.
|
|
5345
4399
|
this.socketMode = false;
|
|
5346
4400
|
this.compressionThreshold = 24 * 1000;
|
|
5347
4401
|
this.bc = null;
|
|
@@ -5351,10 +4405,7 @@ class App {
|
|
|
5351
4405
|
this.rootId = null;
|
|
5352
4406
|
this.pageFrames = [];
|
|
5353
4407
|
this.frameOderNumber = 0;
|
|
5354
|
-
this.
|
|
5355
|
-
'feature-flags': true,
|
|
5356
|
-
'usability-test': true,
|
|
5357
|
-
};
|
|
4408
|
+
this.frameLevel = 0;
|
|
5358
4409
|
this.emptyBatchCounter = 0;
|
|
5359
4410
|
/** used by child iframes for crossdomain only */
|
|
5360
4411
|
this.parentActive = false;
|
|
@@ -5382,8 +4433,9 @@ class App {
|
|
|
5382
4433
|
if (data.line === proto.iframeId) {
|
|
5383
4434
|
this.parentActive = true;
|
|
5384
4435
|
this.rootId = data.id;
|
|
5385
|
-
this.session.setSessionToken(data.token);
|
|
4436
|
+
this.session.setSessionToken(data.token, this.projectKey);
|
|
5386
4437
|
this.frameOderNumber = data.frameOrderNumber;
|
|
4438
|
+
this.frameLevel = data.frameLevel;
|
|
5387
4439
|
this.debug.log('starting iframe tracking', data);
|
|
5388
4440
|
this.allowAppStart();
|
|
5389
4441
|
}
|
|
@@ -5424,7 +4476,7 @@ class App {
|
|
|
5424
4476
|
this.trackedFrames.push(data.context);
|
|
5425
4477
|
}
|
|
5426
4478
|
await this.waitStarted();
|
|
5427
|
-
const token = this.session.getSessionToken();
|
|
4479
|
+
const token = this.session.getSessionToken(this.projectKey);
|
|
5428
4480
|
const order = this.trackedFrames.findIndex((f) => f === data.context) + 1;
|
|
5429
4481
|
if (order === 0) {
|
|
5430
4482
|
this.debug.error('Couldnt get order number for iframe', data.context, this.trackedFrames);
|
|
@@ -5433,8 +4485,8 @@ class App {
|
|
|
5433
4485
|
line: proto.iframeId,
|
|
5434
4486
|
id,
|
|
5435
4487
|
token,
|
|
5436
|
-
// since indexes go from 0 we +1
|
|
5437
4488
|
frameOrderNumber: order,
|
|
4489
|
+
frameLevel: this.frameLevel + 1,
|
|
5438
4490
|
};
|
|
5439
4491
|
this.debug.log('Got child frame signal; nodeId', id, event.source, iframeData);
|
|
5440
4492
|
// @ts-ignore
|
|
@@ -5452,7 +4504,8 @@ class App {
|
|
|
5452
4504
|
* */
|
|
5453
4505
|
if (data.line === proto.iframeBatch) {
|
|
5454
4506
|
const msgBatch = data.messages;
|
|
5455
|
-
const mappedMessages =
|
|
4507
|
+
const mappedMessages = [];
|
|
4508
|
+
msgBatch.forEach((msg) => {
|
|
5456
4509
|
if (msg[0] === 20 /* MType.MouseMove */) {
|
|
5457
4510
|
let fixedMessage = msg;
|
|
5458
4511
|
this.pageFrames.forEach((frame) => {
|
|
@@ -5462,7 +4515,7 @@ class App {
|
|
|
5462
4515
|
fixedMessage = [type, x + left, y + top];
|
|
5463
4516
|
}
|
|
5464
4517
|
});
|
|
5465
|
-
|
|
4518
|
+
mappedMessages.push(fixedMessage);
|
|
5466
4519
|
}
|
|
5467
4520
|
if (msg[0] === 68 /* MType.MouseClick */) {
|
|
5468
4521
|
let fixedMessage = msg;
|
|
@@ -5488,9 +4541,11 @@ class App {
|
|
|
5488
4541
|
];
|
|
5489
4542
|
}
|
|
5490
4543
|
});
|
|
5491
|
-
|
|
4544
|
+
mappedMessages.push(fixedMessage);
|
|
4545
|
+
}
|
|
4546
|
+
if (![28 /* MType.UserID */, 29 /* MType.UserAnonymousID */, 30 /* MType.Metadata */].includes(msg[0])) {
|
|
4547
|
+
mappedMessages.push(msg);
|
|
5492
4548
|
}
|
|
5493
|
-
return msg;
|
|
5494
4549
|
});
|
|
5495
4550
|
this.messages.push(...mappedMessages);
|
|
5496
4551
|
}
|
|
@@ -5661,7 +4716,6 @@ class App {
|
|
|
5661
4716
|
});
|
|
5662
4717
|
});
|
|
5663
4718
|
};
|
|
5664
|
-
this.onUxtCb = [];
|
|
5665
4719
|
this.contextId = Math.random().toString(36).slice(2);
|
|
5666
4720
|
this.projectKey = projectKey;
|
|
5667
4721
|
this.networkOptions = options.network;
|
|
@@ -5696,8 +4750,9 @@ class App {
|
|
|
5696
4750
|
useAnimationFrame: false,
|
|
5697
4751
|
},
|
|
5698
4752
|
forceNgOff: false,
|
|
5699
|
-
inlineCss:
|
|
4753
|
+
inlineCss: InlineCssMode.Unset,
|
|
5700
4754
|
disableSprites: false,
|
|
4755
|
+
disableThrottling: false,
|
|
5701
4756
|
};
|
|
5702
4757
|
this.options = simpleMerge(defaultOptions, options);
|
|
5703
4758
|
if (!this.insideIframe &&
|
|
@@ -5728,7 +4783,6 @@ class App {
|
|
|
5728
4783
|
app: this,
|
|
5729
4784
|
isDictDisabled: Boolean(this.options.disableStringDict || this.options.crossdomain?.enabled),
|
|
5730
4785
|
});
|
|
5731
|
-
this.featureFlags = new FeatureFlags(this);
|
|
5732
4786
|
this.tagWatcher = new TagWatcher({
|
|
5733
4787
|
sessionStorage: this.sessionStorage,
|
|
5734
4788
|
errLog: this.debug.error,
|
|
@@ -5753,6 +4807,7 @@ class App {
|
|
|
5753
4807
|
* listen for messages from parent window, so we can signal that we're alive
|
|
5754
4808
|
* */
|
|
5755
4809
|
window.addEventListener('message', this.parentCrossDomainFrameListener);
|
|
4810
|
+
window.addEventListener('message', this.crossDomainIframeListener);
|
|
5756
4811
|
setInterval(() => {
|
|
5757
4812
|
if (document.hidden) {
|
|
5758
4813
|
return;
|
|
@@ -5776,34 +4831,37 @@ class App {
|
|
|
5776
4831
|
line: proto.ask,
|
|
5777
4832
|
source: thisTab,
|
|
5778
4833
|
context: this.contextId,
|
|
4834
|
+
projectKey: this.projectKey,
|
|
5779
4835
|
});
|
|
5780
4836
|
this.startTimeout = setTimeout(() => {
|
|
5781
4837
|
this.allowAppStart();
|
|
5782
4838
|
}, 250);
|
|
5783
4839
|
this.bc.onmessage = (ev) => {
|
|
5784
|
-
if (ev.data.context === this.contextId) {
|
|
4840
|
+
if (ev.data.context === this.contextId || this.projectKey !== ev.data.projectKey) {
|
|
4841
|
+
this.debug.log('same ctx event', ev);
|
|
5785
4842
|
return;
|
|
5786
4843
|
}
|
|
5787
4844
|
this.debug.log(ev);
|
|
5788
4845
|
if (ev.data.line === proto.resp) {
|
|
5789
4846
|
const sessionToken = ev.data.token;
|
|
5790
|
-
this.session.setSessionToken(sessionToken);
|
|
4847
|
+
this.session.setSessionToken(sessionToken, this.projectKey);
|
|
5791
4848
|
this.allowAppStart();
|
|
5792
4849
|
}
|
|
5793
4850
|
if (ev.data.line === proto.reg) {
|
|
5794
4851
|
const sessionToken = ev.data.token;
|
|
5795
4852
|
this.session.regenerateTabId();
|
|
5796
|
-
this.session.setSessionToken(sessionToken);
|
|
4853
|
+
this.session.setSessionToken(sessionToken, this.projectKey);
|
|
5797
4854
|
this.allowAppStart();
|
|
5798
4855
|
}
|
|
5799
4856
|
if (ev.data.line === proto.ask) {
|
|
5800
|
-
const token = this.session.getSessionToken();
|
|
4857
|
+
const token = this.session.getSessionToken(this.projectKey);
|
|
5801
4858
|
if (token && this.bc) {
|
|
5802
4859
|
this.bc.postMessage({
|
|
5803
4860
|
line: ev.data.source === thisTab ? proto.reg : proto.resp,
|
|
5804
4861
|
token,
|
|
5805
4862
|
source: thisTab,
|
|
5806
4863
|
context: this.contextId,
|
|
4864
|
+
projectKey: this.projectKey,
|
|
5807
4865
|
});
|
|
5808
4866
|
}
|
|
5809
4867
|
}
|
|
@@ -5860,16 +4918,23 @@ class App {
|
|
|
5860
4918
|
this.worker.onmessage = ({ data }) => {
|
|
5861
4919
|
this.handleWorkerMsg(data);
|
|
5862
4920
|
};
|
|
4921
|
+
let closing = false;
|
|
5863
4922
|
const alertWorker = () => {
|
|
4923
|
+
if (closing) {
|
|
4924
|
+
return;
|
|
4925
|
+
}
|
|
4926
|
+
closing = true;
|
|
4927
|
+
setTimeout(() => {
|
|
4928
|
+
closing = false;
|
|
4929
|
+
}, 500);
|
|
5864
4930
|
if (this.worker) {
|
|
5865
|
-
this.worker.postMessage(
|
|
4931
|
+
this.worker.postMessage('closing');
|
|
5866
4932
|
}
|
|
5867
4933
|
};
|
|
5868
|
-
// keep better tactics, discard others?
|
|
5869
|
-
this.attachEventListener(window, 'beforeunload', alertWorker, false);
|
|
5870
4934
|
this.attachEventListener(document.body, 'mouseleave', alertWorker, false, false);
|
|
4935
|
+
this.attachEventListener(window, 'pagehide', alertWorker, false, false);
|
|
5871
4936
|
// TODO: stop session after inactivity timeout (make configurable)
|
|
5872
|
-
this.attachEventListener(document, 'visibilitychange', alertWorker, false);
|
|
4937
|
+
this.attachEventListener(document, 'visibilitychange', (e) => document.visibilityState === 'hidden' && alertWorker(), false);
|
|
5873
4938
|
}
|
|
5874
4939
|
catch (e) {
|
|
5875
4940
|
this._debug('worker_start', e);
|
|
@@ -6064,7 +5129,7 @@ class App {
|
|
|
6064
5129
|
};
|
|
6065
5130
|
}
|
|
6066
5131
|
getSessionToken() {
|
|
6067
|
-
return this.session.getSessionToken();
|
|
5132
|
+
return this.session.getSessionToken(this.projectKey);
|
|
6068
5133
|
}
|
|
6069
5134
|
getSessionID() {
|
|
6070
5135
|
return this.session.getInfo().sessionID || undefined;
|
|
@@ -6126,7 +5191,7 @@ class App {
|
|
|
6126
5191
|
checkSessionToken(forceNew) {
|
|
6127
5192
|
const lsReset = this.sessionStorage.getItem(this.options.session_reset_key) !== null;
|
|
6128
5193
|
const needNewSessionID = forceNew || lsReset;
|
|
6129
|
-
const sessionToken = this.session.getSessionToken();
|
|
5194
|
+
const sessionToken = this.session.getSessionToken(this.projectKey);
|
|
6130
5195
|
return needNewSessionID || !sessionToken;
|
|
6131
5196
|
}
|
|
6132
5197
|
/**
|
|
@@ -6204,8 +5269,7 @@ class App {
|
|
|
6204
5269
|
const {
|
|
6205
5270
|
// this token is needed to fetch conditions and flags,
|
|
6206
5271
|
// but it can't be used to record a session
|
|
6207
|
-
token, userBrowser, userCity, userCountry, userDevice, userOS, userState, projectID,
|
|
6208
|
-
this.features = features ? features : this.features;
|
|
5272
|
+
token, userBrowser, userCity, userCountry, userDevice, userOS, userState, projectID, } = await r.json();
|
|
6209
5273
|
this.session.assign({ projectID });
|
|
6210
5274
|
this.session.setUserInfo({
|
|
6211
5275
|
userBrowser,
|
|
@@ -6218,10 +5282,6 @@ class App {
|
|
|
6218
5282
|
const onStartInfo = { sessionToken: token, userUUID: '', sessionID: '' };
|
|
6219
5283
|
this.startCallbacks.forEach((cb) => cb(onStartInfo));
|
|
6220
5284
|
await this.conditionsManager?.fetchConditions(projectID, token);
|
|
6221
|
-
if (this.features['feature-flags']) {
|
|
6222
|
-
await this.featureFlags.reloadFlags(token);
|
|
6223
|
-
this.conditionsManager?.processFlags(this.featureFlags.flags);
|
|
6224
|
-
}
|
|
6225
5285
|
await this.tagWatcher.fetchTags(this.options.ingestPoint, token);
|
|
6226
5286
|
}
|
|
6227
5287
|
/**
|
|
@@ -6345,7 +5405,7 @@ class App {
|
|
|
6345
5405
|
while (this.bufferedMessages1.length > 0) {
|
|
6346
5406
|
await this.flushBuffer(this.bufferedMessages1);
|
|
6347
5407
|
}
|
|
6348
|
-
this.postToWorker([[
|
|
5408
|
+
this.postToWorker([[-1]]);
|
|
6349
5409
|
this.clearBuffers();
|
|
6350
5410
|
}
|
|
6351
5411
|
async _start(startOpts = {}, resetByWorker = false, conditionName) {
|
|
@@ -6393,7 +5453,7 @@ class App {
|
|
|
6393
5453
|
connAttemptGap: this.options.connAttemptGap,
|
|
6394
5454
|
tabId: this.session.getTabId(),
|
|
6395
5455
|
});
|
|
6396
|
-
const sessionToken = this.session.getSessionToken();
|
|
5456
|
+
const sessionToken = this.session.getSessionToken(this.projectKey);
|
|
6397
5457
|
const isNewSession = this.checkSessionToken(startOpts.forceNew);
|
|
6398
5458
|
this.sessionStorage.removeItem(this.options.session_reset_key);
|
|
6399
5459
|
this.debug.log('OpenReplay: starting session; need new session id?', isNewSession, 'session token: ', sessionToken);
|
|
@@ -6433,8 +5493,7 @@ class App {
|
|
|
6433
5493
|
delay, // derived from token
|
|
6434
5494
|
sessionID, // derived from token
|
|
6435
5495
|
startTimestamp, // real startTS (server time), derived from sessionID
|
|
6436
|
-
userBrowser, userCity, userCountry, userDevice, userOS, userState, canvasEnabled, canvasQuality, canvasFPS, assistOnly: socketOnly,
|
|
6437
|
-
this.features = features ? features : this.features;
|
|
5496
|
+
userBrowser, userCity, userCountry, userDevice, userOS, userState, canvasEnabled, canvasQuality, canvasFPS, assistOnly: socketOnly, } = await r.json();
|
|
6438
5497
|
if (typeof token !== 'string' ||
|
|
6439
5498
|
typeof userUUID !== 'string' ||
|
|
6440
5499
|
(typeof startTimestamp !== 'number' && typeof startTimestamp !== 'undefined') ||
|
|
@@ -6446,7 +5505,7 @@ class App {
|
|
|
6446
5505
|
return UnsuccessfulStart(reason);
|
|
6447
5506
|
}
|
|
6448
5507
|
this.delay = delay;
|
|
6449
|
-
this.session.setSessionToken(token);
|
|
5508
|
+
this.session.setSessionToken(token, this.projectKey);
|
|
6450
5509
|
this.session.setUserInfo({
|
|
6451
5510
|
userBrowser,
|
|
6452
5511
|
userCity,
|
|
@@ -6487,12 +5546,9 @@ class App {
|
|
|
6487
5546
|
if (startOpts.startCallback) {
|
|
6488
5547
|
startOpts.startCallback(SuccessfulStart(onStartInfo));
|
|
6489
5548
|
}
|
|
6490
|
-
if (this.features['feature-flags']) {
|
|
6491
|
-
void this.featureFlags.reloadFlags();
|
|
6492
|
-
}
|
|
6493
5549
|
await this.tagWatcher.fetchTags(this.options.ingestPoint, token);
|
|
6494
5550
|
this.activityState = ActivityState.Active;
|
|
6495
|
-
if (this.options.crossdomain?.enabled
|
|
5551
|
+
if (this.options.crossdomain?.enabled) {
|
|
6496
5552
|
void this.bootChildrenFrames();
|
|
6497
5553
|
}
|
|
6498
5554
|
if (canvasEnabled && !this.options.canvas.disableCanvas) {
|
|
@@ -6518,47 +5574,14 @@ class App {
|
|
|
6518
5574
|
this.commit();
|
|
6519
5575
|
/** --------------- COLD START BUFFER ------------------*/
|
|
6520
5576
|
}
|
|
5577
|
+
if (this.insideIframe && this.rootId) {
|
|
5578
|
+
this.observer.crossdomainObserve(this.rootId, this.frameOderNumber, this.frameLevel);
|
|
5579
|
+
}
|
|
6521
5580
|
else {
|
|
6522
|
-
|
|
6523
|
-
this.observer.crossdomainObserve(this.rootId, this.frameOderNumber);
|
|
6524
|
-
}
|
|
6525
|
-
else {
|
|
6526
|
-
this.observer.observe();
|
|
6527
|
-
}
|
|
6528
|
-
this.ticker.start();
|
|
5581
|
+
this.observer.observe();
|
|
6529
5582
|
}
|
|
5583
|
+
this.ticker.start();
|
|
6530
5584
|
this.canvasRecorder?.startTracking();
|
|
6531
|
-
if (this.features['usability-test'] && !this.insideIframe) {
|
|
6532
|
-
this.uxtManager = this.uxtManager
|
|
6533
|
-
? this.uxtManager
|
|
6534
|
-
: new UserTestManager(this, uxtStorageKey);
|
|
6535
|
-
let uxtId;
|
|
6536
|
-
const savedUxtTag = this.localStorage.getItem(uxtStorageKey);
|
|
6537
|
-
if (savedUxtTag) {
|
|
6538
|
-
uxtId = parseInt(savedUxtTag, 10);
|
|
6539
|
-
}
|
|
6540
|
-
if (location?.search) {
|
|
6541
|
-
const query = new URLSearchParams(location.search);
|
|
6542
|
-
if (query.has('oruxt')) {
|
|
6543
|
-
const qId = query.get('oruxt');
|
|
6544
|
-
uxtId = qId ? parseInt(qId, 10) : undefined;
|
|
6545
|
-
}
|
|
6546
|
-
}
|
|
6547
|
-
if (uxtId) {
|
|
6548
|
-
if (!this.uxtManager.isActive) {
|
|
6549
|
-
// eslint-disable-next-line
|
|
6550
|
-
this.uxtManager.getTest(uxtId, token, Boolean(savedUxtTag)).then((id) => {
|
|
6551
|
-
if (id) {
|
|
6552
|
-
this.onUxtCb.forEach((cb) => cb(id));
|
|
6553
|
-
}
|
|
6554
|
-
});
|
|
6555
|
-
}
|
|
6556
|
-
else {
|
|
6557
|
-
// @ts-ignore
|
|
6558
|
-
this.onUxtCb.forEach((cb) => cb(uxtId));
|
|
6559
|
-
}
|
|
6560
|
-
}
|
|
6561
|
-
}
|
|
6562
5585
|
return SuccessfulStart(onStartInfo);
|
|
6563
5586
|
}
|
|
6564
5587
|
catch (reason) {
|
|
@@ -6579,13 +5602,6 @@ class App {
|
|
|
6579
5602
|
return UnsuccessfulStart(errorMessage);
|
|
6580
5603
|
}
|
|
6581
5604
|
}
|
|
6582
|
-
addOnUxtCb(cb) {
|
|
6583
|
-
// @ts-ignore
|
|
6584
|
-
this.onUxtCb.push(cb);
|
|
6585
|
-
}
|
|
6586
|
-
getUxtId() {
|
|
6587
|
-
return this.uxtManager?.getTestId();
|
|
6588
|
-
}
|
|
6589
5605
|
async waitStart() {
|
|
6590
5606
|
return new Promise((resolve) => {
|
|
6591
5607
|
const int = setInterval(() => {
|
|
@@ -6674,7 +5690,7 @@ class App {
|
|
|
6674
5690
|
stop(stopWorker = true) {
|
|
6675
5691
|
if (this.activityState !== ActivityState.NotActive) {
|
|
6676
5692
|
try {
|
|
6677
|
-
if (
|
|
5693
|
+
if (this.options.crossdomain?.enabled) {
|
|
6678
5694
|
this.killChildrenFrames();
|
|
6679
5695
|
}
|
|
6680
5696
|
this.attributeSender.clear();
|
|
@@ -6706,9 +5722,16 @@ function Connection (app) {
|
|
|
6706
5722
|
if (connection === undefined) {
|
|
6707
5723
|
return;
|
|
6708
5724
|
}
|
|
6709
|
-
const sendConnectionInformation = () =>
|
|
6710
|
-
|
|
6711
|
-
|
|
5725
|
+
const sendConnectionInformation = () => {
|
|
5726
|
+
app.send(ConnectionInformation(Math.round(connection.downlink * 1000), connection.effectiveType || 'unknown'));
|
|
5727
|
+
};
|
|
5728
|
+
app.attachStartCallback(() => {
|
|
5729
|
+
sendConnectionInformation();
|
|
5730
|
+
connection.addEventListener('change', sendConnectionInformation);
|
|
5731
|
+
});
|
|
5732
|
+
app.attachStopCallback(() => {
|
|
5733
|
+
connection.removeEventListener('change', sendConnectionInformation);
|
|
5734
|
+
});
|
|
6712
5735
|
}
|
|
6713
5736
|
|
|
6714
5737
|
const printError = IN_BROWSER && 'InstallTrigger' in window // detect Firefox
|
|
@@ -7381,308 +6404,11 @@ function Input (app, opts) {
|
|
|
7381
6404
|
}));
|
|
7382
6405
|
}
|
|
7383
6406
|
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
const
|
|
7388
|
-
|
|
7389
|
-
function attr(name, value) {
|
|
7390
|
-
let nameIsOk = acceptedAttrNames.has(name);
|
|
7391
|
-
nameIsOk ||= name.startsWith('data-') && wordLike(name);
|
|
7392
|
-
let valueIsOk = wordLike(value) && value.length < 100;
|
|
7393
|
-
valueIsOk ||= value.startsWith('#') && wordLike(value.slice(1));
|
|
7394
|
-
return nameIsOk && valueIsOk;
|
|
7395
|
-
}
|
|
7396
|
-
/** Check if id name is word-like. */
|
|
7397
|
-
function idName(name) {
|
|
7398
|
-
return wordLike(name);
|
|
7399
|
-
}
|
|
7400
|
-
/** Check if class name is word-like. */
|
|
7401
|
-
function className(name) {
|
|
7402
|
-
return wordLike(name);
|
|
7403
|
-
}
|
|
7404
|
-
/** Check if tag name is word-like. */
|
|
7405
|
-
function tagName(name) {
|
|
7406
|
-
return true;
|
|
7407
|
-
}
|
|
7408
|
-
/** Finds unique CSS selectors for the given element. */
|
|
7409
|
-
function finder(input, options) {
|
|
7410
|
-
if (input.nodeType !== Node.ELEMENT_NODE) {
|
|
7411
|
-
throw new Error(`Can't generate CSS selector for non-element node type.`);
|
|
7412
|
-
}
|
|
7413
|
-
if (input.tagName.toLowerCase() === 'html') {
|
|
7414
|
-
return 'html';
|
|
7415
|
-
}
|
|
7416
|
-
const defaults = {
|
|
7417
|
-
root: document.body,
|
|
7418
|
-
idName: idName,
|
|
7419
|
-
className: className,
|
|
7420
|
-
tagName: tagName,
|
|
7421
|
-
attr: attr,
|
|
7422
|
-
timeoutMs: 1000,
|
|
7423
|
-
seedMinLength: 3,
|
|
7424
|
-
optimizedMinLength: 2,
|
|
7425
|
-
maxNumberOfPathChecks: Infinity,
|
|
7426
|
-
};
|
|
7427
|
-
const startTime = new Date();
|
|
7428
|
-
const config = { ...defaults, ...options };
|
|
7429
|
-
const rootDocument = findRootDocument(config.root, defaults);
|
|
7430
|
-
let foundPath;
|
|
7431
|
-
let count = 0;
|
|
7432
|
-
for (const candidate of search(input, config, rootDocument)) {
|
|
7433
|
-
const elapsedTimeMs = new Date().getTime() - startTime.getTime();
|
|
7434
|
-
if (elapsedTimeMs > config.timeoutMs ||
|
|
7435
|
-
count >= config.maxNumberOfPathChecks) {
|
|
7436
|
-
const fPath = fallback(input, rootDocument);
|
|
7437
|
-
if (!fPath) {
|
|
7438
|
-
throw new Error(`Timeout: Can't find a unique selector after ${config.timeoutMs}ms`);
|
|
7439
|
-
}
|
|
7440
|
-
return selector(fPath);
|
|
7441
|
-
}
|
|
7442
|
-
count++;
|
|
7443
|
-
if (unique(candidate, rootDocument)) {
|
|
7444
|
-
foundPath = candidate;
|
|
7445
|
-
break;
|
|
7446
|
-
}
|
|
7447
|
-
}
|
|
7448
|
-
if (!foundPath) {
|
|
7449
|
-
throw new Error(`Selector was not found.`);
|
|
7450
|
-
}
|
|
7451
|
-
const optimized = [
|
|
7452
|
-
...optimize(foundPath, input, config, rootDocument, startTime),
|
|
7453
|
-
];
|
|
7454
|
-
optimized.sort(byPenalty);
|
|
7455
|
-
if (optimized.length > 0) {
|
|
7456
|
-
return selector(optimized[0]);
|
|
7457
|
-
}
|
|
7458
|
-
return selector(foundPath);
|
|
7459
|
-
}
|
|
7460
|
-
function* search(input, config, rootDocument) {
|
|
7461
|
-
const stack = [];
|
|
7462
|
-
let paths = [];
|
|
7463
|
-
let current = input;
|
|
7464
|
-
let i = 0;
|
|
7465
|
-
while (current && current !== rootDocument) {
|
|
7466
|
-
const level = tie(current, config);
|
|
7467
|
-
for (const node of level) {
|
|
7468
|
-
node.level = i;
|
|
7469
|
-
}
|
|
7470
|
-
stack.push(level);
|
|
7471
|
-
current = current.parentElement;
|
|
7472
|
-
i++;
|
|
7473
|
-
paths.push(...combinations(stack));
|
|
7474
|
-
if (i >= config.seedMinLength) {
|
|
7475
|
-
paths.sort(byPenalty);
|
|
7476
|
-
for (const candidate of paths) {
|
|
7477
|
-
yield candidate;
|
|
7478
|
-
}
|
|
7479
|
-
paths = [];
|
|
7480
|
-
}
|
|
7481
|
-
}
|
|
7482
|
-
paths.sort(byPenalty);
|
|
7483
|
-
for (const candidate of paths) {
|
|
7484
|
-
yield candidate;
|
|
7485
|
-
}
|
|
7486
|
-
}
|
|
7487
|
-
function wordLike(name) {
|
|
7488
|
-
if (/^[a-z\-]{3,}$/i.test(name)) {
|
|
7489
|
-
const words = name.split(/-|[A-Z]/);
|
|
7490
|
-
for (const word of words) {
|
|
7491
|
-
if (word.length <= 2) {
|
|
7492
|
-
return false;
|
|
7493
|
-
}
|
|
7494
|
-
if (/[^aeiou]{4,}/i.test(word)) {
|
|
7495
|
-
return false;
|
|
7496
|
-
}
|
|
7497
|
-
}
|
|
7498
|
-
return true;
|
|
7499
|
-
}
|
|
7500
|
-
return false;
|
|
7501
|
-
}
|
|
7502
|
-
function tie(element, config) {
|
|
7503
|
-
const level = [];
|
|
7504
|
-
const elementId = element.getAttribute('id');
|
|
7505
|
-
if (elementId && config.idName(elementId)) {
|
|
7506
|
-
level.push({
|
|
7507
|
-
name: '#' + CSS.escape(elementId),
|
|
7508
|
-
penalty: 0,
|
|
7509
|
-
});
|
|
7510
|
-
}
|
|
7511
|
-
for (let i = 0; i < element.classList.length; i++) {
|
|
7512
|
-
const name = element.classList[i];
|
|
7513
|
-
if (config.className(name)) {
|
|
7514
|
-
level.push({
|
|
7515
|
-
name: '.' + CSS.escape(name),
|
|
7516
|
-
penalty: 1,
|
|
7517
|
-
});
|
|
7518
|
-
}
|
|
7519
|
-
}
|
|
7520
|
-
for (let i = 0; i < element.attributes.length; i++) {
|
|
7521
|
-
const attr = element.attributes[i];
|
|
7522
|
-
if (config.attr(attr.name, attr.value)) {
|
|
7523
|
-
level.push({
|
|
7524
|
-
name: `[${CSS.escape(attr.name)}="${CSS.escape(attr.value)}"]`,
|
|
7525
|
-
penalty: 2,
|
|
7526
|
-
});
|
|
7527
|
-
}
|
|
7528
|
-
}
|
|
7529
|
-
const tagName = element.tagName.toLowerCase();
|
|
7530
|
-
if (config.tagName(tagName)) {
|
|
7531
|
-
level.push({
|
|
7532
|
-
name: tagName,
|
|
7533
|
-
penalty: 5,
|
|
7534
|
-
});
|
|
7535
|
-
const index = indexOf(element, tagName);
|
|
7536
|
-
if (index !== undefined) {
|
|
7537
|
-
level.push({
|
|
7538
|
-
name: nthOfType(tagName, index),
|
|
7539
|
-
penalty: 10,
|
|
7540
|
-
});
|
|
7541
|
-
}
|
|
7542
|
-
}
|
|
7543
|
-
const nth = indexOf(element);
|
|
7544
|
-
if (nth !== undefined) {
|
|
7545
|
-
level.push({
|
|
7546
|
-
name: nthChild(tagName, nth),
|
|
7547
|
-
penalty: 50,
|
|
7548
|
-
});
|
|
7549
|
-
}
|
|
7550
|
-
return level;
|
|
7551
|
-
}
|
|
7552
|
-
function selector(path) {
|
|
7553
|
-
let node = path[0];
|
|
7554
|
-
let query = node.name;
|
|
7555
|
-
for (let i = 1; i < path.length; i++) {
|
|
7556
|
-
const level = path[i].level || 0;
|
|
7557
|
-
if (node.level === level - 1) {
|
|
7558
|
-
query = `${path[i].name} > ${query}`;
|
|
7559
|
-
}
|
|
7560
|
-
else {
|
|
7561
|
-
query = `${path[i].name} ${query}`;
|
|
7562
|
-
}
|
|
7563
|
-
node = path[i];
|
|
7564
|
-
}
|
|
7565
|
-
return query;
|
|
7566
|
-
}
|
|
7567
|
-
function penalty(path) {
|
|
7568
|
-
return path.map((node) => node.penalty).reduce((acc, i) => acc + i, 0);
|
|
7569
|
-
}
|
|
7570
|
-
function byPenalty(a, b) {
|
|
7571
|
-
return penalty(a) - penalty(b);
|
|
7572
|
-
}
|
|
7573
|
-
function indexOf(input, tagName) {
|
|
7574
|
-
const parent = input.parentNode;
|
|
7575
|
-
if (!parent) {
|
|
7576
|
-
return undefined;
|
|
7577
|
-
}
|
|
7578
|
-
let child = parent.firstChild;
|
|
7579
|
-
if (!child) {
|
|
7580
|
-
return undefined;
|
|
7581
|
-
}
|
|
7582
|
-
let i = 0;
|
|
7583
|
-
while (child) {
|
|
7584
|
-
if (child.nodeType === Node.ELEMENT_NODE &&
|
|
7585
|
-
(tagName === undefined ||
|
|
7586
|
-
child.tagName.toLowerCase() === tagName)) {
|
|
7587
|
-
i++;
|
|
7588
|
-
}
|
|
7589
|
-
if (child === input) {
|
|
7590
|
-
break;
|
|
7591
|
-
}
|
|
7592
|
-
child = child.nextSibling;
|
|
7593
|
-
}
|
|
7594
|
-
return i;
|
|
7595
|
-
}
|
|
7596
|
-
function fallback(input, rootDocument) {
|
|
7597
|
-
let i = 0;
|
|
7598
|
-
let current = input;
|
|
7599
|
-
const path = [];
|
|
7600
|
-
while (current && current !== rootDocument) {
|
|
7601
|
-
const tagName = current.tagName.toLowerCase();
|
|
7602
|
-
const index = indexOf(current, tagName);
|
|
7603
|
-
if (index === undefined) {
|
|
7604
|
-
return;
|
|
7605
|
-
}
|
|
7606
|
-
path.push({
|
|
7607
|
-
name: nthOfType(tagName, index),
|
|
7608
|
-
penalty: NaN,
|
|
7609
|
-
level: i,
|
|
7610
|
-
});
|
|
7611
|
-
current = current.parentElement;
|
|
7612
|
-
i++;
|
|
7613
|
-
}
|
|
7614
|
-
if (unique(path, rootDocument)) {
|
|
7615
|
-
return path;
|
|
7616
|
-
}
|
|
7617
|
-
}
|
|
7618
|
-
function nthChild(tagName, index) {
|
|
7619
|
-
if (tagName === 'html') {
|
|
7620
|
-
return 'html';
|
|
7621
|
-
}
|
|
7622
|
-
return `${tagName}:nth-child(${index})`;
|
|
7623
|
-
}
|
|
7624
|
-
function nthOfType(tagName, index) {
|
|
7625
|
-
if (tagName === 'html') {
|
|
7626
|
-
return 'html';
|
|
7627
|
-
}
|
|
7628
|
-
return `${tagName}:nth-of-type(${index})`;
|
|
7629
|
-
}
|
|
7630
|
-
function* combinations(stack, path = []) {
|
|
7631
|
-
if (stack.length > 0) {
|
|
7632
|
-
for (let node of stack[0]) {
|
|
7633
|
-
yield* combinations(stack.slice(1, stack.length), path.concat(node));
|
|
7634
|
-
}
|
|
7635
|
-
}
|
|
7636
|
-
else {
|
|
7637
|
-
yield path;
|
|
7638
|
-
}
|
|
7639
|
-
}
|
|
7640
|
-
function findRootDocument(rootNode, defaults) {
|
|
7641
|
-
if (rootNode.nodeType === Node.DOCUMENT_NODE) {
|
|
7642
|
-
return rootNode;
|
|
7643
|
-
}
|
|
7644
|
-
if (rootNode === defaults.root) {
|
|
7645
|
-
return rootNode.ownerDocument;
|
|
7646
|
-
}
|
|
7647
|
-
return rootNode;
|
|
7648
|
-
}
|
|
7649
|
-
function unique(path, rootDocument) {
|
|
7650
|
-
const css = selector(path);
|
|
7651
|
-
switch (rootDocument.querySelectorAll(css).length) {
|
|
7652
|
-
case 0:
|
|
7653
|
-
throw new Error(`Can't select any node with this selector: ${css}`);
|
|
7654
|
-
case 1:
|
|
7655
|
-
return true;
|
|
7656
|
-
default:
|
|
7657
|
-
return false;
|
|
7658
|
-
}
|
|
7659
|
-
}
|
|
7660
|
-
function* optimize(path, input, config, rootDocument, startTime) {
|
|
7661
|
-
if (path.length > 2 && path.length > config.optimizedMinLength) {
|
|
7662
|
-
for (let i = 1; i < path.length - 1; i++) {
|
|
7663
|
-
const elapsedTimeMs = new Date().getTime() - startTime.getTime();
|
|
7664
|
-
if (elapsedTimeMs > config.timeoutMs) {
|
|
7665
|
-
return;
|
|
7666
|
-
}
|
|
7667
|
-
const newPath = [...path];
|
|
7668
|
-
newPath.splice(i, 1);
|
|
7669
|
-
if (unique(newPath, rootDocument) &&
|
|
7670
|
-
rootDocument.querySelector(selector(newPath)) === input) {
|
|
7671
|
-
yield newPath;
|
|
7672
|
-
yield* optimize(newPath, input, config, rootDocument, startTime);
|
|
7673
|
-
}
|
|
7674
|
-
}
|
|
7675
|
-
}
|
|
7676
|
-
}
|
|
7677
|
-
|
|
7678
|
-
function _getSelector(target, document, options) {
|
|
7679
|
-
const selector = finder(target, {
|
|
7680
|
-
root: document.body,
|
|
7681
|
-
seedMinLength: 3,
|
|
7682
|
-
optimizedMinLength: options?.minSelectorDepth || 2,
|
|
7683
|
-
maxNumberOfPathChecks: options?.maxOptimiseTries || 10000,
|
|
7684
|
-
});
|
|
7685
|
-
return selector;
|
|
6407
|
+
const cssEscape = (typeof CSS !== 'undefined' && CSS.escape) || ((t) => t);
|
|
6408
|
+
const docClassCache = new WeakMap();
|
|
6409
|
+
function _getSelector(target) {
|
|
6410
|
+
const selector = getCSSPath(target);
|
|
6411
|
+
return selector || '';
|
|
7686
6412
|
}
|
|
7687
6413
|
function isClickable(element) {
|
|
7688
6414
|
const tag = element.tagName.toUpperCase();
|
|
@@ -7802,8 +6528,8 @@ function Mouse (app, options) {
|
|
|
7802
6528
|
}
|
|
7803
6529
|
};
|
|
7804
6530
|
const patchDocument = (document, topframe = false) => {
|
|
7805
|
-
function getSelector(id, target
|
|
7806
|
-
return (selectorMap[id] = selectorMap[id] || _getSelector(target
|
|
6531
|
+
function getSelector(id, target) {
|
|
6532
|
+
return (selectorMap[id] = selectorMap[id] || _getSelector(target));
|
|
7807
6533
|
}
|
|
7808
6534
|
const attachListener = topframe
|
|
7809
6535
|
? app.attachEventListener.bind(app) // attached/removed on start/stop
|
|
@@ -7842,7 +6568,7 @@ function Mouse (app, options) {
|
|
|
7842
6568
|
const normalizedY = roundNumber(clickY / contentHeight);
|
|
7843
6569
|
sendMouseMove();
|
|
7844
6570
|
const label = getTargetLabel(target);
|
|
7845
|
-
app.send(MouseClick(id, mouseTarget === target ? Math.round(performance.now() - mouseTargetTime) : 0, app.sanitizer.privateMode ? label.replaceAll(/./g, '*') : label, isClickable(target) && !disableClickmaps ? getSelector(id, target
|
|
6571
|
+
app.send(MouseClick(id, mouseTarget === target ? Math.round(performance.now() - mouseTargetTime) : 0, app.sanitizer.privateMode ? label.replaceAll(/./g, '*') : label, isClickable(target) && !disableClickmaps ? getSelector(id, target) : '', normalizedX, normalizedY), true);
|
|
7846
6572
|
}
|
|
7847
6573
|
mouseTarget = null;
|
|
7848
6574
|
});
|
|
@@ -7862,8 +6588,90 @@ function Mouse (app, options) {
|
|
|
7862
6588
|
function roundNumber(num) {
|
|
7863
6589
|
return Math.round(num * 1e4);
|
|
7864
6590
|
}
|
|
6591
|
+
function isDocUniqueClass(cls, doc) {
|
|
6592
|
+
let cache = docClassCache.get(doc);
|
|
6593
|
+
if (!cache) {
|
|
6594
|
+
cache = Object.create(null);
|
|
6595
|
+
docClassCache.set(doc, cache);
|
|
6596
|
+
}
|
|
6597
|
+
if (cls in cache)
|
|
6598
|
+
return cache[cls];
|
|
6599
|
+
const unique = doc.querySelectorAll(`.${cssEscape(cls)}`).length === 1;
|
|
6600
|
+
cache[cls] = unique;
|
|
6601
|
+
return unique;
|
|
6602
|
+
}
|
|
6603
|
+
function wordLike(name) {
|
|
6604
|
+
if (/^[a-z\-]{3,}$/i.test(name)) {
|
|
6605
|
+
const words = name.split(/-|[A-Z]/);
|
|
6606
|
+
for (const word of words) {
|
|
6607
|
+
if (word.length <= 2) {
|
|
6608
|
+
return false;
|
|
6609
|
+
}
|
|
6610
|
+
if (/[^aeiou]{4,}/i.test(word)) {
|
|
6611
|
+
return false;
|
|
6612
|
+
}
|
|
6613
|
+
}
|
|
6614
|
+
return true;
|
|
6615
|
+
}
|
|
6616
|
+
return false;
|
|
6617
|
+
}
|
|
6618
|
+
function getCSSPath(el) {
|
|
6619
|
+
if (!el || el.nodeType !== 1)
|
|
6620
|
+
return false;
|
|
6621
|
+
if (el.id)
|
|
6622
|
+
return `#${cssEscape(el.id)}`;
|
|
6623
|
+
const parts = [];
|
|
6624
|
+
while (el && el.nodeType === 1 && el !== el.ownerDocument) {
|
|
6625
|
+
if (el.id) {
|
|
6626
|
+
parts.unshift(`#${cssEscape(el.id)}`);
|
|
6627
|
+
break;
|
|
6628
|
+
}
|
|
6629
|
+
const tag = el.tagName.toLowerCase();
|
|
6630
|
+
if (el.classList?.length) {
|
|
6631
|
+
for (const cls of el.classList) {
|
|
6632
|
+
if (wordLike(cls) && isDocUniqueClass(cls, el.ownerDocument)) {
|
|
6633
|
+
parts.unshift(`${tag}.${cssEscape(cls)}`);
|
|
6634
|
+
return parts.join(' > ');
|
|
6635
|
+
}
|
|
6636
|
+
}
|
|
6637
|
+
}
|
|
6638
|
+
const sibCls = getUniqueSiblingClass(el);
|
|
6639
|
+
if (sibCls) {
|
|
6640
|
+
parts.unshift(`${tag}.${cssEscape(sibCls)}`);
|
|
6641
|
+
}
|
|
6642
|
+
else if (el === el.ownerDocument.body ||
|
|
6643
|
+
el === el.ownerDocument.documentElement) {
|
|
6644
|
+
parts.unshift(tag);
|
|
6645
|
+
}
|
|
6646
|
+
else {
|
|
6647
|
+
let idx = 1;
|
|
6648
|
+
for (let sib = el.previousElementSibling; sib; sib = sib.previousElementSibling) {
|
|
6649
|
+
if (sib.tagName.toLowerCase() === tag)
|
|
6650
|
+
idx++;
|
|
6651
|
+
}
|
|
6652
|
+
parts.unshift(`${tag}:nth-of-type(${idx})`);
|
|
6653
|
+
}
|
|
6654
|
+
el = el.parentNode;
|
|
6655
|
+
}
|
|
6656
|
+
return parts.join(' > ');
|
|
6657
|
+
}
|
|
6658
|
+
function getUniqueSiblingClass(el) {
|
|
6659
|
+
if (!el.classList?.length || !el.parentNode)
|
|
6660
|
+
return null;
|
|
6661
|
+
const sibs = el.parentNode.children;
|
|
6662
|
+
outer: for (const cls of el.classList) {
|
|
6663
|
+
if (!wordLike(cls) || !isDocUniqueClass(cls, el.ownerDocument))
|
|
6664
|
+
continue;
|
|
6665
|
+
for (const sib of sibs) {
|
|
6666
|
+
if (sib !== el && sib.classList?.contains(cls))
|
|
6667
|
+
continue outer;
|
|
6668
|
+
}
|
|
6669
|
+
return cls;
|
|
6670
|
+
}
|
|
6671
|
+
return null;
|
|
6672
|
+
}
|
|
7865
6673
|
|
|
7866
|
-
|
|
6674
|
+
let e=-1;const t=t=>{addEventListener("pageshow",(n=>{n.persisted&&(e=n.timeStamp,t(n));}),true);},n=(e,t,n,i)=>{let s,o;return r=>{t.value>=0&&(r||i)&&(o=t.value-(s??0),(o||void 0===s)&&(s=t.value,t.delta=o,t.rating=((e,t)=>e>t[1]?"poor":e>t[0]?"needs-improvement":"good")(t.value,n),e(t)));}},i=e=>{requestAnimationFrame((()=>requestAnimationFrame((()=>e()))));},s=()=>{const e=performance.getEntriesByType("navigation")[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},o=()=>{const e=s();return e?.activationStart??0},r=(t,n=-1)=>{const i=s();let r="navigate";e>=0?r="back-forward-cache":i&&(document.prerendering||o()>0?r="prerender":document.wasDiscarded?r="restore":i.type&&(r=i.type.replace(/_/g,"-")));return {name:t,value:n,rating:"good",delta:0,entries:[],id:`v5-${Date.now()}-${Math.floor(8999999999999*Math.random())+1e12}`,navigationType:r}},c=new WeakMap;function a(e,t){return c.get(e)||c.set(e,new t),c.get(e)}class d{t;i=0;o=[];h(e){if(e.hadRecentInput)return;const t=this.o[0],n=this.o.at(-1);this.i&&t&&n&&e.startTime-n.startTime<1e3&&e.startTime-t.startTime<5e3?(this.i+=e.value,this.o.push(e)):(this.i=e.value,this.o=[e]),this.t?.(e);}}const h=(e,t,n={})=>{try{if(PerformanceObserver.supportedEntryTypes.includes(e)){const i=new PerformanceObserver((e=>{Promise.resolve().then((()=>{t(e.getEntries());}));}));return i.observe({type:e,buffered:!0,...n}),i}}catch{}},f=e=>{let t=false;return ()=>{t||(e(),t=true);}};let u=-1;const l=new Set,m=()=>"hidden"!==document.visibilityState||document.prerendering?1/0:0,p=e=>{if("hidden"===document.visibilityState){if("visibilitychange"===e.type)for(const e of l)e();isFinite(u)||(u="visibilitychange"===e.type?e.timeStamp:0,removeEventListener("prerenderingchange",p,true));}},v=()=>{if(u<0){const e=o(),n=document.prerendering?void 0:globalThis.performance.getEntriesByType("visibility-state").filter((t=>"hidden"===t.name&&t.startTime>e))[0]?.startTime;u=n??m(),addEventListener("visibilitychange",p,true),addEventListener("prerenderingchange",p,true),t((()=>{setTimeout((()=>{u=m();}));}));}return {get firstHiddenTime(){return u},onHidden(e){l.add(e);}}},g=e=>{document.prerendering?addEventListener("prerenderingchange",(()=>e()),true):e();},y=[1800,3e3],E=(e,s={})=>{g((()=>{const c=v();let a,d=r("FCP");const f=h("paint",(e=>{for(const t of e)"first-contentful-paint"===t.name&&(f.disconnect(),t.startTime<c.firstHiddenTime&&(d.value=Math.max(t.startTime-o(),0),d.entries.push(t),a(true)));}));f&&(a=n(e,d,y,s.reportAllChanges),t((t=>{d=r("FCP"),a=n(e,d,y,s.reportAllChanges),i((()=>{d.value=performance.now()-t.timeStamp,a(true);}));})));}));},b=[.1,.25],L=(e,s={})=>{const o=v();E(f((()=>{let c,f=r("CLS",0);const u=a(s,d),l=e=>{for(const t of e)u.h(t);u.i>f.value&&(f.value=u.i,f.entries=u.o,c());},m=h("layout-shift",l);m&&(c=n(e,f,b,s.reportAllChanges),o.onHidden((()=>{l(m.takeRecords()),c(true);})),t((()=>{u.i=0,f=r("CLS",0),c=n(e,f,b,s.reportAllChanges),i((()=>c()));})),setTimeout(c));})));};let P=0,T=1/0,_=0;const M=e=>{for(const t of e)t.interactionId&&(T=Math.min(T,t.interactionId),_=Math.max(_,t.interactionId),P=_?(_-T)/7+1:0);};let w;const C=()=>w?P:performance.interactionCount??0,I=()=>{"interactionCount"in performance||w||(w=h("event",M,{type:"event",buffered:true,durationThreshold:0}));};let F=0;class k{u=[];l=new Map;m;p;v(){F=C(),this.u.length=0,this.l.clear();}L(){const e=Math.min(this.u.length-1,Math.floor((C()-F)/50));return this.u[e]}h(e){if(this.m?.(e),!e.interactionId&&"first-input"!==e.entryType)return;const t=this.u.at(-1);let n=this.l.get(e.interactionId);if(n||this.u.length<10||e.duration>t.P){if(n?e.duration>n.P?(n.entries=[e],n.P=e.duration):e.duration===n.P&&e.startTime===n.entries[0].startTime&&n.entries.push(e):(n={id:e.interactionId,entries:[e],P:e.duration},this.l.set(n.id,n),this.u.push(n)),this.u.sort(((e,t)=>t.P-e.P)),this.u.length>10){const e=this.u.splice(10);for(const t of e)this.l.delete(t.id);}this.p?.(n);}}}const A=e=>{const t=globalThis.requestIdleCallback||setTimeout;"hidden"===document.visibilityState?e():(e=f(e),addEventListener("visibilitychange",e,{once:true,capture:true}),t((()=>{e(),removeEventListener("visibilitychange",e,{capture:true});})));},B=[200,500],S=(e,i={})=>{if(!globalThis.PerformanceEventTiming||!("interactionId"in PerformanceEventTiming.prototype))return;const s=v();g((()=>{I();let o,c=r("INP");const d=a(i,k),f=e=>{A((()=>{for(const t of e)d.h(t);const t=d.L();t&&t.P!==c.value&&(c.value=t.P,c.entries=t.entries,o());}));},u=h("event",f,{durationThreshold:i.durationThreshold??40});o=n(e,c,B,i.reportAllChanges),u&&(u.observe({type:"first-input",buffered:true}),s.onHidden((()=>{f(u.takeRecords()),o(true);})),t((()=>{d.v(),c=r("INP"),o=n(e,c,B,i.reportAllChanges);})));}));};class N{m;h(e){this.m?.(e);}}const q=[2500,4e3],x=(e,s={})=>{g((()=>{const c=v();let d,u=r("LCP");const l=a(s,N),m=e=>{s.reportAllChanges||(e=e.slice(-1));for(const t of e)l.h(t),t.startTime<c.firstHiddenTime&&(u.value=Math.max(t.startTime-o(),0),u.entries=[t],d());},p=h("largest-contentful-paint",m);if(p){d=n(e,u,q,s.reportAllChanges);const o=f((()=>{m(p.takeRecords()),p.disconnect(),d(true);})),c=e=>{e.isTrusted&&(A(o),removeEventListener(e.type,c,{capture:true}));};for(const e of ["keydown","click","visibilitychange"])addEventListener(e,c,{capture:true});t((t=>{u=r("LCP"),d=n(e,u,q,s.reportAllChanges),i((()=>{u.value=performance.now()-t.timeStamp,d(true);}));}));}}));},H=[800,1800],O=e=>{document.prerendering?g((()=>O(e))):"complete"!==document.readyState?addEventListener("load",(()=>O(e)),true):setTimeout(e);},$=(e,i={})=>{let c=r("TTFB"),a=n(e,c,H,i.reportAllChanges);O((()=>{const d=s();d&&(c.value=Math.max(d.responseStart-o(),0),c.entries=[d],a(true),t((()=>{c=r("TTFB",0),a=n(e,c,H,i.reportAllChanges),a(true);})));}));};
|
|
7867
6675
|
|
|
7868
6676
|
function getPaintBlocks(resources) {
|
|
7869
6677
|
const paintBlocks = [];
|
|
@@ -7948,12 +6756,7 @@ function Timing (app, opts) {
|
|
|
7948
6756
|
if (shouldSkip) {
|
|
7949
6757
|
return;
|
|
7950
6758
|
}
|
|
7951
|
-
|
|
7952
|
-
? entry.responseEnd === 0
|
|
7953
|
-
|| (entry.transferSize === 0 && entry.decodedBodySize === 0)
|
|
7954
|
-
|| (entry.responseStatus && entry.responseStatus >= 400)
|
|
7955
|
-
: entry.responseStatus && entry.responseStatus >= 400;
|
|
7956
|
-
// will probably require custom header added to responses for tracked fetch/xhr requests:
|
|
6759
|
+
// will probably require custom header added to responses for tracked requests:
|
|
7957
6760
|
// Timing-Allow-Origin: *
|
|
7958
6761
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Timing-Allow-Origin
|
|
7959
6762
|
let stalled = 0;
|
|
@@ -7969,17 +6772,22 @@ function Timing (app, opts) {
|
|
|
7969
6772
|
queueing: entry.requestStart - entry.fetchStart,
|
|
7970
6773
|
dnsLookup: entry.domainLookupEnd - entry.domainLookupStart,
|
|
7971
6774
|
initialConnection: entry.connectEnd - entry.connectStart,
|
|
7972
|
-
ssl: entry.secureConnectionStart > 0
|
|
7973
|
-
? entry.connectEnd - entry.secureConnectionStart : 0,
|
|
6775
|
+
ssl: entry.secureConnectionStart > 0 ? entry.connectEnd - entry.secureConnectionStart : 0,
|
|
7974
6776
|
ttfb: entry.responseStart - entry.requestStart,
|
|
7975
6777
|
contentDownload: entry.responseEnd - entry.responseStart,
|
|
7976
|
-
total: entry.duration ??
|
|
6778
|
+
total: entry.duration ?? entry.responseEnd - entry.startTime,
|
|
7977
6779
|
stalled,
|
|
7978
6780
|
};
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
|
|
6781
|
+
const entryName = options.resourceNameSanitizer
|
|
6782
|
+
? options.resourceNameSanitizer(entry.name)
|
|
6783
|
+
: entry.name;
|
|
6784
|
+
const cached = (entry.responseStatus && entry.responseStatus === 304) ||
|
|
6785
|
+
// @ts-ignore
|
|
6786
|
+
(entry.deliveryType && entry.deliveryType === 'cache') ||
|
|
6787
|
+
(entry.transferSize === 0 && entry.decodedBodySize > 0);
|
|
6788
|
+
const requestFailed = entry.responseStatus && entry.responseStatus >= 400;
|
|
6789
|
+
const decodedBodySize = requestFailed ? -111 : entry.decodedBodySize || 0;
|
|
6790
|
+
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));
|
|
7983
6791
|
}
|
|
7984
6792
|
const observer = new PerformanceObserver((list) => list.getEntries().forEach(resourceTiming));
|
|
7985
6793
|
function onVitalsSignal(msg) {
|
|
@@ -7987,14 +6795,8 @@ function Timing (app, opts) {
|
|
|
7987
6795
|
return app.send(WebVitals(msg.name, String(msg.value)));
|
|
7988
6796
|
}
|
|
7989
6797
|
}
|
|
7990
|
-
let prevSessionID;
|
|
7991
6798
|
app.attachStartCallback(function ({ sessionID }) {
|
|
7992
|
-
|
|
7993
|
-
// Send past page resources on a newly started session
|
|
7994
|
-
performance.getEntriesByType('resource').forEach(resourceTiming);
|
|
7995
|
-
prevSessionID = sessionID;
|
|
7996
|
-
}
|
|
7997
|
-
observer.observe({ entryTypes: ['resource'] });
|
|
6799
|
+
observer.observe({ type: 'resource', buffered: true });
|
|
7998
6800
|
// browser support:
|
|
7999
6801
|
// onCLS(): Chromium
|
|
8000
6802
|
// onFCP(): Chromium, Firefox, Safari
|
|
@@ -8002,10 +6804,10 @@ function Timing (app, opts) {
|
|
|
8002
6804
|
// onINP(): Chromium
|
|
8003
6805
|
// onLCP(): Chromium, Firefox
|
|
8004
6806
|
// onTTFB(): Chromium, Firefox, Safari
|
|
8005
|
-
|
|
8006
|
-
|
|
8007
|
-
|
|
8008
|
-
|
|
6807
|
+
L(onVitalsSignal);
|
|
6808
|
+
S(onVitalsSignal);
|
|
6809
|
+
x(onVitalsSignal);
|
|
6810
|
+
$(onVitalsSignal);
|
|
8009
6811
|
});
|
|
8010
6812
|
app.attachStopCallback(function () {
|
|
8011
6813
|
observer.disconnect();
|
|
@@ -8158,16 +6960,19 @@ function Scroll (app, insideIframe) {
|
|
|
8158
6960
|
}, 5, false);
|
|
8159
6961
|
}
|
|
8160
6962
|
|
|
8161
|
-
function Viewport (app) {
|
|
6963
|
+
function Viewport (app, options) {
|
|
8162
6964
|
let url, width, height;
|
|
8163
6965
|
let navigationStart;
|
|
8164
6966
|
let referrer = document.referrer;
|
|
6967
|
+
const urlSanitizer = options?.urlSanitizer || ((u) => u);
|
|
6968
|
+
const titleSanitizer = options?.titleSanitizer || ((t) => t);
|
|
8165
6969
|
const sendSetPageLocation = app.safe(() => {
|
|
8166
6970
|
const { URL } = document;
|
|
8167
6971
|
if (URL !== url) {
|
|
8168
6972
|
url = URL;
|
|
8169
|
-
const
|
|
8170
|
-
const
|
|
6973
|
+
const sanitized = urlSanitizer(url);
|
|
6974
|
+
const safeTitle = app.sanitizer.privateMode ? stringWiper(document.title) : titleSanitizer(document.title);
|
|
6975
|
+
const safeUrl = app.sanitizer.privateMode ? stringWiper(sanitized) : sanitized;
|
|
8171
6976
|
const safeReferrer = app.sanitizer.privateMode ? stringWiper(referrer) : referrer;
|
|
8172
6977
|
app.send(SetPageLocation(safeUrl, safeReferrer, navigationStart, safeTitle));
|
|
8173
6978
|
navigationStart = 0;
|
|
@@ -8793,7 +7598,9 @@ class NetworkMessage {
|
|
|
8793
7598
|
});
|
|
8794
7599
|
if (!messageInfo)
|
|
8795
7600
|
return null;
|
|
8796
|
-
const
|
|
7601
|
+
const gqlHeader = "application/graphql-response";
|
|
7602
|
+
const isGraphql = messageInfo.url.includes("/graphql")
|
|
7603
|
+
|| Object.values(messageInfo.request.headers).some(v => v.includes(gqlHeader));
|
|
8797
7604
|
if (isGraphql && messageInfo.response.body && typeof messageInfo.response.body === 'string') {
|
|
8798
7605
|
const isError = messageInfo.response.body.includes("errors");
|
|
8799
7606
|
messageInfo.status = isError ? 400 : 200;
|
|
@@ -8871,42 +7678,47 @@ const genStringBody = (body) => {
|
|
|
8871
7678
|
return null;
|
|
8872
7679
|
}
|
|
8873
7680
|
let result;
|
|
8874
|
-
|
|
8875
|
-
if (
|
|
8876
|
-
|
|
7681
|
+
try {
|
|
7682
|
+
if (typeof body === 'string') {
|
|
7683
|
+
if (body[0] === '{' || body[0] === '[') {
|
|
7684
|
+
result = body;
|
|
7685
|
+
}
|
|
7686
|
+
// 'a=1&b=2' => try to parse as query
|
|
7687
|
+
const arr = body.split('&');
|
|
7688
|
+
if (arr.length === 1) {
|
|
7689
|
+
// not a query, parse as original string
|
|
7690
|
+
result = body;
|
|
7691
|
+
}
|
|
7692
|
+
else {
|
|
7693
|
+
// 'a=1&b=2&c' => parse as query
|
|
7694
|
+
result = arr.join(',');
|
|
7695
|
+
}
|
|
7696
|
+
}
|
|
7697
|
+
else if (isIterable(body)) {
|
|
7698
|
+
// FormData or URLSearchParams or Array
|
|
7699
|
+
const arr = [];
|
|
7700
|
+
for (const [key, value] of body) {
|
|
7701
|
+
arr.push(`${key}=${typeof value === 'string' ? value : '[object Object]'}`);
|
|
7702
|
+
}
|
|
7703
|
+
result = arr.join(',');
|
|
7704
|
+
}
|
|
7705
|
+
else if (body instanceof Blob ||
|
|
7706
|
+
body instanceof ReadableStream ||
|
|
7707
|
+
body instanceof ArrayBuffer) {
|
|
7708
|
+
result = 'byte data';
|
|
8877
7709
|
}
|
|
8878
|
-
|
|
8879
|
-
|
|
8880
|
-
if (arr.length === 1) {
|
|
8881
|
-
// not a query, parse as original string
|
|
7710
|
+
else if (isPureObject(body)) {
|
|
7711
|
+
// overriding ArrayBufferView which is not convertable to string
|
|
8882
7712
|
result = body;
|
|
8883
7713
|
}
|
|
8884
7714
|
else {
|
|
8885
|
-
|
|
8886
|
-
result = arr.join(',');
|
|
8887
|
-
}
|
|
8888
|
-
}
|
|
8889
|
-
else if (isIterable(body)) {
|
|
8890
|
-
// FormData or URLSearchParams or Array
|
|
8891
|
-
const arr = [];
|
|
8892
|
-
for (const [key, value] of body) {
|
|
8893
|
-
arr.push(`${key}=${typeof value === 'string' ? value : '[object Object]'}`);
|
|
7715
|
+
result = `can't parse body ${typeof body}`;
|
|
8894
7716
|
}
|
|
8895
|
-
result
|
|
8896
|
-
}
|
|
8897
|
-
else if (body instanceof Blob ||
|
|
8898
|
-
body instanceof ReadableStream ||
|
|
8899
|
-
body instanceof ArrayBuffer) {
|
|
8900
|
-
result = 'byte data';
|
|
7717
|
+
return result;
|
|
8901
7718
|
}
|
|
8902
|
-
|
|
8903
|
-
|
|
8904
|
-
result = body;
|
|
7719
|
+
catch (_) {
|
|
7720
|
+
return "can't parse body";
|
|
8905
7721
|
}
|
|
8906
|
-
else {
|
|
8907
|
-
result = `can't parse body ${typeof body}`;
|
|
8908
|
-
}
|
|
8909
|
-
return result;
|
|
8910
7722
|
};
|
|
8911
7723
|
const genGetDataByUrl = (url, getData = {}) => {
|
|
8912
7724
|
if (!isPureObject(getData)) {
|
|
@@ -9043,15 +7855,6 @@ class BeaconProxy {
|
|
|
9043
7855
|
}
|
|
9044
7856
|
}
|
|
9045
7857
|
|
|
9046
|
-
var RequestState;
|
|
9047
|
-
(function (RequestState) {
|
|
9048
|
-
RequestState[RequestState["UNSENT"] = 0] = "UNSENT";
|
|
9049
|
-
RequestState[RequestState["OPENED"] = 1] = "OPENED";
|
|
9050
|
-
RequestState[RequestState["HEADERS_RECEIVED"] = 2] = "HEADERS_RECEIVED";
|
|
9051
|
-
RequestState[RequestState["LOADING"] = 3] = "LOADING";
|
|
9052
|
-
RequestState[RequestState["DONE"] = 4] = "DONE";
|
|
9053
|
-
})(RequestState || (RequestState = {}));
|
|
9054
|
-
|
|
9055
7858
|
/**
|
|
9056
7859
|
* I took inspiration in few stack exchange posts
|
|
9057
7860
|
* and Tencent vConsole library (MIT)
|
|
@@ -9063,19 +7866,19 @@ class ResponseProxyHandler {
|
|
|
9063
7866
|
constructor(resp, item) {
|
|
9064
7867
|
this.resp = resp;
|
|
9065
7868
|
this.item = item;
|
|
9066
|
-
this.mockReader();
|
|
9067
7869
|
}
|
|
9068
7870
|
set(target, key, value) {
|
|
9069
7871
|
return Reflect.set(target, key, value);
|
|
9070
7872
|
}
|
|
9071
7873
|
get(target, key) {
|
|
9072
7874
|
const value = Reflect.get(target, key);
|
|
7875
|
+
if (key === "arrayBuffer" || key === "blob") {
|
|
7876
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
7877
|
+
}
|
|
9073
7878
|
switch (key) {
|
|
9074
|
-
case
|
|
9075
|
-
case
|
|
9076
|
-
case
|
|
9077
|
-
case 'json':
|
|
9078
|
-
case 'text':
|
|
7879
|
+
case "formData":
|
|
7880
|
+
case "json":
|
|
7881
|
+
case "text":
|
|
9079
7882
|
return () => {
|
|
9080
7883
|
this.item.responseType = key.toLowerCase();
|
|
9081
7884
|
// @ts-ignore
|
|
@@ -9085,74 +7888,13 @@ class ResponseProxyHandler {
|
|
|
9085
7888
|
});
|
|
9086
7889
|
};
|
|
9087
7890
|
}
|
|
9088
|
-
if (typeof value ===
|
|
7891
|
+
if (typeof value === "function") {
|
|
9089
7892
|
return value.bind(target);
|
|
9090
7893
|
}
|
|
9091
7894
|
else {
|
|
9092
7895
|
return value;
|
|
9093
7896
|
}
|
|
9094
7897
|
}
|
|
9095
|
-
mockReader() {
|
|
9096
|
-
let readerReceivedValue;
|
|
9097
|
-
if (!this.resp.body) {
|
|
9098
|
-
// some browsers do not return `body` in some cases, like `OPTIONS` method
|
|
9099
|
-
return;
|
|
9100
|
-
}
|
|
9101
|
-
if (typeof this.resp.body.getReader !== 'function') {
|
|
9102
|
-
return;
|
|
9103
|
-
}
|
|
9104
|
-
const clonedResp = this.resp.clone();
|
|
9105
|
-
const _getReader = clonedResp.body.getReader;
|
|
9106
|
-
// @ts-ignore
|
|
9107
|
-
clonedResp.body.getReader = () => {
|
|
9108
|
-
const reader = _getReader.apply(this.resp.body);
|
|
9109
|
-
// when readyState is already 4,
|
|
9110
|
-
// it's not a chunked stream, or it had already been read.
|
|
9111
|
-
// so should not update status.
|
|
9112
|
-
if (this.item.readyState === RequestState.DONE) {
|
|
9113
|
-
return reader;
|
|
9114
|
-
}
|
|
9115
|
-
const _read = reader.read;
|
|
9116
|
-
const _cancel = reader.cancel;
|
|
9117
|
-
this.item.responseType = 'arraybuffer';
|
|
9118
|
-
// @ts-ignore
|
|
9119
|
-
reader.read = () => {
|
|
9120
|
-
return _read.apply(reader).then((result) => {
|
|
9121
|
-
if (!readerReceivedValue) {
|
|
9122
|
-
// @ts-ignore
|
|
9123
|
-
readerReceivedValue = new Uint8Array(result.value);
|
|
9124
|
-
}
|
|
9125
|
-
else {
|
|
9126
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
9127
|
-
const newValue = new Uint8Array(readerReceivedValue.length + result.value.length);
|
|
9128
|
-
newValue.set(readerReceivedValue);
|
|
9129
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
9130
|
-
newValue.set(result.value, readerReceivedValue.length);
|
|
9131
|
-
readerReceivedValue = newValue;
|
|
9132
|
-
}
|
|
9133
|
-
this.item.endTime = performance.now();
|
|
9134
|
-
this.item.duration = this.item.endTime - (this.item.startTime || this.item.endTime);
|
|
9135
|
-
this.item.readyState = result.done ? 4 : 3;
|
|
9136
|
-
this.item.statusText = result.done ? String(this.item.status) : 'Loading';
|
|
9137
|
-
this.item.responseSize = readerReceivedValue.length;
|
|
9138
|
-
this.item.responseSizeText = formatByteSize(this.item.responseSize);
|
|
9139
|
-
if (result.done) {
|
|
9140
|
-
this.item.response = getStringResponseByType(this.item.responseType, readerReceivedValue);
|
|
9141
|
-
}
|
|
9142
|
-
return result;
|
|
9143
|
-
});
|
|
9144
|
-
};
|
|
9145
|
-
reader.cancel = (...args) => {
|
|
9146
|
-
this.item.cancelState = 2;
|
|
9147
|
-
this.item.statusText = 'Cancel';
|
|
9148
|
-
this.item.endTime = performance.now();
|
|
9149
|
-
this.item.duration = this.item.endTime - (this.item.startTime || this.item.endTime);
|
|
9150
|
-
this.item.response = getStringResponseByType(this.item.responseType, readerReceivedValue);
|
|
9151
|
-
return _cancel.apply(reader, args);
|
|
9152
|
-
};
|
|
9153
|
-
return reader;
|
|
9154
|
-
};
|
|
9155
|
-
}
|
|
9156
7898
|
}
|
|
9157
7899
|
class FetchProxyHandler {
|
|
9158
7900
|
constructor(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher) {
|
|
@@ -9164,14 +7906,15 @@ class FetchProxyHandler {
|
|
|
9164
7906
|
this.tokenUrlMatcher = tokenUrlMatcher;
|
|
9165
7907
|
}
|
|
9166
7908
|
apply(target, _, argsList) {
|
|
7909
|
+
var _a;
|
|
9167
7910
|
const input = argsList[0];
|
|
9168
7911
|
const init = argsList[1];
|
|
9169
7912
|
if (!input ||
|
|
9170
7913
|
// @ts-ignore
|
|
9171
|
-
(typeof input !==
|
|
7914
|
+
(typeof input !== "string" && !(input === null || input === void 0 ? void 0 : input.url))) {
|
|
9172
7915
|
return target.apply(window, argsList);
|
|
9173
7916
|
}
|
|
9174
|
-
const isORUrl = input instanceof URL || typeof input ===
|
|
7917
|
+
const isORUrl = input instanceof URL || typeof input === "string"
|
|
9175
7918
|
? this.isServiceUrl(String(input))
|
|
9176
7919
|
: this.isServiceUrl(String(input.url));
|
|
9177
7920
|
if (isORUrl) {
|
|
@@ -9179,6 +7922,31 @@ class FetchProxyHandler {
|
|
|
9179
7922
|
}
|
|
9180
7923
|
const item = new NetworkMessage(this.ignoredHeaders, this.setSessionTokenHeader, this.sanitize);
|
|
9181
7924
|
this.beforeFetch(item, input, init);
|
|
7925
|
+
const signal = (argsList[0] instanceof Request ? argsList[0].signal : undefined) ||
|
|
7926
|
+
((_a = argsList[1]) === null || _a === void 0 ? void 0 : _a.signal);
|
|
7927
|
+
// guard to avoid double-send
|
|
7928
|
+
let abortedNotified = false;
|
|
7929
|
+
const notifyAbort = () => {
|
|
7930
|
+
if (abortedNotified)
|
|
7931
|
+
return;
|
|
7932
|
+
abortedNotified = true;
|
|
7933
|
+
item.endTime = performance.now();
|
|
7934
|
+
item.duration = item.endTime - (item.startTime || item.endTime);
|
|
7935
|
+
item.status = 0;
|
|
7936
|
+
item.statusText = "Aborted";
|
|
7937
|
+
item.readyState = 0;
|
|
7938
|
+
const msg = item.getMessage();
|
|
7939
|
+
if (msg)
|
|
7940
|
+
this.sendMessage(msg);
|
|
7941
|
+
};
|
|
7942
|
+
if (signal) {
|
|
7943
|
+
if (signal.aborted) {
|
|
7944
|
+
notifyAbort();
|
|
7945
|
+
}
|
|
7946
|
+
else {
|
|
7947
|
+
signal.addEventListener("abort", notifyAbort, { once: true });
|
|
7948
|
+
}
|
|
7949
|
+
}
|
|
9182
7950
|
this.setSessionTokenHeader((name, value) => {
|
|
9183
7951
|
if (this.tokenUrlMatcher !== undefined) {
|
|
9184
7952
|
if (!this.tokenUrlMatcher(item.url)) {
|
|
@@ -9207,42 +7975,53 @@ class FetchProxyHandler {
|
|
|
9207
7975
|
}
|
|
9208
7976
|
});
|
|
9209
7977
|
return target.apply(window, argsList)
|
|
9210
|
-
.then(this.afterFetch(item)
|
|
7978
|
+
.then(this.afterFetch(item, () => {
|
|
7979
|
+
abortedNotified = true;
|
|
7980
|
+
}))
|
|
9211
7981
|
.catch((e) => {
|
|
9212
|
-
// mock finally
|
|
9213
7982
|
item.endTime = performance.now();
|
|
9214
7983
|
item.duration = item.endTime - (item.startTime || item.endTime);
|
|
7984
|
+
if (e && e.name === "AbortError") {
|
|
7985
|
+
item.status = 0;
|
|
7986
|
+
item.statusText = "Aborted";
|
|
7987
|
+
item.readyState = 0;
|
|
7988
|
+
if (!abortedNotified) {
|
|
7989
|
+
const msg = item.getMessage();
|
|
7990
|
+
if (msg)
|
|
7991
|
+
this.sendMessage(msg);
|
|
7992
|
+
}
|
|
7993
|
+
}
|
|
9215
7994
|
throw e;
|
|
9216
7995
|
});
|
|
9217
7996
|
}
|
|
9218
7997
|
beforeFetch(item, input, init) {
|
|
9219
|
-
let url, method =
|
|
7998
|
+
let url, method = "GET", requestHeader = {};
|
|
9220
7999
|
// handle `input` content
|
|
9221
|
-
if (typeof input ===
|
|
8000
|
+
if (typeof input === "string") {
|
|
9222
8001
|
// when `input` is a string
|
|
9223
|
-
method = (init === null || init === void 0 ? void 0 : init.method) ||
|
|
8002
|
+
method = (init === null || init === void 0 ? void 0 : init.method) || "GET";
|
|
9224
8003
|
url = getURL(input);
|
|
9225
8004
|
requestHeader = (init === null || init === void 0 ? void 0 : init.headers) || {};
|
|
9226
8005
|
}
|
|
9227
8006
|
else {
|
|
9228
8007
|
// when `input` is a `Request` object
|
|
9229
|
-
method = input.method ||
|
|
8008
|
+
method = input.method || "GET";
|
|
9230
8009
|
url = getURL(input.url);
|
|
9231
8010
|
requestHeader = input.headers;
|
|
9232
8011
|
}
|
|
9233
8012
|
item.method = method;
|
|
9234
|
-
item.requestType =
|
|
8013
|
+
item.requestType = "fetch";
|
|
9235
8014
|
item.requestHeader = requestHeader;
|
|
9236
8015
|
item.url = url.toString();
|
|
9237
|
-
item.name = (url.pathname.split(
|
|
8016
|
+
item.name = (url.pathname.split("/").pop() || "") + url.search;
|
|
9238
8017
|
item.status = 0;
|
|
9239
|
-
item.statusText =
|
|
8018
|
+
item.statusText = "Pending";
|
|
9240
8019
|
item.readyState = 1;
|
|
9241
8020
|
if (!item.startTime) {
|
|
9242
8021
|
// UNSENT
|
|
9243
8022
|
item.startTime = performance.now();
|
|
9244
8023
|
}
|
|
9245
|
-
if (Object.prototype.toString.call(requestHeader) ===
|
|
8024
|
+
if (Object.prototype.toString.call(requestHeader) === "[object Headers]") {
|
|
9246
8025
|
item.requestHeader = {};
|
|
9247
8026
|
for (const [key, value] of requestHeader) {
|
|
9248
8027
|
item.requestHeader[key] = value;
|
|
@@ -9263,8 +8042,10 @@ class FetchProxyHandler {
|
|
|
9263
8042
|
item.requestData = genStringBody(init.body);
|
|
9264
8043
|
}
|
|
9265
8044
|
}
|
|
9266
|
-
afterFetch(item) {
|
|
8045
|
+
afterFetch(item, onResolved) {
|
|
9267
8046
|
return (resp) => {
|
|
8047
|
+
if (onResolved)
|
|
8048
|
+
onResolved === null || onResolved === void 0 ? void 0 : onResolved();
|
|
9268
8049
|
item.endTime = performance.now();
|
|
9269
8050
|
item.duration = item.endTime - (item.startTime || item.endTime);
|
|
9270
8051
|
item.status = resp.status;
|
|
@@ -9273,7 +8054,8 @@ class FetchProxyHandler {
|
|
|
9273
8054
|
item.header = {};
|
|
9274
8055
|
for (const [key, value] of resp.headers) {
|
|
9275
8056
|
item.header[key] = value;
|
|
9276
|
-
isChunked =
|
|
8057
|
+
isChunked =
|
|
8058
|
+
value.toLowerCase().indexOf("chunked") > -1 ? true : isChunked;
|
|
9277
8059
|
}
|
|
9278
8060
|
if (isChunked) {
|
|
9279
8061
|
// when `transfer-encoding` is chunked, the response is a stream which is under loading,
|
|
@@ -9288,7 +8070,9 @@ class FetchProxyHandler {
|
|
|
9288
8070
|
this.handleResponseBody(resp.clone(), item)
|
|
9289
8071
|
.then((responseValue) => {
|
|
9290
8072
|
item.responseSize =
|
|
9291
|
-
typeof responseValue ===
|
|
8073
|
+
typeof responseValue === "string"
|
|
8074
|
+
? responseValue.length
|
|
8075
|
+
: responseValue.byteLength;
|
|
9292
8076
|
item.responseSizeText = formatByteSize(item.responseSize);
|
|
9293
8077
|
item.response = getStringResponseByType(item.responseType, responseValue);
|
|
9294
8078
|
const msg = item.getMessage();
|
|
@@ -9297,28 +8081,40 @@ class FetchProxyHandler {
|
|
|
9297
8081
|
}
|
|
9298
8082
|
})
|
|
9299
8083
|
.catch((e) => {
|
|
9300
|
-
if (e.name
|
|
8084
|
+
if (e.name === "AbortError") {
|
|
8085
|
+
item.status = 0;
|
|
8086
|
+
item.statusText = "Aborted";
|
|
8087
|
+
item.readyState = 0;
|
|
8088
|
+
const msg = item.getMessage();
|
|
8089
|
+
if (msg)
|
|
8090
|
+
this.sendMessage(msg);
|
|
8091
|
+
}
|
|
8092
|
+
else {
|
|
9301
8093
|
throw e;
|
|
9302
8094
|
}
|
|
9303
8095
|
});
|
|
9304
8096
|
}
|
|
9305
|
-
|
|
8097
|
+
const ct = (resp.headers.get("content-type") || "").toLowerCase();
|
|
8098
|
+
const isTextLike = ct.includes("application/json") || ct.startsWith("text/");
|
|
8099
|
+
return isTextLike
|
|
8100
|
+
? new Proxy(resp, new ResponseProxyHandler(resp, item))
|
|
8101
|
+
: resp;
|
|
9306
8102
|
};
|
|
9307
8103
|
}
|
|
9308
8104
|
handleResponseBody(resp, item) {
|
|
9309
8105
|
// parse response body by Content-Type
|
|
9310
|
-
const contentType = resp.headers.get(
|
|
9311
|
-
if (contentType && contentType.includes(
|
|
9312
|
-
item.responseType =
|
|
8106
|
+
const contentType = resp.headers.get("content-type");
|
|
8107
|
+
if (contentType && contentType.includes("application/json")) {
|
|
8108
|
+
item.responseType = "json";
|
|
9313
8109
|
return resp.text();
|
|
9314
8110
|
}
|
|
9315
8111
|
else if (contentType &&
|
|
9316
|
-
(contentType.includes(
|
|
9317
|
-
item.responseType =
|
|
8112
|
+
(contentType.includes("text/html") || contentType.includes("text/plain"))) {
|
|
8113
|
+
item.responseType = "text";
|
|
9318
8114
|
return resp.text();
|
|
9319
8115
|
}
|
|
9320
8116
|
else {
|
|
9321
|
-
item.responseType =
|
|
8117
|
+
item.responseType = "arraybuffer";
|
|
9322
8118
|
return resp.arrayBuffer();
|
|
9323
8119
|
}
|
|
9324
8120
|
}
|
|
@@ -9329,6 +8125,15 @@ class FetchProxy {
|
|
|
9329
8125
|
}
|
|
9330
8126
|
}
|
|
9331
8127
|
|
|
8128
|
+
var RequestState;
|
|
8129
|
+
(function (RequestState) {
|
|
8130
|
+
RequestState[RequestState["UNSENT"] = 0] = "UNSENT";
|
|
8131
|
+
RequestState[RequestState["OPENED"] = 1] = "OPENED";
|
|
8132
|
+
RequestState[RequestState["HEADERS_RECEIVED"] = 2] = "HEADERS_RECEIVED";
|
|
8133
|
+
RequestState[RequestState["LOADING"] = 3] = "LOADING";
|
|
8134
|
+
RequestState[RequestState["DONE"] = 4] = "DONE";
|
|
8135
|
+
})(RequestState || (RequestState = {}));
|
|
8136
|
+
|
|
9332
8137
|
/**
|
|
9333
8138
|
* I took inspiration in few stack exchange posts
|
|
9334
8139
|
* and Tencent vConsole library (MIT)
|
|
@@ -9355,28 +8160,29 @@ class XHRProxyHandler {
|
|
|
9355
8160
|
this.onTimeout();
|
|
9356
8161
|
};
|
|
9357
8162
|
this.item = new NetworkMessage(ignoredHeaders, setSessionTokenHeader, sanitize);
|
|
9358
|
-
this.item.requestType =
|
|
8163
|
+
this.item.requestType = "xhr";
|
|
9359
8164
|
}
|
|
9360
8165
|
get(target, key) {
|
|
9361
8166
|
switch (key) {
|
|
9362
|
-
case
|
|
8167
|
+
case "open":
|
|
9363
8168
|
return this.getOpen(target);
|
|
9364
|
-
case
|
|
8169
|
+
case "send":
|
|
9365
8170
|
this.setSessionTokenHeader((name, value) => {
|
|
9366
8171
|
if (this.tokenUrlMatcher !== undefined) {
|
|
9367
8172
|
if (!this.tokenUrlMatcher(this.item.url)) {
|
|
9368
8173
|
return;
|
|
9369
8174
|
}
|
|
9370
8175
|
}
|
|
9371
|
-
target.
|
|
8176
|
+
if (target.readyState === 1)
|
|
8177
|
+
target.setRequestHeader(name, value);
|
|
9372
8178
|
});
|
|
9373
8179
|
return this.getSend(target);
|
|
9374
|
-
case
|
|
8180
|
+
case "setRequestHeader":
|
|
9375
8181
|
return this.getSetRequestHeader(target);
|
|
9376
8182
|
default:
|
|
9377
8183
|
// eslint-disable-next-line no-case-declarations
|
|
9378
8184
|
const value = Reflect.get(target, key);
|
|
9379
|
-
if (typeof value ===
|
|
8185
|
+
if (typeof value === "function") {
|
|
9380
8186
|
return value.bind(target);
|
|
9381
8187
|
}
|
|
9382
8188
|
else {
|
|
@@ -9386,11 +8192,11 @@ class XHRProxyHandler {
|
|
|
9386
8192
|
}
|
|
9387
8193
|
set(target, key, value) {
|
|
9388
8194
|
switch (key) {
|
|
9389
|
-
case
|
|
8195
|
+
case "onreadystatechange":
|
|
9390
8196
|
return this.setOnReadyStateChange(target, key, value);
|
|
9391
|
-
case
|
|
8197
|
+
case "onabort":
|
|
9392
8198
|
return this.setOnAbort(target, key, value);
|
|
9393
|
-
case
|
|
8199
|
+
case "ontimeout":
|
|
9394
8200
|
return this.setOnTimeout(target, key, value);
|
|
9395
8201
|
// not tracked methods
|
|
9396
8202
|
}
|
|
@@ -9404,9 +8210,12 @@ class XHRProxyHandler {
|
|
|
9404
8210
|
this.item.endTime = performance.now();
|
|
9405
8211
|
this.item.duration = this.item.endTime - this.item.startTime;
|
|
9406
8212
|
this.updateItemByReadyState();
|
|
9407
|
-
|
|
9408
|
-
|
|
9409
|
-
|
|
8213
|
+
const rt = this.item.responseType || "";
|
|
8214
|
+
if (rt === "" || rt === "text" || rt === "json") {
|
|
8215
|
+
setTimeout(() => {
|
|
8216
|
+
this.item.response = getStringResponseByType(rt, this.XMLReq.response);
|
|
8217
|
+
}, 0);
|
|
8218
|
+
}
|
|
9410
8219
|
if (this.XMLReq.readyState === RequestState.DONE) {
|
|
9411
8220
|
const msg = this.item.getMessage();
|
|
9412
8221
|
if (msg) {
|
|
@@ -9416,7 +8225,7 @@ class XHRProxyHandler {
|
|
|
9416
8225
|
}
|
|
9417
8226
|
onAbort() {
|
|
9418
8227
|
this.item.cancelState = 1;
|
|
9419
|
-
this.item.statusText =
|
|
8228
|
+
this.item.statusText = "Abort";
|
|
9420
8229
|
const msg = this.item.getMessage();
|
|
9421
8230
|
if (msg) {
|
|
9422
8231
|
this.sendMessage(msg);
|
|
@@ -9424,27 +8233,28 @@ class XHRProxyHandler {
|
|
|
9424
8233
|
}
|
|
9425
8234
|
onTimeout() {
|
|
9426
8235
|
this.item.cancelState = 3;
|
|
9427
|
-
this.item.statusText =
|
|
8236
|
+
this.item.statusText = "Timeout";
|
|
9428
8237
|
const msg = this.item.getMessage();
|
|
9429
8238
|
if (msg) {
|
|
9430
8239
|
this.sendMessage(msg);
|
|
9431
8240
|
}
|
|
9432
8241
|
}
|
|
9433
8242
|
getOpen(target) {
|
|
9434
|
-
const targetFunction = Reflect.get(target,
|
|
8243
|
+
const targetFunction = Reflect.get(target, "open");
|
|
9435
8244
|
return (...args) => {
|
|
9436
8245
|
var _a, _b, _c;
|
|
9437
8246
|
const method = args[0];
|
|
9438
8247
|
const url = args[1];
|
|
9439
|
-
this.item.method = method ? method.toUpperCase() :
|
|
9440
|
-
this.item.url = ((_a = url.toString) === null || _a === void 0 ? void 0 : _a.call(url)) ||
|
|
9441
|
-
this.item.name =
|
|
8248
|
+
this.item.method = method ? method.toUpperCase() : "GET";
|
|
8249
|
+
this.item.url = ((_a = url.toString) === null || _a === void 0 ? void 0 : _a.call(url)) || "";
|
|
8250
|
+
this.item.name =
|
|
8251
|
+
(_c = (_b = this.item.url) === null || _b === void 0 ? void 0 : _b.replace(new RegExp("/*$"), "").split("/").pop()) !== null && _c !== void 0 ? _c : "";
|
|
9442
8252
|
this.item.getData = genGetDataByUrl(this.item.url, {});
|
|
9443
8253
|
return targetFunction.apply(target, args);
|
|
9444
8254
|
};
|
|
9445
8255
|
}
|
|
9446
8256
|
getSend(target) {
|
|
9447
|
-
const targetFunction = Reflect.get(target,
|
|
8257
|
+
const targetFunction = Reflect.get(target, "send");
|
|
9448
8258
|
return (...args) => {
|
|
9449
8259
|
const data = args[0];
|
|
9450
8260
|
this.item.requestData = genStringBody(data);
|
|
@@ -9452,7 +8262,7 @@ class XHRProxyHandler {
|
|
|
9452
8262
|
};
|
|
9453
8263
|
}
|
|
9454
8264
|
getSetRequestHeader(target) {
|
|
9455
|
-
const targetFunction = Reflect.get(target,
|
|
8265
|
+
const targetFunction = Reflect.get(target, "setRequestHeader");
|
|
9456
8266
|
return (...args) => {
|
|
9457
8267
|
if (!this.item.requestHeader) {
|
|
9458
8268
|
this.item.requestHeader = {};
|
|
@@ -9488,34 +8298,44 @@ class XHRProxyHandler {
|
|
|
9488
8298
|
case RequestState.UNSENT:
|
|
9489
8299
|
case RequestState.OPENED:
|
|
9490
8300
|
this.item.status = RequestState.UNSENT;
|
|
9491
|
-
this.item.statusText =
|
|
8301
|
+
this.item.statusText = "Pending";
|
|
9492
8302
|
if (!this.item.startTime) {
|
|
9493
8303
|
this.item.startTime = performance.now();
|
|
9494
8304
|
}
|
|
9495
8305
|
break;
|
|
9496
8306
|
case RequestState.HEADERS_RECEIVED:
|
|
9497
8307
|
this.item.status = this.XMLReq.status;
|
|
9498
|
-
this.item.statusText =
|
|
8308
|
+
this.item.statusText = "Loading";
|
|
9499
8309
|
this.item.header = {};
|
|
9500
8310
|
// eslint-disable-next-line no-case-declarations
|
|
9501
|
-
const header = this.XMLReq.getAllResponseHeaders() ||
|
|
8311
|
+
const header = this.XMLReq.getAllResponseHeaders() || "", headerArr = header.split("\n");
|
|
9502
8312
|
// extract plain text to key-value format
|
|
9503
8313
|
for (let i = 0; i < headerArr.length; i++) {
|
|
9504
8314
|
const line = headerArr[i];
|
|
9505
8315
|
if (!line) {
|
|
9506
8316
|
continue;
|
|
9507
8317
|
}
|
|
9508
|
-
const arr = line.split(
|
|
8318
|
+
const arr = line.split(": ");
|
|
9509
8319
|
const key = arr[0];
|
|
9510
|
-
this.item.header[key] = arr.slice(1).join(
|
|
8320
|
+
this.item.header[key] = arr.slice(1).join(": ");
|
|
9511
8321
|
}
|
|
9512
8322
|
break;
|
|
9513
8323
|
case RequestState.LOADING:
|
|
9514
8324
|
this.item.status = this.XMLReq.status;
|
|
9515
|
-
this.item.statusText =
|
|
9516
|
-
|
|
9517
|
-
|
|
9518
|
-
|
|
8325
|
+
this.item.statusText = "Loading";
|
|
8326
|
+
const response = this.XMLReq.response;
|
|
8327
|
+
if (response) {
|
|
8328
|
+
const respSize = typeof response === "string"
|
|
8329
|
+
? response.length
|
|
8330
|
+
: response instanceof ArrayBuffer
|
|
8331
|
+
? response.byteLength
|
|
8332
|
+
: typeof Blob !== "undefined" && response instanceof Blob
|
|
8333
|
+
? response.size
|
|
8334
|
+
: 0;
|
|
8335
|
+
if (respSize) {
|
|
8336
|
+
this.item.responseSize = respSize;
|
|
8337
|
+
this.item.responseSizeText = formatByteSize(this.item.responseSize);
|
|
8338
|
+
}
|
|
9519
8339
|
}
|
|
9520
8340
|
break;
|
|
9521
8341
|
case RequestState.DONE:
|
|
@@ -9524,16 +8344,30 @@ class XHRProxyHandler {
|
|
|
9524
8344
|
// show status code when request completed
|
|
9525
8345
|
this.item.statusText = String(this.item.status);
|
|
9526
8346
|
this.item.endTime = performance.now();
|
|
9527
|
-
this.item.duration =
|
|
9528
|
-
|
|
9529
|
-
|
|
9530
|
-
|
|
9531
|
-
|
|
8347
|
+
this.item.duration =
|
|
8348
|
+
this.item.endTime - (this.item.startTime || this.item.endTime);
|
|
8349
|
+
const resp = this.XMLReq.response;
|
|
8350
|
+
const respType = this.XMLReq.responseType || "";
|
|
8351
|
+
if (respType === "" || respType === "text" || respType === "json") {
|
|
8352
|
+
this.item.response = resp;
|
|
8353
|
+
}
|
|
8354
|
+
if (resp) {
|
|
8355
|
+
const respSize = typeof resp === "string"
|
|
8356
|
+
? resp.length
|
|
8357
|
+
: resp instanceof ArrayBuffer
|
|
8358
|
+
? resp.byteLength
|
|
8359
|
+
: typeof Blob !== "undefined" && resp instanceof Blob
|
|
8360
|
+
? resp.size
|
|
8361
|
+
: 0;
|
|
8362
|
+
if (respSize) {
|
|
8363
|
+
this.item.responseSize = respSize;
|
|
8364
|
+
this.item.responseSizeText = formatByteSize(respSize);
|
|
8365
|
+
}
|
|
9532
8366
|
}
|
|
9533
8367
|
break;
|
|
9534
8368
|
default:
|
|
9535
8369
|
this.item.status = this.XMLReq.status;
|
|
9536
|
-
this.item.statusText =
|
|
8370
|
+
this.item.statusText = "Unknown";
|
|
9537
8371
|
break;
|
|
9538
8372
|
}
|
|
9539
8373
|
}
|
|
@@ -9549,10 +8383,17 @@ class XHRProxy {
|
|
|
9549
8383
|
}
|
|
9550
8384
|
}
|
|
9551
8385
|
|
|
9552
|
-
const
|
|
8386
|
+
const warn = (api) => {
|
|
9553
8387
|
const str = `Openreplay: Can't find ${api} in global context.`;
|
|
9554
8388
|
console.warn(str);
|
|
9555
8389
|
};
|
|
8390
|
+
const OR_FLAG = Symbol('OpenReplayProxyOriginal');
|
|
8391
|
+
const isProxied = (fn) => !!fn && fn[OR_FLAG] !== undefined;
|
|
8392
|
+
const unwrap = (fn) => isProxied(fn) ? fn[OR_FLAG] : fn;
|
|
8393
|
+
const wrap = (proxy, orig) => {
|
|
8394
|
+
proxy[OR_FLAG] = orig;
|
|
8395
|
+
return proxy;
|
|
8396
|
+
};
|
|
9556
8397
|
/**
|
|
9557
8398
|
* Creates network proxies for XMLHttpRequest, fetch, and sendBeacon to intercept and monitor network requests and
|
|
9558
8399
|
* responses.
|
|
@@ -9586,26 +8427,24 @@ function createNetworkProxy(context, ignoredHeaders, setSessionTokenHeader, sani
|
|
|
9586
8427
|
if (!context)
|
|
9587
8428
|
return;
|
|
9588
8429
|
if (modules.xhr) {
|
|
9589
|
-
|
|
9590
|
-
|
|
9591
|
-
|
|
8430
|
+
const original = unwrap(context.XMLHttpRequest);
|
|
8431
|
+
if (!original)
|
|
8432
|
+
warn('XMLHttpRequest');
|
|
9592
8433
|
else {
|
|
9593
|
-
|
|
8434
|
+
context.XMLHttpRequest = wrap(XHRProxy.create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher), original);
|
|
9594
8435
|
}
|
|
9595
8436
|
}
|
|
9596
8437
|
if (modules.fetch) {
|
|
9597
|
-
|
|
9598
|
-
|
|
9599
|
-
|
|
8438
|
+
const original = unwrap(context.fetch);
|
|
8439
|
+
if (!original)
|
|
8440
|
+
warn('fetch');
|
|
9600
8441
|
else {
|
|
9601
|
-
|
|
8442
|
+
context.fetch = wrap(FetchProxy.create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher), original);
|
|
9602
8443
|
}
|
|
9603
8444
|
}
|
|
9604
|
-
if (modules.beacon) {
|
|
9605
|
-
|
|
9606
|
-
|
|
9607
|
-
context.navigator.sendBeacon = BeaconProxy.create(origBeacon, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl);
|
|
9608
|
-
}
|
|
8445
|
+
if (modules.beacon && ((_a = context.navigator) === null || _a === void 0 ? void 0 : _a.sendBeacon)) {
|
|
8446
|
+
const original = unwrap(context.navigator.sendBeacon);
|
|
8447
|
+
context.navigator.sendBeacon = wrap(BeaconProxy.create(original, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl), original);
|
|
9609
8448
|
}
|
|
9610
8449
|
}
|
|
9611
8450
|
|
|
@@ -9922,6 +8761,57 @@ function LongAnimationTask (app, opts) {
|
|
|
9922
8761
|
});
|
|
9923
8762
|
}
|
|
9924
8763
|
|
|
8764
|
+
const toIgnore = ["composite", "computedOffset", "easing", "offset"];
|
|
8765
|
+
function webAnimations(app, options = {}) {
|
|
8766
|
+
const { allElements = false } = options;
|
|
8767
|
+
let listening = new WeakSet();
|
|
8768
|
+
let handled = new WeakSet();
|
|
8769
|
+
function wire(anim, el, nodeId) {
|
|
8770
|
+
if (handled.has(anim))
|
|
8771
|
+
return;
|
|
8772
|
+
handled.add(anim);
|
|
8773
|
+
anim.addEventListener('finish', () => {
|
|
8774
|
+
const lastKF = anim.effect.getKeyframes().at(-1);
|
|
8775
|
+
const computedStyle = getComputedStyle(el);
|
|
8776
|
+
const keys = Object.keys(lastKF).filter((p) => !toIgnore.includes(p));
|
|
8777
|
+
// @ts-ignore
|
|
8778
|
+
const finalStyle = {};
|
|
8779
|
+
keys.forEach((key) => {
|
|
8780
|
+
finalStyle[key] = computedStyle[key];
|
|
8781
|
+
});
|
|
8782
|
+
app.send(NodeAnimationResult(nodeId, JSON.stringify(finalStyle)));
|
|
8783
|
+
}, { once: true });
|
|
8784
|
+
}
|
|
8785
|
+
function scanElement(el, nodeId) {
|
|
8786
|
+
el.getAnimations({ subtree: false }).forEach((anim) => wire(anim, el, nodeId));
|
|
8787
|
+
}
|
|
8788
|
+
app.nodes.attachNodeCallback((node) => {
|
|
8789
|
+
if ((allElements || node.nodeName.includes('-')) && 'getAnimations' in node) {
|
|
8790
|
+
const animations = node.getAnimations({ subtree: false });
|
|
8791
|
+
const id = app.nodes.getID(node);
|
|
8792
|
+
if (animations.length > 0 && !listening.has(node) && id) {
|
|
8793
|
+
listening.add(node);
|
|
8794
|
+
scanElement(node, id);
|
|
8795
|
+
node.addEventListener('animationstart', () => scanElement(node, id));
|
|
8796
|
+
}
|
|
8797
|
+
}
|
|
8798
|
+
});
|
|
8799
|
+
const origAnimate = Element.prototype.animate;
|
|
8800
|
+
Element.prototype.animate = function (...args) {
|
|
8801
|
+
const anim = origAnimate.apply(this, args);
|
|
8802
|
+
const id = app.nodes.getID(this);
|
|
8803
|
+
if (!id)
|
|
8804
|
+
return anim;
|
|
8805
|
+
wire(anim, this, id);
|
|
8806
|
+
return anim;
|
|
8807
|
+
};
|
|
8808
|
+
app.attachStopCallback(() => {
|
|
8809
|
+
Element.prototype.animate = origAnimate; // Restore original animate method
|
|
8810
|
+
listening = new WeakSet();
|
|
8811
|
+
handled = new WeakSet();
|
|
8812
|
+
});
|
|
8813
|
+
}
|
|
8814
|
+
|
|
9925
8815
|
const Messages = _Messages;
|
|
9926
8816
|
const DOCS_SETUP = '/en/sdk';
|
|
9927
8817
|
function processOptions(obj) {
|
|
@@ -9973,7 +8863,7 @@ class API {
|
|
|
9973
8863
|
this.signalStartIssue = (reason, missingApi) => {
|
|
9974
8864
|
const doNotTrack = this.checkDoNotTrack();
|
|
9975
8865
|
console.log("Tracker couldn't start due to:", JSON.stringify({
|
|
9976
|
-
trackerVersion: '17.0.
|
|
8866
|
+
trackerVersion: '17.0.1',
|
|
9977
8867
|
projectKey: this.options.projectKey,
|
|
9978
8868
|
doNotTrack,
|
|
9979
8869
|
reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
|
|
@@ -10067,7 +8957,7 @@ class API {
|
|
|
10067
8957
|
this.app = app;
|
|
10068
8958
|
if (!this.crossdomainMode) {
|
|
10069
8959
|
// no need to send iframe viewport data since its a node for us
|
|
10070
|
-
Viewport(app);
|
|
8960
|
+
Viewport(app, options.urls);
|
|
10071
8961
|
// calculated in main window
|
|
10072
8962
|
Connection(app);
|
|
10073
8963
|
// while we can calculate it here, trying to compute it for all parts is hard
|
|
@@ -10093,10 +8983,8 @@ class API {
|
|
|
10093
8983
|
Network(app, options.network);
|
|
10094
8984
|
}
|
|
10095
8985
|
selection(app);
|
|
8986
|
+
webAnimations(app, options.webAnimations);
|
|
10096
8987
|
window.__OPENREPLAY__ = this;
|
|
10097
|
-
if (options.flags && options.flags.onFlagsLoad) {
|
|
10098
|
-
this.onFlagsLoad(options.flags.onFlagsLoad);
|
|
10099
|
-
}
|
|
10100
8988
|
const wOpen = window.open;
|
|
10101
8989
|
if (options.autoResetOnWindowOpen || options.resetTabOnWindowOpen) {
|
|
10102
8990
|
app.attachStartCallback(() => {
|
|
@@ -10119,24 +9007,6 @@ class API {
|
|
|
10119
9007
|
});
|
|
10120
9008
|
}
|
|
10121
9009
|
}
|
|
10122
|
-
isFlagEnabled(flagName) {
|
|
10123
|
-
return this.featureFlags.isFlagEnabled(flagName);
|
|
10124
|
-
}
|
|
10125
|
-
onFlagsLoad(callback) {
|
|
10126
|
-
this.app?.featureFlags.onFlagsLoad(callback);
|
|
10127
|
-
}
|
|
10128
|
-
clearPersistFlags() {
|
|
10129
|
-
this.app?.featureFlags.clearPersistFlags();
|
|
10130
|
-
}
|
|
10131
|
-
reloadFlags() {
|
|
10132
|
-
return this.app?.featureFlags.reloadFlags();
|
|
10133
|
-
}
|
|
10134
|
-
getFeatureFlag(flagName) {
|
|
10135
|
-
return this.app?.featureFlags.getFeatureFlag(flagName);
|
|
10136
|
-
}
|
|
10137
|
-
getAllFeatureFlags() {
|
|
10138
|
-
return this.app?.featureFlags.flags;
|
|
10139
|
-
}
|
|
10140
9010
|
use(fn) {
|
|
10141
9011
|
return fn(this.app, this.options);
|
|
10142
9012
|
}
|
|
@@ -10267,12 +9137,6 @@ class API {
|
|
|
10267
9137
|
}
|
|
10268
9138
|
return this.app.getTabId();
|
|
10269
9139
|
}
|
|
10270
|
-
getUxId() {
|
|
10271
|
-
if (this.app === null) {
|
|
10272
|
-
return null;
|
|
10273
|
-
}
|
|
10274
|
-
return this.app.getUxtId();
|
|
10275
|
-
}
|
|
10276
9140
|
sessionID() {
|
|
10277
9141
|
deprecationWarn("'sessionID' method", "'getSessionID' method", '/');
|
|
10278
9142
|
return this.getSessionID();
|
|
@@ -10316,12 +9180,20 @@ class API {
|
|
|
10316
9180
|
return this.issue(key, payload);
|
|
10317
9181
|
}
|
|
10318
9182
|
else {
|
|
9183
|
+
if (!payload || typeof payload === 'string') {
|
|
9184
|
+
return this.app.send(CustomEvent(key, payload));
|
|
9185
|
+
}
|
|
10319
9186
|
try {
|
|
9187
|
+
if ('or_timestamp' in payload) {
|
|
9188
|
+
const startTs = this.getSessionInfo()?.timestamp ?? 0;
|
|
9189
|
+
const diff = payload.or_timestamp - startTs;
|
|
9190
|
+
if (diff < 0) {
|
|
9191
|
+
console.error(`OpenReplay: event ${key} has or_timestamp (${payload.or_timestamp}) before session start (${startTs}). It will be ignored.`);
|
|
9192
|
+
}
|
|
9193
|
+
}
|
|
10320
9194
|
payload = JSON.stringify(payload);
|
|
10321
9195
|
}
|
|
10322
|
-
catch (
|
|
10323
|
-
return;
|
|
10324
|
-
}
|
|
9196
|
+
catch (_) { }
|
|
10325
9197
|
this.app.send(CustomEvent(key, payload));
|
|
10326
9198
|
}
|
|
10327
9199
|
}
|
|
@@ -10445,42 +9317,6 @@ class TrackerSingleton {
|
|
|
10445
9317
|
}
|
|
10446
9318
|
this.instance.handleError(e, metadata);
|
|
10447
9319
|
}
|
|
10448
|
-
isFlagEnabled(flagName) {
|
|
10449
|
-
if (!IN_BROWSER || !this.ensureConfigured() || !this.instance) {
|
|
10450
|
-
return false;
|
|
10451
|
-
}
|
|
10452
|
-
return this.instance.isFlagEnabled(flagName);
|
|
10453
|
-
}
|
|
10454
|
-
onFlagsLoad(...args) {
|
|
10455
|
-
if (!IN_BROWSER || !this.ensureConfigured() || !this.instance) {
|
|
10456
|
-
return;
|
|
10457
|
-
}
|
|
10458
|
-
this.instance.onFlagsLoad(...args);
|
|
10459
|
-
}
|
|
10460
|
-
clearPersistFlags() {
|
|
10461
|
-
if (!IN_BROWSER || !this.ensureConfigured() || !this.instance) {
|
|
10462
|
-
return;
|
|
10463
|
-
}
|
|
10464
|
-
this.instance.clearPersistFlags();
|
|
10465
|
-
}
|
|
10466
|
-
reloadFlags() {
|
|
10467
|
-
if (!IN_BROWSER || !this.ensureConfigured() || !this.instance) {
|
|
10468
|
-
return;
|
|
10469
|
-
}
|
|
10470
|
-
return this.instance.reloadFlags();
|
|
10471
|
-
}
|
|
10472
|
-
getFeatureFlag(flagName) {
|
|
10473
|
-
if (!IN_BROWSER || !this.ensureConfigured() || !this.instance) {
|
|
10474
|
-
return;
|
|
10475
|
-
}
|
|
10476
|
-
return this.instance.getFeatureFlag(flagName);
|
|
10477
|
-
}
|
|
10478
|
-
getAllFeatureFlags() {
|
|
10479
|
-
if (!IN_BROWSER || !this.ensureConfigured() || !this.instance) {
|
|
10480
|
-
return;
|
|
10481
|
-
}
|
|
10482
|
-
return this.instance.getAllFeatureFlags();
|
|
10483
|
-
}
|
|
10484
9320
|
restartCanvasTracking() {
|
|
10485
9321
|
if (!IN_BROWSER || !this.ensureConfigured() || !this.instance) {
|
|
10486
9322
|
return;
|
|
@@ -10603,12 +9439,6 @@ class TrackerSingleton {
|
|
|
10603
9439
|
}
|
|
10604
9440
|
return this.instance.getTabId();
|
|
10605
9441
|
}
|
|
10606
|
-
getUxId() {
|
|
10607
|
-
if (!IN_BROWSER || !this.ensureConfigured() || !this.instance) {
|
|
10608
|
-
return null;
|
|
10609
|
-
}
|
|
10610
|
-
return this.instance.getUxId();
|
|
10611
|
-
}
|
|
10612
9442
|
}
|
|
10613
9443
|
const tracker = new TrackerSingleton();
|
|
10614
9444
|
|