@pendo/agent 2.295.1 → 2.296.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.
@@ -3527,6 +3527,7 @@ var ConfigReader = (function () {
3527
3527
  addOption('enableAllEmbeddedGuideEvents', [PENDO_CONFIG_SRC], false);
3528
3528
  // Form Validation
3529
3529
  addOption('formValidation', [PENDO_CONFIG_SRC], false);
3530
+ addOption('performanceMetricsEnabled', [SNIPPET_SRC, PENDO_CONFIG_SRC], true);
3530
3531
  }
3531
3532
  initializeOptions();
3532
3533
  var sourceGetters = {};
@@ -3658,10 +3659,10 @@ var ConfigReader = (function () {
3658
3659
  /* eslint-enable no-console */
3659
3660
  })();
3660
3661
 
3661
- var EXTENSION_INSTALL_TYPE = 'extension';
3662
- var NATIVE_INSTALL_TYPE = 'native';
3662
+ const EXTENSION_INSTALL_TYPE = 'extension';
3663
+ const NATIVE_INSTALL_TYPE = 'native';
3663
3664
  function getInstallType() {
3664
- var installType = ConfigReader.get('installType') || getPendoConfigFromEnclosingScope().installType;
3665
+ const installType = ConfigReader.get('installType') || getPendoConfigFromEnclosingScope().installType;
3665
3666
  return installType || NATIVE_INSTALL_TYPE;
3666
3667
  }
3667
3668
  function isExtensionAgent() {
@@ -3891,8 +3892,8 @@ let SERVER = '';
3891
3892
  let ASSET_HOST = '';
3892
3893
  let ASSET_PATH = '';
3893
3894
  let DESIGNER_SERVER = '';
3894
- let VERSION = '2.295.1_';
3895
- let PACKAGE_VERSION = '2.295.1';
3895
+ let VERSION = '2.296.1_';
3896
+ let PACKAGE_VERSION = '2.296.1';
3896
3897
  let LOADER = 'xhr';
3897
3898
  /* eslint-enable agent-eslint-rules/no-gulp-env-references */
3898
3899
  /**
@@ -9772,6 +9773,31 @@ function writeErrorPOST(msg) {
9772
9773
  return writeMessage('Failed to write error to server using POST endpoint: ' + e);
9773
9774
  }
9774
9775
  }
9776
+ /**
9777
+ * @access private
9778
+ * @param {Object} payload of named metrics to send to backend
9779
+ * @returns void
9780
+ */
9781
+ function writeMetricsPOST(payload) {
9782
+ try {
9783
+ const url = `${HOST}/data/agentmetrics?apiKey=${pendo$1.apiKey}`;
9784
+ log.debug(`Will send ${JSON.stringify(payload)} to ${url} using ${fetchKeepalive.supported() ? 'fetch' : 'xhr'} once the endpoint exists`);
9785
+ if (fetchKeepalive.supported()) {
9786
+ // fetch(url, {
9787
+ // method: 'POST',
9788
+ // keepalive: true,
9789
+ // body: JSON.stringify(payload),
9790
+ // headers: { 'Content-Type': 'application/json' }
9791
+ // });
9792
+ }
9793
+ else {
9794
+ // ajax.postJSON(url, payload);
9795
+ }
9796
+ }
9797
+ catch (e) {
9798
+ log.critical(`Failed to write metrics payload to server: ${e}`);
9799
+ }
9800
+ }
9775
9801
  /**
9776
9802
  * @access private
9777
9803
  * @param {string} src to apply to {Image}
@@ -11192,7 +11218,7 @@ class DomObserver {
11192
11218
  this.signal();
11193
11219
  }, 500);
11194
11220
  this._teardown = () => {
11195
- clearTimeout(handle);
11221
+ clearInterval(handle);
11196
11222
  };
11197
11223
  }
11198
11224
  }
@@ -12168,27 +12194,55 @@ class LocalStorageEventBuffer {
12168
12194
  }
12169
12195
  var localStorageEventBuffer = new LocalStorageEventBuffer();
12170
12196
 
12197
+ /*
12198
+ * These implementations are meant to help keep the agent's metrics usage aligned with
12199
+ * the expectations for the backend's open telemetry.
12200
+ *
12201
+ * We're leveraging the details attribute that is optionally defined on all Performance
12202
+ * API marks.
12203
+ *
12204
+ * See https://opentelemetry.io/docs/concepts/signals/metrics/#metric-instruments
12205
+ */
12206
+ const count = (entries) => {
12207
+ if (!entries)
12208
+ return 0;
12209
+ if (entries instanceof Array) {
12210
+ return _.reduce(entries, (count, e) => {
12211
+ const incr = e.detail && e.detail.incr ? e.detail.incr : 1;
12212
+ return count + incr;
12213
+ }, 0);
12214
+ }
12215
+ return 0;
12216
+ };
12217
+
12218
+ const METRIC_GUIDELOOP_TIMEOUT = 'agent-guideloop-timeout';
12219
+ const Metrics = {};
12220
+ Metrics[METRIC_GUIDELOOP_TIMEOUT] = {
12221
+ displayName: 'Guide Loop Timeouts',
12222
+ name: METRIC_GUIDELOOP_TIMEOUT,
12223
+ instrument: count
12224
+ };
12225
+
12226
+ const PERF_INTERVAL = 1000 * 60 * 10;
12171
12227
  class PerformanceMonitor {
12172
12228
  constructor() {
12173
12229
  this._isPerformanceApiAvailable = this._checkPerformanceApi();
12174
12230
  this._measuringPerformance = false;
12175
- this._marks = {};
12176
- this._measures = {};
12231
+ this.marks = new Set();
12232
+ this.measures = new Set();
12177
12233
  }
12178
12234
  initialize() {
12179
12235
  this._measuringPerformance = true;
12180
12236
  this._markPerformance('initialize');
12181
- // temporary clear interval while working on send implementation
12182
12237
  this.interval = setInterval(() => {
12183
- this._clearMarksAndMeasures();
12184
- }, 1000 * 60 * 10);
12238
+ this.send();
12239
+ }, PERF_INTERVAL);
12185
12240
  return () => {
12186
12241
  this.teardown();
12187
12242
  };
12188
12243
  }
12189
12244
  teardown() {
12190
12245
  this._measuringPerformance = false;
12191
- this._markPerformance('teardown');
12192
12246
  this._clearMarksAndMeasures();
12193
12247
  clearInterval(this.interval);
12194
12248
  }
@@ -12199,16 +12253,29 @@ class PerformanceMonitor {
12199
12253
  this._markPerformance(`${name}-stop`);
12200
12254
  this._measurePerformance(name);
12201
12255
  }
12202
- track(name) {
12203
- this._markPerformance(name);
12256
+ count(name, incr = 1) {
12257
+ this._markPerformance(name, {
12258
+ detail: { type: 'count', incr }
12259
+ });
12204
12260
  }
12205
12261
  send() {
12206
- performance.getEntries();
12207
- // TODO: implement filter/send process
12262
+ const metrics = _.reduce(_.keys(Metrics), (acc, name) => {
12263
+ const entries = performance.getEntriesByName(name);
12264
+ const value = Metrics[name].instrument(entries);
12265
+ acc.push({ name, value });
12266
+ return acc;
12267
+ }, []);
12268
+ const payload = _.filter(metrics, (metric) => {
12269
+ return metric.value > 0;
12270
+ });
12208
12271
  this._clearMarksAndMeasures();
12272
+ if (_.size(payload)) {
12273
+ writeMetricsPOST(payload);
12274
+ }
12209
12275
  }
12210
12276
  _checkPerformanceApi() {
12211
- return detectNativeBrowserAPI('performance.mark') &&
12277
+ return ConfigReader.get('performanceMetricsEnabled') &&
12278
+ detectNativeBrowserAPI('performance.mark') &&
12212
12279
  detectNativeBrowserAPI('performance.measure') &&
12213
12280
  detectNativeBrowserAPI('performance.getEntries') &&
12214
12281
  detectNativeBrowserAPI('performance.getEntriesByName') &&
@@ -12218,12 +12285,12 @@ class PerformanceMonitor {
12218
12285
  _shouldMeasurePerformance() {
12219
12286
  return this._isPerformanceApiAvailable && this._measuringPerformance;
12220
12287
  }
12221
- _markPerformance(name) {
12288
+ _markPerformance(name, attr) {
12222
12289
  if (!this._shouldMeasurePerformance())
12223
12290
  return;
12224
12291
  name = `pendo-${name}`;
12225
12292
  performance.mark(name);
12226
- this._count(this._marks, name);
12293
+ this.marks.add(name);
12227
12294
  }
12228
12295
  _measurePerformance(name) {
12229
12296
  if (!this._shouldMeasurePerformance())
@@ -12233,29 +12300,24 @@ class PerformanceMonitor {
12233
12300
  const stopMark = `${name}-stop`;
12234
12301
  if (performance.getEntriesByName(startMark).length && performance.getEntriesByName(stopMark).length) {
12235
12302
  performance.measure(name, startMark, stopMark);
12236
- this._count(this._measures, name);
12237
- }
12238
- }
12239
- _count(registry, name) {
12240
- if (!registry[name]) {
12241
- registry[name] = 1;
12242
- }
12243
- else {
12244
- registry[name]++;
12303
+ this.measures.add(name);
12245
12304
  }
12246
12305
  }
12247
12306
  _clearMarksAndMeasures() {
12248
- _.each(this._marks, (count, name) => {
12307
+ // TODO: fix custom lint rule to handle sets
12308
+ // eslint-disable-next-line agent-eslint-rules/no-array-foreach
12309
+ this.marks.forEach(name => {
12249
12310
  performance.clearMarks(name);
12250
12311
  });
12251
- _.each(this._measures, (count, name) => {
12312
+ this.marks.clear();
12313
+ // eslint-disable-next-line agent-eslint-rules/no-array-foreach
12314
+ this.measures.forEach(name => {
12252
12315
  performance.clearMeasures(name);
12253
12316
  });
12254
- this._marks = {};
12255
- this._measures = {};
12317
+ this.measures.clear();
12256
12318
  }
12257
12319
  }
12258
- var PerformanceMonitor$1 = new PerformanceMonitor();
12320
+ const _PerformanceMonitor = new PerformanceMonitor();
12259
12321
 
12260
12322
  var defaultTrackName = '_PENDO_UNNAMED_';
12261
12323
  var SILO_AVG_COMPRESSION_RATIO = 5;
@@ -12757,7 +12819,7 @@ function createSendQueue(options, send, guaranteedSend) {
12757
12819
  }
12758
12820
  });
12759
12821
  queue.onTimeout = function () {
12760
- PerformanceMonitor$1.track(`${options.beacon}-gif-failure`);
12822
+ _PerformanceMonitor.track(`${options.beacon}-gif-failure`);
12761
12823
  };
12762
12824
  queue.retryPending = true;
12763
12825
  return queue;
@@ -13287,7 +13349,7 @@ var getValidTarget = function (node) {
13287
13349
  */
13288
13350
  var handle_event = function (evt) {
13289
13351
  try {
13290
- PerformanceMonitor$1.startTimer('event-captured');
13352
+ _PerformanceMonitor.startTimer('event-captured');
13291
13353
  if (dom.data.get(evt, 'counted'))
13292
13354
  return;
13293
13355
  dom.data.set(evt, 'counted', true);
@@ -13328,7 +13390,7 @@ var handle_event = function (evt) {
13328
13390
  log.critical('pendo.io while handling event', { error: e });
13329
13391
  }
13330
13392
  finally {
13331
- PerformanceMonitor$1.stopTimer('event-captured');
13393
+ _PerformanceMonitor.stopTimer('event-captured');
13332
13394
  }
13333
13395
  };
13334
13396
  function getClickEventProperties(target) {
@@ -13456,7 +13518,7 @@ function wireSyntheticClicks(handle_event, attach, interceptElementRemoval, inte
13456
13518
  ignoreNextClick = false;
13457
13519
  if (!e || !downEvent)
13458
13520
  return;
13459
- if (interceptMouseUp && getTarget(downEvent) !== getTarget(e)) {
13521
+ if (interceptMouseUp && getTarget(downEvent) !== getTarget(e) && isInDocument(getTarget(downEvent))) {
13460
13522
  ignoreNextClick = true;
13461
13523
  handle_event(downEvent);
13462
13524
  }
@@ -16875,7 +16937,7 @@ function sizeElements(guide) {
16875
16937
  const targetEleGrowHeightParent = targetEle.parentNode.closest('[data-pendo-grow-height="true"]');
16876
16938
  if (targetEleGrowHeightParent) {
16877
16939
  // Sizing will be ineffective on nested elements of grow height elements that are not resized, so skip if grow height parent is not sized
16878
- if (!sizedElements.includes(targetEleGrowHeightParent))
16940
+ if (!_.contains(sizedElements, targetEleGrowHeightParent))
16879
16941
  continue;
16880
16942
  containerEle = targetEleGrowHeightParent;
16881
16943
  }
@@ -21167,6 +21229,7 @@ class UpdateRunner {
21167
21229
  monitor.start();
21168
21230
  promise = currentPhase.process(monitor);
21169
21231
  if (!promise && monitor.isTimeExceeded()) {
21232
+ _PerformanceMonitor.count(METRIC_GUIDELOOP_TIMEOUT);
21170
21233
  if (currentPhase.handleProcessTimeExceeded) {
21171
21234
  currentPhase.handleProcessTimeExceeded(monitor);
21172
21235
  }
@@ -21355,6 +21418,7 @@ class GuideTypeIdentifier {
21355
21418
  const GuideMonitor = (() => {
21356
21419
  const guideTypeMap = {};
21357
21420
  const onFetchFail = ({ data }) => {
21421
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
21358
21422
  const [contentContainer, error] = data;
21359
21423
  const { guideId } = contentContainer;
21360
21424
  const guide = findGuideById(guideId);
@@ -23961,35 +24025,37 @@ function onTurbolinksPageLoad(document, onPageLoad, beforeTurboCache) {
23961
24025
  };
23962
24026
  }
23963
24027
 
23964
- var EMPTY_ARRAY_JZB = 'eJwFwIEIAAAAwDDQd3-N1QABFQC5';
23965
- var AD_BLOCK_STORAGE_KEY = 'guides_blocked';
23966
- var GUIDE_GIF_BLOCKED = '1';
23967
- var GUIDE_GIF_NOT_BLOCKED = '0';
23968
- var GUIDE_GIF_BLOCKED_MSG = 'Guides disabled: unreachable endpoint guide.gif';
24028
+ const EMPTY_ARRAY_JZB = 'eJwFwIEIAAAAwDDQd3-N1QABFQC5';
24029
+ const AD_BLOCK_STORAGE_KEY = 'guides_blocked';
24030
+ const BLOCKED_STORAGE_DURATION = 1800000; // 30 minutes
24031
+ const NOT_BLOCKED_STORAGE_DURATION = 14400000; // 4 hours
24032
+ const GUIDE_GIF_BLOCKED = '1';
24033
+ const GUIDE_GIF_NOT_BLOCKED = '0';
24034
+ const GUIDE_GIF_BLOCKED_MSG = 'Guides disabled: unreachable endpoint guide.gif';
23969
24035
  function areGuidesBlocked() {
23970
- var blocked = agentStorage.read(AD_BLOCK_STORAGE_KEY);
24036
+ const blocked = agentStorage.read(AD_BLOCK_STORAGE_KEY);
23971
24037
  return blocked === GUIDE_GIF_BLOCKED;
23972
24038
  }
23973
24039
  function setGuidesBlocked(testGuideGifResult) {
23974
24040
  if (testGuideGifResult.cached)
23975
24041
  return;
23976
24042
  if (testGuideGifResult.success) {
23977
- agentStorage.write(AD_BLOCK_STORAGE_KEY, GUIDE_GIF_NOT_BLOCKED);
24043
+ agentStorage.write(AD_BLOCK_STORAGE_KEY, GUIDE_GIF_NOT_BLOCKED, NOT_BLOCKED_STORAGE_DURATION);
23978
24044
  }
23979
24045
  else {
23980
24046
  log.info(GUIDE_GIF_BLOCKED_MSG);
23981
- agentStorage.write(AD_BLOCK_STORAGE_KEY, GUIDE_GIF_BLOCKED);
24047
+ agentStorage.write(AD_BLOCK_STORAGE_KEY, GUIDE_GIF_BLOCKED, BLOCKED_STORAGE_DURATION);
23982
24048
  }
23983
24049
  }
23984
24050
  function testGuideGifEndpoint(loader, apiKey) {
23985
- var blocked = agentStorage.read(AD_BLOCK_STORAGE_KEY);
24051
+ const blocked = agentStorage.read(AD_BLOCK_STORAGE_KEY);
23986
24052
  if (blocked === GUIDE_GIF_BLOCKED) {
23987
24053
  log.info(GUIDE_GIF_BLOCKED_MSG);
23988
24054
  return q.resolve({ success: false, cached: true });
23989
24055
  }
23990
24056
  if (blocked === GUIDE_GIF_NOT_BLOCKED)
23991
24057
  return q.resolve({ success: true, cached: true });
23992
- var url = buildBaseDataUrl('guide.gif', apiKey, {
24058
+ const url = buildBaseDataUrl('guide.gif', apiKey, {
23993
24059
  jzb: EMPTY_ARRAY_JZB,
23994
24060
  ct: getNow(),
23995
24061
  v: VERSION
@@ -27636,7 +27702,7 @@ var ResourceCenterActivity = (function () {
27636
27702
  }
27637
27703
  function getResourceCenterModule(appData) {
27638
27704
  var classes = appData.cls.split(' ');
27639
- if (classes.indexOf('_pendo-resource-center-module-list-item') !== -1) {
27705
+ if (_.contains(classes, '_pendo-resource-center-module-list-item')) {
27640
27706
  var moduleElement = dom('#' + appData.id).closest('[data-pendo-module-guide-id]');
27641
27707
  return { type: 'BUTTON', elementId: moduleElement.attr('data-pendo-module-guide-id') };
27642
27708
  }
@@ -27651,8 +27717,8 @@ var ResourceCenterActivity = (function () {
27651
27717
  }
27652
27718
  function getResourceCenterModuleItem(appData) {
27653
27719
  var classes = appData.cls.split(' ');
27654
- if (classes.indexOf('_pendo-resource-center-guidelist-module-listed-guide') !== -1 ||
27655
- classes.indexOf('_pendo-resource-center-onboarding-module-listed-guide') !== -1) {
27720
+ if (_.contains(classes, '_pendo-resource-center-guidelist-module-listed-guide') ||
27721
+ _.contains(classes, '_pendo-resource-center-onboarding-module-listed-guide')) {
27656
27722
  const activeRC = BuildingBlockResourceCenter.getResourceCenter();
27657
27723
  if (activeRC) {
27658
27724
  var itemIndex = appData.id.split('-').pop();
@@ -28101,7 +28167,7 @@ const initialize = makeSafe(function (options) {
28101
28167
  Events.appUsage.on(GuideActivity.handler);
28102
28168
  Events.appUsage.on(ResourceCenterActivity.handler);
28103
28169
  teardownFns.push(flushEvery(SEND_INTERVAL));
28104
- teardownFns.push(PerformanceMonitor$1.initialize());
28170
+ teardownFns.push(_PerformanceMonitor.initialize());
28105
28171
  }
28106
28172
  Events.appHidden.on(() => {
28107
28173
  flushNow(true, { hidden: true });
@@ -29352,7 +29418,7 @@ var validateNativeMethods = function (skipLogging) {
29352
29418
  _.each(keys, function (propName) {
29353
29419
  try {
29354
29420
  if (propName && nativeType[propName] && typeof nativeType[propName] === 'function') {
29355
- var isNativeImplementation = nativeType[propName].toString().includes('[native code]');
29421
+ var isNativeImplementation = nativeType[propName].toString().indexOf('[native code]') !== -1;
29356
29422
  if (!isNativeImplementation)
29357
29423
  nonNativeImplementations.push(propName);
29358
29424
  }
@@ -29758,8 +29824,8 @@ UrlTransform.fromJSON = function (obj) {
29758
29824
  }
29759
29825
  catch (error) {
29760
29826
  // If it's already a detailed error from our validation, re-throw it
29761
- if (error.message.includes('Invalid attribute') || error.message.includes('Invalid action') ||
29762
- error.message.includes('requires') || error.message.includes('expects')) {
29827
+ if (error.message.indexOf('Invalid attribute') !== -1 || error.message.indexOf('Invalid action') !== -1 ||
29828
+ error.message.indexOf('requires') !== -1 || error.message.indexOf('expects') !== -1) {
29763
29829
  throw error;
29764
29830
  }
29765
29831
  // Otherwise, wrap the original error with context
@@ -33140,12 +33206,12 @@ var GuideUpdateModule = (function () {
33140
33206
  state.scheduledUpdate = scheduledUpdate;
33141
33207
  },
33142
33208
  startUpdate(state, time) {
33143
- PerformanceMonitor$1.startTimer('guide-loop');
33209
+ _PerformanceMonitor.startTimer('guide-loop');
33144
33210
  state.needsUpdate = false;
33145
33211
  state.updateId = time;
33146
33212
  },
33147
33213
  completeUpdate(state, time) {
33148
- PerformanceMonitor$1.stopTimer('guide-loop');
33214
+ _PerformanceMonitor.stopTimer('guide-loop');
33149
33215
  state.updateId = null;
33150
33216
  state.updateCompleteTime = time;
33151
33217
  }
@@ -37652,7 +37718,7 @@ const buildGuideBehaviors = function ({ globalPendo, pluginApi }) {
37652
37718
  const firstStep = _.first(guide.steps);
37653
37719
  if (guide.forceShowFirstStep) {
37654
37720
  guide.forceShowFirstStep = false;
37655
- return firstStep.show('reason');
37721
+ return firstStep.show(reason);
37656
37722
  }
37657
37723
  const steps = guide.steps.map((step) => {
37658
37724
  // The stored step state is most up to date. Fallback to the guides payload
@@ -38242,7 +38308,7 @@ const paidMediumRegex = new RegExp('^(.*cp.*|ppc|retargeting|paid)$');
38242
38308
  // add other email-related values here, if needed
38243
38309
  const emailRegex = new RegExp('(.*email.*|.*e_mail.*|.*e mail.*|.*e-mail.*)', 'i');
38244
38310
  function utmIncludesValue(utm = '', value) {
38245
- return utm.replace(/[^a-zA-Z]/g, '').includes(value);
38311
+ return utm.replace(/[^a-zA-Z]/g, '').indexOf(value) !== -1;
38246
38312
  }
38247
38313
  // order is critical here, as the first match is returned, consider this when adding new channels and updating conditions
38248
38314
  const channels = [
@@ -39662,6 +39728,7 @@ const PollBranching = {
39662
39728
  .attr({ title: 'Custom Branching Added' });
39663
39729
  let dataPendoPollId = question.getAttribute('data-pendo-poll-id');
39664
39730
  if (pendo.dom(`._pendo-multi-choice-poll-question[data-pendo-poll-id=${dataPendoPollId}]`)[0]) {
39731
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
39665
39732
  pendo
39666
39733
  .dom(`._pendo-multi-choice-poll-question[data-pendo-poll-id=${dataPendoPollId}]`)[0]
39667
39734
  .textContent.trim();
@@ -40062,7 +40129,7 @@ const RequiredQuestions = {
40062
40129
  return input[0].value;
40063
40130
  }
40064
40131
  }));
40065
- if (responses.includes(undefined) || pendo._.isEmpty(responses)) {
40132
+ if (pendo._.contains(responses, undefined) || pendo._.isEmpty(responses)) {
40066
40133
  allRequiredComplete = false;
40067
40134
  }
40068
40135
  if (allRequiredComplete) {
@@ -40095,6 +40162,7 @@ const RequiredQuestions = {
40095
40162
  return !pendo._.isUndefined(requiredQuestions) && pendo._.size(requiredQuestions);
40096
40163
  },
40097
40164
  designerListener(pendo) {
40165
+ const requiredQuestions = [];
40098
40166
  const target = pendo.dom.getBody();
40099
40167
  const config = {
40100
40168
  attributeFilter: ['data-layout'],
@@ -40126,7 +40194,7 @@ const RequiredQuestions = {
40126
40194
  if (pendo.dom(`[class*="-poll-question"][data-pendo-poll-id=${dataPendoPollId}]`)[0]) {
40127
40195
  questionText = pendo.dom(`[class*="-poll-question"][data-pendo-poll-id=${dataPendoPollId}]`)[0].textContent;
40128
40196
  }
40129
- if (questionText.includes('{required/}')) {
40197
+ if (pendo._.contains(questionText, '{required/}')) {
40130
40198
  pendo._.each(pendo.dom(`[data-pendo-poll-id=${dataPendoPollId}]:not(.pendo-radio)`), (element) => {
40131
40199
  pendo._.each(pendo.dom(`#${element.id} *:not(".pendo-radio"), #${element.id}:not(".pendo-radio")`), (item) => {
40132
40200
  guideMarkdownUtil.removeMarkdownSyntax(item, '{required/}', '', pendo);
@@ -40139,6 +40207,23 @@ const RequiredQuestions = {
40139
40207
  else {
40140
40208
  pendo.dom(`.bb-text[data-pendo-poll-id=${dataPendoPollId}]`).append(requiredElement);
40141
40209
  }
40210
+ if (pendo._.contains(requiredQuestions, dataPendoPollId)) {
40211
+ let questionIndex = requiredQuestions.indexOf(dataPendoPollId);
40212
+ if (questionIndex !== -1) {
40213
+ requiredQuestions.splice(questionIndex, 1);
40214
+ }
40215
+ }
40216
+ else {
40217
+ requiredQuestions.push(dataPendoPollId);
40218
+ }
40219
+ }
40220
+ else {
40221
+ if (pendo._.contains(requiredQuestions, dataPendoPollId)) {
40222
+ let index = requiredQuestions.indexOf(dataPendoPollId);
40223
+ if (index !== -1) {
40224
+ requiredQuestions.splice(index, 1);
40225
+ }
40226
+ }
40142
40227
  }
40143
40228
  });
40144
40229
  }
@@ -40214,8 +40299,8 @@ const SkipToEligibleStep = {
40214
40299
  },
40215
40300
  test(step, guide, pendo) {
40216
40301
  var _a;
40217
- let guideContainerAriaLabel = (_a = step.guideElement) === null || _a === void 0 ? void 0 : _a.find('#pendo-guide-container').attr('aria-label');
40218
- return !pendo._.isUndefined(guideContainerAriaLabel) && (guideContainerAriaLabel === null || guideContainerAriaLabel === void 0 ? void 0 : guideContainerAriaLabel.includes('{skipStep'));
40302
+ const guideContainerAriaLabel = (_a = step.guideElement) === null || _a === void 0 ? void 0 : _a.find('#pendo-guide-container').attr('aria-label');
40303
+ return pendo._.isString(guideContainerAriaLabel) && guideContainerAriaLabel.indexOf('{skipStep') !== -1;
40219
40304
  },
40220
40305
  designerListener(pendo) {
40221
40306
  const target = pendo.dom.getBody();
@@ -41273,7 +41358,7 @@ function VocPortal() {
41273
41358
  return;
41274
41359
  }
41275
41360
  const validUnits = ['px', '%', 'vh', 'vw'];
41276
- if (!validUnits.includes(widthUnit) || !validUnits.includes(heightUnit)) {
41361
+ if (!pendoGlobal._.contains(validUnits, widthUnit) || !pendoGlobal._.contains(validUnits, heightUnit)) {
41277
41362
  return;
41278
41363
  }
41279
41364
  const width = `${widthValue}${widthUnit}${widthIsImportant ? ' !important' : ''}`;
@@ -45982,7 +46067,7 @@ class IframeManager {
45982
46067
  this.loadListener = cb;
45983
46068
  }
45984
46069
  attachIframe(iframeEl, childSn) {
45985
- var _a2, _b;
46070
+ var _a2, _b, _c;
45986
46071
  this.mutationCb({
45987
46072
  adds: [
45988
46073
  {
@@ -45996,12 +46081,16 @@ class IframeManager {
45996
46081
  attributes: [],
45997
46082
  isAttachIframe: true
45998
46083
  });
45999
- if (this.recordCrossOriginIframes)
46084
+ if (this.recordCrossOriginIframes) {
46000
46085
  (_a2 = iframeEl.contentWindow) == null ? void 0 : _a2.addEventListener(
46001
46086
  "message",
46002
46087
  this.handleMessage.bind(this)
46003
46088
  );
46004
- (_b = this.loadListener) == null ? void 0 : _b.call(this, iframeEl);
46089
+ (_b = iframeEl.contentWindow) == null ? void 0 : _b.addEventListener("pagehide", () => {
46090
+ this.crossOriginIframeMap.delete(iframeEl.contentWindow);
46091
+ });
46092
+ }
46093
+ (_c = this.loadListener) == null ? void 0 : _c.call(this, iframeEl);
46005
46094
  if (iframeEl.contentDocument && iframeEl.contentDocument.adoptedStyleSheets && iframeEl.contentDocument.adoptedStyleSheets.length > 0)
46006
46095
  this.stylesheetManager.adoptStyleSheets(
46007
46096
  iframeEl.contentDocument.adoptedStyleSheets,
@@ -54373,6 +54462,16 @@ function scrubPII(string) {
54373
54462
  return Object.values(PII_PATTERN).reduce((str, pattern) => str.replace(pattern, PII_REPLACEMENT), string);
54374
54463
  }
54375
54464
 
54465
+ /**
54466
+ * Helper function to check if a string includes a substring (legacy IE compatible).
54467
+ *
54468
+ * @param {string} str - The string to search in
54469
+ * @param {string} substring - The substring to search for
54470
+ * @returns {boolean} True if the substring is found, false otherwise
54471
+ */
54472
+ function includes(str, substring) {
54473
+ return str.indexOf(substring) !== -1;
54474
+ }
54376
54475
  /**
54377
54476
  * Determines the type of resource that was blocked based on the blocked URI and CSP directive.
54378
54477
  *
@@ -54391,47 +54490,47 @@ function getResourceType(blockedURI, directive) {
54391
54490
  return 'resource';
54392
54491
  const d = directive.toLowerCase();
54393
54492
  if (blockedURI === 'inline') {
54394
- if (d.includes('script-src-attr')) {
54493
+ if (includes(d, 'script-src-attr')) {
54395
54494
  return 'inline event handler';
54396
54495
  }
54397
- if (d.includes('style-src-attr')) {
54496
+ if (includes(d, 'style-src-attr')) {
54398
54497
  return 'inline style attribute';
54399
54498
  }
54400
- if (d.includes('script')) {
54499
+ if (includes(d, 'script')) {
54401
54500
  return 'inline script';
54402
54501
  }
54403
- if (d.includes('style')) {
54502
+ if (includes(d, 'style')) {
54404
54503
  return 'inline style';
54405
54504
  }
54406
54505
  }
54407
54506
  if (blockedURI === 'eval') {
54408
54507
  return 'eval script execution';
54409
54508
  }
54410
- if (d.includes('worker'))
54509
+ if (includes(d, 'worker'))
54411
54510
  return 'worker';
54412
- if (d.includes('script')) {
54413
- return d.includes('elem') ? 'script element' : 'script';
54511
+ if (includes(d, 'script')) {
54512
+ return includes(d, 'elem') ? 'script element' : 'script';
54414
54513
  }
54415
- if (d.includes('style')) {
54416
- return d.includes('elem') ? 'style element' : 'stylesheet';
54514
+ if (includes(d, 'style')) {
54515
+ return includes(d, 'elem') ? 'style element' : 'stylesheet';
54417
54516
  }
54418
- if (d.includes('img'))
54517
+ if (includes(d, 'img'))
54419
54518
  return 'image';
54420
- if (d.includes('font'))
54519
+ if (includes(d, 'font'))
54421
54520
  return 'font';
54422
- if (d.includes('connect'))
54521
+ if (includes(d, 'connect'))
54423
54522
  return 'network request';
54424
- if (d.includes('media'))
54523
+ if (includes(d, 'media'))
54425
54524
  return 'media resource';
54426
- if (d.includes('frame-ancestors'))
54525
+ if (includes(d, 'frame-ancestors'))
54427
54526
  return 'display of your page in a frame';
54428
- if (d.includes('frame'))
54527
+ if (includes(d, 'frame'))
54429
54528
  return 'frame';
54430
- if (d.includes('manifest'))
54529
+ if (includes(d, 'manifest'))
54431
54530
  return 'manifest';
54432
- if (d.includes('base-uri'))
54531
+ if (includes(d, 'base-uri'))
54433
54532
  return 'base URI';
54434
- if (d.includes('form-action'))
54533
+ if (includes(d, 'form-action'))
54435
54534
  return 'form submission';
54436
54535
  return 'resource';
54437
54536
  }
@@ -54475,7 +54574,7 @@ function getArticle(phrase) {
54475
54574
  if (!phrase || typeof phrase !== 'string')
54476
54575
  return 'A';
54477
54576
  const c = phrase.trim().charAt(0).toLowerCase();
54478
- return 'aeiou'.includes(c) ? 'An' : 'A';
54577
+ return includes('aeiou', c) ? 'An' : 'A';
54479
54578
  }
54480
54579
  /**
54481
54580
  * Returns the original blocked URI when it looks like a URL or scheme,
@@ -54569,7 +54668,7 @@ class ConsoleCaptureBuffer {
54569
54668
  }
54570
54669
  push(event) {
54571
54670
  const { devLogLevel } = event;
54572
- if (!DEV_LOG_LEVELS.includes(devLogLevel))
54671
+ if (!this.pendo._.contains(DEV_LOG_LEVELS, devLogLevel))
54573
54672
  return false;
54574
54673
  this.refillTokens();
54575
54674
  if (this.tokens === 0)
@@ -55774,6 +55873,7 @@ var ConfigReader = (function () {
55774
55873
  addOption('enableAllEmbeddedGuideEvents', [PENDO_CONFIG_SRC], false);
55775
55874
  // Form Validation
55776
55875
  addOption('formValidation', [PENDO_CONFIG_SRC], false);
55876
+ addOption('performanceMetricsEnabled', [SNIPPET_SRC, PENDO_CONFIG_SRC], true);
55777
55877
  }
55778
55878
  initializeOptions();
55779
55879
  var sourceGetters = {};
@@ -56054,10 +56154,10 @@ store.subscribe(function (mutation, state) {
56054
56154
  // console.log(mutation, JSON.parse(JSON.stringify(state)));
56055
56155
  });
56056
56156
 
56057
- var EXTENSION_INSTALL_TYPE = 'extension';
56058
- var NATIVE_INSTALL_TYPE = 'native';
56157
+ const EXTENSION_INSTALL_TYPE = 'extension';
56158
+ const NATIVE_INSTALL_TYPE = 'native';
56059
56159
  function getInstallType() {
56060
- var installType = ConfigReader.get('installType') || getPendoConfigFromEnclosingScope().installType;
56160
+ const installType = ConfigReader.get('installType') || getPendoConfigFromEnclosingScope().installType;
56061
56161
  return installType || NATIVE_INSTALL_TYPE;
56062
56162
  }
56063
56163
  function isExtensionAgent() {
@@ -56580,7 +56680,7 @@ class ConsoleTransport {
56580
56680
  }
56581
56681
  params.jzb = jzb;
56582
56682
  const queryString = this.pendo._.map(params, (value, key) => `${key}=${value}`).join('&');
56583
- return `${baseUrl}${baseUrl.includes('?') ? '&' : '?'}${queryString}`;
56683
+ return `${baseUrl}${baseUrl.indexOf('?') !== -1 ? '&' : '?'}${queryString}`;
56584
56684
  }
56585
56685
  get(url, options) {
56586
56686
  options.method = 'GET';