@pendo/agent 2.329.0 → 2.330.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3403,7 +3403,7 @@ var ConfigReader = (function () {
3403
3403
  * cookies, localStorage, click tracking, and metadata. Only displays guides
3404
3404
  * that have been configured explicitly to show to this visitor.
3405
3405
  *
3406
- * @access private
3406
+ * @access public
3407
3407
  * @category Config/Guides
3408
3408
  * @name doNotTrackGuides
3409
3409
  * @default false
@@ -4010,8 +4010,8 @@ let SERVER = '';
4010
4010
  let ASSET_HOST = '';
4011
4011
  let ASSET_PATH = '';
4012
4012
  let DESIGNER_SERVER = '';
4013
- let VERSION = '2.329.0_';
4014
- let PACKAGE_VERSION = '2.329.0';
4013
+ let VERSION = '2.330.1_';
4014
+ let PACKAGE_VERSION = '2.330.1';
4015
4015
  let LOADER = 'xhr';
4016
4016
  /* eslint-enable web-sdk-eslint-rules/no-gulp-env-references */
4017
4017
  /**
@@ -4587,11 +4587,16 @@ function hasCookieDomain() {
4587
4587
  return !!cookieDomain;
4588
4588
  }
4589
4589
  function clearCookie(name) {
4590
- if (hasCookieDomain()) {
4591
- setCookie(name, '');
4592
- return;
4590
+ // Always expire the cookie rather than overwriting it with an empty value.
4591
+ // When a cookieDomain is set the domain attribute must be included or the
4592
+ // domain-scoped cookie can't be matched for deletion -- omitting it (or
4593
+ // writing a blank value) leaves a permanent empty cookie that still costs
4594
+ // request-header space via its name.
4595
+ var cookie = name + '=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT';
4596
+ if (cookieDomain) {
4597
+ cookie += ';domain=' + cookieDomain;
4593
4598
  }
4594
- document.cookie = name + '=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT';
4599
+ document.cookie = cookie;
4595
4600
  }
4596
4601
  var getPendoCookieKey = function (name, cookieSuffix) {
4597
4602
  return `_pendo_${name}.${cookieSuffix || pendo$1.apiKey}`;
@@ -9750,7 +9755,11 @@ function exportDataHost(pendo) {
9750
9755
  pendo.HOST = HOST;
9751
9756
  }
9752
9757
  function getAssetHost() {
9753
- return ConfigReader.get('assetHost') || getContentHost();
9758
+ var assetHost = ConfigReader.get('assetHost');
9759
+ if (assetHost) {
9760
+ return assetHost.indexOf('://') === -1 ? 'https://' + assetHost : assetHost;
9761
+ }
9762
+ return getContentHost();
9754
9763
  }
9755
9764
  function getContentHost() {
9756
9765
  var protocol = 'https://';
@@ -11752,13 +11761,13 @@ function isTrustedOrigin(host) {
11752
11761
  // Domains that Pendo owns, will be swapped in by build patches
11753
11762
  const patterns = [
11754
11763
  /^https:\/\/(adopt\.)?((us1)\.)?(app|via|adopt|cdn|oem|novus-api|novus)(\.(au|eu|gov|hsbc|jpn))?\.pendo\.io$/,
11755
- /^https:\/\/([0-9]{8}t[0-9]{4}-dot-)pendo-(au|eu|govramp|hsbc|io|jp-prod|us1)\.appspot\.com$/,
11756
- /^https:\/\/hotfix-(ops|app)-([0-9]+-dot-)pendo-(au|eu|govramp|hsbc|io|jp-prod|us1)\.appspot\.com$/,
11757
- /^https:\/\/pendo-(au|eu|govramp|hsbc|io|jp-prod|us1)-static\.storage\.googleapis\.com$/,
11764
+ /^https:\/\/([0-9]{8}t[0-9]{4}-dot-)(pendo-au|pendo-eu|pendo-govramp|pendo-hsbc|pendo-io|pendo-jp-prod|pendo-us1)\.appspot\.com$/,
11765
+ /^https:\/\/hotfix-(ops|app)-([0-9]+-dot-)(pendo-au|pendo-eu|pendo-govramp|pendo-hsbc|pendo-io|pendo-jp-prod|pendo-us1)\.appspot\.com$/,
11766
+ /^https:\/\/(pendo-au|pendo-eu|pendo-govramp|pendo-hsbc|pendo-io|pendo-jp-prod|pendo-us1)-static\.storage\.googleapis\.com$/,
11758
11767
  /^https:\/\/([a-zA-Z0-9-]+\.)*pendo-dev\.com$/,
11759
- /^https:\/\/([a-zA-Z0-9-]+-dot-)?pendo-(apollo|armada|atlas|batman|calypso|dap|dev|dr-us-east1|eu-dev|freeze|helix|link|magic|mango|mcfly|ml|mobile-fbi|mobile-guides|mobile-hummus|mobile-plat|perfserf|voc|wildlings|ionchef|scrum-ops|security|test|uat|au|eu|govramp|hsbc|io|jp-prod|us1)\.appspot\.com$/,
11768
+ /^https:\/\/([a-zA-Z0-9-]+-dot-)?(pendo-apollo|pendo-armada|pendo-atlas|pendo-batman|pendo-calypso|pendo-dap|pendo-dev|pendo-dr-us-east1|pendo-eu-dev|pendo-freeze|pendo-helix|pendo-link|pendo-magic|pendo-mango|pendo-mcfly|pendo-ml|pendo-mobile-fbi|pendo-mobile-guides|pendo-mobile-hummus|pendo-mobile-plat|pendo-perfserf|pendo-voc|pendo-wildlings|pendo-ionchef|pendo-scrum-ops|pendo-security|pendo-test|pendo-uat|pendo-au|pendo-eu|pendo-govramp|pendo-hsbc|pendo-io|pendo-jp-prod|pendo-us1)\.appspot\.com$/,
11760
11769
  /^https:\/\/(via|adopt|local)\.pendo\.(local|io):\d{4}$/,
11761
- /^https:\/\/pendo-(apollo|armada|atlas|batman|calypso|dap|dev|dr-us-east1|eu-dev|freeze|helix|link|magic|mango|mcfly|ml|mobile-fbi|mobile-guides|mobile-hummus|mobile-plat|perfserf|voc|wildlings|ionchef|scrum-ops|security|test|uat)-static\.storage\.googleapis\.com$/
11770
+ /^https:\/\/(pendo-apollo|pendo-armada|pendo-atlas|pendo-batman|pendo-calypso|pendo-dap|pendo-dev|pendo-dr-us-east1|pendo-eu-dev|pendo-freeze|pendo-helix|pendo-link|pendo-magic|pendo-mango|pendo-mcfly|pendo-ml|pendo-mobile-fbi|pendo-mobile-guides|pendo-mobile-hummus|pendo-mobile-plat|pendo-perfserf|pendo-voc|pendo-wildlings|pendo-ionchef|pendo-scrum-ops|pendo-security|pendo-test|pendo-uat)-static\.storage\.googleapis\.com$/
11762
11771
  ]; // eslint-disable-line web-sdk-eslint-rules/no-gulp-env-references
11763
11772
  var adoptHost = ConfigReader.get('adoptHost');
11764
11773
  if (adoptHost) {
@@ -11846,7 +11855,9 @@ var trustedOriginForLoadResource = function (origin) {
11846
11855
  return isTrustedOrigin(origin);
11847
11856
  };
11848
11857
  var parseUrlOrigin = function (url) {
11849
- return new URL(url).origin;
11858
+ // Resolve against the document URL so relative asset urls (used when self-hosting
11859
+ // with an empty asset host) parse to the current page origin instead of throwing.
11860
+ return new URL(url, window.location.href).origin;
11850
11861
  };
11851
11862
  var loadResource = function (options, callback, sendErrorToCallback = false) {
11852
11863
  try {
@@ -24992,7 +25003,10 @@ var initGuides = function (observer) {
24992
25003
  * @access public
24993
25004
  * @label AD_BLOCK_STORAGE_KEY
24994
25005
  */
24995
- agentStorage.registry.addLocal(AD_BLOCK_STORAGE_KEY, { duration: 14400000 }); // 4 hours default duration
25006
+ agentStorage.registry.addLocal(AD_BLOCK_STORAGE_KEY, {
25007
+ duration: 14400000,
25008
+ localStorageOnly: true
25009
+ });
24996
25010
  GuideRuntime.initialize();
24997
25011
  registerPostrenderScripts(GuideRuntime);
24998
25012
  return () => {
@@ -27263,7 +27277,7 @@ function launchDesignerOrPreview(options) {
27263
27277
  * @access public
27264
27278
  * @label pendoPreview
27265
27279
  */
27266
- agentStorage.registry.addLocal(pendoPreview$1);
27280
+ agentStorage.registry.addLocal(pendoPreview$1, { localStorageOnly: true });
27267
27281
  /**
27268
27282
  * Application state while previewing a guide from the designer. Used while designer preview is active
27269
27283
  * to track step, status, etc., and cleared when designer preview is exited.
@@ -27273,7 +27287,7 @@ function launchDesignerOrPreview(options) {
27273
27287
  * @access public
27274
27288
  * @label designerPreview
27275
27289
  */
27276
- agentStorage.registry.addLocal(designerPreview$1);
27290
+ agentStorage.registry.addLocal(designerPreview$1, { localStorageOnly: true });
27277
27291
  // in order, try to launch:
27278
27292
  // 1) designer
27279
27293
  // 2) preview
@@ -30203,7 +30217,10 @@ function initLogging() {
30203
30217
  * @access public
30204
30218
  * @label LOG_ENABLED
30205
30219
  */
30206
- agentStorage.registry.addLocal(LOG_ENABLED, { isPlain: true });
30220
+ agentStorage.registry.addLocal(LOG_ENABLED, {
30221
+ isPlain: true,
30222
+ localStorageOnly: true
30223
+ });
30207
30224
  /**
30208
30225
  * DEPRECATED: Stores the active contexts for logging.
30209
30226
  *
@@ -30212,7 +30229,10 @@ function initLogging() {
30212
30229
  * @access private
30213
30230
  * @label ACTIVE_CONTEXTS
30214
30231
  */
30215
- agentStorage.registry.addLocal(ACTIVE_CONTEXTS, { isPlain: true });
30232
+ agentStorage.registry.addLocal(ACTIVE_CONTEXTS, {
30233
+ isPlain: true,
30234
+ localStorageOnly: true
30235
+ });
30216
30236
  }
30217
30237
  var createContexts = function (contexts, args) {
30218
30238
  return _.compact([].concat(contexts, args));
@@ -30367,10 +30387,8 @@ function track(name, props, eventProperties) {
30367
30387
  collectEventHelper({ type: 'track', name, props, eventProperties });
30368
30388
  }
30369
30389
 
30370
- const privacyFilterCache = new Map();
30371
30390
  /**
30372
30391
  * Method to manually track agentic events. Uses agent functions for IDs and context.
30373
- * Automatically applies privacy filters if agentId is provided and agent configuration exists.
30374
30392
  *
30375
30393
  * @access public
30376
30394
  * @category Events
@@ -30390,64 +30408,8 @@ const privacyFilterCache = new Map();
30390
30408
  * }, { experiment: 'variant_a' })
30391
30409
  */
30392
30410
  function trackAgent(type, props, eventProperties) {
30393
- const filteredTypes = ['prompt', 'agent_response'];
30394
- if (_.contains(filteredTypes, type)) {
30395
- props = applyPrivacyFilters(props);
30396
- }
30397
30411
  collectEventHelper({ type, name: 'agentic', props, eventProperties });
30398
30412
  }
30399
- /**
30400
- * Apply privacy filters to event properties based on agent configuration
30401
- * Optimized for maximum performance with caching
30402
- * @param {Object} props - Event properties to filter
30403
- * @returns {Object} - Filtered properties
30404
- */
30405
- function applyPrivacyFilters(props) {
30406
- if (!(props === null || props === void 0 ? void 0 : props.agentId)) {
30407
- return props;
30408
- }
30409
- try {
30410
- const agents = ConfigReader.get('aiAgents', []);
30411
- const agent = (agents === null || agents === void 0 ? void 0 : agents.find(agent => agent.id === props.agentId)) || null;
30412
- const content = props.content;
30413
- if (!content) {
30414
- return props;
30415
- }
30416
- if (!(agent === null || agent === void 0 ? void 0 : agent.privacyFilters)) {
30417
- return props;
30418
- }
30419
- const privacyFilter = getCachedRegex(agent.privacyFilters);
30420
- if (!privacyFilter) {
30421
- return props;
30422
- }
30423
- const filteredContent = content.replace(privacyFilter, '<redacted>');
30424
- if (filteredContent === content) {
30425
- return props;
30426
- }
30427
- return Object.assign(Object.assign({}, props), { content: filteredContent });
30428
- }
30429
- catch (error) {
30430
- console.error('Error applying privacy filters', error);
30431
- return props;
30432
- }
30433
- }
30434
- /**
30435
- * Get cached regex or compile and cache new one
30436
- */
30437
- function getCachedRegex(filterPattern) {
30438
- let regex = privacyFilterCache.get(filterPattern);
30439
- if (!regex) {
30440
- try {
30441
- regex = new RegExp(filterPattern, 'gmi');
30442
- privacyFilterCache.set(filterPattern, regex);
30443
- }
30444
- catch (e) {
30445
- privacyFilterCache.set(filterPattern, null);
30446
- return null;
30447
- }
30448
- }
30449
- return regex;
30450
- }
30451
30413
 
30452
30414
  /**
30453
30415
  * Checks visitor and account metadata in the current Pendo installation. Either logs to the console
@@ -37640,7 +37602,7 @@ const GuideCachePlugin = {
37640
37602
  if (!capturedEvent || capturedEvent.type !== 'guideSeen') {
37641
37603
  return;
37642
37604
  }
37643
- if (capturedEvent.props.reason !== 'auto') {
37605
+ if (!_.contains(['auto', 'continue'], capturedEvent.props.reason)) {
37644
37606
  return;
37645
37607
  }
37646
37608
  const snap = getSnapshot(capturedEvent.props.guide_id, capturedEvent.props.guide_step_id);
@@ -39466,7 +39428,10 @@ var initLauncherPlugin = function (pendo, PluginAPI) {
39466
39428
  * @access public
39467
39429
  * @label LAUNCHER_CLOSED
39468
39430
  */
39469
- PluginAPI.agentStorage.registry.addLocal(LAUNCHER_CLOSED, { duration: 10 * 24 * 60 * 60 * 1000 }); // 10 days default duration
39431
+ PluginAPI.agentStorage.registry.addLocal(LAUNCHER_CLOSED, {
39432
+ duration: 10 * 24 * 60 * 60 * 1000,
39433
+ localStorageOnly: true
39434
+ });
39470
39435
  };
39471
39436
  var teardownLauncherPlugin = function (pendo, PluginAPI) {
39472
39437
  deregisterLoadGuideJobs(loadLauncherContentHandler);
@@ -40047,7 +40012,7 @@ function SegmentFlags() {
40047
40012
  }
40048
40013
 
40049
40014
  class DOMPrompt {
40050
- constructor(pendo, PluginAPI, id, privacyFilters, inputCssSelectors, submitCssSelectors) {
40015
+ constructor(pendo, PluginAPI, id, inputCssSelectors, submitCssSelectors) {
40051
40016
  this.listeners = [];
40052
40017
  this.latestPromptValue = '';
40053
40018
  this.isActive = true;
@@ -40058,7 +40023,6 @@ class DOMPrompt {
40058
40023
  this.api = PluginAPI;
40059
40024
  this.q = PluginAPI.q;
40060
40025
  this.id = id;
40061
- this.setFilters(privacyFilters);
40062
40026
  if (!this._.isArray(inputCssSelectors)) {
40063
40027
  this.api.log.error('inputCssSelectors must be an array, received:', typeof inputCssSelectors);
40064
40028
  inputCssSelectors = [];
@@ -40161,26 +40125,6 @@ class DOMPrompt {
40161
40125
  const validSubmitEls = this._.filter(this.submitEls, el => el);
40162
40126
  this.promptContainer.addObservers(...validInputEls, ...validSubmitEls);
40163
40127
  }
40164
- setFilters(candidateFilter) {
40165
- if (!candidateFilter) {
40166
- this.privacyFilters = null;
40167
- return null;
40168
- }
40169
- try {
40170
- this.privacyFilters = new RegExp(candidateFilter, 'gmi');
40171
- }
40172
- catch (e) {
40173
- this.privacyFilters = null;
40174
- this.api.log.error(e);
40175
- }
40176
- return this.privacyFilters;
40177
- }
40178
- applyPrivacyFilter(candidateValue, filters = null) {
40179
- const filtersToUse = filters || this.privacyFilters;
40180
- if (!filtersToUse || !this._.isRegExp(filtersToUse))
40181
- return candidateValue;
40182
- return candidateValue.replace(filtersToUse, 'redacted');
40183
- }
40184
40128
  submit(origVal) {
40185
40129
  if (!origVal || !this.isActive) {
40186
40130
  return;
@@ -40191,11 +40135,9 @@ class DOMPrompt {
40191
40135
  return;
40192
40136
  }
40193
40137
  this.lastSubmitTime = now;
40194
- const val = this.applyPrivacyFilter(origVal);
40195
40138
  const payload = {
40196
40139
  agentId: this.id,
40197
- prompt: val,
40198
- privacyFilterApplied: val !== origVal
40140
+ prompt: origVal
40199
40141
  };
40200
40142
  this._.each(this.listeners, (cb) => cb(payload));
40201
40143
  }
@@ -40369,11 +40311,6 @@ class PromptPlugin {
40369
40311
  }
40370
40312
  return this.agentsCache.get(agentId);
40371
40313
  }
40372
- applyPrivacyFilter(candidateValue, filters = null) {
40373
- if (!filters || !this._.isRegExp(filters))
40374
- return candidateValue;
40375
- return candidateValue.replace(filters, 'redacted');
40376
- }
40377
40314
  // conversation agents, owned by the ConversationAnalytics plugin.
40378
40315
  isConversationAgent(agent) {
40379
40316
  return agent.preset && agent.preset != 'chatgpt';
@@ -40424,13 +40361,11 @@ class PromptPlugin {
40424
40361
  return;
40425
40362
  }
40426
40363
  const originalBody = body || '';
40427
- const filteredPrompt = this.applyPrivacyFilter(originalBody, aiAgent.privacyFilters);
40428
40364
  this.api.analytics.collectEvent('prompt', {
40429
- prompt: filteredPrompt,
40365
+ prompt: originalBody,
40430
40366
  agentId: aiAgent.id,
40431
40367
  promptType: method,
40432
- url,
40433
- privacyFilterApplied: filteredPrompt !== originalBody
40368
+ url
40434
40369
  }, undefined, 'agentic');
40435
40370
  });
40436
40371
  }
@@ -40443,7 +40378,7 @@ class PromptPlugin {
40443
40378
  }
40444
40379
  }
40445
40380
  observePrompt(config) {
40446
- const { id, cssSelectors, privacyFilters } = config;
40381
+ const { id, cssSelectors } = config;
40447
40382
  // Check if agent already exists
40448
40383
  const existingPrompt = this._.find(this.prompts, prompt => prompt.id === id);
40449
40384
  if (existingPrompt) {
@@ -40452,7 +40387,7 @@ class PromptPlugin {
40452
40387
  let inputCssSelectors, submitCssSelectors;
40453
40388
  inputCssSelectors = this.parseCssSelector('input', cssSelectors);
40454
40389
  submitCssSelectors = this.parseCssSelector('submit', cssSelectors);
40455
- const prompt = new DOMPrompt(this.pendo, this.api, id, privacyFilters, inputCssSelectors, submitCssSelectors);
40390
+ const prompt = new DOMPrompt(this.pendo, this.api, id, inputCssSelectors, submitCssSelectors);
40456
40391
  prompt.onSubmit((promptPayload) => {
40457
40392
  this.sendPromptEvent(promptPayload);
40458
40393
  });
@@ -41099,7 +41034,12 @@ function initAgent(pendo, PendoConfig) {
41099
41034
  * @access public
41100
41035
  * @label debugEnabled
41101
41036
  */
41102
- agentStorage.registry.addLocal(debugEnabled, { isPlain: true, serializer: JSON.stringify, deserializer: SafeJsonDeserializer });
41037
+ agentStorage.registry.addLocal(debugEnabled, {
41038
+ isPlain: true,
41039
+ serializer: JSON.stringify,
41040
+ deserializer: SafeJsonDeserializer,
41041
+ localStorageOnly: true
41042
+ });
41103
41043
  setPendoConfig(PendoConfig);
41104
41044
  overwriteBuiltConfigWithPendoConfig();
41105
41045
  if (!loadAsModule(PendoConfig) && loadAlternateAgent(PendoConfig, pendo, isDebuggingEnabled()))
@@ -43216,7 +43156,7 @@ function Feedback() {
43216
43156
  * @access public
43217
43157
  * @label notificationCountCookie
43218
43158
  */
43219
- PluginAPI.agentStorage.registry.addLocal(notificationCountCookie);
43159
+ PluginAPI.agentStorage.registry.addLocal(notificationCountCookie, { localStorageOnly: true });
43220
43160
  /**
43221
43161
  * Stores the last ping time for the legacy Feedback widget. Used to control the
43222
43162
  * frequency of communication with the Feedback server.
@@ -43226,7 +43166,10 @@ function Feedback() {
43226
43166
  * @access public
43227
43167
  * @label PING_COOKIE
43228
43168
  */
43229
- PluginAPI.agentStorage.registry.addLocal(PING_COOKIE, { duration: PING_COOKIE_EXPIRATION });
43169
+ PluginAPI.agentStorage.registry.addLocal(PING_COOKIE, {
43170
+ duration: PING_COOKIE_EXPIRATION,
43171
+ localStorageOnly: true
43172
+ });
43230
43173
  return {
43231
43174
  validate
43232
43175
  };
@@ -49381,32 +49324,31 @@ var n;
49381
49324
  }(n || (n = {}));
49382
49325
  return record; }
49383
49326
 
49384
- var SessionRecorderBuffer = /** @class */ (function () {
49385
- function SessionRecorderBuffer(interval, maxCount) {
49386
- if (maxCount === void 0) { maxCount = Infinity; }
49327
+ class SessionRecorderBuffer {
49328
+ constructor(interval, maxCount = Infinity) {
49387
49329
  this.data = [];
49388
49330
  this.sequenceNumber = 0;
49389
49331
  this.interval = interval;
49390
49332
  this.maxCount = maxCount;
49391
49333
  this.doubledMaxCount = maxCount * 2;
49392
49334
  }
49393
- SessionRecorderBuffer.prototype.isEmpty = function () {
49335
+ isEmpty() {
49394
49336
  return this.data.length === 0;
49395
- };
49396
- SessionRecorderBuffer.prototype.count = function () {
49337
+ }
49338
+ count() {
49397
49339
  return this.data.length;
49398
- };
49399
- SessionRecorderBuffer.prototype.clear = function () {
49340
+ }
49341
+ clear() {
49400
49342
  this.data.length = 0;
49401
- };
49402
- SessionRecorderBuffer.prototype.clearSequence = function () {
49343
+ }
49344
+ clearSequence() {
49403
49345
  this.sequenceNumber = 0;
49404
- };
49405
- SessionRecorderBuffer.prototype.push = function (event) {
49346
+ }
49347
+ push(event) {
49406
49348
  this.data.push(event);
49407
49349
  this.checkRateLimit();
49408
- };
49409
- SessionRecorderBuffer.prototype.pack = function (envelope, _) {
49350
+ }
49351
+ pack(envelope, _) {
49410
49352
  var eventsToSend = this.data.splice(0, this.maxCount);
49411
49353
  envelope.recordingPayload = eventsToSend;
49412
49354
  envelope.sequence = this.sequenceNumber;
@@ -49414,8 +49356,8 @@ var SessionRecorderBuffer = /** @class */ (function () {
49414
49356
  if (eventsToSend.length) {
49415
49357
  envelope.browserTime = eventsToSend[0].timestamp;
49416
49358
  }
49417
- envelope.recordingPayloadMetadata = _.map(eventsToSend, function (event) {
49418
- var metadata = _.pick(event, 'type', 'timestamp');
49359
+ envelope.recordingPayloadMetadata = _.map(eventsToSend, event => {
49360
+ const metadata = _.pick(event, 'type', 'timestamp');
49419
49361
  if (event.data) {
49420
49362
  metadata.data = _.pick(event.data, 'source', 'type', 'x', 'y', 'id', 'height', 'width', 'href');
49421
49363
  }
@@ -49423,18 +49365,17 @@ var SessionRecorderBuffer = /** @class */ (function () {
49423
49365
  });
49424
49366
  this.sequenceNumber += eventsToSend.length;
49425
49367
  return envelope;
49426
- };
49427
- SessionRecorderBuffer.prototype.checkRateLimit = function () {
49428
- var length = this.data.length;
49368
+ }
49369
+ checkRateLimit() {
49370
+ const length = this.data.length;
49429
49371
  if (length >= this.doubledMaxCount && length % this.maxCount === 0) {
49430
- var elapsed = this.data[length - 1].timestamp - this.data[length - this.doubledMaxCount].timestamp;
49372
+ const elapsed = this.data[length - 1].timestamp - this.data[length - this.doubledMaxCount].timestamp;
49431
49373
  if (elapsed <= this.interval && this.onRateLimit) {
49432
49374
  this.onRateLimit();
49433
49375
  }
49434
49376
  }
49435
- };
49436
- return SessionRecorderBuffer;
49437
- }());
49377
+ }
49378
+ }
49438
49379
 
49439
49380
  function __rest(s, e) {
49440
49381
  var t = {};
@@ -49458,52 +49399,24 @@ function __awaiter(thisArg, _arguments, P, generator) {
49458
49399
  });
49459
49400
  }
49460
49401
 
49461
- function __generator(thisArg, body) {
49462
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
49463
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
49464
- function verb(n) { return function (v) { return step([n, v]); }; }
49465
- function step(op) {
49466
- if (f) throw new TypeError("Generator is already executing.");
49467
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
49468
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
49469
- if (y = 0, t) op = [op[0] & 2, t.value];
49470
- switch (op[0]) {
49471
- case 0: case 1: t = op; break;
49472
- case 4: _.label++; return { value: op[1], done: false };
49473
- case 5: _.label++; y = op[1]; op = [0]; continue;
49474
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
49475
- default:
49476
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
49477
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
49478
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
49479
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
49480
- if (t[2]) _.ops.pop();
49481
- _.trys.pop(); continue;
49482
- }
49483
- op = body.call(thisArg, _);
49484
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
49485
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
49486
- }
49487
- }
49488
-
49489
49402
  typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
49490
49403
  var e = new Error(message);
49491
49404
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
49492
49405
  };
49493
49406
 
49494
- var RECORDING_CONFIG_WORKERURL$1 = 'recording.workerUrl';
49495
- var MAX_SIZE = 2000000;
49496
- var RESOURCE_CACHING$1 = 'resourceCaching';
49497
- var Transport = /** @class */ (function () {
49498
- function Transport(WorkerClass, pendo, api) {
49407
+ const RECORDING_CONFIG_WORKERURL$1 = 'recording.workerUrl';
49408
+ const MAX_SIZE = 2000000;
49409
+ const RESOURCE_CACHING$1 = 'resourceCaching';
49410
+ class Transport {
49411
+ constructor(WorkerClass, pendo, api) {
49499
49412
  this.WorkerClass = WorkerClass;
49500
49413
  this.pendo = pendo;
49501
49414
  this.api = api;
49502
49415
  this.maxSize = MAX_SIZE;
49503
- this.lockID = "worker-lock-".concat(this.pendo.randomString(16));
49416
+ this.lockID = `worker-lock-${this.pendo.randomString(16)}`;
49504
49417
  this.isResourceCachingEnabled = this.api.ConfigReader.get(RESOURCE_CACHING$1);
49505
49418
  }
49506
- Transport.prototype.start = function (config) {
49419
+ start(config) {
49507
49420
  if (config.disableWorker)
49508
49421
  return;
49509
49422
  if (!this.worker) {
@@ -49513,7 +49426,7 @@ var Transport = /** @class */ (function () {
49513
49426
  this.worker = config.workerOverride;
49514
49427
  }
49515
49428
  else {
49516
- var workerUrl = this.api.ConfigReader.get(RECORDING_CONFIG_WORKERURL$1);
49429
+ const workerUrl = this.api.ConfigReader.get(RECORDING_CONFIG_WORKERURL$1);
49517
49430
  this.usesSelfHostedWorker = workerUrl != null;
49518
49431
  this.worker = workerUrl ? new Worker(workerUrl) : new this.WorkerClass();
49519
49432
  }
@@ -49527,35 +49440,34 @@ var Transport = /** @class */ (function () {
49527
49440
  this.worker = null;
49528
49441
  }
49529
49442
  }
49530
- };
49531
- Transport.prototype.stop = function () {
49443
+ }
49444
+ stop() {
49532
49445
  if (this.worker) {
49533
49446
  this.worker.terminate();
49534
49447
  delete this.worker;
49535
49448
  }
49536
- };
49537
- Transport.prototype.send = function (envelope, isUnload, failureCount) {
49538
- if (failureCount === void 0) { failureCount = 0; }
49539
- var url = envelope.url;
49540
- var payload = envelope.payload;
49449
+ }
49450
+ send(envelope, isUnload, failureCount = 0) {
49451
+ let { url } = envelope;
49452
+ const { payload } = envelope;
49541
49453
  if (failureCount > 0) {
49542
- url = "".concat(url, "&rt=").concat(failureCount);
49454
+ url = `${url}&rt=${failureCount}`;
49543
49455
  }
49544
49456
  if (this.worker && !isUnload && payload) {
49545
- var deferred_1 = {};
49546
- deferred_1.promise = new Promise$2(function (resolve, reject) {
49547
- deferred_1.resolve = resolve;
49548
- deferred_1.reject = reject;
49457
+ const deferred = {};
49458
+ deferred.promise = new Promise$2((resolve, reject) => {
49459
+ deferred.resolve = resolve;
49460
+ deferred.reject = reject;
49549
49461
  });
49550
- this.workerResponse = deferred_1;
49551
- this.worker.postMessage({ url: url, payload: payload, shouldCacheResources: this.isResourceCachingEnabled });
49552
- return deferred_1.promise;
49462
+ this.workerResponse = deferred;
49463
+ this.worker.postMessage({ url, payload, shouldCacheResources: this.isResourceCachingEnabled });
49464
+ return deferred.promise;
49553
49465
  }
49554
49466
  else {
49555
49467
  if (!envelope.body) {
49556
- var strPayload = JSON.stringify(payload);
49468
+ const strPayload = JSON.stringify(payload);
49557
49469
  if (strPayload.length > this.maxSize) {
49558
- var error = new Error('maximum recording payload size exceeded');
49470
+ const error = new Error('maximum recording payload size exceeded');
49559
49471
  error.reason = 'HEAVY_EVENT';
49560
49472
  error.context = {
49561
49473
  size: strPayload.length,
@@ -49566,14 +49478,14 @@ var Transport = /** @class */ (function () {
49566
49478
  envelope.body = this.pendo.compress(strPayload, 'binary');
49567
49479
  delete envelope.payload;
49568
49480
  }
49569
- url = "".concat(url, "&ct=").concat(new Date().getTime());
49481
+ url = `${url}&ct=${new Date().getTime()}`;
49570
49482
  return this.post(url, {
49571
49483
  keepalive: isUnload,
49572
49484
  body: envelope.body
49573
49485
  });
49574
49486
  }
49575
- };
49576
- Transport.prototype.post = function (url, options) {
49487
+ }
49488
+ post(url, options) {
49577
49489
  options.method = 'POST';
49578
49490
  if (options.keepalive && this.api.transmit.fetchKeepalive.supported()) {
49579
49491
  return this.api.transmit.fetchKeepalive(url, options);
@@ -49585,57 +49497,46 @@ var Transport = /** @class */ (function () {
49585
49497
  else {
49586
49498
  return this.pendo.ajax.post(url, options.body);
49587
49499
  }
49588
- };
49589
- Transport.prototype._onMessage = function (messageEvent) {
49590
- return __awaiter(this, void 0, void 0, function () {
49591
- return __generator(this, function (_a) {
49592
- switch (_a.label) {
49593
- case 0:
49594
- if (!(messageEvent.data && messageEvent.data.ready && navigator.locks)) return [3 /*break*/, 2];
49595
- // When the lock is released, we can assume the worker was terminated or closed
49596
- return [4 /*yield*/, navigator.locks.request(this.lockID, function () { })];
49597
- case 1:
49598
- // When the lock is released, we can assume the worker was terminated or closed
49599
- _a.sent();
49600
- this.onWorkerMessage({ type: 'workerDied' });
49601
- _a.label = 2;
49602
- case 2:
49603
- // handle non-POST request responses from worker
49604
- if (messageEvent.data && messageEvent.data.type) {
49605
- this.onWorkerMessage(messageEvent.data);
49606
- return [2 /*return*/];
49607
- }
49608
- // handle POST request response from worker
49609
- if (messageEvent.data && messageEvent.data.error) {
49610
- if ((messageEvent.data.status && messageEvent.data.status < 500) ||
49611
- messageEvent.data.sequence == null) {
49612
- this.api.log.critical('Failed to send recording data from web worker', { error: messageEvent.data.error });
49613
- }
49614
- if (this.workerResponse) {
49615
- this.workerResponse.reject();
49616
- this.workerResponse = null;
49617
- }
49618
- }
49619
- if (this.workerResponse) {
49620
- this.workerResponse.resolve();
49621
- this.workerResponse = null;
49622
- }
49623
- return [2 /*return*/];
49500
+ }
49501
+ _onMessage(messageEvent) {
49502
+ return __awaiter(this, void 0, void 0, function* () {
49503
+ if (messageEvent.data && messageEvent.data.ready && navigator.locks) {
49504
+ // When the lock is released, we can assume the worker was terminated or closed
49505
+ yield navigator.locks.request(this.lockID, () => { });
49506
+ this.onWorkerMessage({ type: 'workerDied' });
49507
+ }
49508
+ // handle non-POST request responses from worker
49509
+ if (messageEvent.data && messageEvent.data.type) {
49510
+ this.onWorkerMessage(messageEvent.data);
49511
+ return;
49512
+ }
49513
+ // handle POST request response from worker
49514
+ if (messageEvent.data && messageEvent.data.error) {
49515
+ if ((messageEvent.data.status && messageEvent.data.status < 500) ||
49516
+ messageEvent.data.sequence == null) {
49517
+ this.api.log.critical('Failed to send recording data from web worker', { error: messageEvent.data.error });
49624
49518
  }
49625
- });
49519
+ if (this.workerResponse) {
49520
+ this.workerResponse.reject();
49521
+ this.workerResponse = null;
49522
+ }
49523
+ }
49524
+ if (this.workerResponse) {
49525
+ this.workerResponse.resolve();
49526
+ this.workerResponse = null;
49527
+ }
49626
49528
  });
49627
- };
49628
- Transport.prototype._onError = function () {
49529
+ }
49530
+ _onError() {
49629
49531
  if (this.onError) {
49630
49532
  this.onError();
49631
49533
  }
49632
- };
49633
- return Transport;
49634
- }());
49534
+ }
49535
+ }
49635
49536
 
49636
- var ELEMENT_NODE = 1;
49637
- var INPUT_MASK = '*'.repeat(10);
49638
- var NUMBER_INPUT_MASK = '0'.repeat(10);
49537
+ const ELEMENT_NODE = 1;
49538
+ const INPUT_MASK = '*'.repeat(10);
49539
+ const NUMBER_INPUT_MASK = '0'.repeat(10);
49639
49540
  function isElementNode(node) {
49640
49541
  if (!node)
49641
49542
  return false;
@@ -49644,12 +49545,10 @@ function isElementNode(node) {
49644
49545
  return true;
49645
49546
  }
49646
49547
  function getParent(elem) {
49647
- var isElementShadowRoot = typeof window.ShadowRoot !== 'undefined' && elem instanceof window.ShadowRoot && elem.host;
49548
+ const isElementShadowRoot = typeof window.ShadowRoot !== 'undefined' && elem instanceof window.ShadowRoot && elem.host;
49648
49549
  return isElementShadowRoot ? elem.host : elem.parentNode;
49649
49550
  }
49650
- function distanceToMatch(node, selector, limit, distance) {
49651
- if (limit === void 0) { limit = Infinity; }
49652
- if (distance === void 0) { distance = 0; }
49551
+ function distanceToMatch(node, selector, limit = Infinity, distance = 0) {
49653
49552
  if (distance > limit)
49654
49553
  return -1;
49655
49554
  if (!node)
@@ -49663,15 +49562,15 @@ function distanceToMatch(node, selector, limit, distance) {
49663
49562
  return distanceToMatch(getParent(node), selector, limit, distance + 1);
49664
49563
  }
49665
49564
  function shouldMask(node, options) {
49666
- var maskAllText = options.maskAllText, maskTextSelector = options.maskTextSelector, unmaskTextSelector = options.unmaskTextSelector;
49565
+ const { maskAllText, maskTextSelector, unmaskTextSelector } = options;
49667
49566
  try {
49668
- var el = isElementNode(node) ? node : node.parentElement;
49567
+ const el = isElementNode(node) ? node : node.parentElement;
49669
49568
  if (el === null)
49670
49569
  return false;
49671
49570
  if ((el.tagName || '').toUpperCase() === 'STYLE')
49672
49571
  return false;
49673
- var maskDistance = -1;
49674
- var unmaskDistance = -1;
49572
+ let maskDistance = -1;
49573
+ let unmaskDistance = -1;
49675
49574
  if (maskAllText) {
49676
49575
  unmaskDistance = distanceToMatch(el, unmaskTextSelector);
49677
49576
  if (unmaskDistance < 0) {
@@ -49704,8 +49603,8 @@ function isNumberInput(element) {
49704
49603
  }
49705
49604
  function shouldMaskInput(element, maskInputOptions) {
49706
49605
  if (maskInputOptions && isElementNode(element)) {
49707
- var tagName = (element.tagName || '').toLowerCase();
49708
- var type = (element.type || '').toLowerCase();
49606
+ const tagName = (element.tagName || '').toLowerCase();
49607
+ const type = (element.type || '').toLowerCase();
49709
49608
  if (maskInputOptions[tagName] || maskInputOptions[type]) {
49710
49609
  return true;
49711
49610
  }
@@ -51199,12 +51098,12 @@ var WorkerFactory = /*#__PURE__*/createInlineWorkerFactory(/* rollup-plugin-web-
51199
51098
  }
51200
51099
  }
51201
51100
 
51202
- var ONE_HUNDRED_MB_IN_BYTES = 100 * 1024 * 1024;
51101
+ const ONE_HUNDRED_MB_IN_BYTES = 100 * 1024 * 1024;
51203
51102
  function matchHostedResources(recordingEvent, stringifiedRecordingPayload) {
51204
- var fontURLRegex = /https:\/\/[^"\\\s]+?\.(woff2?|ttf|otf|eot)(\?[^"\\\s]*)?\b/g;
51205
- var matches = stringifiedRecordingPayload.match(fontURLRegex);
51103
+ const fontURLRegex = /https:\/\/[^"\\\s]+?\.(woff2?|ttf|otf|eot)(\?[^"\\\s]*)?\b/g;
51104
+ const matches = stringifiedRecordingPayload.match(fontURLRegex);
51206
51105
  // de-duplicate matches
51207
- var hostedResources = matches ? Array.from(new Set(matches)) : [];
51106
+ const hostedResources = matches ? Array.from(new Set(matches)) : [];
51208
51107
  return {
51209
51108
  type: 'recording',
51210
51109
  visitorId: recordingEvent.visitorId,
@@ -51219,7 +51118,7 @@ var WorkerFactory = /*#__PURE__*/createInlineWorkerFactory(/* rollup-plugin-web-
51219
51118
  recordingPayloadMetadata: [],
51220
51119
  sequence: 0,
51221
51120
  recordingPayloadCount: 0,
51222
- hostedResources: hostedResources
51121
+ hostedResources
51223
51122
  };
51224
51123
  }
51225
51124
  // keep in mind changes here may need addressing in the extension worker proxy as well
@@ -51227,69 +51126,69 @@ var WorkerFactory = /*#__PURE__*/createInlineWorkerFactory(/* rollup-plugin-web-
51227
51126
  try {
51228
51127
  if (e.data.type === 'init' && e.data.lockID) {
51229
51128
  if (navigator.locks) {
51230
- navigator.locks.request(e.data.lockID, function () {
51129
+ navigator.locks.request(e.data.lockID, () => {
51231
51130
  postMessage({ ready: true });
51232
51131
  // This unresolved promise keeps the lock held with the worker until the worker is
51233
51132
  // terminated at which point the lock is released.
51234
- return new Promise$2(function () { });
51133
+ return new Promise$2(() => { });
51235
51134
  });
51236
51135
  }
51237
51136
  return;
51238
51137
  }
51239
51138
  if (e.data.url && e.data.payload) {
51240
- var _a = e.data, url = _a.url, payload = _a.payload, shouldCacheResources = _a.shouldCacheResources;
51139
+ let { url, payload, shouldCacheResources } = e.data;
51241
51140
  if (Object.keys(payload).length === 0) {
51242
51141
  postMessage({
51243
51142
  type: 'emptyPayload'
51244
51143
  });
51245
51144
  }
51246
- var sequence_1 = payload.sequence;
51247
- var stringifiedRecordingPayload = JSON.stringify(payload.recordingPayload);
51145
+ const { sequence } = payload;
51146
+ const stringifiedRecordingPayload = JSON.stringify(payload.recordingPayload);
51248
51147
  // calculate and post back the recording payload size before the payload is compressed
51249
- var recordingPayloadSize = new TextEncoder().encode(stringifiedRecordingPayload).length;
51250
- var exceedsPayloadSizeLimit = recordingPayloadSize >= ONE_HUNDRED_MB_IN_BYTES;
51148
+ const recordingPayloadSize = new TextEncoder().encode(stringifiedRecordingPayload).length;
51149
+ const exceedsPayloadSizeLimit = recordingPayloadSize >= ONE_HUNDRED_MB_IN_BYTES;
51251
51150
  postMessage({
51252
51151
  type: 'recordingPayloadSize',
51253
- recordingPayloadSize: recordingPayloadSize,
51254
- exceedsPayloadSizeLimit: exceedsPayloadSizeLimit
51152
+ recordingPayloadSize,
51153
+ exceedsPayloadSizeLimit
51255
51154
  });
51256
51155
  // don't attempt to send the payload if it exceeds the allowed limit
51257
51156
  if (exceedsPayloadSizeLimit)
51258
51157
  return;
51259
51158
  if (shouldCacheResources) {
51260
- var hostedResourcesEvent = matchHostedResources(payload, stringifiedRecordingPayload);
51159
+ const hostedResourcesEvent = matchHostedResources(payload, stringifiedRecordingPayload);
51261
51160
  if (hostedResourcesEvent.hostedResources.length) {
51262
51161
  postMessage({
51263
51162
  type: 'hostedResources',
51264
- hostedResourcesEvent: hostedResourcesEvent
51163
+ hostedResourcesEvent
51265
51164
  });
51266
51165
  }
51267
51166
  }
51268
51167
  payload.recordingSize = recordingPayloadSize;
51269
- var body = compress(payload, 'binary');
51168
+ const body = compress(payload, 'binary');
51270
51169
  // we want to calculate ct (current time) as close as we can to the actual POST request
51271
51170
  // so that it's as accurate as possible
51272
- url = "".concat(url, "&ct=").concat(new Date().getTime());
51171
+ url = `${url}&ct=${new Date().getTime()}`;
51273
51172
  fetch(url, {
51274
51173
  method: 'POST',
51275
- body: body
51174
+ body
51276
51175
  }).then(function (response) {
51277
51176
  if (response.status < 200 || response.status >= 300) {
51278
51177
  postMessage({
51279
- error: new Error("received status code ".concat(response.status, ": ").concat(response.statusText)),
51178
+ error: new Error(`received status code ${response.status}: ${response.statusText}`),
51280
51179
  status: response.status,
51281
- sequence: sequence_1
51180
+ sequence
51282
51181
  });
51283
51182
  }
51284
51183
  else {
51285
51184
  postMessage({
51286
- sequence: sequence_1
51185
+ sequence
51287
51186
  });
51288
51187
  }
51289
- })["catch"](function (e) {
51188
+ }).catch(function (e) {
51290
51189
  postMessage({
51291
51190
  error: e,
51292
- sequence: sequence_1
51191
+ sequence
51293
51192
  });
51294
51193
  });
51295
51194
  }
@@ -53055,6 +52954,7 @@ const PredictGuides = () => {
53055
52954
  const ASSISTANT_MESSAGE = 'assistantMessage';
53056
52955
  const CONVERSATION_ID_URL_PATTERN = 'conversationIdUrlPattern';
53057
52956
  const MESSAGE_ID_ATTR = 'messageIdAttr';
52957
+ const MESSAGE_ID_PATTERN = 'messageIdPattern';
53058
52958
  const MODEL_USED_ATTR = 'modelUsedAttr';
53059
52959
  const REACTION_ACTIVE = 'reactionActive';
53060
52960
  const STREAMING_ACTIVE = 'streamingActive';
@@ -53062,7 +52962,6 @@ const STREAMING_ACTIVE_ATTR = 'streamingActiveAttr';
53062
52962
  const THUMB_DOWN = 'thumbDown';
53063
52963
  const THUMB_UP = 'thumbUp';
53064
52964
  const TURN_CONTAINER = 'turnContainer';
53065
- const TURN_ATTR = 'turnAttr';
53066
52965
  const USER_MESSAGE = 'userMessage';
53067
52966
  const CUSTOM_AGENT_ID_URL_PATTERN = 'customAgentIdUrlPattern';
53068
52967
  const CUSTOM_AGENT_NAME = 'customAgentName';
@@ -53072,9 +52971,9 @@ const REQUIRED_SELECTORS = [
53072
52971
  MESSAGE_ID_ATTR,
53073
52972
  STREAMING_ACTIVE,
53074
52973
  TURN_CONTAINER,
53075
- TURN_ATTR,
53076
52974
  USER_MESSAGE
53077
52975
  ];
52976
+ const SUPPORTED_PRESETS = ['chatgpt-full', 'gemini-full'];
53078
52977
  const STREAMING_END_SETTLE_MS = 500;
53079
52978
  const SUBMISSION_START_RETRY_MS = 1000;
53080
52979
  const SUBMISSION_START_MAX_ATTEMPTS = 4;
@@ -53103,9 +53002,9 @@ class DOMConversation {
53103
53002
  return REQUIRED_SELECTORS.filter((r) => !present.has(r));
53104
53003
  }
53105
53004
  static supportedPreset(preset) {
53106
- return preset === 'chatgpt-full';
53005
+ return SUPPORTED_PRESETS.indexOf(preset) !== -1;
53107
53006
  }
53108
- constructor(pendo, PluginAPI, id, privacyFilters, cssSelectors) {
53007
+ constructor(pendo, PluginAPI, id, cssSelectors) {
53109
53008
  this.selectors = {};
53110
53009
  this.listeners = [];
53111
53010
  this.isActive = true;
@@ -53116,13 +53015,13 @@ class DOMConversation {
53116
53015
  this.requestNode = null;
53117
53016
  this.conversationIdRegex = null;
53118
53017
  this.customAgentIdRegex = null;
53018
+ this.messageIdRegex = null;
53119
53019
  this.lastReturnedMessageId = null;
53120
53020
  this.dom = pendo.dom;
53121
53021
  this._ = pendo._;
53122
53022
  this.api = PluginAPI;
53123
53023
  this.Sizzle = pendo.Sizzle;
53124
53024
  this.id = id;
53125
- this.setFilters(privacyFilters);
53126
53025
  if (!this._.isArray(cssSelectors)) {
53127
53026
  this.api.log.error(`cssSelectors must be an array, received: ${typeof cssSelectors}`);
53128
53027
  cssSelectors = [];
@@ -53142,6 +53041,15 @@ class DOMConversation {
53142
53041
  this.api.log.error(`bad customAgentIdUrlPattern ${customAgentIdUrlPattern}`, { error });
53143
53042
  }
53144
53043
  }
53044
+ const messageIdPattern = this.selectors[MESSAGE_ID_PATTERN];
53045
+ if (messageIdPattern) { // optional: gates the request node until its id is fully rendered
53046
+ try {
53047
+ this.messageIdRegex = new RegExp(messageIdPattern);
53048
+ }
53049
+ catch (error) {
53050
+ this.api.log.error(`bad messageIdPattern ${messageIdPattern}`, { error });
53051
+ }
53052
+ }
53145
53053
  this.root = document.body;
53146
53054
  this.setupReactionListener();
53147
53055
  this.setupStreamingObserver();
@@ -53171,8 +53079,7 @@ class DOMConversation {
53171
53079
  this.emit('user_reaction', {
53172
53080
  agentId: this.id,
53173
53081
  messageId: this.getMessageId(assistantNode),
53174
- content,
53175
- privacyFilterApplied: false
53082
+ content
53176
53083
  });
53177
53084
  }
53178
53085
  // observe the streaming indicator
@@ -53241,28 +53148,22 @@ class DOMConversation {
53241
53148
  return;
53242
53149
  this.handleUserMessage(requestNode);
53243
53150
  }
53244
- const requestTurn = this.findTurnNumber(requestNode);
53245
- if (requestTurn === null)
53151
+ const requestEl = requestNode[0];
53152
+ if (!requestEl)
53246
53153
  return;
53154
+ // the request is the latest user message, so any assistant message that
53155
+ // follows it in the DOM is a response to it. document order is already
53156
+ // chronological, so we emit as we go
53247
53157
  const assistantNodes = this.select(ASSISTANT_MESSAGE);
53248
- const toEmit = [];
53249
- for (let i = assistantNodes.length - 1; i >= 0; i--) {
53250
- const n = this.findTurnNumber(this.dom(assistantNodes[i]));
53251
- if (n === null)
53252
- continue;
53253
- if (n <= requestTurn)
53254
- break;
53255
- toEmit.push(assistantNodes[i]);
53256
- }
53257
- // emit in chronological order (reverse of collection order)
53258
- for (let i = toEmit.length - 1; i >= 0; i--) {
53259
- this.handleAssistantMessage(this.dom(toEmit[i]));
53158
+ for (let i = 0; i < assistantNodes.length; i++) {
53159
+ const el = assistantNodes[i];
53160
+ if (requestEl.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING) {
53161
+ this.handleAssistantMessage(this.dom(el));
53162
+ }
53260
53163
  }
53261
53164
  }
53262
53165
  extractContent(node) {
53263
- const rawContent = node.text().trim();
53264
- const content = this.applyPrivacyFilter(rawContent);
53265
- return { content, privacyFilterApplied: content !== rawContent };
53166
+ return { content: node.text().trim() };
53266
53167
  }
53267
53168
  getMessageId(node) {
53268
53169
  return node.attr(this.findSelector(MESSAGE_ID_ATTR));
@@ -53285,20 +53186,16 @@ class DOMConversation {
53285
53186
  const messageId = this.getMessageId($node);
53286
53187
  if (!messageId)
53287
53188
  return null;
53189
+ // the node may still be rendering (e.g. a framework interpolating an
53190
+ // unresolved id); treat it as not-ready so the retry waits for the
53191
+ // finalized node rather than caching a placeholder that gets replaced
53192
+ if (this.messageIdRegex && !this.messageIdRegex.test(messageId))
53193
+ return null;
53288
53194
  if (messageId === this.lastReturnedMessageId)
53289
53195
  return null;
53290
53196
  this.lastReturnedMessageId = messageId;
53291
53197
  return $node;
53292
53198
  }
53293
- findTurnNumber(node) {
53294
- const turnSelector = this.findSelector(TURN_CONTAINER);
53295
- const turnAttr = this.findSelector(TURN_ATTR);
53296
- const turn = node.closest(turnSelector).attr(turnAttr);
53297
- if (!turn)
53298
- return null;
53299
- const seqMatch = String(turn).match(/\d+/);
53300
- return seqMatch ? parseInt(seqMatch[0], 10) : null;
53301
- }
53302
53199
  findSelector(type) {
53303
53200
  return this.selectors[type];
53304
53201
  }
@@ -53337,26 +53234,6 @@ class DOMConversation {
53337
53234
  eventPayload.customAgentName = customAgentName;
53338
53235
  }
53339
53236
  }
53340
- setFilters(candidateFilter) {
53341
- if (!candidateFilter) {
53342
- this.privacyFilters = null;
53343
- return null;
53344
- }
53345
- try {
53346
- this.privacyFilters = new RegExp(candidateFilter, 'gmi');
53347
- }
53348
- catch (e) {
53349
- this.privacyFilters = null;
53350
- this.api.log.error(e);
53351
- }
53352
- return this.privacyFilters;
53353
- }
53354
- applyPrivacyFilter(candidateValue, filters = null) {
53355
- const filtersToUse = filters || this.privacyFilters;
53356
- if (!filtersToUse || !this._.isRegExp(filtersToUse))
53357
- return candidateValue;
53358
- return candidateValue.replace(filtersToUse, 'redacted');
53359
- }
53360
53237
  onSubmit(callback) {
53361
53238
  this.listeners.push(callback);
53362
53239
  }
@@ -53517,7 +53394,7 @@ function ConversationAnalytics() {
53517
53394
  });
53518
53395
  }
53519
53396
  function observeConversation(config) {
53520
- const { id, cssSelectors, privacyFilters } = config;
53397
+ const { id, cssSelectors } = config;
53521
53398
  // Check if this agent is already being tracked
53522
53399
  const existing = _.find(conversations, conversation => conversation.id === id);
53523
53400
  if (existing) {
@@ -53528,7 +53405,7 @@ function ConversationAnalytics() {
53528
53405
  log.error('aiAgent config missing required selectors', { agentId: id, missing });
53529
53406
  return;
53530
53407
  }
53531
- const conversation = new DOMConversation(pendo, api, id, privacyFilters, cssSelectors);
53408
+ const conversation = new DOMConversation(pendo, api, id, cssSelectors);
53532
53409
  conversation.onSubmit(sendConversationEvent);
53533
53410
  conversations.push(conversation);
53534
53411
  }