@pendo/agent 2.346.0 → 2.348.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.
package/dist/dom.esm.js CHANGED
@@ -6579,9 +6579,9 @@ var ConfigReader = (function () {
6579
6579
  */
6580
6580
  addOption('selfHostedWebSDKUrl', [SNIPPET_SRC, PENDO_CONFIG_SRC], undefined, undefined, ['selfHostedAgentUrl']);
6581
6581
  /**
6582
- * If this option is set to true, event data will only be transmitted using requests of type POST instead
6583
- * of first trying to use GET requests. This can result in fewer requests being sent each time that event data
6584
- * is transmitted.
6582
+ * If this option is set to true, event data, guide requests, and segment flag requests will only be
6583
+ * transmitted using requests of type POST instead of first trying to use GET requests. For event data, this
6584
+ * can result in fewer requests being sent each time that event data is transmitted.
6585
6585
  *
6586
6586
  * @access public
6587
6587
  * @category Config/Core
@@ -7555,7 +7555,7 @@ function applyMatrix2dRect(matrix2d, rect) {
7555
7555
  return transformedRect;
7556
7556
  }
7557
7557
 
7558
- var VERSION = '2.346.0_';
7558
+ var VERSION = '2.348.0_';
7559
7559
 
7560
7560
  var decodeURIComponent = _.isFunction(globalScope.decodeURIComponent) ? globalScope.decodeURIComponent : _.identity;
7561
7561
 
@@ -7915,13 +7915,13 @@ var agentStorage = (function () {
7915
7915
  resetCache(storageAvailable);
7916
7916
  if (storageIsDisabled()) {
7917
7917
  inMemoryStorage[key] = ttlWrite(val, duration);
7918
- return;
7918
+ return true;
7919
7919
  }
7920
7920
  if (shouldUseLocalStorage(keyLocalStorageOnly)) {
7921
7921
  if (storageAvailable('localStorage')) {
7922
7922
  try {
7923
7923
  localStorage.setItem(key, ttlWrite(val, duration));
7924
- return;
7924
+ return true;
7925
7925
  }
7926
7926
  catch (e) { }
7927
7927
  }
@@ -7931,11 +7931,12 @@ var agentStorage = (function () {
7931
7931
  if (!isPlain)
7932
7932
  duration = duration || DEFAULT_EXPIRE_LEN;
7933
7933
  setCookie(key, val, duration, isSecure);
7934
- return;
7934
+ return true;
7935
7935
  }
7936
7936
  catch (e) { }
7937
7937
  }
7938
7938
  inMemoryStorage[key] = ttlWrite(val, duration);
7939
+ return false;
7939
7940
  }
7940
7941
  function ttlWrite(value, duration) {
7941
7942
  if (duration === null) {
@@ -3271,9 +3271,9 @@ var ConfigReader = (function () {
3271
3271
  */
3272
3272
  addOption('selfHostedWebSDKUrl', [SNIPPET_SRC, PENDO_CONFIG_SRC], undefined, undefined, ['selfHostedAgentUrl']);
3273
3273
  /**
3274
- * If this option is set to true, event data will only be transmitted using requests of type POST instead
3275
- * of first trying to use GET requests. This can result in fewer requests being sent each time that event data
3276
- * is transmitted.
3274
+ * If this option is set to true, event data, guide requests, and segment flag requests will only be
3275
+ * transmitted using requests of type POST instead of first trying to use GET requests. For event data, this
3276
+ * can result in fewer requests being sent each time that event data is transmitted.
3277
3277
  *
3278
3278
  * @access public
3279
3279
  * @category Config/Core
@@ -4138,8 +4138,8 @@ let SERVER = '';
4138
4138
  let ASSET_HOST = '';
4139
4139
  let ASSET_PATH = '';
4140
4140
  let DESIGNER_SERVER = '';
4141
- let VERSION = '2.346.0_';
4142
- let PACKAGE_VERSION = '2.346.0';
4141
+ let VERSION = '2.348.0_';
4142
+ let PACKAGE_VERSION = '2.348.0';
4143
4143
  let LOADER = 'xhr';
4144
4144
  /* eslint-enable web-sdk-eslint-rules/no-gulp-env-references */
4145
4145
  /**
@@ -5133,13 +5133,13 @@ var agentStorage = (function () {
5133
5133
  resetCache(storageAvailable);
5134
5134
  if (storageIsDisabled()) {
5135
5135
  inMemoryStorage[key] = ttlWrite(val, duration);
5136
- return;
5136
+ return true;
5137
5137
  }
5138
5138
  if (shouldUseLocalStorage(keyLocalStorageOnly)) {
5139
5139
  if (storageAvailable('localStorage')) {
5140
5140
  try {
5141
5141
  localStorage.setItem(key, ttlWrite(val, duration));
5142
- return;
5142
+ return true;
5143
5143
  }
5144
5144
  catch (e) { }
5145
5145
  }
@@ -5149,11 +5149,12 @@ var agentStorage = (function () {
5149
5149
  if (!isPlain)
5150
5150
  duration = duration || DEFAULT_EXPIRE_LEN;
5151
5151
  setCookie(key, val, duration, isSecure);
5152
- return;
5152
+ return true;
5153
5153
  }
5154
5154
  catch (e) { }
5155
5155
  }
5156
5156
  inMemoryStorage[key] = ttlWrite(val, duration);
5157
+ return false;
5157
5158
  }
5158
5159
  function ttlWrite(value, duration) {
5159
5160
  if (duration === null) {
@@ -12995,6 +12996,23 @@ function migrateLegacyCookieEvents(events) {
12995
12996
  clearCookie(getPendoCookieKey(UNSENT_EVENTS_KEY));
12996
12997
  }
12997
12998
  }
12999
+ // the quota error doesn't say how much space is left, so halving keeps the
13000
+ // number of retries during pagehide small
13001
+ function dropOldestHalf(events) {
13002
+ const entries = [];
13003
+ _.each(events, (requests, key) => {
13004
+ _.each(requests, (request) => {
13005
+ entries.push({ key, request });
13006
+ });
13007
+ });
13008
+ const newest = _.sortBy(entries, (entry) => entry.request.ts).slice(Math.ceil(entries.length / 2));
13009
+ const remaining = {};
13010
+ _.each(newest, (entry) => {
13011
+ remaining[entry.key] = remaining[entry.key] || [];
13012
+ remaining[entry.key].push(entry.request);
13013
+ });
13014
+ return remaining;
13015
+ }
12998
13016
  class LocalStorageEventBuffer {
12999
13017
  constructor() {
13000
13018
  this.events = {};
@@ -13039,12 +13057,14 @@ class LocalStorageEventBuffer {
13039
13057
  storage.clear(UNSENT_EVENTS_KEY);
13040
13058
  }
13041
13059
  write(storage) {
13042
- if (_.size(this.events) > 0) {
13043
- storage.write(UNSENT_EVENTS_KEY, JSON.stringify(this.events), UNSENT_EVENTS_MAX_AGE);
13044
- }
13045
- else {
13046
- storage.clear(UNSENT_EVENTS_KEY);
13060
+ let events = this.events;
13061
+ while (_.size(events) > 0) {
13062
+ if (storage.write(UNSENT_EVENTS_KEY, JSON.stringify(events), UNSENT_EVENTS_MAX_AGE)) {
13063
+ return;
13064
+ }
13065
+ events = dropOldestHalf(events);
13047
13066
  }
13067
+ storage.clear(UNSENT_EVENTS_KEY);
13048
13068
  }
13049
13069
  }
13050
13070
  var localStorageEventBuffer = new LocalStorageEventBuffer();
@@ -13132,7 +13152,7 @@ function isDebuggingEnabled(asBoolean = true) {
13132
13152
  }
13133
13153
  }
13134
13154
 
13135
- const PERFORMANCE_SEND_INTERVAL = 1000 * 60 * 10; // 10 minutes
13155
+ const PERFORMANCE_COLLECT_INTERVAL = 1000 * 60 * 10; // 10 minutes
13136
13156
  class PerformanceMonitor {
13137
13157
  constructor() {
13138
13158
  this._isPerformanceApiAvailable = this._checkPerformanceApi();
@@ -13140,6 +13160,8 @@ class PerformanceMonitor {
13140
13160
  this._measuringPerformance = false;
13141
13161
  this._debugging = false;
13142
13162
  this._setDebuggingBound = _.bind(this._setDebugging, this);
13163
+ this._sendBound = _.bind(this.send, this);
13164
+ this._totals = {};
13143
13165
  this.marks = new Set();
13144
13166
  this.measures = new Set();
13145
13167
  }
@@ -13150,12 +13172,13 @@ class PerformanceMonitor {
13150
13172
  this._markPerformance(INITIALIZE);
13151
13173
  this._setDebugging();
13152
13174
  Events.debuggerLaunched.on(this._setDebuggingBound);
13175
+ Events.appUnloaded.on(this._sendBound);
13153
13176
  const shouldSend = Math.random() * 100 < ConfigReader.get('performanceMetricsSampleRate');
13154
13177
  this._setSending(shouldSend);
13155
13178
  // interval always runs to periodically free memory used by performance api
13156
13179
  this.interval = setInterval(() => {
13157
- this.send(); // includes call to _clearMarksAndMeasures()
13158
- }, PERFORMANCE_SEND_INTERVAL);
13180
+ this._collect();
13181
+ }, PERFORMANCE_COLLECT_INTERVAL);
13159
13182
  return () => {
13160
13183
  this.teardown();
13161
13184
  };
@@ -13166,6 +13189,7 @@ class PerformanceMonitor {
13166
13189
  this._measuringPerformance = false;
13167
13190
  this._setDebugging();
13168
13191
  Events.debuggerLaunched.off(this._setDebuggingBound);
13192
+ Events.appUnloaded.off(this._sendBound);
13169
13193
  this._clearMarksAndMeasures();
13170
13194
  clearInterval(this.interval);
13171
13195
  }
@@ -13185,25 +13209,41 @@ class PerformanceMonitor {
13185
13209
  this._markPerformance(name, { detail });
13186
13210
  }
13187
13211
  send() {
13188
- const payload = _.reduce(METRICS, (acc, metric) => {
13189
- const { name, type, instrument } = metric;
13190
- if (!instrument)
13191
- return acc;
13192
- const entries = performance.getEntriesByName(name);
13193
- const value = instrument(entries);
13194
- if (value > 0) {
13195
- acc.push({
13196
- name,
13197
- type,
13198
- value,
13199
- timestamp: Date.now()
13200
- });
13212
+ // runs in the appUnloaded handler ahead of the agent's event flush, so it must not throw
13213
+ try {
13214
+ this._collect();
13215
+ const payload = _.map(this._totals, (value, name) => ({
13216
+ name,
13217
+ type: METRICS[name].type,
13218
+ value,
13219
+ timestamp: Date.now()
13220
+ }));
13221
+ this._totals = {};
13222
+ if (_.size(payload) && this._sending) {
13223
+ writeMetricsPOST(payload);
13201
13224
  }
13202
- return acc;
13203
- }, []);
13204
- this._clearMarksAndMeasures();
13205
- if (_.size(payload) && this._sending) {
13206
- writeMetricsPOST(payload);
13225
+ }
13226
+ catch (e) {
13227
+ log.debug(`Failed to send performance metrics: ${e}`);
13228
+ }
13229
+ }
13230
+ _collect() {
13231
+ if (!this._isPerformanceApiAvailable)
13232
+ return;
13233
+ try {
13234
+ if (!this._sending)
13235
+ return;
13236
+ _.each(METRICS, ({ name, instrument }) => {
13237
+ if (!instrument)
13238
+ return;
13239
+ const value = instrument(performance.getEntriesByName(name));
13240
+ if (value > 0) {
13241
+ this._totals[name] = (this._totals[name] || 0) + value;
13242
+ }
13243
+ });
13244
+ }
13245
+ finally {
13246
+ this._clearMarksAndMeasures();
13207
13247
  }
13208
13248
  }
13209
13249
  _checkPerformanceApi() {
@@ -13451,6 +13491,9 @@ function filterSiloCapacity(options) {
13451
13491
  };
13452
13492
  }
13453
13493
  var URL_MAX_LENGTH = 2000;
13494
+ function shouldLoadWithPost(url, jwtOptions) {
13495
+ return url.length > URL_MAX_LENGTH || !_.isEmpty(jwtOptions) || !!ConfigReader.get('sendEventsWithPostOnly');
13496
+ }
13454
13497
  function shortenUrlFields(options) {
13455
13498
  options = _.defaults(options || {}, {
13456
13499
  fields: [],
@@ -14216,6 +14259,14 @@ var isWalkthrough = function (guide) {
14216
14259
  var isForm = function (guide) {
14217
14260
  return !!(_.get(guide, 'attributes.form'));
14218
14261
  };
14262
+ // An HTML guide step's type is 'html' and it has no domJson to derive calculatedType
14263
+ // from, so its layout only shows up in buildingBlockLayoutType
14264
+ var isTooltipStep = function (step) {
14265
+ var tooltip = 'tooltip';
14266
+ return _.get(step, 'type') === tooltip ||
14267
+ _.get(step, 'attributes.calculatedType') === tooltip ||
14268
+ _.get(step, 'attributes.buildingBlockLayoutType', _.get(step, 'buildingBlockLayoutType')) === tooltip;
14269
+ };
14219
14270
  function isPreviewing() {
14220
14271
  /* global selmo */
14221
14272
  return (typeof selmo !== 'undefined' && !!selmo.isPreviewing);
@@ -17858,6 +17909,7 @@ var FlexboxPolyfill = (function () {
17858
17909
  wrapElementInMockFlexboxContainer,
17859
17910
  getVisualElementsWrappedInFlexElements,
17860
17911
  initializeFlexRows,
17912
+ initializeNativeFlexRow,
17861
17913
  getRowWidth,
17862
17914
  wrapFlexElementsInFlexRows,
17863
17915
  formatFlexRows,
@@ -18219,32 +18271,26 @@ var FlexboxPolyfill = (function () {
18219
18271
  var computedStyles = getComputedStyle_safe(row);
18220
18272
  return parseInt(width, 10) - parseInt(computedStyles.paddingLeft, 10) - parseInt(computedStyles.paddingRight, 10);
18221
18273
  }
18222
- function initializeFlexRows(row, justifyContent, rowVerticalAlignment, useNativeFlexbox = false) {
18223
- if (useNativeFlexbox) {
18224
- var alignments = {
18225
- top: 'flex-start',
18226
- center: 'center',
18227
- bottom: 'flex-end'
18228
- };
18229
- row.style.display = 'flex';
18230
- row.style.flexWrap = 'wrap';
18231
- row.style.justifyContent = justifyContent;
18232
- row.style.alignItems = alignments[rowVerticalAlignment] || 'flex-start';
18233
- }
18234
- else {
18235
- var flexElements = getFlexboxElements(row.children);
18236
- if (flexElements.length === 0)
18237
- return;
18238
- // In the following steps, we remove and add elements to the guide.
18239
- // Therefore we precalculation the rowWidth to ensure it won't change
18240
- // in case of scrollbar will be added or removed from the screen.
18241
- var rowWidth = FlexboxPolyfill.getRowWidth(row);
18242
- var flexRows = FlexboxPolyfill.wrapFlexElementsInFlexRows(flexElements, row, rowWidth);
18243
- // Once we have all the pendo-mock-flexbox-element elements placed in to
18244
- // pendo-mock-flexbox-row rows, loop through each pendo-mock-flexbox-row and set the
18245
- // height and alignment
18246
- FlexboxPolyfill.formatFlexRows(flexRows, row, justifyContent, rowVerticalAlignment, rowWidth);
18247
- }
18274
+ function initializeNativeFlexRow(row, justifyContent, rowVerticalAlignment) {
18275
+ var alignments = {
18276
+ top: 'flex-start',
18277
+ center: 'center',
18278
+ bottom: 'flex-end'
18279
+ };
18280
+ row.style.display = 'flex';
18281
+ row.style.flexWrap = 'wrap';
18282
+ row.style.justifyContent = justifyContent;
18283
+ row.style.alignItems = alignments[rowVerticalAlignment] || 'flex-start';
18284
+ }
18285
+ function initializeFlexRows(row, justifyContent, rowVerticalAlignment, rowWidth) {
18286
+ var flexElements = getFlexboxElements(row.children);
18287
+ if (flexElements.length === 0)
18288
+ return;
18289
+ var flexRows = FlexboxPolyfill.wrapFlexElementsInFlexRows(flexElements, row, rowWidth);
18290
+ // Once we have all the pendo-mock-flexbox-element elements placed in to
18291
+ // pendo-mock-flexbox-row rows, loop through each pendo-mock-flexbox-row and set the
18292
+ // height and alignment
18293
+ FlexboxPolyfill.formatFlexRows(flexRows, row, justifyContent, rowVerticalAlignment, rowWidth);
18248
18294
  }
18249
18295
  function wrapFlexElementsInFlexRows(flexElements, row, rowWidthPreCalc) {
18250
18296
  var rowWidth = rowWidthPreCalc || getRowWidth(row);
@@ -18324,10 +18370,17 @@ var FlexboxPolyfill = (function () {
18324
18370
  function flexElement(ele, useNativeFlexbox) {
18325
18371
  var rowsToBeFlexed = dom('[data-pendo-display-flex]', ele);
18326
18372
  _.each(rowsToBeFlexed, function (row) {
18327
- var rowWithFlexedElements = useNativeFlexbox ? row : FlexboxPolyfill.initializeFlexElements(row);
18328
18373
  var horizontalAlignment = row.getAttribute('data-pendo-justify-content');
18329
18374
  var rowVerticalAlignment = row.getAttribute('data-row-vertical-alignment');
18330
- FlexboxPolyfill.initializeFlexRows(rowWithFlexedElements, horizontalAlignment, rowVerticalAlignment, useNativeFlexbox);
18375
+ if (useNativeFlexbox) {
18376
+ FlexboxPolyfill.initializeNativeFlexRow(row, horizontalAlignment, rowVerticalAlignment);
18377
+ return;
18378
+ }
18379
+ // Initializing flex elements can add a temporary scrollbar to a scrolling ancestor and shrink the
18380
+ // width of the rows. Pre-measure the row width to prevent its children from wrapping onto a new row.
18381
+ var rowWidth = FlexboxPolyfill.getRowWidth(row);
18382
+ var rowWithFlexedElements = FlexboxPolyfill.initializeFlexElements(row);
18383
+ FlexboxPolyfill.initializeFlexRows(rowWithFlexedElements, horizontalAlignment, rowVerticalAlignment, rowWidth);
18331
18384
  });
18332
18385
  }
18333
18386
  function flexAllThings(containerId, step) {
@@ -22891,7 +22944,7 @@ function stepShowingProc(guide, step) {
22891
22944
  step.checkPlacement();
22892
22945
  return;
22893
22946
  }
22894
- var isTooltip = (step.type === 'tooltip' || step.attributes.calculatedType === 'tooltip');
22947
+ var isTooltip = isTooltipStep(step);
22895
22948
  if (isTooltip && wouldBeVisibleAfterAutoScroll(element) && elementMatchesContainsRules) {
22896
22949
  // the element was scrolled out of view, the guide should be invisible for now, but still "active"
22897
22950
  return;
@@ -23693,10 +23746,9 @@ function attachP1AdvanceActions(step, guide, pendo) {
23693
23746
  return;
23694
23747
  if (isBadge(guide) && !isWalkthrough(guide))
23695
23748
  return;
23696
- const { _ } = pendo;
23697
- const htmlLayoutType = _.get(step, 'attributes.buildingBlockLayoutType', step.buildingBlockLayoutType);
23698
- if (!_.contains([htmlLayoutType, step.type], 'tooltip'))
23749
+ if (!isTooltipStep(step))
23699
23750
  return;
23751
+ const { _ } = pendo;
23700
23752
  const advanceMethods = step.advanceMethod.split(',');
23701
23753
  _.each(advanceMethods, (method) => {
23702
23754
  if (method === 'element') {
@@ -23936,12 +23988,6 @@ var popoverStep = {
23936
23988
  script: popoverRuntimeScript
23937
23989
  };
23938
23990
 
23939
- function isTooltip({ _ }, step) {
23940
- const tooltip = 'tooltip';
23941
- return _.get(step, 'attributes.calculatedType') === tooltip ||
23942
- _.get(step, 'attributes.buildingBlockLayoutType', step.buildingBlockLayoutType) === tooltip ||
23943
- step.type === tooltip;
23944
- }
23945
23991
  function attachScrollHandlers({ _ }, step, scrollCallback) {
23946
23992
  const throttledScrollCallback = _.throttle(_.bind(scrollCallback, step, step), 10);
23947
23993
  step.attachEvent(window, 'scroll', throttledScrollCallback, true);
@@ -23969,7 +24015,7 @@ function attachStepScrollHandlers(step, guide, pendo) {
23969
24015
  // APP-68789
23970
24016
  if (isPreviewing() && step.element === dom.getBody())
23971
24017
  return;
23972
- if (isTooltip(pendo, step)) {
24018
+ if (isTooltipStep(step)) {
23973
24019
  const repositionCallback = step.domJson ? bbRepositionTooltip : p1RepositionTooltip;
23974
24020
  attachScrollHandlers(pendo, step, _.partial(tooltipOnScroll, pendo, step, repositionCallback));
23975
24021
  }
@@ -24668,11 +24714,17 @@ var canStepBeRendered = function (step) {
24668
24714
  if (targetElem && step.elementContainsRulesList && !doesElementMatchContainsRules(targetElem, step.elementContainsRulesList)) {
24669
24715
  return statusWriter(false, 'contains_rules');
24670
24716
  }
24671
- const embedSelector = _.get(step, 'guide.attributes.embedConfig.selector');
24672
- if (embedSelector && !dom(embedSelector).length) {
24673
- return false;
24717
+ const embedConfig = _.get(step, 'guide.attributes.embedConfig');
24718
+ if (embedConfig && embedConfig.selector) {
24719
+ const embedHost = dom(embedConfig.selector)[0];
24720
+ if (!embedHost) {
24721
+ return false;
24722
+ }
24723
+ if (embedConfig.method === 'replace' && isEmbedHostReplacedByAnotherGuide(step.guide, embedHost)) {
24724
+ return false;
24725
+ }
24674
24726
  }
24675
- var isTooltip = step.type === 'tooltip' || BuildingBlockTooltips.isBuildingBlockGuideRelativeToElement(step);
24727
+ var isTooltip = isTooltipStep(step) || BuildingBlockTooltips.isBuildingBlockGuideRelativeToElement(step);
24676
24728
  var isVisible = isElementVisible(elm);
24677
24729
  if (!isTooltip) {
24678
24730
  return statusWriter(isVisible, 'target_element');
@@ -24683,6 +24735,14 @@ var canStepBeRendered = function (step) {
24683
24735
  const wouldBeVisible = wouldBeVisibleAfterAutoScroll(elm);
24684
24736
  return statusWriter(wouldBeVisible, 'target_element_tooltip_scroll');
24685
24737
  };
24738
+ function isEmbedHostReplacedByAnotherGuide(guide, embedHost) {
24739
+ return _.some(getActiveGuides(), function (other) {
24740
+ if (other === guide || !_.isFunction(other.isShown) || !other.isShown())
24741
+ return false;
24742
+ const otherEmbedConfig = _.get(other, 'attributes.embedConfig');
24743
+ return !!otherEmbedConfig && otherEmbedConfig.method === 'replace' && dom(otherEmbedConfig.selector)[0] === embedHost;
24744
+ });
24745
+ }
24686
24746
  function pullContentsFromTargetElement(ele) {
24687
24747
  var wrappedEle = dom(ele);
24688
24748
  var eleText = wrappedEle.text() || ''; // .text() can return undefined
@@ -25195,7 +25255,7 @@ var loadGuideJs = function (apiKey, params) {
25195
25255
  var url = buildBaseDataUrl(guideLoaderImpl.endpoint(), apiKey, queryString);
25196
25256
  var jwtOptions = JWT.get();
25197
25257
  let loadingPromise;
25198
- if (url.length > URL_MAX_LENGTH || !_.isEmpty(jwtOptions)) {
25258
+ if (shouldLoadWithPost(url, jwtOptions)) {
25199
25259
  delete queryString.jzb;
25200
25260
  url = buildBaseDataUrl('guide.json', apiKey, queryString);
25201
25261
  var payload = _.extend({ events: jzb }, jwtOptions);
@@ -29711,10 +29771,6 @@ const PluginAPI = {
29711
29771
  removeGlobalScript: GuideRuntime.removeGlobalScript
29712
29772
  },
29713
29773
  GuideActivity,
29714
- GuideEvents: {
29715
- stageGuideEvent,
29716
- createGuideEvent
29717
- },
29718
29774
  GuideLoop: {
29719
29775
  addUpdatePhase,
29720
29776
  removeUpdatePhase
@@ -29744,7 +29800,8 @@ const PluginAPI = {
29744
29800
  transmit: {
29745
29801
  buildBaseDataUrl,
29746
29802
  fetchKeepalive,
29747
- sendBeacon
29803
+ sendBeacon,
29804
+ shouldLoadWithPost
29748
29805
  },
29749
29806
  log,
29750
29807
  NetworkRequest,
@@ -29919,6 +29976,19 @@ function initIdentityEvents() {
29919
29976
  };
29920
29977
  }
29921
29978
 
29979
+ /**
29980
+ * The cookie consent tier, or tiers, the visitor has already agreed to. Each tier is the id of a cookie consent
29981
+ * level configured for your subscription, and determines what data the web SDK can collect: visitor identity,
29982
+ * analytics events, guides, and session replay. If not set, the web SDK runs without any consent restrictions.
29983
+ * Use `pendo.updateCookieConsent` to change consent after initialization. Read more about
29984
+ * [Cookie Consent Levels](/cookies/consent-levels).
29985
+ *
29986
+ * @access public
29987
+ * @category Config/Core
29988
+ * @name cookieConsentTiers
29989
+ * @default undefined
29990
+ * @type {string | string[]}
29991
+ */
29922
29992
  const CONSENT_TIERS = 'cookieConsentTiers';
29923
29993
  function applyCookieConsent(tiers, identity) {
29924
29994
  rememberConsentTiers(tiers);
@@ -29940,18 +30010,21 @@ function isCurrentCookieConsent(tiers) {
29940
30010
  }
29941
30011
  /**
29942
30012
  * Enforces the cookie consent policy a visitor has agreed to. The policy is defined by the subscription's cookie consent configuration,
29943
- * and is used to determine whether each product the web SDK may run.
30013
+ * and is used to determine what data the web SDK can collect. The new tiers replace any previously consented tiers,
30014
+ * including those passed to `pendo.initialize` as `cookieConsentTiers`, and are shared with other frames running the web SDK for the same application.
29944
30015
  *
29945
30016
  * A visitor who was not being tracked has no identity for the web SDK to resume, so pass one in
29946
30017
  * `identity` when the new tiers start allowing identity. It is ignored otherwise.
29947
30018
  *
30019
+ * Read more about [Cookie Consent Levels](/cookies/consent-levels).
30020
+ *
29948
30021
  * @access public
29949
30022
  * @category Core
29950
30023
  * @param {string | string[]} tiers tier or tiers the visitor consented to
29951
30024
  * @param {object} [identity] visitor and account to identify, in the same shape as
29952
30025
  * `pendo.updateOptions` -- applied only when consent moves a do-not-track visitor to a tier
29953
30026
  * that permits identity
29954
- * @returns {object} map of product to its resolved value -- `guides` and `identity` are
30027
+ * @returns {object} what data is now collected -- `guides` and `identity` are
29955
30028
  * booleans (identity disabled means DNT), `textCollection` is `none`/`whitelist`/`all`,
29956
30029
  * `analytics` and `guideAnalytics` are each an array of allowed event types
29957
30030
  * @example
@@ -33923,10 +33996,12 @@ function Poll(guide) {
33923
33996
  _.each(responses, function (response, i) {
33924
33997
  var curPoll = getPoll(response.pollId, guide);
33925
33998
  var evt = createGuideEvent('pollResponse', step.guideId, step.id, get_visitor_id(), undefined, guide.language);
33999
+ // A behavior that replaces show() outright (HTML guides) drops the after('show')
34000
+ // hook above, so fall back to when the step was last seen.
33926
34001
  _.extend(evt.props, {
33927
34002
  poll_id: response.pollId,
33928
34003
  poll_response: response.value,
33929
- duration: (new Date().getTime() - shownTime)
34004
+ duration: (new Date().getTime() - (shownTime || step.lastSeenAt))
33930
34005
  }, options);
33931
34006
  if (curPoll &&
33932
34007
  curPoll.attributes &&
@@ -33985,7 +34060,11 @@ var GuideDisplay = (function () {
33985
34060
  return false;
33986
34061
  }
33987
34062
  step.lock();
33988
- return AsyncContent.fetchContent(step).then(function () {
34063
+ // Prefer the step's own fetchContent so a plugin-defined step (e.g. HTML
34064
+ // guides) can supply its content; for building-block steps it is
34065
+ // AsyncContent.fetchContent anyway
34066
+ var contentPromise = _.isFunction(step.fetchContent) ? step.fetchContent() : AsyncContent.fetchContent(step);
34067
+ return contentPromise.then(function () {
33989
34068
  if (step.type !== 'whatsnew' && !step.isShown()) {
33990
34069
  return false;
33991
34070
  }
@@ -37238,7 +37317,11 @@ var Branding = (function () {
37238
37317
  return;
37239
37318
  var guide = pendo.findGuideById(props.guide_id);
37240
37319
  var guideContainer = guide.steps[0].guideElement[0].lastElementChild;
37241
- var verticalAlignment = guideContainer.dataset.verticalAlignment;
37320
+ var verticalAlignment = guideContainer && guideContainer.dataset.verticalAlignment;
37321
+ // Only Visual Design Studio containers carry the alignment the badge is placed by;
37322
+ // an HTML guide's container has none.
37323
+ if (!verticalAlignment)
37324
+ return;
37242
37325
  var isBottomAligned = verticalAlignment.indexOf('Bottom') > -1;
37243
37326
  var isSetWidth = guideContainer.style.width !== '';
37244
37327
  var link = document.createElement('a');
@@ -41172,7 +41255,7 @@ var buildLauncherItem = function (guide) {
41172
41255
  dom(guideContainer).attr('id', 'launcher-' + guide.id);
41173
41256
  var guideLink = document.createElement('a');
41174
41257
  guideLink.href = '#';
41175
- guideLink.innerHTML = guide.name;
41258
+ guideLink.appendChild(document.createTextNode(guide.name));
41176
41259
  guideContainer.appendChild(guideLink);
41177
41260
  return guideContainer;
41178
41261
  };
@@ -41527,8 +41610,9 @@ var P1GuidePlugin = (function () {
41527
41610
  // Adds a close button to the guide
41528
41611
  function CloseButton(guide) {
41529
41612
  var step = this;
41530
- // We only want to have the agent add close buttons to legacy guides, not building block inserts
41531
- if (step.domJson || step.domJsonpUrl)
41613
+ // We only want to have the agent add close buttons to legacy guides, not building block
41614
+ // inserts or HTML guides (which have no domJson either)
41615
+ if (step.domJson || step.domJsonpUrl || step.type === 'html')
41532
41616
  return step;
41533
41617
  step.after('render', function () {
41534
41618
  if (!step.guideElement || !step.guideElement.length)
@@ -41545,7 +41629,7 @@ var P1GuidePlugin = (function () {
41545
41629
  // Adds pendo credits to the guide unless disabled
41546
41630
  function Credits() {
41547
41631
  var step = this;
41548
- if (!step.hideCredits && !step.domJson && !step.domJsonpUrl && !isForm(step.guide)) {
41632
+ if (!step.hideCredits && !step.domJson && !step.domJsonpUrl && step.type !== 'html' && !isForm(step.guide)) {
41549
41633
  step.after('render', function () {
41550
41634
  _addCredits(step.guideElement[0]);
41551
41635
  });
@@ -41858,7 +41942,7 @@ function SegmentFlags() {
41858
41942
  const jwtOptions = pluginApi.agent.getJwtInfoCopy();
41859
41943
  let payload;
41860
41944
  try {
41861
- if (url.length > pluginApi.constants.URL_MAX_LENGTH || !globalPendo._.isEmpty(jwtOptions)) {
41945
+ if (pluginApi.transmit.shouldLoadWithPost(url, jwtOptions)) {
41862
41946
  delete queryString.jzb;
41863
41947
  url = pluginApi.transmit.buildBaseDataUrl('segmentflag.json', globalPendo.apiKey, queryString);
41864
41948
  payload = globalPendo._.extend({ events: jzb }, jwtOptions);
@@ -48091,7 +48175,7 @@ function serializeNodeWithId(n, options) {
48091
48175
  if (parent && isShadowRoot(parent) && isNativeShadowDom(parent)) {
48092
48176
  serializedNode.isShadow = true;
48093
48177
  }
48094
- if (serializedNode.type === NodeType.Element && serializedNode.tagName === "iframe") {
48178
+ if (serializedNode.type === NodeType.Element && serializedNode.tagName === "iframe" && !_isBlockedElement(n, blockClass, blockSelector)) {
48095
48179
  onceIframeLoaded(
48096
48180
  n,
48097
48181
  () => {
@@ -50241,11 +50325,15 @@ class IframeManager {
50241
50325
  __publicField(this, "pageHideListener");
50242
50326
  __publicField(this, "stylesheetManager");
50243
50327
  __publicField(this, "recordCrossOriginIframes");
50328
+ __publicField(this, "blockClass");
50329
+ __publicField(this, "blockSelector");
50244
50330
  this.mutationCb = options.mutationCb;
50245
50331
  this.wrappedEmit = options.wrappedEmit;
50246
50332
  this.takeFullSnapshot = options.takeFullSnapshot;
50247
50333
  this.stylesheetManager = options.stylesheetManager;
50248
50334
  this.recordCrossOriginIframes = options.recordCrossOriginIframes;
50335
+ this.blockClass = options.blockClass;
50336
+ this.blockSelector = options.blockSelector;
50249
50337
  this.crossOriginIframeStyleMirror = new CrossOriginIframeMirror(
50250
50338
  this.stylesheetManager.styleMirror.generateId.bind(
50251
50339
  this.stylesheetManager.styleMirror
@@ -50260,6 +50348,7 @@ class IframeManager {
50260
50348
  this.takeFullSnapshot = takeFullSnapshot2;
50261
50349
  }
50262
50350
  addIframe(iframeEl) {
50351
+ if (isBlocked(iframeEl, this.blockClass, this.blockSelector, false)) return;
50263
50352
  this.iframes.set(iframeEl, true);
50264
50353
  if (iframeEl.contentWindow)
50265
50354
  this.crossOriginIframeMap.set(iframeEl.contentWindow, iframeEl);
@@ -51384,6 +51473,8 @@ function record(options = {}) {
51384
51473
  mutationCb: wrappedMutationEmit,
51385
51474
  stylesheetManager,
51386
51475
  recordCrossOriginIframes,
51476
+ blockClass,
51477
+ blockSelector,
51387
51478
  wrappedEmit,
51388
51479
  takeFullSnapshot
51389
51480
  });