@newrelic/browser-agent 1.251.1 → 1.252.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/CHANGELOG.md +25 -0
- package/README.md +5 -5
- package/dist/cjs/common/config/state/init.js +2 -2
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/drain/drain.js +3 -1
- package/dist/cjs/common/event-emitter/contextual-ee.js +7 -1
- package/dist/cjs/common/harvest/harvest.js +3 -2
- package/dist/cjs/common/session/session-entity.js +3 -1
- package/dist/cjs/features/ajax/instrument/index.js +2 -0
- package/dist/cjs/features/jserrors/instrument/index.js +5 -0
- package/dist/cjs/features/page_view_event/aggregate/index.js +1 -1
- package/dist/cjs/features/session_replay/aggregate/index.js +27 -2
- package/dist/cjs/features/session_replay/shared/recorder.js +10 -4
- package/dist/cjs/features/session_replay/shared/stylesheet-evaluator.js +13 -12
- package/dist/cjs/features/utils/instrument-base.js +1 -1
- package/dist/cjs/loaders/api/api-methods.js +8 -0
- package/dist/cjs/loaders/api/api.js +7 -8
- package/dist/cjs/loaders/configure/configure.js +1 -1
- package/dist/esm/common/config/state/init.js +2 -2
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/drain/drain.js +3 -1
- package/dist/esm/common/event-emitter/contextual-ee.js +7 -1
- package/dist/esm/common/harvest/harvest.js +3 -2
- package/dist/esm/common/session/session-entity.js +3 -1
- package/dist/esm/features/ajax/instrument/index.js +2 -0
- package/dist/esm/features/jserrors/instrument/index.js +5 -0
- package/dist/esm/features/page_view_event/aggregate/index.js +1 -1
- package/dist/esm/features/session_replay/aggregate/index.js +27 -2
- package/dist/esm/features/session_replay/shared/recorder.js +10 -4
- package/dist/esm/features/session_replay/shared/stylesheet-evaluator.js +13 -12
- package/dist/esm/features/utils/instrument-base.js +1 -1
- package/dist/esm/loaders/api/api-methods.js +2 -0
- package/dist/esm/loaders/api/api.js +7 -7
- package/dist/esm/loaders/configure/configure.js +1 -1
- package/dist/types/common/drain/drain.d.ts +2 -1
- package/dist/types/common/drain/drain.d.ts.map +1 -1
- package/dist/types/common/event-emitter/contextual-ee.d.ts.map +1 -1
- package/dist/types/common/harvest/harvest.d.ts.map +1 -1
- package/dist/types/common/session/session-entity.d.ts +0 -1
- package/dist/types/common/session/session-entity.d.ts.map +1 -1
- package/dist/types/features/ajax/instrument/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/stylesheet-evaluator.d.ts +1 -1
- package/dist/types/features/session_replay/shared/stylesheet-evaluator.d.ts.map +1 -1
- package/dist/types/loaders/api/api-methods.d.ts +3 -0
- package/dist/types/loaders/api/api-methods.d.ts.map +1 -0
- package/dist/types/loaders/api/api.d.ts +0 -1
- package/dist/types/loaders/api/api.d.ts.map +1 -1
- package/package.json +4 -1
- package/src/common/config/state/init.js +2 -2
- package/src/common/drain/drain.js +3 -2
- package/src/common/event-emitter/contextual-ee.js +7 -1
- package/src/common/harvest/harvest.js +3 -2
- package/src/common/session/session-entity.js +3 -1
- package/src/features/ajax/instrument/index.js +2 -0
- package/src/features/jserrors/instrument/index.js +6 -0
- package/src/features/page_view_event/aggregate/index.js +1 -1
- package/src/features/session_replay/aggregate/index.js +21 -3
- package/src/features/session_replay/shared/recorder.js +10 -4
- package/src/features/session_replay/shared/stylesheet-evaluator.js +13 -12
- package/src/features/utils/instrument-base.js +1 -1
- package/src/loaders/api/api-methods.js +9 -0
- package/src/loaders/api/api.js +7 -17
|
@@ -52,6 +52,7 @@ export class Aggregate extends AggregateBase {
|
|
|
52
52
|
this.entitled = false;
|
|
53
53
|
this.recorder = args?.recorder;
|
|
54
54
|
if (this.recorder) this.recorder.parent = this;
|
|
55
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/Enabled'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
55
56
|
const shouldSetup = getConfigurationValue(agentIdentifier, 'privacy.cookies_enabled') === true && getConfigurationValue(agentIdentifier, 'session_trace.enabled') === true;
|
|
56
57
|
if (shouldSetup) {
|
|
57
58
|
// The SessionEntity class can emit a message indicating the session was cleared and reset (expiry, inactivity). This feature must abort and never resume if that occurs.
|
|
@@ -116,13 +117,37 @@ export class Aggregate extends AggregateBase {
|
|
|
116
117
|
this.switchToFull();
|
|
117
118
|
}
|
|
118
119
|
}, this.featureName, this.ee);
|
|
120
|
+
const {
|
|
121
|
+
error_sampling_rate,
|
|
122
|
+
sampling_rate,
|
|
123
|
+
autoStart,
|
|
124
|
+
block_selector,
|
|
125
|
+
mask_text_selector,
|
|
126
|
+
mask_all_inputs,
|
|
127
|
+
inline_stylesheet,
|
|
128
|
+
inline_images,
|
|
129
|
+
collect_fonts
|
|
130
|
+
} = getConfigurationValue(this.agentIdentifier, 'session_replay');
|
|
119
131
|
this.waitForFlags(['sr']).then(_ref => {
|
|
120
132
|
let [flagOn] = _ref;
|
|
121
133
|
this.entitled = flagOn;
|
|
122
|
-
if (!this.entitled && this.recorder?.recording)
|
|
123
|
-
|
|
134
|
+
if (!this.entitled && this.recorder?.recording) {
|
|
135
|
+
this.recorder.abort(ABORT_REASONS.ENTITLEMENTS);
|
|
136
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/EnabledNotEntitled/Detected'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
137
|
+
}
|
|
138
|
+
this.initializeRecording(Math.random() * 100 < error_sampling_rate, Math.random() * 100 < sampling_rate);
|
|
124
139
|
}).then(() => sharedChannel.onReplayReady(this.mode)); // notify watchers that replay started with the mode
|
|
125
140
|
|
|
141
|
+
/** Detect if the default configs have been altered and report a SM. This is useful to evaluate what the reasonable defaults are across a customer base over time */
|
|
142
|
+
if (!autoStart) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/AutoStart/Modified'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
143
|
+
if (collect_fonts === true) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/CollectFonts/Modified'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
144
|
+
if (inline_stylesheet !== true) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/InlineStylesheet/Modified'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
145
|
+
if (inline_images === true) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/InlineImages/Modifed'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
146
|
+
if (mask_all_inputs !== true) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/MaskAllInputs/Modified'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
147
|
+
if (block_selector !== '[data-nr-block]') handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/BlockSelector/Modified'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
148
|
+
if (mask_text_selector !== '*') handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/MaskTextSelector/Modified'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
149
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/SamplingRate/Value', sampling_rate], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
150
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/ErrorSamplingRate/Value', error_sampling_rate], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
126
151
|
this.drain();
|
|
127
152
|
}
|
|
128
153
|
}
|
|
@@ -109,14 +109,15 @@ export class Recorder {
|
|
|
109
109
|
const incompletes = stylesheetEvaluator.evaluate();
|
|
110
110
|
/** Only stop ignoring data if already ignoring and a new valid snapshap is taking place (0 incompletes and we get a meta node for the snap) */
|
|
111
111
|
if (!incompletes && this.#fixing && event.type === RRWEB_EVENT_TYPES.Meta) this.#fixing = false;
|
|
112
|
-
if (incompletes) {
|
|
113
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/Payload/Missing-Inline-Css', incompletes], undefined, FEATURE_NAMES.metrics, this.parent.ee);
|
|
112
|
+
if (incompletes > 0) {
|
|
114
113
|
/** wait for the evaluator to download/replace the incompletes' src code and then take a new snap */
|
|
115
114
|
stylesheetEvaluator.fix().then(failedToFix => {
|
|
116
|
-
if (failedToFix) {
|
|
115
|
+
if (failedToFix > 0) {
|
|
117
116
|
this.currentBufferTarget.inlinedAllStylesheets = false;
|
|
118
117
|
this.shouldFix = false;
|
|
119
118
|
}
|
|
119
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/Payload/Missing-Inline-Css/Failed', failedToFix], undefined, FEATURE_NAMES.metrics, this.parent.ee);
|
|
120
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/Payload/Missing-Inline-Css/Fixed', incompletes - failedToFix], undefined, FEATURE_NAMES.metrics, this.parent.ee);
|
|
120
121
|
this.takeFullSnapshot();
|
|
121
122
|
});
|
|
122
123
|
/** Only start ignoring data if got a faulty snapshot */
|
|
@@ -170,7 +171,12 @@ export class Recorder {
|
|
|
170
171
|
|
|
171
172
|
/** force the recording lib to take a full DOM snapshot. This needs to occur in certain cases, like visibility changes */
|
|
172
173
|
takeFullSnapshot() {
|
|
173
|
-
|
|
174
|
+
try {
|
|
175
|
+
if (!this.recording) return;
|
|
176
|
+
recorder.takeFullSnapshot();
|
|
177
|
+
} catch (err) {
|
|
178
|
+
// in the off chance we think we are recording, but rrweb does not, rrweb's lib will throw an error. This catch is just a precaution
|
|
179
|
+
}
|
|
174
180
|
}
|
|
175
181
|
clearTimestamps() {
|
|
176
182
|
this.currentBufferTarget.cycleTimestamp = undefined;
|
|
@@ -8,7 +8,7 @@ class StylesheetEvaluator {
|
|
|
8
8
|
* Used at harvest time to denote that all subsequent payloads are subject to this and customers should be advised to handle crossorigin decoration
|
|
9
9
|
* */
|
|
10
10
|
invalidStylesheetsDetected = false;
|
|
11
|
-
failedToFix =
|
|
11
|
+
failedToFix = 0;
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* this works by checking (only ever once) each cssRules obj in the style sheets array. The try/catch will catch an error if the cssRules obj blocks access, triggering the module to try to "fix" the asset`. Returns the count of incomplete assets discovered.
|
|
@@ -18,15 +18,15 @@ class StylesheetEvaluator {
|
|
|
18
18
|
let incompletes = 0;
|
|
19
19
|
if (isBrowserScope) {
|
|
20
20
|
for (let i = 0; i < Object.keys(document.styleSheets).length; i++) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
this.#evaluated.add(ss);
|
|
21
|
+
if (!this.#evaluated.has(document.styleSheets[i])) {
|
|
22
|
+
this.#evaluated.add(document.styleSheets[i]);
|
|
24
23
|
try {
|
|
25
24
|
// eslint-disable-next-line
|
|
26
|
-
const temp =
|
|
25
|
+
const temp = document.styleSheets[i].cssRules;
|
|
27
26
|
} catch (err) {
|
|
27
|
+
if (!document.styleSheets[i].href) return;
|
|
28
28
|
incompletes++;
|
|
29
|
-
this.#fetchProms.push(this.#fetchAndOverride(document.styleSheets[i]
|
|
29
|
+
this.#fetchProms.push(this.#fetchAndOverride(document.styleSheets[i]));
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
}
|
|
@@ -43,7 +43,7 @@ class StylesheetEvaluator {
|
|
|
43
43
|
await Promise.all(this.#fetchProms);
|
|
44
44
|
this.#fetchProms = [];
|
|
45
45
|
const failedToFix = this.failedToFix;
|
|
46
|
-
this.failedToFix =
|
|
46
|
+
this.failedToFix = 0;
|
|
47
47
|
return failedToFix;
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -53,11 +53,12 @@ class StylesheetEvaluator {
|
|
|
53
53
|
* @param {*} href - The asset href to fetch
|
|
54
54
|
* @returns {Promise}
|
|
55
55
|
*/
|
|
56
|
-
async #fetchAndOverride(target
|
|
56
|
+
async #fetchAndOverride(target) {
|
|
57
|
+
if (!target?.href) return;
|
|
57
58
|
try {
|
|
58
|
-
const stylesheetContents = await originals.FETCH.bind(window)(href);
|
|
59
|
+
const stylesheetContents = await originals.FETCH.bind(window)(target.href);
|
|
59
60
|
if (!stylesheetContents.ok) {
|
|
60
|
-
this.failedToFix
|
|
61
|
+
this.failedToFix++;
|
|
61
62
|
return;
|
|
62
63
|
}
|
|
63
64
|
const stylesheetText = await stylesheetContents.text();
|
|
@@ -82,11 +83,11 @@ class StylesheetEvaluator {
|
|
|
82
83
|
return stylesheetText;
|
|
83
84
|
}
|
|
84
85
|
});
|
|
85
|
-
this.failedToFix
|
|
86
|
+
this.failedToFix++;
|
|
86
87
|
}
|
|
87
88
|
} catch (err) {
|
|
88
89
|
// failed to fetch
|
|
89
|
-
this.failedToFix
|
|
90
|
+
this.failedToFix++;
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
}
|
|
@@ -114,7 +114,7 @@ export class InstrumentBase extends FeatureBase {
|
|
|
114
114
|
warn("Downloading and initializing ".concat(this.featureName, " failed..."), e);
|
|
115
115
|
this.abortHandler?.(); // undo any important alterations made to the page
|
|
116
116
|
// not supported yet but nice to do: "abort" this agent's EE for this feature specifically
|
|
117
|
-
drain(this.agentIdentifier, this.featureName);
|
|
117
|
+
drain(this.agentIdentifier, this.featureName, true);
|
|
118
118
|
loadedSuccessfully(false);
|
|
119
119
|
}
|
|
120
120
|
};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export const apiMethods = ['setErrorHandler', 'finished', 'addToTrace', 'addRelease', 'addPageAction', 'setCurrentRouteName', 'setPageViewName', 'setCustomAttribute', 'interaction', 'noticeError', 'setUserId', 'setApplicationVersion', 'start', 'recordReplay', 'pauseReplay'];
|
|
2
|
+
export const asyncApiMethods = ['setErrorHandler', 'finished', 'addToTrace', 'addRelease'];
|
|
@@ -13,12 +13,10 @@ import { isBrowserScope } from '../../common/constants/runtime';
|
|
|
13
13
|
import { warn } from '../../common/util/console';
|
|
14
14
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../features/metrics/constants';
|
|
15
15
|
import { gosCDN } from '../../common/window/nreum';
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
import { apiMethods, asyncApiMethods } from './api-methods';
|
|
18
17
|
export function setTopLevelCallers() {
|
|
19
18
|
const nr = gosCDN();
|
|
20
|
-
|
|
21
|
-
funcs.forEach(f => {
|
|
19
|
+
apiMethods.forEach(f => {
|
|
22
20
|
nr[f] = function () {
|
|
23
21
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
24
22
|
args[_key] = arguments[_key];
|
|
@@ -44,12 +42,11 @@ export function setAPI(agentIdentifier, forceDrain) {
|
|
|
44
42
|
const apiInterface = {};
|
|
45
43
|
var instanceEE = ee.get(agentIdentifier);
|
|
46
44
|
var tracerEE = instanceEE.get('tracer');
|
|
47
|
-
var asyncApiFns = ['setErrorHandler', 'finished', 'addToTrace', 'addRelease'];
|
|
48
45
|
var prefix = 'api-';
|
|
49
46
|
var spaPrefix = prefix + 'ixn-';
|
|
50
47
|
|
|
51
48
|
// Setup stub functions that queue calls for later processing.
|
|
52
|
-
|
|
49
|
+
asyncApiMethods.forEach(fnName => {
|
|
53
50
|
apiInterface[fnName] = apiCall(prefix, fnName, true, 'api');
|
|
54
51
|
});
|
|
55
52
|
apiInterface.addPageAction = apiCall(prefix, 'addPageAction', true, FEATURE_NAMES.pageAction);
|
|
@@ -200,7 +197,10 @@ export function setAPI(agentIdentifier, forceDrain) {
|
|
|
200
197
|
} = _ref;
|
|
201
198
|
setAPI(agentIdentifier);
|
|
202
199
|
drain(agentIdentifier, 'api');
|
|
203
|
-
}).catch(() =>
|
|
200
|
+
}).catch(() => {
|
|
201
|
+
warn('Downloading runtime APIs failed...');
|
|
202
|
+
drain(agentIdentifier, 'api', true);
|
|
203
|
+
});
|
|
204
204
|
}
|
|
205
205
|
return apiInterface;
|
|
206
206
|
}
|
|
@@ -3,7 +3,7 @@ import { addToNREUM, gosCDN } from '../../common/window/nreum';
|
|
|
3
3
|
import { getConfiguration, setConfiguration, setInfo, setLoaderConfig, setRuntime } from '../../common/config/config';
|
|
4
4
|
import { activatedFeatures } from '../../common/util/feature-flags';
|
|
5
5
|
import { isWorkerScope } from '../../common/constants/runtime';
|
|
6
|
-
import { redefinePublicPath } from
|
|
6
|
+
import { redefinePublicPath } from "./public-path.npm";
|
|
7
7
|
let alreadySetOnce = false; // the configure() function can run multiple times in agent lifecycle
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -12,6 +12,7 @@ export function registerDrain(agentIdentifier: string, group: string): void;
|
|
|
12
12
|
* its own named group explicitly, when ready.
|
|
13
13
|
* @param {string} agentIdentifier - A unique 16 character ID corresponding to an instantiated agent.
|
|
14
14
|
* @param {string} featureName - A named group into which the feature's buffered events are bucketed.
|
|
15
|
+
* @param {boolean} force - Whether to force the drain to occur immediately, bypassing the registry and staging logic.
|
|
15
16
|
*/
|
|
16
|
-
export function drain(agentIdentifier?: string, featureName?: string): void;
|
|
17
|
+
export function drain(agentIdentifier?: string, featureName?: string, force?: boolean): void;
|
|
17
18
|
//# sourceMappingURL=drain.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drain.d.ts","sourceRoot":"","sources":["../../../../src/common/drain/drain.js"],"names":[],"mappings":"AAYA;;;;;;;GAOG;AACH,+CAHW,MAAM,SACN,MAAM,QAQhB;AAYD
|
|
1
|
+
{"version":3,"file":"drain.d.ts","sourceRoot":"","sources":["../../../../src/common/drain/drain.js"],"names":[],"mappings":"AAYA;;;;;;;GAOG;AACH,+CAHW,MAAM,SACN,MAAM,QAQhB;AAYD;;;;;;GAMG;AACH,wCAJW,MAAM,gBACN,MAAM,UACN,OAAO,QAuDjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contextual-ee.d.ts","sourceRoot":"","sources":["../../../../src/common/event-emitter/contextual-ee.js"],"names":[],"mappings":";;;;;;;;;;;;;;;AAYA,+BAA0C;AA0DxC,+FAsBC;AAqBD,6CAEC;AAND,2CAEC;AAMD,mEAaC;AAcH,+
|
|
1
|
+
{"version":3,"file":"contextual-ee.d.ts","sourceRoot":"","sources":["../../../../src/common/event-emitter/contextual-ee.js"],"names":[],"mappings":";;;;;;;;;;;;;;;AAYA,+BAA0C;AA0DxC,+FAsBC;AAqBD,6CAEC;AAND,2CAEC;AAMD,mEAaC;AAcH,+BASC;AArBC,iDAGC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"harvest.d.ts","sourceRoot":"","sources":["../../../../src/common/harvest/harvest.js"],"names":[],"mappings":"AAsBA;;;;;;GAMG;AACH;IAII,0BAA2H;IAC3H,uBAAoD;IAEpD,YAAiB;IAGnB;;;;;OAKG;IACH,aAFW,eAAe,WAWzB;IAED;;;OAGG;IACH,YAFW,eAAe,WAMzB;IAED;;;OAGG;IACH,wBAFW,eAAe,WAMzB;IAED;;;;;;OAMG;IACH,gGAJW,eAAe,GACb,OAAO,
|
|
1
|
+
{"version":3,"file":"harvest.d.ts","sourceRoot":"","sources":["../../../../src/common/harvest/harvest.js"],"names":[],"mappings":"AAsBA;;;;;;GAMG;AACH;IAII,0BAA2H;IAC3H,uBAAoD;IAEpD,YAAiB;IAGnB;;;;;OAKG;IACH,aAFW,eAAe,WAWzB;IAED;;;OAGG;IACH,YAFW,eAAe,WAMzB;IAED;;;OAGG;IACH,wBAFW,eAAe,WAMzB;IAED;;;;;;OAMG;IACH,gGAJW,eAAe,GACb,OAAO,CAmFnB;IAGD,iCAoBC;IAED;;;;;;;OAOG;IACH,wBALW,yBAAyB,WACzB,6BAA6B,GAE3B,cAAc,CA2B1B;IAED;;;;;;;OAOG;IACH,uBAHW,cAAc,GACZ,cAAc,CAuB1B;IAED;;;;;OAKG;IACH,aAHW,yBAAyB,YACzB,sBAAsB,QAQhC;CACF;8BApPY,OAAO,YAAY,EAAE,eAAe;wCACpC,OAAO,YAAY,EAAE,yBAAyB;6BAC9C,OAAO,YAAY,EAAE,cAAc;qCACnC,OAAO,YAAY,EAAE,sBAAsB;4CAC3C,OAAO,YAAY,EAAE,6BAA6B;8BAZjC,2BAA2B;2BAF9B,mBAAmB"}
|
|
@@ -20,7 +20,6 @@ export class SessionEntity {
|
|
|
20
20
|
inactiveMs: number | undefined;
|
|
21
21
|
expiresTimer: Timer | undefined;
|
|
22
22
|
inactiveTimer: InteractionTimer | undefined;
|
|
23
|
-
isNew: boolean | undefined;
|
|
24
23
|
initialized: boolean | undefined;
|
|
25
24
|
get lookupKey(): string;
|
|
26
25
|
sync(data: any): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-entity.d.ts","sourceRoot":"","sources":["../../../../src/common/session/session-entity.js"],"names":[],"mappings":"AA6BA;IACE;;;;;OAKG;IACH,uBA0BC;IApBC,qBAAsC;IACtC,aAAsB;IACtB,UAAe;IAGf,SAAc;IAEd,QAAiC;IAenC;;;;
|
|
1
|
+
{"version":3,"file":"session-entity.d.ts","sourceRoot":"","sources":["../../../../src/common/session/session-entity.js"],"names":[],"mappings":"AA6BA;IACE;;;;;OAKG;IACH,uBA0BC;IApBC,qBAAsC;IACtC,aAAsB;IACtB,UAAe;IAGf,SAAc;IAEd,QAAiC;IAenC;;;;aAwEC;IAjEC,8BAA0B;IAC1B,+BAA4B;IAc1B,gCAOqC;IAUrC,4CAiBsC;IAexC,iCAAuB;IAIzB,wBAEC;IAED,sBAEC;IAED;;;OAGG;IACH,QAFa,MAAM,CA6BlB;IAED;;;;;;OAMG;IACH,YAHW,MAAM,GACJ,MAAM,CAkBlB;IAED,gBAuBC;IAED;;OAEG;IACH,gBAIC;IAED;;;OAGG;IACH,qBAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;OAGG;IACH,gBAHW,MAAM,GACJ,OAAO,CAKnB;IAED,yDAUC;IAED,6DAIC;IAED;;;OAGG;IACH,6BAHW,MAAM,GACJ,MAAM,CAIlB;IAED,gDAaC;IAHG,YAAuD;CAI5D;sBApSqB,gBAAgB;iCAGL,4BAA4B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/instrument/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/instrument/index.js"],"names":[],"mappings":"AA0BA;IACE,2BAAiC;IACjC,mEAqCC;IA/BC,mBAAiC;IAEjC,4EAAkF;CA8BrF;+BAnD8B,6BAA6B;mBAFzC,uBAAuB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/instrument/index.js"],"names":[],"mappings":"AAeA;IACE,2BAAiC;IAIjC,mEA4CC;IAvCG,2CAA0C;IAqC5C,yBAA+B;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/instrument/index.js"],"names":[],"mappings":"AAeA;IACE,2BAAiC;IAIjC,mEA4CC;IAvCG,2CAA0C;IAqC5C,yBAA+B;;CAoFlC;+BA3I8B,6BAA6B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"AA8BA;IACE,2BAAiC;IAEjC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"AA8BA;IACE,2BAAiC;IAEjC,8DAwHC;IAtHC,8GAA8G;IAC9G,wBAAgH;IAChH,iFAAiF;IACjF,qBAAwB;IAGxB,2CAA2C;IAC3C,sDAAwB;IACxB,6CAA6C;IAC7C,gDAAmB;IAGnB,UAAuD;IAEvD,0BAA0B;IAC1B,kBAAqB;IAErB,cAA8B;IAoC5B,wCAKQ;IAyBN,sBAAwB;IAqC9B,qBAWC;IAED;;;;;;;OAOG;IACH,iCALW,OAAO,cACP,OAAO,iBACP,OAAO,GACL,IAAI,CAsDhB;IAED,2BASC;IAED;;;;;;;;;;;oBAiCC;IAED;;;;;;;;;MAmEC;IAED,qCAOC;IAED;;;;OAIG;IACH,mCAKC;IAED,yDAAyD;IACzD,yBAUC;IAED,yCAGC;CACF;8BA/W6B,4BAA4B;iCAHzB,2CAA2C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/recorder.js"],"names":[],"mappings":"AAWA;IAUE,yBAeC;IAdC,iEAAiE;IACjE,mBAAsB;IACtB,6DAA6D;IAC7D,oCAAuC;IACvC,kIAAkI;IAClI,kBAAqB;IACrB,sDAAsD;IACtD,YAAoB;IACpB,oEAAoE;IACpE,6BAAqH;IACrH,0FAA0F;IAC1F,eAA6C;IAC7C,uIAAuI;IACvI,0BAAyE;IAG3E;;;;;;;;;MAYC;IAED,mFAAmF;IACnF,oBAKC;IAED,qDAAqD;IACrD,uBAwBC;IAED;;;;;OAKG;IACH,
|
|
1
|
+
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/recorder.js"],"names":[],"mappings":"AAWA;IAUE,yBAeC;IAdC,iEAAiE;IACjE,mBAAsB;IACtB,6DAA6D;IAC7D,oCAAuC;IACvC,kIAAkI;IAClI,kBAAqB;IACrB,sDAAsD;IACtD,YAAoB;IACpB,oEAAoE;IACpE,6BAAqH;IACrH,0FAA0F;IAC1F,eAA6C;IAC7C,uIAAuI;IACvI,0BAAyE;IAG3E;;;;;;;;;MAYC;IAED,mFAAmF;IACnF,oBAKC;IAED,qDAAqD;IACrD,uBAwBC;IAED;;;;;OAKG;IACH,yCA0BC;IAED,0HAA0H;IAC1H,yCA2CC;IAED,0HAA0H;IAC1H,yBAOC;IAED,wBAEC;IAED,gCAAgC;IAChC,uCAGC;IAED;;;SAGK;IACL,oCAGC;;CACF;+BA/L8B,mBAAmB"}
|
|
@@ -5,7 +5,7 @@ declare class StylesheetEvaluator {
|
|
|
5
5
|
* Used at harvest time to denote that all subsequent payloads are subject to this and customers should be advised to handle crossorigin decoration
|
|
6
6
|
* */
|
|
7
7
|
invalidStylesheetsDetected: boolean;
|
|
8
|
-
failedToFix:
|
|
8
|
+
failedToFix: number;
|
|
9
9
|
/**
|
|
10
10
|
* this works by checking (only ever once) each cssRules obj in the style sheets array. The try/catch will catch an error if the cssRules obj blocks access, triggering the module to try to "fix" the asset`. Returns the count of incomplete assets discovered.
|
|
11
11
|
* @returns {Number}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stylesheet-evaluator.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/stylesheet-evaluator.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"stylesheet-evaluator.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/stylesheet-evaluator.js"],"names":[],"mappings":"AAyFA,sDAA4D;AAtF5D;IAGE;;;QAGI;IACJ,oCAAkC;IAClC,oBAAe;IAEf;;;OAGG;IACH,mBAmBC;IAED;;;OAGG;IACH,oBAMC;;CAuCF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-methods.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/api-methods.js"],"names":[],"mappings":"AAAA,kCAIC;AAED,uCAEC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/api.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/api.js"],"names":[],"mappings":"AAiBA,2CAeC;AAED;;;;;IAkDE;;;;OAIG;qBAFQ,MAAM;IAWjB;;;;OAIG;iCAFQ,MAAM,GAAC,IAAI;;;;;;EAwGvB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newrelic/browser-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.252.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
|
|
6
6
|
"description": "New Relic Browser Agent",
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
"src/*": [
|
|
18
18
|
"dist/types/*"
|
|
19
19
|
],
|
|
20
|
+
"dist/esm/*": [
|
|
21
|
+
"dist/types/*"
|
|
22
|
+
],
|
|
20
23
|
"loaders/agent": [
|
|
21
24
|
"dist/types/loaders/agent.d.ts"
|
|
22
25
|
],
|
|
@@ -64,8 +64,8 @@ const model = () => {
|
|
|
64
64
|
autoStart: true,
|
|
65
65
|
enabled: false,
|
|
66
66
|
harvestTimeSeconds: 60,
|
|
67
|
-
sampling_rate:
|
|
68
|
-
error_sampling_rate:
|
|
67
|
+
sampling_rate: 10, // float from 0 - 100
|
|
68
|
+
error_sampling_rate: 100, // float from 0 - 100
|
|
69
69
|
collect_fonts: false, // serialize fonts for collection without public asset url, this is currently broken in RRWeb -- https://github.com/rrweb-io/rrweb/issues/1304. When fixed, revisit with test cases
|
|
70
70
|
inline_images: false, // serialize images for collection without public asset url -- right now this is only useful for testing as it easily generates payloads too large to be harvested
|
|
71
71
|
inline_stylesheet: true, // serialize css for collection without public asset url
|
|
@@ -41,13 +41,14 @@ function curateRegistry (agentIdentifier) {
|
|
|
41
41
|
* its own named group explicitly, when ready.
|
|
42
42
|
* @param {string} agentIdentifier - A unique 16 character ID corresponding to an instantiated agent.
|
|
43
43
|
* @param {string} featureName - A named group into which the feature's buffered events are bucketed.
|
|
44
|
+
* @param {boolean} force - Whether to force the drain to occur immediately, bypassing the registry and staging logic.
|
|
44
45
|
*/
|
|
45
|
-
export function drain (agentIdentifier = '', featureName = 'feature') {
|
|
46
|
+
export function drain (agentIdentifier = '', featureName = 'feature', force = false) {
|
|
46
47
|
curateRegistry(agentIdentifier)
|
|
47
48
|
// If the feature for the specified agent is not in the registry, that means the instrument file was bypassed.
|
|
48
49
|
// This could happen in tests, or loaders that directly import the aggregator. In these cases it is safe to
|
|
49
50
|
// drain the feature group immediately rather than waiting to drain all at once.
|
|
50
|
-
if (!agentIdentifier || !registry[agentIdentifier].get(featureName)) return drainGroup(featureName)
|
|
51
|
+
if (!agentIdentifier || !registry[agentIdentifier].get(featureName) || force) return drainGroup(featureName)
|
|
51
52
|
|
|
52
53
|
// When `drain` is called, this feature is ready to drain (staged).
|
|
53
54
|
registry[agentIdentifier].get(featureName).staged = true
|
|
@@ -144,5 +144,11 @@ function ee (old, debugId) {
|
|
|
144
144
|
|
|
145
145
|
function abort () {
|
|
146
146
|
globalInstance.aborted = true
|
|
147
|
-
|
|
147
|
+
// The global backlog can be referenced directly by other emitters,
|
|
148
|
+
// so we need to delete its contents as opposed to replacing it.
|
|
149
|
+
// Otherwise, these references to the old backlog would still exist
|
|
150
|
+
// and the keys will not be garbage collected.
|
|
151
|
+
Object.keys(globalInstance.backlog).forEach(key => {
|
|
152
|
+
delete globalInstance.backlog[key]
|
|
153
|
+
})
|
|
148
154
|
}
|
|
@@ -142,9 +142,10 @@ export class Harvest extends SharedContext {
|
|
|
142
142
|
|
|
143
143
|
if (!opts.unload && cbFinished && submitMethod === submitData.xhr) {
|
|
144
144
|
const harvestScope = this
|
|
145
|
-
result.addEventListener('
|
|
145
|
+
result.addEventListener('loadend', function () {
|
|
146
146
|
// `this` refers to the XHR object in this scope, do not change this to a fat arrow
|
|
147
|
-
|
|
147
|
+
// status 0 refers to a local error, such as CORS or network failure, or a blocked request by the browser (e.g. adblocker)
|
|
148
|
+
const cbResult = { sent: this.status !== 0, status: this.status }
|
|
148
149
|
if (this.status === 429) {
|
|
149
150
|
cbResult.retry = true
|
|
150
151
|
cbResult.delay = harvestScope.tooManyRequestsDelay
|
|
@@ -125,7 +125,9 @@ export class SessionEntity {
|
|
|
125
125
|
|
|
126
126
|
// The fact that the session is "new" or pre-existing is used in some places in the agent. Session Replay and Trace
|
|
127
127
|
// can use this info to inform whether to trust a new sampling decision vs continue a previous tracking effort.
|
|
128
|
-
|
|
128
|
+
/* [NR-230914] 02/2024 - the logical OR assignment is used so that isNew remains 'true' if it was already set as such. This fixes the expires and inactive timestamps timing out in localStorage
|
|
129
|
+
while no page for a given domain is in-use and the session resetting upon user returning to the page as part of a fresh session. */
|
|
130
|
+
this.isNew ||= !Object.keys(initialRead).length
|
|
129
131
|
// if its a "new" session, we write to storage API with the default values. These values may change over the lifespan of the agent run.
|
|
130
132
|
// we can use a modeled object here to help us know and manage what values are being used. -- see "model" above
|
|
131
133
|
if (this.isNew) this.write(getModeledObject(this.state, model), true)
|
|
@@ -16,6 +16,7 @@ import { responseSizeFromXhr } from './response-size'
|
|
|
16
16
|
import { InstrumentBase } from '../../utils/instrument-base'
|
|
17
17
|
import { FEATURE_NAME } from '../constants'
|
|
18
18
|
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
19
|
+
import { SUPPORTABILITY_METRIC } from '../../metrics/constants'
|
|
19
20
|
|
|
20
21
|
var handlers = ['load', 'error', 'abort', 'timeout']
|
|
21
22
|
var handlersLen = handlers.length
|
|
@@ -395,6 +396,7 @@ function subscribeToEvents (agentIdentifier, ee, handler, dt) {
|
|
|
395
396
|
if (ctx.sameOrigin) {
|
|
396
397
|
var header = xhr.getResponseHeader('X-NewRelic-App-Data')
|
|
397
398
|
if (header) {
|
|
399
|
+
handle(SUPPORTABILITY_METRIC, ['Ajax/CrossApplicationTracing/Header/Seen'], undefined, FEATURE_NAMES.metrics, ee)
|
|
398
400
|
ctx.params.cat = header.split(', ').pop()
|
|
399
401
|
}
|
|
400
402
|
}
|
|
@@ -128,6 +128,12 @@ export class Instrument extends InstrumentBase {
|
|
|
128
128
|
* @returns {Error|UncaughtError} The error event converted to an Error object
|
|
129
129
|
*/
|
|
130
130
|
#castErrorEvent (errorEvent) {
|
|
131
|
+
if (errorEvent.error instanceof SyntaxError && !/:\d+$/.test(errorEvent.error.stack?.trim())) {
|
|
132
|
+
const error = new UncaughtError(errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno)
|
|
133
|
+
error.name = SyntaxError.name
|
|
134
|
+
return error
|
|
135
|
+
}
|
|
136
|
+
|
|
131
137
|
if (errorEvent.error instanceof Error) {
|
|
132
138
|
return errorEvent.error
|
|
133
139
|
}
|
|
@@ -101,7 +101,7 @@ export class Aggregate extends AggregateBase {
|
|
|
101
101
|
payload: { qs: queryParameters, body },
|
|
102
102
|
opts: { needResponse: true, sendEmptyBody: true },
|
|
103
103
|
cbFinished: ({ status, responseText }) => {
|
|
104
|
-
if (status >= 400) {
|
|
104
|
+
if (status >= 400 || status === 0) {
|
|
105
105
|
// Adding retry logic for the rum call will be a separate change
|
|
106
106
|
this.ee.abort()
|
|
107
107
|
return
|
|
@@ -53,6 +53,8 @@ export class Aggregate extends AggregateBase {
|
|
|
53
53
|
this.recorder = args?.recorder
|
|
54
54
|
if (this.recorder) this.recorder.parent = this
|
|
55
55
|
|
|
56
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/Enabled'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
57
|
+
|
|
56
58
|
const shouldSetup = (
|
|
57
59
|
getConfigurationValue(agentIdentifier, 'privacy.cookies_enabled') === true &&
|
|
58
60
|
getConfigurationValue(agentIdentifier, 'session_trace.enabled') === true
|
|
@@ -122,15 +124,31 @@ export class Aggregate extends AggregateBase {
|
|
|
122
124
|
}
|
|
123
125
|
}, this.featureName, this.ee)
|
|
124
126
|
|
|
127
|
+
const { error_sampling_rate, sampling_rate, autoStart, block_selector, mask_text_selector, mask_all_inputs, inline_stylesheet, inline_images, collect_fonts } = getConfigurationValue(this.agentIdentifier, 'session_replay')
|
|
128
|
+
|
|
125
129
|
this.waitForFlags(['sr']).then(([flagOn]) => {
|
|
126
130
|
this.entitled = flagOn
|
|
127
|
-
if (!this.entitled && this.recorder?.recording)
|
|
131
|
+
if (!this.entitled && this.recorder?.recording) {
|
|
132
|
+
this.recorder.abort(ABORT_REASONS.ENTITLEMENTS)
|
|
133
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/EnabledNotEntitled/Detected'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
134
|
+
}
|
|
128
135
|
this.initializeRecording(
|
|
129
|
-
(Math.random() * 100) <
|
|
130
|
-
(Math.random() * 100) <
|
|
136
|
+
(Math.random() * 100) < error_sampling_rate,
|
|
137
|
+
(Math.random() * 100) < sampling_rate
|
|
131
138
|
)
|
|
132
139
|
}).then(() => sharedChannel.onReplayReady(this.mode)) // notify watchers that replay started with the mode
|
|
133
140
|
|
|
141
|
+
/** Detect if the default configs have been altered and report a SM. This is useful to evaluate what the reasonable defaults are across a customer base over time */
|
|
142
|
+
if (!autoStart) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/AutoStart/Modified'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
143
|
+
if (collect_fonts === true) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/CollectFonts/Modified'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
144
|
+
if (inline_stylesheet !== true) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/InlineStylesheet/Modified'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
145
|
+
if (inline_images === true) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/InlineImages/Modifed'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
146
|
+
if (mask_all_inputs !== true) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/MaskAllInputs/Modified'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
147
|
+
if (block_selector !== '[data-nr-block]') handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/BlockSelector/Modified'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
148
|
+
if (mask_text_selector !== '*') handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/MaskTextSelector/Modified'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
149
|
+
|
|
150
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/SamplingRate/Value', sampling_rate], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
151
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/ErrorSamplingRate/Value', error_sampling_rate], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
134
152
|
this.drain()
|
|
135
153
|
}
|
|
136
154
|
}
|
|
@@ -101,14 +101,15 @@ export class Recorder {
|
|
|
101
101
|
const incompletes = stylesheetEvaluator.evaluate()
|
|
102
102
|
/** Only stop ignoring data if already ignoring and a new valid snapshap is taking place (0 incompletes and we get a meta node for the snap) */
|
|
103
103
|
if (!incompletes && this.#fixing && event.type === RRWEB_EVENT_TYPES.Meta) this.#fixing = false
|
|
104
|
-
if (incompletes) {
|
|
105
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/Payload/Missing-Inline-Css', incompletes], undefined, FEATURE_NAMES.metrics, this.parent.ee)
|
|
104
|
+
if (incompletes > 0) {
|
|
106
105
|
/** wait for the evaluator to download/replace the incompletes' src code and then take a new snap */
|
|
107
106
|
stylesheetEvaluator.fix().then((failedToFix) => {
|
|
108
|
-
if (failedToFix) {
|
|
107
|
+
if (failedToFix > 0) {
|
|
109
108
|
this.currentBufferTarget.inlinedAllStylesheets = false
|
|
110
109
|
this.shouldFix = false
|
|
111
110
|
}
|
|
111
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/Payload/Missing-Inline-Css/Failed', failedToFix], undefined, FEATURE_NAMES.metrics, this.parent.ee)
|
|
112
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/Payload/Missing-Inline-Css/Fixed', incompletes - failedToFix], undefined, FEATURE_NAMES.metrics, this.parent.ee)
|
|
112
113
|
this.takeFullSnapshot()
|
|
113
114
|
})
|
|
114
115
|
/** Only start ignoring data if got a faulty snapshot */
|
|
@@ -166,7 +167,12 @@ export class Recorder {
|
|
|
166
167
|
|
|
167
168
|
/** force the recording lib to take a full DOM snapshot. This needs to occur in certain cases, like visibility changes */
|
|
168
169
|
takeFullSnapshot () {
|
|
169
|
-
|
|
170
|
+
try {
|
|
171
|
+
if (!this.recording) return
|
|
172
|
+
recorder.takeFullSnapshot()
|
|
173
|
+
} catch (err) {
|
|
174
|
+
// in the off chance we think we are recording, but rrweb does not, rrweb's lib will throw an error. This catch is just a precaution
|
|
175
|
+
}
|
|
170
176
|
}
|
|
171
177
|
|
|
172
178
|
clearTimestamps () {
|
|
@@ -9,7 +9,7 @@ class StylesheetEvaluator {
|
|
|
9
9
|
* Used at harvest time to denote that all subsequent payloads are subject to this and customers should be advised to handle crossorigin decoration
|
|
10
10
|
* */
|
|
11
11
|
invalidStylesheetsDetected = false
|
|
12
|
-
failedToFix =
|
|
12
|
+
failedToFix = 0
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* this works by checking (only ever once) each cssRules obj in the style sheets array. The try/catch will catch an error if the cssRules obj blocks access, triggering the module to try to "fix" the asset`. Returns the count of incomplete assets discovered.
|
|
@@ -19,15 +19,15 @@ class StylesheetEvaluator {
|
|
|
19
19
|
let incompletes = 0
|
|
20
20
|
if (isBrowserScope) {
|
|
21
21
|
for (let i = 0; i < Object.keys(document.styleSheets).length; i++) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
this.#evaluated.add(ss)
|
|
22
|
+
if (!this.#evaluated.has(document.styleSheets[i])) {
|
|
23
|
+
this.#evaluated.add(document.styleSheets[i])
|
|
25
24
|
try {
|
|
26
25
|
// eslint-disable-next-line
|
|
27
|
-
const temp =
|
|
26
|
+
const temp = document.styleSheets[i].cssRules
|
|
28
27
|
} catch (err) {
|
|
28
|
+
if (!document.styleSheets[i].href) return
|
|
29
29
|
incompletes++
|
|
30
|
-
this.#fetchProms.push(this.#fetchAndOverride(document.styleSheets[i]
|
|
30
|
+
this.#fetchProms.push(this.#fetchAndOverride(document.styleSheets[i]))
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -44,7 +44,7 @@ class StylesheetEvaluator {
|
|
|
44
44
|
await Promise.all(this.#fetchProms)
|
|
45
45
|
this.#fetchProms = []
|
|
46
46
|
const failedToFix = this.failedToFix
|
|
47
|
-
this.failedToFix =
|
|
47
|
+
this.failedToFix = 0
|
|
48
48
|
return failedToFix
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -54,11 +54,12 @@ class StylesheetEvaluator {
|
|
|
54
54
|
* @param {*} href - The asset href to fetch
|
|
55
55
|
* @returns {Promise}
|
|
56
56
|
*/
|
|
57
|
-
async #fetchAndOverride (target
|
|
57
|
+
async #fetchAndOverride (target) {
|
|
58
|
+
if (!target?.href) return
|
|
58
59
|
try {
|
|
59
|
-
const stylesheetContents = await originals.FETCH.bind(window)(href)
|
|
60
|
+
const stylesheetContents = await originals.FETCH.bind(window)(target.href)
|
|
60
61
|
if (!stylesheetContents.ok) {
|
|
61
|
-
this.failedToFix
|
|
62
|
+
this.failedToFix++
|
|
62
63
|
return
|
|
63
64
|
}
|
|
64
65
|
const stylesheetText = await stylesheetContents.text()
|
|
@@ -77,11 +78,11 @@ class StylesheetEvaluator {
|
|
|
77
78
|
Object.defineProperty(target, 'cssText', {
|
|
78
79
|
get () { return stylesheetText }
|
|
79
80
|
})
|
|
80
|
-
this.failedToFix
|
|
81
|
+
this.failedToFix++
|
|
81
82
|
}
|
|
82
83
|
} catch (err) {
|
|
83
84
|
// failed to fetch
|
|
84
|
-
this.failedToFix
|
|
85
|
+
this.failedToFix++
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
88
|
}
|
|
@@ -108,7 +108,7 @@ export class InstrumentBase extends FeatureBase {
|
|
|
108
108
|
warn(`Downloading and initializing ${this.featureName} failed...`, e)
|
|
109
109
|
this.abortHandler?.() // undo any important alterations made to the page
|
|
110
110
|
// not supported yet but nice to do: "abort" this agent's EE for this feature specifically
|
|
111
|
-
drain(this.agentIdentifier, this.featureName)
|
|
111
|
+
drain(this.agentIdentifier, this.featureName, true)
|
|
112
112
|
loadedSuccessfully(false)
|
|
113
113
|
}
|
|
114
114
|
}
|