@pendo/agent 2.329.0 → 2.330.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dom.esm.js +9 -3
- package/dist/pendo.module.js +208 -331
- package/dist/pendo.module.min.js +10 -10
- package/dist/servers.json +7 -7
- package/package.json +1 -1
package/dist/pendo.module.js
CHANGED
|
@@ -3403,7 +3403,7 @@ var ConfigReader = (function () {
|
|
|
3403
3403
|
* cookies, localStorage, click tracking, and metadata. Only displays guides
|
|
3404
3404
|
* that have been configured explicitly to show to this visitor.
|
|
3405
3405
|
*
|
|
3406
|
-
* @access
|
|
3406
|
+
* @access public
|
|
3407
3407
|
* @category Config/Guides
|
|
3408
3408
|
* @name doNotTrackGuides
|
|
3409
3409
|
* @default false
|
|
@@ -4010,8 +4010,8 @@ let SERVER = '';
|
|
|
4010
4010
|
let ASSET_HOST = '';
|
|
4011
4011
|
let ASSET_PATH = '';
|
|
4012
4012
|
let DESIGNER_SERVER = '';
|
|
4013
|
-
let VERSION = '2.
|
|
4014
|
-
let PACKAGE_VERSION = '2.
|
|
4013
|
+
let VERSION = '2.330.1_';
|
|
4014
|
+
let PACKAGE_VERSION = '2.330.1';
|
|
4015
4015
|
let LOADER = 'xhr';
|
|
4016
4016
|
/* eslint-enable web-sdk-eslint-rules/no-gulp-env-references */
|
|
4017
4017
|
/**
|
|
@@ -4587,11 +4587,16 @@ function hasCookieDomain() {
|
|
|
4587
4587
|
return !!cookieDomain;
|
|
4588
4588
|
}
|
|
4589
4589
|
function clearCookie(name) {
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4590
|
+
// Always expire the cookie rather than overwriting it with an empty value.
|
|
4591
|
+
// When a cookieDomain is set the domain attribute must be included or the
|
|
4592
|
+
// domain-scoped cookie can't be matched for deletion -- omitting it (or
|
|
4593
|
+
// writing a blank value) leaves a permanent empty cookie that still costs
|
|
4594
|
+
// request-header space via its name.
|
|
4595
|
+
var cookie = name + '=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT';
|
|
4596
|
+
if (cookieDomain) {
|
|
4597
|
+
cookie += ';domain=' + cookieDomain;
|
|
4593
4598
|
}
|
|
4594
|
-
document.cookie =
|
|
4599
|
+
document.cookie = cookie;
|
|
4595
4600
|
}
|
|
4596
4601
|
var getPendoCookieKey = function (name, cookieSuffix) {
|
|
4597
4602
|
return `_pendo_${name}.${cookieSuffix || pendo$1.apiKey}`;
|
|
@@ -9750,7 +9755,11 @@ function exportDataHost(pendo) {
|
|
|
9750
9755
|
pendo.HOST = HOST;
|
|
9751
9756
|
}
|
|
9752
9757
|
function getAssetHost() {
|
|
9753
|
-
|
|
9758
|
+
var assetHost = ConfigReader.get('assetHost');
|
|
9759
|
+
if (assetHost) {
|
|
9760
|
+
return assetHost.indexOf('://') === -1 ? 'https://' + assetHost : assetHost;
|
|
9761
|
+
}
|
|
9762
|
+
return getContentHost();
|
|
9754
9763
|
}
|
|
9755
9764
|
function getContentHost() {
|
|
9756
9765
|
var protocol = 'https://';
|
|
@@ -11752,13 +11761,13 @@ function isTrustedOrigin(host) {
|
|
|
11752
11761
|
// Domains that Pendo owns, will be swapped in by build patches
|
|
11753
11762
|
const patterns = [
|
|
11754
11763
|
/^https:\/\/(adopt\.)?((us1)\.)?(app|via|adopt|cdn|oem|novus-api|novus)(\.(au|eu|gov|hsbc|jpn))?\.pendo\.io$/,
|
|
11755
|
-
/^https:\/\/([0-9]{8}t[0-9]{4}-dot-)pendo-
|
|
11756
|
-
/^https:\/\/hotfix-(ops|app)-([0-9]+-dot-)pendo-
|
|
11757
|
-
/^https:\/\/pendo-
|
|
11764
|
+
/^https:\/\/([0-9]{8}t[0-9]{4}-dot-)(pendo-au|pendo-eu|pendo-govramp|pendo-hsbc|pendo-io|pendo-jp-prod|pendo-us1)\.appspot\.com$/,
|
|
11765
|
+
/^https:\/\/hotfix-(ops|app)-([0-9]+-dot-)(pendo-au|pendo-eu|pendo-govramp|pendo-hsbc|pendo-io|pendo-jp-prod|pendo-us1)\.appspot\.com$/,
|
|
11766
|
+
/^https:\/\/(pendo-au|pendo-eu|pendo-govramp|pendo-hsbc|pendo-io|pendo-jp-prod|pendo-us1)-static\.storage\.googleapis\.com$/,
|
|
11758
11767
|
/^https:\/\/([a-zA-Z0-9-]+\.)*pendo-dev\.com$/,
|
|
11759
|
-
/^https:\/\/([a-zA-Z0-9-]+-dot-)?pendo-
|
|
11768
|
+
/^https:\/\/([a-zA-Z0-9-]+-dot-)?(pendo-apollo|pendo-armada|pendo-atlas|pendo-batman|pendo-calypso|pendo-dap|pendo-dev|pendo-dr-us-east1|pendo-eu-dev|pendo-freeze|pendo-helix|pendo-link|pendo-magic|pendo-mango|pendo-mcfly|pendo-ml|pendo-mobile-fbi|pendo-mobile-guides|pendo-mobile-hummus|pendo-mobile-plat|pendo-perfserf|pendo-voc|pendo-wildlings|pendo-ionchef|pendo-scrum-ops|pendo-security|pendo-test|pendo-uat|pendo-au|pendo-eu|pendo-govramp|pendo-hsbc|pendo-io|pendo-jp-prod|pendo-us1)\.appspot\.com$/,
|
|
11760
11769
|
/^https:\/\/(via|adopt|local)\.pendo\.(local|io):\d{4}$/,
|
|
11761
|
-
/^https:\/\/pendo-
|
|
11770
|
+
/^https:\/\/(pendo-apollo|pendo-armada|pendo-atlas|pendo-batman|pendo-calypso|pendo-dap|pendo-dev|pendo-dr-us-east1|pendo-eu-dev|pendo-freeze|pendo-helix|pendo-link|pendo-magic|pendo-mango|pendo-mcfly|pendo-ml|pendo-mobile-fbi|pendo-mobile-guides|pendo-mobile-hummus|pendo-mobile-plat|pendo-perfserf|pendo-voc|pendo-wildlings|pendo-ionchef|pendo-scrum-ops|pendo-security|pendo-test|pendo-uat)-static\.storage\.googleapis\.com$/
|
|
11762
11771
|
]; // eslint-disable-line web-sdk-eslint-rules/no-gulp-env-references
|
|
11763
11772
|
var adoptHost = ConfigReader.get('adoptHost');
|
|
11764
11773
|
if (adoptHost) {
|
|
@@ -11846,7 +11855,9 @@ var trustedOriginForLoadResource = function (origin) {
|
|
|
11846
11855
|
return isTrustedOrigin(origin);
|
|
11847
11856
|
};
|
|
11848
11857
|
var parseUrlOrigin = function (url) {
|
|
11849
|
-
|
|
11858
|
+
// Resolve against the document URL so relative asset urls (used when self-hosting
|
|
11859
|
+
// with an empty asset host) parse to the current page origin instead of throwing.
|
|
11860
|
+
return new URL(url, window.location.href).origin;
|
|
11850
11861
|
};
|
|
11851
11862
|
var loadResource = function (options, callback, sendErrorToCallback = false) {
|
|
11852
11863
|
try {
|
|
@@ -24992,7 +25003,10 @@ var initGuides = function (observer) {
|
|
|
24992
25003
|
* @access public
|
|
24993
25004
|
* @label AD_BLOCK_STORAGE_KEY
|
|
24994
25005
|
*/
|
|
24995
|
-
agentStorage.registry.addLocal(AD_BLOCK_STORAGE_KEY, {
|
|
25006
|
+
agentStorage.registry.addLocal(AD_BLOCK_STORAGE_KEY, {
|
|
25007
|
+
duration: 14400000,
|
|
25008
|
+
localStorageOnly: true
|
|
25009
|
+
});
|
|
24996
25010
|
GuideRuntime.initialize();
|
|
24997
25011
|
registerPostrenderScripts(GuideRuntime);
|
|
24998
25012
|
return () => {
|
|
@@ -27263,7 +27277,7 @@ function launchDesignerOrPreview(options) {
|
|
|
27263
27277
|
* @access public
|
|
27264
27278
|
* @label pendoPreview
|
|
27265
27279
|
*/
|
|
27266
|
-
agentStorage.registry.addLocal(pendoPreview$1);
|
|
27280
|
+
agentStorage.registry.addLocal(pendoPreview$1, { localStorageOnly: true });
|
|
27267
27281
|
/**
|
|
27268
27282
|
* Application state while previewing a guide from the designer. Used while designer preview is active
|
|
27269
27283
|
* to track step, status, etc., and cleared when designer preview is exited.
|
|
@@ -27273,7 +27287,7 @@ function launchDesignerOrPreview(options) {
|
|
|
27273
27287
|
* @access public
|
|
27274
27288
|
* @label designerPreview
|
|
27275
27289
|
*/
|
|
27276
|
-
agentStorage.registry.addLocal(designerPreview$1);
|
|
27290
|
+
agentStorage.registry.addLocal(designerPreview$1, { localStorageOnly: true });
|
|
27277
27291
|
// in order, try to launch:
|
|
27278
27292
|
// 1) designer
|
|
27279
27293
|
// 2) preview
|
|
@@ -30203,7 +30217,10 @@ function initLogging() {
|
|
|
30203
30217
|
* @access public
|
|
30204
30218
|
* @label LOG_ENABLED
|
|
30205
30219
|
*/
|
|
30206
|
-
agentStorage.registry.addLocal(LOG_ENABLED, {
|
|
30220
|
+
agentStorage.registry.addLocal(LOG_ENABLED, {
|
|
30221
|
+
isPlain: true,
|
|
30222
|
+
localStorageOnly: true
|
|
30223
|
+
});
|
|
30207
30224
|
/**
|
|
30208
30225
|
* DEPRECATED: Stores the active contexts for logging.
|
|
30209
30226
|
*
|
|
@@ -30212,7 +30229,10 @@ function initLogging() {
|
|
|
30212
30229
|
* @access private
|
|
30213
30230
|
* @label ACTIVE_CONTEXTS
|
|
30214
30231
|
*/
|
|
30215
|
-
agentStorage.registry.addLocal(ACTIVE_CONTEXTS, {
|
|
30232
|
+
agentStorage.registry.addLocal(ACTIVE_CONTEXTS, {
|
|
30233
|
+
isPlain: true,
|
|
30234
|
+
localStorageOnly: true
|
|
30235
|
+
});
|
|
30216
30236
|
}
|
|
30217
30237
|
var createContexts = function (contexts, args) {
|
|
30218
30238
|
return _.compact([].concat(contexts, args));
|
|
@@ -30367,10 +30387,8 @@ function track(name, props, eventProperties) {
|
|
|
30367
30387
|
collectEventHelper({ type: 'track', name, props, eventProperties });
|
|
30368
30388
|
}
|
|
30369
30389
|
|
|
30370
|
-
const privacyFilterCache = new Map();
|
|
30371
30390
|
/**
|
|
30372
30391
|
* Method to manually track agentic events. Uses agent functions for IDs and context.
|
|
30373
|
-
* Automatically applies privacy filters if agentId is provided and agent configuration exists.
|
|
30374
30392
|
*
|
|
30375
30393
|
* @access public
|
|
30376
30394
|
* @category Events
|
|
@@ -30390,64 +30408,8 @@ const privacyFilterCache = new Map();
|
|
|
30390
30408
|
* }, { experiment: 'variant_a' })
|
|
30391
30409
|
*/
|
|
30392
30410
|
function trackAgent(type, props, eventProperties) {
|
|
30393
|
-
const filteredTypes = ['prompt', 'agent_response'];
|
|
30394
|
-
if (_.contains(filteredTypes, type)) {
|
|
30395
|
-
props = applyPrivacyFilters(props);
|
|
30396
|
-
}
|
|
30397
30411
|
collectEventHelper({ type, name: 'agentic', props, eventProperties });
|
|
30398
30412
|
}
|
|
30399
|
-
/**
|
|
30400
|
-
* Apply privacy filters to event properties based on agent configuration
|
|
30401
|
-
* Optimized for maximum performance with caching
|
|
30402
|
-
* @param {Object} props - Event properties to filter
|
|
30403
|
-
* @returns {Object} - Filtered properties
|
|
30404
|
-
*/
|
|
30405
|
-
function applyPrivacyFilters(props) {
|
|
30406
|
-
if (!(props === null || props === void 0 ? void 0 : props.agentId)) {
|
|
30407
|
-
return props;
|
|
30408
|
-
}
|
|
30409
|
-
try {
|
|
30410
|
-
const agents = ConfigReader.get('aiAgents', []);
|
|
30411
|
-
const agent = (agents === null || agents === void 0 ? void 0 : agents.find(agent => agent.id === props.agentId)) || null;
|
|
30412
|
-
const content = props.content;
|
|
30413
|
-
if (!content) {
|
|
30414
|
-
return props;
|
|
30415
|
-
}
|
|
30416
|
-
if (!(agent === null || agent === void 0 ? void 0 : agent.privacyFilters)) {
|
|
30417
|
-
return props;
|
|
30418
|
-
}
|
|
30419
|
-
const privacyFilter = getCachedRegex(agent.privacyFilters);
|
|
30420
|
-
if (!privacyFilter) {
|
|
30421
|
-
return props;
|
|
30422
|
-
}
|
|
30423
|
-
const filteredContent = content.replace(privacyFilter, '<redacted>');
|
|
30424
|
-
if (filteredContent === content) {
|
|
30425
|
-
return props;
|
|
30426
|
-
}
|
|
30427
|
-
return Object.assign(Object.assign({}, props), { content: filteredContent });
|
|
30428
|
-
}
|
|
30429
|
-
catch (error) {
|
|
30430
|
-
console.error('Error applying privacy filters', error);
|
|
30431
|
-
return props;
|
|
30432
|
-
}
|
|
30433
|
-
}
|
|
30434
|
-
/**
|
|
30435
|
-
* Get cached regex or compile and cache new one
|
|
30436
|
-
*/
|
|
30437
|
-
function getCachedRegex(filterPattern) {
|
|
30438
|
-
let regex = privacyFilterCache.get(filterPattern);
|
|
30439
|
-
if (!regex) {
|
|
30440
|
-
try {
|
|
30441
|
-
regex = new RegExp(filterPattern, 'gmi');
|
|
30442
|
-
privacyFilterCache.set(filterPattern, regex);
|
|
30443
|
-
}
|
|
30444
|
-
catch (e) {
|
|
30445
|
-
privacyFilterCache.set(filterPattern, null);
|
|
30446
|
-
return null;
|
|
30447
|
-
}
|
|
30448
|
-
}
|
|
30449
|
-
return regex;
|
|
30450
|
-
}
|
|
30451
30413
|
|
|
30452
30414
|
/**
|
|
30453
30415
|
* Checks visitor and account metadata in the current Pendo installation. Either logs to the console
|
|
@@ -37640,7 +37602,7 @@ const GuideCachePlugin = {
|
|
|
37640
37602
|
if (!capturedEvent || capturedEvent.type !== 'guideSeen') {
|
|
37641
37603
|
return;
|
|
37642
37604
|
}
|
|
37643
|
-
if (capturedEvent.props.reason
|
|
37605
|
+
if (!_.contains(['auto', 'continue'], capturedEvent.props.reason)) {
|
|
37644
37606
|
return;
|
|
37645
37607
|
}
|
|
37646
37608
|
const snap = getSnapshot(capturedEvent.props.guide_id, capturedEvent.props.guide_step_id);
|
|
@@ -39466,7 +39428,10 @@ var initLauncherPlugin = function (pendo, PluginAPI) {
|
|
|
39466
39428
|
* @access public
|
|
39467
39429
|
* @label LAUNCHER_CLOSED
|
|
39468
39430
|
*/
|
|
39469
|
-
PluginAPI.agentStorage.registry.addLocal(LAUNCHER_CLOSED, {
|
|
39431
|
+
PluginAPI.agentStorage.registry.addLocal(LAUNCHER_CLOSED, {
|
|
39432
|
+
duration: 10 * 24 * 60 * 60 * 1000,
|
|
39433
|
+
localStorageOnly: true
|
|
39434
|
+
});
|
|
39470
39435
|
};
|
|
39471
39436
|
var teardownLauncherPlugin = function (pendo, PluginAPI) {
|
|
39472
39437
|
deregisterLoadGuideJobs(loadLauncherContentHandler);
|
|
@@ -40047,7 +40012,7 @@ function SegmentFlags() {
|
|
|
40047
40012
|
}
|
|
40048
40013
|
|
|
40049
40014
|
class DOMPrompt {
|
|
40050
|
-
constructor(pendo, PluginAPI, id,
|
|
40015
|
+
constructor(pendo, PluginAPI, id, inputCssSelectors, submitCssSelectors) {
|
|
40051
40016
|
this.listeners = [];
|
|
40052
40017
|
this.latestPromptValue = '';
|
|
40053
40018
|
this.isActive = true;
|
|
@@ -40058,7 +40023,6 @@ class DOMPrompt {
|
|
|
40058
40023
|
this.api = PluginAPI;
|
|
40059
40024
|
this.q = PluginAPI.q;
|
|
40060
40025
|
this.id = id;
|
|
40061
|
-
this.setFilters(privacyFilters);
|
|
40062
40026
|
if (!this._.isArray(inputCssSelectors)) {
|
|
40063
40027
|
this.api.log.error('inputCssSelectors must be an array, received:', typeof inputCssSelectors);
|
|
40064
40028
|
inputCssSelectors = [];
|
|
@@ -40161,26 +40125,6 @@ class DOMPrompt {
|
|
|
40161
40125
|
const validSubmitEls = this._.filter(this.submitEls, el => el);
|
|
40162
40126
|
this.promptContainer.addObservers(...validInputEls, ...validSubmitEls);
|
|
40163
40127
|
}
|
|
40164
|
-
setFilters(candidateFilter) {
|
|
40165
|
-
if (!candidateFilter) {
|
|
40166
|
-
this.privacyFilters = null;
|
|
40167
|
-
return null;
|
|
40168
|
-
}
|
|
40169
|
-
try {
|
|
40170
|
-
this.privacyFilters = new RegExp(candidateFilter, 'gmi');
|
|
40171
|
-
}
|
|
40172
|
-
catch (e) {
|
|
40173
|
-
this.privacyFilters = null;
|
|
40174
|
-
this.api.log.error(e);
|
|
40175
|
-
}
|
|
40176
|
-
return this.privacyFilters;
|
|
40177
|
-
}
|
|
40178
|
-
applyPrivacyFilter(candidateValue, filters = null) {
|
|
40179
|
-
const filtersToUse = filters || this.privacyFilters;
|
|
40180
|
-
if (!filtersToUse || !this._.isRegExp(filtersToUse))
|
|
40181
|
-
return candidateValue;
|
|
40182
|
-
return candidateValue.replace(filtersToUse, 'redacted');
|
|
40183
|
-
}
|
|
40184
40128
|
submit(origVal) {
|
|
40185
40129
|
if (!origVal || !this.isActive) {
|
|
40186
40130
|
return;
|
|
@@ -40191,11 +40135,9 @@ class DOMPrompt {
|
|
|
40191
40135
|
return;
|
|
40192
40136
|
}
|
|
40193
40137
|
this.lastSubmitTime = now;
|
|
40194
|
-
const val = this.applyPrivacyFilter(origVal);
|
|
40195
40138
|
const payload = {
|
|
40196
40139
|
agentId: this.id,
|
|
40197
|
-
prompt:
|
|
40198
|
-
privacyFilterApplied: val !== origVal
|
|
40140
|
+
prompt: origVal
|
|
40199
40141
|
};
|
|
40200
40142
|
this._.each(this.listeners, (cb) => cb(payload));
|
|
40201
40143
|
}
|
|
@@ -40369,11 +40311,6 @@ class PromptPlugin {
|
|
|
40369
40311
|
}
|
|
40370
40312
|
return this.agentsCache.get(agentId);
|
|
40371
40313
|
}
|
|
40372
|
-
applyPrivacyFilter(candidateValue, filters = null) {
|
|
40373
|
-
if (!filters || !this._.isRegExp(filters))
|
|
40374
|
-
return candidateValue;
|
|
40375
|
-
return candidateValue.replace(filters, 'redacted');
|
|
40376
|
-
}
|
|
40377
40314
|
// conversation agents, owned by the ConversationAnalytics plugin.
|
|
40378
40315
|
isConversationAgent(agent) {
|
|
40379
40316
|
return agent.preset && agent.preset != 'chatgpt';
|
|
@@ -40424,13 +40361,11 @@ class PromptPlugin {
|
|
|
40424
40361
|
return;
|
|
40425
40362
|
}
|
|
40426
40363
|
const originalBody = body || '';
|
|
40427
|
-
const filteredPrompt = this.applyPrivacyFilter(originalBody, aiAgent.privacyFilters);
|
|
40428
40364
|
this.api.analytics.collectEvent('prompt', {
|
|
40429
|
-
prompt:
|
|
40365
|
+
prompt: originalBody,
|
|
40430
40366
|
agentId: aiAgent.id,
|
|
40431
40367
|
promptType: method,
|
|
40432
|
-
url
|
|
40433
|
-
privacyFilterApplied: filteredPrompt !== originalBody
|
|
40368
|
+
url
|
|
40434
40369
|
}, undefined, 'agentic');
|
|
40435
40370
|
});
|
|
40436
40371
|
}
|
|
@@ -40443,7 +40378,7 @@ class PromptPlugin {
|
|
|
40443
40378
|
}
|
|
40444
40379
|
}
|
|
40445
40380
|
observePrompt(config) {
|
|
40446
|
-
const { id, cssSelectors
|
|
40381
|
+
const { id, cssSelectors } = config;
|
|
40447
40382
|
// Check if agent already exists
|
|
40448
40383
|
const existingPrompt = this._.find(this.prompts, prompt => prompt.id === id);
|
|
40449
40384
|
if (existingPrompt) {
|
|
@@ -40452,7 +40387,7 @@ class PromptPlugin {
|
|
|
40452
40387
|
let inputCssSelectors, submitCssSelectors;
|
|
40453
40388
|
inputCssSelectors = this.parseCssSelector('input', cssSelectors);
|
|
40454
40389
|
submitCssSelectors = this.parseCssSelector('submit', cssSelectors);
|
|
40455
|
-
const prompt = new DOMPrompt(this.pendo, this.api, id,
|
|
40390
|
+
const prompt = new DOMPrompt(this.pendo, this.api, id, inputCssSelectors, submitCssSelectors);
|
|
40456
40391
|
prompt.onSubmit((promptPayload) => {
|
|
40457
40392
|
this.sendPromptEvent(promptPayload);
|
|
40458
40393
|
});
|
|
@@ -41099,7 +41034,12 @@ function initAgent(pendo, PendoConfig) {
|
|
|
41099
41034
|
* @access public
|
|
41100
41035
|
* @label debugEnabled
|
|
41101
41036
|
*/
|
|
41102
|
-
agentStorage.registry.addLocal(debugEnabled, {
|
|
41037
|
+
agentStorage.registry.addLocal(debugEnabled, {
|
|
41038
|
+
isPlain: true,
|
|
41039
|
+
serializer: JSON.stringify,
|
|
41040
|
+
deserializer: SafeJsonDeserializer,
|
|
41041
|
+
localStorageOnly: true
|
|
41042
|
+
});
|
|
41103
41043
|
setPendoConfig(PendoConfig);
|
|
41104
41044
|
overwriteBuiltConfigWithPendoConfig();
|
|
41105
41045
|
if (!loadAsModule(PendoConfig) && loadAlternateAgent(PendoConfig, pendo, isDebuggingEnabled()))
|
|
@@ -43216,7 +43156,7 @@ function Feedback() {
|
|
|
43216
43156
|
* @access public
|
|
43217
43157
|
* @label notificationCountCookie
|
|
43218
43158
|
*/
|
|
43219
|
-
PluginAPI.agentStorage.registry.addLocal(notificationCountCookie);
|
|
43159
|
+
PluginAPI.agentStorage.registry.addLocal(notificationCountCookie, { localStorageOnly: true });
|
|
43220
43160
|
/**
|
|
43221
43161
|
* Stores the last ping time for the legacy Feedback widget. Used to control the
|
|
43222
43162
|
* frequency of communication with the Feedback server.
|
|
@@ -43226,7 +43166,10 @@ function Feedback() {
|
|
|
43226
43166
|
* @access public
|
|
43227
43167
|
* @label PING_COOKIE
|
|
43228
43168
|
*/
|
|
43229
|
-
PluginAPI.agentStorage.registry.addLocal(PING_COOKIE, {
|
|
43169
|
+
PluginAPI.agentStorage.registry.addLocal(PING_COOKIE, {
|
|
43170
|
+
duration: PING_COOKIE_EXPIRATION,
|
|
43171
|
+
localStorageOnly: true
|
|
43172
|
+
});
|
|
43230
43173
|
return {
|
|
43231
43174
|
validate
|
|
43232
43175
|
};
|
|
@@ -49381,32 +49324,31 @@ var n;
|
|
|
49381
49324
|
}(n || (n = {}));
|
|
49382
49325
|
return record; }
|
|
49383
49326
|
|
|
49384
|
-
|
|
49385
|
-
|
|
49386
|
-
if (maxCount === void 0) { maxCount = Infinity; }
|
|
49327
|
+
class SessionRecorderBuffer {
|
|
49328
|
+
constructor(interval, maxCount = Infinity) {
|
|
49387
49329
|
this.data = [];
|
|
49388
49330
|
this.sequenceNumber = 0;
|
|
49389
49331
|
this.interval = interval;
|
|
49390
49332
|
this.maxCount = maxCount;
|
|
49391
49333
|
this.doubledMaxCount = maxCount * 2;
|
|
49392
49334
|
}
|
|
49393
|
-
|
|
49335
|
+
isEmpty() {
|
|
49394
49336
|
return this.data.length === 0;
|
|
49395
|
-
}
|
|
49396
|
-
|
|
49337
|
+
}
|
|
49338
|
+
count() {
|
|
49397
49339
|
return this.data.length;
|
|
49398
|
-
}
|
|
49399
|
-
|
|
49340
|
+
}
|
|
49341
|
+
clear() {
|
|
49400
49342
|
this.data.length = 0;
|
|
49401
|
-
}
|
|
49402
|
-
|
|
49343
|
+
}
|
|
49344
|
+
clearSequence() {
|
|
49403
49345
|
this.sequenceNumber = 0;
|
|
49404
|
-
}
|
|
49405
|
-
|
|
49346
|
+
}
|
|
49347
|
+
push(event) {
|
|
49406
49348
|
this.data.push(event);
|
|
49407
49349
|
this.checkRateLimit();
|
|
49408
|
-
}
|
|
49409
|
-
|
|
49350
|
+
}
|
|
49351
|
+
pack(envelope, _) {
|
|
49410
49352
|
var eventsToSend = this.data.splice(0, this.maxCount);
|
|
49411
49353
|
envelope.recordingPayload = eventsToSend;
|
|
49412
49354
|
envelope.sequence = this.sequenceNumber;
|
|
@@ -49414,8 +49356,8 @@ var SessionRecorderBuffer = /** @class */ (function () {
|
|
|
49414
49356
|
if (eventsToSend.length) {
|
|
49415
49357
|
envelope.browserTime = eventsToSend[0].timestamp;
|
|
49416
49358
|
}
|
|
49417
|
-
envelope.recordingPayloadMetadata = _.map(eventsToSend,
|
|
49418
|
-
|
|
49359
|
+
envelope.recordingPayloadMetadata = _.map(eventsToSend, event => {
|
|
49360
|
+
const metadata = _.pick(event, 'type', 'timestamp');
|
|
49419
49361
|
if (event.data) {
|
|
49420
49362
|
metadata.data = _.pick(event.data, 'source', 'type', 'x', 'y', 'id', 'height', 'width', 'href');
|
|
49421
49363
|
}
|
|
@@ -49423,18 +49365,17 @@ var SessionRecorderBuffer = /** @class */ (function () {
|
|
|
49423
49365
|
});
|
|
49424
49366
|
this.sequenceNumber += eventsToSend.length;
|
|
49425
49367
|
return envelope;
|
|
49426
|
-
}
|
|
49427
|
-
|
|
49428
|
-
|
|
49368
|
+
}
|
|
49369
|
+
checkRateLimit() {
|
|
49370
|
+
const length = this.data.length;
|
|
49429
49371
|
if (length >= this.doubledMaxCount && length % this.maxCount === 0) {
|
|
49430
|
-
|
|
49372
|
+
const elapsed = this.data[length - 1].timestamp - this.data[length - this.doubledMaxCount].timestamp;
|
|
49431
49373
|
if (elapsed <= this.interval && this.onRateLimit) {
|
|
49432
49374
|
this.onRateLimit();
|
|
49433
49375
|
}
|
|
49434
49376
|
}
|
|
49435
|
-
}
|
|
49436
|
-
|
|
49437
|
-
}());
|
|
49377
|
+
}
|
|
49378
|
+
}
|
|
49438
49379
|
|
|
49439
49380
|
function __rest(s, e) {
|
|
49440
49381
|
var t = {};
|
|
@@ -49458,52 +49399,24 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
49458
49399
|
});
|
|
49459
49400
|
}
|
|
49460
49401
|
|
|
49461
|
-
function __generator(thisArg, body) {
|
|
49462
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
49463
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
49464
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
49465
|
-
function step(op) {
|
|
49466
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
49467
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
49468
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
49469
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
49470
|
-
switch (op[0]) {
|
|
49471
|
-
case 0: case 1: t = op; break;
|
|
49472
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
49473
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
49474
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
49475
|
-
default:
|
|
49476
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
49477
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
49478
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
49479
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
49480
|
-
if (t[2]) _.ops.pop();
|
|
49481
|
-
_.trys.pop(); continue;
|
|
49482
|
-
}
|
|
49483
|
-
op = body.call(thisArg, _);
|
|
49484
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
49485
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
49486
|
-
}
|
|
49487
|
-
}
|
|
49488
|
-
|
|
49489
49402
|
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
49490
49403
|
var e = new Error(message);
|
|
49491
49404
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
49492
49405
|
};
|
|
49493
49406
|
|
|
49494
|
-
|
|
49495
|
-
|
|
49496
|
-
|
|
49497
|
-
|
|
49498
|
-
|
|
49407
|
+
const RECORDING_CONFIG_WORKERURL$1 = 'recording.workerUrl';
|
|
49408
|
+
const MAX_SIZE = 2000000;
|
|
49409
|
+
const RESOURCE_CACHING$1 = 'resourceCaching';
|
|
49410
|
+
class Transport {
|
|
49411
|
+
constructor(WorkerClass, pendo, api) {
|
|
49499
49412
|
this.WorkerClass = WorkerClass;
|
|
49500
49413
|
this.pendo = pendo;
|
|
49501
49414
|
this.api = api;
|
|
49502
49415
|
this.maxSize = MAX_SIZE;
|
|
49503
|
-
this.lockID =
|
|
49416
|
+
this.lockID = `worker-lock-${this.pendo.randomString(16)}`;
|
|
49504
49417
|
this.isResourceCachingEnabled = this.api.ConfigReader.get(RESOURCE_CACHING$1);
|
|
49505
49418
|
}
|
|
49506
|
-
|
|
49419
|
+
start(config) {
|
|
49507
49420
|
if (config.disableWorker)
|
|
49508
49421
|
return;
|
|
49509
49422
|
if (!this.worker) {
|
|
@@ -49513,7 +49426,7 @@ var Transport = /** @class */ (function () {
|
|
|
49513
49426
|
this.worker = config.workerOverride;
|
|
49514
49427
|
}
|
|
49515
49428
|
else {
|
|
49516
|
-
|
|
49429
|
+
const workerUrl = this.api.ConfigReader.get(RECORDING_CONFIG_WORKERURL$1);
|
|
49517
49430
|
this.usesSelfHostedWorker = workerUrl != null;
|
|
49518
49431
|
this.worker = workerUrl ? new Worker(workerUrl) : new this.WorkerClass();
|
|
49519
49432
|
}
|
|
@@ -49527,35 +49440,34 @@ var Transport = /** @class */ (function () {
|
|
|
49527
49440
|
this.worker = null;
|
|
49528
49441
|
}
|
|
49529
49442
|
}
|
|
49530
|
-
}
|
|
49531
|
-
|
|
49443
|
+
}
|
|
49444
|
+
stop() {
|
|
49532
49445
|
if (this.worker) {
|
|
49533
49446
|
this.worker.terminate();
|
|
49534
49447
|
delete this.worker;
|
|
49535
49448
|
}
|
|
49536
|
-
}
|
|
49537
|
-
|
|
49538
|
-
|
|
49539
|
-
|
|
49540
|
-
var payload = envelope.payload;
|
|
49449
|
+
}
|
|
49450
|
+
send(envelope, isUnload, failureCount = 0) {
|
|
49451
|
+
let { url } = envelope;
|
|
49452
|
+
const { payload } = envelope;
|
|
49541
49453
|
if (failureCount > 0) {
|
|
49542
|
-
url =
|
|
49454
|
+
url = `${url}&rt=${failureCount}`;
|
|
49543
49455
|
}
|
|
49544
49456
|
if (this.worker && !isUnload && payload) {
|
|
49545
|
-
|
|
49546
|
-
|
|
49547
|
-
|
|
49548
|
-
|
|
49457
|
+
const deferred = {};
|
|
49458
|
+
deferred.promise = new Promise$2((resolve, reject) => {
|
|
49459
|
+
deferred.resolve = resolve;
|
|
49460
|
+
deferred.reject = reject;
|
|
49549
49461
|
});
|
|
49550
|
-
this.workerResponse =
|
|
49551
|
-
this.worker.postMessage({ url
|
|
49552
|
-
return
|
|
49462
|
+
this.workerResponse = deferred;
|
|
49463
|
+
this.worker.postMessage({ url, payload, shouldCacheResources: this.isResourceCachingEnabled });
|
|
49464
|
+
return deferred.promise;
|
|
49553
49465
|
}
|
|
49554
49466
|
else {
|
|
49555
49467
|
if (!envelope.body) {
|
|
49556
|
-
|
|
49468
|
+
const strPayload = JSON.stringify(payload);
|
|
49557
49469
|
if (strPayload.length > this.maxSize) {
|
|
49558
|
-
|
|
49470
|
+
const error = new Error('maximum recording payload size exceeded');
|
|
49559
49471
|
error.reason = 'HEAVY_EVENT';
|
|
49560
49472
|
error.context = {
|
|
49561
49473
|
size: strPayload.length,
|
|
@@ -49566,14 +49478,14 @@ var Transport = /** @class */ (function () {
|
|
|
49566
49478
|
envelope.body = this.pendo.compress(strPayload, 'binary');
|
|
49567
49479
|
delete envelope.payload;
|
|
49568
49480
|
}
|
|
49569
|
-
url =
|
|
49481
|
+
url = `${url}&ct=${new Date().getTime()}`;
|
|
49570
49482
|
return this.post(url, {
|
|
49571
49483
|
keepalive: isUnload,
|
|
49572
49484
|
body: envelope.body
|
|
49573
49485
|
});
|
|
49574
49486
|
}
|
|
49575
|
-
}
|
|
49576
|
-
|
|
49487
|
+
}
|
|
49488
|
+
post(url, options) {
|
|
49577
49489
|
options.method = 'POST';
|
|
49578
49490
|
if (options.keepalive && this.api.transmit.fetchKeepalive.supported()) {
|
|
49579
49491
|
return this.api.transmit.fetchKeepalive(url, options);
|
|
@@ -49585,57 +49497,46 @@ var Transport = /** @class */ (function () {
|
|
|
49585
49497
|
else {
|
|
49586
49498
|
return this.pendo.ajax.post(url, options.body);
|
|
49587
49499
|
}
|
|
49588
|
-
}
|
|
49589
|
-
|
|
49590
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
49591
|
-
|
|
49592
|
-
|
|
49593
|
-
|
|
49594
|
-
|
|
49595
|
-
|
|
49596
|
-
|
|
49597
|
-
|
|
49598
|
-
|
|
49599
|
-
|
|
49600
|
-
|
|
49601
|
-
|
|
49602
|
-
|
|
49603
|
-
|
|
49604
|
-
|
|
49605
|
-
|
|
49606
|
-
return [2 /*return*/];
|
|
49607
|
-
}
|
|
49608
|
-
// handle POST request response from worker
|
|
49609
|
-
if (messageEvent.data && messageEvent.data.error) {
|
|
49610
|
-
if ((messageEvent.data.status && messageEvent.data.status < 500) ||
|
|
49611
|
-
messageEvent.data.sequence == null) {
|
|
49612
|
-
this.api.log.critical('Failed to send recording data from web worker', { error: messageEvent.data.error });
|
|
49613
|
-
}
|
|
49614
|
-
if (this.workerResponse) {
|
|
49615
|
-
this.workerResponse.reject();
|
|
49616
|
-
this.workerResponse = null;
|
|
49617
|
-
}
|
|
49618
|
-
}
|
|
49619
|
-
if (this.workerResponse) {
|
|
49620
|
-
this.workerResponse.resolve();
|
|
49621
|
-
this.workerResponse = null;
|
|
49622
|
-
}
|
|
49623
|
-
return [2 /*return*/];
|
|
49500
|
+
}
|
|
49501
|
+
_onMessage(messageEvent) {
|
|
49502
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
49503
|
+
if (messageEvent.data && messageEvent.data.ready && navigator.locks) {
|
|
49504
|
+
// When the lock is released, we can assume the worker was terminated or closed
|
|
49505
|
+
yield navigator.locks.request(this.lockID, () => { });
|
|
49506
|
+
this.onWorkerMessage({ type: 'workerDied' });
|
|
49507
|
+
}
|
|
49508
|
+
// handle non-POST request responses from worker
|
|
49509
|
+
if (messageEvent.data && messageEvent.data.type) {
|
|
49510
|
+
this.onWorkerMessage(messageEvent.data);
|
|
49511
|
+
return;
|
|
49512
|
+
}
|
|
49513
|
+
// handle POST request response from worker
|
|
49514
|
+
if (messageEvent.data && messageEvent.data.error) {
|
|
49515
|
+
if ((messageEvent.data.status && messageEvent.data.status < 500) ||
|
|
49516
|
+
messageEvent.data.sequence == null) {
|
|
49517
|
+
this.api.log.critical('Failed to send recording data from web worker', { error: messageEvent.data.error });
|
|
49624
49518
|
}
|
|
49625
|
-
|
|
49519
|
+
if (this.workerResponse) {
|
|
49520
|
+
this.workerResponse.reject();
|
|
49521
|
+
this.workerResponse = null;
|
|
49522
|
+
}
|
|
49523
|
+
}
|
|
49524
|
+
if (this.workerResponse) {
|
|
49525
|
+
this.workerResponse.resolve();
|
|
49526
|
+
this.workerResponse = null;
|
|
49527
|
+
}
|
|
49626
49528
|
});
|
|
49627
|
-
}
|
|
49628
|
-
|
|
49529
|
+
}
|
|
49530
|
+
_onError() {
|
|
49629
49531
|
if (this.onError) {
|
|
49630
49532
|
this.onError();
|
|
49631
49533
|
}
|
|
49632
|
-
}
|
|
49633
|
-
|
|
49634
|
-
}());
|
|
49534
|
+
}
|
|
49535
|
+
}
|
|
49635
49536
|
|
|
49636
|
-
|
|
49637
|
-
|
|
49638
|
-
|
|
49537
|
+
const ELEMENT_NODE = 1;
|
|
49538
|
+
const INPUT_MASK = '*'.repeat(10);
|
|
49539
|
+
const NUMBER_INPUT_MASK = '0'.repeat(10);
|
|
49639
49540
|
function isElementNode(node) {
|
|
49640
49541
|
if (!node)
|
|
49641
49542
|
return false;
|
|
@@ -49644,12 +49545,10 @@ function isElementNode(node) {
|
|
|
49644
49545
|
return true;
|
|
49645
49546
|
}
|
|
49646
49547
|
function getParent(elem) {
|
|
49647
|
-
|
|
49548
|
+
const isElementShadowRoot = typeof window.ShadowRoot !== 'undefined' && elem instanceof window.ShadowRoot && elem.host;
|
|
49648
49549
|
return isElementShadowRoot ? elem.host : elem.parentNode;
|
|
49649
49550
|
}
|
|
49650
|
-
function distanceToMatch(node, selector, limit, distance) {
|
|
49651
|
-
if (limit === void 0) { limit = Infinity; }
|
|
49652
|
-
if (distance === void 0) { distance = 0; }
|
|
49551
|
+
function distanceToMatch(node, selector, limit = Infinity, distance = 0) {
|
|
49653
49552
|
if (distance > limit)
|
|
49654
49553
|
return -1;
|
|
49655
49554
|
if (!node)
|
|
@@ -49663,15 +49562,15 @@ function distanceToMatch(node, selector, limit, distance) {
|
|
|
49663
49562
|
return distanceToMatch(getParent(node), selector, limit, distance + 1);
|
|
49664
49563
|
}
|
|
49665
49564
|
function shouldMask(node, options) {
|
|
49666
|
-
|
|
49565
|
+
const { maskAllText, maskTextSelector, unmaskTextSelector } = options;
|
|
49667
49566
|
try {
|
|
49668
|
-
|
|
49567
|
+
const el = isElementNode(node) ? node : node.parentElement;
|
|
49669
49568
|
if (el === null)
|
|
49670
49569
|
return false;
|
|
49671
49570
|
if ((el.tagName || '').toUpperCase() === 'STYLE')
|
|
49672
49571
|
return false;
|
|
49673
|
-
|
|
49674
|
-
|
|
49572
|
+
let maskDistance = -1;
|
|
49573
|
+
let unmaskDistance = -1;
|
|
49675
49574
|
if (maskAllText) {
|
|
49676
49575
|
unmaskDistance = distanceToMatch(el, unmaskTextSelector);
|
|
49677
49576
|
if (unmaskDistance < 0) {
|
|
@@ -49704,8 +49603,8 @@ function isNumberInput(element) {
|
|
|
49704
49603
|
}
|
|
49705
49604
|
function shouldMaskInput(element, maskInputOptions) {
|
|
49706
49605
|
if (maskInputOptions && isElementNode(element)) {
|
|
49707
|
-
|
|
49708
|
-
|
|
49606
|
+
const tagName = (element.tagName || '').toLowerCase();
|
|
49607
|
+
const type = (element.type || '').toLowerCase();
|
|
49709
49608
|
if (maskInputOptions[tagName] || maskInputOptions[type]) {
|
|
49710
49609
|
return true;
|
|
49711
49610
|
}
|
|
@@ -51199,12 +51098,12 @@ var WorkerFactory = /*#__PURE__*/createInlineWorkerFactory(/* rollup-plugin-web-
|
|
|
51199
51098
|
}
|
|
51200
51099
|
}
|
|
51201
51100
|
|
|
51202
|
-
|
|
51101
|
+
const ONE_HUNDRED_MB_IN_BYTES = 100 * 1024 * 1024;
|
|
51203
51102
|
function matchHostedResources(recordingEvent, stringifiedRecordingPayload) {
|
|
51204
|
-
|
|
51205
|
-
|
|
51103
|
+
const fontURLRegex = /https:\/\/[^"\\\s]+?\.(woff2?|ttf|otf|eot)(\?[^"\\\s]*)?\b/g;
|
|
51104
|
+
const matches = stringifiedRecordingPayload.match(fontURLRegex);
|
|
51206
51105
|
// de-duplicate matches
|
|
51207
|
-
|
|
51106
|
+
const hostedResources = matches ? Array.from(new Set(matches)) : [];
|
|
51208
51107
|
return {
|
|
51209
51108
|
type: 'recording',
|
|
51210
51109
|
visitorId: recordingEvent.visitorId,
|
|
@@ -51219,7 +51118,7 @@ var WorkerFactory = /*#__PURE__*/createInlineWorkerFactory(/* rollup-plugin-web-
|
|
|
51219
51118
|
recordingPayloadMetadata: [],
|
|
51220
51119
|
sequence: 0,
|
|
51221
51120
|
recordingPayloadCount: 0,
|
|
51222
|
-
hostedResources
|
|
51121
|
+
hostedResources
|
|
51223
51122
|
};
|
|
51224
51123
|
}
|
|
51225
51124
|
// keep in mind changes here may need addressing in the extension worker proxy as well
|
|
@@ -51227,69 +51126,69 @@ var WorkerFactory = /*#__PURE__*/createInlineWorkerFactory(/* rollup-plugin-web-
|
|
|
51227
51126
|
try {
|
|
51228
51127
|
if (e.data.type === 'init' && e.data.lockID) {
|
|
51229
51128
|
if (navigator.locks) {
|
|
51230
|
-
navigator.locks.request(e.data.lockID,
|
|
51129
|
+
navigator.locks.request(e.data.lockID, () => {
|
|
51231
51130
|
postMessage({ ready: true });
|
|
51232
51131
|
// This unresolved promise keeps the lock held with the worker until the worker is
|
|
51233
51132
|
// terminated at which point the lock is released.
|
|
51234
|
-
return new Promise$2(
|
|
51133
|
+
return new Promise$2(() => { });
|
|
51235
51134
|
});
|
|
51236
51135
|
}
|
|
51237
51136
|
return;
|
|
51238
51137
|
}
|
|
51239
51138
|
if (e.data.url && e.data.payload) {
|
|
51240
|
-
|
|
51139
|
+
let { url, payload, shouldCacheResources } = e.data;
|
|
51241
51140
|
if (Object.keys(payload).length === 0) {
|
|
51242
51141
|
postMessage({
|
|
51243
51142
|
type: 'emptyPayload'
|
|
51244
51143
|
});
|
|
51245
51144
|
}
|
|
51246
|
-
|
|
51247
|
-
|
|
51145
|
+
const { sequence } = payload;
|
|
51146
|
+
const stringifiedRecordingPayload = JSON.stringify(payload.recordingPayload);
|
|
51248
51147
|
// calculate and post back the recording payload size before the payload is compressed
|
|
51249
|
-
|
|
51250
|
-
|
|
51148
|
+
const recordingPayloadSize = new TextEncoder().encode(stringifiedRecordingPayload).length;
|
|
51149
|
+
const exceedsPayloadSizeLimit = recordingPayloadSize >= ONE_HUNDRED_MB_IN_BYTES;
|
|
51251
51150
|
postMessage({
|
|
51252
51151
|
type: 'recordingPayloadSize',
|
|
51253
|
-
recordingPayloadSize
|
|
51254
|
-
exceedsPayloadSizeLimit
|
|
51152
|
+
recordingPayloadSize,
|
|
51153
|
+
exceedsPayloadSizeLimit
|
|
51255
51154
|
});
|
|
51256
51155
|
// don't attempt to send the payload if it exceeds the allowed limit
|
|
51257
51156
|
if (exceedsPayloadSizeLimit)
|
|
51258
51157
|
return;
|
|
51259
51158
|
if (shouldCacheResources) {
|
|
51260
|
-
|
|
51159
|
+
const hostedResourcesEvent = matchHostedResources(payload, stringifiedRecordingPayload);
|
|
51261
51160
|
if (hostedResourcesEvent.hostedResources.length) {
|
|
51262
51161
|
postMessage({
|
|
51263
51162
|
type: 'hostedResources',
|
|
51264
|
-
hostedResourcesEvent
|
|
51163
|
+
hostedResourcesEvent
|
|
51265
51164
|
});
|
|
51266
51165
|
}
|
|
51267
51166
|
}
|
|
51268
51167
|
payload.recordingSize = recordingPayloadSize;
|
|
51269
|
-
|
|
51168
|
+
const body = compress(payload, 'binary');
|
|
51270
51169
|
// we want to calculate ct (current time) as close as we can to the actual POST request
|
|
51271
51170
|
// so that it's as accurate as possible
|
|
51272
|
-
url =
|
|
51171
|
+
url = `${url}&ct=${new Date().getTime()}`;
|
|
51273
51172
|
fetch(url, {
|
|
51274
51173
|
method: 'POST',
|
|
51275
|
-
body
|
|
51174
|
+
body
|
|
51276
51175
|
}).then(function (response) {
|
|
51277
51176
|
if (response.status < 200 || response.status >= 300) {
|
|
51278
51177
|
postMessage({
|
|
51279
|
-
error: new Error(
|
|
51178
|
+
error: new Error(`received status code ${response.status}: ${response.statusText}`),
|
|
51280
51179
|
status: response.status,
|
|
51281
|
-
sequence
|
|
51180
|
+
sequence
|
|
51282
51181
|
});
|
|
51283
51182
|
}
|
|
51284
51183
|
else {
|
|
51285
51184
|
postMessage({
|
|
51286
|
-
sequence
|
|
51185
|
+
sequence
|
|
51287
51186
|
});
|
|
51288
51187
|
}
|
|
51289
|
-
})
|
|
51188
|
+
}).catch(function (e) {
|
|
51290
51189
|
postMessage({
|
|
51291
51190
|
error: e,
|
|
51292
|
-
sequence
|
|
51191
|
+
sequence
|
|
51293
51192
|
});
|
|
51294
51193
|
});
|
|
51295
51194
|
}
|
|
@@ -53055,6 +52954,7 @@ const PredictGuides = () => {
|
|
|
53055
52954
|
const ASSISTANT_MESSAGE = 'assistantMessage';
|
|
53056
52955
|
const CONVERSATION_ID_URL_PATTERN = 'conversationIdUrlPattern';
|
|
53057
52956
|
const MESSAGE_ID_ATTR = 'messageIdAttr';
|
|
52957
|
+
const MESSAGE_ID_PATTERN = 'messageIdPattern';
|
|
53058
52958
|
const MODEL_USED_ATTR = 'modelUsedAttr';
|
|
53059
52959
|
const REACTION_ACTIVE = 'reactionActive';
|
|
53060
52960
|
const STREAMING_ACTIVE = 'streamingActive';
|
|
@@ -53062,7 +52962,6 @@ const STREAMING_ACTIVE_ATTR = 'streamingActiveAttr';
|
|
|
53062
52962
|
const THUMB_DOWN = 'thumbDown';
|
|
53063
52963
|
const THUMB_UP = 'thumbUp';
|
|
53064
52964
|
const TURN_CONTAINER = 'turnContainer';
|
|
53065
|
-
const TURN_ATTR = 'turnAttr';
|
|
53066
52965
|
const USER_MESSAGE = 'userMessage';
|
|
53067
52966
|
const CUSTOM_AGENT_ID_URL_PATTERN = 'customAgentIdUrlPattern';
|
|
53068
52967
|
const CUSTOM_AGENT_NAME = 'customAgentName';
|
|
@@ -53072,9 +52971,9 @@ const REQUIRED_SELECTORS = [
|
|
|
53072
52971
|
MESSAGE_ID_ATTR,
|
|
53073
52972
|
STREAMING_ACTIVE,
|
|
53074
52973
|
TURN_CONTAINER,
|
|
53075
|
-
TURN_ATTR,
|
|
53076
52974
|
USER_MESSAGE
|
|
53077
52975
|
];
|
|
52976
|
+
const SUPPORTED_PRESETS = ['chatgpt-full', 'gemini-full'];
|
|
53078
52977
|
const STREAMING_END_SETTLE_MS = 500;
|
|
53079
52978
|
const SUBMISSION_START_RETRY_MS = 1000;
|
|
53080
52979
|
const SUBMISSION_START_MAX_ATTEMPTS = 4;
|
|
@@ -53103,9 +53002,9 @@ class DOMConversation {
|
|
|
53103
53002
|
return REQUIRED_SELECTORS.filter((r) => !present.has(r));
|
|
53104
53003
|
}
|
|
53105
53004
|
static supportedPreset(preset) {
|
|
53106
|
-
return preset
|
|
53005
|
+
return SUPPORTED_PRESETS.indexOf(preset) !== -1;
|
|
53107
53006
|
}
|
|
53108
|
-
constructor(pendo, PluginAPI, id,
|
|
53007
|
+
constructor(pendo, PluginAPI, id, cssSelectors) {
|
|
53109
53008
|
this.selectors = {};
|
|
53110
53009
|
this.listeners = [];
|
|
53111
53010
|
this.isActive = true;
|
|
@@ -53116,13 +53015,13 @@ class DOMConversation {
|
|
|
53116
53015
|
this.requestNode = null;
|
|
53117
53016
|
this.conversationIdRegex = null;
|
|
53118
53017
|
this.customAgentIdRegex = null;
|
|
53018
|
+
this.messageIdRegex = null;
|
|
53119
53019
|
this.lastReturnedMessageId = null;
|
|
53120
53020
|
this.dom = pendo.dom;
|
|
53121
53021
|
this._ = pendo._;
|
|
53122
53022
|
this.api = PluginAPI;
|
|
53123
53023
|
this.Sizzle = pendo.Sizzle;
|
|
53124
53024
|
this.id = id;
|
|
53125
|
-
this.setFilters(privacyFilters);
|
|
53126
53025
|
if (!this._.isArray(cssSelectors)) {
|
|
53127
53026
|
this.api.log.error(`cssSelectors must be an array, received: ${typeof cssSelectors}`);
|
|
53128
53027
|
cssSelectors = [];
|
|
@@ -53142,6 +53041,15 @@ class DOMConversation {
|
|
|
53142
53041
|
this.api.log.error(`bad customAgentIdUrlPattern ${customAgentIdUrlPattern}`, { error });
|
|
53143
53042
|
}
|
|
53144
53043
|
}
|
|
53044
|
+
const messageIdPattern = this.selectors[MESSAGE_ID_PATTERN];
|
|
53045
|
+
if (messageIdPattern) { // optional: gates the request node until its id is fully rendered
|
|
53046
|
+
try {
|
|
53047
|
+
this.messageIdRegex = new RegExp(messageIdPattern);
|
|
53048
|
+
}
|
|
53049
|
+
catch (error) {
|
|
53050
|
+
this.api.log.error(`bad messageIdPattern ${messageIdPattern}`, { error });
|
|
53051
|
+
}
|
|
53052
|
+
}
|
|
53145
53053
|
this.root = document.body;
|
|
53146
53054
|
this.setupReactionListener();
|
|
53147
53055
|
this.setupStreamingObserver();
|
|
@@ -53171,8 +53079,7 @@ class DOMConversation {
|
|
|
53171
53079
|
this.emit('user_reaction', {
|
|
53172
53080
|
agentId: this.id,
|
|
53173
53081
|
messageId: this.getMessageId(assistantNode),
|
|
53174
|
-
content
|
|
53175
|
-
privacyFilterApplied: false
|
|
53082
|
+
content
|
|
53176
53083
|
});
|
|
53177
53084
|
}
|
|
53178
53085
|
// observe the streaming indicator
|
|
@@ -53241,28 +53148,22 @@ class DOMConversation {
|
|
|
53241
53148
|
return;
|
|
53242
53149
|
this.handleUserMessage(requestNode);
|
|
53243
53150
|
}
|
|
53244
|
-
const
|
|
53245
|
-
if (
|
|
53151
|
+
const requestEl = requestNode[0];
|
|
53152
|
+
if (!requestEl)
|
|
53246
53153
|
return;
|
|
53154
|
+
// the request is the latest user message, so any assistant message that
|
|
53155
|
+
// follows it in the DOM is a response to it. document order is already
|
|
53156
|
+
// chronological, so we emit as we go
|
|
53247
53157
|
const assistantNodes = this.select(ASSISTANT_MESSAGE);
|
|
53248
|
-
|
|
53249
|
-
|
|
53250
|
-
|
|
53251
|
-
|
|
53252
|
-
|
|
53253
|
-
if (n <= requestTurn)
|
|
53254
|
-
break;
|
|
53255
|
-
toEmit.push(assistantNodes[i]);
|
|
53256
|
-
}
|
|
53257
|
-
// emit in chronological order (reverse of collection order)
|
|
53258
|
-
for (let i = toEmit.length - 1; i >= 0; i--) {
|
|
53259
|
-
this.handleAssistantMessage(this.dom(toEmit[i]));
|
|
53158
|
+
for (let i = 0; i < assistantNodes.length; i++) {
|
|
53159
|
+
const el = assistantNodes[i];
|
|
53160
|
+
if (requestEl.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
53161
|
+
this.handleAssistantMessage(this.dom(el));
|
|
53162
|
+
}
|
|
53260
53163
|
}
|
|
53261
53164
|
}
|
|
53262
53165
|
extractContent(node) {
|
|
53263
|
-
|
|
53264
|
-
const content = this.applyPrivacyFilter(rawContent);
|
|
53265
|
-
return { content, privacyFilterApplied: content !== rawContent };
|
|
53166
|
+
return { content: node.text().trim() };
|
|
53266
53167
|
}
|
|
53267
53168
|
getMessageId(node) {
|
|
53268
53169
|
return node.attr(this.findSelector(MESSAGE_ID_ATTR));
|
|
@@ -53285,20 +53186,16 @@ class DOMConversation {
|
|
|
53285
53186
|
const messageId = this.getMessageId($node);
|
|
53286
53187
|
if (!messageId)
|
|
53287
53188
|
return null;
|
|
53189
|
+
// the node may still be rendering (e.g. a framework interpolating an
|
|
53190
|
+
// unresolved id); treat it as not-ready so the retry waits for the
|
|
53191
|
+
// finalized node rather than caching a placeholder that gets replaced
|
|
53192
|
+
if (this.messageIdRegex && !this.messageIdRegex.test(messageId))
|
|
53193
|
+
return null;
|
|
53288
53194
|
if (messageId === this.lastReturnedMessageId)
|
|
53289
53195
|
return null;
|
|
53290
53196
|
this.lastReturnedMessageId = messageId;
|
|
53291
53197
|
return $node;
|
|
53292
53198
|
}
|
|
53293
|
-
findTurnNumber(node) {
|
|
53294
|
-
const turnSelector = this.findSelector(TURN_CONTAINER);
|
|
53295
|
-
const turnAttr = this.findSelector(TURN_ATTR);
|
|
53296
|
-
const turn = node.closest(turnSelector).attr(turnAttr);
|
|
53297
|
-
if (!turn)
|
|
53298
|
-
return null;
|
|
53299
|
-
const seqMatch = String(turn).match(/\d+/);
|
|
53300
|
-
return seqMatch ? parseInt(seqMatch[0], 10) : null;
|
|
53301
|
-
}
|
|
53302
53199
|
findSelector(type) {
|
|
53303
53200
|
return this.selectors[type];
|
|
53304
53201
|
}
|
|
@@ -53337,26 +53234,6 @@ class DOMConversation {
|
|
|
53337
53234
|
eventPayload.customAgentName = customAgentName;
|
|
53338
53235
|
}
|
|
53339
53236
|
}
|
|
53340
|
-
setFilters(candidateFilter) {
|
|
53341
|
-
if (!candidateFilter) {
|
|
53342
|
-
this.privacyFilters = null;
|
|
53343
|
-
return null;
|
|
53344
|
-
}
|
|
53345
|
-
try {
|
|
53346
|
-
this.privacyFilters = new RegExp(candidateFilter, 'gmi');
|
|
53347
|
-
}
|
|
53348
|
-
catch (e) {
|
|
53349
|
-
this.privacyFilters = null;
|
|
53350
|
-
this.api.log.error(e);
|
|
53351
|
-
}
|
|
53352
|
-
return this.privacyFilters;
|
|
53353
|
-
}
|
|
53354
|
-
applyPrivacyFilter(candidateValue, filters = null) {
|
|
53355
|
-
const filtersToUse = filters || this.privacyFilters;
|
|
53356
|
-
if (!filtersToUse || !this._.isRegExp(filtersToUse))
|
|
53357
|
-
return candidateValue;
|
|
53358
|
-
return candidateValue.replace(filtersToUse, 'redacted');
|
|
53359
|
-
}
|
|
53360
53237
|
onSubmit(callback) {
|
|
53361
53238
|
this.listeners.push(callback);
|
|
53362
53239
|
}
|
|
@@ -53517,7 +53394,7 @@ function ConversationAnalytics() {
|
|
|
53517
53394
|
});
|
|
53518
53395
|
}
|
|
53519
53396
|
function observeConversation(config) {
|
|
53520
|
-
const { id, cssSelectors
|
|
53397
|
+
const { id, cssSelectors } = config;
|
|
53521
53398
|
// Check if this agent is already being tracked
|
|
53522
53399
|
const existing = _.find(conversations, conversation => conversation.id === id);
|
|
53523
53400
|
if (existing) {
|
|
@@ -53528,7 +53405,7 @@ function ConversationAnalytics() {
|
|
|
53528
53405
|
log.error('aiAgent config missing required selectors', { agentId: id, missing });
|
|
53529
53406
|
return;
|
|
53530
53407
|
}
|
|
53531
|
-
const conversation = new DOMConversation(pendo, api, id,
|
|
53408
|
+
const conversation = new DOMConversation(pendo, api, id, cssSelectors);
|
|
53532
53409
|
conversation.onSubmit(sendConversationEvent);
|
|
53533
53410
|
conversations.push(conversation);
|
|
53534
53411
|
}
|