@pendo/agent 2.326.0 → 2.327.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.
@@ -2707,11 +2707,11 @@ var underscoreExports = underscore.exports;
2707
2707
  var _ = /*@__PURE__*/getDefaultExportFromCjs(underscoreExports);
2708
2708
 
2709
2709
  /**
2710
- * Utility function to check if passed value exists. Returns false for `null` and `undefined`.
2710
+ * Utility function to check if the passed value exists. Returns false for `null` and `undefined`.
2711
2711
  *
2712
2712
  * @access public
2713
2713
  * @category Utility
2714
- * @param {any} value argument to type check
2714
+ * @param {any} arg value to type check
2715
2715
  * @returns {Boolean}
2716
2716
  * @example
2717
2717
  * pendo.doesExist(null) => false
@@ -2964,7 +2964,7 @@ var ConfigReader = (function () {
2964
2964
  *
2965
2965
  * @access public
2966
2966
  * @category Config/Core
2967
- * @name forceLeader
2967
+ * @name forcedLeader
2968
2968
  * @default false
2969
2969
  * @type {boolean}
2970
2970
  */
@@ -3151,7 +3151,7 @@ var ConfigReader = (function () {
3151
3151
  * An array of exact strings that can still be included in event data if text capture is disabled
3152
3152
  * (`excludeAllText`). This will not override any allow list specified by your application settings but will apply if none is provided.
3153
3153
  * These are not selectors but are equality checks (the string 'Bug' will allow links that have 'Bug' as the
3154
- * text to be captured but not ones like 'Bug Report')
3154
+ * text to be captured but not ones like 'Bug Report').
3155
3155
  *
3156
3156
  * @access public
3157
3157
  * @category Config/Analytics
@@ -3249,7 +3249,7 @@ var ConfigReader = (function () {
3249
3249
  /**
3250
3250
  * By default, the web SDK will also attempt to intercept calls to `stopPropagation` and
3251
3251
  * `stopImmediatePropagation` for click, focus, submit, and change events in order to ensure that Pendo can
3252
- * still probably recognize these events. In the case of this causing duplicate events or other issues, this
3252
+ * still properly recognize these events. In the case of this causing duplicate events or other issues, this
3253
3253
  * functionality can be disabled.
3254
3254
  *
3255
3255
  * @access public
@@ -3312,7 +3312,7 @@ var ConfigReader = (function () {
3312
3312
  */
3313
3313
  addOption('cacheGuides', [SNIPPET_SRC, PENDO_CONFIG_SRC], false);
3314
3314
  /**
3315
- * How often to clear the guides cache (in milliseconds)
3315
+ * How often to clear the guides cache (in milliseconds).
3316
3316
  *
3317
3317
  * @access public
3318
3318
  * @category Config/Guides
@@ -3346,7 +3346,7 @@ var ConfigReader = (function () {
3346
3346
  addOption('disableGlobalCSS', [SNIPPET_SRC, PENDO_CONFIG_SRC], false);
3347
3347
  /**
3348
3348
  * Building block guides use an inline style tag for various pseudo styles (e.g. hover, carets, animations).
3349
- * These can be turned off using this flag for application's with more restrictive CSP settings but will
3349
+ * These can be turned off using this flag for applications with more restrictive CSP settings but will
3350
3350
  * require custom effort to reach style parity.
3351
3351
  *
3352
3352
  * @access public
@@ -3372,7 +3372,7 @@ var ConfigReader = (function () {
3372
3372
  * cookies, localStorage, click tracking, and metadata. Only displays guides
3373
3373
  * that have been configured explicitly to show to this visitor.
3374
3374
  *
3375
- * @access public
3375
+ * @access private
3376
3376
  * @category Config/Guides
3377
3377
  * @name doNotTrackGuides
3378
3378
  * @default false
@@ -3380,7 +3380,7 @@ var ConfigReader = (function () {
3380
3380
  */
3381
3381
  addOption('doNotTrackGuides', [SNIPPET_SRC, PENDO_CONFIG_SRC]);
3382
3382
  /**
3383
- * If `true`, the web SDK will listen for `alt+shift+8` on the keyboard and try to launch the designer (). The
3383
+ * If `true`, the web SDK will listen for `alt+shift+8` on the keyboard and try to launch the designer. The
3384
3384
  * keyboard shortcut requires the guide launch modal of Engage to be open in another tab showing the shortcut.
3385
3385
  *
3386
3386
  * @access public
@@ -3458,7 +3458,7 @@ var ConfigReader = (function () {
3458
3458
  */
3459
3459
  addOption('guides.disabled', [SNIPPET_SRC], false, undefined, ['disableGuides']);
3460
3460
  /**
3461
- * If 'true', guides with slow selectors will be removed from guide display processing.
3461
+ * If `true`, guides with slow selectors will be removed from guide display processing.
3462
3462
  * This will improve application performance, but slow guides will not be shown to users.
3463
3463
  *
3464
3464
  * @access public
@@ -3514,7 +3514,7 @@ var ConfigReader = (function () {
3514
3514
  */
3515
3515
  addOption('inlineStyleNonce', [SNIPPET_SRC]);
3516
3516
  /**
3517
- * Formerly `leaderKey` Specify a preferred publicAppId to lead the multi-application iframe installation to make decisions about automatic
3517
+ * Formerly `leaderKey`. Specify a preferred publicAppId to lead the multi-application iframe installation to make decisions about automatic
3518
3518
  * guide display. In installations with more than 2 publicAppIds, the leaderApplication can be specified as a priority
3519
3519
  * list (e.g. `leaderApplication: ['key1', 'key2', ...]`). Either all frames must agree on the leaderApplication setting,
3520
3520
  * or only one frame should specify the leaderApplication. If neither of these conditions are met, the default leader
@@ -3544,7 +3544,7 @@ var ConfigReader = (function () {
3544
3544
  addOption('storage.allowKeys', [SNIPPET_SRC], '*');
3545
3545
  // Feedback
3546
3546
  /**
3547
- * If Feedback is setup for your subscription, this option can be used to selectively disable Feedback.
3547
+ * If Feedback is set up for your subscription, this option can be used to selectively disable Feedback.
3548
3548
  *
3549
3549
  * @access public
3550
3550
  * @category Config/Core
@@ -3557,8 +3557,8 @@ var ConfigReader = (function () {
3557
3557
  addOption('feedbackSettings', [PENDO_CONFIG_SRC], {});
3558
3558
  addOption('pendoFeedback', [PENDO_CONFIG_SRC], false);
3559
3559
  /**
3560
- * If set, the web SDK will use this as the suffix when writing last step advanced key into the visitors cookie.
3561
- * This supports cross app guides by having a shared accessible location for different apps on the same effective level domain.
3560
+ * If set, the web SDK will use this as the suffix when writing the last step advanced key into the visitor's cookie.
3561
+ * This supports cross-app guides by having a shared accessible location for different apps on the same effective level domain.
3562
3562
  *
3563
3563
  * @access public
3564
3564
  * @category Config/Core
@@ -3979,12 +3979,12 @@ let SERVER = '';
3979
3979
  let ASSET_HOST = '';
3980
3980
  let ASSET_PATH = '';
3981
3981
  let DESIGNER_SERVER = '';
3982
- let VERSION = '2.326.0_';
3983
- let PACKAGE_VERSION = '2.326.0';
3982
+ let VERSION = '2.327.0_';
3983
+ let PACKAGE_VERSION = '2.327.0';
3984
3984
  let LOADER = 'xhr';
3985
3985
  /* eslint-enable web-sdk-eslint-rules/no-gulp-env-references */
3986
3986
  /**
3987
- * Returns current version of the Pendo Web SDK as a string. Also directly accessible at `pendo.VERSION`.
3987
+ * Returns the current version of the Pendo Web SDK as a string. Also directly accessible at `pendo.VERSION`.
3988
3988
  *
3989
3989
  * @access public
3990
3990
  * @category Core
@@ -5925,7 +5925,7 @@ const ACCOUNT_ID_KEY = 'accountId';
5925
5925
  *
5926
5926
  * @access public
5927
5927
  * @category Identity
5928
- * @param {string} prefix string to prepend to the unique id
5928
+ * @param {string} [prefix] string to prepend to the unique id
5929
5929
  * @returns {string}
5930
5930
  * @example
5931
5931
  * pendo.generate_unique_id('user-') => 'user-RaPiWJ5M53Y'
@@ -6042,7 +6042,7 @@ function findVisitorId() {
6042
6042
  }
6043
6043
  /**
6044
6044
  * Returns the id for the visitor currently being applied to any events being sent to Pendo.
6045
- * Will always be set either by host application or as an anonymous generated ID.
6045
+ * Will always be set either by the host application or as an anonymous generated ID.
6046
6046
  *
6047
6047
  * @access public
6048
6048
  * @alias getVisitorId
@@ -6072,8 +6072,8 @@ function get_visitor_id_public() {
6072
6072
  return get_visitor_id() || generate_anonymous_visitor_id();
6073
6073
  }
6074
6074
  /**
6075
- * Sets visitor id for the web SDK. Requires a valid visitor id string. This will not change
6076
- * or clear existing visitor metadata set.
6075
+ * Sets the visitor id for the web SDK. Requires a valid visitor id string. This will not change
6076
+ * or clear existing visitor metadata.
6077
6077
  *
6078
6078
  * @access public
6079
6079
  * @category Identity
@@ -6115,8 +6115,8 @@ var get_account_id = function () {
6115
6115
  return pendo$1.accountId;
6116
6116
  };
6117
6117
  /**
6118
- * Sets account id for the web SDK without changing existing metadata. However,
6119
- * An invalid account id or an explicit `null` value will clear the current account id
6118
+ * Sets the account id for the web SDK without changing existing metadata. However,
6119
+ * an invalid account id or an explicit `null` value will clear the current account id
6120
6120
  * and account metadata.
6121
6121
  *
6122
6122
  * @access public
@@ -6167,7 +6167,7 @@ function clearAccount() {
6167
6167
  }
6168
6168
  }
6169
6169
  /**
6170
- * Removes current visitor id and account id. Triggers an identify event and reloads
6170
+ * Removes the current visitor id and account id. Triggers an identify event and reloads
6171
6171
  * with a new anonymous visitor.
6172
6172
  *
6173
6173
  * @access public
@@ -8902,16 +8902,17 @@ var SizzleProxy = wrapSizzle(Sizzle);
8902
8902
  * pendo.dom('h1')[0].remove()
8903
8903
  * @example
8904
8904
  * pendo.dom('.left').css({ 'text-align': 'center' })
8905
- */ /**
8906
- * Creates new DOM elements from HTML text.
8907
- *
8908
- * @param {string} htmlString HTML syntax used to produce new DOM elements
8909
- * @returns {DomQuery} array with the matching elements
8910
- * @access public
8911
- * @category DOM
8912
- * @example
8913
- * pendo.dom('<div><span>this should create an unattached DOM node</span></div>');
8914
- */
8905
+ */
8906
+ /**
8907
+ * Creates new DOM elements from HTML text.
8908
+ *
8909
+ * @param {string} htmlString HTML syntax used to produce new DOM elements
8910
+ * @returns {DomQuery} array with the newly created elements
8911
+ * @access public
8912
+ * @category DOM
8913
+ * @example
8914
+ * pendo.dom('<div><span>this should create an unattached DOM node</span></div>');
8915
+ */
8915
8916
  function dom(selection, context) {
8916
8917
  var self = this;
8917
8918
  var nodes;
@@ -9673,7 +9674,7 @@ var objectToQueryString = function (obj) {
9673
9674
  }, '');
9674
9675
  };
9675
9676
  /**
9676
- * URL getter that will return the URL that will be used by the web SDK to describe all data events
9677
+ * URL getter that returns the URL used by the web SDK to describe all data events
9677
9678
  * collected for this app and for Guide requests. This URL can differ from the browser's URL based on
9678
9679
  * customizations made by the host application. The URL customizations can be learned about [here](https://agent.pendo.io/advanced/location).
9679
9680
  *
@@ -10108,7 +10109,7 @@ var locked = false;
10108
10109
  * @category Events
10109
10110
  * @example
10110
10111
  * $ pendo.stopSendingEvents()
10111
- * > Pendo Web SDK locked. No more events will be written.
10112
+ * > Pendo Web SDK locked. No more events will be written.
10112
10113
  */
10113
10114
  var lockEvents = function () {
10114
10115
  var fireEvent = isUnlocked();
@@ -10125,7 +10126,7 @@ var lockEvents = function () {
10125
10126
  * @category Events
10126
10127
  * @example
10127
10128
  * $ pendo.startSendingEvents()
10128
- * > Pendo Web SDK unlocked. Events will be written.
10129
+ * > Pendo Web SDK unlocked. Events will be written.
10129
10130
  */
10130
10131
  var unlockEvents = function () {
10131
10132
  var fireEvent = !isUnlocked();
@@ -10155,8 +10156,8 @@ var isUnlocked = function () {
10155
10156
  * Check if the Element has this classname.
10156
10157
  *
10157
10158
  * @alias hasClass
10158
- * @param {element} elem The Element to test for the classname
10159
- * @param {String} class The classname to look for on the element
10159
+ * @param {element} ele The Element to test for the classname
10160
+ * @param {String} cls The classname to look for on the element
10160
10161
  * @returns {Boolean}
10161
10162
  * @access public
10162
10163
  * @category DOM
@@ -10196,7 +10197,7 @@ var _addClass = function (ele, cls) {
10196
10197
  }
10197
10198
  };
10198
10199
  /**
10199
- * Remove a classname from an Elements classlist.
10200
+ * Remove a classname from an Element's classlist.
10200
10201
  *
10201
10202
  * @alias removeClass
10202
10203
  * @param {element} ele The Element from which the class will be removed
@@ -10219,7 +10220,7 @@ var _removeClass = function (ele, cls) {
10219
10220
  }
10220
10221
  };
10221
10222
  /**
10222
- * Sets the classname from an Element.
10223
+ * Sets the classname for an Element.
10223
10224
  *
10224
10225
  * @alias setClass
10225
10226
  * @param {element} ele The Element that will get the new classlist.
@@ -11031,8 +11032,8 @@ DomQuery.$ = {
11031
11032
  return newDom;
11032
11033
  },
11033
11034
  /**
11034
- * Iterate over each element in the DomQuery list and call the provide callback function passing in the
11035
- * the element as the argument.
11035
+ * Iterate over each element in the DomQuery list and call the provided callback function passing in the
11036
+ * element as the argument.
11036
11037
  *
11037
11038
  * @function each
11038
11039
  * @param {function} callback The callback to be called for each element in the list
@@ -11054,7 +11055,7 @@ DomQuery.$ = {
11054
11055
  * Iterate over each element in the DomQuery list and create and append the Elements represented by the HTML string provided.
11055
11056
  *
11056
11057
  * @function html
11057
- * @param {String} htmlString String representing html to be created as dom Elements for each of the Elements in the list.
11058
+ * @param {String} content String representing html to be created as dom Elements for each of the Elements in the list.
11058
11059
  * @returns {DomQuery}
11059
11060
  * @category DOMQuery
11060
11061
  * @access public
@@ -11075,7 +11076,7 @@ DomQuery.$ = {
11075
11076
  * Iterate over each element in the DomQuery list and add the text provided as innerText on the element.
11076
11077
  *
11077
11078
  * @function text
11078
- * @param {String} content String to be added as innerText
11079
+ * @param {String} content String to be added as innerText.
11079
11080
  * @returns {DomQuery}
11080
11081
  * @access public
11081
11082
  * @category DOMQuery
@@ -11140,7 +11141,7 @@ DomQuery.$ = {
11140
11141
  });
11141
11142
  },
11142
11143
  /**
11143
- * Iterate over each element and checks for each class name. Returns true if all elements have each classname.
11144
+ * Iterate over each element and check for each class name. Returns true if all elements have each classname.
11144
11145
  *
11145
11146
  * @function hasClass
11146
11147
  * @param {String} classNames Space separated string of classnames.
@@ -11163,7 +11164,7 @@ DomQuery.$ = {
11163
11164
  return allElemsHaveClass;
11164
11165
  },
11165
11166
  /**
11166
- * Iterate over each element and toggle each class name on or off depending on the
11167
+ * Iterate over each element and toggle each class name on or off depending on
11167
11168
  * the current state of the element.
11168
11169
  *
11169
11170
  * @function toggleClass
@@ -11191,7 +11192,7 @@ DomQuery.$ = {
11191
11192
  * Iterate over each element and apply the styles object.
11192
11193
  *
11193
11194
  * @function css
11194
- * @param {Object} styles Object containing style attributes names and values
11195
+ * @param {Object} styles Object containing style attribute names and values.
11195
11196
  * @returns {DomQuery}
11196
11197
  * @access public
11197
11198
  * @category DOMQuery
@@ -11245,7 +11246,7 @@ DomQuery.$ = {
11245
11246
  return self;
11246
11247
  },
11247
11248
  /**
11248
- * Add all elements in the list as top most child nodes of the first element found for the given selector.
11249
+ * Add all elements in the list as topmost child nodes of the first element found for the given selector.
11249
11250
  *
11250
11251
  * @function prependTo
11251
11252
  * @param {String} selector CSS selector to identify the target parent element
@@ -11260,10 +11261,10 @@ DomQuery.$ = {
11260
11261
  return this;
11261
11262
  },
11262
11263
  /**
11263
- * Add all children from the selector as top most children of the first element in this list
11264
+ * Add all children from the selector as topmost children of the first element in this list.
11264
11265
  *
11265
11266
  * @function prepend
11266
- * @param {String} selector CSS selector to identify top most child element(s)
11267
+ * @param {String} selector CSS selector to identify topmost child element(s)
11267
11268
  * @returns {DomQuery}
11268
11269
  * @access public
11269
11270
  * @category DOMQuery
@@ -11287,7 +11288,7 @@ DomQuery.$ = {
11287
11288
  return self;
11288
11289
  },
11289
11290
  /**
11290
- * Return the parent node of the first element in this list
11291
+ * Return the parent node of the first element in this list.
11291
11292
  *
11292
11293
  * @function getParent
11293
11294
  * @returns {element}
@@ -11304,7 +11305,7 @@ DomQuery.$ = {
11304
11305
  },
11305
11306
  /**
11306
11307
  * For the first element in this list, insert the first element from the selector before it
11307
- * in parent element's child nodes list.
11308
+ * in the parent element's child nodes list.
11308
11309
  *
11309
11310
  * @function insertBefore
11310
11311
  * @param {String} selector CSS selector for the element to be inserted before this element
@@ -11343,7 +11344,7 @@ DomQuery.$ = {
11343
11344
  return this;
11344
11345
  },
11345
11346
  /**
11346
- * Iterate over each element and set the attribute name to the specified value
11347
+ * Iterate over each element and set the attribute name to the specified value.
11347
11348
  *
11348
11349
  * @function attr
11349
11350
  * @param {String} attrName Name of attribute to set
@@ -11404,10 +11405,10 @@ DomQuery.$ = {
11404
11405
  return dom(this[index]);
11405
11406
  },
11406
11407
  /**
11407
- * Set the height or unset the height for the first element in the list
11408
+ * Set the height or unset the height for the first element in the list.
11408
11409
  *
11409
11410
  * @function height
11410
- * @param {Number} height The new height to set. Undefined will remove the height allow it to auto determined.
11411
+ * @param {Number} height The new height to set. Undefined will remove the height and allow it to be auto determined.
11411
11412
  * @returns {DomQuery}
11412
11413
  * @access public
11413
11414
  * @category DOMQuery
@@ -11428,10 +11429,10 @@ DomQuery.$ = {
11428
11429
  }
11429
11430
  },
11430
11431
  /**
11431
- * Set the width or unset the width for the first element in the list
11432
+ * Set the width or unset the width for the first element in the list.
11432
11433
  *
11433
11434
  * @function width
11434
- * @param {Number} width The new width to set. Undefined will remove the width allow it to auto determined.
11435
+ * @param {Number} width The new width to set. Undefined will remove the width and allow it to be auto determined.
11435
11436
  * @returns {DomQuery}
11436
11437
  * @access public
11437
11438
  * @category DOMQuery
@@ -11452,7 +11453,7 @@ DomQuery.$ = {
11452
11453
  }
11453
11454
  },
11454
11455
  /**
11455
- * For each element in the list, call the element's focus method if it exists
11456
+ * For each element in the list, call the element's focus method if it exists.
11456
11457
  *
11457
11458
  * @function focus
11458
11459
  * @returns {DomQuery}
@@ -12203,12 +12204,14 @@ function callLater(callback, n) {
12203
12204
  *
12204
12205
  * @access public
12205
12206
  * @category Events
12206
- * @param {boolean} force a "full" flush, i.e. ALL `pendo.buffers.silos`
12207
+ * @param {Object} [options] - Options passed through to each queue's flush method
12208
+ * @param {boolean} [options.unload] - signals the page is unloading; drains the send queue using sendBeacon or sync XHR for reliable last-chance delivery
12209
+ * @param {boolean} [options.hidden] - signals the page is being hidden; drains the send queue immediately rather than waiting for the next timer tick
12207
12210
  * @returns {void}
12208
12211
  * @example
12209
12212
  * pendo.flushNow()
12210
12213
  */
12211
- function flushNow(force, options) {
12214
+ function flushNow(options) {
12212
12215
  try {
12213
12216
  _.each(queues, function (queue) {
12214
12217
  if (queue.flush) {
@@ -12221,14 +12224,14 @@ function flushNow(force, options) {
12221
12224
  }
12222
12225
  }
12223
12226
  /*
12224
- * Queue a curried {flushNow} with `force:true` for {n} ticks of the event
12225
- * loop, deferring CPU-intensive compression until the main thread is free.
12227
+ * Queue {flushNow} for {n} ticks of the event loop, deferring CPU-intensive
12228
+ * compression until the main thread is free.
12226
12229
  */
12227
12230
  function flushLater(n) {
12228
- return callLater(_.partial(flushNow, true), n);
12231
+ return callLater(flushNow, n);
12229
12232
  }
12230
12233
  /**
12231
- * Force a full flush, i.e. `flushNow(true)`, on {n} ticks
12234
+ * Force a full flush on {n} ticks
12232
12235
  *
12233
12236
  * @access private
12234
12237
  * @param {number} n ticks to call {flushNow} on
@@ -12492,7 +12495,7 @@ class LocalStorageEventBuffer {
12492
12495
  }
12493
12496
  read(storage) {
12494
12497
  /**
12495
- * If enabled, Pendo will write pending events to local storage before unloading the page
12498
+ * If enabled, Pendo will write pending events to localStorage before unloading the page
12496
12499
  * rather than attempting to send them. The events will be sent the next time the page is loaded.
12497
12500
  *
12498
12501
  * @name _pendo_unsentEvents
@@ -13408,6 +13411,7 @@ var makeSafe = function (method, noLogging) {
13408
13411
  * @function
13409
13412
  * @category URL
13410
13413
  * @param {string} [url] if not provided, defaults to the current URL from the browser
13414
+ * @returns {boolean | undefined} true if the URL changed and a load event was sent, otherwise undefined
13411
13415
  * @example
13412
13416
  * pendo.pageLoad()
13413
13417
  */
@@ -13447,7 +13451,7 @@ pageLoad.reset = function () {
13447
13451
 
13448
13452
  /**
13449
13453
  * Returns the normalized URL sent from the backend. This won't always
13450
- * match the desired output from the customer's url customizations if using location API.
13454
+ * match the desired output from the customer's URL customizations if using the location API.
13451
13455
  *
13452
13456
  * @access public
13453
13457
  * @category URL
@@ -13574,13 +13578,13 @@ function createChannelMatcher(options = {}) {
13574
13578
  }
13575
13579
  /**
13576
13580
  * Returns an array of all guides available on the current page to the current user.
13577
- * If multiple frames on a pages, `pendo.getActiveGuides()` will return the list of eligible
13581
+ * If there are multiple frames on a page, `pendo.getActiveGuides()` will return the list of eligible
13578
13582
  * guides across all frames. If no frames, this will be the same as `pendo.guides`.
13579
13583
  *
13580
13584
  * @access public
13581
13585
  * @category Guides
13582
- * @param {object} options - Options for filtering guides
13583
- * @param {string} options.channel - Channel to filter guides by
13586
+ * @param {object} [options] - Options for filtering guides
13587
+ * @param {string} [options.channel] - Channel to filter guides by
13584
13588
  * @returns {Guide[]}
13585
13589
  * @example
13586
13590
  * pendo.getActiveGuides() => [{ Pendo Guide Object }, ...]
@@ -13642,7 +13646,7 @@ function findGuideBy(field, value) {
13642
13646
  *
13643
13647
  * @access public
13644
13648
  * @category Guides
13645
- * @param {string} id id of the guide as a string
13649
+ * @param {string} guideId id of the guide as a string
13646
13650
  * @returns {Guide | null} JSON guide object or null if no guide found
13647
13651
  * @example
13648
13652
  * pendo.findGuideById('guide_id')
@@ -18239,7 +18243,7 @@ var updateVisitorOptions = function (options = {}) {
18239
18243
  };
18240
18244
  };
18241
18245
  /**
18242
- * Updates metadata object for the Pendo Web SDK. Can include visitor and/or account updates, along
18246
+ * Updates the metadata object for the Pendo Web SDK. Can include visitor and/or account updates, along
18243
18247
  * with customer-defined metadata values. Changes to identity information will potentially fire
18244
18248
  * identity and metadata events, in turn evaluating guide eligibility for the new user and displaying
18245
18249
  * any matching guides automatically.
@@ -18257,11 +18261,11 @@ var updateOptions = makeSafe(function (options) {
18257
18261
  });
18258
18262
  /**
18259
18263
  * This function accepts either a string for just the visitor id or it accepts an Object that will contain at least
18260
- * a visitor object with at least an id field. It may also contain other visitor related Key/Value pairs in the
18261
- * visitor object. Also, in the options object may be an account object that will contain at least an id field. It may
18262
- * also contain other account related Key/Value pairs. This will potentially send an identify event and a metadata event.
18264
+ * a visitor object with at least an id field. It may also contain other visitor-related Key/Value pairs in the
18265
+ * visitor object. Also, the options object may contain an account object that will contain at least an id field. It may
18266
+ * also contain other account-related Key/Value pairs. This will potentially send an identify event and a metadata event.
18263
18267
  *
18264
- * Identifying a visitor will send an event to Pendo and begin loading eligible guides to the identified user. To remove
18268
+ * Identifying a visitor will send an event to Pendo and begin loading eligible guides for the identified user. To remove
18265
18269
  * visitor identity use `pendo.clearSession()`.
18266
18270
  *
18267
18271
  * @access public
@@ -20677,7 +20681,7 @@ var clearLoopTimer = function () {
20677
20681
  store.dispatch('guideUpdate/stopScheduledUpdate');
20678
20682
  };
20679
20683
  /**
20680
- * Clear any showing guides and prevent any loaded guides from rendering.
20684
+ * Clears any showing guides and prevents any loaded guides from rendering.
20681
20685
  * Loaded guides remain in memory, so calling startGuides will work just fine
20682
20686
  * after a stopGuides call.
20683
20687
  *
@@ -20700,7 +20704,7 @@ var stopGuides = function () {
20700
20704
  };
20701
20705
  /**
20702
20706
  * Starts the process that loops over all currently loaded guides and
20703
- * determines what to show. Checks multistep guide continuation,
20707
+ * determines what to show. Checks multi-step guide continuation,
20704
20708
  * auto-display guides, launcher guides, and badges.
20705
20709
  *
20706
20710
  * @access public
@@ -21968,12 +21972,12 @@ function interceptPreventDefault(EventConstructor, eventList) {
21968
21972
  *
21969
21973
  * @access public
21970
21974
  * @category Events
21971
- * @param {HTMLElement} element DOM element to attach listener
21975
+ * @param {HTMLElement} element DOM element to attach listener to
21972
21976
  * @param {string} evt type of DOM event
21973
21977
  * @param {Function} fn callback function
21974
21978
  * @param {Boolean} useCapture use capture phase instead of bubble
21975
21979
  * @example
21976
- * pendo.attachEvent(pendo.dom("h1")[0], 'click', helloWorld = () => { console.log(Hello World") });"
21980
+ * pendo.attachEvent(pendo.dom("h1")[0], 'click', helloWorld = () => { console.log("Hello World") });
21977
21981
  */
21978
21982
  function attachEvent(element, evt, fn, useCapture) {
21979
21983
  if (!(element && evt && fn)) {
@@ -21989,12 +21993,12 @@ function attachEvent(element, evt, fn, useCapture) {
21989
21993
  });
21990
21994
  }
21991
21995
  /**
21992
- * Pendo Web SDK's version of detaching event listeners. Callback must be a named function, cannot remove
21993
- * anonymous functions.
21996
+ * Pendo Web SDK's version of detaching event listeners. The callback must be a named function; anonymous
21997
+ * functions cannot be removed.
21994
21998
  *
21995
21999
  * @access public
21996
22000
  * @category Events
21997
- * @param {HTMLElement} element DOM element to attach listener
22001
+ * @param {HTMLElement} element DOM element to detach listener from
21998
22002
  * @param {string} evt type of DOM event
21999
22003
  * @param {Function} fn callback function
22000
22004
  * @param {Boolean} useCapture use capture phase instead of bubble
@@ -23303,7 +23307,7 @@ var controlGuideLogMessage = 'Guide was not shown because this visitor is in a c
23303
23307
  /**
23304
23308
  * @constant defaultCssUrl {String}
23305
23309
  *
23306
- * Readonly Property that provides the default CSS Url based on the customer's Apps configuration with Pendo.
23310
+ * Readonly property that provides the default CSS URL based on the customer's Apps configuration with Pendo.
23307
23311
  *
23308
23312
  * @access public
23309
23313
  * @category Guides
@@ -23398,7 +23402,7 @@ var getStepIdFromElement = function (element) {
23398
23402
  * In most cases, `pendo.stopGuides()` is preferred since it will stop the loop and guides will not redisplay until `pendo.startGuides()` is called.
23399
23403
  *
23400
23404
  * Manually hide any active Guides. An argument of an Object containing the property stayHidden set to true needs to be
23401
- * provided in order for the guides hidden to stay hidden.
23405
+ * provided in order for the hidden guides to stay hidden.
23402
23406
  *
23403
23407
  * @param {Object} - Optional JS Object containing boolean property `stayHidden`
23404
23408
  * @access public
@@ -23481,7 +23485,7 @@ function shouldAffectThrottling(guide, seenReason) {
23481
23485
  * Hides the current guide and invokes the `guideDismissed` event. Dismissed guides will not
23482
23486
  * be re-displayed by default unless they have a recurrence setting or can be reactivated
23483
23487
  * with an element. They can always be redisplayed via onGuideAdvanced or onGuidePrevious.
23484
-
23488
+ *
23485
23489
  * @access public
23486
23490
  * @category Guides
23487
23491
  * @example
@@ -23545,7 +23549,7 @@ var onGuideDismissed = function (evt, step) {
23545
23549
  };
23546
23550
  /**
23547
23551
  * Snoozes the current guide. If another guide is eligible to be shown automatically, it will show after snooze.
23548
- * Guide will redisplay after one day by default, or a custom `snoozeDuration` can be set in milliseconds as the third argument.
23552
+ * The guide will redisplay after one day by default, or a custom `snoozeDuration` can be set in milliseconds as the third argument.
23549
23553
  *
23550
23554
  * @access public
23551
23555
  * @category Guides
@@ -23660,7 +23664,7 @@ var goToStep = function (evt) {
23660
23664
  };
23661
23665
  /**
23662
23666
  * Proceeds to the next step in a multi-step guide and sends a `guideAdvanced` event.
23663
- * Can advanced multiple steps or beyond a specific step by passing optional parameters.
23667
+ * Can advance multiple steps or beyond a specific step by passing optional parameters.
23664
23668
  * Lastly, sends a `guideSeen` event for the resulting displayed step.
23665
23669
  *
23666
23670
  * @access public
@@ -24222,7 +24226,7 @@ var getNextStepInMultistep = function (lastSeen, urlToCheck) {
24222
24226
  };
24223
24227
  /**
24224
24228
  * Returns the normalized URL sent from the backend with the guides payload. This won't always
24225
- * match the desired output from the customer's url customizations if using location API.
24229
+ * match the desired output from the customer's URL customizations if using the location API.
24226
24230
  *
24227
24231
  * @access public
24228
24232
  * @alias getCurrentUrl
@@ -24234,6 +24238,7 @@ var getNextStepInMultistep = function (lastSeen, urlToCheck) {
24234
24238
  * pendo.normalizedUrl
24235
24239
  * @example
24236
24240
  * pendo.getCurrentUrl()
24241
+ */
24237
24242
  /**
24238
24243
  * Activates the Guide for the given name, if loaded. If it is not in the payload,
24239
24244
  * this function will return false.
@@ -24241,7 +24246,7 @@ var getNextStepInMultistep = function (lastSeen, urlToCheck) {
24241
24246
  * @access public
24242
24247
  * @category Guides
24243
24248
  * @param {string} name name of the guide to display
24244
- * @param {string} reason optional reason for the display
24249
+ * @param {string} [reason] optional reason for the display
24245
24250
  * @example
24246
24251
  * pendo.showGuideByName('guide_name')
24247
24252
  */
@@ -24263,7 +24268,7 @@ var showGuideByName = function (name, reason) {
24263
24268
  * @access public
24264
24269
  * @category Guides
24265
24270
  * @param {string} id id of the guide to display
24266
- * @param {string} reason optional reason for the display
24271
+ * @param {string} [reason] optional reason for the display
24267
24272
  * @example
24268
24273
  * pendo.showGuideById('guide_id')
24269
24274
  */
@@ -24290,7 +24295,7 @@ var resetPendoUI = function () {
24290
24295
  *
24291
24296
  * @access public
24292
24297
  * @name doNotProcess
24293
- * @type {string}
24298
+ * @type {boolean}
24294
24299
  * @category Events
24295
24300
  * @example
24296
24301
  * pendo.doNotProcess => true
@@ -24515,8 +24520,8 @@ function shouldLoadGuides(visitorId, callback) {
24515
24520
  return true;
24516
24521
  }
24517
24522
  /**
24518
- * Manually load guides for current visitor and URL. This is typically handled automatically by the web SDK
24519
- * whenever the host Application changes its URL. In rare circumstances, a host Application may chose to
24523
+ * Manually load guides for the current visitor and URL. This is typically handled automatically by the web SDK
24524
+ * whenever the host Application changes its URL. In rare circumstances, a host Application may choose to
24520
24525
  * force the load of Guides programmatically. One reason may be in order to get any guides designed for a visitor
24521
24526
  * immediately after using a specific part of the Application that doesn't cause a URL change.
24522
24527
  *
@@ -24818,7 +24823,7 @@ function securityPolicyViolationFn(evt) {
24818
24823
  }
24819
24824
  let guideCache;
24820
24825
  /**
24821
- * Resets and starts guide loop
24826
+ * Resets and starts the guide loop.
24822
24827
  *
24823
24828
  * @access public
24824
24829
  * @category Guides
@@ -24924,7 +24929,7 @@ var initGuides = function (observer) {
24924
24929
  */
24925
24930
  agentStorage.registry.addLocal(THROTTLING_STATE.SNOOZED);
24926
24931
  /**
24927
- * Used to determine if guides have been blocked, by the user, adblocker, or a failed guide request.
24932
+ * Used to determine if guides have been blocked by the user, an ad blocker, or a failed guide request.
24928
24933
  * This will prevent additional guide requests and display attempts, to optimize page performance and
24929
24934
  * user experience in cases where guides cannot be loaded.
24930
24935
  *
@@ -24950,7 +24955,7 @@ var initGuides = function (observer) {
24950
24955
  };
24951
24956
  };
24952
24957
  /**
24953
- * Returns true or false if the client has disabled guides in the snippet or via a command
24958
+ * Returns true or false depending on whether the client has disabled guides in the snippet or via a command.
24954
24959
  *
24955
24960
  * @access public
24956
24961
  * @category Guides
@@ -24962,7 +24967,7 @@ var areGuidesDisabled = function () {
24962
24967
  return ConfigReader.get('guides.disabled', false) || !pendoCore;
24963
24968
  };
24964
24969
  /**
24965
- * Returns true or false if the client has delayed guides in the snippet or via a command
24970
+ * Returns true or false depending on whether the client has delayed guides in the snippet or via a command.
24966
24971
  *
24967
24972
  * @access public
24968
24973
  * @category Guides
@@ -26418,7 +26423,7 @@ function insertOriginContentHash(originalHash, url, extensionStr, sha256Hash) {
26418
26423
  }
26419
26424
 
26420
26425
  /**
26421
- * Formerly `apiKey`. Public app ID that is associated with the current Pendo installation as a string.
26426
+ * Formerly `apiKey`. The public app ID associated with the current Pendo installation as a string.
26422
26427
  *
26423
26428
  * @access public
26424
26429
  * @name publicAppId
@@ -26428,7 +26433,7 @@ function insertOriginContentHash(originalHash, url, extensionStr, sha256Hash) {
26428
26433
  * pendo.publicAppId => 'PUBLIC_APP_ID'
26429
26434
  */
26430
26435
  /**
26431
- * Formerly `additionalApiKeys`. Array of additional app IDs that are set in the config. If no primary app ID is set,
26436
+ * Formerly `additionalApiKeys`. An array of additional app IDs that are set in the config. If no primary app ID is set,
26432
26437
  * the first in this array will be assigned to `pendo.publicAppId`.
26433
26438
  *
26434
26439
  * @access public
@@ -27197,7 +27202,7 @@ var P2AutoLaunch = (function () {
27197
27202
  function launchDesignerOrPreview(options) {
27198
27203
  /**
27199
27204
  * Application state while viewing a guide in preview mode. Used while preview mode is active
27200
- * to track step, status, etc, and cleared when preview mode is exited.
27205
+ * to track step, status, etc., and cleared when preview mode is exited.
27201
27206
  *
27202
27207
  * @name pendo-preview
27203
27208
  * @category Cookies/localStorage
@@ -27207,7 +27212,7 @@ function launchDesignerOrPreview(options) {
27207
27212
  agentStorage.registry.addLocal(pendoPreview$1);
27208
27213
  /**
27209
27214
  * Application state while previewing a guide from the designer. Used while designer preview is active
27210
- * to track step, status, etc, and cleared when designer preview is exited.
27215
+ * to track step, status, etc., and cleared when designer preview is exited.
27211
27216
  *
27212
27217
  * @name current-guide-preview
27213
27218
  * @category Cookies/localStorage
@@ -28762,7 +28767,7 @@ var ResourceCenterActivity = (function () {
28762
28767
  })();
28763
28768
 
28764
28769
  /**
28765
- * Returns boolean representing whether the Pendo Web SDK is fully loaded and has an API key.
28770
+ * Returns a boolean representing whether the Pendo Web SDK is fully loaded and has an API key.
28766
28771
  *
28767
28772
  * @access public
28768
28773
  * @category Core
@@ -28977,7 +28982,7 @@ const initializeImmediately = 'initializeImmediately';
28977
28982
  * @function
28978
28983
  * @category Core
28979
28984
  * @name initialize
28980
- * @param {object} options identity metadata and configuration to initialize web SDK
28985
+ * @param {object} options identity metadata and configuration to initialize the web SDK
28981
28986
  * @see {@link https://support.pendo.io/hc/en-us/articles/360046272771-Developer-s-guide-to-installing-Pendo#what-installation-involves-0-2 | Pendo Installation}
28982
28987
  * @example
28983
28988
  * pendo.initialize({
@@ -29080,7 +29085,7 @@ function initialize(options) {
29080
29085
  teardownFns.push(() => observer.teardown());
29081
29086
  if (pendoCore) {
29082
29087
  /**
29083
- * Current visitor id for pendo installation, either anonymous or identified. Used to determine
29088
+ * Current visitor id for the Pendo installation, either anonymous or identified. Used to determine
29084
29089
  * a visitor's guide experience, settings, and associated data.
29085
29090
  *
29086
29091
  * @name _pendo_visitorId
@@ -29090,7 +29095,7 @@ function initialize(options) {
29090
29095
  */
29091
29096
  agentStorage.registry.addLocal(VISITOR_ID_KEY);
29092
29097
  /**
29093
- * Often an anonymous visitor id that is replaced by a logged in user.
29098
+ * Often an anonymous visitor id that is replaced by a logged-in user.
29094
29099
  *
29095
29100
  * @name _pendo_oldVisitorId
29096
29101
  * @category Cookies/localStorage
@@ -29099,7 +29104,7 @@ function initialize(options) {
29099
29104
  */
29100
29105
  agentStorage.registry.addLocal(OLD_VISITOR_ID_KEY);
29101
29106
  /**
29102
- * The current account id for pendo installation provided in the `pendo.initialize()` call.
29107
+ * The current account id for the Pendo installation provided in the `pendo.initialize()` call.
29103
29108
  *
29104
29109
  * @name _pendo_accountId
29105
29110
  * @category Cookies/localStorage
@@ -29135,12 +29140,12 @@ function initialize(options) {
29135
29140
  teardownFns.push(performanceMonitor.initialize());
29136
29141
  }
29137
29142
  const flushOnAppHidden = () => {
29138
- flushNow(true, { hidden: true });
29143
+ flushNow({ hidden: true });
29139
29144
  };
29140
29145
  Events.appHidden.on(flushOnAppHidden);
29141
29146
  teardownFns.push(() => Events.appHidden.off(flushOnAppHidden));
29142
29147
  const flushOnAppUnloaded = () => {
29143
- flushNow(true, { unload: true });
29148
+ flushNow({ unload: true });
29144
29149
  if (localStorageUnloadEnabled) {
29145
29150
  localStorageEventBuffer.write(agentStorage);
29146
29151
  }
@@ -29756,13 +29761,20 @@ var BuildingBlockGuides = (function () {
29756
29761
  detachEvent(targetElement, 'focus', targetElementFocusCallback);
29757
29762
  });
29758
29763
  }
29764
+ function getTargetElementForStep(step) {
29765
+ if (step.element && step.element !== getBody()) {
29766
+ return step.element;
29767
+ }
29768
+ return null;
29769
+ }
29759
29770
  function trapFocusStep(step, guideContainer) {
29760
- var elem = guideContainer.find('#pendo-guide-container');
29761
- trapFocus(elem);
29771
+ var guideContainerElement = guideContainer.find('#pendo-guide-container');
29772
+ var targetElement = _.get(step, 'attributes.blockOutUI.enabled') && getTargetElementForStep(step);
29773
+ trapFocus(guideContainerElement, targetElement);
29762
29774
  }
29763
29775
  function getSelectedPollElementForFocus(focusableChildren, bumperElement) {
29764
29776
  let elementToFocus;
29765
- if (bumperElement.getAttribute('type') === 'radio') {
29777
+ if (bumperElement.getAttribute('type') === 'radio' && bumperElement.getAttribute('data-pendo-poll-id')) {
29766
29778
  const pollId = bumperElement.getAttribute('data-pendo-poll-id');
29767
29779
  elementToFocus = _.find(focusableChildren, function (child) {
29768
29780
  const childPollId = child.getAttribute('data-pendo-poll-id');
@@ -29771,8 +29783,42 @@ var BuildingBlockGuides = (function () {
29771
29783
  }
29772
29784
  return elementToFocus || bumperElement;
29773
29785
  }
29774
- function trapFocus(domElem) {
29775
- var containerNode = domElem[0];
29786
+ function collectTargetFocusables(targetElement) {
29787
+ if (!targetElement)
29788
+ return [];
29789
+ var focusables = _.toArray(targetElement.querySelectorAll(FOCUSABLE_SELECTORS));
29790
+ if (targetElement.matches(FOCUSABLE_SELECTORS)) {
29791
+ focusables.unshift(targetElement);
29792
+ }
29793
+ return focusables;
29794
+ }
29795
+ function createTargetBumper(className) {
29796
+ var bumper = document.createElement('div');
29797
+ bumper.setAttribute('tabIndex', 0);
29798
+ bumper.setAttribute('class', className);
29799
+ bumper.setAttribute('aria-hidden', 'true');
29800
+ bumper.style.cssText = 'position:absolute !important;width:0 !important;height:0 !important;overflow:hidden !important;outline:none !important;border:none !important;padding:0 !important;margin:0 !important;';
29801
+ return bumper;
29802
+ }
29803
+ function insertTargetBumpers(targetElement) {
29804
+ if (!targetElement || !targetElement.parentNode)
29805
+ return null;
29806
+ var before = createTargetBumper('pendo-before-target-focus-bumper');
29807
+ var after = createTargetBumper('pendo-after-target-focus-bumper');
29808
+ targetElement.parentNode.insertBefore(before, targetElement);
29809
+ targetElement.parentNode.insertBefore(after, targetElement.nextSibling);
29810
+ return { before, after };
29811
+ }
29812
+ function removeTargetBumpers(targetBumpers) {
29813
+ if (!targetBumpers)
29814
+ return;
29815
+ _.each([targetBumpers.before, targetBumpers.after], function (bumper) {
29816
+ if (bumper && bumper.parentNode)
29817
+ bumper.parentNode.removeChild(bumper);
29818
+ });
29819
+ }
29820
+ function trapFocus(guideContainerElement, targetElement) {
29821
+ var containerNode = guideContainerElement[0];
29776
29822
  if (!containerNode) {
29777
29823
  return;
29778
29824
  }
@@ -29792,43 +29838,75 @@ var BuildingBlockGuides = (function () {
29792
29838
  // some quirks
29793
29839
  'iframe'
29794
29840
  ].join(', ');
29795
- var focusableChildren = _.toArray(domElem.find(selectors));
29841
+ var focusableChildren = _.toArray(guideContainerElement.find(selectors));
29796
29842
  if (!focusableChildren.length) {
29797
29843
  return;
29798
29844
  }
29799
29845
  var firstFocusableEl = focusableChildren[0];
29800
29846
  var lastFocusableEl = focusableChildren[focusableChildren.length - 1];
29801
29847
  // insert bumpers after the above selectors run for content
29802
- var bumpers = insertTrapFocusBumpers(domElem);
29848
+ var bumpers = insertTrapFocusBumpers(guideContainerElement);
29803
29849
  var startFocusBumper = bumpers[0];
29804
29850
  var endFocusBumper = bumpers[1];
29851
+ var targetFocusables = collectTargetFocusables(targetElement);
29852
+ var firstTargetFocusable = targetFocusables[0];
29853
+ var lastTargetFocusable = targetFocusables[targetFocusables.length - 1];
29854
+ // Insert bumpers as siblings of the target so we can catch focus crossings even when focus moves through a
29855
+ // cross-origin iframe inside the target (our keydown listener can't see events inside the iframe, but it can
29856
+ // see focus landing on a bumper in the parent document afterwards).
29857
+ var targetBumpers = targetFocusables.length ? insertTargetBumpers(targetElement) : null;
29858
+ var beforeTargetBumper = targetBumpers && targetBumpers.before;
29859
+ var afterTargetBumper = targetBumpers && targetBumpers.after;
29860
+ var targetRoot = targetElement && dom.getRootNode(targetElement);
29861
+ var wrapForward = firstTargetFocusable || firstFocusableEl;
29862
+ var wrapBackward = lastTargetFocusable || lastFocusableEl;
29805
29863
  var trapFocusCallback = function (e) {
29806
- const isTabPressed = isTabEvent(e);
29807
- var isShiftPressed = e.shiftKey;
29808
- if (!isTabPressed) {
29864
+ if (!isTabEvent(e)) {
29809
29865
  return;
29810
29866
  }
29867
+ const isShiftPressed = e.shiftKey;
29868
+ const isKeydown = e.type === 'keydown';
29811
29869
  // Check if focus is on the body (clicked on the backdrop), the guide container (starts there when guide opens), or on the focus bumpers
29812
29870
  const activeElement = dom.getRootNode(containerNode).activeElement;
29813
29871
  const containerActive = activeElement === containerNode;
29814
29872
  const bodyActive = document.activeElement === document.body; // if the guide is in a shadow root but you click on the backdrop, the active element is the body of the main document
29815
- // shift + tab
29873
+ const startBumperActive = activeElement === startFocusBumper;
29874
+ const endBumperActive = activeElement === endFocusBumper;
29875
+ const targetActiveElement = targetRoot && targetRoot.activeElement;
29876
+ const beforeTargetBumperActive = !!beforeTargetBumper && targetActiveElement === beforeTargetBumper;
29877
+ const afterTargetBumperActive = !!afterTargetBumper && targetActiveElement === afterTargetBumper;
29878
+ const onLastTargetFocusable = isKeydown && !!lastTargetFocusable && targetActiveElement === lastTargetFocusable;
29879
+ const onFirstTargetFocusable = isKeydown && !!firstTargetFocusable && targetActiveElement === firstTargetFocusable;
29880
+ let elementToFocus;
29816
29881
  if (isShiftPressed) {
29817
- const startBumperActive = activeElement === startFocusBumper;
29818
- if (startBumperActive || containerActive || bodyActive) {
29819
- let elementToFocus = getSelectedPollElementForFocus(focusableChildren, lastFocusableEl);
29820
- elementToFocus.focus();
29821
- e.preventDefault();
29822
- }
29823
- // tab
29882
+ if (onFirstTargetFocusable)
29883
+ elementToFocus = lastFocusableEl;
29884
+ else if (beforeTargetBumperActive)
29885
+ elementToFocus = lastFocusableEl;
29886
+ else if (afterTargetBumperActive)
29887
+ elementToFocus = lastTargetFocusable;
29888
+ else if (startBumperActive || containerActive || bodyActive)
29889
+ elementToFocus = wrapBackward;
29824
29890
  }
29825
29891
  else {
29826
- const endBumperActive = activeElement === endFocusBumper;
29827
- if (containerActive || endBumperActive || bodyActive) {
29828
- let elementToFocus = getSelectedPollElementForFocus(focusableChildren, firstFocusableEl);
29829
- elementToFocus.focus();
29830
- e.preventDefault();
29831
- }
29892
+ if (onLastTargetFocusable)
29893
+ elementToFocus = firstFocusableEl;
29894
+ else if (afterTargetBumperActive)
29895
+ elementToFocus = firstFocusableEl;
29896
+ else if (beforeTargetBumperActive)
29897
+ elementToFocus = firstTargetFocusable;
29898
+ else if (endBumperActive)
29899
+ elementToFocus = wrapForward;
29900
+ else if (containerActive || bodyActive)
29901
+ elementToFocus = firstFocusableEl;
29902
+ }
29903
+ if (elementToFocus) {
29904
+ const resolved = getSelectedPollElementForFocus(focusableChildren, elementToFocus);
29905
+ resolved.focus();
29906
+ if (dom.getRootNode(resolved).activeElement !== resolved) {
29907
+ (isShiftPressed ? lastFocusableEl : firstFocusableEl).focus();
29908
+ }
29909
+ e.preventDefault();
29832
29910
  }
29833
29911
  };
29834
29912
  // attaching to both events helps some edge cases such as breakout by long-pressing the tab
@@ -29837,6 +29915,7 @@ var BuildingBlockGuides = (function () {
29837
29915
  Events.one('unmounted', () => {
29838
29916
  detachEvent(document, 'keyup', trapFocusCallback);
29839
29917
  detachEvent(document, 'keydown', trapFocusCallback);
29918
+ removeTargetBumpers(targetBumpers);
29840
29919
  });
29841
29920
  }
29842
29921
  // bumpers are divs with a tabindex to allow them to be focused, but which should immediately
@@ -30056,7 +30135,7 @@ var shouldWeLog = function (contexts) {
30056
30135
  return (!!logOverride || !!isDebuggingEnabled());
30057
30136
  };
30058
30137
  /**
30059
- * Logs an output to the console as the [Pendo Web SDK].
30138
+ * Logs output to the console as the [Pendo Web SDK].
30060
30139
  *
30061
30140
  * @access public
30062
30141
  * @category Debugging
@@ -30174,12 +30253,12 @@ function collectEventHelper({ type, name, props, eventProperties }) {
30174
30253
  collectEvent(type, correctedProps, url, name, correctedEventProperties);
30175
30254
  }
30176
30255
  /**
30177
- * Method to manually track events. Requires a non-empty name string to collect event.
30256
+ * Method to manually track events. Requires a non-empty name string to collect the event.
30178
30257
  *
30179
30258
  * @access public
30180
30259
  * @category Events
30181
30260
  * @param {string} name name of the collected event
30182
- * @param {Object} [props] optional properties object to collect with to the event
30261
+ * @param {Object} [props] optional properties object to collect with the event
30183
30262
  * @param {Object} [eventProperties] optional key-value map stored on the event as top-level event properties
30184
30263
  * @example
30185
30264
  * pendo.track('scroll')
@@ -30196,7 +30275,7 @@ const privacyFilterCache = new Map();
30196
30275
  *
30197
30276
  * @access public
30198
30277
  * @category Events
30199
- * @param {string} type type of the collected agentic event ['prompt', 'agent_response', 'user_reaction']
30278
+ * @param {string} type type of the collected agentic event (e.g. 'prompt', 'agent_response', 'user_reaction')
30200
30279
  * @param {Object} props event-specific properties object
30201
30280
  * @param {Object} [eventProperties] optional key-value map stored on the event as top-level event properties (same as pendo.track)
30202
30281
  * @example
@@ -30272,7 +30351,7 @@ function getCachedRegex(filterPattern) {
30272
30351
  }
30273
30352
 
30274
30353
  /**
30275
- * Checks visitor and account metadata in the current Pendo installation. Either logs to console
30354
+ * Checks visitor and account metadata in the current Pendo installation. Either logs to the console
30276
30355
  * or returns an array with the results of validation.
30277
30356
  *
30278
30357
  * @access public
@@ -30534,7 +30613,7 @@ var validateBuiltInGlobals = function (skipLogging) {
30534
30613
  }
30535
30614
  };
30536
30615
  /**
30537
- * Checks current URL of the browser for customized or sanitized strings by the application.
30616
+ * Checks the current URL of the browser for strings customized or sanitized by the application.
30538
30617
  *
30539
30618
  * @access public
30540
30619
  * @category Validation
@@ -30623,6 +30702,7 @@ const validatePluginsAndExtensions = (skipLogging) => {
30623
30702
  *
30624
30703
  * @access public
30625
30704
  * @category Validation
30705
+ * @param {boolean} [skipLogging] does not log output to console if true, returning the environment object instead
30626
30706
  * @example
30627
30707
  * pendo.validateEnvironment()
30628
30708
  */
@@ -31111,7 +31191,7 @@ const DEFAULT_GUIDE_SEEN_TIMEOUT_LENGTH = 10000;
31111
31191
  * @constant guideSeenTimeoutLength {number}
31112
31192
  *
31113
31193
  * Readonly number that indicates how long a guide will try to show before sending an error.
31114
- * Defaults to 10 seconds.
31194
+ * Defaults to 10 seconds (10000 ms).
31115
31195
  *
31116
31196
  * @access public
31117
31197
  * @category Guides
@@ -31229,9 +31309,7 @@ function exportPublicApi(pendo) {
31229
31309
  pendo.VERSION = VERSION;
31230
31310
  pendo.LOADER = LOADER;
31231
31311
  // cache.js
31232
- pendo.flushNow = exportPendoCoreOnly(function forceFlushNow(options) {
31233
- return flushNow(true, options);
31234
- });
31312
+ pendo.flushNow = exportPendoCoreOnly(flushNow);
31235
31313
  pendo.teardown = makeSafe(teardown);
31236
31314
  // guides.js
31237
31315
  pendo.initGuides = exportPendoCoreOnly(initGuides);
@@ -31374,7 +31452,7 @@ function exportPublicApi(pendo) {
31374
31452
  pendo.receiveDomStructureJson = exportPendoCoreOnly(ContentLoader.receiveDomStructureJson);
31375
31453
  pendo.addExtension = addExtension;
31376
31454
  /**
31377
- * Retrieve a configuration value from the web sdk's config. Available configuration keys can be
31455
+ * Retrieve a configuration value from the web SDK's config. Available configuration keys can be
31378
31456
  * found in the [configuration section](/config).
31379
31457
  *
31380
31458
  * @access public
@@ -31624,7 +31702,7 @@ function Guide() {
31624
31702
  return true;
31625
31703
  };
31626
31704
  /**
31627
- * Returns a Boolean value to indicate if the Guide can Show at this time.
31705
+ * Returns a Boolean value to indicate if the Guide can show at this time.
31628
31706
  *
31629
31707
  * @access public
31630
31708
  * @category Guides
@@ -31657,13 +31735,13 @@ function Guide() {
31657
31735
  return promise;
31658
31736
  };
31659
31737
  /**
31660
- * Attempt to show the Guide. The Guide will still honor any constraints like
31661
- * requiring a DOM element to be present if it was configured for that.
31662
- *
31663
- * @access public
31664
- * @category Guides
31665
- * @returns {void}
31666
- */
31738
+ * Attempt to show the Guide. The Guide will still honor any constraints like
31739
+ * requiring a DOM element to be present if it was configured for that.
31740
+ *
31741
+ * @access public
31742
+ * @category Guides
31743
+ * @returns {void}
31744
+ */
31667
31745
  this.show = function (reason) {
31668
31746
  var guide = this;
31669
31747
  return joinShowPromises(_.map(guide.steps, function (step) {
@@ -31677,7 +31755,7 @@ function Guide() {
31677
31755
  *
31678
31756
  * @access public
31679
31757
  * @category Guides
31680
- * @returns {Boolean}
31758
+ * @returns {void}
31681
31759
  * @example
31682
31760
  * guide.hide({stayHidden: true});
31683
31761
  */
@@ -32774,7 +32852,7 @@ function GuideStep(guide) {
32774
32852
  removeStyleElementsForIdFromHead(this.id);
32775
32853
  };
32776
32854
  /**
32777
- * Attemps to show the step.
32855
+ * Attempts to show the step.
32778
32856
  *
32779
32857
  * @access public
32780
32858
  * @category Guides
@@ -32955,7 +33033,7 @@ function GuideStep(guide) {
32955
33033
  /**
32956
33034
  * Hides the Step if shown. Use an argument of an Object containing a
32957
33035
  * key of `stayHidden` set to `true` to make sure to keep the Step hidden
32958
- * if the Guide it belongs to is designated as Automatically shown.
33036
+ * if the Guide it belongs to is designated as automatically shown.
32959
33037
  *
32960
33038
  * @access public
32961
33039
  * @category Guides
@@ -33006,7 +33084,7 @@ function GuideStep(guide) {
33006
33084
  *
33007
33085
  * @access public
33008
33086
  * @category Guides
33009
- * @returns {boolean}
33087
+ * @returns {void}
33010
33088
  */
33011
33089
  this.dismiss = function () {
33012
33090
  if (this.seenState === 'dismissed' && !this.isRendered())
@@ -33032,9 +33110,9 @@ function GuideStep(guide) {
33032
33110
  * Allows for an eventListener to be created that will automatically get cleaned up when this
33033
33111
  * Step is torn down.
33034
33112
  *
33035
- * @param element {Element} - The DOM element to attach the listener.
33113
+ * @param element {Element} - The DOM element to attach the listener to.
33036
33114
  * @param type {String} - The type of event: 'click', 'mousedown', 'keypress', etc...
33037
- * @param fn {function} - A function that will be called when an event occurs of the specified type.
33115
+ * @param fn {function} - A function that will be called when an event of the specified type occurs.
33038
33116
  *
33039
33117
  * @access public
33040
33118
  * @category Guides
@@ -33192,7 +33270,7 @@ class CloneDetection {
33192
33270
  return;
33193
33271
  /**
33194
33272
  * Randomly generated ID used to detect when sessionStorage has been cloned
33195
- * from another browser window.
33273
+ * from another browser tab.
33196
33274
  *
33197
33275
  * @name pendo_cd
33198
33276
  * @category Cookies/sessionStorage
@@ -33309,7 +33387,7 @@ var FramesModule = (function () {
33309
33387
  if (state.initialized)
33310
33388
  return;
33311
33389
  /**
33312
- * Randomly generated string that identifies a browser window.
33390
+ * Randomly generated string that identifies a browser tab.
33313
33391
  *
33314
33392
  * @name pendo_tabId
33315
33393
  * @category Cookies/sessionStorage
@@ -33318,7 +33396,7 @@ var FramesModule = (function () {
33318
33396
  */
33319
33397
  agentStorage.registry.addSession(TAB_ID);
33320
33398
  /**
33321
- * When a browser window is cloned the `pendo_tabId` is copied to the new window.
33399
+ * When a browser tab is cloned, the `pendo_tabId` is copied to the new tab.
33322
33400
  * The Pendo Web SDK detects this, creates a new `pendo_tabId`, and stores the old
33323
33401
  * `pendo_tabId` in `pendo_parentTabId`.
33324
33402
  *
@@ -35397,7 +35475,7 @@ function addDebuggingFunctions() {
35397
35475
  pendo$1.debugging = debugging;
35398
35476
  }
35399
35477
  /**
35400
- * Loads Pendo Debugger and extends the global pendo object with additional functionality
35478
+ * Loads the Pendo Debugger and extends the global `pendo` object with additional functionality
35401
35479
  * for debugging purposes.
35402
35480
  *
35403
35481
  * @access public
@@ -35424,7 +35502,7 @@ function enableDebugging(andChain) {
35424
35502
  return 'debugging enabled';
35425
35503
  }
35426
35504
  /**
35427
- * Removes Pendo Debugger extension.
35505
+ * Removes the Pendo Debugger extension.
35428
35506
  *
35429
35507
  * @access public
35430
35508
  * @category Debugging
@@ -35503,7 +35581,7 @@ const DebuggerLauncher = (function () {
35503
35581
  }
35504
35582
  globalPendo = pendo;
35505
35583
  /**
35506
- * Returns a string indicating debugging status. Pass an optional value of true to get result as a boolean.
35584
+ * Returns a string indicating debugging status. Pass an optional value of true to get the result as a boolean.
35507
35585
  *
35508
35586
  * @access public
35509
35587
  * @category Debugging
@@ -36081,7 +36159,7 @@ const EmbeddedGuides = (function () {
36081
36159
  }
36082
36160
  })();
36083
36161
  /**
36084
- * Returns a list of embedded guides eligible to the active visitor on the active page
36162
+ * Returns a list of embedded guides eligible for the active visitor on the active page.
36085
36163
  *
36086
36164
  * @access public
36087
36165
  * @category Guides
@@ -36093,7 +36171,7 @@ function getEmbeddedGuides() {
36093
36171
  return EmbeddedGuides.activeEmbeddedGuides;
36094
36172
  }
36095
36173
  /**
36096
- * Returns a list of embedded guides that are rendered on the page
36174
+ * Returns a list of embedded guides that are rendered on the page.
36097
36175
  *
36098
36176
  * @access public
36099
36177
  * @category Guides
@@ -39031,7 +39109,7 @@ var doesLauncherHaveGuides = function () {
39031
39109
  return dom('._pendo-launcher-item_').length > 0;
39032
39110
  };
39033
39111
  /**
39034
- * Closes Pendo Guide Center (launcher) if open on page.
39112
+ * Closes the Pendo Guide Center (launcher) if open on the page.
39035
39113
  *
39036
39114
  * @access public
39037
39115
  * @category Classic Guides
@@ -39049,7 +39127,7 @@ var collapseLauncherList = function () {
39049
39127
  }
39050
39128
  };
39051
39129
  /**
39052
- * Opens Pendo Guide Center (launcher) if present on page.
39130
+ * Opens the Pendo Guide Center (launcher) if present on the page.
39053
39131
  *
39054
39132
  * @access public
39055
39133
  * @category Classic Guides
@@ -39162,7 +39240,7 @@ var initLauncherPlugin = function (pendo, PluginAPI) {
39162
39240
  PluginAPI.GuideLoop.addUpdatePhase(launcherProc);
39163
39241
  registerLoadGuideJobs(loadLauncherContentHandler);
39164
39242
  /**
39165
- * Written when the classic guide center is closed. Legacy guide center only, not used for resource center.
39243
+ * Written when the classic guide center is closed. Legacy guide center only; not used for the resource center.
39166
39244
  *
39167
39245
  * @name _pendo_launcher-closed
39168
39246
  * @category Cookies/localStorage
@@ -39367,7 +39445,7 @@ var PromoteMetadata = (function () {
39367
39445
  promotedAgentMetadata = PluginAPI.ConfigReader.get(PROMOTED_AGENT_METADATA);
39368
39446
  schemaGroup = {};
39369
39447
  /**
39370
- * Stores the historical metadata fields for the current visitor, when enabled in an application.
39448
+ * Stores the historical metadata fields for the current visitor when enabled in an application.
39371
39449
  * This is turned on by an admin in Pendo's Data Mappings and used to track metadata changes over time.
39372
39450
  *
39373
39451
  * @name _pendo___sg__
@@ -39972,6 +40050,299 @@ class DOMPrompt {
39972
40050
  }
39973
40051
  }
39974
40052
 
40053
+ const ASSISTANT_MESSAGE = 'assistantMessage';
40054
+ const CONVERSATION_ID_URL_PATTERN = 'conversationIdUrlPattern';
40055
+ const MESSAGE_ID_ATTR = 'messageIdAttr';
40056
+ const MODEL_USED_ATTR = 'modelUsedAttr';
40057
+ const REACTION_ACTIVE = 'reactionActive';
40058
+ const STREAMING_ACTIVE = 'streamingActive';
40059
+ const STREAMING_ACTIVE_ATTR = 'streamingActiveAttr';
40060
+ const THUMB_DOWN = 'thumbDown';
40061
+ const THUMB_UP = 'thumbUp';
40062
+ const TURN_CONTAINER = 'turnContainer';
40063
+ const TURN_ATTR = 'turnAttr';
40064
+ const USER_MESSAGE = 'userMessage';
40065
+ const REQUIRED_SELECTORS = [
40066
+ ASSISTANT_MESSAGE,
40067
+ CONVERSATION_ID_URL_PATTERN,
40068
+ MESSAGE_ID_ATTR,
40069
+ STREAMING_ACTIVE,
40070
+ TURN_CONTAINER,
40071
+ TURN_ATTR,
40072
+ USER_MESSAGE
40073
+ ];
40074
+ const STREAMING_END_SETTLE_MS = 500;
40075
+ class DOMConversation {
40076
+ // Returns the list of required selector types that are missing or empty
40077
+ // in the given cssSelectors config. An empty array means the config is
40078
+ // valid for instantiation.
40079
+ static validateConfig(cssSelectors) {
40080
+ if (!Array.isArray(cssSelectors)) {
40081
+ return REQUIRED_SELECTORS.slice();
40082
+ }
40083
+ const present = new Set();
40084
+ for (const cfg of cssSelectors) {
40085
+ if (!cfg || !cfg.type || !cfg.cssSelector)
40086
+ continue;
40087
+ if (cfg.type === CONVERSATION_ID_URL_PATTERN) {
40088
+ try {
40089
+ RegExp(cfg.cssSelector);
40090
+ }
40091
+ catch (e) {
40092
+ continue;
40093
+ }
40094
+ }
40095
+ present.add(cfg.type);
40096
+ }
40097
+ return REQUIRED_SELECTORS.filter((r) => !present.has(r));
40098
+ }
40099
+ static supportedPreset(preset) {
40100
+ return preset === 'chatgpt-full';
40101
+ }
40102
+ constructor(pendo, PluginAPI, id, privacyFilters, cssSelectors) {
40103
+ this.selectors = {};
40104
+ this.listeners = [];
40105
+ this.isActive = true;
40106
+ this.observers = [];
40107
+ this.wasStreaming = false;
40108
+ this.streamingEndTimer = null;
40109
+ this.requestNode = null;
40110
+ this.conversationIdRegex = null;
40111
+ this.lastReturnedMessageId = null;
40112
+ this.dom = pendo.dom;
40113
+ this._ = pendo._;
40114
+ this.api = PluginAPI;
40115
+ this.Sizzle = pendo.Sizzle;
40116
+ this.id = id;
40117
+ this.setFilters(privacyFilters);
40118
+ if (!this._.isArray(cssSelectors)) {
40119
+ this.api.log.error(`cssSelectors must be an array, received: ${typeof cssSelectors}`);
40120
+ cssSelectors = [];
40121
+ }
40122
+ this._.each(cssSelectors, (cfg) => {
40123
+ if (cfg && cfg.type) {
40124
+ this.selectors[cfg.type] = cfg.cssSelector;
40125
+ }
40126
+ });
40127
+ this.conversationIdRegex = new RegExp(this.selectors[CONVERSATION_ID_URL_PATTERN]);
40128
+ this.root = document.body;
40129
+ this.setupReactionListener();
40130
+ this.setupStreamingObserver();
40131
+ }
40132
+ setupReactionListener() {
40133
+ if (!this.findSelector(THUMB_UP) && !this.findSelector(THUMB_DOWN))
40134
+ return;
40135
+ this.reactionClickHandler = this.handleReactionClick.bind(this);
40136
+ this.root.addEventListener('click', this.reactionClickHandler, true);
40137
+ }
40138
+ handleReactionClick(evt) {
40139
+ const target = evt.target;
40140
+ if (!target || target.nodeType !== 1)
40141
+ return;
40142
+ const upSelector = this.findSelector(THUMB_UP);
40143
+ const downSelector = this.findSelector(THUMB_DOWN);
40144
+ const thumb = this.dom(target).closest(`${upSelector}, ${downSelector}`);
40145
+ if (!thumb.length)
40146
+ return;
40147
+ const isUp = this.Sizzle.matchesSelector(thumb[0], upSelector);
40148
+ const activeSelector = this.findSelector(REACTION_ACTIVE);
40149
+ const wasPressed = activeSelector && this.Sizzle.matchesSelector(thumb[0], activeSelector);
40150
+ const direction = isUp ? 'positive' : 'negative';
40151
+ const content = wasPressed ? 'unreact' : direction;
40152
+ const assistantNode = thumb.closest(this.findSelector(TURN_CONTAINER))
40153
+ .find(this.findSelector(ASSISTANT_MESSAGE));
40154
+ this.emit('user_reaction', {
40155
+ agentId: this.id,
40156
+ messageId: this.getMessageId(assistantNode),
40157
+ content,
40158
+ privacyFilterApplied: false
40159
+ });
40160
+ }
40161
+ // observe the streaming indicator
40162
+ setupStreamingObserver() {
40163
+ this.wasStreaming = this.select(STREAMING_ACTIVE).length > 0;
40164
+ this.stopStreamingEndTimer();
40165
+ const MutationObserver = getZoneSafeMethod('MutationObserver');
40166
+ const observer = new MutationObserver(this.handleMutation.bind(this));
40167
+ const attrName = this.findSelector(STREAMING_ACTIVE_ATTR);
40168
+ observer.observe(this.root, {
40169
+ childList: true,
40170
+ subtree: true,
40171
+ attributes: true,
40172
+ attributeFilter: attrName ? [attrName] : undefined
40173
+ });
40174
+ this.observers.push(observer);
40175
+ }
40176
+ // look for changes in the state of the streaming indicator.
40177
+ // streaming started -> a prompt has been submitted
40178
+ // streaming ended -> got a response
40179
+ // we don't send the prompt immediately when it's submitted because it might not have a
40180
+ // conversation id yet.
40181
+ // we don't send the agent_response immediately when the streaming indicator is cleared
40182
+ // because it clears slightly before the final text chunk is committed to the DOM so the
40183
+ // end-handling is deferred by a short settle window
40184
+ handleMutation() {
40185
+ const isStreaming = this.select(STREAMING_ACTIVE).length > 0;
40186
+ if (isStreaming === this.wasStreaming)
40187
+ return;
40188
+ if (isStreaming) { // started streaming
40189
+ if (!this.streamingEndTimer) {
40190
+ this.onSubmissionStart();
40191
+ }
40192
+ else {
40193
+ // stream restarted during the settle window (multi-phase response).
40194
+ // treat as a continuation of the prior request, not a new submission.
40195
+ // we'll handle it next time streaming stops
40196
+ this.stopStreamingEndTimer();
40197
+ }
40198
+ }
40199
+ else { // finished streaming
40200
+ this.startStreamingEndTimer();
40201
+ }
40202
+ this.wasStreaming = isStreaming;
40203
+ }
40204
+ onSubmissionStart() {
40205
+ this.requestNode = this.findLastRequestNode();
40206
+ if (this.requestNode) {
40207
+ this.handleUserMessage(this.requestNode);
40208
+ }
40209
+ }
40210
+ onSubmissionEnd() {
40211
+ this.streamingEndTimer = null;
40212
+ let requestNode = this.requestNode;
40213
+ this.requestNode = null;
40214
+ if (!requestNode) {
40215
+ // onSubmissionStart didn't send, send it now
40216
+ requestNode = this.findLastRequestNode();
40217
+ if (!requestNode)
40218
+ return;
40219
+ this.handleUserMessage(requestNode);
40220
+ }
40221
+ const requestTurn = this.findTurnNumber(requestNode);
40222
+ if (requestTurn === null)
40223
+ return;
40224
+ const assistantNodes = this.select(ASSISTANT_MESSAGE);
40225
+ const toEmit = [];
40226
+ for (let i = assistantNodes.length - 1; i >= 0; i--) {
40227
+ const n = this.findTurnNumber(this.dom(assistantNodes[i]));
40228
+ if (n === null)
40229
+ continue;
40230
+ if (n <= requestTurn)
40231
+ break;
40232
+ toEmit.push(assistantNodes[i]);
40233
+ }
40234
+ // emit in chronological order (reverse of collection order)
40235
+ for (let i = toEmit.length - 1; i >= 0; i--) {
40236
+ this.handleAssistantMessage(this.dom(toEmit[i]));
40237
+ }
40238
+ }
40239
+ extractContent(node) {
40240
+ const rawContent = node.text().trim();
40241
+ const content = this.applyPrivacyFilter(rawContent);
40242
+ return { content, privacyFilterApplied: content !== rawContent };
40243
+ }
40244
+ getMessageId(node) {
40245
+ return node.attr(this.findSelector(MESSAGE_ID_ATTR));
40246
+ }
40247
+ handleUserMessage(node) {
40248
+ this.emit('prompt', Object.assign({ agentId: this.id, messageId: this.getMessageId(node) }, this.extractContent(node)));
40249
+ }
40250
+ handleAssistantMessage(node) {
40251
+ const modelUsedAttr = this.findSelector(MODEL_USED_ATTR);
40252
+ const modelUsed = modelUsedAttr && node.attr(modelUsedAttr);
40253
+ this.emit('agent_response', Object.assign({ agentId: this.id, messageId: this.getMessageId(node), agentModelsUsed: modelUsed ? [modelUsed] : [] }, this.extractContent(node)));
40254
+ }
40255
+ findLastRequestNode() {
40256
+ if (!this.getConversationId())
40257
+ return null;
40258
+ const node = this._.last(this.select(USER_MESSAGE));
40259
+ if (!node)
40260
+ return null;
40261
+ const $node = this.dom(node);
40262
+ const messageId = this.getMessageId($node);
40263
+ if (!messageId)
40264
+ return null;
40265
+ if (messageId === this.lastReturnedMessageId)
40266
+ return null;
40267
+ this.lastReturnedMessageId = messageId;
40268
+ return $node;
40269
+ }
40270
+ findTurnNumber(node) {
40271
+ const turnSelector = this.findSelector(TURN_CONTAINER);
40272
+ const turnAttr = this.findSelector(TURN_ATTR);
40273
+ const turn = node.closest(turnSelector).attr(turnAttr);
40274
+ if (!turn)
40275
+ return null;
40276
+ const seqMatch = String(turn).match(/\d+/);
40277
+ return seqMatch ? parseInt(seqMatch[0], 10) : null;
40278
+ }
40279
+ findSelector(type) {
40280
+ return this.selectors[type];
40281
+ }
40282
+ select(type) {
40283
+ return this.dom(this.findSelector(type), this.root);
40284
+ }
40285
+ getConversationId() {
40286
+ const m = location.href.match(this.conversationIdRegex);
40287
+ if (!m)
40288
+ return null;
40289
+ return m[1] !== undefined ? m[1] : m[0];
40290
+ }
40291
+ setFilters(candidateFilter) {
40292
+ if (!candidateFilter) {
40293
+ this.privacyFilters = null;
40294
+ return null;
40295
+ }
40296
+ try {
40297
+ this.privacyFilters = new RegExp(candidateFilter, 'gmi');
40298
+ }
40299
+ catch (e) {
40300
+ this.privacyFilters = null;
40301
+ this.api.log.error(e);
40302
+ }
40303
+ return this.privacyFilters;
40304
+ }
40305
+ applyPrivacyFilter(candidateValue, filters = null) {
40306
+ const filtersToUse = filters || this.privacyFilters;
40307
+ if (!filtersToUse || !this._.isRegExp(filtersToUse))
40308
+ return candidateValue;
40309
+ return candidateValue.replace(filtersToUse, 'redacted');
40310
+ }
40311
+ onSubmit(callback) {
40312
+ this.listeners.push(callback);
40313
+ }
40314
+ emit(eventType, eventPayload) {
40315
+ eventPayload.conversationId = this.getConversationId();
40316
+ this._.each(this.listeners, (cb) => cb(eventType, eventPayload));
40317
+ }
40318
+ startStreamingEndTimer() {
40319
+ this.stopStreamingEndTimer();
40320
+ this.streamingEndTimer = setTimeout$1(this.onSubmissionEnd.bind(this), STREAMING_END_SETTLE_MS);
40321
+ }
40322
+ stopStreamingEndTimer() {
40323
+ if (!this.streamingEndTimer)
40324
+ return;
40325
+ clearTimeout(this.streamingEndTimer);
40326
+ this.streamingEndTimer = null;
40327
+ }
40328
+ suspend() {
40329
+ this.isActive = false;
40330
+ }
40331
+ resume() {
40332
+ this.isActive = true;
40333
+ }
40334
+ teardown() {
40335
+ this._.each(this.observers, (o) => o && o.disconnect && o.disconnect());
40336
+ this.observers = [];
40337
+ if (this.reactionClickHandler && this.root) {
40338
+ this.root.removeEventListener('click', this.reactionClickHandler, true);
40339
+ this.reactionClickHandler = null;
40340
+ }
40341
+ this.stopStreamingEndTimer();
40342
+ this.listeners = [];
40343
+ }
40344
+ }
40345
+
39975
40346
  /*
39976
40347
  * Prompt Analytics Plugin
39977
40348
  *
@@ -40136,18 +40507,31 @@ class PromptPlugin {
40136
40507
  }
40137
40508
  }
40138
40509
  observePrompt(config) {
40139
- const { id, cssSelectors, privacyFilters } = config;
40510
+ const { id, cssSelectors, privacyFilters, preset } = config;
40140
40511
  // Check if agent already exists
40141
40512
  const existingPrompt = this._.find(this.prompts, prompt => prompt.id === id);
40142
40513
  if (existingPrompt) {
40143
40514
  return;
40144
40515
  }
40516
+ if (DOMConversation.supportedPreset(preset)) {
40517
+ const missing = DOMConversation.validateConfig(cssSelectors);
40518
+ if (missing.length) {
40519
+ this.api.log.error('aiAgent config missing required selectors', { agentId: id, missing });
40520
+ return;
40521
+ }
40522
+ const conversation = new DOMConversation(this.pendo, this.api, id, privacyFilters, cssSelectors);
40523
+ conversation.onSubmit((eventType, payload) => {
40524
+ this.sendConversationEvent(eventType, payload);
40525
+ });
40526
+ this.prompts.push(conversation);
40527
+ return;
40528
+ }
40145
40529
  let inputCssSelectors, submitCssSelectors;
40146
40530
  inputCssSelectors = this.parseCssSelector('input', cssSelectors);
40147
40531
  submitCssSelectors = this.parseCssSelector('submit', cssSelectors);
40148
40532
  const prompt = new DOMPrompt(this.pendo, this.api, id, privacyFilters, inputCssSelectors, submitCssSelectors);
40149
40533
  prompt.onSubmit((promptPayload) => {
40150
- this.sendEvent(promptPayload);
40534
+ this.sendPromptEvent(promptPayload);
40151
40535
  });
40152
40536
  this.prompts.push(prompt);
40153
40537
  }
@@ -40156,7 +40540,7 @@ class PromptPlugin {
40156
40540
  const selectors = this._.map(filtered, cfg => cfg.cssSelector);
40157
40541
  return selectors;
40158
40542
  }
40159
- sendEvent(promptEvent) {
40543
+ sendPromptEvent(promptEvent) {
40160
40544
  // Block event if the prompt is suspended
40161
40545
  const prompt = this._.find(this.prompts, p => p.id === promptEvent.agentId);
40162
40546
  if (prompt && !prompt.isActive) {
@@ -40168,6 +40552,15 @@ class PromptPlugin {
40168
40552
  }, promptEvent);
40169
40553
  this.api.analytics.collectEvent('prompt', event, undefined, 'agentic');
40170
40554
  }
40555
+ sendConversationEvent(eventType, eventPayload) {
40556
+ // Block event if the prompt is suspended
40557
+ const conv = this._.find(this.prompts, p => p.id === eventPayload.agentId);
40558
+ if (conv && !conv.isActive) {
40559
+ return;
40560
+ }
40561
+ eventPayload = this._.extend({ agentType: 'conversation' }, eventPayload);
40562
+ this.api.analytics.collectEvent(eventType, eventPayload, undefined, 'agentic');
40563
+ }
40171
40564
  teardown() {
40172
40565
  this._.each(this.prompts, (prompt) => prompt.teardown());
40173
40566
  if (this.agentsCache) {
@@ -40235,7 +40628,7 @@ class SessionManager {
40235
40628
  this.suffix = this.api.ConfigReader.get('identityStorageSuffix');
40236
40629
  /**
40237
40630
  * Randomly generated string that identifies a session. This is similar to `pendo_tabId`,
40238
- * but identifies the entire browser, rather than individual tabs.
40631
+ * but identifies the entire browser session rather than individual tabs.
40239
40632
  *
40240
40633
  * @name sessionId
40241
40634
  * @category Cookies/localStorage
@@ -49467,7 +49860,7 @@ class SessionRecorder {
49467
49860
  // https://github.com/pendo-io/pendo-browser-extension/blob/master/src/common/agent-loader.js
49468
49861
  cf.addOption(RECORDING_CONFIG_ON_RECORDING_STOP, [cf.sources.SNIPPET_SRC, cf.sources.PENDO_CONFIG_SRC], undefined);
49469
49862
  /**
49470
- * Used when self hosting the replay web worker. Specifies the URL that points to the self hosted web worker.
49863
+ * Used when self-hosting the replay web worker. Specifies the URL that points to the self-hosted web worker.
49471
49864
  *
49472
49865
  * @access public
49473
49866
  * @category Config/Replay
@@ -49575,7 +49968,7 @@ class SessionRecorder {
49575
49968
  this.subscriptions.push(this.api.attachEvent(this.api.Events, 'ready', bind(this.ready, this)));
49576
49969
  }
49577
49970
  /**
49578
- * Randomly generated string that identifies a session. This is the same as `pendo_sessionId`, but
49971
+ * Randomly generated string that identifies a session. This is similar to `pendo_sessionId`, but
49579
49972
  * meant specifically for session recording.
49580
49973
  *
49581
49974
  * @name pendo_srId
@@ -49740,6 +50133,7 @@ class SessionRecorder {
49740
50133
  * Used to start collecting replay data.
49741
50134
  *
49742
50135
  * @function start
50136
+ * @alias recording.start
49743
50137
  * @category Replay
49744
50138
  * @access public
49745
50139
  * @example
@@ -52090,6 +52484,7 @@ function NetworkCapture() {
52090
52484
  * Use RegExp for flexible or partial matching.
52091
52485
  *
52092
52486
  * Example: `['https://example.com', new RegExp('https://test\\.com\\/.*'), /.*\\.domain\\.com/]`
52487
+ *
52093
52488
  * @access public
52094
52489
  * @category Config/Network Logs
52095
52490
  * @name networkLogs.excludeRequestUrls