@openreplay/tracker 16.1.3 → 16.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/entry.js +504 -322
- package/dist/cjs/entry.js.map +1 -1
- package/dist/cjs/index.js +504 -322
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/main/app/index.d.ts +2 -1
- package/dist/cjs/main/app/observer/cssInliner.d.ts +1 -0
- package/dist/cjs/main/app/observer/observer.d.ts +17 -3
- package/dist/cjs/main/app/observer/top_observer.d.ts +14 -0
- package/dist/lib/entry.js +504 -322
- package/dist/lib/entry.js.map +1 -1
- package/dist/lib/index.js +504 -322
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/main/app/index.d.ts +2 -1
- package/dist/lib/main/app/observer/cssInliner.d.ts +1 -0
- package/dist/lib/main/app/observer/observer.d.ts +17 -3
- package/dist/lib/main/app/observer/top_observer.d.ts +14 -0
- package/dist/types/main/app/index.d.ts +2 -1
- package/dist/types/main/app/observer/cssInliner.d.ts +1 -0
- package/dist/types/main/app/observer/observer.d.ts +17 -3
- package/dist/types/main/app/observer/top_observer.d.ts +14 -0
- package/package.json +2 -2
package/dist/cjs/entry.js
CHANGED
|
@@ -3702,6 +3702,381 @@ class Nodes {
|
|
|
3702
3702
|
}
|
|
3703
3703
|
}
|
|
3704
3704
|
|
|
3705
|
+
let fakeIdHolder = 1000000 * 99;
|
|
3706
|
+
function inlineRemoteCss(node, id, baseHref, getNextID, insertRule, addOwner, forceFetch, sendPlain, onPlain) {
|
|
3707
|
+
const sheetId = sendPlain ? null : getNextID();
|
|
3708
|
+
if (!sendPlain) {
|
|
3709
|
+
addOwner(sheetId, id);
|
|
3710
|
+
}
|
|
3711
|
+
const sheet = node.sheet;
|
|
3712
|
+
if (sheet && !forceFetch) {
|
|
3713
|
+
try {
|
|
3714
|
+
const cssText = stringifyStylesheet(sheet);
|
|
3715
|
+
if (cssText) {
|
|
3716
|
+
processCssText(cssText);
|
|
3717
|
+
return;
|
|
3718
|
+
}
|
|
3719
|
+
}
|
|
3720
|
+
catch (e) {
|
|
3721
|
+
// console.warn("Could not stringify sheet, falling back to fetch:", e);
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3724
|
+
// Fall back to fetching if we couldn't get or stringify the sheet
|
|
3725
|
+
if (node.href) {
|
|
3726
|
+
fetch(node.href)
|
|
3727
|
+
.then(response => {
|
|
3728
|
+
if (!response.ok) {
|
|
3729
|
+
throw new Error(`response status ${response.status}`);
|
|
3730
|
+
}
|
|
3731
|
+
return response.text();
|
|
3732
|
+
})
|
|
3733
|
+
.then(cssText => {
|
|
3734
|
+
if (sendPlain && onPlain) {
|
|
3735
|
+
onPlain(cssText, fakeIdHolder++);
|
|
3736
|
+
}
|
|
3737
|
+
else {
|
|
3738
|
+
processCssText(cssText);
|
|
3739
|
+
}
|
|
3740
|
+
})
|
|
3741
|
+
.catch(error => {
|
|
3742
|
+
console.error(`OpenReplay: Failed to fetch CSS from ${node.href}:`, error);
|
|
3743
|
+
});
|
|
3744
|
+
}
|
|
3745
|
+
function processCssText(cssText) {
|
|
3746
|
+
// Remove comments
|
|
3747
|
+
cssText = cssText.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
3748
|
+
// Parse and process the CSS text to extract rules
|
|
3749
|
+
const ruleTexts = parseCSS(cssText);
|
|
3750
|
+
for (let i = 0; i < ruleTexts.length; i++) {
|
|
3751
|
+
insertRule(sheetId, ruleTexts[i], i, baseHref);
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
function parseCSS(cssText) {
|
|
3755
|
+
const rules = [];
|
|
3756
|
+
let inComment = false;
|
|
3757
|
+
let inString = false;
|
|
3758
|
+
let stringChar = '';
|
|
3759
|
+
let braceLevel = 0;
|
|
3760
|
+
let currentRule = '';
|
|
3761
|
+
for (let i = 0; i < cssText.length; i++) {
|
|
3762
|
+
const char = cssText[i];
|
|
3763
|
+
const nextChar = cssText[i + 1] || '';
|
|
3764
|
+
// comments
|
|
3765
|
+
if (!inString && char === '/' && nextChar === '*') {
|
|
3766
|
+
inComment = true;
|
|
3767
|
+
i++; // Skip the next character
|
|
3768
|
+
continue;
|
|
3769
|
+
}
|
|
3770
|
+
if (inComment) {
|
|
3771
|
+
if (char === '*' && nextChar === '/') {
|
|
3772
|
+
inComment = false;
|
|
3773
|
+
i++; // Skip the next character
|
|
3774
|
+
}
|
|
3775
|
+
continue;
|
|
3776
|
+
}
|
|
3777
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
3778
|
+
inString = true;
|
|
3779
|
+
stringChar = char;
|
|
3780
|
+
currentRule += char;
|
|
3781
|
+
continue;
|
|
3782
|
+
}
|
|
3783
|
+
if (inString) {
|
|
3784
|
+
currentRule += char;
|
|
3785
|
+
if (char === stringChar && cssText[i - 1] !== '\\') {
|
|
3786
|
+
inString = false;
|
|
3787
|
+
}
|
|
3788
|
+
continue;
|
|
3789
|
+
}
|
|
3790
|
+
currentRule += char;
|
|
3791
|
+
if (char === '{') {
|
|
3792
|
+
braceLevel++;
|
|
3793
|
+
}
|
|
3794
|
+
else if (char === '}') {
|
|
3795
|
+
braceLevel--;
|
|
3796
|
+
if (braceLevel === 0) {
|
|
3797
|
+
// End of a top-level rule
|
|
3798
|
+
rules.push(currentRule.trim());
|
|
3799
|
+
currentRule = '';
|
|
3800
|
+
}
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
// Handle any remaining text (should be rare)
|
|
3804
|
+
if (currentRule.trim()) {
|
|
3805
|
+
rules.push(currentRule.trim());
|
|
3806
|
+
}
|
|
3807
|
+
return rules;
|
|
3808
|
+
}
|
|
3809
|
+
function stringifyStylesheet(s) {
|
|
3810
|
+
try {
|
|
3811
|
+
const rules = s.rules || s.cssRules;
|
|
3812
|
+
if (!rules) {
|
|
3813
|
+
return null;
|
|
3814
|
+
}
|
|
3815
|
+
let sheetHref = s.href;
|
|
3816
|
+
if (!sheetHref && s.ownerNode && s.ownerNode.ownerDocument) {
|
|
3817
|
+
// an inline <style> element
|
|
3818
|
+
sheetHref = s.ownerNode.ownerDocument.location.href;
|
|
3819
|
+
}
|
|
3820
|
+
const stringifiedRules = Array.from(rules, (rule) => stringifyRule(rule, sheetHref)).join('');
|
|
3821
|
+
return fixBrowserCompatibilityIssuesInCSS(stringifiedRules);
|
|
3822
|
+
}
|
|
3823
|
+
catch (error) {
|
|
3824
|
+
return null;
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
function stringifyRule(rule, sheetHref) {
|
|
3828
|
+
if (isCSSImportRule(rule)) {
|
|
3829
|
+
let importStringified;
|
|
3830
|
+
try {
|
|
3831
|
+
importStringified =
|
|
3832
|
+
// for same-origin stylesheets,
|
|
3833
|
+
// we can access the imported stylesheet rules directly
|
|
3834
|
+
stringifyStylesheet(rule.styleSheet) ||
|
|
3835
|
+
// work around browser issues with the raw string `@import url(...)` statement
|
|
3836
|
+
escapeImportStatement(rule);
|
|
3837
|
+
}
|
|
3838
|
+
catch (error) {
|
|
3839
|
+
importStringified = rule.cssText;
|
|
3840
|
+
}
|
|
3841
|
+
if (rule.styleSheet.href) {
|
|
3842
|
+
// url()s within the imported stylesheet are relative to _that_ sheet's href
|
|
3843
|
+
return absolutifyURLs(importStringified, rule.styleSheet.href);
|
|
3844
|
+
}
|
|
3845
|
+
return importStringified;
|
|
3846
|
+
}
|
|
3847
|
+
else {
|
|
3848
|
+
let ruleStringified = rule.cssText;
|
|
3849
|
+
if (isCSSStyleRule(rule) && rule.selectorText.includes(':')) {
|
|
3850
|
+
// Safari does not escape selectors with : properly
|
|
3851
|
+
ruleStringified = fixSafariColons(ruleStringified);
|
|
3852
|
+
}
|
|
3853
|
+
if (sheetHref) {
|
|
3854
|
+
return absolutifyURLs(ruleStringified, sheetHref);
|
|
3855
|
+
}
|
|
3856
|
+
return ruleStringified;
|
|
3857
|
+
}
|
|
3858
|
+
}
|
|
3859
|
+
function fixBrowserCompatibilityIssuesInCSS(cssText) {
|
|
3860
|
+
// Fix for Chrome's handling of webkit-background-clip
|
|
3861
|
+
if (cssText.includes(' background-clip: text;') &&
|
|
3862
|
+
!cssText.includes(' -webkit-background-clip: text;')) {
|
|
3863
|
+
cssText = cssText.replace(/\sbackground-clip:\s*text;/g, ' -webkit-background-clip: text; background-clip: text;');
|
|
3864
|
+
}
|
|
3865
|
+
return cssText;
|
|
3866
|
+
}
|
|
3867
|
+
function escapeImportStatement(rule) {
|
|
3868
|
+
const { cssText } = rule;
|
|
3869
|
+
if (cssText.split('"').length < 3)
|
|
3870
|
+
return cssText;
|
|
3871
|
+
const statement = ['@import', `url(${JSON.stringify(rule.href)})`];
|
|
3872
|
+
if (rule.layerName === '') {
|
|
3873
|
+
statement.push(`layer`);
|
|
3874
|
+
}
|
|
3875
|
+
else if (rule.layerName) {
|
|
3876
|
+
statement.push(`layer(${rule.layerName})`);
|
|
3877
|
+
}
|
|
3878
|
+
if (rule.supportsText) {
|
|
3879
|
+
statement.push(`supports(${rule.supportsText})`);
|
|
3880
|
+
}
|
|
3881
|
+
if (rule.media.length) {
|
|
3882
|
+
statement.push(rule.media.mediaText);
|
|
3883
|
+
}
|
|
3884
|
+
return statement.join(' ') + ';';
|
|
3885
|
+
}
|
|
3886
|
+
function fixSafariColons(cssStringified) {
|
|
3887
|
+
const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
|
|
3888
|
+
return cssStringified.replace(regex, '$1\\$2');
|
|
3889
|
+
}
|
|
3890
|
+
function isCSSImportRule(rule) {
|
|
3891
|
+
return 'styleSheet' in rule;
|
|
3892
|
+
}
|
|
3893
|
+
function isCSSStyleRule(rule) {
|
|
3894
|
+
return 'selectorText' in rule;
|
|
3895
|
+
}
|
|
3896
|
+
function absolutifyURLs(cssText, href) {
|
|
3897
|
+
if (!cssText)
|
|
3898
|
+
return '';
|
|
3899
|
+
const URL_IN_CSS_REF = /url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm;
|
|
3900
|
+
const URL_PROTOCOL_MATCH = /^(?:[a-z+]+:)?\/\//i;
|
|
3901
|
+
const URL_WWW_MATCH = /^www\..*/i;
|
|
3902
|
+
const DATA_URI = /^(data:)([^,]*),(.*)/i;
|
|
3903
|
+
return cssText.replace(URL_IN_CSS_REF, (origin, quote1, path1, quote2, path2, path3) => {
|
|
3904
|
+
const filePath = path1 || path2 || path3;
|
|
3905
|
+
const maybeQuote = quote1 || quote2 || '';
|
|
3906
|
+
if (!filePath) {
|
|
3907
|
+
return origin;
|
|
3908
|
+
}
|
|
3909
|
+
if (URL_PROTOCOL_MATCH.test(filePath) || URL_WWW_MATCH.test(filePath)) {
|
|
3910
|
+
return `url(${maybeQuote}${filePath}${maybeQuote})`;
|
|
3911
|
+
}
|
|
3912
|
+
if (DATA_URI.test(filePath)) {
|
|
3913
|
+
return `url(${maybeQuote}${filePath}${maybeQuote})`;
|
|
3914
|
+
}
|
|
3915
|
+
if (filePath[0] === '/') {
|
|
3916
|
+
return `url(${maybeQuote}${extractOrigin(href) + filePath}${maybeQuote})`;
|
|
3917
|
+
}
|
|
3918
|
+
const stack = href.split('/');
|
|
3919
|
+
const parts = filePath.split('/');
|
|
3920
|
+
stack.pop();
|
|
3921
|
+
for (const part of parts) {
|
|
3922
|
+
if (part === '.') {
|
|
3923
|
+
continue;
|
|
3924
|
+
}
|
|
3925
|
+
else if (part === '..') {
|
|
3926
|
+
stack.pop();
|
|
3927
|
+
}
|
|
3928
|
+
else {
|
|
3929
|
+
stack.push(part);
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
return `url(${maybeQuote}${stack.join('/')}${maybeQuote})`;
|
|
3933
|
+
});
|
|
3934
|
+
}
|
|
3935
|
+
function extractOrigin(url) {
|
|
3936
|
+
let origin = '';
|
|
3937
|
+
if (url.indexOf('//') > -1) {
|
|
3938
|
+
origin = url.split('/').slice(0, 3).join('/');
|
|
3939
|
+
}
|
|
3940
|
+
else {
|
|
3941
|
+
origin = url.split('/')[0];
|
|
3942
|
+
}
|
|
3943
|
+
origin = origin.split('?')[0];
|
|
3944
|
+
return origin;
|
|
3945
|
+
}
|
|
3946
|
+
}
|
|
3947
|
+
|
|
3948
|
+
function hasAdoptedSS(node) {
|
|
3949
|
+
return (isRootNode(node) &&
|
|
3950
|
+
// @ts-ignore
|
|
3951
|
+
!!node.adoptedStyleSheets);
|
|
3952
|
+
}
|
|
3953
|
+
// TODO: encapsulate to be init-ed on-start and join with cssrules.ts under one folder
|
|
3954
|
+
let _id = 0xf;
|
|
3955
|
+
function nextID() {
|
|
3956
|
+
return _id++;
|
|
3957
|
+
}
|
|
3958
|
+
const styleSheetIDMap = new Map();
|
|
3959
|
+
function ConstructedStyleSheets (app) {
|
|
3960
|
+
if (app === null) {
|
|
3961
|
+
return;
|
|
3962
|
+
}
|
|
3963
|
+
if (!hasAdoptedSS(document)) {
|
|
3964
|
+
return;
|
|
3965
|
+
}
|
|
3966
|
+
const styleSheetIDMap = new Map();
|
|
3967
|
+
const adoptedStyleSheetsOwnings = new Map();
|
|
3968
|
+
const sendAdoptedStyleSheetsUpdate = (root) => setTimeout(() => {
|
|
3969
|
+
let nodeID = app.nodes.getID(root);
|
|
3970
|
+
if (root === document) {
|
|
3971
|
+
nodeID = 0; // main document doesn't have nodeID. ID count starts from the documentElement
|
|
3972
|
+
}
|
|
3973
|
+
if (nodeID === undefined) {
|
|
3974
|
+
return;
|
|
3975
|
+
}
|
|
3976
|
+
let pastOwning = adoptedStyleSheetsOwnings.get(nodeID);
|
|
3977
|
+
if (!pastOwning) {
|
|
3978
|
+
pastOwning = [];
|
|
3979
|
+
}
|
|
3980
|
+
const nowOwning = [];
|
|
3981
|
+
const styleSheets = root.adoptedStyleSheets;
|
|
3982
|
+
if (styleSheets && Symbol.iterator in styleSheets) {
|
|
3983
|
+
for (const s of styleSheets) {
|
|
3984
|
+
let sheetID = styleSheetIDMap.get(s);
|
|
3985
|
+
const init = !sheetID;
|
|
3986
|
+
if (!sheetID) {
|
|
3987
|
+
sheetID = nextID();
|
|
3988
|
+
styleSheetIDMap.set(s, sheetID);
|
|
3989
|
+
}
|
|
3990
|
+
if (!pastOwning.includes(sheetID)) {
|
|
3991
|
+
app.send(AdoptedSSAddOwner(sheetID, nodeID));
|
|
3992
|
+
}
|
|
3993
|
+
if (init) {
|
|
3994
|
+
const rules = s.cssRules;
|
|
3995
|
+
for (let i = 0; i < rules.length; i++) {
|
|
3996
|
+
app.send(AdoptedSSInsertRuleURLBased(sheetID, rules[i].cssText, i, app.getBaseHref()));
|
|
3997
|
+
}
|
|
3998
|
+
}
|
|
3999
|
+
nowOwning.push(sheetID);
|
|
4000
|
+
}
|
|
4001
|
+
}
|
|
4002
|
+
if (Symbol.iterator in pastOwning) {
|
|
4003
|
+
for (const sheetID of pastOwning) {
|
|
4004
|
+
if (!nowOwning.includes(sheetID)) {
|
|
4005
|
+
app.send(AdoptedSSRemoveOwner(sheetID, nodeID));
|
|
4006
|
+
}
|
|
4007
|
+
}
|
|
4008
|
+
}
|
|
4009
|
+
adoptedStyleSheetsOwnings.set(nodeID, nowOwning);
|
|
4010
|
+
}, 20); // Mysterious bug:
|
|
4011
|
+
/* On the page https://explore.fast.design/components/fast-accordion
|
|
4012
|
+
the only rule inside the only adoptedStyleSheet of the iframe-s document
|
|
4013
|
+
gets changed during first milliseconds after the load.
|
|
4014
|
+
However, none of the documented methods (replace, insertRule) is triggered.
|
|
4015
|
+
The rule is not substituted (remains the same object), however the text gets changed.
|
|
4016
|
+
*/
|
|
4017
|
+
function patchAdoptedStyleSheets(prototype) {
|
|
4018
|
+
const nativeAdoptedStyleSheetsDescriptor = Object.getOwnPropertyDescriptor(prototype, 'adoptedStyleSheets');
|
|
4019
|
+
if (nativeAdoptedStyleSheetsDescriptor) {
|
|
4020
|
+
Object.defineProperty(prototype, 'adoptedStyleSheets', {
|
|
4021
|
+
...nativeAdoptedStyleSheetsDescriptor,
|
|
4022
|
+
set: function (value) {
|
|
4023
|
+
// @ts-ignore
|
|
4024
|
+
const retVal = nativeAdoptedStyleSheetsDescriptor.set.call(this, value);
|
|
4025
|
+
sendAdoptedStyleSheetsUpdate(this);
|
|
4026
|
+
return retVal;
|
|
4027
|
+
},
|
|
4028
|
+
});
|
|
4029
|
+
}
|
|
4030
|
+
}
|
|
4031
|
+
const patchContext = (context) => {
|
|
4032
|
+
// @ts-ignore
|
|
4033
|
+
if (context.__openreplay_adpss_patched__) {
|
|
4034
|
+
return;
|
|
4035
|
+
}
|
|
4036
|
+
else {
|
|
4037
|
+
// @ts-ignore
|
|
4038
|
+
context.__openreplay_adpss_patched__ = true;
|
|
4039
|
+
}
|
|
4040
|
+
patchAdoptedStyleSheets(context.Document.prototype);
|
|
4041
|
+
patchAdoptedStyleSheets(context.ShadowRoot.prototype);
|
|
4042
|
+
//@ts-ignore TODO: upgrade ts to 4.8+
|
|
4043
|
+
const { replace, replaceSync } = context.CSSStyleSheet.prototype;
|
|
4044
|
+
//@ts-ignore
|
|
4045
|
+
context.CSSStyleSheet.prototype.replace = function (text) {
|
|
4046
|
+
return replace.call(this, text).then((sheet) => {
|
|
4047
|
+
const sheetID = styleSheetIDMap.get(this);
|
|
4048
|
+
if (sheetID) {
|
|
4049
|
+
app.send(AdoptedSSReplaceURLBased(sheetID, text, app.getBaseHref()));
|
|
4050
|
+
}
|
|
4051
|
+
return sheet;
|
|
4052
|
+
});
|
|
4053
|
+
};
|
|
4054
|
+
//@ts-ignore
|
|
4055
|
+
context.CSSStyleSheet.prototype.replaceSync = function (text) {
|
|
4056
|
+
const sheetID = styleSheetIDMap.get(this);
|
|
4057
|
+
if (sheetID) {
|
|
4058
|
+
app.send(AdoptedSSReplaceURLBased(sheetID, text, app.getBaseHref()));
|
|
4059
|
+
}
|
|
4060
|
+
return replaceSync.call(this, text);
|
|
4061
|
+
};
|
|
4062
|
+
};
|
|
4063
|
+
patchContext(window);
|
|
4064
|
+
app.observer.attachContextCallback(app.safe(patchContext));
|
|
4065
|
+
app.attachStopCallback(() => {
|
|
4066
|
+
styleSheetIDMap.clear();
|
|
4067
|
+
adoptedStyleSheetsOwnings.clear();
|
|
4068
|
+
});
|
|
4069
|
+
// So far main Document is not triggered with nodeCallbacks
|
|
4070
|
+
app.attachStartCallback(() => {
|
|
4071
|
+
sendAdoptedStyleSheetsUpdate(document);
|
|
4072
|
+
});
|
|
4073
|
+
app.nodes.attachNodeCallback((node) => {
|
|
4074
|
+
if (hasAdoptedSS(node)) {
|
|
4075
|
+
sendAdoptedStyleSheetsUpdate(node);
|
|
4076
|
+
}
|
|
4077
|
+
});
|
|
4078
|
+
}
|
|
4079
|
+
|
|
3705
4080
|
const iconCache = {};
|
|
3706
4081
|
const svgUrlCache = {};
|
|
3707
4082
|
async function parseUseEl(useElement, mode, domParser) {
|
|
@@ -3720,7 +4095,7 @@ async function parseUseEl(useElement, mode, domParser) {
|
|
|
3720
4095
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="${symbol.getAttribute('viewBox') || '0 0 24 24'}">
|
|
3721
4096
|
${symbol.innerHTML}
|
|
3722
4097
|
</svg>
|
|
3723
|
-
|
|
4098
|
+
`;
|
|
3724
4099
|
iconCache[symbolId] = inlineSvg;
|
|
3725
4100
|
return inlineSvg;
|
|
3726
4101
|
}
|
|
@@ -3780,7 +4155,7 @@ async function parseUseEl(useElement, mode, domParser) {
|
|
|
3780
4155
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="${symbol.getAttribute('viewBox') || '0 0 24 24'}">
|
|
3781
4156
|
${symbol.innerHTML}
|
|
3782
4157
|
</svg>
|
|
3783
|
-
|
|
4158
|
+
`;
|
|
3784
4159
|
iconCache[symbolId] = inlineSvg;
|
|
3785
4160
|
return inlineSvg;
|
|
3786
4161
|
}
|
|
@@ -3827,7 +4202,7 @@ var RecentsType;
|
|
|
3827
4202
|
RecentsType[RecentsType["Changed"] = 2] = "Changed";
|
|
3828
4203
|
})(RecentsType || (RecentsType = {}));
|
|
3829
4204
|
class Observer {
|
|
3830
|
-
constructor(app, isTopContext = false, options = {
|
|
4205
|
+
constructor(app, isTopContext = false, options = {}) {
|
|
3831
4206
|
this.app = app;
|
|
3832
4207
|
this.isTopContext = isTopContext;
|
|
3833
4208
|
this.commited = [];
|
|
@@ -3836,8 +4211,17 @@ class Observer {
|
|
|
3836
4211
|
this.attributesMap = new Map();
|
|
3837
4212
|
this.textSet = new Set();
|
|
3838
4213
|
this.disableSprites = false;
|
|
4214
|
+
/**
|
|
4215
|
+
* this option means that, instead of using link element with href to load css,
|
|
4216
|
+
* we will try to parse the css text instead and send it as css rules set
|
|
4217
|
+
* can (and will) affect performance
|
|
4218
|
+
* */
|
|
4219
|
+
this.inlineRemoteCss = false;
|
|
4220
|
+
this.inlinerOptions = undefined;
|
|
3839
4221
|
this.domParser = new DOMParser();
|
|
3840
|
-
this.disableSprites = options.disableSprites;
|
|
4222
|
+
this.disableSprites = Boolean(options.disableSprites);
|
|
4223
|
+
this.inlineRemoteCss = Boolean(options.inlineRemoteCss);
|
|
4224
|
+
this.inlinerOptions = options.inlinerOptions;
|
|
3841
4225
|
this.observer = createMutationObserver(this.app.safe((mutations) => {
|
|
3842
4226
|
for (const mutation of mutations) {
|
|
3843
4227
|
// mutations order is sequential
|
|
@@ -3911,10 +4295,12 @@ class Observer {
|
|
|
3911
4295
|
false);
|
|
3912
4296
|
let removed = 0;
|
|
3913
4297
|
const totalBeforeRemove = this.app.nodes.getNodeCount();
|
|
4298
|
+
const contentDocument = iframe.contentDocument;
|
|
4299
|
+
const nodesUnregister = this.app.nodes.unregisterNode.bind(this.app.nodes);
|
|
3914
4300
|
while (walker.nextNode()) {
|
|
3915
|
-
if (!
|
|
4301
|
+
if (!contentDocument.contains(walker.currentNode)) {
|
|
3916
4302
|
removed += 1;
|
|
3917
|
-
|
|
4303
|
+
nodesUnregister(walker.currentNode);
|
|
3918
4304
|
}
|
|
3919
4305
|
}
|
|
3920
4306
|
const removedPercent = Math.floor((removed / totalBeforeRemove) * 100);
|
|
@@ -3926,7 +4312,7 @@ class Observer {
|
|
|
3926
4312
|
}
|
|
3927
4313
|
sendNodeAttribute(id, node, name, value) {
|
|
3928
4314
|
if (isSVGElement(node)) {
|
|
3929
|
-
if (name.
|
|
4315
|
+
if (name.startsWith('xlink:')) {
|
|
3930
4316
|
name = name.substring(6);
|
|
3931
4317
|
}
|
|
3932
4318
|
if (value === null) {
|
|
@@ -3975,6 +4361,23 @@ class Observer {
|
|
|
3975
4361
|
return;
|
|
3976
4362
|
}
|
|
3977
4363
|
if (name === 'style' || (name === 'href' && hasTag(node, 'link'))) {
|
|
4364
|
+
if ('rel' in node && node.rel === 'stylesheet' && this.inlineRemoteCss) {
|
|
4365
|
+
setTimeout(() => {
|
|
4366
|
+
inlineRemoteCss(
|
|
4367
|
+
// @ts-ignore
|
|
4368
|
+
node, id, this.app.getBaseHref(), nextID, (id, cssText, index, baseHref) => {
|
|
4369
|
+
this.app.send(AdoptedSSInsertRuleURLBased(id, cssText, index, baseHref));
|
|
4370
|
+
}, (sheetId, ownerId) => {
|
|
4371
|
+
this.app.send(AdoptedSSAddOwner(sheetId, ownerId));
|
|
4372
|
+
}, this.inlinerOptions?.forceFetch, this.inlinerOptions?.forcePlain, (cssText, fakeTextId) => {
|
|
4373
|
+
this.app.send(CreateTextNode(fakeTextId, id, 0));
|
|
4374
|
+
setTimeout(() => {
|
|
4375
|
+
this.app.send(SetCSSDataURLBased(fakeTextId, cssText, this.app.getBaseHref()));
|
|
4376
|
+
}, 10);
|
|
4377
|
+
});
|
|
4378
|
+
}, 0);
|
|
4379
|
+
return;
|
|
4380
|
+
}
|
|
3978
4381
|
this.app.send(SetNodeAttributeURLBased(id, name, value, this.app.getBaseHref()));
|
|
3979
4382
|
return;
|
|
3980
4383
|
}
|
|
@@ -4054,7 +4457,8 @@ class Observer {
|
|
|
4054
4457
|
if (isRootNode(node)) {
|
|
4055
4458
|
return true;
|
|
4056
4459
|
}
|
|
4057
|
-
|
|
4460
|
+
// @ts-ignore SALESFORCE
|
|
4461
|
+
const parent = node.assignedSlot ? node.assignedSlot : node.parentNode;
|
|
4058
4462
|
let parentID;
|
|
4059
4463
|
// Disable parent check for the upper context HTMLHtmlElement, because it is root there... (before)
|
|
4060
4464
|
// TODO: get rid of "special" cases (there is an issue with CreateDocument altered behaviour though)
|
|
@@ -4111,7 +4515,12 @@ class Observer {
|
|
|
4111
4515
|
el.style.width = `${width}px`;
|
|
4112
4516
|
el.style.height = `${height}px`;
|
|
4113
4517
|
}
|
|
4114
|
-
|
|
4518
|
+
if ('rel' in el && el.rel === 'stylesheet' && this.inlineRemoteCss) {
|
|
4519
|
+
this.app.send(CreateElementNode(id, parentID, index, 'STYLE', false));
|
|
4520
|
+
}
|
|
4521
|
+
else {
|
|
4522
|
+
this.app.send(CreateElementNode(id, parentID, index, el.tagName, isSVGElement(node)));
|
|
4523
|
+
}
|
|
4115
4524
|
}
|
|
4116
4525
|
for (let i = 0; i < el.attributes.length; i++) {
|
|
4117
4526
|
const attr = el.attributes[i];
|
|
@@ -4159,12 +4568,12 @@ class Observer {
|
|
|
4159
4568
|
}
|
|
4160
4569
|
commitNodes(isStart = false) {
|
|
4161
4570
|
let node;
|
|
4162
|
-
this.recents.
|
|
4571
|
+
for (const [id, type] of this.recents.entries()) {
|
|
4163
4572
|
this.commitNode(id);
|
|
4164
4573
|
if (type === RecentsType.New && (node = this.app.nodes.getNode(id))) {
|
|
4165
4574
|
this.app.nodes.callNodeCallbacks(node, isStart);
|
|
4166
4575
|
}
|
|
4167
|
-
}
|
|
4576
|
+
}
|
|
4168
4577
|
this.clear();
|
|
4169
4578
|
}
|
|
4170
4579
|
// ISSSUE (nodeToBinde should be the same as node in all cases. Look at the comment about 0-node at the beginning of the file.)
|
|
@@ -4286,12 +4695,20 @@ class IFrameOffsets {
|
|
|
4286
4695
|
}
|
|
4287
4696
|
}
|
|
4288
4697
|
|
|
4698
|
+
var InlineCssMode;
|
|
4699
|
+
(function (InlineCssMode) {
|
|
4700
|
+
InlineCssMode[InlineCssMode["None"] = 0] = "None";
|
|
4701
|
+
InlineCssMode[InlineCssMode["RemoteOnly"] = 1] = "RemoteOnly";
|
|
4702
|
+
InlineCssMode[InlineCssMode["RemoteWithForceFetch"] = 2] = "RemoteWithForceFetch";
|
|
4703
|
+
InlineCssMode[InlineCssMode["All"] = 3] = "All";
|
|
4704
|
+
})(InlineCssMode || (InlineCssMode = {}));
|
|
4289
4705
|
const attachShadowNativeFn = IN_BROWSER ? Element.prototype.attachShadow : () => new ShadowRoot();
|
|
4290
4706
|
class TopObserver extends Observer {
|
|
4291
4707
|
constructor(params) {
|
|
4292
4708
|
const opts = Object.assign({
|
|
4293
4709
|
captureIFrames: true,
|
|
4294
4710
|
disableSprites: false,
|
|
4711
|
+
inlineCss: 0,
|
|
4295
4712
|
}, params.options);
|
|
4296
4713
|
super(params.app, true, opts);
|
|
4297
4714
|
this.iframeOffsets = new IFrameOffsets();
|
|
@@ -4342,7 +4759,7 @@ class TopObserver extends Observer {
|
|
|
4342
4759
|
this.app.debug.info('doc already observed for', id);
|
|
4343
4760
|
return;
|
|
4344
4761
|
}
|
|
4345
|
-
const observer = new IFrameObserver(this.app);
|
|
4762
|
+
const observer = new IFrameObserver(this.app, false, {});
|
|
4346
4763
|
this.iframeObservers.set(iframe, observer);
|
|
4347
4764
|
this.docObservers.set(currentDoc, observer);
|
|
4348
4765
|
this.iframeObserversArr.push(observer);
|
|
@@ -4713,6 +5130,43 @@ function getTimezone() {
|
|
|
4713
5130
|
return `UTC${sign}${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;
|
|
4714
5131
|
}
|
|
4715
5132
|
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
|
|
5133
|
+
function getInlineOptions(mode) {
|
|
5134
|
+
switch (mode) {
|
|
5135
|
+
case InlineCssMode.RemoteOnly:
|
|
5136
|
+
return {
|
|
5137
|
+
inlineRemoteCss: true,
|
|
5138
|
+
inlinerOptions: {
|
|
5139
|
+
forceFetch: false,
|
|
5140
|
+
forcePlain: false,
|
|
5141
|
+
},
|
|
5142
|
+
};
|
|
5143
|
+
case InlineCssMode.RemoteWithForceFetch:
|
|
5144
|
+
return {
|
|
5145
|
+
inlineRemoteCss: true,
|
|
5146
|
+
inlinerOptions: {
|
|
5147
|
+
forceFetch: true,
|
|
5148
|
+
forcePlain: false,
|
|
5149
|
+
},
|
|
5150
|
+
};
|
|
5151
|
+
case InlineCssMode.All:
|
|
5152
|
+
return {
|
|
5153
|
+
inlineRemoteCss: true,
|
|
5154
|
+
inlinerOptions: {
|
|
5155
|
+
forceFetch: true,
|
|
5156
|
+
forcePlain: true,
|
|
5157
|
+
},
|
|
5158
|
+
};
|
|
5159
|
+
case InlineCssMode.None:
|
|
5160
|
+
default:
|
|
5161
|
+
return {
|
|
5162
|
+
inlineRemoteCss: false,
|
|
5163
|
+
inlinerOptions: {
|
|
5164
|
+
forceFetch: false,
|
|
5165
|
+
forcePlain: false,
|
|
5166
|
+
},
|
|
5167
|
+
};
|
|
5168
|
+
}
|
|
5169
|
+
}
|
|
4716
5170
|
const proto = {
|
|
4717
5171
|
// ask if there are any tabs alive
|
|
4718
5172
|
ask: 'never-gonna-give-you-up',
|
|
@@ -4744,7 +5198,7 @@ class App {
|
|
|
4744
5198
|
this.stopCallbacks = [];
|
|
4745
5199
|
this.commitCallbacks = [];
|
|
4746
5200
|
this.activityState = ActivityState.NotActive;
|
|
4747
|
-
this.version = '16.
|
|
5201
|
+
this.version = '16.2.0'; // TODO: version compatability check inside each plugin.
|
|
4748
5202
|
this.socketMode = false;
|
|
4749
5203
|
this.compressionThreshold = 24 * 1000;
|
|
4750
5204
|
this.bc = null;
|
|
@@ -4977,6 +5431,30 @@ class App {
|
|
|
4977
5431
|
}
|
|
4978
5432
|
};
|
|
4979
5433
|
this.startTimeout = null;
|
|
5434
|
+
this.send = (message, urgent = false) => {
|
|
5435
|
+
if (this.activityState === ActivityState.NotActive) {
|
|
5436
|
+
return;
|
|
5437
|
+
}
|
|
5438
|
+
// ====================================================
|
|
5439
|
+
if (this.activityState === ActivityState.ColdStart) {
|
|
5440
|
+
this.bufferedMessages1.push(message);
|
|
5441
|
+
if (!this.singleBuffer) {
|
|
5442
|
+
this.bufferedMessages2.push(message);
|
|
5443
|
+
}
|
|
5444
|
+
this.conditionsManager?.processMessage(message);
|
|
5445
|
+
}
|
|
5446
|
+
else {
|
|
5447
|
+
this.messages.push(message);
|
|
5448
|
+
}
|
|
5449
|
+
// TODO: commit on start if there were `urgent` sends;
|
|
5450
|
+
// Clarify where urgent can be used for;
|
|
5451
|
+
// Clarify workflow for each type of message in case it was sent before start
|
|
5452
|
+
// (like Fetch before start; maybe add an option "preCapture: boolean" or sth alike)
|
|
5453
|
+
// Careful: `this.delay` is equal to zero before start so all Timestamp-s will have to be updated on start
|
|
5454
|
+
if (this.activityState === ActivityState.Active && urgent) {
|
|
5455
|
+
this.commit();
|
|
5456
|
+
}
|
|
5457
|
+
};
|
|
4980
5458
|
this.coldStartCommitN = 0;
|
|
4981
5459
|
this.delay = 0;
|
|
4982
5460
|
this.attachStartCallback = (cb, useSafe = false) => {
|
|
@@ -5043,6 +5521,7 @@ class App {
|
|
|
5043
5521
|
this.onUxtCb = [];
|
|
5044
5522
|
this.contextId = Math.random().toString(36).slice(2);
|
|
5045
5523
|
this.projectKey = projectKey;
|
|
5524
|
+
this.inlineCss = getInlineOptions(options.inlineCss ?? 0);
|
|
5046
5525
|
if (Object.keys(options).findIndex((k) => ['fixedCanvasScaling', 'disableCanvas'].includes(k)) !==
|
|
5047
5526
|
-1) {
|
|
5048
5527
|
console.warn('Openreplay: canvas options are moving to separate key "canvas" in next update. Please update your configuration.');
|
|
@@ -5072,15 +5551,14 @@ class App {
|
|
|
5072
5551
|
__save_canvas_locally: false,
|
|
5073
5552
|
localStorage: null,
|
|
5074
5553
|
sessionStorage: null,
|
|
5075
|
-
disableStringDict: false,
|
|
5076
5554
|
forceSingleTab: false,
|
|
5077
5555
|
assistSocketHost: '',
|
|
5078
5556
|
fixedCanvasScaling: false,
|
|
5079
5557
|
disableCanvas: false,
|
|
5080
5558
|
captureIFrames: true,
|
|
5081
|
-
|
|
5082
|
-
obscureTextEmails: true,
|
|
5559
|
+
obscureTextEmails: false,
|
|
5083
5560
|
obscureTextNumbers: false,
|
|
5561
|
+
disableStringDict: false,
|
|
5084
5562
|
crossdomain: {
|
|
5085
5563
|
parentDomain: '*',
|
|
5086
5564
|
},
|
|
@@ -5091,6 +5569,8 @@ class App {
|
|
|
5091
5569
|
useAnimationFrame: false,
|
|
5092
5570
|
},
|
|
5093
5571
|
forceNgOff: false,
|
|
5572
|
+
inlineCss: 0,
|
|
5573
|
+
disableSprites: false,
|
|
5094
5574
|
};
|
|
5095
5575
|
this.options = simpleMerge(defaultOptions, options);
|
|
5096
5576
|
if (!this.insideIframe &&
|
|
@@ -5112,7 +5592,7 @@ class App {
|
|
|
5112
5592
|
forceNgOff: Boolean(options.forceNgOff),
|
|
5113
5593
|
maintainer: this.options.nodes?.maintainer,
|
|
5114
5594
|
});
|
|
5115
|
-
this.observer = new TopObserver({ app: this, options });
|
|
5595
|
+
this.observer = new TopObserver({ app: this, options: { ...options, ...this.inlineCss } });
|
|
5116
5596
|
this.ticker = new Ticker(this);
|
|
5117
5597
|
this.ticker.attach(() => this.commit());
|
|
5118
5598
|
this.debug = new Logger(this.options.__debug__);
|
|
@@ -5329,30 +5809,6 @@ class App {
|
|
|
5329
5809
|
}
|
|
5330
5810
|
this.debug.error('OpenReplay error: ', context, e);
|
|
5331
5811
|
}
|
|
5332
|
-
send(message, urgent = false) {
|
|
5333
|
-
if (this.activityState === ActivityState.NotActive) {
|
|
5334
|
-
return;
|
|
5335
|
-
}
|
|
5336
|
-
// ====================================================
|
|
5337
|
-
if (this.activityState === ActivityState.ColdStart) {
|
|
5338
|
-
this.bufferedMessages1.push(message);
|
|
5339
|
-
if (!this.singleBuffer) {
|
|
5340
|
-
this.bufferedMessages2.push(message);
|
|
5341
|
-
}
|
|
5342
|
-
this.conditionsManager?.processMessage(message);
|
|
5343
|
-
}
|
|
5344
|
-
else {
|
|
5345
|
-
this.messages.push(message);
|
|
5346
|
-
}
|
|
5347
|
-
// TODO: commit on start if there were `urgent` sends;
|
|
5348
|
-
// Clarify where urgent can be used for;
|
|
5349
|
-
// Clarify workflow for each type of message in case it was sent before start
|
|
5350
|
-
// (like Fetch before start; maybe add an option "preCapture: boolean" or sth alike)
|
|
5351
|
-
// Careful: `this.delay` is equal to zero before start so all Timestamp-s will have to be updated on start
|
|
5352
|
-
if (this.activityState === ActivityState.Active && urgent) {
|
|
5353
|
-
this.commit();
|
|
5354
|
-
}
|
|
5355
|
-
}
|
|
5356
5812
|
/**
|
|
5357
5813
|
* Normal workflow: add timestamp and tab data to batch, then commit it
|
|
5358
5814
|
* every ~30ms
|
|
@@ -7593,138 +8049,6 @@ function Viewport (app) {
|
|
|
7593
8049
|
app.ticker.attach(sendSetViewportSize, 5, false);
|
|
7594
8050
|
}
|
|
7595
8051
|
|
|
7596
|
-
function hasAdoptedSS(node) {
|
|
7597
|
-
return (isRootNode(node) &&
|
|
7598
|
-
// @ts-ignore
|
|
7599
|
-
!!node.adoptedStyleSheets);
|
|
7600
|
-
}
|
|
7601
|
-
// TODO: encapsulate to be init-ed on-start and join with cssrules.ts under one folder
|
|
7602
|
-
let _id = 0xf;
|
|
7603
|
-
function nextID() {
|
|
7604
|
-
return _id++;
|
|
7605
|
-
}
|
|
7606
|
-
const styleSheetIDMap = new Map();
|
|
7607
|
-
function ConstructedStyleSheets (app) {
|
|
7608
|
-
if (app === null) {
|
|
7609
|
-
return;
|
|
7610
|
-
}
|
|
7611
|
-
if (!hasAdoptedSS(document)) {
|
|
7612
|
-
return;
|
|
7613
|
-
}
|
|
7614
|
-
const styleSheetIDMap = new Map();
|
|
7615
|
-
const adoptedStyleSheetsOwnings = new Map();
|
|
7616
|
-
const sendAdoptedStyleSheetsUpdate = (root) => setTimeout(() => {
|
|
7617
|
-
let nodeID = app.nodes.getID(root);
|
|
7618
|
-
if (root === document) {
|
|
7619
|
-
nodeID = 0; // main document doesn't have nodeID. ID count starts from the documentElement
|
|
7620
|
-
}
|
|
7621
|
-
if (nodeID === undefined) {
|
|
7622
|
-
return;
|
|
7623
|
-
}
|
|
7624
|
-
let pastOwning = adoptedStyleSheetsOwnings.get(nodeID);
|
|
7625
|
-
if (!pastOwning) {
|
|
7626
|
-
pastOwning = [];
|
|
7627
|
-
}
|
|
7628
|
-
const nowOwning = [];
|
|
7629
|
-
const styleSheets = root.adoptedStyleSheets;
|
|
7630
|
-
if (styleSheets && Symbol.iterator in styleSheets) {
|
|
7631
|
-
for (const s of styleSheets) {
|
|
7632
|
-
let sheetID = styleSheetIDMap.get(s);
|
|
7633
|
-
const init = !sheetID;
|
|
7634
|
-
if (!sheetID) {
|
|
7635
|
-
sheetID = nextID();
|
|
7636
|
-
styleSheetIDMap.set(s, sheetID);
|
|
7637
|
-
}
|
|
7638
|
-
if (!pastOwning.includes(sheetID)) {
|
|
7639
|
-
app.send(AdoptedSSAddOwner(sheetID, nodeID));
|
|
7640
|
-
}
|
|
7641
|
-
if (init) {
|
|
7642
|
-
const rules = s.cssRules;
|
|
7643
|
-
for (let i = 0; i < rules.length; i++) {
|
|
7644
|
-
app.send(AdoptedSSInsertRuleURLBased(sheetID, rules[i].cssText, i, app.getBaseHref()));
|
|
7645
|
-
}
|
|
7646
|
-
}
|
|
7647
|
-
nowOwning.push(sheetID);
|
|
7648
|
-
}
|
|
7649
|
-
}
|
|
7650
|
-
if (Symbol.iterator in pastOwning) {
|
|
7651
|
-
for (const sheetID of pastOwning) {
|
|
7652
|
-
if (!nowOwning.includes(sheetID)) {
|
|
7653
|
-
app.send(AdoptedSSRemoveOwner(sheetID, nodeID));
|
|
7654
|
-
}
|
|
7655
|
-
}
|
|
7656
|
-
}
|
|
7657
|
-
adoptedStyleSheetsOwnings.set(nodeID, nowOwning);
|
|
7658
|
-
}, 20); // Mysterious bug:
|
|
7659
|
-
/* On the page https://explore.fast.design/components/fast-accordion
|
|
7660
|
-
the only rule inside the only adoptedStyleSheet of the iframe-s document
|
|
7661
|
-
gets changed during first milliseconds after the load.
|
|
7662
|
-
However, none of the documented methods (replace, insertRule) is triggered.
|
|
7663
|
-
The rule is not substituted (remains the same object), however the text gets changed.
|
|
7664
|
-
*/
|
|
7665
|
-
function patchAdoptedStyleSheets(prototype) {
|
|
7666
|
-
const nativeAdoptedStyleSheetsDescriptor = Object.getOwnPropertyDescriptor(prototype, 'adoptedStyleSheets');
|
|
7667
|
-
if (nativeAdoptedStyleSheetsDescriptor) {
|
|
7668
|
-
Object.defineProperty(prototype, 'adoptedStyleSheets', {
|
|
7669
|
-
...nativeAdoptedStyleSheetsDescriptor,
|
|
7670
|
-
set: function (value) {
|
|
7671
|
-
// @ts-ignore
|
|
7672
|
-
const retVal = nativeAdoptedStyleSheetsDescriptor.set.call(this, value);
|
|
7673
|
-
sendAdoptedStyleSheetsUpdate(this);
|
|
7674
|
-
return retVal;
|
|
7675
|
-
},
|
|
7676
|
-
});
|
|
7677
|
-
}
|
|
7678
|
-
}
|
|
7679
|
-
const patchContext = (context) => {
|
|
7680
|
-
// @ts-ignore
|
|
7681
|
-
if (context.__openreplay_adpss_patched__) {
|
|
7682
|
-
return;
|
|
7683
|
-
}
|
|
7684
|
-
else {
|
|
7685
|
-
// @ts-ignore
|
|
7686
|
-
context.__openreplay_adpss_patched__ = true;
|
|
7687
|
-
}
|
|
7688
|
-
patchAdoptedStyleSheets(context.Document.prototype);
|
|
7689
|
-
patchAdoptedStyleSheets(context.ShadowRoot.prototype);
|
|
7690
|
-
//@ts-ignore TODO: upgrade ts to 4.8+
|
|
7691
|
-
const { replace, replaceSync } = context.CSSStyleSheet.prototype;
|
|
7692
|
-
//@ts-ignore
|
|
7693
|
-
context.CSSStyleSheet.prototype.replace = function (text) {
|
|
7694
|
-
return replace.call(this, text).then((sheet) => {
|
|
7695
|
-
const sheetID = styleSheetIDMap.get(this);
|
|
7696
|
-
if (sheetID) {
|
|
7697
|
-
app.send(AdoptedSSReplaceURLBased(sheetID, text, app.getBaseHref()));
|
|
7698
|
-
}
|
|
7699
|
-
return sheet;
|
|
7700
|
-
});
|
|
7701
|
-
};
|
|
7702
|
-
//@ts-ignore
|
|
7703
|
-
context.CSSStyleSheet.prototype.replaceSync = function (text) {
|
|
7704
|
-
const sheetID = styleSheetIDMap.get(this);
|
|
7705
|
-
if (sheetID) {
|
|
7706
|
-
app.send(AdoptedSSReplaceURLBased(sheetID, text, app.getBaseHref()));
|
|
7707
|
-
}
|
|
7708
|
-
return replaceSync.call(this, text);
|
|
7709
|
-
};
|
|
7710
|
-
};
|
|
7711
|
-
patchContext(window);
|
|
7712
|
-
app.observer.attachContextCallback(app.safe(patchContext));
|
|
7713
|
-
app.attachStopCallback(() => {
|
|
7714
|
-
styleSheetIDMap.clear();
|
|
7715
|
-
adoptedStyleSheetsOwnings.clear();
|
|
7716
|
-
});
|
|
7717
|
-
// So far main Document is not triggered with nodeCallbacks
|
|
7718
|
-
app.attachStartCallback(() => {
|
|
7719
|
-
sendAdoptedStyleSheetsUpdate(document);
|
|
7720
|
-
});
|
|
7721
|
-
app.nodes.attachNodeCallback((node) => {
|
|
7722
|
-
if (hasAdoptedSS(node)) {
|
|
7723
|
-
sendAdoptedStyleSheetsUpdate(node);
|
|
7724
|
-
}
|
|
7725
|
-
});
|
|
7726
|
-
}
|
|
7727
|
-
|
|
7728
8052
|
function CSSRules (app) {
|
|
7729
8053
|
if (app === null) {
|
|
7730
8054
|
return;
|
|
@@ -8031,142 +8355,6 @@ function isObject(thing) {
|
|
|
8031
8355
|
return thing !== null && typeof thing === 'object';
|
|
8032
8356
|
}
|
|
8033
8357
|
|
|
8034
|
-
const sensitiveParams = new Set([
|
|
8035
|
-
"password",
|
|
8036
|
-
"pass",
|
|
8037
|
-
"pwd",
|
|
8038
|
-
"mdp",
|
|
8039
|
-
"token",
|
|
8040
|
-
"bearer",
|
|
8041
|
-
"jwt",
|
|
8042
|
-
"api_key",
|
|
8043
|
-
"api-key",
|
|
8044
|
-
"apiKey",
|
|
8045
|
-
"secret",
|
|
8046
|
-
"ssn",
|
|
8047
|
-
"zip",
|
|
8048
|
-
"zipcode",
|
|
8049
|
-
"x-api-key",
|
|
8050
|
-
"www-authenticate",
|
|
8051
|
-
"x-csrf-token",
|
|
8052
|
-
"x-requested-with",
|
|
8053
|
-
"x-forwarded-for",
|
|
8054
|
-
"x-real-ip",
|
|
8055
|
-
"cookie",
|
|
8056
|
-
"authorization",
|
|
8057
|
-
"auth",
|
|
8058
|
-
"proxy-authorization",
|
|
8059
|
-
"set-cookie",
|
|
8060
|
-
"account_key",
|
|
8061
|
-
]);
|
|
8062
|
-
function numDigits(x) {
|
|
8063
|
-
return (Math.log10((x ^ (x >> 31)) - (x >> 31)) | 0) + 1;
|
|
8064
|
-
}
|
|
8065
|
-
function obscure(value) {
|
|
8066
|
-
if (typeof value === "number") {
|
|
8067
|
-
const digits = numDigits(value);
|
|
8068
|
-
return "9".repeat(digits);
|
|
8069
|
-
}
|
|
8070
|
-
return value.replace(/[^\f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff\s]/g, '*');
|
|
8071
|
-
}
|
|
8072
|
-
function filterHeaders(headers) {
|
|
8073
|
-
const filteredHeaders = {};
|
|
8074
|
-
if (Array.isArray(headers)) {
|
|
8075
|
-
headers.forEach(({ name, value }) => {
|
|
8076
|
-
if (sensitiveParams.has(name.toLowerCase())) {
|
|
8077
|
-
filteredHeaders[name] = obscure(value);
|
|
8078
|
-
}
|
|
8079
|
-
else {
|
|
8080
|
-
filteredHeaders[name] = value;
|
|
8081
|
-
}
|
|
8082
|
-
});
|
|
8083
|
-
}
|
|
8084
|
-
else {
|
|
8085
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
8086
|
-
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8087
|
-
filteredHeaders[key] = obscure(value);
|
|
8088
|
-
}
|
|
8089
|
-
else {
|
|
8090
|
-
filteredHeaders[key] = value;
|
|
8091
|
-
}
|
|
8092
|
-
}
|
|
8093
|
-
}
|
|
8094
|
-
return filteredHeaders;
|
|
8095
|
-
}
|
|
8096
|
-
function filterBody(body) {
|
|
8097
|
-
if (!body) {
|
|
8098
|
-
return body;
|
|
8099
|
-
}
|
|
8100
|
-
let parsedBody;
|
|
8101
|
-
let isJSON = false;
|
|
8102
|
-
try {
|
|
8103
|
-
parsedBody = JSON.parse(body);
|
|
8104
|
-
isJSON = true;
|
|
8105
|
-
}
|
|
8106
|
-
catch (e) {
|
|
8107
|
-
// not json
|
|
8108
|
-
}
|
|
8109
|
-
if (isJSON) {
|
|
8110
|
-
obscureSensitiveData(parsedBody);
|
|
8111
|
-
return JSON.stringify(parsedBody);
|
|
8112
|
-
}
|
|
8113
|
-
else {
|
|
8114
|
-
try {
|
|
8115
|
-
const params = new URLSearchParams(body);
|
|
8116
|
-
for (const key of params.keys()) {
|
|
8117
|
-
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8118
|
-
const value = obscure(params.get(key));
|
|
8119
|
-
params.set(key, value);
|
|
8120
|
-
}
|
|
8121
|
-
}
|
|
8122
|
-
return params.toString();
|
|
8123
|
-
}
|
|
8124
|
-
catch (e) {
|
|
8125
|
-
// not string or url query
|
|
8126
|
-
return body;
|
|
8127
|
-
}
|
|
8128
|
-
}
|
|
8129
|
-
}
|
|
8130
|
-
function sanitizeObject(obj) {
|
|
8131
|
-
obscureSensitiveData(obj);
|
|
8132
|
-
return obj;
|
|
8133
|
-
}
|
|
8134
|
-
function obscureSensitiveData(obj) {
|
|
8135
|
-
if (Array.isArray(obj)) {
|
|
8136
|
-
obj.forEach(obscureSensitiveData);
|
|
8137
|
-
}
|
|
8138
|
-
else if (obj && typeof obj === "object") {
|
|
8139
|
-
for (const key in obj) {
|
|
8140
|
-
if (Object.hasOwn(obj, key)) {
|
|
8141
|
-
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8142
|
-
obj[key] = obscure(obj[key]);
|
|
8143
|
-
}
|
|
8144
|
-
else if (obj[key] !== null && typeof obj[key] === "object") {
|
|
8145
|
-
obscureSensitiveData(obj[key]);
|
|
8146
|
-
}
|
|
8147
|
-
}
|
|
8148
|
-
}
|
|
8149
|
-
}
|
|
8150
|
-
}
|
|
8151
|
-
function tryFilterUrl(url) {
|
|
8152
|
-
if (!url)
|
|
8153
|
-
return "";
|
|
8154
|
-
try {
|
|
8155
|
-
const urlObj = new URL(url);
|
|
8156
|
-
if (urlObj.searchParams) {
|
|
8157
|
-
for (const key of urlObj.searchParams.keys()) {
|
|
8158
|
-
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8159
|
-
urlObj.searchParams.set(key, "******");
|
|
8160
|
-
}
|
|
8161
|
-
}
|
|
8162
|
-
}
|
|
8163
|
-
return urlObj.toString();
|
|
8164
|
-
}
|
|
8165
|
-
catch (e) {
|
|
8166
|
-
return url;
|
|
8167
|
-
}
|
|
8168
|
-
}
|
|
8169
|
-
|
|
8170
8358
|
/**
|
|
8171
8359
|
* I know we're not using most of the information from this class
|
|
8172
8360
|
* but it can be useful in the future if we will decide to display more stuff in our ui
|
|
@@ -8198,18 +8386,13 @@ class NetworkMessage {
|
|
|
8198
8386
|
}
|
|
8199
8387
|
getMessage() {
|
|
8200
8388
|
const { reqHs, resHs } = this.writeHeaders();
|
|
8201
|
-
const reqBody = this.method === 'GET'
|
|
8202
|
-
? JSON.stringify(sanitizeObject(this.getData)) : filterBody(this.requestData);
|
|
8203
8389
|
const request = {
|
|
8204
|
-
headers:
|
|
8205
|
-
body:
|
|
8206
|
-
};
|
|
8207
|
-
const response = {
|
|
8208
|
-
headers: filterHeaders(resHs),
|
|
8209
|
-
body: filterBody(this.response)
|
|
8390
|
+
headers: reqHs,
|
|
8391
|
+
body: this.method === 'GET' ? JSON.stringify(this.getData) : this.requestData,
|
|
8210
8392
|
};
|
|
8393
|
+
const response = { headers: resHs, body: this.response };
|
|
8211
8394
|
const messageInfo = this.sanitize({
|
|
8212
|
-
url:
|
|
8395
|
+
url: this.url,
|
|
8213
8396
|
method: this.method,
|
|
8214
8397
|
status: this.status,
|
|
8215
8398
|
request,
|
|
@@ -8525,10 +8708,9 @@ class ResponseProxyHandler {
|
|
|
8525
8708
|
if (typeof this.resp.body.getReader !== 'function') {
|
|
8526
8709
|
return;
|
|
8527
8710
|
}
|
|
8528
|
-
const
|
|
8529
|
-
const _getReader = clonedResp.body.getReader;
|
|
8711
|
+
const _getReader = this.resp.body.getReader;
|
|
8530
8712
|
// @ts-ignore
|
|
8531
|
-
|
|
8713
|
+
this.resp.body.getReader = () => {
|
|
8532
8714
|
const reader = _getReader.apply(this.resp.body);
|
|
8533
8715
|
// when readyState is already 4,
|
|
8534
8716
|
// it's not a chunked stream, or it had already been read.
|
|
@@ -9370,7 +9552,7 @@ class API {
|
|
|
9370
9552
|
this.signalStartIssue = (reason, missingApi) => {
|
|
9371
9553
|
const doNotTrack = this.checkDoNotTrack();
|
|
9372
9554
|
console.log("Tracker couldn't start due to:", JSON.stringify({
|
|
9373
|
-
trackerVersion: '16.
|
|
9555
|
+
trackerVersion: '16.2.0',
|
|
9374
9556
|
projectKey: this.options.projectKey,
|
|
9375
9557
|
doNotTrack,
|
|
9376
9558
|
reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
|