@pendo/agent 2.313.0 → 2.315.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.
@@ -3423,7 +3422,7 @@ var ConfigReader = (function () {
3423
3422
  * @default false
3424
3423
  * @type {boolean}
3425
3424
  */
3426
- addOption('guides.delay', [SNIPPET_SRC], undefined, undefined, ['delayGuides']);
3425
+ addOption('guides.delay', [SNIPPET_SRC], false, undefined, ['delayGuides']);
3427
3426
  /**
3428
3427
  * Completely disables guides (this option has been moved from `disableGuides`).
3429
3428
  * Alias: `disableGuides`
@@ -3434,7 +3433,7 @@ var ConfigReader = (function () {
3434
3433
  * @default false
3435
3434
  * @type {boolean}
3436
3435
  */
3437
- addOption('guides.disabled', [SNIPPET_SRC], undefined, undefined, ['disableGuides']);
3436
+ addOption('guides.disabled', [SNIPPET_SRC], false, undefined, ['disableGuides']);
3438
3437
  /**
3439
3438
  * If 'true', guides with slow selectors will be removed from guide display processing.
3440
3439
  * This will improve application performance, but slow guides will not be shown to users.
@@ -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.315.0_';
3949
+ let PACKAGE_VERSION = '2.315.0';
3951
3950
  let LOADER = 'xhr';
3952
3951
  /* eslint-enable web-sdk-eslint-rules/no-gulp-env-references */
3953
3952
  /**
@@ -5570,6 +5569,7 @@ var Events = (function () {
5570
5569
  new EventType('deliverablesLoaded', [DEBUG, LIFECYCLE]),
5571
5570
  new EventType('guidesFailed', [DEBUG, LIFECYCLE]),
5572
5571
  new EventType('guidesLoaded', [DEBUG, LIFECYCLE]),
5572
+ new EventType('segmentFlagsUpdated', [DEBUG, LIFECYCLE]),
5573
5573
  new EventType('guideListChanged', [DEBUG, LIFECYCLE]),
5574
5574
  new EventType('guideSeen', [DEBUG, LIFECYCLE]),
5575
5575
  new EventType('guideNotSeen', [DEBUG, LIFECYCLE]),
@@ -12275,16 +12275,17 @@ var JWT = (function () {
12275
12275
  };
12276
12276
  })();
12277
12277
 
12278
- const MAX_BACKOFF = 6;
12279
- const MAX_FAILURES = 100;
12278
+ const MAX_RETRY_DELAY_MS = 5 * 60 * 1000; // 5 minutes
12279
+ const ONE_HOUR = 60 * 60 * 1000; // 1 hour
12280
+ const FAILURE_WINDOW_MS = 2 * ONE_HOUR;
12280
12281
  class SendQueue {
12281
- constructor(sendFn, maxFailures = MAX_FAILURES) {
12282
+ constructor(sendFn) {
12282
12283
  this.queue = [];
12283
12284
  this.unloads = new Set();
12284
12285
  this.pending = new Set();
12285
12286
  this.failures = new Map();
12287
+ this.firstFailureTime = null;
12286
12288
  this.sendFn = sendFn;
12287
- this.maxFailures = maxFailures;
12288
12289
  }
12289
12290
  isEmpty() {
12290
12291
  return this.queue.length <= 0;
@@ -12294,6 +12295,7 @@ class SendQueue {
12294
12295
  this.unloads.clear();
12295
12296
  this.pending.clear();
12296
12297
  this.failures.clear();
12298
+ this.firstFailureTime = null;
12297
12299
  this.stopped = true;
12298
12300
  clearTimeout(this.timer);
12299
12301
  delete this.timer;
@@ -12314,12 +12316,16 @@ class SendQueue {
12314
12316
  incrementFailure(payload) {
12315
12317
  const failureCount = (this.failures.get(payload) || 0) + 1;
12316
12318
  this.failures.set(payload, failureCount);
12319
+ if (this.firstFailureTime == null) {
12320
+ this.firstFailureTime = new Date().getTime();
12321
+ }
12317
12322
  return failureCount;
12318
12323
  }
12319
12324
  pass(payload, dequeue = true) {
12320
12325
  this.unloads.delete(payload);
12321
12326
  this.pending.delete(payload);
12322
- this.failures.clear();
12327
+ this.failures.delete(payload);
12328
+ this.firstFailureTime = null;
12323
12329
  const index = this.queue.indexOf(payload);
12324
12330
  if (index >= 0) {
12325
12331
  this.queue.splice(index, 1);
@@ -12334,18 +12340,26 @@ class SendQueue {
12334
12340
  const failureCount = this.incrementFailure(payload);
12335
12341
  if (this.stopped || !retry)
12336
12342
  return;
12337
- if (failureCount >= this.maxFailures) {
12343
+ const now = new Date().getTime();
12344
+ const elapsed = now - (this.firstFailureTime || now);
12345
+ if (elapsed >= FAILURE_WINDOW_MS) {
12338
12346
  if (this.onTimeout) {
12339
12347
  this.onTimeout();
12340
12348
  }
12341
- this.pass(payload, false);
12349
+ this.firstFailureTime = null;
12350
+ this.retryLater(ONE_HOUR);
12351
+ return;
12342
12352
  }
12343
- this.retryLater(Math.pow(2, Math.min(failureCount - 1, MAX_BACKOFF)) * 1000);
12353
+ this.retryLater(Math.min(Math.pow(2, failureCount - 1) * 1000, MAX_RETRY_DELAY_MS));
12354
+ }
12355
+ retryNow() {
12356
+ clearTimeout(this.timer);
12357
+ delete this.timer;
12358
+ this.next();
12344
12359
  }
12345
12360
  retryLater(delay) {
12346
12361
  this.timer = setTimeout$1(() => {
12347
- delete this.timer;
12348
- this.next();
12362
+ this.retryNow();
12349
12363
  }, delay);
12350
12364
  }
12351
12365
  failed() {
@@ -12360,7 +12374,7 @@ class SendQueue {
12360
12374
  }
12361
12375
  drain(finalPayloadArray, isUnload = true) {
12362
12376
  this.queue.push(...finalPayloadArray);
12363
- if (this.failed())
12377
+ if (this.failed() && !this.allowDrainWhileFailed)
12364
12378
  return Promise$2.reject();
12365
12379
  const promises = [];
12366
12380
  for (const payload of this.queue) {
@@ -12379,7 +12393,7 @@ class SendQueue {
12379
12393
  }
12380
12394
 
12381
12395
  const UNSENT_EVENTS_KEY = 'unsentEvents';
12382
- const UNSENT_EVENTS_DURATION = 6 * 24 * 60 * 60 * 1000; // 6 days
12396
+ const UNSENT_EVENTS_MAX_AGE = 7 * 24 * 60 * 60 * 1000; // 7 days
12383
12397
  class LocalStorageEventBuffer {
12384
12398
  constructor() {
12385
12399
  this.events = {};
@@ -12421,7 +12435,7 @@ class LocalStorageEventBuffer {
12421
12435
  }
12422
12436
  write(storage) {
12423
12437
  if (_.size(this.events) > 0) {
12424
- storage.write(UNSENT_EVENTS_KEY, JSON.stringify(this.events), UNSENT_EVENTS_DURATION);
12438
+ storage.write(UNSENT_EVENTS_KEY, JSON.stringify(this.events), UNSENT_EVENTS_MAX_AGE);
12425
12439
  }
12426
12440
  else {
12427
12441
  storage.clear(UNSENT_EVENTS_KEY);
@@ -12920,6 +12934,7 @@ function addSiloParams(options) {
12920
12934
  silo.params = _.extend({}, silo.params, options.params);
12921
12935
  silo.beacon = options.beacon;
12922
12936
  silo.eventLength = silo.JZB.length;
12937
+ silo.ts = silo[0].browser_time || getNow();
12923
12938
  var jwtOptions = JWT.get();
12924
12939
  if (!_.isEmpty(jwtOptions)) {
12925
12940
  silo.auth = jwtOptions;
@@ -13110,6 +13125,9 @@ function createSendQueue(options, send, guaranteedSend) {
13110
13125
  const apiKeys = getApiKeysFromOptions(options);
13111
13126
  const queues = _.map(apiKeys, (apiKey, i) => {
13112
13127
  const queue = new SendQueue(function (request, isUnload, failureCount) {
13128
+ if (getNow() - request.ts > UNSENT_EVENTS_MAX_AGE) {
13129
+ return q.resolve(); // ignore event if it's too old
13130
+ }
13113
13131
  if (failureCount) {
13114
13132
  request.params = _.extend({}, request.params, {
13115
13133
  rt: failureCount
@@ -13121,7 +13139,10 @@ function createSendQueue(options, send, guaranteedSend) {
13121
13139
  }
13122
13140
  return q.resolve();
13123
13141
  }
13124
- else if (isUnload) {
13142
+ if (isUnload && queue.failed()) {
13143
+ return q.reject();
13144
+ }
13145
+ if (isUnload) {
13125
13146
  return guaranteedSend(apiKey, request);
13126
13147
  }
13127
13148
  else {
@@ -13131,6 +13152,7 @@ function createSendQueue(options, send, guaranteedSend) {
13131
13152
  queue.onTimeout = function () {
13132
13153
  performanceMonitor.count(BEACON_GIF_FAILURES[options.beacon]);
13133
13154
  };
13155
+ queue.allowDrainWhileFailed = true;
13134
13156
  queue.retryPending = true;
13135
13157
  return queue;
13136
13158
  });
@@ -14180,9 +14202,31 @@ var activeGuides = [];
14180
14202
  var activeElements = [];
14181
14203
  var badgesShown = {};
14182
14204
  let _displayableGuides = {};
14205
+ const Channel = {
14206
+ ALL: '*',
14207
+ DEFAULT: 'default'
14208
+ };
14183
14209
  function setBadgesShown(badges) {
14184
14210
  badgesShown = badges;
14185
14211
  }
14212
+ function createChannelMatcher(options = {}) {
14213
+ let channel = options.channel;
14214
+ if (!options.hasOwnProperty('channel')) {
14215
+ channel = Channel.ALL;
14216
+ }
14217
+ else if (channel == null) {
14218
+ channel = Channel.DEFAULT;
14219
+ }
14220
+ if (channel === Channel.ALL) {
14221
+ return () => true;
14222
+ }
14223
+ else if (channel === Channel.DEFAULT) {
14224
+ return (guide) => guide.channel == null;
14225
+ }
14226
+ else {
14227
+ return (guide) => guide.channel == channel;
14228
+ }
14229
+ }
14186
14230
  /**
14187
14231
  * Returns an array of all guides available on the current page to the current user.
14188
14232
  * If multiple frames on a pages, `pendo.getActiveGuides()` will return the list of eligible
@@ -14190,15 +14234,18 @@ function setBadgesShown(badges) {
14190
14234
  *
14191
14235
  * @access public
14192
14236
  * @category Guides
14237
+ * @param {object} options - Options for filtering guides
14238
+ * @param {string} options.channel - Channel to filter guides by
14193
14239
  * @returns {Guide[]}
14194
14240
  * @example
14195
14241
  * pendo.getActiveGuides() => [{ Pendo Guide Object }, ...]
14196
14242
  */
14197
- function getActiveGuides() {
14198
- return activeGuides;
14243
+ function getActiveGuides(options) {
14244
+ const hasChannel = createChannelMatcher(options);
14245
+ return _.filter(activeGuides, hasChannel);
14199
14246
  }
14200
- function getLocalActiveGuides() {
14201
- return frameLocalGuides(getActiveGuides());
14247
+ function getLocalActiveGuides(options) {
14248
+ return frameLocalGuides(getActiveGuides(options));
14202
14249
  }
14203
14250
  function frameLocalGuides(guideList) {
14204
14251
  return _.filter(guideList, function (guide) {
@@ -14341,6 +14388,10 @@ function getGuideAttachPoint(doc = document) {
14341
14388
  return attachPoint || getBody(doc);
14342
14389
  }
14343
14390
  var findBadgeForStep = function (step) {
14391
+ var guide = step.getGuide();
14392
+ if (!guide)
14393
+ return;
14394
+ guide.placeBadge();
14344
14395
  var badge = badgesShown[step.guideId];
14345
14396
  if (!badge)
14346
14397
  return;
@@ -14480,10 +14531,12 @@ const internalEvents = {
14480
14531
  deliverablesLoaded: 1,
14481
14532
  guidesFailed: 1,
14482
14533
  guidesLoaded: 1,
14483
- onClickCaptured: 1
14534
+ onClickCaptured: 1,
14535
+ segmentFlagsUpdated: 1
14484
14536
  };
14485
14537
  const browserEvents = {
14486
- ready: 1
14538
+ ready: 1,
14539
+ segmentFlagsUpdated: 1
14487
14540
  };
14488
14541
  const supportedPublicEvents = [
14489
14542
  'ready',
@@ -14491,6 +14544,7 @@ const supportedPublicEvents = [
14491
14544
  'deliverablesLoaded',
14492
14545
  'guidesFailed',
14493
14546
  'guidesLoaded',
14547
+ 'segmentFlagsUpdated',
14494
14548
  'validateGuide',
14495
14549
  'validateLauncher',
14496
14550
  'validateGlobalScript'
@@ -20620,6 +20674,11 @@ var BuildingBlockResourceCenter = (function () {
20620
20674
 
20621
20675
  var GUIDE_STATE_TTL = 10000; // 10 seconds
20622
20676
  var LAST_STEP_ADVANCED_COOKIE = 'lastStepAdvanced';
20677
+ var THROTTLING_STATE = {
20678
+ DISMISSED: 'latestDismissedAutoAt',
20679
+ SNOOZED: 'latestSnoozedAutoAt',
20680
+ ADVANCED: 'finalAdvancedAutoAt'
20681
+ };
20623
20682
  function writeLastStepSeenCache(lastSeen) {
20624
20683
  store.dispatch('guideState/updateLastGuideStepSeen', lastSeen);
20625
20684
  store.dispatch('guideState/write');
@@ -20644,6 +20703,18 @@ function regainFocus() {
20644
20703
  function getLastGuideStepSeen() {
20645
20704
  return store.state.guideState.lastGuideStepSeen;
20646
20705
  }
20706
+ function applyTimerCache(timerValue, cachedTimerValue) {
20707
+ cachedTimerValue = parseInt(cachedTimerValue, 10);
20708
+ if (isNaN(cachedTimerValue) || !_.isNumber(cachedTimerValue))
20709
+ return timerValue;
20710
+ if (_.isNumber(timerValue) && cachedTimerValue > timerValue) {
20711
+ return cachedTimerValue;
20712
+ }
20713
+ if (!_.isNumber(timerValue)) {
20714
+ return cachedTimerValue;
20715
+ }
20716
+ return timerValue;
20717
+ }
20647
20718
  var GuideStateModule = (function () {
20648
20719
  var state = {
20649
20720
  steps: {},
@@ -20680,19 +20751,25 @@ var GuideStateModule = (function () {
20680
20751
  }
20681
20752
  });
20682
20753
  },
20683
- load(context, storedValue) {
20684
- if (!storedValue)
20685
- return;
20686
- var parsedValue;
20687
- try {
20688
- parsedValue = JSON.parse(storedValue);
20689
- }
20690
- catch (e) {
20754
+ load(context) {
20755
+ const storage = context.getters.storage();
20756
+ let storedValue = storage.read(LAST_STEP_ADVANCED_COOKIE, false, context.getters.cookieSuffix());
20757
+ if (storedValue) {
20758
+ var parsedValue;
20759
+ try {
20760
+ parsedValue = JSON.parse(storedValue);
20761
+ }
20762
+ catch (e) {
20763
+ }
20764
+ if (parsedValue) {
20765
+ _.each([].concat(parsedValue), function (stepState) {
20766
+ context.commit('setStepState', stepState);
20767
+ });
20768
+ }
20691
20769
  }
20692
- if (!parsedValue)
20693
- return;
20694
- _.each([].concat(parsedValue), function (stepState) {
20695
- context.commit('setStepState', stepState);
20770
+ _.each(THROTTLING_STATE, function (throttlingStorageKey) {
20771
+ const value = storage.read(throttlingStorageKey);
20772
+ context.dispatch('updateThrottlingState', { name: throttlingStorageKey, value });
20696
20773
  });
20697
20774
  },
20698
20775
  forceExpire(context) {
@@ -20747,6 +20824,14 @@ var GuideStateModule = (function () {
20747
20824
  }
20748
20825
  log.info('making sure that dismissCount = \'' + step.dismissCount + '\' for ' + storageKey + ': ' + stepId);
20749
20826
  }
20827
+ if (stepState.destinationStepId !== undefined && step.destinationStepId != stepState.destinationStepId) {
20828
+ log.info('making sure that destinationStepId = \'' + stepState.destinationStepId + '\' for ' + storageKey + ': ' + stepId);
20829
+ step.destinationStepId = stepState.destinationStepId;
20830
+ }
20831
+ if (step.lastSeenAt != stepState.time) {
20832
+ log.info('making sure that lastSeenAt = \'' + stepState.time + '\' for ' + storageKey + ': ' + stepId);
20833
+ step.lastSeenAt = stepState.time;
20834
+ }
20750
20835
  var stepIndex = _.indexOf(guide.steps, step);
20751
20836
  _.each(guide.steps.slice(0, stepIndex), function (step) {
20752
20837
  if (!_.contains(['advanced', 'dismissed'], step.seenState)) {
@@ -20762,6 +20847,10 @@ var GuideStateModule = (function () {
20762
20847
  if (mostRecentLastGuideStepSeen) {
20763
20848
  context.dispatch('updateLastGuideStepSeen', _.extend({}, context.state.lastGuideStepSeen, mostRecentLastGuideStepSeen));
20764
20849
  }
20850
+ _.each(THROTTLING_STATE, function (throttlingStorageKey) {
20851
+ pendo$1[throttlingStorageKey] = applyTimerCache(pendo$1[throttlingStorageKey], context.state[throttlingStorageKey]);
20852
+ context.dispatch('updateThrottlingState', { name: throttlingStorageKey, value: pendo$1[throttlingStorageKey] });
20853
+ });
20765
20854
  },
20766
20855
  receiveLastGuideStepSeen(context, lastGuideStepSeen) {
20767
20856
  context.commit('setReceivedLastGuideStepSeen', lastGuideStepSeen);
@@ -20772,8 +20861,8 @@ var GuideStateModule = (function () {
20772
20861
  return;
20773
20862
  // Embedded guides should not update the lastGuideStepSeen in order to not interfere with auto guide display
20774
20863
  // Embedded guides are not included in getters.guideList
20775
- const shouldUpdateLastGuideStepSeen = _.some(context.getters.guideList(), function ({ id }) {
20776
- return id === lastGuideStepSeen.guideId;
20864
+ const shouldUpdateLastGuideStepSeen = _.some(context.getters.guideList(), function ({ id, channel }) {
20865
+ return id === lastGuideStepSeen.guideId && !channel;
20777
20866
  });
20778
20867
  if (lastGuideStepSeen.guideStepId) {
20779
20868
  context.commit('setStepState', lastGuideStepSeen);
@@ -20817,7 +20906,7 @@ var GuideStateModule = (function () {
20817
20906
  }
20818
20907
  if (context.getters.storageChangedInOtherTab()(newValue)) {
20819
20908
  clearLoopTimer();
20820
- context.dispatch('load', rawNewValue);
20909
+ context.dispatch('load');
20821
20910
  context.dispatch('apply');
20822
20911
  if (!context.state.receivedStateChangeAt) {
20823
20912
  context.commit('setReceivedStateChange', context.getters.now());
@@ -21139,15 +21228,27 @@ var Permalink = _.memoize(function () {
21139
21228
  return PermalinkConstructor(findGuideById);
21140
21229
  });
21141
21230
 
21231
+ function shouldNotResumeWalkthrough(walkthrough) {
21232
+ return walkthrough && walkthrough.attributes && walkthrough.attributes.doNotResume;
21233
+ }
21142
21234
  function findInProgressWalkthrough(guidesList, lastGuideStepSeen) {
21143
- var walkthrough = _.find(guidesList, function (guide) {
21235
+ const walkthrough = _.find(guidesList, function (guide) {
21144
21236
  return guide.isContinuation(lastGuideStepSeen);
21145
21237
  });
21146
- var shouldNotResume = walkthrough && walkthrough.attributes && walkthrough.attributes.doNotResume;
21147
- if (walkthrough && !shouldNotResume) {
21238
+ if (walkthrough && !shouldNotResumeWalkthrough(walkthrough)) {
21148
21239
  return walkthrough;
21149
21240
  }
21150
21241
  }
21242
+ function findInProgressChannelWalkthroughs(guidesList) {
21243
+ return _.filter(guidesList, function (guide) {
21244
+ return guide.channel && !shouldNotResumeWalkthrough(guide) && guide.isContinuation();
21245
+ });
21246
+ }
21247
+ const AutoDisplayType = {
21248
+ permalink: 'permalink',
21249
+ continuation: 'continuation',
21250
+ auto: 'auto'
21251
+ };
21151
21252
  class AutoDisplayPhase {
21152
21253
  constructor() {
21153
21254
  this.name = 'autoDisplay';
@@ -21156,33 +21257,45 @@ class AutoDisplayPhase {
21156
21257
  markDirty() {
21157
21258
  if (!isLeader())
21158
21259
  return;
21159
- this.queue.push('permalink', 'continuation');
21160
- this.queue.push(...AutoDisplay.sortAndFilter(getActiveGuides(), pendo$1.autoOrdering));
21260
+ this.queue.push({ type: AutoDisplayType.permalink });
21261
+ const activeGuides = getActiveGuides();
21262
+ const walkthrough = findInProgressWalkthrough(activeGuides, getLastGuideStepSeen());
21263
+ if (walkthrough) {
21264
+ this.queue.push({
21265
+ type: AutoDisplayType.continuation,
21266
+ guide: walkthrough
21267
+ });
21268
+ }
21269
+ for (const channelWalkthrough of findInProgressChannelWalkthroughs(activeGuides)) {
21270
+ this.queue.push({
21271
+ type: AutoDisplayType.continuation,
21272
+ guide: channelWalkthrough
21273
+ });
21274
+ }
21275
+ const allAutoGuides = AutoDisplay.sortAndFilter(activeGuides, pendo$1.autoOrdering);
21276
+ const filteredAutoGuides = walkthrough ? _.filter(allAutoGuides, guide => guide.channel) : allAutoGuides;
21277
+ this.queue.push(..._.map(filteredAutoGuides, guide => ({ type: AutoDisplayType.auto, guide })));
21161
21278
  }
21162
21279
  process(monitor) {
21163
- if (isGuideShown()) {
21164
- this.cancel();
21165
- return;
21166
- }
21167
- var next = this.queue.shift();
21168
- if (next === 'permalink') {
21169
- return Permalink().tryDisplay();
21280
+ const next = this.queue.shift();
21281
+ if (next.type === AutoDisplayType.permalink) {
21282
+ if (!isGuideShown()) {
21283
+ return Permalink().tryDisplay();
21284
+ }
21170
21285
  }
21171
- else if (next === 'continuation') {
21172
- // check for in-progress walkthroughs
21173
- var walkthrough = findInProgressWalkthrough(getActiveGuides(), getLastGuideStepSeen());
21174
- if (walkthrough) {
21175
- monitor.saveContext(walkthrough);
21176
- return walkthrough.show('continue');
21286
+ else if (next.type === AutoDisplayType.continuation) {
21287
+ const { guide } = next;
21288
+ if (!isGuideShown({ channel: guide.channel })) {
21289
+ monitor.saveContext(guide);
21290
+ return guide.show('continue');
21177
21291
  }
21178
21292
  }
21179
- else if (next) {
21180
- if (findInProgressWalkthrough(getActiveGuides(), getLastGuideStepSeen())) {
21181
- this.cancel();
21182
- return;
21293
+ else {
21294
+ const { guide } = next;
21295
+ if (!isGuideShown({ channel: guide.channel })) {
21296
+ monitor.saveContext(guide);
21297
+ return AutoDisplay.tryDisplayGuide(guide, pendo$1);
21183
21298
  }
21184
- monitor.saveContext(next);
21185
- return AutoDisplay.tryDisplayGuide(next, pendo$1);
21186
21299
  }
21187
21300
  }
21188
21301
  handleProcessTimeExceeded(monitor) {
@@ -24771,9 +24884,8 @@ function setSeenTime(time) {
24771
24884
  function getSeenTime() {
24772
24885
  return seenTime;
24773
24886
  }
24774
- // Fix: this is a terrible name.
24775
- var isGuideShown = function () {
24776
- return _.any(getActiveGuides(), function (guide) {
24887
+ var isGuideShown = function (options = {}) {
24888
+ return _.any(getActiveGuides(options), function (guide) {
24777
24889
  return guide.isShown();
24778
24890
  });
24779
24891
  };
@@ -24858,8 +24970,8 @@ var getStepIdFromElement = function (element) {
24858
24970
  * @example
24859
24971
  * pendo.hideGuides({stayHidden: true})
24860
24972
  */
24861
- function hideGuides(hideOptions) {
24862
- _.each(getActiveGuides(), function (guide) {
24973
+ function hideGuides(hideOptions = {}) {
24974
+ _.each(getActiveGuides(hideOptions), function (guide) {
24863
24975
  if (_.isFunction(guide.isShown) && guide.isShown()) {
24864
24976
  guide.hide(hideOptions);
24865
24977
  }
@@ -25010,7 +25122,7 @@ var setFocusToActivationElement = function (guide) {
25010
25122
  }
25011
25123
  };
25012
25124
  function shouldAffectThrottling(guide, seenReason) {
25013
- return !guide.isMultiApp && (seenReason === 'auto' || seenReason === 'repeatGuide');
25125
+ return !guide.isMultiApp && !guide.channel && (seenReason === 'auto' || seenReason === 'repeatGuide');
25014
25126
  }
25015
25127
  /**
25016
25128
  * Hides the current guide and invokes the `guideDismissed` event. Dismissed guides will not
@@ -25617,7 +25729,7 @@ var showPreview = function () {
25617
25729
  };
25618
25730
  var isGuideRCType = _.partial(_.get, _, 'attributes.resourceCenter');
25619
25731
  var beforeShowGuide = function (guide) {
25620
- if (isGuideShown()) {
25732
+ if (isGuideShown({ channel: guide.channel })) {
25621
25733
  var guideStep = findStepForGuideEvent();
25622
25734
  removeGuideEventListeners(guideStep);
25623
25735
  if (isGuideRCType(guide)) {
@@ -25629,7 +25741,7 @@ var beforeShowGuide = function (guide) {
25629
25741
  }
25630
25742
  }
25631
25743
  else {
25632
- hideGuides();
25744
+ hideGuides({ channel: guide.channel });
25633
25745
  store.dispatch('frames/hideGuides');
25634
25746
  }
25635
25747
  }
@@ -25772,11 +25884,6 @@ function snoozeCanceledGuide(guideId, stepId, visitorId, seenReason, language) {
25772
25884
  stageGuideEvent(evt, null, true);
25773
25885
  Events.guideSnoozeCancelled.trigger(evt);
25774
25886
  }
25775
- var THROTTLING_STATE = {
25776
- DISMISSED: 'latestDismissedAutoAt',
25777
- SNOOZED: 'latestSnoozedAutoAt',
25778
- ADVANCED: 'finalAdvancedAutoAt'
25779
- };
25780
25887
  function writeThrottlingStateCache(time, cacheName) {
25781
25888
  _writeThrottlingStateCache(time, cacheName);
25782
25889
  var message = {};
@@ -25793,10 +25900,6 @@ function _writeThrottlingStateCache(time, cacheName) {
25793
25900
  agentStorage.write(cacheName, time, GUIDE_STATE_TTL);
25794
25901
  store.dispatch('guideState/updateThrottlingState', { name: cacheName, value: time });
25795
25902
  }
25796
- function readGuideStatusesFromStorage(cacheName) {
25797
- const cookieSuffix = ConfigReader.get('crossAppGuideStorageSuffix');
25798
- return agentStorage.read(cacheName, false, cookieSuffix);
25799
- }
25800
25903
  function createGuideEvent(name, guideId, stepId, visitorId, reason, language) {
25801
25904
  var params = name;
25802
25905
  if (typeof params !== 'object') {
@@ -25906,18 +26009,6 @@ var showGuideById = function (id, reason) {
25906
26009
  }
25907
26010
  return false;
25908
26011
  };
25909
- function applyTimerCache(timerValue, cachedTimerValue) {
25910
- cachedTimerValue = parseInt(cachedTimerValue, 10);
25911
- if (isNaN(cachedTimerValue) || !_.isNumber(cachedTimerValue))
25912
- return timerValue;
25913
- if (_.isNumber(timerValue) && cachedTimerValue > timerValue) {
25914
- return cachedTimerValue;
25915
- }
25916
- if (!_.isNumber(timerValue)) {
25917
- return cachedTimerValue;
25918
- }
25919
- return timerValue;
25920
- }
25921
26012
  var resetPendoUI = function () {
25922
26013
  stopGuides();
25923
26014
  clearLoopTimer();
@@ -25943,6 +26034,15 @@ function handleDoNotProcess() {
25943
26034
  store.commit('debugger/doNotProcess', true);
25944
26035
  log.info('not tracking visitor due to 451 response');
25945
26036
  }
26037
+ function clearDoNotProcess() {
26038
+ if (!pendo$1.doNotProcess)
26039
+ return;
26040
+ delete pendo$1.doNotProcess;
26041
+ unlockEvents();
26042
+ startGuides();
26043
+ store.commit('debugger/doNotProcess', false);
26044
+ log.info('cleared do not process flag');
26045
+ }
25946
26046
  function guidesPayload(guidesJson) {
25947
26047
  if (!mostRecentGuideRequest)
25948
26048
  return;
@@ -25952,6 +26052,9 @@ function guidesPayload(guidesJson) {
25952
26052
  }
25953
26053
  if (_.isString(guidesJson.id) && guidesJson.id !== mostRecentGuideRequest.id)
25954
26054
  return;
26055
+ if (ConfigReader.get('requestSegmentFlags')) {
26056
+ delete guidesJson.segmentFlags; // This is temporary until the BE stops sending segment flags in the guides payload, at which point this can be removed
26057
+ }
25955
26058
  _.extend(pendo$1, guidesJson);
25956
26059
  pendo$1.guides = _.map(pendo$1.guides, function (guide) {
25957
26060
  if (_.keys(guide).length == 1 && guide.id) {
@@ -25978,6 +26081,9 @@ var mostRecentGuideRequest;
25978
26081
  var loadGuideJs = function (apiKey, params) {
25979
26082
  var guideRequestId = _.uniqueId();
25980
26083
  var deferred = q.defer();
26084
+ if (mostRecentGuideRequest && mostRecentGuideRequest.deferred) {
26085
+ mostRecentGuideRequest.deferred.reject('newRequest'); // make sure that we don't leave open any promises if multiple guide requests are made in quick succession
26086
+ }
25981
26087
  mostRecentGuideRequest = {
25982
26088
  id: guideRequestId,
25983
26089
  deferred
@@ -26204,8 +26310,7 @@ var loadGuides = function (apiKey, visitorId, page, callback) {
26204
26310
  resetPendoUI();
26205
26311
  var lastGuideStepSeen = pendo$1.lastGuideStepSeen;
26206
26312
  if (!lastGuideStepSeen) {
26207
- log.info('lastGuideStepSeen is not set, shutting down guides');
26208
- return;
26313
+ throw new Error('lastGuideStepSeen is not set, check response from guide payload');
26209
26314
  }
26210
26315
  store.dispatch('guideState/receiveLastGuideStepSeen', lastGuideStepSeen);
26211
26316
  lastGuideStepSeen.visitorId = visitorId;
@@ -26215,15 +26320,8 @@ var loadGuides = function (apiKey, visitorId, page, callback) {
26215
26320
  const activeGuides = buildActiveGuideList(pendo$1.guides);
26216
26321
  setActiveGuides(activeGuides);
26217
26322
  const displayableGuides = getDisplayableGuides();
26218
- store.dispatch('guideState/load', readGuideStatusesFromStorage(LAST_STEP_ADVANCED_COOKIE));
26323
+ store.dispatch('guideState/load');
26219
26324
  store.dispatch('guideState/apply');
26220
- pendo$1.latestDismissedAutoAt = applyTimerCache(pendo$1.latestDismissedAutoAt, agentStorage.read('latestDismissedAutoAt'));
26221
- store.dispatch('guideState/updateThrottlingState', { name: 'latestDismissedAutoAt', value: pendo$1.latestDismissedAutoAt });
26222
- pendo$1.finalAdvancedAutoAt = applyTimerCache(pendo$1.finalAdvancedAutoAt, agentStorage.read('finalAdvancedAutoAt'));
26223
- store.dispatch('guideState/updateThrottlingState', { name: 'finalAdvancedAutoAt', value: pendo$1.finalAdvancedAutoAt });
26224
- // APP-40144
26225
- pendo$1.latestSnoozedAutoAt = applyTimerCache(pendo$1.latestSnoozedAutoAt, agentStorage.read('latestSnoozedAutoAt'));
26226
- store.dispatch('guideState/updateThrottlingState', { name: 'latestSnoozedAutoAt', value: pendo$1.latestSnoozedAutoAt });
26227
26325
  store.dispatch('healthCheck/init', activeGuides);
26228
26326
  // This needs to run *immediately* when pendo.guides changes
26229
26327
  // so Events.guidesLoaded.trigger() doesn't cut it, since it
@@ -26270,6 +26368,12 @@ var loadGuides = function (apiKey, visitorId, page, callback) {
26270
26368
  }
26271
26369
  }
26272
26370
  }).catch(function (err) {
26371
+ if (err === 'newRequest') {
26372
+ log.info('Guide load cancelled due to new request');
26373
+ deferred.resolve('Guide load cancelled due to new request');
26374
+ return;
26375
+ }
26376
+ log.info(`Error in loadGuideJs, shutting down guides, err: ${_.get(err, 'message', err || 'Unknown error')}`);
26273
26377
  Events.guidesFailed.trigger();
26274
26378
  deferred.reject(err);
26275
26379
  });
@@ -26499,6 +26603,7 @@ var initGuides = function (observer) {
26499
26603
  }
26500
26604
  });
26501
26605
  Events.identify.on(function () {
26606
+ clearDoNotProcess();
26502
26607
  queueGuideReload();
26503
26608
  });
26504
26609
  Events.urlChanged.on(function () {
@@ -26816,9 +26921,9 @@ function removeGuideProcessor(callback) {
26816
26921
  * @returns {Object | null}
26817
26922
  */
26818
26923
  // TODO: this needs to be updated to support an array of steps
26819
- function getActiveGuide() {
26924
+ function getActiveGuide(options) {
26820
26925
  var currentStep, currentSteps, stepIndex;
26821
- var currentGuide = _.find(getActiveGuides(), function (guide) { return guide.isShown(); });
26926
+ var currentGuide = _.find(getActiveGuides(options), function (guide) { return guide.isShown(); });
26822
26927
  if (!currentGuide)
26823
26928
  return null;
26824
26929
  if (_.get(currentGuide, 'attributes.resourceCenter.isModule')) {
@@ -28047,8 +28152,7 @@ var GuideActivity = (function () {
28047
28152
  return guide;
28048
28153
  }
28049
28154
  const stepId = getStepIdFromAppData(appData);
28050
- const activeGuide = getActiveGuide();
28051
- if (stepId && activeGuide && activeGuide.step && stepId != activeGuide.step.id) {
28155
+ if (stepId) {
28052
28156
  let step;
28053
28157
  const guide = _.find(getLocalActiveGuides(), function (guide) {
28054
28158
  step = _.find(guide.steps, (step) => step.id === stepId);
@@ -28058,7 +28162,7 @@ var GuideActivity = (function () {
28058
28162
  return { guide, step };
28059
28163
  }
28060
28164
  }
28061
- return activeGuide;
28165
+ return getActiveGuide();
28062
28166
  }
28063
28167
  })();
28064
28168
 
@@ -28097,6 +28201,11 @@ const PluginAPI = {
28097
28201
  removeGlobalScript: GuideRuntime.removeGlobalScript
28098
28202
  },
28099
28203
  GuideActivity,
28204
+ GuideEvents: {
28205
+ stageGuideEvent,
28206
+ createGuideEvent,
28207
+ getSeenTime
28208
+ },
28100
28209
  GuideLoop: {
28101
28210
  addUpdatePhase,
28102
28211
  removeUpdatePhase
@@ -28105,7 +28214,9 @@ const PluginAPI = {
28105
28214
  addProcessor: addGuideProcessor,
28106
28215
  removeProcessor: removeGuideProcessor,
28107
28216
  registerDisplayableGuides,
28108
- removeDisplayableGuides
28217
+ removeDisplayableGuides,
28218
+ GuideFactory,
28219
+ GuideStepFactory
28109
28220
  },
28110
28221
  hosts: {
28111
28222
  SERVER
@@ -28128,7 +28239,8 @@ const PluginAPI = {
28128
28239
  base64EncodeString,
28129
28240
  parseUrl,
28130
28241
  addInlineStyles: _.partial(addInlineStyles, ConfigReader),
28131
- getNow
28242
+ getNow,
28243
+ escapeRegExp
28132
28244
  },
28133
28245
  constants: {
28134
28246
  URL_MAX_LENGTH
@@ -28894,6 +29006,9 @@ function teardown() {
28894
29006
  initializeCounter = 0;
28895
29007
  }
28896
29008
 
29009
+ function getActiveDefaultGuide(options = { channel: Channel.DEFAULT }) {
29010
+ return getActiveGuide(options);
29011
+ }
28897
29012
  // CANDIDATES for behaviors to add to guides
28898
29013
  // Starting to expose some useful utilities from service experiences
28899
29014
  var smartNextStep = function (delay) {
@@ -28901,7 +29016,7 @@ var smartNextStep = function (delay) {
28901
29016
  // if it's not, skip that step.
28902
29017
  // need to know:
28903
29018
  // -- this steps' index
28904
- var activeObj = getActiveGuide();
29019
+ var activeObj = getActiveDefaultGuide();
28905
29020
  if (!activeObj)
28906
29021
  return;
28907
29022
  // var stepIndex = _.last(_.map(activeObj.steps, function(s){ return _.indexOf(activeObj.guide.steps, s); }));
@@ -28920,7 +29035,7 @@ var smartNextStep = function (delay) {
28920
29035
  setTimeout$1(checkNext, delay);
28921
29036
  };
28922
29037
  var advanceOn = function (eventType, elementPath) {
28923
- var obj = getActiveGuide();
29038
+ var obj = getActiveDefaultGuide();
28924
29039
  elementPath = elementPath || obj.step.elementPathRule;
28925
29040
  var btn = dom(elementPath)[0];
28926
29041
  var onEvent = function () {
@@ -28933,7 +29048,7 @@ var smartFirstStep = function () {
28933
29048
  dom('._pendo-guide_').css('display:none;');
28934
29049
  // look through steps to see which are applicable for the current url.
28935
29050
  var url = getNormalizedUrl();
28936
- var activeObj = getActiveGuide();
29051
+ var activeObj = getActiveDefaultGuide();
28937
29052
  var steps = activeObj.guide.steps;
28938
29053
  var testSteps = _.filter(_.rest(steps), function (step) {
28939
29054
  return !!step.pageId;
@@ -28973,7 +29088,7 @@ var renderStepPosition = function (template, guide, step) {
28973
29088
  return template(posObj);
28974
29089
  };
28975
29090
  var guideDev = {
28976
- getActiveGuide,
29091
+ getActiveGuide: getActiveDefaultGuide,
28977
29092
  smartNextStep,
28978
29093
  smartFirstStep,
28979
29094
  advanceOn,
@@ -30864,12 +30979,17 @@ function exportPublicApi(pendo) {
30864
30979
  pendo.startGuides = exportPendoCoreOnly(manuallyStartGuides);
30865
30980
  pendo.stopGuides = exportPendoCoreOnly(manuallyStopGuides);
30866
30981
  pendo.defaultCssUrl = exportPendoCoreOnly(getDefaultCssUrl());
30867
- pendo.getActiveGuides = getActiveGuides;
30868
- pendo.getActiveGuide = getActiveGuide;
30982
+ pendo.getActiveGuides = function (options = { channel: Channel.DEFAULT }) {
30983
+ return getActiveGuides(options);
30984
+ };
30985
+ pendo.getActiveGuide = function (options = { channel: Channel.DEFAULT }) {
30986
+ return getActiveGuide(options);
30987
+ };
30869
30988
  pendo.guideSeenTimeoutLength = StepTimeoutMonitor.getGuideSeenTimeoutLength();
30870
30989
  pendo.guidesPayload = guidesPayload;
30871
30990
  pendo.areGuidesDisabled = exportPendoCoreOnly(areGuidesDisabled);
30872
30991
  pendo.setGuidesDisabled = exportPendoCoreOnly(setGuidesDisabled);
30992
+ pendo.areGuidesDelayed = exportPendoCoreOnly(areGuidesDelayed);
30873
30993
  pendo.buildNodeFromJSON = BuildingBlockGuides.buildNodeFromJSON;
30874
30994
  pendo.flexElement = exportPendoCoreOnly(BuildingBlockGuides.flexElement);
30875
30995
  pendo.GuideFactory = exportPendoCoreOnly(GuideFactory);
@@ -31656,44 +31776,48 @@ function WalkthroughGuide() {
31656
31776
  // Do not continue a snoozed guide
31657
31777
  if (currentGuide.isGuideSnoozed())
31658
31778
  return null;
31659
- lastSeenObj = lastSeenObj || {};
31660
- for (var j = 0; j < currentGuide.steps.length; j++) {
31661
- if (currentGuide.steps[j].id === lastSeenObj.guideStepId) {
31662
- if (lastSeenObj.state === 'dismissed') {
31663
- // The guide was dismissed
31664
- break;
31665
- }
31666
- else if (lastSeenObj.state === 'active' || lastSeenObj.state === 'snoozed') {
31667
- // This is current.
31668
- nextStep = currentGuide.steps[j];
31669
- break;
31670
- }
31671
- else if (lastSeenObj.state === 'advanced' && lastSeenObj.destinationStepId) {
31672
- nextStep = _.find(currentGuide.steps, function (step) {
31673
- return step.id === lastSeenObj.destinationStepId;
31674
- });
31675
- break;
31676
- }
31677
- else if ((j + 1) < currentGuide.steps.length) {
31678
- // Get the step after that last one seen
31679
- nextStep = currentGuide.steps[j + 1];
31680
- break;
31779
+ if (lastSeenObj != null) {
31780
+ for (var j = 0; j < currentGuide.steps.length; j++) {
31781
+ if (currentGuide.steps[j].id === lastSeenObj.guideStepId) {
31782
+ if (lastSeenObj.state === 'dismissed') {
31783
+ // The guide was dismissed
31784
+ break;
31785
+ }
31786
+ else if (lastSeenObj.state === 'active' || lastSeenObj.state === 'snoozed') {
31787
+ // This is current.
31788
+ nextStep = currentGuide.steps[j];
31789
+ break;
31790
+ }
31791
+ else if (lastSeenObj.state === 'advanced' && lastSeenObj.destinationStepId) {
31792
+ nextStep = _.find(currentGuide.steps, function (step) {
31793
+ return step.id === lastSeenObj.destinationStepId;
31794
+ });
31795
+ break;
31796
+ }
31797
+ else if ((j + 1) < currentGuide.steps.length) {
31798
+ // Get the step after that last one seen
31799
+ nextStep = currentGuide.steps[j + 1];
31800
+ break;
31801
+ }
31681
31802
  }
31682
31803
  }
31683
- }
31684
- if (nextStep) {
31685
- var now = new Date().getTime();
31686
- var lastSeenTime = lastSeenObj.time;
31687
- if (lastSeenTime &&
31688
- ((now - lastSeenTime) > MULTISTEP_CONTINUATION_TIME_LIMIT) &&
31689
- !isOB(currentGuide)) {
31690
- if (!didLogContinuationExpired) {
31691
- log.info('Multi-step continuation has expired', { contexts: ['guides', 'info'] });
31692
- didLogContinuationExpired = true;
31804
+ if (nextStep) {
31805
+ var now = new Date().getTime();
31806
+ var lastSeenTime = lastSeenObj.time;
31807
+ if (lastSeenTime &&
31808
+ ((now - lastSeenTime) > MULTISTEP_CONTINUATION_TIME_LIMIT) &&
31809
+ !isOB(currentGuide)) {
31810
+ if (!didLogContinuationExpired) {
31811
+ log.info('Multi-step continuation has expired', { contexts: ['guides', 'info'] });
31812
+ didLogContinuationExpired = true;
31813
+ }
31814
+ return null;
31693
31815
  }
31694
- return null;
31816
+ return nextStep;
31695
31817
  }
31696
- return nextStep;
31818
+ }
31819
+ else {
31820
+ return findNextStepFromState(currentGuide);
31697
31821
  }
31698
31822
  return null;
31699
31823
  };
@@ -31743,6 +31867,40 @@ function WalkthroughGuide() {
31743
31867
  }
31744
31868
  return this;
31745
31869
  }
31870
+ /*
31871
+ * Finds next step in guide based on seen state/time of steps (instead of pendo.lastGuideStepSeen)
31872
+ */
31873
+ function findNextStepFromState(guide) {
31874
+ const { steps } = guide;
31875
+ if (!steps || !steps.length)
31876
+ return null;
31877
+ // find the step with the most recent lastSeenAt
31878
+ const { currentStep, currentIndex } = _.reduce(steps, (memo, currentStep, currentIndex) => {
31879
+ const { lastSeenAt } = memo.currentStep;
31880
+ if (lastSeenAt == null)
31881
+ return memo;
31882
+ return currentStep.lastSeenAt > lastSeenAt ? { currentStep, currentIndex } : memo;
31883
+ }, { currentStep: steps[0], currentIndex: 0 });
31884
+ if (currentStep.seenState === 'dismissed')
31885
+ return null;
31886
+ if (typeof currentStep.isSnoozed === 'function' && currentStep.isSnoozed()) {
31887
+ return null;
31888
+ }
31889
+ if (currentStep.seenState === 'active' || currentStep.seenState === 'snoozed')
31890
+ return currentStep;
31891
+ if (currentStep.seenState === 'advanced') {
31892
+ const { destinationStepId } = currentStep;
31893
+ if (destinationStepId) {
31894
+ return _.find(steps, function (step) {
31895
+ return step.id === destinationStepId;
31896
+ });
31897
+ }
31898
+ else {
31899
+ return steps[currentIndex + 1] || null;
31900
+ }
31901
+ }
31902
+ return null;
31903
+ }
31746
31904
 
31747
31905
  /*
31748
31906
  * Traps and logs errors that occur while displaying a guide. If the
@@ -33813,7 +33971,7 @@ function updateMasterGuideList(state) {
33813
33971
  })
33814
33972
  .map(GuideFactory)
33815
33973
  .value();
33816
- var mergedGuideList = _.toArray(guidesInThisFrame).concat(guidesInOtherFrames).filter(runGuideProcessors);
33974
+ var mergedGuideList = _.filter(_.toArray(guidesInThisFrame).concat(guidesInOtherFrames), runGuideProcessors);
33817
33975
  sortGuidesByPriority(mergedGuideList);
33818
33976
  initializeResourceCenter(mergedGuideList);
33819
33977
  setActiveGuides(mergedGuideList);
@@ -34401,7 +34559,7 @@ const DebuggerModule = (() => {
34401
34559
  store.commit('debugger/stepEligibilitySet', stepElg);
34402
34560
  }
34403
34561
  function guidesLoadedFn(evt) {
34404
- const autoOrdering = _.map(AutoDisplay.sortAndFilter(getActiveGuides(), pendo$1.autoOrdering), guide => guide.id);
34562
+ const autoOrdering = _.map(AutoDisplay.sortAndFilter(getActiveGuides({ channel: Channel.DEFAULT }), pendo$1.autoOrdering), guide => guide.id);
34405
34563
  store.commit('debugger/autoOrdering', autoOrdering || []);
34406
34564
  store.commit('debugger/excludedGuides', pendo$1.excludedGuides || []);
34407
34565
  store.commit('debugger/throttling', pendo$1.throttling || {});
@@ -37917,14 +38075,15 @@ const OemAccountId = (function () {
37917
38075
 
37918
38076
  var debugging;
37919
38077
  function debuggerExports() {
38078
+ const getActiveDefaultGuides = () => getActiveGuides({ channel: Channel.DEFAULT });
37920
38079
  return {
37921
38080
  store,
37922
38081
  ConfigReader,
37923
38082
  getState() { return JSON.stringify(store.state); },
37924
38083
  getEventCache() { return [].concat(eventCache); },
37925
- getAllGuides() { return [].concat(getActiveGuides()); },
37926
- getAutoGuides() { return AutoDisplay.sortAndFilter(getActiveGuides(), pendo$1.autoOrdering); },
37927
- getBadgeGuides() { return _.filter(getActiveGuides(), isBadge); },
38084
+ getAllGuides() { return [].concat(getActiveDefaultGuides()); },
38085
+ getAutoGuides() { return AutoDisplay.sortAndFilter(getActiveDefaultGuides(), pendo$1.autoOrdering); },
38086
+ getBadgeGuides() { return _.filter(getActiveDefaultGuides(), isBadge); },
37928
38087
  getLauncherGuides() { return []; },
37929
38088
  getEventHistory() { return []; },
37930
38089
  getAllFrames() { return store.getters['frames/allFrames'](); },
@@ -37933,7 +38092,6 @@ function debuggerExports() {
37933
38092
  setActiveGuides,
37934
38093
  getBody: dom.getBody,
37935
38094
  isMobileUserAgent: sniffer.isMobileUserAgent,
37936
- areGuidesDelayed,
37937
38095
  doesElementMatchContainsRules,
37938
38096
  getMetadata,
37939
38097
  isStagingServer,
@@ -38501,7 +38659,6 @@ const FrustrationEvent = (function () {
38501
38659
  // A guide that show nested inside another element.
38502
38660
  // Multiple embedded guides can show at the same time.
38503
38661
  const buildGuideBehaviors = function ({ globalPendo, pluginApi }) {
38504
- const guide = this;
38505
38662
  const { _ } = globalPendo;
38506
38663
  const { store } = pluginApi;
38507
38664
  this.process = function () {
@@ -38558,12 +38715,6 @@ const buildGuideBehaviors = function ({ globalPendo, pluginApi }) {
38558
38715
  const nextStep = guide.nextStep(lastSeenStep) || firstStep;
38559
38716
  return nextStep.show(reason);
38560
38717
  };
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
38718
  this.isShownInThisFrame = function () {
38568
38719
  const guide = this;
38569
38720
  return _.any(guide.steps, function (step) {
@@ -38620,7 +38771,6 @@ const EmbeddedGuides = (function () {
38620
38771
  pluginApi.Events.on('deliverablesLoaded', clearEmbeddedGuides);
38621
38772
  pluginApi.Events.on('guideLoopStopped', onGuidesStopped);
38622
38773
  pluginApi.Events.on('guideListChanged', initializeEmbeddedGuides);
38623
- pluginApi.Events.on('urlChanged', setForceShowFirstStepFlags);
38624
38774
  pluginApi.Events.on('guideAdvanced', hideGuide);
38625
38775
  pluginApi.Events.on('metadata', onMetadataChange);
38626
38776
  pluginApi.Events.on('identify', onIdentify);
@@ -38635,7 +38785,6 @@ const EmbeddedGuides = (function () {
38635
38785
  pluginApi.Events.off('deliverablesLoaded', clearEmbeddedGuides);
38636
38786
  pluginApi.Events.off('guideLoopStopped', onGuidesStopped);
38637
38787
  pluginApi.Events.off('guideListChanged', initializeEmbeddedGuides);
38638
- pluginApi.Events.off('urlChanged', setForceShowFirstStepFlags);
38639
38788
  pluginApi.Events.off('guideAdvanced', hideGuide);
38640
38789
  pluginApi.Events.off('metadata', onMetadataChange);
38641
38790
  pluginApi.Events.off('identify', onIdentify);
@@ -38700,13 +38849,6 @@ const EmbeddedGuides = (function () {
38700
38849
  function onIdentify() {
38701
38850
  setEmbeddedGuideCacheValid(false);
38702
38851
  }
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
38852
  function extractEmbeddedGuides(guide) {
38711
38853
  if (isEmbedded(guide)) {
38712
38854
  if (!_.some(embeddedGuides, ({ id }) => id === guide.id)) {
@@ -38915,6 +39057,7 @@ class SessionManager {
38915
39057
  }
38916
39058
  var SessionManager$1 = new SessionManager();
38917
39059
 
39060
+ const SEGMENT_FLAGS_CACHE = 'segmentFlagsCache';
38918
39061
  class SegmentFlags {
38919
39062
  constructor() {
38920
39063
  this.name = 'SegmentFlags';
@@ -38932,26 +39075,57 @@ class SegmentFlags {
38932
39075
  if (!this.segmentFlagsEnabled)
38933
39076
  return;
38934
39077
  this.mostRecentSegmentsRequest = null;
39078
+ /**
39079
+ * Stores the cached segment flags for the current visitor.
39080
+ * Cleared on identity change and refreshed from server on page load.
39081
+ *
39082
+ * @name _pendo_segmentFlagsCache
39083
+ * @category Cookies/localStorage
39084
+ * @access public
39085
+ * @label SEGMENT_FLAGS_CACHE
39086
+ */
39087
+ PluginAPI.agentStorage.registry.addLocal(SEGMENT_FLAGS_CACHE, {
39088
+ isSecure: true,
39089
+ serializer: JSON.stringify,
39090
+ deserializer: SafeJsonDeserializer
39091
+ });
39092
+ if (shouldPersist()) {
39093
+ try {
39094
+ const cached = PluginAPI.agentStorage.read(SEGMENT_FLAGS_CACHE);
39095
+ if (cached) {
39096
+ this.pendo.segmentFlags = cached;
39097
+ }
39098
+ }
39099
+ catch (e) {
39100
+ // ignore read errors
39101
+ }
39102
+ }
38935
39103
  this.pendo.segmentsPayload = this.pendo._.bind(this.segmentsPayload, this);
38936
- this.handleMetadataChange = this.pendo._.debounce(this.pendo._.bind(this.requestSegmentFlags, this), 50);
38937
39104
  this.handleReadyBound = this.pendo._.bind(this.handleReady, this);
39105
+ this.handleIdentityChangeBound = this.pendo._.bind(this.handleIdentityChange, this);
38938
39106
  this.api.Events.ready.on(this.handleReadyBound);
38939
- this.api.Events.metadata.on(this.handleMetadataChange);
38940
- this.api.Events.identify.on(this.handleMetadataChange);
39107
+ this.api.Events.identify.on(this.handleIdentityChangeBound);
39108
+ this.api.Events.metadata.on(this.handleIdentityChangeBound);
38941
39109
  }
38942
39110
  teardown() {
38943
39111
  if (!this.segmentFlagsEnabled)
38944
39112
  return;
38945
39113
  this.pendo.segmentsPayload = this.pendo._.noop;
38946
- this.handleMetadataChange.cancel();
38947
39114
  this.api.Events.ready.off(this.handleReadyBound);
38948
- this.api.Events.metadata.off(this.handleMetadataChange);
38949
- this.api.Events.identify.off(this.handleMetadataChange);
39115
+ this.api.Events.identify.off(this.handleIdentityChangeBound);
39116
+ this.api.Events.metadata.off(this.handleIdentityChangeBound);
38950
39117
  }
38951
39118
  handleReady() {
38952
39119
  this.ready = true;
38953
39120
  this.requestSegmentFlags();
38954
39121
  }
39122
+ handleIdentityChange(event) {
39123
+ if (this.pendo._.get(event, 'data[0].wasCleared')) {
39124
+ this.api.agentStorage.clear(SEGMENT_FLAGS_CACHE);
39125
+ delete this.pendo.segmentFlags;
39126
+ }
39127
+ this.requestSegmentFlags();
39128
+ }
38955
39129
  requestSegmentFlags() {
38956
39130
  if (!this.ready)
38957
39131
  return;
@@ -39000,10 +39174,23 @@ class SegmentFlags {
39000
39174
  return;
39001
39175
  if (this.pendo._.isString(payload.id) && payload.id !== this.mostRecentSegmentsRequest)
39002
39176
  return;
39177
+ const changed = this.flagsChanged(this.pendo.segmentFlags, payload.segmentFlags);
39003
39178
  this.pendo.segmentFlags = payload.segmentFlags;
39179
+ if (shouldPersist()) {
39180
+ this.api.agentStorage.write(SEGMENT_FLAGS_CACHE, payload.segmentFlags);
39181
+ }
39182
+ if (changed) {
39183
+ this.api.Events.segmentFlagsUpdated.trigger(this.pendo.segmentFlags);
39184
+ }
39004
39185
  this.api.log.info('successfully loaded segment flags');
39005
39186
  this.mostRecentSegmentsRequest = null;
39006
39187
  }
39188
+ flagsChanged(oldFlags = [], newFlags = []) {
39189
+ if (oldFlags.length !== newFlags.length)
39190
+ return true;
39191
+ const intersection = this.pendo._.intersection(oldFlags, newFlags);
39192
+ return intersection.length !== oldFlags.length;
39193
+ }
39007
39194
  scriptLoad(url) {
39008
39195
  this.pendo.loadResource(url, this.pendo._.noop);
39009
39196
  }
@@ -40339,6 +40526,35 @@ class PromptPlugin {
40339
40526
  }
40340
40527
  var PromptAnalytics = new PromptPlugin();
40341
40528
 
40529
+ class RestartOnReload {
40530
+ initialize(pendo, { Events }) {
40531
+ this.pendo = pendo;
40532
+ const { _, attachEvent } = pendo;
40533
+ const boundSetForceShowFirstStepFlags = _.bind(this.setForceShowFirstStepFlags, this);
40534
+ this.subscriptions = [
40535
+ attachEvent(Events, 'deliverablesLoaded', boundSetForceShowFirstStepFlags),
40536
+ attachEvent(Events, 'urlChanged', boundSetForceShowFirstStepFlags)
40537
+ ];
40538
+ }
40539
+ teardown() {
40540
+ this.pendo._.forEach(this.subscriptions, function (unsubscribe) {
40541
+ unsubscribe();
40542
+ });
40543
+ this.subscriptions.length = 0;
40544
+ }
40545
+ setForceShowFirstStepFlags() {
40546
+ const { pendo } = this;
40547
+ const { _ } = pendo;
40548
+ _.forEach(pendo.guides, function (guide) {
40549
+ const restartOnReload = !!_.get(guide, 'attributes.restartOnReload');
40550
+ if (restartOnReload) {
40551
+ guide.forceShowFirstStep = true;
40552
+ }
40553
+ });
40554
+ }
40555
+ }
40556
+ var RestartOnReload$1 = new RestartOnReload();
40557
+
40342
40558
  function registerBuiltInPlugins() {
40343
40559
  registerPlugin(IFrameMonitor);
40344
40560
  registerPlugin(DOMActivation);
@@ -40358,6 +40574,7 @@ function registerBuiltInPlugins() {
40358
40574
  registerPlugin(WebAnalytics$1);
40359
40575
  registerPlugin(FormValidation);
40360
40576
  registerPlugin(PromptAnalytics);
40577
+ registerPlugin(RestartOnReload$1);
40361
40578
  }
40362
40579
 
40363
40580
  /*
@@ -40498,18 +40715,30 @@ function TextCapture() {
40498
40715
  function guideActivity(pendo, event) {
40499
40716
  if (!isEnabled())
40500
40717
  return;
40501
- var eventData = event.data[0];
40718
+ const { _ } = pendo;
40719
+ const eventData = event.data[0];
40502
40720
  if (eventData && eventData.type === 'guideActivity') {
40503
- var activeGuideObj = pendo.getActiveGuide();
40504
- if (!activeGuideObj)
40721
+ const shownSteps = _.reduce(pendo.getActiveGuides({ channel: '*' }), (shown, guide) => {
40722
+ if (guide.isShown()) {
40723
+ return shown.concat(_.filter(guide.steps, (step) => step.isShown()));
40724
+ }
40725
+ return shown;
40726
+ }, []);
40727
+ if (!shownSteps.length)
40505
40728
  return;
40506
- var findDomBlockInDomJson = pendo.BuildingBlocks.BuildingBlockGuides.findDomBlockInDomJson;
40507
- var element = findDomBlockInDomJson(activeGuideObj.step.domJson, function (domJson) {
40508
- return domJson.props && domJson.props.id && domJson.props.id === eventData.props.ui_element_id;
40729
+ const findDomBlockInDomJson = pendo.BuildingBlocks.BuildingBlockGuides.findDomBlockInDomJson;
40730
+ let elementJson;
40731
+ _.find(shownSteps, (step) => {
40732
+ if (!step.domJson)
40733
+ return false;
40734
+ elementJson = findDomBlockInDomJson(step.domJson, function (domJson) {
40735
+ return domJson.props && domJson.props.id && domJson.props.id === eventData.props.ui_element_id;
40736
+ });
40737
+ return elementJson;
40509
40738
  });
40510
- if (!element)
40739
+ if (!elementJson)
40511
40740
  return;
40512
- eventData.props.ui_element_text = element.content;
40741
+ eventData.props.ui_element_text = elementJson.content;
40513
40742
  }
40514
40743
  }
40515
40744
  function isEnabled() {
@@ -40536,6 +40765,7 @@ const substitutionRegex = '\\{(?:\\s?)([^.\\s]?visitor|account|parentAccount)\\.
40536
40765
  const skipStepString = '{skipStep:* *(auto|\\d+)\\/}';
40537
40766
  const goToMiddleString = '(?!0)(\\d+)';
40538
40767
  const goToString = `({goto-${goToMiddleString}\\/})`;
40768
+ const containerSelector = '[id^="pendo-guide-container"]';
40539
40769
  function lookupGuideButtons(domJson, buttons = []) {
40540
40770
  if (domJson.type === 'button' && domJson.actions) {
40541
40771
  buttons.push(domJson);
@@ -40573,6 +40803,7 @@ var guideMarkdownUtil = {
40573
40803
  substitutionRegex,
40574
40804
  skipStepString,
40575
40805
  goToString,
40806
+ containerSelector,
40576
40807
  lookupGuideButtons,
40577
40808
  removeMarkdownSyntax
40578
40809
  };
@@ -40626,7 +40857,7 @@ const PollBranching = {
40626
40857
  attributes: true,
40627
40858
  childList: true,
40628
40859
  characterData: true,
40629
- subtree: false
40860
+ subtree: true
40630
40861
  };
40631
40862
  const MutationObserver = getZoneSafeMethod$1(pendo._, 'MutationObserver');
40632
40863
  const observer = new MutationObserver(applyBranchingIndicators);
@@ -40745,13 +40976,13 @@ function branchingGoToStep(event, step, guide, pendo) {
40745
40976
  if (pollStepIndex < 0)
40746
40977
  return;
40747
40978
  const destinationObject = {
40748
- destinationStepId: guide.steps[pollStepIndex].id
40979
+ destinationStepId: guide.steps[pollStepIndex].id,
40980
+ step
40749
40981
  };
40750
40982
  pendo.goToStep(destinationObject);
40751
40983
  event.cancel = true;
40752
40984
  }
40753
40985
 
40754
- const containerSelector = '[id^="pendo-guide-container"]';
40755
40986
  const MetadataSubstitution = {
40756
40987
  name: 'MetadataSubstitution',
40757
40988
  script(step, guide, pendo) {
@@ -40770,12 +41001,36 @@ const MetadataSubstitution = {
40770
41001
  },
40771
41002
  designerListener(pendo) {
40772
41003
  const target = pendo.dom.getBody();
41004
+ if (pendo.designerv2) {
41005
+ pendo.designerv2.runMetadataSubstitutionForDesignerPreview = function runMetadataSubstitutionForDesignerPreview() {
41006
+ var _a;
41007
+ if (!document.querySelector(guideMarkdownUtil.containerSelector))
41008
+ return;
41009
+ const step = (_a = pendo.designerv2.currentlyPreviewedGuide) === null || _a === void 0 ? void 0 : _a.steps[0];
41010
+ if (!step)
41011
+ return;
41012
+ const placeholderData = findSubstitutableElements(pendo);
41013
+ if (step.buildingBlocks) {
41014
+ findSubstitutableUrlsInJson(step.buildingBlocks, placeholderData, pendo);
41015
+ }
41016
+ if (pendo._.size(placeholderData)) {
41017
+ pendo._.each(placeholderData, function (placeholder) {
41018
+ if (pendo._.isUndefined(placeholder))
41019
+ return;
41020
+ processPlaceholder(placeholder, pendo);
41021
+ });
41022
+ const containerId = `pendo-g-${step.id}`;
41023
+ const context = step.guideElement;
41024
+ updateGuideContainer(containerId, context, pendo);
41025
+ }
41026
+ };
41027
+ }
40773
41028
  const config = {
40774
41029
  attributeFilter: ['data-layout'],
40775
41030
  attributes: true,
40776
41031
  childList: true,
40777
41032
  characterData: true,
40778
- subtree: false
41033
+ subtree: true
40779
41034
  };
40780
41035
  const MutationObserver = getZoneSafeMethod$1(pendo._, 'MutationObserver');
40781
41036
  const observer = new MutationObserver(applySubstitutionIndicators);
@@ -40784,7 +41039,7 @@ const MetadataSubstitution = {
40784
41039
  pendo._.each(mutations, function (mutation) {
40785
41040
  var _a;
40786
41041
  if (mutation.addedNodes.length) {
40787
- if (document.querySelector(containerSelector)) {
41042
+ if (document.querySelector(guideMarkdownUtil.containerSelector)) {
40788
41043
  const placeholderData = findSubstitutableElements(pendo);
40789
41044
  const step = (_a = pendo.designerv2.currentlyPreviewedGuide) === null || _a === void 0 ? void 0 : _a.steps[0];
40790
41045
  if (!step)
@@ -40814,8 +41069,14 @@ function processPlaceholder(placeholder, pendo) {
40814
41069
  const { data, target } = placeholder;
40815
41070
  const subRegex = new RegExp(guideMarkdownUtil.substitutionRegex);
40816
41071
  while ((match = matchPlaceholder(placeholder, subRegex))) {
40817
- let matched = subRegex.exec(match);
40818
- let mdValue = getSubstituteValue(matched, pendo);
41072
+ const usedArrayPath = Array.isArray(match) && match.length >= 2;
41073
+ const currentStr = target === 'textContent'
41074
+ ? data[target]
41075
+ : decodeURI((data.getAttribute && (target === 'href' || target === 'value') ? (data.getAttribute(target) || '') : data[target]));
41076
+ const matched = usedArrayPath ? match : subRegex.exec(currentStr);
41077
+ if (!matched)
41078
+ continue;
41079
+ const mdValue = getSubstituteValue(matched, pendo);
40819
41080
  substituteMetadataByTarget(data, target, mdValue, matched);
40820
41081
  }
40821
41082
  }
@@ -40824,36 +41085,59 @@ function matchPlaceholder(placeholder, regex) {
40824
41085
  return placeholder.data[placeholder.target].match(regex);
40825
41086
  }
40826
41087
  else {
40827
- return decodeURI(placeholder.data[placeholder.target]).match(regex);
41088
+ const raw = placeholder.data.getAttribute && (placeholder.target === 'href' || placeholder.target === 'value')
41089
+ ? (placeholder.data.getAttribute(placeholder.target) || '')
41090
+ : placeholder.data[placeholder.target];
41091
+ return decodeURI(raw).match(regex);
40828
41092
  }
40829
41093
  }
41094
+ function getMetadataValueCaseInsensitive(metadata, type, property) {
41095
+ const kind = metadata && metadata[type];
41096
+ if (!kind || typeof kind !== 'object')
41097
+ return undefined;
41098
+ const direct = Object.prototype.hasOwnProperty.call(kind, property) ? kind[property] : undefined;
41099
+ if (direct !== undefined) {
41100
+ return direct;
41101
+ }
41102
+ const propLower = property.toLowerCase();
41103
+ const key = Object.keys(kind).find(k => k.toLowerCase() === propLower);
41104
+ const value = key !== undefined ? kind[key] : undefined;
41105
+ return value;
41106
+ }
40830
41107
  function getSubstituteValue(match, pendo) {
40831
- if (pendo._.isUndefined(match[1]) || pendo._.isUndefined(match[2]))
41108
+ if (pendo._.isUndefined(match[1]) || pendo._.isUndefined(match[2])) {
40832
41109
  return;
41110
+ }
40833
41111
  let type = match[1];
40834
41112
  let property = match[2];
40835
41113
  let defaultValue = match[3];
40836
41114
  if (pendo._.isUndefined(type) || pendo._.isUndefined(property)) {
40837
41115
  return;
40838
41116
  }
40839
- let mdValue = pendo._.get(pendo.getSerializedMetadata(), `${type}.${property}`) || defaultValue || '';
41117
+ const metadata = pendo.getSerializedMetadata();
41118
+ let mdValue = getMetadataValueCaseInsensitive(metadata, type, property);
41119
+ if (mdValue === undefined || mdValue === null)
41120
+ mdValue = defaultValue || '';
40840
41121
  return mdValue;
40841
41122
  }
40842
41123
  function substituteMetadataByTarget(data, target, mdValue, matched) {
41124
+ const isElement = data && typeof data.getAttribute === 'function';
41125
+ const current = (target === 'href' || target === 'value') && isElement
41126
+ ? (data.getAttribute(target) || '')
41127
+ : data[target];
40843
41128
  if (target === 'href' || target === 'value') {
40844
- data[target] = decodeURI(data[target])
40845
- .replace(matched[0], window.encodeURI(mdValue));
41129
+ const safeValue = window.encodeURIComponent(String(mdValue === undefined || mdValue === null ? '' : mdValue));
41130
+ data[target] = decodeURI(current).replace(matched[0], safeValue);
40846
41131
  }
40847
41132
  else {
40848
- data[target] = data[target]
40849
- .replace(matched[0], mdValue);
41133
+ data[target] = current.replace(matched[0], mdValue);
40850
41134
  }
40851
41135
  }
40852
41136
  function updateGuideContainer(containerId, context, pendo) {
40853
41137
  if (pendo.designer && !pendo._.size(pendo.dom('#pendo-ps-substitution-icon'))) {
40854
- pendo.dom(containerSelector).append(substitutionIcon('#999', '30px'));
41138
+ pendo.dom(guideMarkdownUtil.containerSelector).append(substitutionIcon('#999', '30px'));
40855
41139
  }
40856
- pendo.flexElement(pendo.dom(containerSelector));
41140
+ pendo.flexElement(pendo.dom(guideMarkdownUtil.containerSelector));
40857
41141
  pendo.BuildingBlocks.BuildingBlockGuides.recalculateGuideHeight(containerId, context);
40858
41142
  }
40859
41143
  function findSubstitutableUrlsInJson(originalData, placeholderData = [], pendo) {
@@ -40894,7 +41178,7 @@ function findSubstitutableUrlsInJson(originalData, placeholderData = [], pendo)
40894
41178
  return placeholderData;
40895
41179
  }
40896
41180
  function findSubstitutableElements(pendo) {
40897
- let elements = pendo.dom(`${containerSelector} *:not(.pendo-inline-ui)`);
41181
+ let elements = pendo.dom(`${guideMarkdownUtil.containerSelector} *:not(.pendo-inline-ui)`);
40898
41182
  return pendo._.chain(elements)
40899
41183
  .filter(function (placeholder) {
40900
41184
  const subRegex = new RegExp(guideMarkdownUtil.substitutionRegex);
@@ -41002,7 +41286,7 @@ const RequiredQuestions = {
41002
41286
  });
41003
41287
  }
41004
41288
  });
41005
- step.attachEvent(step.guideElement.find('[id^="pendo-guide-container"]')[0], 'click', function (event) {
41289
+ step.attachEvent(step.guideElement.find(guideMarkdownUtil.containerSelector)[0], 'click', function (event) {
41006
41290
  if (!event.target.classList.contains('_pendo-button')) {
41007
41291
  evaluateRequiredQuestions(requiredQuestions);
41008
41292
  }
@@ -41173,7 +41457,7 @@ const SkipToEligibleStep = {
41173
41457
  script(step, guide, pendo) {
41174
41458
  let isAdvanceIntercepted = false;
41175
41459
  let isPreviousIntercepted = false;
41176
- let guideContainer = step.guideElement.find('#pendo-guide-container');
41460
+ let guideContainer = step.guideElement.find(guideMarkdownUtil.containerSelector);
41177
41461
  let guideContainerAriaLabel = guideContainer.attr('aria-label');
41178
41462
  let stepNumberOrAuto = skipStepRegex.exec(guideContainerAriaLabel)[1];
41179
41463
  if (guideContainer) {
@@ -41185,7 +41469,7 @@ const SkipToEligibleStep = {
41185
41469
  let eligibleStep = findEligibleSkipStep(stepNumberOrAuto, 'next');
41186
41470
  if (!isAdvanceIntercepted && stepNumberOrAuto) {
41187
41471
  isAdvanceIntercepted = true;
41188
- pendo.goToStep({ destinationStepId: eligibleStep.id });
41472
+ pendo.goToStep({ destinationStepId: eligibleStep.id, step });
41189
41473
  evt.cancel = true;
41190
41474
  }
41191
41475
  });
@@ -41195,7 +41479,7 @@ const SkipToEligibleStep = {
41195
41479
  let eligibleStep = findEligibleSkipStep(stepNumberOrAuto, 'previous');
41196
41480
  if (!isPreviousIntercepted && stepNumberOrAuto) {
41197
41481
  isPreviousIntercepted = true;
41198
- pendo.goToStep({ destinationStepId: eligibleStep.id });
41482
+ pendo.goToStep({ destinationStepId: eligibleStep.id, step });
41199
41483
  evt.cancel = true;
41200
41484
  }
41201
41485
  });
@@ -41205,10 +41489,10 @@ const SkipToEligibleStep = {
41205
41489
  let skipForwardStep = findStepOnPage(guide.getPositionOfStep(step), 'next', stepNumber);
41206
41490
  let skipPreviousStep = findStepOnPage(guide.getPositionOfStep(step) - 2, 'previous', stepNumber);
41207
41491
  if (skipForwardStep && direction == 'next') {
41208
- pendo.goToStep({ destinationStepId: skipForwardStep });
41492
+ pendo.goToStep({ destinationStepId: skipForwardStep, step });
41209
41493
  }
41210
41494
  if (skipPreviousStep && direction == 'previous') {
41211
- pendo.goToStep({ destinationStepId: skipPreviousStep });
41495
+ pendo.goToStep({ destinationStepId: skipPreviousStep, step });
41212
41496
  }
41213
41497
  return direction === 'next' ? skipForwardStep : skipPreviousStep;
41214
41498
  }
@@ -41234,7 +41518,7 @@ const SkipToEligibleStep = {
41234
41518
  },
41235
41519
  test(step, guide, pendo) {
41236
41520
  var _a;
41237
- const guideContainerAriaLabel = (_a = step.guideElement) === null || _a === void 0 ? void 0 : _a.find('#pendo-guide-container').attr('aria-label');
41521
+ const guideContainerAriaLabel = (_a = step.guideElement) === null || _a === void 0 ? void 0 : _a.find(guideMarkdownUtil.containerSelector).attr('aria-label');
41238
41522
  return pendo._.isString(guideContainerAriaLabel) && guideContainerAriaLabel.indexOf('{skipStep') !== -1;
41239
41523
  },
41240
41524
  designerListener(pendo) {
@@ -41244,7 +41528,7 @@ const SkipToEligibleStep = {
41244
41528
  attributes: true,
41245
41529
  childList: true,
41246
41530
  characterData: true,
41247
- subtree: false
41531
+ subtree: true
41248
41532
  };
41249
41533
  const MutationObserver = getZoneSafeMethod$1(pendo._, 'MutationObserver');
41250
41534
  const observer = new MutationObserver(applySkipStepIndicator);
@@ -41255,14 +41539,14 @@ const SkipToEligibleStep = {
41255
41539
  var _a, _b;
41256
41540
  const nodeHasQuerySelector = pendo._.isFunction((_a = mutation.addedNodes[0]) === null || _a === void 0 ? void 0 : _a.querySelectorAll);
41257
41541
  if (mutation.addedNodes.length && nodeHasQuerySelector) {
41258
- let guideContainer = mutation.addedNodes[0].querySelectorAll('#pendo-guide-container');
41542
+ let guideContainer = mutation.addedNodes[0].querySelectorAll(guideMarkdownUtil.containerSelector);
41259
41543
  let guideContainerAriaLabel = (_b = guideContainer[0]) === null || _b === void 0 ? void 0 : _b.getAttribute('aria-label');
41260
41544
  if (guideContainerAriaLabel) {
41261
41545
  if (guideContainerAriaLabel.match(skipStepRegex)) {
41262
41546
  let fullSkipStepString = guideContainerAriaLabel.match(skipStepRegex)[0];
41263
41547
  guideContainerAriaLabel.replace(fullSkipStepString, '');
41264
41548
  if (!pendo.dom('#_pendoSkipIcon').length) {
41265
- pendo.dom('#pendo-guide-container').append(skipIcon('#999', '30px').trim());
41549
+ pendo.dom(guideMarkdownUtil.containerSelector).append(skipIcon('#999', '30px').trim());
41266
41550
  }
41267
41551
  }
41268
41552
  }
@@ -48566,16 +48850,17 @@ class SessionRecorderBuffer {
48566
48850
  }
48567
48851
  }
48568
48852
 
48569
- const MAX_BACKOFF = 6;
48570
- const MAX_FAILURES = 100;
48853
+ const MAX_RETRY_DELAY_MS = 5 * 60 * 1000; // 5 minutes
48854
+ const ONE_HOUR = 60 * 60 * 1000; // 1 hour
48855
+ const FAILURE_WINDOW_MS = 2 * ONE_HOUR;
48571
48856
  class SendQueue {
48572
- constructor(sendFn, maxFailures = MAX_FAILURES) {
48857
+ constructor(sendFn) {
48573
48858
  this.queue = [];
48574
48859
  this.unloads = new Set();
48575
48860
  this.pending = new Set();
48576
48861
  this.failures = new Map();
48862
+ this.firstFailureTime = null;
48577
48863
  this.sendFn = sendFn;
48578
- this.maxFailures = maxFailures;
48579
48864
  }
48580
48865
  isEmpty() {
48581
48866
  return this.queue.length <= 0;
@@ -48585,6 +48870,7 @@ class SendQueue {
48585
48870
  this.unloads.clear();
48586
48871
  this.pending.clear();
48587
48872
  this.failures.clear();
48873
+ this.firstFailureTime = null;
48588
48874
  this.stopped = true;
48589
48875
  clearTimeout(this.timer);
48590
48876
  delete this.timer;
@@ -48605,12 +48891,16 @@ class SendQueue {
48605
48891
  incrementFailure(payload) {
48606
48892
  const failureCount = (this.failures.get(payload) || 0) + 1;
48607
48893
  this.failures.set(payload, failureCount);
48894
+ if (this.firstFailureTime == null) {
48895
+ this.firstFailureTime = new Date().getTime();
48896
+ }
48608
48897
  return failureCount;
48609
48898
  }
48610
48899
  pass(payload, dequeue = true) {
48611
48900
  this.unloads.delete(payload);
48612
48901
  this.pending.delete(payload);
48613
- this.failures.clear();
48902
+ this.failures.delete(payload);
48903
+ this.firstFailureTime = null;
48614
48904
  const index = this.queue.indexOf(payload);
48615
48905
  if (index >= 0) {
48616
48906
  this.queue.splice(index, 1);
@@ -48625,18 +48915,26 @@ class SendQueue {
48625
48915
  const failureCount = this.incrementFailure(payload);
48626
48916
  if (this.stopped || !retry)
48627
48917
  return;
48628
- if (failureCount >= this.maxFailures) {
48918
+ const now = new Date().getTime();
48919
+ const elapsed = now - (this.firstFailureTime || now);
48920
+ if (elapsed >= FAILURE_WINDOW_MS) {
48629
48921
  if (this.onTimeout) {
48630
48922
  this.onTimeout();
48631
48923
  }
48632
- this.pass(payload, false);
48924
+ this.firstFailureTime = null;
48925
+ this.retryLater(ONE_HOUR);
48926
+ return;
48633
48927
  }
48634
- this.retryLater(Math.pow(2, Math.min(failureCount - 1, MAX_BACKOFF)) * 1000);
48928
+ this.retryLater(Math.min(Math.pow(2, failureCount - 1) * 1000, MAX_RETRY_DELAY_MS));
48929
+ }
48930
+ retryNow() {
48931
+ clearTimeout(this.timer);
48932
+ delete this.timer;
48933
+ this.next();
48635
48934
  }
48636
48935
  retryLater(delay) {
48637
48936
  this.timer = setTimeout$1(() => {
48638
- delete this.timer;
48639
- this.next();
48937
+ this.retryNow();
48640
48938
  }, delay);
48641
48939
  }
48642
48940
  failed() {
@@ -48651,7 +48949,7 @@ class SendQueue {
48651
48949
  }
48652
48950
  drain(finalPayloadArray, isUnload = true) {
48653
48951
  this.queue.push(...finalPayloadArray);
48654
- if (this.failed())
48952
+ if (this.failed() && !this.allowDrainWhileFailed)
48655
48953
  return Promise$2.reject();
48656
48954
  const promises = [];
48657
48955
  for (const payload of this.queue) {
@@ -53712,6 +54010,7 @@ const RECORDING_CONFIG_TREAT_IFRAME_AS_ROOT = 'recording.treatIframeAsRoot';
53712
54010
  const RECORDING_CONFIG_DISABLE_UNLOAD = 'recording.disableUnload';
53713
54011
  const RESOURCE_CACHING = 'resourceCaching';
53714
54012
  const ONE_DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
54013
+ const ONE_MINUTE_IN_MILLISECONDS = 60 * 1000;
53715
54014
  const THIRTY_MINUTES = 1000 * 60 * 30;
53716
54015
  const ONE_HUNDRED_MB_IN_BYTES = 100 * 1024 * 1024;
53717
54016
  const SESSION_RECORDING_ID = 'pendo_srId';
@@ -53834,6 +54133,7 @@ class SessionRecorder {
53834
54133
  this.transport.onWorkerMessage = bind(this.onWorkerMessage, this);
53835
54134
  this.sendQueue = new SendQueue(bind(this.transport.send, this.transport));
53836
54135
  this.sendQueue.onTimeout = bind(this.sendFailure, this, 'SEND_TIMEOUT');
54136
+ this.errorHandler = this.pendo._.throttle(bind(this.logStopReason, this, 'RRWEB_ERROR'), ONE_MINUTE_IN_MILLISECONDS, { trailing: false });
53837
54137
  this.isNewSession = false;
53838
54138
  this.isCheckingVisitorEligibility = false;
53839
54139
  this.pageLifecycleListeners = [];
@@ -54128,7 +54428,7 @@ class SessionRecorder {
54128
54428
  var config = this.recordingConfig(visitorConfig);
54129
54429
  this._stop = this.record(this.pendo._.extend({
54130
54430
  emit: bind(this.emit, this),
54131
- errorHandler: bind(this.errorHandler, this)
54431
+ errorHandler: this.errorHandler
54132
54432
  }, config));
54133
54433
  this._refreshIds();
54134
54434
  this.onRecordingStart();
@@ -54240,9 +54540,6 @@ class SessionRecorder {
54240
54540
  return null;
54241
54541
  }
54242
54542
  }
54243
- errorHandler(error) {
54244
- this.logStopReason('RRWEB_ERROR', error);
54245
- }
54246
54543
  /**
54247
54544
  * Handle new rrweb events coming in. This will also make sure that we are properly sending a "keyframe"
54248
54545
  * as the BE expects it. A "keyframe" should consist of only the events needed to start a recording. This includes
@@ -54550,7 +54847,7 @@ class SessionRecorder {
54550
54847
  recordingPayload: [],
54551
54848
  sequence: 0,
54552
54849
  recordingPayloadCount: 0,
54553
- props: Object.assign({ reason }, (error && { error }))
54850
+ props: Object.assign({ reason }, (error && { error: error instanceof Error ? error === null || error === void 0 ? void 0 : error.message : error }))
54554
54851
  }, tracer);
54555
54852
  var jzb = this.pendo.compress(payload);
54556
54853
  var url = this.buildRequestUrl(`${this.pendo.HOST}/data/rec/${this.pendo.apiKey}`, {
@@ -56940,7 +57237,6 @@ var ConfigReader = (function () {
56940
57237
  * @type {number}
56941
57238
  */
56942
57239
  addOption('guideSeenTimeoutLength', [PENDO_CONFIG_SRC, SNIPPET_SRC], 10000);
56943
- // addOption('guideTimeout', [SNIPPET_SRC]); // old, use guides.timeout instead
56944
57240
  /**
56945
57241
  * If `true`, guides will be verified against their saved content hash before display to ensure validity of
56946
57242
  * guide content.
@@ -56974,7 +57270,7 @@ var ConfigReader = (function () {
56974
57270
  * @default false
56975
57271
  * @type {boolean}
56976
57272
  */
56977
- addOption('guides.delay', [SNIPPET_SRC], undefined, undefined, ['delayGuides']);
57273
+ addOption('guides.delay', [SNIPPET_SRC], false, undefined, ['delayGuides']);
56978
57274
  /**
56979
57275
  * Completely disables guides (this option has been moved from `disableGuides`).
56980
57276
  * Alias: `disableGuides`
@@ -56985,7 +57281,7 @@ var ConfigReader = (function () {
56985
57281
  * @default false
56986
57282
  * @type {boolean}
56987
57283
  */
56988
- addOption('guides.disabled', [SNIPPET_SRC], undefined, undefined, ['disableGuides']);
57284
+ addOption('guides.disabled', [SNIPPET_SRC], false, undefined, ['disableGuides']);
56989
57285
  /**
56990
57286
  * If 'true', guides with slow selectors will be removed from guide display processing.
56991
57287
  * This will improve application performance, but slow guides will not be shown to users.
@@ -58246,6 +58542,7 @@ function NetworkCapture() {
58246
58542
  let responseBodyCb;
58247
58543
  let pendoDevlogBaseUrl;
58248
58544
  let isCapturingNetworkLogs = false;
58545
+ let excludeRequestUrls = [];
58249
58546
  const CAPTURE_NETWORK_CONFIG = 'captureNetworkRequests';
58250
58547
  const NETWORK_SUB_TYPE = 'network';
58251
58548
  const NETWORK_LOGS_CONFIG = 'networkLogs';
@@ -58253,6 +58550,7 @@ function NetworkCapture() {
58253
58550
  const NETWORK_LOGS_CONFIG_ALLOWED_RESPONSE_HEADERS = 'networkLogs.allowedResponseHeaders';
58254
58551
  const NETWORK_LOGS_CONFIG_CAPTURE_REQUEST_BODY = 'networkLogs.captureRequestBody';
58255
58552
  const NETWORK_LOGS_CONFIG_CAPTURE_RESPONSE_BODY = 'networkLogs.captureResponseBody';
58553
+ const NETWORK_LOGS_CONFIG_EXCLUDE_REQUEST_URLS = 'networkLogs.excludeRequestUrls';
58256
58554
  const allowedRequestHeaders = {
58257
58555
  'content-type': true, 'content-length': true, 'accept': true, 'accept-language': true
58258
58556
  };
@@ -58283,6 +58581,8 @@ function NetworkCapture() {
58283
58581
  processBody,
58284
58582
  processRequestBody,
58285
58583
  processResponseBody,
58584
+ buildExcludeRequestUrls,
58585
+ isUrlExcluded,
58286
58586
  get isCapturingNetworkLogs() {
58287
58587
  return isCapturingNetworkLogs;
58288
58588
  },
@@ -58309,6 +58609,9 @@ function NetworkCapture() {
58309
58609
  },
58310
58610
  get responseBodyCb() {
58311
58611
  return responseBodyCb;
58612
+ },
58613
+ get excludeRequestUrls() {
58614
+ return excludeRequestUrls;
58312
58615
  }
58313
58616
  };
58314
58617
  function initialize(pendo, PluginAPI) {
@@ -58326,6 +58629,7 @@ function NetworkCapture() {
58326
58629
  processHeaderConfig(NETWORK_LOGS_CONFIG_ALLOWED_REQUEST_HEADERS, allowedRequestHeaders);
58327
58630
  processHeaderConfig(NETWORK_LOGS_CONFIG_ALLOWED_RESPONSE_HEADERS, allowedResponseHeaders);
58328
58631
  setupBodyCallbacks();
58632
+ buildExcludeRequestUrls();
58329
58633
  sendInterval = setInterval(() => {
58330
58634
  if (!sendQueue.failed()) {
58331
58635
  send();
@@ -58386,13 +58690,26 @@ function NetworkCapture() {
58386
58690
  * @type {function}
58387
58691
  */
58388
58692
  ConfigReader.addOption(NETWORK_LOGS_CONFIG_CAPTURE_RESPONSE_BODY, [ConfigReader.sources.SNIPPET_SRC], undefined);
58693
+ /**
58694
+ * A list of request URL patterns to exclude from network capture.
58695
+ * String patterns must match the full URL, including query parameters and fragments.
58696
+ * Use RegExp for flexible or partial matching.
58697
+ *
58698
+ * Example: `['https://example.com', new RegExp('https://test\\.com\\/.*'), /.*\\.domain\\.com/]`
58699
+ * @access public
58700
+ * @category Config/Network Logs
58701
+ * @name networkLogs.excludeRequestUrls
58702
+ * @default []
58703
+ * @type {Array<string|RegExp>}
58704
+ */
58705
+ ConfigReader.addOption(NETWORK_LOGS_CONFIG_EXCLUDE_REQUEST_URLS, [ConfigReader.sources.SNIPPET_SRC], []);
58389
58706
  }
58390
58707
  function processHeaderConfig(configHeaderName, targetHeaders) {
58391
58708
  const configHeaders = pluginAPI.ConfigReader.get(configHeaderName);
58392
58709
  if (!configHeaders || configHeaders.length === 0)
58393
58710
  return;
58394
58711
  globalPendo._.each(configHeaders, (header) => {
58395
- if (!header || typeof header !== 'string')
58712
+ if (!header || !globalPendo._.isString(header))
58396
58713
  return;
58397
58714
  targetHeaders[header.toLowerCase()] = true;
58398
58715
  });
@@ -58408,6 +58725,28 @@ function NetworkCapture() {
58408
58725
  responseBodyCb = config.captureResponseBody;
58409
58726
  }
58410
58727
  }
58728
+ function buildExcludeRequestUrls() {
58729
+ const requestUrls = pluginAPI.ConfigReader.get(NETWORK_LOGS_CONFIG_EXCLUDE_REQUEST_URLS);
58730
+ if (!requestUrls || requestUrls.length === 0)
58731
+ return;
58732
+ globalPendo._.each(requestUrls, (requestUrl) => {
58733
+ const processedRequestUrl = processUrlPattern(requestUrl);
58734
+ if (!processedRequestUrl)
58735
+ return;
58736
+ excludeRequestUrls.push(processedRequestUrl);
58737
+ });
58738
+ }
58739
+ function processUrlPattern(url) {
58740
+ if (!url)
58741
+ return;
58742
+ const isRegex = globalPendo._.isRegExp(url);
58743
+ if (!globalPendo._.isString(url) && !isRegex)
58744
+ return;
58745
+ if (isRegex)
58746
+ return url;
58747
+ const escapedUrl = pluginAPI.util.escapeRegExp(url);
58748
+ return new RegExp(`^${escapedUrl}$`);
58749
+ }
58411
58750
  function onPtmPaused() {
58412
58751
  isPtmPaused = true;
58413
58752
  }
@@ -58460,8 +58799,17 @@ function NetworkCapture() {
58460
58799
  pluginAPI.Events['recording:unpaused'].off(recordingStarted);
58461
58800
  pluginAPI.Events['recording:paused'].off(recordingStopped);
58462
58801
  }
58802
+ function isUrlExcluded(url) {
58803
+ if (!url || !globalPendo._.isString(url))
58804
+ return false;
58805
+ if (excludeRequestUrls.length === 0)
58806
+ return false;
58807
+ return globalPendo._.some(excludeRequestUrls, (excludeRequestUrl) => {
58808
+ return excludeRequestUrl.test(url);
58809
+ });
58810
+ }
58463
58811
  function handleRequest(request) {
58464
- if (!isCapturingNetworkLogs)
58812
+ if (!isCapturingNetworkLogs || !request || isUrlExcluded(request.url))
58465
58813
  return;
58466
58814
  requestMap[request.requestId] = request;
58467
58815
  }
@@ -58518,7 +58866,7 @@ function NetworkCapture() {
58518
58866
  }, []);
58519
58867
  }
58520
58868
  function processBody(body, contentType) {
58521
- if (!body || typeof body !== 'string')
58869
+ if (!body || !globalPendo._.isString(body))
58522
58870
  return '';
58523
58871
  const processedBody = maskSensitiveFields({ string: body, contentType, _: globalPendo._ });
58524
58872
  return truncate(processedBody, true);