@pendo/web-sdk 2.313.0 → 2.314.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.
@@ -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.1_';
3949
+ let PACKAGE_VERSION = '2.314.1';
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.resolve(); // 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,7 @@ var loadGuides = function (apiKey, visitorId, page, callback) {
26270
26293
  }
26271
26294
  }
26272
26295
  }).catch(function (err) {
26296
+ log.info(`Error in loadGuideJs, shutting down guides, err: ${_.get(err, 'message', err || 'Unknown error')}`);
26273
26297
  Events.guidesFailed.trigger();
26274
26298
  deferred.reject(err);
26275
26299
  });
@@ -38501,7 +38525,6 @@ const FrustrationEvent = (function () {
38501
38525
  // A guide that show nested inside another element.
38502
38526
  // Multiple embedded guides can show at the same time.
38503
38527
  const buildGuideBehaviors = function ({ globalPendo, pluginApi }) {
38504
- const guide = this;
38505
38528
  const { _ } = globalPendo;
38506
38529
  const { store } = pluginApi;
38507
38530
  this.process = function () {
@@ -38558,12 +38581,6 @@ const buildGuideBehaviors = function ({ globalPendo, pluginApi }) {
38558
38581
  const nextStep = guide.nextStep(lastSeenStep) || firstStep;
38559
38582
  return nextStep.show(reason);
38560
38583
  };
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
38584
  this.isShownInThisFrame = function () {
38568
38585
  const guide = this;
38569
38586
  return _.any(guide.steps, function (step) {
@@ -38620,7 +38637,6 @@ const EmbeddedGuides = (function () {
38620
38637
  pluginApi.Events.on('deliverablesLoaded', clearEmbeddedGuides);
38621
38638
  pluginApi.Events.on('guideLoopStopped', onGuidesStopped);
38622
38639
  pluginApi.Events.on('guideListChanged', initializeEmbeddedGuides);
38623
- pluginApi.Events.on('urlChanged', setForceShowFirstStepFlags);
38624
38640
  pluginApi.Events.on('guideAdvanced', hideGuide);
38625
38641
  pluginApi.Events.on('metadata', onMetadataChange);
38626
38642
  pluginApi.Events.on('identify', onIdentify);
@@ -38635,7 +38651,6 @@ const EmbeddedGuides = (function () {
38635
38651
  pluginApi.Events.off('deliverablesLoaded', clearEmbeddedGuides);
38636
38652
  pluginApi.Events.off('guideLoopStopped', onGuidesStopped);
38637
38653
  pluginApi.Events.off('guideListChanged', initializeEmbeddedGuides);
38638
- pluginApi.Events.off('urlChanged', setForceShowFirstStepFlags);
38639
38654
  pluginApi.Events.off('guideAdvanced', hideGuide);
38640
38655
  pluginApi.Events.off('metadata', onMetadataChange);
38641
38656
  pluginApi.Events.off('identify', onIdentify);
@@ -38700,13 +38715,6 @@ const EmbeddedGuides = (function () {
38700
38715
  function onIdentify() {
38701
38716
  setEmbeddedGuideCacheValid(false);
38702
38717
  }
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
38718
  function extractEmbeddedGuides(guide) {
38711
38719
  if (isEmbedded(guide)) {
38712
38720
  if (!_.some(embeddedGuides, ({ id }) => id === guide.id)) {
@@ -40339,6 +40347,35 @@ class PromptPlugin {
40339
40347
  }
40340
40348
  var PromptAnalytics = new PromptPlugin();
40341
40349
 
40350
+ class RestartOnReload {
40351
+ initialize(pendo, { Events }) {
40352
+ this.pendo = pendo;
40353
+ const { _, attachEvent } = pendo;
40354
+ const boundSetForceShowFirstStepFlags = _.bind(this.setForceShowFirstStepFlags, this);
40355
+ this.subscriptions = [
40356
+ attachEvent(Events, 'deliverablesLoaded', boundSetForceShowFirstStepFlags),
40357
+ attachEvent(Events, 'urlChanged', boundSetForceShowFirstStepFlags)
40358
+ ];
40359
+ }
40360
+ teardown() {
40361
+ this.pendo._.forEach(this.subscriptions, function (unsubscribe) {
40362
+ unsubscribe();
40363
+ });
40364
+ this.subscriptions.length = 0;
40365
+ }
40366
+ setForceShowFirstStepFlags() {
40367
+ const { pendo } = this;
40368
+ const { _ } = pendo;
40369
+ _.forEach(pendo.guides, function (guide) {
40370
+ const restartOnReload = !!_.get(guide, 'attributes.restartOnReload');
40371
+ if (restartOnReload) {
40372
+ guide.forceShowFirstStep = true;
40373
+ }
40374
+ });
40375
+ }
40376
+ }
40377
+ var RestartOnReload$1 = new RestartOnReload();
40378
+
40342
40379
  function registerBuiltInPlugins() {
40343
40380
  registerPlugin(IFrameMonitor);
40344
40381
  registerPlugin(DOMActivation);
@@ -40358,6 +40395,7 @@ function registerBuiltInPlugins() {
40358
40395
  registerPlugin(WebAnalytics$1);
40359
40396
  registerPlugin(FormValidation);
40360
40397
  registerPlugin(PromptAnalytics);
40398
+ registerPlugin(RestartOnReload$1);
40361
40399
  }
40362
40400
 
40363
40401
  /*
@@ -40536,6 +40574,7 @@ const substitutionRegex = '\\{(?:\\s?)([^.\\s]?visitor|account|parentAccount)\\.
40536
40574
  const skipStepString = '{skipStep:* *(auto|\\d+)\\/}';
40537
40575
  const goToMiddleString = '(?!0)(\\d+)';
40538
40576
  const goToString = `({goto-${goToMiddleString}\\/})`;
40577
+ const containerSelector = '[id^="pendo-guide-container"]';
40539
40578
  function lookupGuideButtons(domJson, buttons = []) {
40540
40579
  if (domJson.type === 'button' && domJson.actions) {
40541
40580
  buttons.push(domJson);
@@ -40573,6 +40612,7 @@ var guideMarkdownUtil = {
40573
40612
  substitutionRegex,
40574
40613
  skipStepString,
40575
40614
  goToString,
40615
+ containerSelector,
40576
40616
  lookupGuideButtons,
40577
40617
  removeMarkdownSyntax
40578
40618
  };
@@ -40626,7 +40666,7 @@ const PollBranching = {
40626
40666
  attributes: true,
40627
40667
  childList: true,
40628
40668
  characterData: true,
40629
- subtree: false
40669
+ subtree: true
40630
40670
  };
40631
40671
  const MutationObserver = getZoneSafeMethod$1(pendo._, 'MutationObserver');
40632
40672
  const observer = new MutationObserver(applyBranchingIndicators);
@@ -40745,13 +40785,13 @@ function branchingGoToStep(event, step, guide, pendo) {
40745
40785
  if (pollStepIndex < 0)
40746
40786
  return;
40747
40787
  const destinationObject = {
40748
- destinationStepId: guide.steps[pollStepIndex].id
40788
+ destinationStepId: guide.steps[pollStepIndex].id,
40789
+ step
40749
40790
  };
40750
40791
  pendo.goToStep(destinationObject);
40751
40792
  event.cancel = true;
40752
40793
  }
40753
40794
 
40754
- const containerSelector = '[id^="pendo-guide-container"]';
40755
40795
  const MetadataSubstitution = {
40756
40796
  name: 'MetadataSubstitution',
40757
40797
  script(step, guide, pendo) {
@@ -40775,7 +40815,7 @@ const MetadataSubstitution = {
40775
40815
  attributes: true,
40776
40816
  childList: true,
40777
40817
  characterData: true,
40778
- subtree: false
40818
+ subtree: true
40779
40819
  };
40780
40820
  const MutationObserver = getZoneSafeMethod$1(pendo._, 'MutationObserver');
40781
40821
  const observer = new MutationObserver(applySubstitutionIndicators);
@@ -40784,7 +40824,7 @@ const MetadataSubstitution = {
40784
40824
  pendo._.each(mutations, function (mutation) {
40785
40825
  var _a;
40786
40826
  if (mutation.addedNodes.length) {
40787
- if (document.querySelector(containerSelector)) {
40827
+ if (document.querySelector(guideMarkdownUtil.containerSelector)) {
40788
40828
  const placeholderData = findSubstitutableElements(pendo);
40789
40829
  const step = (_a = pendo.designerv2.currentlyPreviewedGuide) === null || _a === void 0 ? void 0 : _a.steps[0];
40790
40830
  if (!step)
@@ -40851,9 +40891,9 @@ function substituteMetadataByTarget(data, target, mdValue, matched) {
40851
40891
  }
40852
40892
  function updateGuideContainer(containerId, context, pendo) {
40853
40893
  if (pendo.designer && !pendo._.size(pendo.dom('#pendo-ps-substitution-icon'))) {
40854
- pendo.dom(containerSelector).append(substitutionIcon('#999', '30px'));
40894
+ pendo.dom(guideMarkdownUtil.containerSelector).append(substitutionIcon('#999', '30px'));
40855
40895
  }
40856
- pendo.flexElement(pendo.dom(containerSelector));
40896
+ pendo.flexElement(pendo.dom(guideMarkdownUtil.containerSelector));
40857
40897
  pendo.BuildingBlocks.BuildingBlockGuides.recalculateGuideHeight(containerId, context);
40858
40898
  }
40859
40899
  function findSubstitutableUrlsInJson(originalData, placeholderData = [], pendo) {
@@ -40894,7 +40934,7 @@ function findSubstitutableUrlsInJson(originalData, placeholderData = [], pendo)
40894
40934
  return placeholderData;
40895
40935
  }
40896
40936
  function findSubstitutableElements(pendo) {
40897
- let elements = pendo.dom(`${containerSelector} *:not(.pendo-inline-ui)`);
40937
+ let elements = pendo.dom(`${guideMarkdownUtil.containerSelector} *:not(.pendo-inline-ui)`);
40898
40938
  return pendo._.chain(elements)
40899
40939
  .filter(function (placeholder) {
40900
40940
  const subRegex = new RegExp(guideMarkdownUtil.substitutionRegex);
@@ -41002,7 +41042,7 @@ const RequiredQuestions = {
41002
41042
  });
41003
41043
  }
41004
41044
  });
41005
- step.attachEvent(step.guideElement.find('[id^="pendo-guide-container"]')[0], 'click', function (event) {
41045
+ step.attachEvent(step.guideElement.find(guideMarkdownUtil.containerSelector)[0], 'click', function (event) {
41006
41046
  if (!event.target.classList.contains('_pendo-button')) {
41007
41047
  evaluateRequiredQuestions(requiredQuestions);
41008
41048
  }
@@ -41173,7 +41213,7 @@ const SkipToEligibleStep = {
41173
41213
  script(step, guide, pendo) {
41174
41214
  let isAdvanceIntercepted = false;
41175
41215
  let isPreviousIntercepted = false;
41176
- let guideContainer = step.guideElement.find('#pendo-guide-container');
41216
+ let guideContainer = step.guideElement.find(guideMarkdownUtil.containerSelector);
41177
41217
  let guideContainerAriaLabel = guideContainer.attr('aria-label');
41178
41218
  let stepNumberOrAuto = skipStepRegex.exec(guideContainerAriaLabel)[1];
41179
41219
  if (guideContainer) {
@@ -41185,7 +41225,7 @@ const SkipToEligibleStep = {
41185
41225
  let eligibleStep = findEligibleSkipStep(stepNumberOrAuto, 'next');
41186
41226
  if (!isAdvanceIntercepted && stepNumberOrAuto) {
41187
41227
  isAdvanceIntercepted = true;
41188
- pendo.goToStep({ destinationStepId: eligibleStep.id });
41228
+ pendo.goToStep({ destinationStepId: eligibleStep.id, step });
41189
41229
  evt.cancel = true;
41190
41230
  }
41191
41231
  });
@@ -41195,7 +41235,7 @@ const SkipToEligibleStep = {
41195
41235
  let eligibleStep = findEligibleSkipStep(stepNumberOrAuto, 'previous');
41196
41236
  if (!isPreviousIntercepted && stepNumberOrAuto) {
41197
41237
  isPreviousIntercepted = true;
41198
- pendo.goToStep({ destinationStepId: eligibleStep.id });
41238
+ pendo.goToStep({ destinationStepId: eligibleStep.id, step });
41199
41239
  evt.cancel = true;
41200
41240
  }
41201
41241
  });
@@ -41205,10 +41245,10 @@ const SkipToEligibleStep = {
41205
41245
  let skipForwardStep = findStepOnPage(guide.getPositionOfStep(step), 'next', stepNumber);
41206
41246
  let skipPreviousStep = findStepOnPage(guide.getPositionOfStep(step) - 2, 'previous', stepNumber);
41207
41247
  if (skipForwardStep && direction == 'next') {
41208
- pendo.goToStep({ destinationStepId: skipForwardStep });
41248
+ pendo.goToStep({ destinationStepId: skipForwardStep, step });
41209
41249
  }
41210
41250
  if (skipPreviousStep && direction == 'previous') {
41211
- pendo.goToStep({ destinationStepId: skipPreviousStep });
41251
+ pendo.goToStep({ destinationStepId: skipPreviousStep, step });
41212
41252
  }
41213
41253
  return direction === 'next' ? skipForwardStep : skipPreviousStep;
41214
41254
  }
@@ -41234,7 +41274,7 @@ const SkipToEligibleStep = {
41234
41274
  },
41235
41275
  test(step, guide, pendo) {
41236
41276
  var _a;
41237
- const guideContainerAriaLabel = (_a = step.guideElement) === null || _a === void 0 ? void 0 : _a.find('#pendo-guide-container').attr('aria-label');
41277
+ const guideContainerAriaLabel = (_a = step.guideElement) === null || _a === void 0 ? void 0 : _a.find(guideMarkdownUtil.containerSelector).attr('aria-label');
41238
41278
  return pendo._.isString(guideContainerAriaLabel) && guideContainerAriaLabel.indexOf('{skipStep') !== -1;
41239
41279
  },
41240
41280
  designerListener(pendo) {
@@ -41244,7 +41284,7 @@ const SkipToEligibleStep = {
41244
41284
  attributes: true,
41245
41285
  childList: true,
41246
41286
  characterData: true,
41247
- subtree: false
41287
+ subtree: true
41248
41288
  };
41249
41289
  const MutationObserver = getZoneSafeMethod$1(pendo._, 'MutationObserver');
41250
41290
  const observer = new MutationObserver(applySkipStepIndicator);
@@ -41255,14 +41295,14 @@ const SkipToEligibleStep = {
41255
41295
  var _a, _b;
41256
41296
  const nodeHasQuerySelector = pendo._.isFunction((_a = mutation.addedNodes[0]) === null || _a === void 0 ? void 0 : _a.querySelectorAll);
41257
41297
  if (mutation.addedNodes.length && nodeHasQuerySelector) {
41258
- let guideContainer = mutation.addedNodes[0].querySelectorAll('#pendo-guide-container');
41298
+ let guideContainer = mutation.addedNodes[0].querySelectorAll(guideMarkdownUtil.containerSelector);
41259
41299
  let guideContainerAriaLabel = (_b = guideContainer[0]) === null || _b === void 0 ? void 0 : _b.getAttribute('aria-label');
41260
41300
  if (guideContainerAriaLabel) {
41261
41301
  if (guideContainerAriaLabel.match(skipStepRegex)) {
41262
41302
  let fullSkipStepString = guideContainerAriaLabel.match(skipStepRegex)[0];
41263
41303
  guideContainerAriaLabel.replace(fullSkipStepString, '');
41264
41304
  if (!pendo.dom('#_pendoSkipIcon').length) {
41265
- pendo.dom('#pendo-guide-container').append(skipIcon('#999', '30px').trim());
41305
+ pendo.dom(guideMarkdownUtil.containerSelector).append(skipIcon('#999', '30px').trim());
41266
41306
  }
41267
41307
  }
41268
41308
  }
@@ -48566,16 +48606,17 @@ class SessionRecorderBuffer {
48566
48606
  }
48567
48607
  }
48568
48608
 
48569
- const MAX_BACKOFF = 6;
48570
- const MAX_FAILURES = 100;
48609
+ const MAX_RETRY_DELAY_MS = 5 * 60 * 1000; // 5 minutes
48610
+ const ONE_HOUR = 60 * 60 * 1000; // 1 hour
48611
+ const FAILURE_WINDOW_MS = 2 * ONE_HOUR;
48571
48612
  class SendQueue {
48572
- constructor(sendFn, maxFailures = MAX_FAILURES) {
48613
+ constructor(sendFn) {
48573
48614
  this.queue = [];
48574
48615
  this.unloads = new Set();
48575
48616
  this.pending = new Set();
48576
48617
  this.failures = new Map();
48618
+ this.firstFailureTime = null;
48577
48619
  this.sendFn = sendFn;
48578
- this.maxFailures = maxFailures;
48579
48620
  }
48580
48621
  isEmpty() {
48581
48622
  return this.queue.length <= 0;
@@ -48585,6 +48626,7 @@ class SendQueue {
48585
48626
  this.unloads.clear();
48586
48627
  this.pending.clear();
48587
48628
  this.failures.clear();
48629
+ this.firstFailureTime = null;
48588
48630
  this.stopped = true;
48589
48631
  clearTimeout(this.timer);
48590
48632
  delete this.timer;
@@ -48605,12 +48647,16 @@ class SendQueue {
48605
48647
  incrementFailure(payload) {
48606
48648
  const failureCount = (this.failures.get(payload) || 0) + 1;
48607
48649
  this.failures.set(payload, failureCount);
48650
+ if (this.firstFailureTime == null) {
48651
+ this.firstFailureTime = new Date().getTime();
48652
+ }
48608
48653
  return failureCount;
48609
48654
  }
48610
48655
  pass(payload, dequeue = true) {
48611
48656
  this.unloads.delete(payload);
48612
48657
  this.pending.delete(payload);
48613
- this.failures.clear();
48658
+ this.failures.delete(payload);
48659
+ this.firstFailureTime = null;
48614
48660
  const index = this.queue.indexOf(payload);
48615
48661
  if (index >= 0) {
48616
48662
  this.queue.splice(index, 1);
@@ -48625,18 +48671,26 @@ class SendQueue {
48625
48671
  const failureCount = this.incrementFailure(payload);
48626
48672
  if (this.stopped || !retry)
48627
48673
  return;
48628
- if (failureCount >= this.maxFailures) {
48674
+ const now = new Date().getTime();
48675
+ const elapsed = now - (this.firstFailureTime || now);
48676
+ if (elapsed >= FAILURE_WINDOW_MS) {
48629
48677
  if (this.onTimeout) {
48630
48678
  this.onTimeout();
48631
48679
  }
48632
- this.pass(payload, false);
48680
+ this.firstFailureTime = null;
48681
+ this.retryLater(ONE_HOUR);
48682
+ return;
48633
48683
  }
48634
- this.retryLater(Math.pow(2, Math.min(failureCount - 1, MAX_BACKOFF)) * 1000);
48684
+ this.retryLater(Math.min(Math.pow(2, failureCount - 1) * 1000, MAX_RETRY_DELAY_MS));
48685
+ }
48686
+ retryNow() {
48687
+ clearTimeout(this.timer);
48688
+ delete this.timer;
48689
+ this.next();
48635
48690
  }
48636
48691
  retryLater(delay) {
48637
48692
  this.timer = setTimeout$1(() => {
48638
- delete this.timer;
48639
- this.next();
48693
+ this.retryNow();
48640
48694
  }, delay);
48641
48695
  }
48642
48696
  failed() {
@@ -48651,7 +48705,7 @@ class SendQueue {
48651
48705
  }
48652
48706
  drain(finalPayloadArray, isUnload = true) {
48653
48707
  this.queue.push(...finalPayloadArray);
48654
- if (this.failed())
48708
+ if (this.failed() && !this.allowDrainWhileFailed)
48655
48709
  return Promise$2.reject();
48656
48710
  const promises = [];
48657
48711
  for (const payload of this.queue) {
@@ -56940,7 +56994,6 @@ var ConfigReader = (function () {
56940
56994
  * @type {number}
56941
56995
  */
56942
56996
  addOption('guideSeenTimeoutLength', [PENDO_CONFIG_SRC, SNIPPET_SRC], 10000);
56943
- // addOption('guideTimeout', [SNIPPET_SRC]); // old, use guides.timeout instead
56944
56997
  /**
56945
56998
  * If `true`, guides will be verified against their saved content hash before display to ensure validity of
56946
56999
  * guide content.