@pendo/agent 2.345.0 → 2.347.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/dom.esm.js +8 -4
- package/dist/pendo.debugger.min.js +11 -11
- package/dist/pendo.module.js +284 -116
- package/dist/pendo.module.min.js +11 -10
- package/dist/pendo.preview.min.js +5 -5
- package/dist/servers.json +8 -8
- package/package.json +1 -1
package/dist/pendo.module.js
CHANGED
|
@@ -668,7 +668,7 @@ function loadStagingAgent(config, pendo, debuggingEnabled) {
|
|
|
668
668
|
var altAgentUrl = getAlternateAgentUrl(config, true, debuggingEnabled);
|
|
669
669
|
if (altAgentUrl) {
|
|
670
670
|
setupMethodCapture(pendo);
|
|
671
|
-
includeScript(altAgentUrl, pendo);
|
|
671
|
+
includeScript(altAgentUrl, pendo, config.pendoGlobalKey);
|
|
672
672
|
return true;
|
|
673
673
|
}
|
|
674
674
|
}
|
|
@@ -679,7 +679,7 @@ function loadUnminifiedAgent(config, pendo, debuggingEnabled) {
|
|
|
679
679
|
var altAgentUrl = getAlternateAgentUrl(config, false, debuggingEnabled);
|
|
680
680
|
if (altAgentUrl) {
|
|
681
681
|
setupMethodCapture(pendo);
|
|
682
|
-
includeScript(altAgentUrl, pendo);
|
|
682
|
+
includeScript(altAgentUrl, pendo, config.pendoGlobalKey);
|
|
683
683
|
return true;
|
|
684
684
|
}
|
|
685
685
|
}
|
|
@@ -688,11 +688,16 @@ function loadUnminifiedAgent(config, pendo, debuggingEnabled) {
|
|
|
688
688
|
function loadAlternateAgent(config, pendo, debuggingEnabled) {
|
|
689
689
|
return loadStagingAgent(config, pendo, debuggingEnabled) || loadUnminifiedAgent(config, pendo, debuggingEnabled);
|
|
690
690
|
}
|
|
691
|
-
function includeScript(scriptUrl, pendo) {
|
|
691
|
+
function includeScript(scriptUrl, pendo, globalKey) {
|
|
692
692
|
var scriptTagName = 'script';
|
|
693
693
|
var stagingScriptTag = document.createElement(scriptTagName);
|
|
694
694
|
stagingScriptTag.async = true;
|
|
695
695
|
stagingScriptTag.src = getPolicy(pendo).createScriptURL(scriptUrl);
|
|
696
|
+
// The alternate agent reads its global key from its own script tag, and its
|
|
697
|
+
// bundled PendoConfig doesn't carry the key the snippet set.
|
|
698
|
+
if (globalKey) {
|
|
699
|
+
stagingScriptTag.setAttribute('data-pendo-global-key', globalKey);
|
|
700
|
+
}
|
|
696
701
|
var otherScriptTag = document.getElementsByTagName(scriptTagName)[0];
|
|
697
702
|
if (otherScriptTag && otherScriptTag.parentNode) {
|
|
698
703
|
otherScriptTag.parentNode.insertBefore(stagingScriptTag, otherScriptTag);
|
|
@@ -3266,9 +3271,9 @@ var ConfigReader = (function () {
|
|
|
3266
3271
|
*/
|
|
3267
3272
|
addOption('selfHostedWebSDKUrl', [SNIPPET_SRC, PENDO_CONFIG_SRC], undefined, undefined, ['selfHostedAgentUrl']);
|
|
3268
3273
|
/**
|
|
3269
|
-
* If this option is set to true, event data
|
|
3270
|
-
* of first trying to use GET requests.
|
|
3271
|
-
* is transmitted.
|
|
3274
|
+
* If this option is set to true, event data, guide requests, and segment flag requests will only be
|
|
3275
|
+
* transmitted using requests of type POST instead of first trying to use GET requests. For event data, this
|
|
3276
|
+
* can result in fewer requests being sent each time that event data is transmitted.
|
|
3272
3277
|
*
|
|
3273
3278
|
* @access public
|
|
3274
3279
|
* @category Config/Core
|
|
@@ -4009,6 +4014,9 @@ function shouldWrapHashChange() {
|
|
|
4009
4014
|
function isMobileUserAgent() {
|
|
4010
4015
|
return (/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i).test(getUA());
|
|
4011
4016
|
}
|
|
4017
|
+
function supportsPopover() {
|
|
4018
|
+
return !!window.HTMLElement && isNativeCode(window.HTMLElement.prototype.showPopover);
|
|
4019
|
+
}
|
|
4012
4020
|
function isSafari(userAgent = getUA()) {
|
|
4013
4021
|
return userAgent.indexOf('Safari') >= 0 && !isChromium(userAgent);
|
|
4014
4022
|
}
|
|
@@ -4021,6 +4029,7 @@ function isChromium(userAgent = getUA()) {
|
|
|
4021
4029
|
const sniffer = {
|
|
4022
4030
|
supportsHistoryApi: shouldWrapNativeHistory,
|
|
4023
4031
|
supportsHashChange: shouldWrapHashChange,
|
|
4032
|
+
supportsPopover,
|
|
4024
4033
|
hasEvent(event) {
|
|
4025
4034
|
// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
|
|
4026
4035
|
// it. In particular the event is not fired when backspace or delete key are pressed or
|
|
@@ -4129,8 +4138,8 @@ let SERVER = '';
|
|
|
4129
4138
|
let ASSET_HOST = '';
|
|
4130
4139
|
let ASSET_PATH = '';
|
|
4131
4140
|
let DESIGNER_SERVER = '';
|
|
4132
|
-
let VERSION = '2.
|
|
4133
|
-
let PACKAGE_VERSION = '2.
|
|
4141
|
+
let VERSION = '2.347.0_';
|
|
4142
|
+
let PACKAGE_VERSION = '2.347.0';
|
|
4134
4143
|
let LOADER = 'xhr';
|
|
4135
4144
|
/* eslint-enable web-sdk-eslint-rules/no-gulp-env-references */
|
|
4136
4145
|
/**
|
|
@@ -13123,7 +13132,7 @@ function isDebuggingEnabled(asBoolean = true) {
|
|
|
13123
13132
|
}
|
|
13124
13133
|
}
|
|
13125
13134
|
|
|
13126
|
-
const
|
|
13135
|
+
const PERFORMANCE_COLLECT_INTERVAL = 1000 * 60 * 10; // 10 minutes
|
|
13127
13136
|
class PerformanceMonitor {
|
|
13128
13137
|
constructor() {
|
|
13129
13138
|
this._isPerformanceApiAvailable = this._checkPerformanceApi();
|
|
@@ -13131,6 +13140,8 @@ class PerformanceMonitor {
|
|
|
13131
13140
|
this._measuringPerformance = false;
|
|
13132
13141
|
this._debugging = false;
|
|
13133
13142
|
this._setDebuggingBound = _.bind(this._setDebugging, this);
|
|
13143
|
+
this._sendBound = _.bind(this.send, this);
|
|
13144
|
+
this._totals = {};
|
|
13134
13145
|
this.marks = new Set();
|
|
13135
13146
|
this.measures = new Set();
|
|
13136
13147
|
}
|
|
@@ -13141,12 +13152,13 @@ class PerformanceMonitor {
|
|
|
13141
13152
|
this._markPerformance(INITIALIZE);
|
|
13142
13153
|
this._setDebugging();
|
|
13143
13154
|
Events.debuggerLaunched.on(this._setDebuggingBound);
|
|
13155
|
+
Events.appUnloaded.on(this._sendBound);
|
|
13144
13156
|
const shouldSend = Math.random() * 100 < ConfigReader.get('performanceMetricsSampleRate');
|
|
13145
13157
|
this._setSending(shouldSend);
|
|
13146
13158
|
// interval always runs to periodically free memory used by performance api
|
|
13147
13159
|
this.interval = setInterval(() => {
|
|
13148
|
-
this.
|
|
13149
|
-
},
|
|
13160
|
+
this._collect();
|
|
13161
|
+
}, PERFORMANCE_COLLECT_INTERVAL);
|
|
13150
13162
|
return () => {
|
|
13151
13163
|
this.teardown();
|
|
13152
13164
|
};
|
|
@@ -13157,6 +13169,7 @@ class PerformanceMonitor {
|
|
|
13157
13169
|
this._measuringPerformance = false;
|
|
13158
13170
|
this._setDebugging();
|
|
13159
13171
|
Events.debuggerLaunched.off(this._setDebuggingBound);
|
|
13172
|
+
Events.appUnloaded.off(this._sendBound);
|
|
13160
13173
|
this._clearMarksAndMeasures();
|
|
13161
13174
|
clearInterval(this.interval);
|
|
13162
13175
|
}
|
|
@@ -13176,25 +13189,41 @@ class PerformanceMonitor {
|
|
|
13176
13189
|
this._markPerformance(name, { detail });
|
|
13177
13190
|
}
|
|
13178
13191
|
send() {
|
|
13179
|
-
|
|
13180
|
-
|
|
13181
|
-
|
|
13182
|
-
|
|
13183
|
-
|
|
13184
|
-
|
|
13185
|
-
|
|
13186
|
-
|
|
13187
|
-
|
|
13188
|
-
|
|
13189
|
-
|
|
13190
|
-
|
|
13191
|
-
});
|
|
13192
|
+
// runs in the appUnloaded handler ahead of the agent's event flush, so it must not throw
|
|
13193
|
+
try {
|
|
13194
|
+
this._collect();
|
|
13195
|
+
const payload = _.map(this._totals, (value, name) => ({
|
|
13196
|
+
name,
|
|
13197
|
+
type: METRICS[name].type,
|
|
13198
|
+
value,
|
|
13199
|
+
timestamp: Date.now()
|
|
13200
|
+
}));
|
|
13201
|
+
this._totals = {};
|
|
13202
|
+
if (_.size(payload) && this._sending) {
|
|
13203
|
+
writeMetricsPOST(payload);
|
|
13192
13204
|
}
|
|
13193
|
-
|
|
13194
|
-
|
|
13195
|
-
|
|
13196
|
-
|
|
13197
|
-
|
|
13205
|
+
}
|
|
13206
|
+
catch (e) {
|
|
13207
|
+
log.debug(`Failed to send performance metrics: ${e}`);
|
|
13208
|
+
}
|
|
13209
|
+
}
|
|
13210
|
+
_collect() {
|
|
13211
|
+
if (!this._isPerformanceApiAvailable)
|
|
13212
|
+
return;
|
|
13213
|
+
try {
|
|
13214
|
+
if (!this._sending)
|
|
13215
|
+
return;
|
|
13216
|
+
_.each(METRICS, ({ name, instrument }) => {
|
|
13217
|
+
if (!instrument)
|
|
13218
|
+
return;
|
|
13219
|
+
const value = instrument(performance.getEntriesByName(name));
|
|
13220
|
+
if (value > 0) {
|
|
13221
|
+
this._totals[name] = (this._totals[name] || 0) + value;
|
|
13222
|
+
}
|
|
13223
|
+
});
|
|
13224
|
+
}
|
|
13225
|
+
finally {
|
|
13226
|
+
this._clearMarksAndMeasures();
|
|
13198
13227
|
}
|
|
13199
13228
|
}
|
|
13200
13229
|
_checkPerformanceApi() {
|
|
@@ -13442,6 +13471,9 @@ function filterSiloCapacity(options) {
|
|
|
13442
13471
|
};
|
|
13443
13472
|
}
|
|
13444
13473
|
var URL_MAX_LENGTH = 2000;
|
|
13474
|
+
function shouldLoadWithPost(url, jwtOptions) {
|
|
13475
|
+
return url.length > URL_MAX_LENGTH || !_.isEmpty(jwtOptions) || !!ConfigReader.get('sendEventsWithPostOnly');
|
|
13476
|
+
}
|
|
13445
13477
|
function shortenUrlFields(options) {
|
|
13446
13478
|
options = _.defaults(options || {}, {
|
|
13447
13479
|
fields: [],
|
|
@@ -23855,6 +23887,78 @@ var backdropVisibilityStep = {
|
|
|
23855
23887
|
script: backdropVisibilityRuntimeScript
|
|
23856
23888
|
};
|
|
23857
23889
|
|
|
23890
|
+
// ":modal" also matches a fullscreen element, which cannot take children
|
|
23891
|
+
const MODAL_DIALOG = 'dialog:modal';
|
|
23892
|
+
function queryModalDialogs() {
|
|
23893
|
+
try {
|
|
23894
|
+
return document.querySelectorAll(MODAL_DIALOG);
|
|
23895
|
+
}
|
|
23896
|
+
catch (e) {
|
|
23897
|
+
return [];
|
|
23898
|
+
}
|
|
23899
|
+
}
|
|
23900
|
+
function closestModalDialog(element) {
|
|
23901
|
+
try {
|
|
23902
|
+
return element && _.isFunction(element.closest) ? element.closest(MODAL_DIALOG) : null;
|
|
23903
|
+
}
|
|
23904
|
+
catch (e) {
|
|
23905
|
+
return null;
|
|
23906
|
+
}
|
|
23907
|
+
}
|
|
23908
|
+
function queryConfiguredSelector(step) {
|
|
23909
|
+
const selector = _.get(step, 'attributes.popover.selector');
|
|
23910
|
+
if (!selector)
|
|
23911
|
+
return null;
|
|
23912
|
+
try {
|
|
23913
|
+
return dom(selector)[0] || null;
|
|
23914
|
+
}
|
|
23915
|
+
catch (e) {
|
|
23916
|
+
log.info('Invalid popover selector', { contexts: ['error', 'guide', 'render'] });
|
|
23917
|
+
return null;
|
|
23918
|
+
}
|
|
23919
|
+
}
|
|
23920
|
+
function findHost(step) {
|
|
23921
|
+
const host = queryConfiguredSelector(step) ||
|
|
23922
|
+
closestModalDialog(step.targetElement) ||
|
|
23923
|
+
_.last(queryModalDialogs());
|
|
23924
|
+
// a host inside a shadow root would change the guide's root node
|
|
23925
|
+
return host && host.getRootNode() === document ? host : null;
|
|
23926
|
+
}
|
|
23927
|
+
function promoteToPopover(element) {
|
|
23928
|
+
element.setAttribute('popover', 'manual');
|
|
23929
|
+
try {
|
|
23930
|
+
element.showPopover();
|
|
23931
|
+
}
|
|
23932
|
+
catch (e) {
|
|
23933
|
+
element.removeAttribute('popover');
|
|
23934
|
+
log.info('Failed to render guide as popover', { contexts: ['error', 'guide', 'render'] });
|
|
23935
|
+
}
|
|
23936
|
+
}
|
|
23937
|
+
// Registered ahead of backdrop-visibility-step and autofocus-step, which mark the siblings of the
|
|
23938
|
+
// guide's ancestors: the guide must already be inside the dialog or the dialog ends up hidden.
|
|
23939
|
+
function popoverRuntimeScript(step, guide, pendo) {
|
|
23940
|
+
if (pendo.designer || !step.guideElement)
|
|
23941
|
+
return;
|
|
23942
|
+
if (!_.get(step, 'attributes.popover.enabled') || !sniffer.supportsPopover())
|
|
23943
|
+
return;
|
|
23944
|
+
if (_.get(guide, 'attributes.resourceCenter') || _.get(guide, 'attributes.embedConfig'))
|
|
23945
|
+
return;
|
|
23946
|
+
const guideContainer = step.guideElement.find(`#${step.containerId}`);
|
|
23947
|
+
if (!guideContainer.length)
|
|
23948
|
+
return;
|
|
23949
|
+
// positioned in document coordinates, which a fixed root in the top layer breaks
|
|
23950
|
+
if (guideContainer.attr('data-vertical-alignment') === 'Relative to Element')
|
|
23951
|
+
return;
|
|
23952
|
+
const host = findHost(step);
|
|
23953
|
+
if (!host)
|
|
23954
|
+
return;
|
|
23955
|
+
host.appendChild(step.guideElement[0]);
|
|
23956
|
+
promoteToPopover(step.guideElement[0]);
|
|
23957
|
+
}
|
|
23958
|
+
var popoverStep = {
|
|
23959
|
+
script: popoverRuntimeScript
|
|
23960
|
+
};
|
|
23961
|
+
|
|
23858
23962
|
function isTooltip({ _ }, step) {
|
|
23859
23963
|
const tooltip = 'tooltip';
|
|
23860
23964
|
return _.get(step, 'attributes.calculatedType') === tooltip ||
|
|
@@ -24011,6 +24115,7 @@ function registerPostrenderScripts(runtime) {
|
|
|
24011
24115
|
_.each([
|
|
24012
24116
|
advanceOnElement,
|
|
24013
24117
|
announcementMarkSeen,
|
|
24118
|
+
popoverStep,
|
|
24014
24119
|
autofocusStep,
|
|
24015
24120
|
backdropVisibilityStep,
|
|
24016
24121
|
repositionOnScroll,
|
|
@@ -25113,7 +25218,7 @@ var loadGuideJs = function (apiKey, params) {
|
|
|
25113
25218
|
var url = buildBaseDataUrl(guideLoaderImpl.endpoint(), apiKey, queryString);
|
|
25114
25219
|
var jwtOptions = JWT.get();
|
|
25115
25220
|
let loadingPromise;
|
|
25116
|
-
if (url
|
|
25221
|
+
if (shouldLoadWithPost(url, jwtOptions)) {
|
|
25117
25222
|
delete queryString.jzb;
|
|
25118
25223
|
url = buildBaseDataUrl('guide.json', apiKey, queryString);
|
|
25119
25224
|
var payload = _.extend({ events: jzb }, jwtOptions);
|
|
@@ -25966,8 +26071,14 @@ var MESSAGE_ENDED = 'pendo-live-preview::ended';
|
|
|
25966
26071
|
var MESSAGE_END_ACK = 'pendo-live-preview::end-ack';
|
|
25967
26072
|
var RELAY_END_MESSAGE_TIMEOUT = 2000;
|
|
25968
26073
|
var activeRelay = null;
|
|
26074
|
+
// event.source alone is not enough: an ancestor page can navigate the relay frame to its own
|
|
26075
|
+
// document and keep the same window object, so the sender's origin has to be the relay's too.
|
|
26076
|
+
// An unknown relay origin ('*') cannot be matched, so it never authenticates a message.
|
|
25969
26077
|
function isRelayMessage(event, relay) {
|
|
25970
|
-
return
|
|
26078
|
+
return relay.origin !== '*' &&
|
|
26079
|
+
event.origin === relay.origin &&
|
|
26080
|
+
event.source === relay.frame.contentWindow &&
|
|
26081
|
+
!!event.data;
|
|
25971
26082
|
}
|
|
25972
26083
|
function sendConfig(relay) {
|
|
25973
26084
|
if (!relay.frame.contentWindow)
|
|
@@ -28502,7 +28613,8 @@ class NetworkRequestIntercept {
|
|
|
28502
28613
|
return MAX_RESPONSE_SIZE_MESSAGE;
|
|
28503
28614
|
}
|
|
28504
28615
|
}
|
|
28505
|
-
const
|
|
28616
|
+
const canStream = config.body && _.isFunction(config.body.getReader) && typeof TextDecoder !== 'undefined';
|
|
28617
|
+
const text = canStream ? yield this.readBodyStream(config.body) : yield config.text();
|
|
28506
28618
|
if (text.length > MAX_RESPONSE_SIZE) {
|
|
28507
28619
|
return MAX_RESPONSE_SIZE_MESSAGE;
|
|
28508
28620
|
}
|
|
@@ -28513,6 +28625,26 @@ class NetworkRequestIntercept {
|
|
|
28513
28625
|
}
|
|
28514
28626
|
});
|
|
28515
28627
|
}
|
|
28628
|
+
// Reads chunk by chunk so a long or never-ending stream stops buffering once it passes the cap
|
|
28629
|
+
readBodyStream(body) {
|
|
28630
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28631
|
+
const reader = body.getReader();
|
|
28632
|
+
const decoder = new TextDecoder();
|
|
28633
|
+
let text = '';
|
|
28634
|
+
let bytesRead = 0;
|
|
28635
|
+
let chunk = yield reader.read();
|
|
28636
|
+
while (!chunk.done) {
|
|
28637
|
+
bytesRead += chunk.value.byteLength;
|
|
28638
|
+
if (bytesRead > MAX_RESPONSE_SIZE) {
|
|
28639
|
+
reader.cancel().catch(_.noop);
|
|
28640
|
+
return MAX_RESPONSE_SIZE_MESSAGE;
|
|
28641
|
+
}
|
|
28642
|
+
text += decoder.decode(chunk.value, { stream: true });
|
|
28643
|
+
chunk = yield reader.read();
|
|
28644
|
+
}
|
|
28645
|
+
return text + decoder.decode();
|
|
28646
|
+
});
|
|
28647
|
+
}
|
|
28516
28648
|
extractConfigHeaders(config) {
|
|
28517
28649
|
let headers = {};
|
|
28518
28650
|
if (config.headers) {
|
|
@@ -28585,33 +28717,7 @@ class NetworkRequestIntercept {
|
|
|
28585
28717
|
// Make the actual fetch call and capture response
|
|
28586
28718
|
try {
|
|
28587
28719
|
const res = yield networkInterceptor._originalFetch.apply(this, args);
|
|
28588
|
-
|
|
28589
|
-
const responseClone = res.clone();
|
|
28590
|
-
try {
|
|
28591
|
-
// Capture response data
|
|
28592
|
-
const responseBody = yield networkInterceptor.safelyReadBody(responseClone, 'response');
|
|
28593
|
-
const { status, statusText } = res;
|
|
28594
|
-
const headers = networkInterceptor.extractConfigHeaders(res);
|
|
28595
|
-
_.each(networkInterceptor.callbackFns, ({ response }) => {
|
|
28596
|
-
if (_.isFunction(response)) {
|
|
28597
|
-
response({
|
|
28598
|
-
requestId,
|
|
28599
|
-
status,
|
|
28600
|
-
statusText,
|
|
28601
|
-
body: responseBody,
|
|
28602
|
-
headers,
|
|
28603
|
-
url: transformedUrl,
|
|
28604
|
-
method
|
|
28605
|
-
});
|
|
28606
|
-
}
|
|
28607
|
-
});
|
|
28608
|
-
}
|
|
28609
|
-
catch (e) {
|
|
28610
|
-
_.each(networkInterceptor.callbackFns, ({ error }) => {
|
|
28611
|
-
if (_.isFunction(error))
|
|
28612
|
-
error({ context: 'fetchResponse', error: e });
|
|
28613
|
-
});
|
|
28614
|
-
}
|
|
28720
|
+
networkInterceptor.captureResponse(res, { requestId, url: transformedUrl, method });
|
|
28615
28721
|
return res;
|
|
28616
28722
|
}
|
|
28617
28723
|
catch (error) {
|
|
@@ -28635,6 +28741,29 @@ class NetworkRequestIntercept {
|
|
|
28635
28741
|
});
|
|
28636
28742
|
};
|
|
28637
28743
|
}
|
|
28744
|
+
// Not awaited by the fetch wrapper: the app gets its response before the body is read
|
|
28745
|
+
captureResponse(res, { requestId, url, method }) {
|
|
28746
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28747
|
+
try {
|
|
28748
|
+
// Clone synchronously, before the app can consume the body
|
|
28749
|
+
const responseClone = res.clone();
|
|
28750
|
+
const body = yield this.safelyReadBody(responseClone, 'response');
|
|
28751
|
+
const { status, statusText } = res;
|
|
28752
|
+
const headers = this.extractConfigHeaders(res);
|
|
28753
|
+
_.each(this.callbackFns, ({ response }) => {
|
|
28754
|
+
if (_.isFunction(response)) {
|
|
28755
|
+
response({ requestId, status, statusText, body, headers, url, method });
|
|
28756
|
+
}
|
|
28757
|
+
});
|
|
28758
|
+
}
|
|
28759
|
+
catch (e) {
|
|
28760
|
+
_.each(this.callbackFns, ({ error }) => {
|
|
28761
|
+
if (_.isFunction(error))
|
|
28762
|
+
error({ context: 'fetchResponse', error: e });
|
|
28763
|
+
});
|
|
28764
|
+
}
|
|
28765
|
+
});
|
|
28766
|
+
}
|
|
28638
28767
|
patchXHR() {
|
|
28639
28768
|
const networkInterceptor = this;
|
|
28640
28769
|
networkInterceptor._originalSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
@@ -29638,7 +29767,8 @@ const PluginAPI = {
|
|
|
29638
29767
|
transmit: {
|
|
29639
29768
|
buildBaseDataUrl,
|
|
29640
29769
|
fetchKeepalive,
|
|
29641
|
-
sendBeacon
|
|
29770
|
+
sendBeacon,
|
|
29771
|
+
shouldLoadWithPost
|
|
29642
29772
|
},
|
|
29643
29773
|
log,
|
|
29644
29774
|
NetworkRequest,
|
|
@@ -33817,10 +33947,12 @@ function Poll(guide) {
|
|
|
33817
33947
|
_.each(responses, function (response, i) {
|
|
33818
33948
|
var curPoll = getPoll(response.pollId, guide);
|
|
33819
33949
|
var evt = createGuideEvent('pollResponse', step.guideId, step.id, get_visitor_id(), undefined, guide.language);
|
|
33950
|
+
// A behavior that replaces show() outright (HTML guides) drops the after('show')
|
|
33951
|
+
// hook above, so fall back to when the step was last seen.
|
|
33820
33952
|
_.extend(evt.props, {
|
|
33821
33953
|
poll_id: response.pollId,
|
|
33822
33954
|
poll_response: response.value,
|
|
33823
|
-
duration: (new Date().getTime() - shownTime)
|
|
33955
|
+
duration: (new Date().getTime() - (shownTime || step.lastSeenAt))
|
|
33824
33956
|
}, options);
|
|
33825
33957
|
if (curPoll &&
|
|
33826
33958
|
curPoll.attributes &&
|
|
@@ -37132,7 +37264,11 @@ var Branding = (function () {
|
|
|
37132
37264
|
return;
|
|
37133
37265
|
var guide = pendo.findGuideById(props.guide_id);
|
|
37134
37266
|
var guideContainer = guide.steps[0].guideElement[0].lastElementChild;
|
|
37135
|
-
var verticalAlignment = guideContainer.dataset.verticalAlignment;
|
|
37267
|
+
var verticalAlignment = guideContainer && guideContainer.dataset.verticalAlignment;
|
|
37268
|
+
// Only Visual Design Studio containers carry the alignment the badge is placed by;
|
|
37269
|
+
// an HTML guide's container has none.
|
|
37270
|
+
if (!verticalAlignment)
|
|
37271
|
+
return;
|
|
37136
37272
|
var isBottomAligned = verticalAlignment.indexOf('Bottom') > -1;
|
|
37137
37273
|
var isSetWidth = guideContainer.style.width !== '';
|
|
37138
37274
|
var link = document.createElement('a');
|
|
@@ -41066,7 +41202,7 @@ var buildLauncherItem = function (guide) {
|
|
|
41066
41202
|
dom(guideContainer).attr('id', 'launcher-' + guide.id);
|
|
41067
41203
|
var guideLink = document.createElement('a');
|
|
41068
41204
|
guideLink.href = '#';
|
|
41069
|
-
guideLink.
|
|
41205
|
+
guideLink.appendChild(document.createTextNode(guide.name));
|
|
41070
41206
|
guideContainer.appendChild(guideLink);
|
|
41071
41207
|
return guideContainer;
|
|
41072
41208
|
};
|
|
@@ -41752,7 +41888,7 @@ function SegmentFlags() {
|
|
|
41752
41888
|
const jwtOptions = pluginApi.agent.getJwtInfoCopy();
|
|
41753
41889
|
let payload;
|
|
41754
41890
|
try {
|
|
41755
|
-
if (
|
|
41891
|
+
if (pluginApi.transmit.shouldLoadWithPost(url, jwtOptions)) {
|
|
41756
41892
|
delete queryString.jzb;
|
|
41757
41893
|
url = pluginApi.transmit.buildBaseDataUrl('segmentflag.json', globalPendo.apiKey, queryString);
|
|
41758
41894
|
payload = globalPendo._.extend({ events: jzb }, jwtOptions);
|
|
@@ -42167,7 +42303,7 @@ class PromptPlugin {
|
|
|
42167
42303
|
});
|
|
42168
42304
|
const currentlyActiveIds = this._.map(this._.filter(this.prompts, prompt => prompt.isActive), prompt => prompt.id);
|
|
42169
42305
|
this._.each(allAgents, aiAgent => {
|
|
42170
|
-
if (this.isConversationAgent(aiAgent)) {
|
|
42306
|
+
if (this.isConversationAgent(aiAgent) || this.isNetworkAgent(aiAgent)) {
|
|
42171
42307
|
return;
|
|
42172
42308
|
}
|
|
42173
42309
|
const isCurrentlyActive = this._.contains(currentlyActiveIds, aiAgent.id);
|
|
@@ -42192,30 +42328,21 @@ class PromptPlugin {
|
|
|
42192
42328
|
isConversationAgent(agent) {
|
|
42193
42329
|
return agent.preset && agent.preset != 'chatgpt';
|
|
42194
42330
|
}
|
|
42331
|
+
// network tracking is not supported; these agents are ignored rather than falling back to DOM.
|
|
42332
|
+
isNetworkAgent(agent) {
|
|
42333
|
+
return agent.trackingMethod === 'network';
|
|
42334
|
+
}
|
|
42195
42335
|
onConfigLoaded(aiAgents = []) {
|
|
42196
42336
|
if (!aiAgents || !this._.isArray(aiAgents) || aiAgents.length === 0) {
|
|
42197
42337
|
return;
|
|
42198
42338
|
}
|
|
42199
|
-
const networkAgents = [];
|
|
42200
42339
|
const domAgents = [];
|
|
42201
42340
|
for (const agent of aiAgents) {
|
|
42202
|
-
if (this.isConversationAgent(agent)) {
|
|
42341
|
+
if (this.isConversationAgent(agent) || this.isNetworkAgent(agent)) {
|
|
42203
42342
|
continue;
|
|
42204
42343
|
}
|
|
42205
|
-
if
|
|
42206
|
-
|
|
42207
|
-
}
|
|
42208
|
-
else if (agent.trackingMethod === 'dom') {
|
|
42209
|
-
domAgents.push(agent);
|
|
42210
|
-
}
|
|
42211
|
-
else {
|
|
42212
|
-
// Default to DOM if no trackingMethod specified
|
|
42213
|
-
domAgents.push(agent);
|
|
42214
|
-
}
|
|
42215
|
-
}
|
|
42216
|
-
if (networkAgents.length > 0) {
|
|
42217
|
-
this.networkAgents = networkAgents;
|
|
42218
|
-
this.api.NetworkRequest.on({ request: this.handleRequest, error: this.handleError });
|
|
42344
|
+
// Default to DOM if no trackingMethod specified
|
|
42345
|
+
domAgents.push(agent);
|
|
42219
42346
|
}
|
|
42220
42347
|
// Cache agents for fast lookup
|
|
42221
42348
|
if (!this.agentsCache) {
|
|
@@ -42236,29 +42363,6 @@ class PromptPlugin {
|
|
|
42236
42363
|
}
|
|
42237
42364
|
});
|
|
42238
42365
|
}
|
|
42239
|
-
handleRequest({ method, url, body }) {
|
|
42240
|
-
const currentUrl = getNormalizedUrl();
|
|
42241
|
-
this._.each(this.networkAgents, aiAgent => {
|
|
42242
|
-
if (!this.testPageRule(aiAgent.pageRule, currentUrl, aiAgent.id)) {
|
|
42243
|
-
return;
|
|
42244
|
-
}
|
|
42245
|
-
const originalBody = body || '';
|
|
42246
|
-
this.api.analytics.collectEvent('prompt', {
|
|
42247
|
-
prompt: originalBody,
|
|
42248
|
-
agentId: aiAgent.id,
|
|
42249
|
-
promptType: method,
|
|
42250
|
-
url
|
|
42251
|
-
}, undefined, 'agentic');
|
|
42252
|
-
});
|
|
42253
|
-
}
|
|
42254
|
-
handleError({ error, context }) {
|
|
42255
|
-
if (context == 'fetch') {
|
|
42256
|
-
this.api.log.debug('[PromptPlugin] Fetch tracking failed:', error);
|
|
42257
|
-
}
|
|
42258
|
-
if (context == 'xhr') {
|
|
42259
|
-
this.api.log.debug('[PromptPlugin] XHR tracking failed:', error);
|
|
42260
|
-
}
|
|
42261
|
-
}
|
|
42262
42366
|
observePrompt(config) {
|
|
42263
42367
|
const { id, cssSelectors } = config;
|
|
42264
42368
|
// Check if agent already exists
|
|
@@ -42297,7 +42401,6 @@ class PromptPlugin {
|
|
|
42297
42401
|
if (this.agentsCache) {
|
|
42298
42402
|
this.agentsCache.clear();
|
|
42299
42403
|
}
|
|
42300
|
-
this.api.NetworkRequest.off({ request: this.handleRequest, error: this.handleError });
|
|
42301
42404
|
}
|
|
42302
42405
|
}
|
|
42303
42406
|
var PromptAnalytics = new PromptPlugin();
|
|
@@ -43650,6 +43753,13 @@ function encodeMetadataForUrl(value, urlBeforePlaceholder = '') {
|
|
|
43650
43753
|
}
|
|
43651
43754
|
return window.encodeURI(str);
|
|
43652
43755
|
}
|
|
43756
|
+
// Resolve through the browser's own URL parser: it strips tabs/newlines inside the scheme
|
|
43757
|
+
// (e.g. "java\tscript:"), which a regex over the raw string would miss.
|
|
43758
|
+
function hasDangerousUrlScheme(url) {
|
|
43759
|
+
const anchor = document.createElement('a');
|
|
43760
|
+
anchor.href = url;
|
|
43761
|
+
return DANGEROUS_URL_SCHEME.test(anchor.protocol);
|
|
43762
|
+
}
|
|
43653
43763
|
|
|
43654
43764
|
const MetadataSubstitution = {
|
|
43655
43765
|
name: 'MetadataSubstitution',
|
|
@@ -43736,27 +43846,37 @@ function processPlaceholder(placeholder, pendo) {
|
|
|
43736
43846
|
let match;
|
|
43737
43847
|
const { data, target } = placeholder;
|
|
43738
43848
|
const subRegex = new RegExp(guideMarkdownUtil.substitutionRegex);
|
|
43849
|
+
const isUrlTarget = target === 'href' || target === 'value';
|
|
43850
|
+
const startedWithDangerousScheme = isUrlTarget && hasDangerousUrlScheme(getRawTargetValue(data, target));
|
|
43739
43851
|
while ((match = matchPlaceholder(placeholder, subRegex))) {
|
|
43740
43852
|
const usedArrayPath = Array.isArray(match) && match.length >= 2;
|
|
43741
43853
|
const currentStr = target === 'textContent'
|
|
43742
43854
|
? data[target]
|
|
43743
|
-
: decodeURI((data
|
|
43855
|
+
: decodeURI(getRawTargetValue(data, target));
|
|
43744
43856
|
const matched = usedArrayPath ? match : subRegex.exec(currentStr);
|
|
43745
43857
|
if (!matched)
|
|
43746
43858
|
continue;
|
|
43747
43859
|
const mdValue = getSubstituteValue(matched, pendo);
|
|
43748
43860
|
substituteMetadataByTarget(data, target, mdValue, matched);
|
|
43861
|
+
// Substituted values can carry new placeholders into the next pass, so a dangerous
|
|
43862
|
+
// scheme can be assembled across passes. Check the whole URL, not each fragment.
|
|
43863
|
+
if (isUrlTarget && !startedWithDangerousScheme && hasDangerousUrlScheme(getRawTargetValue(data, target))) {
|
|
43864
|
+
data[target] = '';
|
|
43865
|
+
return;
|
|
43866
|
+
}
|
|
43749
43867
|
}
|
|
43750
43868
|
}
|
|
43869
|
+
function getRawTargetValue(data, target) {
|
|
43870
|
+
return data.getAttribute && (target === 'href' || target === 'value')
|
|
43871
|
+
? (data.getAttribute(target) || '')
|
|
43872
|
+
: data[target];
|
|
43873
|
+
}
|
|
43751
43874
|
function matchPlaceholder(placeholder, regex) {
|
|
43752
43875
|
if (placeholder.target === 'textContent') {
|
|
43753
43876
|
return placeholder.data[placeholder.target].match(regex);
|
|
43754
43877
|
}
|
|
43755
43878
|
else {
|
|
43756
|
-
|
|
43757
|
-
? (placeholder.data.getAttribute(placeholder.target) || '')
|
|
43758
|
-
: placeholder.data[placeholder.target];
|
|
43759
|
-
return decodeURI(raw).match(regex);
|
|
43879
|
+
return decodeURI(getRawTargetValue(placeholder.data, placeholder.target)).match(regex);
|
|
43760
43880
|
}
|
|
43761
43881
|
}
|
|
43762
43882
|
function getMetadataValueCaseInsensitive(metadata, type, property) {
|
|
@@ -48001,7 +48121,7 @@ function serializeNodeWithId(n, options) {
|
|
|
48001
48121
|
if (parent && isShadowRoot(parent) && isNativeShadowDom(parent)) {
|
|
48002
48122
|
serializedNode.isShadow = true;
|
|
48003
48123
|
}
|
|
48004
|
-
if (serializedNode.type === NodeType.Element && serializedNode.tagName === "iframe") {
|
|
48124
|
+
if (serializedNode.type === NodeType.Element && serializedNode.tagName === "iframe" && !_isBlockedElement(n, blockClass, blockSelector)) {
|
|
48005
48125
|
onceIframeLoaded(
|
|
48006
48126
|
n,
|
|
48007
48127
|
() => {
|
|
@@ -50151,11 +50271,15 @@ class IframeManager {
|
|
|
50151
50271
|
__publicField(this, "pageHideListener");
|
|
50152
50272
|
__publicField(this, "stylesheetManager");
|
|
50153
50273
|
__publicField(this, "recordCrossOriginIframes");
|
|
50274
|
+
__publicField(this, "blockClass");
|
|
50275
|
+
__publicField(this, "blockSelector");
|
|
50154
50276
|
this.mutationCb = options.mutationCb;
|
|
50155
50277
|
this.wrappedEmit = options.wrappedEmit;
|
|
50156
50278
|
this.takeFullSnapshot = options.takeFullSnapshot;
|
|
50157
50279
|
this.stylesheetManager = options.stylesheetManager;
|
|
50158
50280
|
this.recordCrossOriginIframes = options.recordCrossOriginIframes;
|
|
50281
|
+
this.blockClass = options.blockClass;
|
|
50282
|
+
this.blockSelector = options.blockSelector;
|
|
50159
50283
|
this.crossOriginIframeStyleMirror = new CrossOriginIframeMirror(
|
|
50160
50284
|
this.stylesheetManager.styleMirror.generateId.bind(
|
|
50161
50285
|
this.stylesheetManager.styleMirror
|
|
@@ -50170,6 +50294,7 @@ class IframeManager {
|
|
|
50170
50294
|
this.takeFullSnapshot = takeFullSnapshot2;
|
|
50171
50295
|
}
|
|
50172
50296
|
addIframe(iframeEl) {
|
|
50297
|
+
if (isBlocked(iframeEl, this.blockClass, this.blockSelector, false)) return;
|
|
50173
50298
|
this.iframes.set(iframeEl, true);
|
|
50174
50299
|
if (iframeEl.contentWindow)
|
|
50175
50300
|
this.crossOriginIframeMap.set(iframeEl.contentWindow, iframeEl);
|
|
@@ -51294,6 +51419,8 @@ function record(options = {}) {
|
|
|
51294
51419
|
mutationCb: wrappedMutationEmit,
|
|
51295
51420
|
stylesheetManager,
|
|
51296
51421
|
recordCrossOriginIframes,
|
|
51422
|
+
blockClass,
|
|
51423
|
+
blockSelector,
|
|
51297
51424
|
wrappedEmit,
|
|
51298
51425
|
takeFullSnapshot
|
|
51299
51426
|
});
|
|
@@ -53413,6 +53540,7 @@ function createReplayPlugin() {
|
|
|
53413
53540
|
/**
|
|
53414
53541
|
* limit of number of keys in an object
|
|
53415
53542
|
* if an object contains more keys than this limit, we would call its toString function directly
|
|
53543
|
+
* arrays longer than this limit are cut down to their first NUM_OF_KEYS_LIMIT elements
|
|
53416
53544
|
*/
|
|
53417
53545
|
const NUM_OF_KEYS_LIMIT = 50;
|
|
53418
53546
|
/**
|
|
@@ -53484,8 +53612,9 @@ function shouldIgnore(_obj) {
|
|
|
53484
53612
|
/**
|
|
53485
53613
|
* stringify any argument
|
|
53486
53614
|
* @param arg - the arg to stringify
|
|
53615
|
+
* @param maxLength - stop serializing once this many characters have been visited
|
|
53487
53616
|
*/
|
|
53488
|
-
function stringify(arg) {
|
|
53617
|
+
function stringify(arg, maxLength = Infinity) {
|
|
53489
53618
|
if (arg === undefined)
|
|
53490
53619
|
return 'undefined';
|
|
53491
53620
|
// Handle primitives
|
|
@@ -53496,11 +53625,19 @@ function stringify(arg) {
|
|
|
53496
53625
|
return arg.toString();
|
|
53497
53626
|
return String(arg);
|
|
53498
53627
|
}
|
|
53628
|
+
let charsVisited = 0;
|
|
53499
53629
|
return JSON.stringify(arg, function (key, value) {
|
|
53630
|
+
if (charsVisited > maxLength)
|
|
53631
|
+
return '';
|
|
53632
|
+
const valueLength = typeof value === 'string' ? value.length : 0;
|
|
53633
|
+
charsVisited += key.length + valueLength;
|
|
53500
53634
|
if (value === null)
|
|
53501
53635
|
return value;
|
|
53502
53636
|
if (value === undefined)
|
|
53503
53637
|
return 'undefined';
|
|
53638
|
+
if (Array.isArray(value) && value.length > NUM_OF_KEYS_LIMIT) {
|
|
53639
|
+
return value.slice(0, NUM_OF_KEYS_LIMIT);
|
|
53640
|
+
}
|
|
53504
53641
|
// Handle objects
|
|
53505
53642
|
if (shouldIgnore(value)) {
|
|
53506
53643
|
return value.toString ? value.toString() : '[object Object]';
|
|
@@ -54127,8 +54264,11 @@ function ConsoleCapture() {
|
|
|
54127
54264
|
let isRecordingActive = false;
|
|
54128
54265
|
const CAPTURE_CONSOLE_CONFIG = 'captureConsoleLogs';
|
|
54129
54266
|
const ALWAYS_CAPTURE_ERRORS_CONFIG = 'alwaysCaptureDevLogErrors';
|
|
54267
|
+
const CONSOLE_LOG_LEVELS_CONFIG = 'consoleLogLevels';
|
|
54130
54268
|
const CONSOLE_METHODS = ['log', 'warn', 'error', 'info'];
|
|
54131
54269
|
const DEV_LOG_SUB_TYPE = 'console';
|
|
54270
|
+
const DEFAULT_CONSOLE_LOG_LEVELS = ['error', 'warn', 'info'];
|
|
54271
|
+
let consoleLogLevels = DEFAULT_CONSOLE_LOG_LEVELS;
|
|
54132
54272
|
// deduplicate logs
|
|
54133
54273
|
let lastLogKey = '';
|
|
54134
54274
|
return {
|
|
@@ -54147,6 +54287,8 @@ function ConsoleCapture() {
|
|
|
54147
54287
|
onPtmPaused,
|
|
54148
54288
|
onPtmUnpaused,
|
|
54149
54289
|
securityPolicyViolationFn,
|
|
54290
|
+
uncaughtErrorFn,
|
|
54291
|
+
unhandledRejectionFn,
|
|
54150
54292
|
get isCapturingConsoleLogs() {
|
|
54151
54293
|
return isCapturingConsoleLogs;
|
|
54152
54294
|
},
|
|
@@ -54166,10 +54308,12 @@ function ConsoleCapture() {
|
|
|
54166
54308
|
const { ConfigReader } = pluginAPI;
|
|
54167
54309
|
ConfigReader.addOption(CAPTURE_CONSOLE_CONFIG, [ConfigReader.sources.PENDO_CONFIG_SRC], false);
|
|
54168
54310
|
ConfigReader.addOption(ALWAYS_CAPTURE_ERRORS_CONFIG, [ConfigReader.sources.PENDO_CONFIG_SRC], false);
|
|
54311
|
+
ConfigReader.addOption(CONSOLE_LOG_LEVELS_CONFIG, [ConfigReader.sources.PENDO_CONFIG_SRC], DEFAULT_CONSOLE_LOG_LEVELS);
|
|
54169
54312
|
const captureConsoleEnabled = ConfigReader.get(CAPTURE_CONSOLE_CONFIG);
|
|
54170
54313
|
if (!captureConsoleEnabled)
|
|
54171
54314
|
return;
|
|
54172
54315
|
alwaysCaptureErrors = !!ConfigReader.get(ALWAYS_CAPTURE_ERRORS_CONFIG);
|
|
54316
|
+
consoleLogLevels = ConfigReader.get(CONSOLE_LOG_LEVELS_CONFIG);
|
|
54173
54317
|
globalPendo = pendo;
|
|
54174
54318
|
buffer = new DevlogBuffer(pendo, pluginAPI);
|
|
54175
54319
|
transport = new DevlogTransport(pendo, pluginAPI);
|
|
@@ -54230,6 +54374,8 @@ function ConsoleCapture() {
|
|
|
54230
54374
|
try {
|
|
54231
54375
|
addIntercepts();
|
|
54232
54376
|
pluginAPI.attachEventInternal(window, 'securitypolicyviolation', securityPolicyViolationFn);
|
|
54377
|
+
pluginAPI.attachEventInternal(window, 'error', uncaughtErrorFn);
|
|
54378
|
+
pluginAPI.attachEventInternal(window, 'unhandledrejection', unhandledRejectionFn);
|
|
54233
54379
|
}
|
|
54234
54380
|
catch (error) {
|
|
54235
54381
|
pluginAPI.log.error('Error setting up console capture intercepts: ', error);
|
|
@@ -54270,16 +54416,36 @@ function ConsoleCapture() {
|
|
|
54270
54416
|
createConsoleEvent([message], 'error', { skipStackTrace: true, skipScrubPII: true });
|
|
54271
54417
|
}
|
|
54272
54418
|
}
|
|
54419
|
+
function uncaughtErrorFn(evt) {
|
|
54420
|
+
if (!evt || typeof evt !== 'object')
|
|
54421
|
+
return;
|
|
54422
|
+
const rawMessage = evt.message || (evt.error && String(evt.error));
|
|
54423
|
+
if (!rawMessage)
|
|
54424
|
+
return;
|
|
54425
|
+
const message = rawMessage.indexOf('Uncaught') === 0 ? rawMessage : `Uncaught ${rawMessage}`;
|
|
54426
|
+
const stackTrace = evt.error && evt.error.stack;
|
|
54427
|
+
createConsoleEvent([stackTrace ? `${message}\n${stackTrace}` : message], 'error', { skipStackTrace: true });
|
|
54428
|
+
}
|
|
54429
|
+
function unhandledRejectionFn(evt) {
|
|
54430
|
+
if (!evt || typeof evt !== 'object')
|
|
54431
|
+
return;
|
|
54432
|
+
const { reason } = evt;
|
|
54433
|
+
const detail = reason && reason.stack ? reason.stack : reason;
|
|
54434
|
+
createConsoleEvent(['Uncaught (in promise)', detail], 'error', { skipStackTrace: true });
|
|
54435
|
+
}
|
|
54273
54436
|
function createConsoleEvent(args, methodName, { skipStackTrace = false, skipScrubPII = false } = {}) {
|
|
54274
54437
|
if (!isCapturingConsoleLogs || !args || args.length === 0 || !_.contains(CONSOLE_METHODS, methodName))
|
|
54275
54438
|
return;
|
|
54276
54439
|
if (isErrorOnlyCapture() && methodName !== 'error')
|
|
54277
54440
|
return;
|
|
54441
|
+
const devLogLevel = methodName === 'log' ? 'info' : methodName;
|
|
54442
|
+
if (!_.contains(consoleLogLevels, devLogLevel))
|
|
54443
|
+
return;
|
|
54278
54444
|
// stringify args
|
|
54279
54445
|
let message = _.compact(_.map(args, arg => {
|
|
54280
54446
|
let stringifiedArg;
|
|
54281
54447
|
try {
|
|
54282
|
-
stringifiedArg = stringify(arg);
|
|
54448
|
+
stringifiedArg = stringify(arg, MAX_LENGTH);
|
|
54283
54449
|
}
|
|
54284
54450
|
catch (error) {
|
|
54285
54451
|
pluginAPI.log.error('Error stringifying arg: ', error);
|
|
@@ -54303,10 +54469,10 @@ function ConsoleCapture() {
|
|
|
54303
54469
|
buffer.lastEvent.devLogCount++;
|
|
54304
54470
|
return;
|
|
54305
54471
|
}
|
|
54306
|
-
const devLogEnvelope = createDevLogEnvelope(pluginAPI, globalPendo);
|
|
54307
|
-
const consoleEvent = Object.assign(Object.assign({}, devLogEnvelope), { subType: DEV_LOG_SUB_TYPE, devLogLevel: methodName === 'log' ? 'info' : methodName, devLogMessage: skipScrubPII ? message : scrubPII({ string: message, _ }), devLogTrace: stackTrace, devLogCount: 1 });
|
|
54308
54472
|
if (!buffer.hasTokenAvailable())
|
|
54309
|
-
return
|
|
54473
|
+
return;
|
|
54474
|
+
const devLogEnvelope = createDevLogEnvelope(pluginAPI, globalPendo);
|
|
54475
|
+
const consoleEvent = Object.assign(Object.assign({}, devLogEnvelope), { subType: DEV_LOG_SUB_TYPE, devLogLevel, devLogMessage: skipScrubPII ? message : scrubPII({ string: message, _ }), devLogTrace: stackTrace, devLogCount: 1 });
|
|
54310
54476
|
if (!isPtmPaused) {
|
|
54311
54477
|
pluginAPI.Events.eventCaptured.trigger(consoleEvent);
|
|
54312
54478
|
}
|
|
@@ -54364,6 +54530,8 @@ function ConsoleCapture() {
|
|
|
54364
54530
|
pluginAPI.Events['recording:unpaused'].off(recordingStarted);
|
|
54365
54531
|
pluginAPI.Events['recording:paused'].off(recordingStopped);
|
|
54366
54532
|
pluginAPI.detachEventInternal(window, 'securitypolicyviolation', securityPolicyViolationFn);
|
|
54533
|
+
pluginAPI.detachEventInternal(window, 'error', uncaughtErrorFn);
|
|
54534
|
+
pluginAPI.detachEventInternal(window, 'unhandledrejection', unhandledRejectionFn);
|
|
54367
54535
|
_.each(CONSOLE_METHODS, function (methodName) {
|
|
54368
54536
|
if (!console[methodName])
|
|
54369
54537
|
return _.noop;
|