@pendo/agent 2.313.0 → 2.314.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.
@@ -3389,7 +3389,6 @@ var ConfigReader = (function () {
3389
3389
  * @type {number}
3390
3390
  */
3391
3391
  addOption('guideSeenTimeoutLength', [PENDO_CONFIG_SRC, SNIPPET_SRC], 10000);
3392
- // addOption('guideTimeout', [SNIPPET_SRC]); // old, use guides.timeout instead
3393
3392
  /**
3394
3393
  * If `true`, guides will be verified against their saved content hash before display to ensure validity of
3395
3394
  * guide content.
@@ -3946,8 +3945,8 @@ let SERVER = '';
3946
3945
  let ASSET_HOST = '';
3947
3946
  let ASSET_PATH = '';
3948
3947
  let DESIGNER_SERVER = '';
3949
- let VERSION = '2.313.0_';
3950
- let PACKAGE_VERSION = '2.313.0';
3948
+ let VERSION = '2.314.0_';
3949
+ let PACKAGE_VERSION = '2.314.0';
3951
3950
  let LOADER = 'xhr';
3952
3951
  /* eslint-enable web-sdk-eslint-rules/no-gulp-env-references */
3953
3952
  /**
@@ -12275,16 +12274,17 @@ var JWT = (function () {
12275
12274
  };
12276
12275
  })();
12277
12276
 
12278
- const MAX_BACKOFF = 6;
12279
- const MAX_FAILURES = 100;
12277
+ const MAX_RETRY_DELAY_MS = 5 * 60 * 1000; // 5 minutes
12278
+ const ONE_HOUR = 60 * 60 * 1000; // 1 hour
12279
+ const FAILURE_WINDOW_MS = 2 * ONE_HOUR;
12280
12280
  class SendQueue {
12281
- constructor(sendFn, maxFailures = MAX_FAILURES) {
12281
+ constructor(sendFn) {
12282
12282
  this.queue = [];
12283
12283
  this.unloads = new Set();
12284
12284
  this.pending = new Set();
12285
12285
  this.failures = new Map();
12286
+ this.firstFailureTime = null;
12286
12287
  this.sendFn = sendFn;
12287
- this.maxFailures = maxFailures;
12288
12288
  }
12289
12289
  isEmpty() {
12290
12290
  return this.queue.length <= 0;
@@ -12294,6 +12294,7 @@ class SendQueue {
12294
12294
  this.unloads.clear();
12295
12295
  this.pending.clear();
12296
12296
  this.failures.clear();
12297
+ this.firstFailureTime = null;
12297
12298
  this.stopped = true;
12298
12299
  clearTimeout(this.timer);
12299
12300
  delete this.timer;
@@ -12314,12 +12315,16 @@ class SendQueue {
12314
12315
  incrementFailure(payload) {
12315
12316
  const failureCount = (this.failures.get(payload) || 0) + 1;
12316
12317
  this.failures.set(payload, failureCount);
12318
+ if (this.firstFailureTime == null) {
12319
+ this.firstFailureTime = new Date().getTime();
12320
+ }
12317
12321
  return failureCount;
12318
12322
  }
12319
12323
  pass(payload, dequeue = true) {
12320
12324
  this.unloads.delete(payload);
12321
12325
  this.pending.delete(payload);
12322
- this.failures.clear();
12326
+ this.failures.delete(payload);
12327
+ this.firstFailureTime = null;
12323
12328
  const index = this.queue.indexOf(payload);
12324
12329
  if (index >= 0) {
12325
12330
  this.queue.splice(index, 1);
@@ -12334,18 +12339,26 @@ class SendQueue {
12334
12339
  const failureCount = this.incrementFailure(payload);
12335
12340
  if (this.stopped || !retry)
12336
12341
  return;
12337
- if (failureCount >= this.maxFailures) {
12342
+ const now = new Date().getTime();
12343
+ const elapsed = now - (this.firstFailureTime || now);
12344
+ if (elapsed >= FAILURE_WINDOW_MS) {
12338
12345
  if (this.onTimeout) {
12339
12346
  this.onTimeout();
12340
12347
  }
12341
- this.pass(payload, false);
12348
+ this.firstFailureTime = null;
12349
+ this.retryLater(ONE_HOUR);
12350
+ return;
12342
12351
  }
12343
- this.retryLater(Math.pow(2, Math.min(failureCount - 1, MAX_BACKOFF)) * 1000);
12352
+ this.retryLater(Math.min(Math.pow(2, failureCount - 1) * 1000, MAX_RETRY_DELAY_MS));
12353
+ }
12354
+ retryNow() {
12355
+ clearTimeout(this.timer);
12356
+ delete this.timer;
12357
+ this.next();
12344
12358
  }
12345
12359
  retryLater(delay) {
12346
12360
  this.timer = setTimeout$1(() => {
12347
- delete this.timer;
12348
- this.next();
12361
+ this.retryNow();
12349
12362
  }, delay);
12350
12363
  }
12351
12364
  failed() {
@@ -12360,7 +12373,7 @@ class SendQueue {
12360
12373
  }
12361
12374
  drain(finalPayloadArray, isUnload = true) {
12362
12375
  this.queue.push(...finalPayloadArray);
12363
- if (this.failed())
12376
+ if (this.failed() && !this.allowDrainWhileFailed)
12364
12377
  return Promise$2.reject();
12365
12378
  const promises = [];
12366
12379
  for (const payload of this.queue) {
@@ -12379,7 +12392,7 @@ class SendQueue {
12379
12392
  }
12380
12393
 
12381
12394
  const UNSENT_EVENTS_KEY = 'unsentEvents';
12382
- const UNSENT_EVENTS_DURATION = 6 * 24 * 60 * 60 * 1000; // 6 days
12395
+ const UNSENT_EVENTS_MAX_AGE = 7 * 24 * 60 * 60 * 1000; // 7 days
12383
12396
  class LocalStorageEventBuffer {
12384
12397
  constructor() {
12385
12398
  this.events = {};
@@ -12421,7 +12434,7 @@ class LocalStorageEventBuffer {
12421
12434
  }
12422
12435
  write(storage) {
12423
12436
  if (_.size(this.events) > 0) {
12424
- storage.write(UNSENT_EVENTS_KEY, JSON.stringify(this.events), UNSENT_EVENTS_DURATION);
12437
+ storage.write(UNSENT_EVENTS_KEY, JSON.stringify(this.events), UNSENT_EVENTS_MAX_AGE);
12425
12438
  }
12426
12439
  else {
12427
12440
  storage.clear(UNSENT_EVENTS_KEY);
@@ -12920,6 +12933,7 @@ function addSiloParams(options) {
12920
12933
  silo.params = _.extend({}, silo.params, options.params);
12921
12934
  silo.beacon = options.beacon;
12922
12935
  silo.eventLength = silo.JZB.length;
12936
+ silo.ts = silo[0].browser_time || getNow();
12923
12937
  var jwtOptions = JWT.get();
12924
12938
  if (!_.isEmpty(jwtOptions)) {
12925
12939
  silo.auth = jwtOptions;
@@ -13110,6 +13124,9 @@ function createSendQueue(options, send, guaranteedSend) {
13110
13124
  const apiKeys = getApiKeysFromOptions(options);
13111
13125
  const queues = _.map(apiKeys, (apiKey, i) => {
13112
13126
  const queue = new SendQueue(function (request, isUnload, failureCount) {
13127
+ if (getNow() - request.ts > UNSENT_EVENTS_MAX_AGE) {
13128
+ return q.resolve(); // ignore event if it's too old
13129
+ }
13113
13130
  if (failureCount) {
13114
13131
  request.params = _.extend({}, request.params, {
13115
13132
  rt: failureCount
@@ -13121,7 +13138,10 @@ function createSendQueue(options, send, guaranteedSend) {
13121
13138
  }
13122
13139
  return q.resolve();
13123
13140
  }
13124
- else if (isUnload) {
13141
+ if (isUnload && queue.failed()) {
13142
+ return q.reject();
13143
+ }
13144
+ if (isUnload) {
13125
13145
  return guaranteedSend(apiKey, request);
13126
13146
  }
13127
13147
  else {
@@ -13131,6 +13151,7 @@ function createSendQueue(options, send, guaranteedSend) {
13131
13151
  queue.onTimeout = function () {
13132
13152
  performanceMonitor.count(BEACON_GIF_FAILURES[options.beacon]);
13133
13153
  };
13154
+ queue.allowDrainWhileFailed = true;
13134
13155
  queue.retryPending = true;
13135
13156
  return queue;
13136
13157
  });
@@ -25978,6 +25999,9 @@ var mostRecentGuideRequest;
25978
25999
  var loadGuideJs = function (apiKey, params) {
25979
26000
  var guideRequestId = _.uniqueId();
25980
26001
  var deferred = q.defer();
26002
+ if (mostRecentGuideRequest && mostRecentGuideRequest.deferred) {
26003
+ mostRecentGuideRequest.deferred.reject('newRequest'); // make sure that we don't leave open any promises if multiple guide requests are made in quick succession
26004
+ }
25981
26005
  mostRecentGuideRequest = {
25982
26006
  id: guideRequestId,
25983
26007
  deferred
@@ -26204,8 +26228,7 @@ var loadGuides = function (apiKey, visitorId, page, callback) {
26204
26228
  resetPendoUI();
26205
26229
  var lastGuideStepSeen = pendo$1.lastGuideStepSeen;
26206
26230
  if (!lastGuideStepSeen) {
26207
- log.info('lastGuideStepSeen is not set, shutting down guides');
26208
- return;
26231
+ throw new Error('lastGuideStepSeen is not set, check response from guide payload');
26209
26232
  }
26210
26233
  store.dispatch('guideState/receiveLastGuideStepSeen', lastGuideStepSeen);
26211
26234
  lastGuideStepSeen.visitorId = visitorId;
@@ -26270,6 +26293,12 @@ var loadGuides = function (apiKey, visitorId, page, callback) {
26270
26293
  }
26271
26294
  }
26272
26295
  }).catch(function (err) {
26296
+ if (err === 'newRequest') {
26297
+ log.info('Guide load cancelled due to new request');
26298
+ deferred.resolve('Guide load cancelled due to new request');
26299
+ return;
26300
+ }
26301
+ log.info(`Error in loadGuideJs, shutting down guides, err: ${_.get(err, 'message', err || 'Unknown error')}`);
26273
26302
  Events.guidesFailed.trigger();
26274
26303
  deferred.reject(err);
26275
26304
  });
@@ -38501,7 +38530,6 @@ const FrustrationEvent = (function () {
38501
38530
  // A guide that show nested inside another element.
38502
38531
  // Multiple embedded guides can show at the same time.
38503
38532
  const buildGuideBehaviors = function ({ globalPendo, pluginApi }) {
38504
- const guide = this;
38505
38533
  const { _ } = globalPendo;
38506
38534
  const { store } = pluginApi;
38507
38535
  this.process = function () {
@@ -38558,12 +38586,6 @@ const buildGuideBehaviors = function ({ globalPendo, pluginApi }) {
38558
38586
  const nextStep = guide.nextStep(lastSeenStep) || firstStep;
38559
38587
  return nextStep.show(reason);
38560
38588
  };
38561
- // when embedded guide is initialized set the forceShowFirstStep property.
38562
- // This property is deleted after the guide shows because we no longer want to foce show the first step.
38563
- // The propert is reset on urlChanged events.
38564
- if (!this.hasOwnProperty('forceShowFirstStep')) {
38565
- this.forceShowFirstStep = _.get(guide, 'attributes.restartOnReload');
38566
- }
38567
38589
  this.isShownInThisFrame = function () {
38568
38590
  const guide = this;
38569
38591
  return _.any(guide.steps, function (step) {
@@ -38620,7 +38642,6 @@ const EmbeddedGuides = (function () {
38620
38642
  pluginApi.Events.on('deliverablesLoaded', clearEmbeddedGuides);
38621
38643
  pluginApi.Events.on('guideLoopStopped', onGuidesStopped);
38622
38644
  pluginApi.Events.on('guideListChanged', initializeEmbeddedGuides);
38623
- pluginApi.Events.on('urlChanged', setForceShowFirstStepFlags);
38624
38645
  pluginApi.Events.on('guideAdvanced', hideGuide);
38625
38646
  pluginApi.Events.on('metadata', onMetadataChange);
38626
38647
  pluginApi.Events.on('identify', onIdentify);
@@ -38635,7 +38656,6 @@ const EmbeddedGuides = (function () {
38635
38656
  pluginApi.Events.off('deliverablesLoaded', clearEmbeddedGuides);
38636
38657
  pluginApi.Events.off('guideLoopStopped', onGuidesStopped);
38637
38658
  pluginApi.Events.off('guideListChanged', initializeEmbeddedGuides);
38638
- pluginApi.Events.off('urlChanged', setForceShowFirstStepFlags);
38639
38659
  pluginApi.Events.off('guideAdvanced', hideGuide);
38640
38660
  pluginApi.Events.off('metadata', onMetadataChange);
38641
38661
  pluginApi.Events.off('identify', onIdentify);
@@ -38700,13 +38720,6 @@ const EmbeddedGuides = (function () {
38700
38720
  function onIdentify() {
38701
38721
  setEmbeddedGuideCacheValid(false);
38702
38722
  }
38703
- // This function syncs the forceShowFirstStep with the restartOnReload property on guides
38704
- // This function is run on the urlChanged event.
38705
- function setForceShowFirstStepFlags() {
38706
- _.forEach(embeddedGuides, function (guide) {
38707
- guide.forceShowFirstStep = !!_.get(guide, 'attributes.restartOnReload');
38708
- });
38709
- }
38710
38723
  function extractEmbeddedGuides(guide) {
38711
38724
  if (isEmbedded(guide)) {
38712
38725
  if (!_.some(embeddedGuides, ({ id }) => id === guide.id)) {
@@ -40339,6 +40352,35 @@ class PromptPlugin {
40339
40352
  }
40340
40353
  var PromptAnalytics = new PromptPlugin();
40341
40354
 
40355
+ class RestartOnReload {
40356
+ initialize(pendo, { Events }) {
40357
+ this.pendo = pendo;
40358
+ const { _, attachEvent } = pendo;
40359
+ const boundSetForceShowFirstStepFlags = _.bind(this.setForceShowFirstStepFlags, this);
40360
+ this.subscriptions = [
40361
+ attachEvent(Events, 'deliverablesLoaded', boundSetForceShowFirstStepFlags),
40362
+ attachEvent(Events, 'urlChanged', boundSetForceShowFirstStepFlags)
40363
+ ];
40364
+ }
40365
+ teardown() {
40366
+ this.pendo._.forEach(this.subscriptions, function (unsubscribe) {
40367
+ unsubscribe();
40368
+ });
40369
+ this.subscriptions.length = 0;
40370
+ }
40371
+ setForceShowFirstStepFlags() {
40372
+ const { pendo } = this;
40373
+ const { _ } = pendo;
40374
+ _.forEach(pendo.guides, function (guide) {
40375
+ const restartOnReload = !!_.get(guide, 'attributes.restartOnReload');
40376
+ if (restartOnReload) {
40377
+ guide.forceShowFirstStep = true;
40378
+ }
40379
+ });
40380
+ }
40381
+ }
40382
+ var RestartOnReload$1 = new RestartOnReload();
40383
+
40342
40384
  function registerBuiltInPlugins() {
40343
40385
  registerPlugin(IFrameMonitor);
40344
40386
  registerPlugin(DOMActivation);
@@ -40358,6 +40400,7 @@ function registerBuiltInPlugins() {
40358
40400
  registerPlugin(WebAnalytics$1);
40359
40401
  registerPlugin(FormValidation);
40360
40402
  registerPlugin(PromptAnalytics);
40403
+ registerPlugin(RestartOnReload$1);
40361
40404
  }
40362
40405
 
40363
40406
  /*
@@ -40536,6 +40579,7 @@ const substitutionRegex = '\\{(?:\\s?)([^.\\s]?visitor|account|parentAccount)\\.
40536
40579
  const skipStepString = '{skipStep:* *(auto|\\d+)\\/}';
40537
40580
  const goToMiddleString = '(?!0)(\\d+)';
40538
40581
  const goToString = `({goto-${goToMiddleString}\\/})`;
40582
+ const containerSelector = '[id^="pendo-guide-container"]';
40539
40583
  function lookupGuideButtons(domJson, buttons = []) {
40540
40584
  if (domJson.type === 'button' && domJson.actions) {
40541
40585
  buttons.push(domJson);
@@ -40573,6 +40617,7 @@ var guideMarkdownUtil = {
40573
40617
  substitutionRegex,
40574
40618
  skipStepString,
40575
40619
  goToString,
40620
+ containerSelector,
40576
40621
  lookupGuideButtons,
40577
40622
  removeMarkdownSyntax
40578
40623
  };
@@ -40626,7 +40671,7 @@ const PollBranching = {
40626
40671
  attributes: true,
40627
40672
  childList: true,
40628
40673
  characterData: true,
40629
- subtree: false
40674
+ subtree: true
40630
40675
  };
40631
40676
  const MutationObserver = getZoneSafeMethod$1(pendo._, 'MutationObserver');
40632
40677
  const observer = new MutationObserver(applyBranchingIndicators);
@@ -40745,13 +40790,13 @@ function branchingGoToStep(event, step, guide, pendo) {
40745
40790
  if (pollStepIndex < 0)
40746
40791
  return;
40747
40792
  const destinationObject = {
40748
- destinationStepId: guide.steps[pollStepIndex].id
40793
+ destinationStepId: guide.steps[pollStepIndex].id,
40794
+ step
40749
40795
  };
40750
40796
  pendo.goToStep(destinationObject);
40751
40797
  event.cancel = true;
40752
40798
  }
40753
40799
 
40754
- const containerSelector = '[id^="pendo-guide-container"]';
40755
40800
  const MetadataSubstitution = {
40756
40801
  name: 'MetadataSubstitution',
40757
40802
  script(step, guide, pendo) {
@@ -40775,7 +40820,7 @@ const MetadataSubstitution = {
40775
40820
  attributes: true,
40776
40821
  childList: true,
40777
40822
  characterData: true,
40778
- subtree: false
40823
+ subtree: true
40779
40824
  };
40780
40825
  const MutationObserver = getZoneSafeMethod$1(pendo._, 'MutationObserver');
40781
40826
  const observer = new MutationObserver(applySubstitutionIndicators);
@@ -40784,7 +40829,7 @@ const MetadataSubstitution = {
40784
40829
  pendo._.each(mutations, function (mutation) {
40785
40830
  var _a;
40786
40831
  if (mutation.addedNodes.length) {
40787
- if (document.querySelector(containerSelector)) {
40832
+ if (document.querySelector(guideMarkdownUtil.containerSelector)) {
40788
40833
  const placeholderData = findSubstitutableElements(pendo);
40789
40834
  const step = (_a = pendo.designerv2.currentlyPreviewedGuide) === null || _a === void 0 ? void 0 : _a.steps[0];
40790
40835
  if (!step)
@@ -40851,9 +40896,9 @@ function substituteMetadataByTarget(data, target, mdValue, matched) {
40851
40896
  }
40852
40897
  function updateGuideContainer(containerId, context, pendo) {
40853
40898
  if (pendo.designer && !pendo._.size(pendo.dom('#pendo-ps-substitution-icon'))) {
40854
- pendo.dom(containerSelector).append(substitutionIcon('#999', '30px'));
40899
+ pendo.dom(guideMarkdownUtil.containerSelector).append(substitutionIcon('#999', '30px'));
40855
40900
  }
40856
- pendo.flexElement(pendo.dom(containerSelector));
40901
+ pendo.flexElement(pendo.dom(guideMarkdownUtil.containerSelector));
40857
40902
  pendo.BuildingBlocks.BuildingBlockGuides.recalculateGuideHeight(containerId, context);
40858
40903
  }
40859
40904
  function findSubstitutableUrlsInJson(originalData, placeholderData = [], pendo) {
@@ -40894,7 +40939,7 @@ function findSubstitutableUrlsInJson(originalData, placeholderData = [], pendo)
40894
40939
  return placeholderData;
40895
40940
  }
40896
40941
  function findSubstitutableElements(pendo) {
40897
- let elements = pendo.dom(`${containerSelector} *:not(.pendo-inline-ui)`);
40942
+ let elements = pendo.dom(`${guideMarkdownUtil.containerSelector} *:not(.pendo-inline-ui)`);
40898
40943
  return pendo._.chain(elements)
40899
40944
  .filter(function (placeholder) {
40900
40945
  const subRegex = new RegExp(guideMarkdownUtil.substitutionRegex);
@@ -41002,7 +41047,7 @@ const RequiredQuestions = {
41002
41047
  });
41003
41048
  }
41004
41049
  });
41005
- step.attachEvent(step.guideElement.find('[id^="pendo-guide-container"]')[0], 'click', function (event) {
41050
+ step.attachEvent(step.guideElement.find(guideMarkdownUtil.containerSelector)[0], 'click', function (event) {
41006
41051
  if (!event.target.classList.contains('_pendo-button')) {
41007
41052
  evaluateRequiredQuestions(requiredQuestions);
41008
41053
  }
@@ -41173,7 +41218,7 @@ const SkipToEligibleStep = {
41173
41218
  script(step, guide, pendo) {
41174
41219
  let isAdvanceIntercepted = false;
41175
41220
  let isPreviousIntercepted = false;
41176
- let guideContainer = step.guideElement.find('#pendo-guide-container');
41221
+ let guideContainer = step.guideElement.find(guideMarkdownUtil.containerSelector);
41177
41222
  let guideContainerAriaLabel = guideContainer.attr('aria-label');
41178
41223
  let stepNumberOrAuto = skipStepRegex.exec(guideContainerAriaLabel)[1];
41179
41224
  if (guideContainer) {
@@ -41185,7 +41230,7 @@ const SkipToEligibleStep = {
41185
41230
  let eligibleStep = findEligibleSkipStep(stepNumberOrAuto, 'next');
41186
41231
  if (!isAdvanceIntercepted && stepNumberOrAuto) {
41187
41232
  isAdvanceIntercepted = true;
41188
- pendo.goToStep({ destinationStepId: eligibleStep.id });
41233
+ pendo.goToStep({ destinationStepId: eligibleStep.id, step });
41189
41234
  evt.cancel = true;
41190
41235
  }
41191
41236
  });
@@ -41195,7 +41240,7 @@ const SkipToEligibleStep = {
41195
41240
  let eligibleStep = findEligibleSkipStep(stepNumberOrAuto, 'previous');
41196
41241
  if (!isPreviousIntercepted && stepNumberOrAuto) {
41197
41242
  isPreviousIntercepted = true;
41198
- pendo.goToStep({ destinationStepId: eligibleStep.id });
41243
+ pendo.goToStep({ destinationStepId: eligibleStep.id, step });
41199
41244
  evt.cancel = true;
41200
41245
  }
41201
41246
  });
@@ -41205,10 +41250,10 @@ const SkipToEligibleStep = {
41205
41250
  let skipForwardStep = findStepOnPage(guide.getPositionOfStep(step), 'next', stepNumber);
41206
41251
  let skipPreviousStep = findStepOnPage(guide.getPositionOfStep(step) - 2, 'previous', stepNumber);
41207
41252
  if (skipForwardStep && direction == 'next') {
41208
- pendo.goToStep({ destinationStepId: skipForwardStep });
41253
+ pendo.goToStep({ destinationStepId: skipForwardStep, step });
41209
41254
  }
41210
41255
  if (skipPreviousStep && direction == 'previous') {
41211
- pendo.goToStep({ destinationStepId: skipPreviousStep });
41256
+ pendo.goToStep({ destinationStepId: skipPreviousStep, step });
41212
41257
  }
41213
41258
  return direction === 'next' ? skipForwardStep : skipPreviousStep;
41214
41259
  }
@@ -41234,7 +41279,7 @@ const SkipToEligibleStep = {
41234
41279
  },
41235
41280
  test(step, guide, pendo) {
41236
41281
  var _a;
41237
- const guideContainerAriaLabel = (_a = step.guideElement) === null || _a === void 0 ? void 0 : _a.find('#pendo-guide-container').attr('aria-label');
41282
+ const guideContainerAriaLabel = (_a = step.guideElement) === null || _a === void 0 ? void 0 : _a.find(guideMarkdownUtil.containerSelector).attr('aria-label');
41238
41283
  return pendo._.isString(guideContainerAriaLabel) && guideContainerAriaLabel.indexOf('{skipStep') !== -1;
41239
41284
  },
41240
41285
  designerListener(pendo) {
@@ -41244,7 +41289,7 @@ const SkipToEligibleStep = {
41244
41289
  attributes: true,
41245
41290
  childList: true,
41246
41291
  characterData: true,
41247
- subtree: false
41292
+ subtree: true
41248
41293
  };
41249
41294
  const MutationObserver = getZoneSafeMethod$1(pendo._, 'MutationObserver');
41250
41295
  const observer = new MutationObserver(applySkipStepIndicator);
@@ -41255,14 +41300,14 @@ const SkipToEligibleStep = {
41255
41300
  var _a, _b;
41256
41301
  const nodeHasQuerySelector = pendo._.isFunction((_a = mutation.addedNodes[0]) === null || _a === void 0 ? void 0 : _a.querySelectorAll);
41257
41302
  if (mutation.addedNodes.length && nodeHasQuerySelector) {
41258
- let guideContainer = mutation.addedNodes[0].querySelectorAll('#pendo-guide-container');
41303
+ let guideContainer = mutation.addedNodes[0].querySelectorAll(guideMarkdownUtil.containerSelector);
41259
41304
  let guideContainerAriaLabel = (_b = guideContainer[0]) === null || _b === void 0 ? void 0 : _b.getAttribute('aria-label');
41260
41305
  if (guideContainerAriaLabel) {
41261
41306
  if (guideContainerAriaLabel.match(skipStepRegex)) {
41262
41307
  let fullSkipStepString = guideContainerAriaLabel.match(skipStepRegex)[0];
41263
41308
  guideContainerAriaLabel.replace(fullSkipStepString, '');
41264
41309
  if (!pendo.dom('#_pendoSkipIcon').length) {
41265
- pendo.dom('#pendo-guide-container').append(skipIcon('#999', '30px').trim());
41310
+ pendo.dom(guideMarkdownUtil.containerSelector).append(skipIcon('#999', '30px').trim());
41266
41311
  }
41267
41312
  }
41268
41313
  }
@@ -48566,16 +48611,17 @@ class SessionRecorderBuffer {
48566
48611
  }
48567
48612
  }
48568
48613
 
48569
- const MAX_BACKOFF = 6;
48570
- const MAX_FAILURES = 100;
48614
+ const MAX_RETRY_DELAY_MS = 5 * 60 * 1000; // 5 minutes
48615
+ const ONE_HOUR = 60 * 60 * 1000; // 1 hour
48616
+ const FAILURE_WINDOW_MS = 2 * ONE_HOUR;
48571
48617
  class SendQueue {
48572
- constructor(sendFn, maxFailures = MAX_FAILURES) {
48618
+ constructor(sendFn) {
48573
48619
  this.queue = [];
48574
48620
  this.unloads = new Set();
48575
48621
  this.pending = new Set();
48576
48622
  this.failures = new Map();
48623
+ this.firstFailureTime = null;
48577
48624
  this.sendFn = sendFn;
48578
- this.maxFailures = maxFailures;
48579
48625
  }
48580
48626
  isEmpty() {
48581
48627
  return this.queue.length <= 0;
@@ -48585,6 +48631,7 @@ class SendQueue {
48585
48631
  this.unloads.clear();
48586
48632
  this.pending.clear();
48587
48633
  this.failures.clear();
48634
+ this.firstFailureTime = null;
48588
48635
  this.stopped = true;
48589
48636
  clearTimeout(this.timer);
48590
48637
  delete this.timer;
@@ -48605,12 +48652,16 @@ class SendQueue {
48605
48652
  incrementFailure(payload) {
48606
48653
  const failureCount = (this.failures.get(payload) || 0) + 1;
48607
48654
  this.failures.set(payload, failureCount);
48655
+ if (this.firstFailureTime == null) {
48656
+ this.firstFailureTime = new Date().getTime();
48657
+ }
48608
48658
  return failureCount;
48609
48659
  }
48610
48660
  pass(payload, dequeue = true) {
48611
48661
  this.unloads.delete(payload);
48612
48662
  this.pending.delete(payload);
48613
- this.failures.clear();
48663
+ this.failures.delete(payload);
48664
+ this.firstFailureTime = null;
48614
48665
  const index = this.queue.indexOf(payload);
48615
48666
  if (index >= 0) {
48616
48667
  this.queue.splice(index, 1);
@@ -48625,18 +48676,26 @@ class SendQueue {
48625
48676
  const failureCount = this.incrementFailure(payload);
48626
48677
  if (this.stopped || !retry)
48627
48678
  return;
48628
- if (failureCount >= this.maxFailures) {
48679
+ const now = new Date().getTime();
48680
+ const elapsed = now - (this.firstFailureTime || now);
48681
+ if (elapsed >= FAILURE_WINDOW_MS) {
48629
48682
  if (this.onTimeout) {
48630
48683
  this.onTimeout();
48631
48684
  }
48632
- this.pass(payload, false);
48685
+ this.firstFailureTime = null;
48686
+ this.retryLater(ONE_HOUR);
48687
+ return;
48633
48688
  }
48634
- this.retryLater(Math.pow(2, Math.min(failureCount - 1, MAX_BACKOFF)) * 1000);
48689
+ this.retryLater(Math.min(Math.pow(2, failureCount - 1) * 1000, MAX_RETRY_DELAY_MS));
48690
+ }
48691
+ retryNow() {
48692
+ clearTimeout(this.timer);
48693
+ delete this.timer;
48694
+ this.next();
48635
48695
  }
48636
48696
  retryLater(delay) {
48637
48697
  this.timer = setTimeout$1(() => {
48638
- delete this.timer;
48639
- this.next();
48698
+ this.retryNow();
48640
48699
  }, delay);
48641
48700
  }
48642
48701
  failed() {
@@ -48651,7 +48710,7 @@ class SendQueue {
48651
48710
  }
48652
48711
  drain(finalPayloadArray, isUnload = true) {
48653
48712
  this.queue.push(...finalPayloadArray);
48654
- if (this.failed())
48713
+ if (this.failed() && !this.allowDrainWhileFailed)
48655
48714
  return Promise$2.reject();
48656
48715
  const promises = [];
48657
48716
  for (const payload of this.queue) {
@@ -56940,7 +56999,6 @@ var ConfigReader = (function () {
56940
56999
  * @type {number}
56941
57000
  */
56942
57001
  addOption('guideSeenTimeoutLength', [PENDO_CONFIG_SRC, SNIPPET_SRC], 10000);
56943
- // addOption('guideTimeout', [SNIPPET_SRC]); // old, use guides.timeout instead
56944
57002
  /**
56945
57003
  * If `true`, guides will be verified against their saved content hash before display to ensure validity of
56946
57004
  * guide content.