@pendo/agent 2.290.1 → 2.291.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.
@@ -2992,7 +2992,8 @@ var ConfigReader = (function () {
2992
2992
  /**
2993
2993
  * Use this setting when using `preferMutationObserver` with an application that has Shadow DOM elements.
2994
2994
  * On page load, the Agent will run a full document scan for shadow roots and attach a MutationObserver to
2995
- * all results.
2995
+ * all results. This setting also allows the agent to run CSS selectors in all shadow roots, so CSS selectors
2996
+ * can be written without specifying the full path through all shadow roots with the `::shadow` pseudo-class.
2996
2997
  *
2997
2998
  * @access public
2998
2999
  * @category Config/Core
@@ -3903,8 +3904,8 @@ var SERVER = '';
3903
3904
  var ASSET_HOST = '';
3904
3905
  var ASSET_PATH = '';
3905
3906
  var DESIGNER_SERVER = '';
3906
- var VERSION = '2.290.1_';
3907
- var PACKAGE_VERSION = '2.290.1';
3907
+ var VERSION = '2.291.0_';
3908
+ var PACKAGE_VERSION = '2.291.0';
3908
3909
  var LOADER = 'xhr';
3909
3910
  /* eslint-enable agent-eslint-rules/no-gulp-env-references */
3910
3911
  /**
@@ -10060,15 +10061,15 @@ var setStyles = function (element, style) {
10060
10061
  }
10061
10062
  });
10062
10063
  };
10063
- var getScreenDimensions = function () {
10064
+ var getScreenDimensions = function (win = window) {
10064
10065
  if (isBrowserInQuirksmode()) {
10065
10066
  return {
10066
- width: document.documentElement.offsetWidth || 0,
10067
- height: document.documentElement.offsetHeight || 0
10067
+ width: win.document.documentElement.offsetWidth || 0,
10068
+ height: win.document.documentElement.offsetHeight || 0
10068
10069
  };
10069
10070
  }
10070
- var w = window.innerWidth || document.documentElement.clientWidth;
10071
- var h = window.innerHeight || document.documentElement.clientHeight;
10071
+ var w = win.innerWidth || win.document.documentElement.clientWidth;
10072
+ var h = win.innerHeight || win.document.documentElement.clientHeight;
10072
10073
  return { width: w, height: h };
10073
10074
  };
10074
10075
  var _isInViewport = function (elemPos) {
@@ -10204,32 +10205,34 @@ function getSiblings(node) {
10204
10205
  * @param {HTMLElement} element
10205
10206
  * @returns {boolean}
10206
10207
  */
10207
- function isInDocument(element) {
10208
- if (SizzleProxy.contains(document, element))
10208
+ function isInDocument(element, doc = document) {
10209
+ if (SizzleProxy.contains(doc, element))
10209
10210
  return true;
10210
10211
  while (element && element.parentNode || shadowAPI.isElementShadowRoot(element)) {
10211
10212
  element = shadowAPI.getParent(element);
10212
10213
  }
10213
- return element === document;
10214
+ return element === doc;
10214
10215
  }
10215
10216
  var getClientRect = function (element) {
10216
- var pbody = getBody();
10217
- if (element === null) {
10217
+ if (element == null) {
10218
10218
  return;
10219
10219
  }
10220
- else if ((element === document || element === window)) {
10220
+ var doc = element.ownerDocument || document;
10221
+ var win = doc.defaultView || window;
10222
+ var pbody = getBody(doc);
10223
+ if ((element === doc || element === win)) {
10221
10224
  var viewport = {
10222
- left: window.pageXOffset || pbody.scrollLeft,
10223
- top: window.pageYOffset || pbody.scrollTop,
10224
- width: window.innerWidth,
10225
- height: window.innerHeight
10225
+ left: win.pageXOffset || pbody.scrollLeft,
10226
+ top: win.pageYOffset || pbody.scrollTop,
10227
+ width: win.innerWidth,
10228
+ height: win.innerHeight
10226
10229
  };
10227
10230
  viewport.right = viewport.left + viewport.width;
10228
10231
  viewport.bottom = viewport.top + viewport.height;
10229
10232
  return viewport;
10230
10233
  }
10231
10234
  else {
10232
- var clientRect = getOffsetPosition(element);
10235
+ var clientRect = getOffsetPosition(element, win);
10233
10236
  clientRect.right = clientRect.left + clientRect.width;
10234
10237
  clientRect.bottom = clientRect.top + clientRect.height;
10235
10238
  return clientRect;
@@ -11034,7 +11037,7 @@ DomQuery.$ = {
11034
11037
  if (target && target.parentNode) {
11035
11038
  target.parentNode.insertBefore(this[0], target);
11036
11039
  // Execute scripts (if any) when the fragment enters the document
11037
- if (isInDocument(document)) {
11040
+ if (isInDocument(document, this)) {
11038
11041
  _.each(SizzleProxy('script', this[0]), evalScript);
11039
11042
  }
11040
11043
  }
@@ -13782,7 +13785,7 @@ function treatAsMobileDevice() {
13782
13785
  }
13783
13786
  return sniffer.isMobileUserAgent();
13784
13787
  }
13785
- function getGuideAttachPoint() {
13788
+ function getGuideAttachPoint(doc = document) {
13786
13789
  var attachPoint = getGuideAttachPoint.attachPoint;
13787
13790
  if (attachPoint == null) {
13788
13791
  var attachPointSelector = ConfigReader.get('guides.attachPoint');
@@ -13805,7 +13808,7 @@ function getGuideAttachPoint() {
13805
13808
  }
13806
13809
  getGuideAttachPoint.attachPoint = attachPoint;
13807
13810
  }
13808
- return attachPoint || getBody();
13811
+ return attachPoint || getBody(doc);
13809
13812
  }
13810
13813
  var findBadgeForStep = function (step) {
13811
13814
  var badge = badgesShown[step.guideId];
@@ -13828,7 +13831,7 @@ var findBadgeForStep = function (step) {
13828
13831
  * where do we render? find destination for that.
13829
13832
  */
13830
13833
  // this is used for rendering
13831
- var getElementForGuideStep = function (step) {
13834
+ var getElementForGuideStep = function (step, doc) {
13832
13835
  if (!step) {
13833
13836
  log.info('Can\'t get element for null step');
13834
13837
  return null;
@@ -13839,20 +13842,20 @@ var getElementForGuideStep = function (step) {
13839
13842
  if (!step.overrideElement && canSetOverrideElement) {
13840
13843
  step.overrideElement = findBadgeForStep(step);
13841
13844
  }
13842
- step.targetElement = getElementForTargeting(step);
13845
+ step.targetElement = getElementForTargeting(step, doc);
13843
13846
  if (step.overrideElement) {
13844
13847
  return step.overrideElement;
13845
13848
  }
13846
13849
  return step.targetElement;
13847
13850
  };
13848
- var getElementForTargeting = function (step) {
13851
+ var getElementForTargeting = function (step, doc) {
13849
13852
  var selector = step.elementPathRule || null;
13850
13853
  var results;
13851
13854
  if (selector) {
13852
- results = SizzleProxy(selector);
13855
+ results = SizzleProxy(selector, doc);
13853
13856
  }
13854
13857
  else {
13855
- results = [getBody()];
13858
+ results = [getBody(doc)];
13856
13859
  }
13857
13860
  if (results.length === 0) {
13858
13861
  return null;
@@ -16046,7 +16049,7 @@ var BuildingBlockTooltips = (function () {
16046
16049
  const guideContainer = providedGuideContainer || getGuideContainer(step);
16047
16050
  if (!guideContainer)
16048
16051
  return;
16049
- const element = step.element || getElementForGuideStep(step);
16052
+ const element = step.element || getElementForGuideStep(step, guideContainer.ownerDocument);
16050
16053
  if (!element)
16051
16054
  return;
16052
16055
  const width = guideContainer.style.width;
@@ -16071,9 +16074,10 @@ var BuildingBlockTooltips = (function () {
16071
16074
  return treatAsMobileDevice() ? MOBILE_TOOLTIP_CSS_NAME : TOOLTIP_CSS_NAME;
16072
16075
  }
16073
16076
  function getTooltipPositioningContext(step, element, json, guideContainer) {
16074
- var elementPos = getOffsetPosition(element);
16077
+ var targetWindow = element.ownerDocument.defaultView;
16078
+ var elementPos = getOffsetPosition(element, targetWindow);
16075
16079
  var screenPos = getScreenPosition(element);
16076
- var screenDimensions = getScreenDimensions();
16080
+ var screenDimensions = getScreenDimensions(targetWindow);
16077
16081
  var layoutDir = step.attributes.layoutDir || 'auto';
16078
16082
  // RETURN IF THE FOUND ELEMENT IS NOT VISIBLE ON THE SCREEN.
16079
16083
  if (elementPos.height === 0 && elementPos.width === 0) {
@@ -16121,7 +16125,7 @@ var BuildingBlockTooltips = (function () {
16121
16125
  var tooltipDiv = step.guideElement;
16122
16126
  tooltipDiv.addClass(buildTooltipCSSName());
16123
16127
  attachBBAdvanceActions(step);
16124
- var tooltipDimensions = getBBTooltipDimensions(elementPos, { height: tooltipSizes.height, width: tooltipSizes.width }, caretDimensions, step.attributes.layoutDir, screenPos);
16128
+ var tooltipDimensions = getBBTooltipDimensions(elementPos, { height: tooltipSizes.height, width: tooltipSizes.width }, caretDimensions, step.attributes.layoutDir, screenPos, tooltipContext.screenDimensions);
16125
16129
  if (step) {
16126
16130
  step.dim = tooltipDimensions;
16127
16131
  }
@@ -16200,8 +16204,7 @@ var BuildingBlockTooltips = (function () {
16200
16204
  }
16201
16205
  }
16202
16206
  }
16203
- function getBBTooltipDimensions(elementPos, tooltipSizes, caretSizes, layoutDir, screenPos) {
16204
- var screenDimensions = getScreenDimensions();
16207
+ function getBBTooltipDimensions(elementPos, tooltipSizes, caretSizes, layoutDir, screenPos, screenDimensions) {
16205
16208
  var layoutDirection = layoutDir || 'auto';
16206
16209
  var tooltipDimensions = {
16207
16210
  width: Math.min(tooltipSizes.width, screenDimensions.width),
@@ -16331,23 +16334,23 @@ var BuildingBlockTooltips = (function () {
16331
16334
  else if (layoutDirection === 'top') {
16332
16335
  tooltipPosition.top = elementPosition.top - height;
16333
16336
  }
16334
- const boundaries = getBoundaries();
16337
+ const boundaries = getBoundaries(screenDimensions);
16335
16338
  if (horizontalBias === 'right') {
16336
16339
  tooltipPosition.left = calculateRightBiasPosition(elementPosition, tooltipDimensions, caretSizes, screenDimensions, boundaries.right, boundaries.left);
16337
16340
  }
16338
16341
  else if (horizontalBias === 'left') {
16339
- tooltipPosition.left = calculateLeftBiasPosition(elementPosition, tooltipDimensions, caretSizes, boundaries.right, boundaries.left);
16342
+ tooltipPosition.left = calculateLeftBiasPosition(elementPosition, tooltipDimensions, caretSizes, screenDimensions, boundaries.right, boundaries.left);
16340
16343
  }
16341
16344
  else {
16342
16345
  // ASSUME CENTER
16343
- tooltipPosition.left = calculateCenterBiasPosition(elementPosition, tooltipDimensions, boundaries.right, boundaries.left);
16346
+ tooltipPosition.left = calculateCenterBiasPosition(elementPosition, tooltipDimensions, screenDimensions, boundaries.right, boundaries.left);
16344
16347
  }
16345
16348
  return tooltipPosition;
16346
16349
  }
16347
- function getBoundaries() {
16350
+ function getBoundaries(screenDimensions) {
16348
16351
  return {
16349
- right: window.innerWidth * TOOLTIP_CONSTANTS.BOUNDARY_MARGIN_RIGHT,
16350
- left: window.innerWidth * TOOLTIP_CONSTANTS.BOUNDARY_MARGIN_LEFT
16352
+ right: screenDimensions.width * TOOLTIP_CONSTANTS.BOUNDARY_MARGIN_RIGHT,
16353
+ left: screenDimensions.width * TOOLTIP_CONSTANTS.BOUNDARY_MARGIN_LEFT
16351
16354
  };
16352
16355
  }
16353
16356
  function calculateCaretPadding(caretSizes) {
@@ -16368,7 +16371,7 @@ var BuildingBlockTooltips = (function () {
16368
16371
  if (tooltipRight > rightBoundary) {
16369
16372
  const overflow = tooltipRight - rightBoundary;
16370
16373
  if (leftVal - overflow < leftBoundary) {
16371
- return spaceEvenly(leftVal, width);
16374
+ return spaceEvenly(leftVal, width, screenDimensions);
16372
16375
  }
16373
16376
  else {
16374
16377
  return leftVal - overflow;
@@ -16376,7 +16379,7 @@ var BuildingBlockTooltips = (function () {
16376
16379
  }
16377
16380
  return leftVal;
16378
16381
  }
16379
- function calculateLeftBiasPosition(elementPosition, tooltipDimensions, caretSizes, rightBoundary, leftBoundary) {
16382
+ function calculateLeftBiasPosition(elementPosition, tooltipDimensions, caretSizes, screenDimensions, rightBoundary, leftBoundary) {
16380
16383
  const caretPadding = calculateCaretPadding(caretSizes);
16381
16384
  const width = tooltipDimensions.width;
16382
16385
  var leftVal = elementPosition.left - width + (elementPosition.width / 2) + caretPadding;
@@ -16384,7 +16387,7 @@ var BuildingBlockTooltips = (function () {
16384
16387
  const overflow = leftBoundary - leftVal;
16385
16388
  const tooltipRight = leftVal + width;
16386
16389
  if (tooltipRight + overflow > rightBoundary) {
16387
- return spaceEvenly(leftVal, width);
16390
+ return spaceEvenly(leftVal, width, screenDimensions);
16388
16391
  }
16389
16392
  else {
16390
16393
  return leftVal + overflow;
@@ -16392,7 +16395,7 @@ var BuildingBlockTooltips = (function () {
16392
16395
  }
16393
16396
  return leftVal;
16394
16397
  }
16395
- function calculateCenterBiasPosition(elementPosition, tooltipDimensions, rightBoundary, leftBoundary) {
16398
+ function calculateCenterBiasPosition(elementPosition, tooltipDimensions, screenDimensions, rightBoundary, leftBoundary) {
16396
16399
  const width = tooltipDimensions.width;
16397
16400
  var leftVal = elementPosition.left + (elementPosition.width / 2) - (width / 2);
16398
16401
  let tooltipRight = leftVal + width;
@@ -16400,7 +16403,7 @@ var BuildingBlockTooltips = (function () {
16400
16403
  const overflow = tooltipRight - rightBoundary;
16401
16404
  leftVal -= overflow;
16402
16405
  if (leftVal < leftBoundary) {
16403
- return spaceEvenly(leftVal, width);
16406
+ return spaceEvenly(leftVal, width, screenDimensions);
16404
16407
  }
16405
16408
  }
16406
16409
  else if (leftVal < leftBoundary) {
@@ -16408,14 +16411,14 @@ var BuildingBlockTooltips = (function () {
16408
16411
  leftVal += overflow;
16409
16412
  let tooltipRight = leftVal + width;
16410
16413
  if (tooltipRight > rightBoundary) {
16411
- return spaceEvenly(leftVal, width);
16414
+ return spaceEvenly(leftVal, width, screenDimensions);
16412
16415
  }
16413
16416
  }
16414
16417
  return leftVal;
16415
16418
  }
16416
- function spaceEvenly(leftVal, width) {
16419
+ function spaceEvenly(leftVal, width, screenDimensions) {
16417
16420
  const availableLeftSpace = leftVal;
16418
- const availableRightSpace = window.innerWidth - (leftVal + width);
16421
+ const availableRightSpace = screenDimensions.width - (leftVal + width);
16419
16422
  if (availableLeftSpace > availableRightSpace) {
16420
16423
  return leftVal - (availableLeftSpace - availableRightSpace) / 2;
16421
16424
  }
@@ -16638,8 +16641,10 @@ var BuildingBlockTooltips = (function () {
16638
16641
  var guideContainer = providedGuideContainer || getGuideContainer(step);
16639
16642
  if (!guideContainer)
16640
16643
  return;
16641
- var element = step.element || getElementForGuideStep(step);
16642
- var elPos = getOffsetPosition(element);
16644
+ var targetDocument = guideContainer.ownerDocument;
16645
+ var targetWindow = targetDocument.defaultView;
16646
+ var element = step.element || getElementForGuideStep(step, targetDocument);
16647
+ var elPos = getOffsetPosition(element, targetWindow);
16643
16648
  // If display:none then don't re-position
16644
16649
  if (getComputedStyle_safe(step.elements[0]).display === 'none')
16645
16650
  return;
@@ -16661,7 +16666,7 @@ var BuildingBlockTooltips = (function () {
16661
16666
  borderColor: ttContainerStyles.borderColor,
16662
16667
  borderWidth: parseInt(ttContainerStyles.borderWidth, 10) || 0
16663
16668
  };
16664
- var tooltipDimensions = this.getBBTooltipDimensions(elPos, tooltipSizes, caretStyles, layoutDir, screenPos);
16669
+ var tooltipDimensions = this.getBBTooltipDimensions(elPos, tooltipSizes, caretStyles, layoutDir, screenPos, getScreenDimensions(targetWindow));
16665
16670
  if (caretStyles.height && caretStyles.width) {
16666
16671
  var caretDiv = ttdiv.find('.pendo-tooltip-caret')[0];
16667
16672
  var borderCaret = ttdiv.find('.pendo-tooltip-caret-border')[0];
@@ -20028,6 +20033,9 @@ var GuideStateModule = (function () {
20028
20033
  }
20029
20034
  context.commit('setLastGuideStepSeen', lastGuideStepSeen);
20030
20035
  pendo$1.lastGuideStepSeen = lastGuideStepSeen;
20036
+ if (guideCache) {
20037
+ guideCache.update(lastGuideStepSeen);
20038
+ }
20031
20039
  },
20032
20040
  updateThrottlingState(context, state) {
20033
20041
  context.commit('setThrottlingState', state);
@@ -21362,6 +21370,16 @@ Badge.behaviors = [
21362
21370
  ShowOnHover
21363
21371
  ];
21364
21372
  function InlinePosition() {
21373
+ function getShadowDomAdjustedTarget(target) {
21374
+ try {
21375
+ if (target.shadowRoot && !target.shadowRoot.querySelector('slot')) {
21376
+ return target.shadowRoot;
21377
+ }
21378
+ }
21379
+ catch (e) {
21380
+ }
21381
+ return target;
21382
+ }
21365
21383
  if (this.position === 'inline' || this.position === 'inline-right' || this.position === 'inline-left') {
21366
21384
  this.before('show', function () {
21367
21385
  var targetElem = this.target();
@@ -21374,18 +21392,19 @@ function InlinePosition() {
21374
21392
  }
21375
21393
  if (targetElem && targetElem.tagName) {
21376
21394
  var tagName = targetElem.tagName.toLowerCase();
21395
+ var shadowDomAdjustedTarget = getShadowDomAdjustedTarget(targetElem);
21377
21396
  if (/br|input|img|select|textarea/.test(tagName)) {
21378
21397
  if (badgeElem.parentNode === targetElem.parentNode)
21379
21398
  return;
21380
21399
  // Insert after if targetElem cannot have children
21381
21400
  targetElem.parentNode.insertBefore(badgeElem, targetElem.nextSibling);
21382
21401
  }
21383
- else if (badgeElem.parentNode !== targetElem) {
21402
+ else if (badgeElem.parentNode !== shadowDomAdjustedTarget) {
21384
21403
  if (this.position === 'inline' || this.position === 'inline-right') {
21385
- targetElem.appendChild(badgeElem);
21404
+ shadowDomAdjustedTarget.appendChild(badgeElem);
21386
21405
  }
21387
21406
  else if (this.position === 'inline-left') {
21388
- targetElem.prepend(badgeElem);
21407
+ shadowDomAdjustedTarget.prepend(badgeElem);
21389
21408
  }
21390
21409
  }
21391
21410
  }
@@ -23229,7 +23248,7 @@ var BuildingBlockWatermark = (function () {
23229
23248
  }
23230
23249
  function buildWatermark(options, buildNodeFromJSON) {
23231
23250
  options = options || {};
23232
- if (!options.isTraining)
23251
+ if (!options.isTraining || options.isEmbedded)
23233
23252
  return;
23234
23253
  var watermarkGuide = options.targetAccount ? findWatermarkByTargetAccount(options.targetAccount) : findWatermarkByAppId(options.appId);
23235
23254
  if (!watermarkGuide || !watermarkGuide.steps)
@@ -23802,6 +23821,149 @@ function testGuideGifEndpoint(loader, apiKey) {
23802
23821
  });
23803
23822
  }
23804
23823
 
23824
+ function deepClone(obj) {
23825
+ return JSON.parse(JSON.stringify(obj));
23826
+ }
23827
+ class GuideCache {
23828
+ constructor(apiKey, ConfigReader) {
23829
+ this.apiKey = apiKey;
23830
+ this.cacheGuides = ConfigReader.get('cacheGuides');
23831
+ this.cacheGuidesTimeout = ConfigReader.get('cacheGuidesTimeout');
23832
+ this.cacheGuidesPersistent = ConfigReader.get('cacheGuidesPersistent');
23833
+ this.cache = null;
23834
+ this.db = null;
23835
+ }
23836
+ openDB(apiKey, indexedDB = window.indexedDB) {
23837
+ if (!this.cacheGuidesPersistent)
23838
+ return q.resolve();
23839
+ if (this.db)
23840
+ return q.resolve(this.db);
23841
+ const deferred = q.defer();
23842
+ const request = indexedDB.open(`pendo-${apiKey}`, 1);
23843
+ request.onerror = () => {
23844
+ log.warn('Error opening guide database');
23845
+ this.cacheGuidesPersistent = false;
23846
+ deferred.resolve();
23847
+ };
23848
+ request.onsuccess = (event) => {
23849
+ const db = event.target.result;
23850
+ this.db = db;
23851
+ deferred.resolve(db);
23852
+ };
23853
+ request.onupgradeneeded = (event) => {
23854
+ const db = event.target.result;
23855
+ const objectStore = db.createObjectStore('guides', { keyPath: 'guide.id' });
23856
+ objectStore.transaction.oncomplete = () => {
23857
+ this.db = db;
23858
+ deferred.resolve(db);
23859
+ };
23860
+ };
23861
+ return deferred.promise;
23862
+ }
23863
+ load(now = getNow()) {
23864
+ if (this.cache)
23865
+ return q.resolve(this.cache);
23866
+ this.cache = {};
23867
+ if (!this.db)
23868
+ return q.resolve(this.cache);
23869
+ const deferred = q.defer();
23870
+ const objectStore = this.db.transaction(['guides'], 'readwrite').objectStore('guides');
23871
+ const request = objectStore.getAll();
23872
+ request.onerror = () => {
23873
+ log.warn('Error loading guide cache');
23874
+ this.cacheGuidesPersistent = false;
23875
+ this.db = null;
23876
+ deferred.resolve(this.cache);
23877
+ };
23878
+ request.onsuccess = (event) => {
23879
+ const cachedGuides = event.target.result;
23880
+ _.each(cachedGuides, (cachedGuide) => {
23881
+ if (cachedGuide.expires > now) {
23882
+ this.cache[cachedGuide.guide.id] = cachedGuide;
23883
+ }
23884
+ else {
23885
+ objectStore.delete(cachedGuide.guide.id);
23886
+ }
23887
+ });
23888
+ deferred.resolve(this.cache);
23889
+ };
23890
+ return deferred.promise;
23891
+ }
23892
+ add(guide, visitorId, now = getNow()) {
23893
+ if (!this.cacheGuides)
23894
+ return;
23895
+ if (!this.cache)
23896
+ return;
23897
+ const cachedGuide = {
23898
+ expires: now + this.cacheGuidesTimeout,
23899
+ visitorId,
23900
+ guide: deepClone(guide)
23901
+ };
23902
+ this.cache[guide.id] = cachedGuide;
23903
+ return this.save(cachedGuide);
23904
+ }
23905
+ save(cachedGuide) {
23906
+ if (!this.db)
23907
+ return;
23908
+ const objectStore = this.db.transaction(['guides'], 'readwrite').objectStore('guides');
23909
+ const deferred = q.defer();
23910
+ const update = objectStore.put(cachedGuide);
23911
+ update.onerror = () => {
23912
+ log.warn(`Error saving guide to cache ${cachedGuide.guide.id}`);
23913
+ deferred.resolve();
23914
+ };
23915
+ update.onsuccess = () => {
23916
+ deferred.resolve();
23917
+ };
23918
+ return deferred.promise;
23919
+ }
23920
+ update(lastGuideStepSeen) {
23921
+ if (!this.cache)
23922
+ return;
23923
+ const cachedGuide = this.cache[lastGuideStepSeen.guideId];
23924
+ if (!cachedGuide)
23925
+ return;
23926
+ const cachedStep = _.find(cachedGuide.guide.steps, (s) => s.id === lastGuideStepSeen.guideStepId);
23927
+ if (!cachedStep)
23928
+ return;
23929
+ cachedStep.seenState = lastGuideStepSeen.state;
23930
+ cachedStep.seenReason = lastGuideStepSeen.seenReason;
23931
+ cachedStep.dismissCount = lastGuideStepSeen.dismissCount;
23932
+ cachedStep.snoozeEndTime = lastGuideStepSeen.snoozeEndTime;
23933
+ return this.save(cachedGuide);
23934
+ }
23935
+ list(visitorId, now = getNow()) {
23936
+ if (!this.cacheGuides)
23937
+ return q.resolve([]);
23938
+ return this.openDB(this.apiKey).then(() => {
23939
+ return this.load(now);
23940
+ }).then(() => {
23941
+ const list = [];
23942
+ _.each(this.cache, (cachedGuide) => {
23943
+ if (cachedGuide.expires > now && cachedGuide.visitorId === visitorId) {
23944
+ list.push(_.pick(cachedGuide.guide, 'id', 'lastUpdatedAt', 'language'));
23945
+ }
23946
+ else {
23947
+ delete this.cache[cachedGuide.guide.id];
23948
+ }
23949
+ });
23950
+ return list;
23951
+ });
23952
+ }
23953
+ get(guideId) {
23954
+ if (this.cache && this.cache[guideId]) {
23955
+ return deepClone(this.cache[guideId].guide);
23956
+ }
23957
+ }
23958
+ clear() {
23959
+ this.cache = {};
23960
+ if (this.db) {
23961
+ const objectStore = this.db.transaction(['guides'], 'readwrite').objectStore('guides');
23962
+ objectStore.clear();
23963
+ }
23964
+ }
23965
+ }
23966
+
23805
23967
  const pendoLocalStorage$1 = agentStorage.getLocal();
23806
23968
  var guideEvtCache = [];
23807
23969
  var controlGuideLogMessage = 'Guide was not shown because this visitor is in a control group of an active experiment for the guide';
@@ -25043,14 +25205,6 @@ function handleDoNotProcess() {
25043
25205
  store.commit('debugger/doNotProcess', true);
25044
25206
  log.info('not tracking visitor due to 451 response');
25045
25207
  }
25046
- function resetCachedGuide(guide) {
25047
- _.each(guide.steps, function (step) {
25048
- if (_.get(step, 'attributes.stayHidden')) {
25049
- delete step.attributes.stayHidden;
25050
- }
25051
- });
25052
- return guide;
25053
- }
25054
25208
  function guidesPayload(guidesJson) {
25055
25209
  if (!mostRecentGuideRequest)
25056
25210
  return;
@@ -25060,13 +25214,13 @@ function guidesPayload(guidesJson) {
25060
25214
  }
25061
25215
  if (_.isString(guidesJson.id) && guidesJson.id !== mostRecentGuideRequest.id)
25062
25216
  return;
25063
- const cachedGuides = _.indexBy(pendo$1.guides, 'id');
25064
25217
  _.extend(pendo$1, guidesJson);
25065
25218
  pendo$1.guides = _.map(pendo$1.guides, function (guide) {
25066
25219
  if (_.keys(guide).length == 1 && guide.id) {
25067
- return resetCachedGuide(cachedGuides[guide.id]);
25220
+ return guideCache.get(guide.id);
25068
25221
  }
25069
25222
  else {
25223
+ guideCache.add(guide, get_visitor_id());
25070
25224
  return guide;
25071
25225
  }
25072
25226
  });
@@ -25101,48 +25255,53 @@ var loadGuideJs = function (apiKey, params) {
25101
25255
  log.info('no metadata to send', { contexts: ['guides', 'metadata'] });
25102
25256
  }
25103
25257
  }
25104
- var jzb = compress(params);
25105
- var queryString = {
25106
- id: guideRequestId,
25107
- jzb,
25108
- v: VERSION,
25109
- ct: (new Date()).getTime()
25110
- };
25111
- if (isAdoptPartner && params.accountId && params.accountId !== 'ACCOUNT-UNIQUE-ID') {
25112
- queryString.acc = base64EncodeString(params.accountId);
25113
- }
25114
- if (isDebuggingEnabled()) {
25115
- // Include debug info from server
25116
- queryString.debug = true;
25117
- }
25118
- var url = buildBaseDataUrl(guideLoaderImpl.endpoint(), apiKey, queryString);
25119
- var loadingPromise;
25120
- var jwtOptions = JWT.get();
25121
- if (url.length > URL_MAX_LENGTH || !_.isEmpty(jwtOptions)) {
25122
- delete queryString.jzb;
25123
- url = buildBaseDataUrl('guide.json', apiKey, queryString);
25124
- var payload = _.extend({ events: jzb }, jwtOptions);
25125
- loadingPromise = guideLoaderImpl.post(url, payload, pendo$1, _.noop);
25126
- }
25127
- else {
25128
- loadingPromise = guideLoaderImpl.load(url, pendo$1, _.noop);
25129
- }
25130
- return q.all([
25131
- // eslint-disable-next-line dot-notation
25132
- loadingPromise['catch'](function (result) {
25133
- if (result.status === 451) {
25134
- handleDoNotProcess();
25135
- }
25136
- // passthrough rejections to subscribers
25137
- return q.reject(result);
25138
- }),
25139
- deferred.promise,
25140
- testGuideGifEndpoint(guideLoaderImpl, apiKey)
25141
- ]).then(function ([, , testGuideGifResult]) {
25142
- setGuidesBlocked(testGuideGifResult);
25143
- if (!testGuideGifResult.success) {
25144
- return q.reject();
25258
+ return guideCache.list(params.visitorId).then(cachedGuides => {
25259
+ if (cachedGuides.length > 0) {
25260
+ params.cachedGuides = cachedGuides;
25145
25261
  }
25262
+ var jzb = compress(params);
25263
+ var queryString = {
25264
+ id: guideRequestId,
25265
+ jzb,
25266
+ v: VERSION,
25267
+ ct: (new Date()).getTime()
25268
+ };
25269
+ if (isAdoptPartner && params.accountId && params.accountId !== 'ACCOUNT-UNIQUE-ID') {
25270
+ queryString.acc = base64EncodeString(params.accountId);
25271
+ }
25272
+ if (isDebuggingEnabled()) {
25273
+ // Include debug info from server
25274
+ queryString.debug = true;
25275
+ }
25276
+ var url = buildBaseDataUrl(guideLoaderImpl.endpoint(), apiKey, queryString);
25277
+ var jwtOptions = JWT.get();
25278
+ let loadingPromise;
25279
+ if (url.length > URL_MAX_LENGTH || !_.isEmpty(jwtOptions)) {
25280
+ delete queryString.jzb;
25281
+ url = buildBaseDataUrl('guide.json', apiKey, queryString);
25282
+ var payload = _.extend({ events: jzb }, jwtOptions);
25283
+ loadingPromise = guideLoaderImpl.post(url, payload, pendo$1, _.noop);
25284
+ }
25285
+ else {
25286
+ loadingPromise = guideLoaderImpl.load(url, pendo$1, _.noop);
25287
+ }
25288
+ return q.all([
25289
+ // eslint-disable-next-line dot-notation
25290
+ loadingPromise['catch'](function (result) {
25291
+ if (result.status === 451) {
25292
+ handleDoNotProcess();
25293
+ }
25294
+ // passthrough rejections to subscribers
25295
+ return q.reject(result);
25296
+ }),
25297
+ deferred.promise,
25298
+ testGuideGifEndpoint(guideLoaderImpl, apiKey)
25299
+ ]).then(function ([, , testGuideGifResult]) {
25300
+ setGuidesBlocked(testGuideGifResult);
25301
+ if (!testGuideGifResult.success) {
25302
+ return q.reject();
25303
+ }
25304
+ });
25146
25305
  });
25147
25306
  };
25148
25307
  var guideLoaderImpl = XHRGuideLoader;
@@ -25255,18 +25414,6 @@ function shouldLoadGuides(visitorId, callback) {
25255
25414
  }
25256
25415
  return true;
25257
25416
  }
25258
- function getCachedGuideList(pendo, cacheInfo, now = getNow()) {
25259
- let cachedGuides = [];
25260
- if (ConfigReader.get('cacheGuides')) {
25261
- if (now - (cacheInfo.lastUncached || 0) < ConfigReader.get('cacheGuidesTimeout')) {
25262
- cachedGuides = _.map(pendo.guides, guide => _.pick(guide, 'id', 'lastUpdatedAt', 'language'));
25263
- }
25264
- if (!cachedGuides.length) {
25265
- cacheInfo.lastUncached = now;
25266
- }
25267
- }
25268
- return cachedGuides;
25269
- }
25270
25417
  /**
25271
25418
  * Manually load guides for current visitor and URL. This is typically handled automatically by the Agent
25272
25419
  * whenever the host Application changes its URL. In rare circumstances, a host Application may chose to
@@ -25301,10 +25448,6 @@ var loadGuides = function (apiKey, visitorId, page, callback) {
25301
25448
  url: page,
25302
25449
  oldVisitorId: get_old_visitor_id()
25303
25450
  };
25304
- const cachedGuides = getCachedGuideList(pendo$1, loadGuides);
25305
- if (cachedGuides.length && !visitorChanged) {
25306
- params.cachedGuides = cachedGuides;
25307
- }
25308
25451
  const reqId = _.uniqueId();
25309
25452
  loadGuides.reqId = reqId;
25310
25453
  loadGuideJs(apiKey, params).then(function () {
@@ -25589,6 +25732,7 @@ function securityPolicyViolationFn(evt) {
25589
25732
  forceGuideReload();
25590
25733
  }
25591
25734
  }
25735
+ let guideCache;
25592
25736
  /**
25593
25737
  * Resets and starts guide loop
25594
25738
  *
@@ -25602,6 +25746,7 @@ var initGuides = function (observer) {
25602
25746
  teardownFns.push(initGuideAnalytics({
25603
25747
  localStorageUnload: ConfigReader.get('analytics.localStorageUnload')
25604
25748
  }));
25749
+ guideCache = new GuideCache(pendo$1.apiKey, ConfigReader);
25605
25750
  GuideMonitor.run();
25606
25751
  teardownFns.push(GuideMonitor.stop);
25607
25752
  Events.appUnloaded.on(function () {
@@ -25717,6 +25862,7 @@ var initGuides = function (observer) {
25717
25862
  agentStorage.registry.addLocal(AD_BLOCK_STORAGE_KEY, { duration: 14400000 }); // 4 hours default duration
25718
25863
  GuideRuntime.initialize();
25719
25864
  return () => {
25865
+ guideCache = null;
25720
25866
  reloadGuides.reset();
25721
25867
  resetPendoUI();
25722
25868
  cancelGuideRequest();
@@ -27157,6 +27303,7 @@ class UberMutationObserver extends EventTarget {
27157
27303
  this.ObserverClass = observerClass;
27158
27304
  this.observing = false;
27159
27305
  this.observers = new Map();
27306
+ this.triggerMutation = this.dispatchMutationEvent;
27160
27307
  this.shadowDom = new ShadowDomManager();
27161
27308
  this.shadowDom.addEventListener('attachShadow', _.bind(this.handleAttachShadow, this));
27162
27309
  this.shadowDom.addEventListener('detachShadow', _.bind(this.handleDetachShadow, this));
@@ -27177,7 +27324,7 @@ class UberMutationObserver extends EventTarget {
27177
27324
  }
27178
27325
  }
27179
27326
  startObserver(target) {
27180
- const observer = new this.ObserverClass(_.bind(this.triggerMutation, this));
27327
+ const observer = new this.ObserverClass(mutation => this.triggerMutation(mutation));
27181
27328
  this.observers.set(target, observer);
27182
27329
  observer.observe(target, {
27183
27330
  subtree: true,
@@ -27190,13 +27337,21 @@ class UberMutationObserver extends EventTarget {
27190
27337
  this.observers.clear();
27191
27338
  this.shadowDom.teardown();
27192
27339
  }
27193
- triggerMutation(mutation) {
27340
+ dispatchMutationEvent(mutation) {
27194
27341
  this.dispatchEvent({
27195
27342
  type: 'mutation',
27196
27343
  mutation
27197
27344
  });
27198
27345
  }
27346
+ triggerMutationOnce(mutation) {
27347
+ this.triggerMutation = _.noop;
27348
+ queueMicrotask(() => {
27349
+ this.dispatchMutationEvent(mutation);
27350
+ this.triggerMutation = this.triggerMutationOnce;
27351
+ });
27352
+ }
27199
27353
  handleAttachShadow({ shadowRoot }) {
27354
+ this.triggerMutation = this.triggerMutationOnce;
27200
27355
  this.startObserver(shadowRoot);
27201
27356
  }
27202
27357
  handleDetachShadow({ shadowRoot }) {
@@ -27357,15 +27512,6 @@ const initialize = makeSafe(function (options) {
27357
27512
  * @label OPTIONS_HASH_KEY_NAME
27358
27513
  */
27359
27514
  agentStorage.registry.addLocal(OPTIONS_HASH_KEY_NAME);
27360
- /**
27361
- * Stores debugging configuration and state for the Pendo debugger.
27362
- *
27363
- * @name debug-enabled
27364
- * @category Cookies/localStorage
27365
- * @access public
27366
- * @label debugEnabled
27367
- */
27368
- agentStorage.registry.addLocal(debugEnabled, { isPlain: true, serializer: JSON.stringify, deserializer: SafeJsonDeserializer });
27369
27515
  // Disable content pre-fetch for guide center
27370
27516
  pendo$1.disableGuideCenterContentSearch = options.disableGuideCenterContentSearch;
27371
27517
  // Register handlers passed through pendo_options
@@ -27662,6 +27808,7 @@ var BuildingBlockGuides = (function () {
27662
27808
  }
27663
27809
  }
27664
27810
  function renderGuideFromJSON(json, step, guides, options) {
27811
+ options = options || {};
27665
27812
  var guide = step.getGuide();
27666
27813
  var containerJSON = findGuideContainerJSON(json);
27667
27814
  var isResourceCenter = _.get(guide, 'attributes.resourceCenter');
@@ -27673,7 +27820,7 @@ var BuildingBlockGuides = (function () {
27673
27820
  var isAnnouncementModule = _.get(guide, 'attributes.resourceCenter.moduleId') === 'AnnouncementsModule';
27674
27821
  step.hasEscapeListener = false;
27675
27822
  step.containerId = containerJSON && containerJSON.props && containerJSON.props.id;
27676
- step.element = getElementForGuideStep(step);
27823
+ step.element = getElementForGuideStep(step, options.document);
27677
27824
  var guideToAppend = BuildingBlockGuides.buildNodeFromJSON(json, step, guides);
27678
27825
  step.guideElement = guideToAppend;
27679
27826
  var guideContainer = guideToAppend.find('#' + step.containerId);
@@ -27692,19 +27839,20 @@ var BuildingBlockGuides = (function () {
27692
27839
  // between re-renders
27693
27840
  guideContainer.css({ visibility: 'hidden' });
27694
27841
  guideToAppend.css({ visibility: 'hidden' });
27842
+ const embedConfig = _.get(guide, 'attributes.embedConfig', null);
27695
27843
  var watermark = BuildingBlockWatermark.buildWatermark({
27696
27844
  appId: guide.appId,
27697
27845
  targetAccount: guide.targetAccount,
27698
27846
  isTraining: guide.isTraining,
27699
- isBottomAligned: guideContainer.attr(verticalAlignmentAttr) === 'Bottom Aligned'
27847
+ isBottomAligned: guideContainer.attr(verticalAlignmentAttr) === 'Bottom Aligned',
27848
+ isEmbedded: !!embedConfig
27700
27849
  }, BuildingBlockGuides.buildNodeFromJSON);
27701
27850
  if (watermark) {
27702
27851
  guideContainer.append(watermark);
27703
27852
  }
27704
27853
  var hasImageCount = step && step.attributes && step.attributes.imgCount;
27705
27854
  // Do conditional Guide Rendering Things
27706
- var parent = getGuideAttachPoint();
27707
- const embedConfig = _.get(guide, 'attributes.embedConfig', null);
27855
+ var parent = getGuideAttachPoint(options.document);
27708
27856
  if (embedConfig) {
27709
27857
  const guideContainerId = 'pendo-guide-container';
27710
27858
  const baseContainerId = 'pendo-base';
@@ -36297,7 +36445,8 @@ function debuggerExports() {
36297
36445
  AutoDisplay,
36298
36446
  isLeader,
36299
36447
  Events,
36300
- observer
36448
+ observer,
36449
+ guideCache
36301
36450
  };
36302
36451
  }
36303
36452
  function startDebuggingModuleIfEnabled() {
@@ -38657,6 +38806,15 @@ function isConfiguredForMV3(config) {
38657
38806
  return config && config.useAssetHostForDesigner;
38658
38807
  }
38659
38808
  function initAgent(pendo, PendoConfig) {
38809
+ /**
38810
+ * Stores debugging configuration and state for the Pendo debugger.
38811
+ *
38812
+ * @name debug-enabled
38813
+ * @category Cookies/localStorage
38814
+ * @access public
38815
+ * @label debugEnabled
38816
+ */
38817
+ agentStorage.registry.addLocal(debugEnabled, { isPlain: true, serializer: JSON.stringify, deserializer: SafeJsonDeserializer });
38660
38818
  setPendoConfig(PendoConfig);
38661
38819
  overwriteBuiltConfigWithPendoConfig();
38662
38820
  if (!loadAsModule(PendoConfig) && loadAlternateAgent(PendoConfig, pendo, isDebuggingEnabled()))
@@ -38770,7 +38928,8 @@ function TextCapture() {
38770
38928
  }
38771
38929
  function isTextCapturable(text) {
38772
38930
  var trimmedText = pluginAPI.util.trim.call(text);
38773
- return isEnabled() || pendoGlobal._.has(whitelist, trimmedText) || pendoGlobal._.has(whitelist, text);
38931
+ // pass the text as an array so that our toPath override doesn't try to split it on `.`
38932
+ return isEnabled() || pendoGlobal._.has(whitelist, [trimmedText]) || pendoGlobal._.has(whitelist, [text]);
38774
38933
  }
38775
38934
  function hasWhitelist() {
38776
38935
  return pendoGlobal._.size(whitelist) > 0;
@@ -47366,7 +47525,8 @@ class SessionRecorder {
47366
47525
  }, SEND_INTERVAL$1);
47367
47526
  var config = this.recordingConfig(visitorConfig);
47368
47527
  this._stop = this.record(this.pendo._.extend({
47369
- emit: bind(this.emit, this)
47528
+ emit: bind(this.emit, this),
47529
+ errorHandler: bind(this.errorHandler, this)
47370
47530
  }, config));
47371
47531
  this._refreshIds();
47372
47532
  this.onRecordingStart();
@@ -47478,6 +47638,9 @@ class SessionRecorder {
47478
47638
  return null;
47479
47639
  }
47480
47640
  }
47641
+ errorHandler(error) {
47642
+ this.logStopReason('RRWEB_ERROR', error);
47643
+ }
47481
47644
  /**
47482
47645
  * Handle new rrweb events coming in. This will also make sure that we are properly sending a "keyframe"
47483
47646
  * as the BE expects it. A "keyframe" should consist of only the events needed to start a recording. This includes
@@ -47581,6 +47744,10 @@ class SessionRecorder {
47581
47744
  this.sendHostedResources(hostedResourcesEvent);
47582
47745
  break;
47583
47746
  }
47747
+ case 'emptyPayload': {
47748
+ this.logStopReason('EMPTY_PAYLOAD');
47749
+ break;
47750
+ }
47584
47751
  case 'missingData': {
47585
47752
  this.logStopReason(`MISSING_${messageData.missingData}`);
47586
47753
  break;
@@ -48390,6 +48557,11 @@ var WorkerFactory = /*#__PURE__*/createInlineWorkerFactory(/* rollup-plugin-web-
48390
48557
  }
48391
48558
  if (e.data.url && e.data.payload) {
48392
48559
  let { url, payload, shouldCacheResources } = e.data;
48560
+ if (Object.keys(payload).length === 0) {
48561
+ postMessage({
48562
+ type: 'emptyPayload'
48563
+ });
48564
+ }
48393
48565
  const { sequence } = payload;
48394
48566
  const stringifiedRecordingPayload = JSON.stringify(payload.recordingPayload);
48395
48567
  // calculate and post back the recording payload size before the payload is compressed
@@ -51603,7 +51775,8 @@ var ConfigReader = (function () {
51603
51775
  /**
51604
51776
  * Use this setting when using `preferMutationObserver` with an application that has Shadow DOM elements.
51605
51777
  * On page load, the Agent will run a full document scan for shadow roots and attach a MutationObserver to
51606
- * all results.
51778
+ * all results. This setting also allows the agent to run CSS selectors in all shadow roots, so CSS selectors
51779
+ * can be written without specifying the full path through all shadow roots with the `::shadow` pseudo-class.
51607
51780
  *
51608
51781
  * @access public
51609
51782
  * @category Config/Core