@pendo/agent 2.291.4 → 2.292.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.
@@ -463,6 +463,9 @@ function shouldUseUnminifiedAgent(config, debuggingEnabled) {
463
463
  return !isExtension(config) && isMinifiedAgent(config) && debuggingEnabled;
464
464
  }
465
465
  function findAgentScriptTag(scripts = [], apiKey) {
466
+ if (document.currentScript) {
467
+ return document.currentScript;
468
+ }
466
469
  const regex = /^https:\/\/[\w\-.]*cdn[\w\-.]*\.(pendo-dev\.com|pendo\.io)\/agent\/static\/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}|PENDO_API_KEY)\/pendo\.js$/g;
467
470
  for (let i = 0; i < scripts.length; i++) {
468
471
  const script = scripts[i];
@@ -3687,6 +3690,10 @@ function globalBucket(env) {
3687
3690
  }
3688
3691
 
3689
3692
  function isNativeCode(fn) { return /native/.test(fn); }
3693
+ const detectNativeBrowserAPI = (name) => {
3694
+ const fn = _.get(window, name);
3695
+ return (fn && isNativeCode(fn));
3696
+ };
3690
3697
 
3691
3698
  var isOldIE = function (olderThan, tVersion) {
3692
3699
  olderThan = olderThan || 10;
@@ -3904,8 +3911,8 @@ var SERVER = '';
3904
3911
  var ASSET_HOST = '';
3905
3912
  var ASSET_PATH = '';
3906
3913
  var DESIGNER_SERVER = '';
3907
- var VERSION = '2.291.4_';
3908
- var PACKAGE_VERSION = '2.291.4';
3914
+ var VERSION = '2.292.1_';
3915
+ var PACKAGE_VERSION = '2.292.1';
3909
3916
  var LOADER = 'xhr';
3910
3917
  /* eslint-enable agent-eslint-rules/no-gulp-env-references */
3911
3918
  /**
@@ -12184,6 +12191,92 @@ class LocalStorageEventBuffer {
12184
12191
  }
12185
12192
  var localStorageEventBuffer = new LocalStorageEventBuffer();
12186
12193
 
12194
+ class PerformanceMonitor {
12195
+ constructor() {
12196
+ this._isPerformanceApiAvailable = this._checkPerformanceApi();
12197
+ this._measuringPerformance = false;
12198
+ this._marks = {};
12199
+ this._measures = {};
12200
+ }
12201
+ initialize() {
12202
+ this._measuringPerformance = true;
12203
+ this._markPerformance('initialize');
12204
+ // temporary clear interval while working on send implementation
12205
+ this.interval = setInterval(() => {
12206
+ this._clearMarksAndMeasures();
12207
+ }, 1000 * 60 * 10);
12208
+ return () => {
12209
+ this.teardown();
12210
+ };
12211
+ }
12212
+ teardown() {
12213
+ this._measuringPerformance = false;
12214
+ this._markPerformance('teardown');
12215
+ this._clearMarksAndMeasures();
12216
+ clearInterval(this.interval);
12217
+ }
12218
+ startTimer(name) {
12219
+ this._markPerformance(`${name}-start`);
12220
+ }
12221
+ stopTimer(name) {
12222
+ this._markPerformance(`${name}-stop`);
12223
+ this._measurePerformance(name);
12224
+ }
12225
+ track(name) {
12226
+ this._markPerformance(name);
12227
+ }
12228
+ send() {
12229
+ performance.getEntries();
12230
+ // TODO: implement filter/send process
12231
+ this._clearMarksAndMeasures();
12232
+ }
12233
+ _checkPerformanceApi() {
12234
+ return detectNativeBrowserAPI('performance.mark') &&
12235
+ detectNativeBrowserAPI('performance.measure') &&
12236
+ detectNativeBrowserAPI('performance.getEntries') &&
12237
+ detectNativeBrowserAPI('performance.clearMarks') &&
12238
+ detectNativeBrowserAPI('performance.clearMeasures');
12239
+ }
12240
+ _shouldMeasurePerformance() {
12241
+ return this._isPerformanceApiAvailable && this._measuringPerformance;
12242
+ }
12243
+ _markPerformance(name) {
12244
+ if (!this._shouldMeasurePerformance())
12245
+ return;
12246
+ name = `pendo-${name}`;
12247
+ performance.mark(name);
12248
+ this._count(this._marks, name);
12249
+ }
12250
+ _measurePerformance(name) {
12251
+ if (!this._shouldMeasurePerformance())
12252
+ return;
12253
+ name = `pendo-${name}`;
12254
+ const startMark = `${name}-start`;
12255
+ const stopMark = `${name}-stop`;
12256
+ performance.measure(name, startMark, stopMark);
12257
+ this._count(this._measures, name);
12258
+ }
12259
+ _count(registry, name) {
12260
+ if (!registry[name]) {
12261
+ registry[name] = 1;
12262
+ }
12263
+ else {
12264
+ registry[name]++;
12265
+ }
12266
+ }
12267
+ _clearMarksAndMeasures() {
12268
+ _.each(this._marks, (count, name) => {
12269
+ performance.clearMarks(name);
12270
+ });
12271
+ _.each(this._measures, (count, name) => {
12272
+ performance.clearMeasures(name);
12273
+ });
12274
+ this._marks = {};
12275
+ this._measures = {};
12276
+ }
12277
+ }
12278
+ var PerformanceMonitor$1 = new PerformanceMonitor();
12279
+
12187
12280
  var defaultTrackName = '_PENDO_UNNAMED_';
12188
12281
  var SILO_AVG_COMPRESSION_RATIO = 5;
12189
12282
  /**
@@ -12245,21 +12338,7 @@ function collectEvent(type, props, url, name, eventProperties, context) {
12245
12338
  agenticEventQueue.push(event);
12246
12339
  return;
12247
12340
  }
12248
- eventQueue.push(attachMonitoringData(store, event));
12249
- }
12250
- function attachMonitoringData(store, event) {
12251
- try {
12252
- if (!store.getters['monitoring/shouldFlush']())
12253
- return event;
12254
- var payload = store.getters['monitoring/payload']();
12255
- store.dispatch('monitoring/flush');
12256
- if (!_.isEmpty(payload)) {
12257
- event.ops = payload;
12258
- }
12259
- }
12260
- catch (e) {
12261
- }
12262
- return event;
12341
+ eventQueue.push(event);
12263
12342
  }
12264
12343
  // @const {Event.type[]}
12265
12344
  var WHITELIST_FREE_NPS = ['load', 'meta', 'identify'];
@@ -12698,7 +12777,7 @@ function createSendQueue(options, send, guaranteedSend) {
12698
12777
  }
12699
12778
  });
12700
12779
  queue.onTimeout = function () {
12701
- store.commit('monitoring/incrementCounter', options.beacon + 'GifFailures');
12780
+ PerformanceMonitor$1.track(`${options.beacon}-gif-failure`);
12702
12781
  };
12703
12782
  queue.retryPending = true;
12704
12783
  return queue;
@@ -12990,7 +13069,7 @@ var handleEmbeddedData = function (src) {
12990
13069
  return src + '';
12991
13070
  };
12992
13071
  function getAttributeValue(element, attrName) {
12993
- return element.getAttribute ? element.getAttribute(attrName) : element[attrName];
13072
+ return store.getters['nodeAttr/getAttribute']()(element, attrName);
12994
13073
  }
12995
13074
  var extractAttribute = function (element, attrName, type) {
12996
13075
  if (!element || !element.nodeName)
@@ -21042,10 +21121,6 @@ class UpdateRunner {
21042
21121
  }
21043
21122
  }
21044
21123
  complete(time) {
21045
- store.commit('monitoring/setTimer', {
21046
- name: 'guideUpdateTimeMS',
21047
- time: this.updateTotalTime
21048
- });
21049
21124
  store.commit('guideUpdate/completeUpdate', time);
21050
21125
  this.cancel();
21051
21126
  }
@@ -26533,6 +26608,11 @@ var EventRouter = function () {
26533
26608
  var config = configParam.value;
26534
26609
  var cases = casesParam.value;
26535
26610
  var conditionResult = evaluateCondition(conditionType, config);
26611
+ Events.trigger('appUsage', {
26612
+ type: 'conditionalSplitResult',
26613
+ elementId: evt.srcElement.id,
26614
+ conditionResult
26615
+ });
26536
26616
  var matchingCase = _.find(cases, function (caseItem) {
26537
26617
  return caseItem.value === conditionResult;
26538
26618
  });
@@ -26600,16 +26680,27 @@ var GuideActivity = (function () {
26600
26680
  var isObject = _.isObject;
26601
26681
  var findWhere = _.findWhere;
26602
26682
  const _guideResolvers = [];
26683
+ var conditionalSplitEventQueue = [];
26603
26684
  return {
26604
26685
  type: GA_TYPE,
26605
26686
  handler(evtData) {
26606
26687
  var appData = evtData.data[0];
26688
+ if (appData && appData.type === 'conditionalSplitResult') {
26689
+ finalizeConditionalSplitEvent(appData);
26690
+ return;
26691
+ }
26607
26692
  var browserEvt = evtData.data[1];
26608
26693
  if (!shouldHandleEvent(appData, browserEvt))
26609
26694
  return;
26610
26695
  var activityEvent = transformToGuideActivity(appData);
26611
26696
  if (activityEvent) {
26612
- stageGuideEvent(activityEvent);
26697
+ const firstAction = _.get(activityEvent, ['props', 'ui_element_actions', 0, 'action']);
26698
+ if (firstAction === 'conditionalSplit') {
26699
+ conditionalSplitEventQueue.push(activityEvent);
26700
+ }
26701
+ else {
26702
+ stageGuideEvent(activityEvent);
26703
+ }
26613
26704
  }
26614
26705
  },
26615
26706
  registerGuideResolver(callBack) {
@@ -26622,6 +26713,22 @@ var GuideActivity = (function () {
26622
26713
  }
26623
26714
  }
26624
26715
  };
26716
+ function finalizeConditionalSplitEvent(evtData) {
26717
+ const { conditionResult, elementId } = evtData;
26718
+ const matchingEventIndex = _.findIndex(conditionalSplitEventQueue, (event) => {
26719
+ return event.props.ui_element_id === elementId;
26720
+ });
26721
+ if (matchingEventIndex === -1)
26722
+ return;
26723
+ const matchingEvent = conditionalSplitEventQueue.splice(matchingEventIndex, 1)[0];
26724
+ const conditionalSplitAction = matchingEvent.props.ui_element_actions[0];
26725
+ conditionalSplitAction.condition_result = conditionResult;
26726
+ const cases = conditionalSplitAction.cases;
26727
+ const resultCase = cases[conditionResult];
26728
+ matchingEvent.props.ui_element_actions = matchingEvent.props.ui_element_actions.concat(resultCase);
26729
+ delete conditionalSplitAction.cases;
26730
+ stageGuideEvent(matchingEvent);
26731
+ }
26625
26732
  function isClickEvent(browserEvt) {
26626
26733
  return browserEvt && browserEvt.type === 'click';
26627
26734
  }
@@ -26738,58 +26845,7 @@ var GuideActivity = (function () {
26738
26845
  ];
26739
26846
  }
26740
26847
  if (element.actions !== undefined) {
26741
- return _.map(element.actions, function (action) {
26742
- switch (action.action) {
26743
- case 'automation':
26744
- var automationIds = findWhere(action.parameters, { name: 'automationIds' });
26745
- return {
26746
- action: action.action,
26747
- automationIds
26748
- };
26749
- case 'openLink':
26750
- var url = findWhere(action.parameters, { name: 'url' });
26751
- var target = findWhere(action.parameters, { name: 'target' });
26752
- return {
26753
- action: action.action,
26754
- url: sanitizeUrl(url.value),
26755
- target: target.value
26756
- };
26757
- case 'submitPollAndGoToStep':
26758
- case 'goToStep':
26759
- var guideStepId = findWhere(action.parameters, { name: 'goToStepId' });
26760
- return {
26761
- action: action.action,
26762
- guideStepId: guideStepId.value
26763
- };
26764
- case 'guideSnoozed':
26765
- var duration = findWhere(action.parameters, { name: 'snooze_duration' });
26766
- var timeUnit = findWhere(action.parameters, { name: 'time_unit' });
26767
- return {
26768
- action: action.action,
26769
- duration: duration.value,
26770
- timeUnit: timeUnit.value
26771
- };
26772
- case 'showGuide':
26773
- case 'launchGuide':
26774
- var guideId = action.parameters[0];
26775
- var stepId = action.parameters[1] || {};
26776
- return {
26777
- action: action.action,
26778
- guideId: guideId.value,
26779
- stepId: stepId.value
26780
- };
26781
- case 'advanceGuide':
26782
- case 'previousStep':
26783
- case 'submitPoll':
26784
- case 'dismissGuide':
26785
- case 'confirmation':
26786
- return {
26787
- action: action.action
26788
- };
26789
- default:
26790
- return {};
26791
- }
26792
- });
26848
+ return _.map(element.actions, processAction);
26793
26849
  }
26794
26850
  if (uiElement.templateName === 'pendo_task_list_item') {
26795
26851
  if (_.isArray(element.templateChildren) && element.templateChildren[uiElement.templateChildIndex]) {
@@ -26801,6 +26857,79 @@ var GuideActivity = (function () {
26801
26857
  }
26802
26858
  return [];
26803
26859
  }
26860
+ function processAction(action) {
26861
+ switch (action.action) {
26862
+ case 'automation':
26863
+ var automationIds = findWhere(action.parameters, { name: 'automationIds' });
26864
+ return {
26865
+ action: action.action,
26866
+ automationIds
26867
+ };
26868
+ case 'openLink':
26869
+ var url = findWhere(action.parameters, { name: 'url' });
26870
+ var target = findWhere(action.parameters, { name: 'target' });
26871
+ return {
26872
+ action: action.action,
26873
+ url: sanitizeUrl(url.value),
26874
+ target: target.value
26875
+ };
26876
+ case 'submitPollAndGoToStep':
26877
+ case 'goToStep':
26878
+ var guideStepId = findWhere(action.parameters, { name: 'goToStepId' });
26879
+ return {
26880
+ action: action.action,
26881
+ guideStepId: guideStepId.value
26882
+ };
26883
+ case 'guideSnoozed':
26884
+ var duration = findWhere(action.parameters, { name: 'snooze_duration' });
26885
+ var timeUnit = findWhere(action.parameters, { name: 'time_unit' });
26886
+ return {
26887
+ action: action.action,
26888
+ duration: duration.value,
26889
+ timeUnit: timeUnit.value
26890
+ };
26891
+ case 'showGuide':
26892
+ case 'launchGuide':
26893
+ var guideId = action.parameters[0];
26894
+ var stepId = action.parameters[1] || {};
26895
+ return {
26896
+ action: action.action,
26897
+ guideId: guideId.value,
26898
+ stepId: stepId.value
26899
+ };
26900
+ case 'conditionalSplit':
26901
+ var name = findWhere(action.parameters, { name: 'name' });
26902
+ var conditionType = findWhere(action.parameters, { name: 'conditionType' });
26903
+ var config = findWhere(action.parameters, { name: 'config' });
26904
+ var cases = findWhere(action.parameters, { name: 'cases' });
26905
+ var processedCases = _.reduce(cases.value, function (acc, c) {
26906
+ acc[c.value] = _.map(c.actions, function (a) {
26907
+ var processedAction = processAction(a);
26908
+ processedAction.source = a.source;
26909
+ return processedAction;
26910
+ });
26911
+ return acc;
26912
+ }, {});
26913
+ return {
26914
+ action: action.action,
26915
+ name: name.value,
26916
+ condition_type: conditionType.value,
26917
+ element_selector: config.value.elementSelector,
26918
+ feature_id: config.value.featureId,
26919
+ cases: processedCases // will be removed in finalizeConditionalSplitEvent
26920
+ };
26921
+ case 'advanceGuide':
26922
+ case 'previousStep':
26923
+ case 'submitPoll':
26924
+ case 'dismissGuide':
26925
+ case 'confirmation':
26926
+ return {
26927
+ action: action.action
26928
+ };
26929
+ default:
26930
+ return {};
26931
+ }
26932
+ }
26804
26933
  function transformToGuideActivity(appData) {
26805
26934
  var activeGuideObj = getGuideForEvent(appData);
26806
26935
  if (!activeGuideObj)
@@ -26999,14 +27128,14 @@ var didAccountIdentityChange = function (props) {
26999
27128
  function initIdentityEvents() {
27000
27129
  if (initialized)
27001
27130
  return;
27002
- Events.identify.on(function (event) {
27131
+ const collectIdentifyEvent = function (event) {
27003
27132
  var props = event.data[0];
27004
27133
  if (wasAnonymousVisitorIdentified(props) || didAccountIdentityChange(props)) {
27005
27134
  collectEvent('identify', props);
27006
27135
  flushLater(); // unconditionally on next tick
27007
27136
  }
27008
- });
27009
- Events.metadata.on(function (event) {
27137
+ };
27138
+ const collectMetadataEvent = function (event) {
27010
27139
  // Check to see if this Application is sending metadata to the backend using
27011
27140
  // different mechanism (like Segment webhooks)
27012
27141
  var blockAgentMetadata = isMetadataBlocked();
@@ -27017,9 +27146,17 @@ function initIdentityEvents() {
27017
27146
  flushLater(); // unconditionally on next tick
27018
27147
  }
27019
27148
  }
27020
- });
27149
+ };
27150
+ Events.identify.on(collectIdentifyEvent);
27151
+ Events.metadata.on(collectMetadataEvent);
27021
27152
  Events.identify.on(handleIdentifyEvent);
27022
27153
  initialized = true;
27154
+ return function () {
27155
+ Events.identify.off(collectIdentifyEvent);
27156
+ Events.metadata.off(collectMetadataEvent);
27157
+ Events.identify.off(handleIdentifyEvent);
27158
+ initialized = false;
27159
+ };
27023
27160
  }
27024
27161
 
27025
27162
  /*
@@ -27230,7 +27367,7 @@ class ShadowDomManager extends EventTarget {
27230
27367
  }
27231
27368
  initialize() {
27232
27369
  this.unpatchAttachShadow = this.patchAttachShadow(Element);
27233
- this.findShadowRoots(document);
27370
+ this.findShadowRoots(document, 5000, (shadowRoot) => this.triggerAttachShadow(shadowRoot));
27234
27371
  }
27235
27372
  triggerAttachShadow(shadowRoot) {
27236
27373
  this.cache.add(shadowRoot);
@@ -27239,7 +27376,7 @@ class ShadowDomManager extends EventTarget {
27239
27376
  shadowRoot
27240
27377
  });
27241
27378
  }
27242
- findShadowRoots(document, maxPerSearch = 5000) {
27379
+ findShadowRoots(document, maxPerSearch = 5000, onShadowRootFound) {
27243
27380
  if (!_.isFunction(document.createNodeIterator))
27244
27381
  return;
27245
27382
  let nodesChecked = 0;
@@ -27255,7 +27392,7 @@ class ShadowDomManager extends EventTarget {
27255
27392
  while ((currentNode = iterator.nextNode())) {
27256
27393
  nodesChecked++;
27257
27394
  if (currentNode && currentNode.shadowRoot) {
27258
- this.triggerAttachShadow(currentNode.shadowRoot);
27395
+ onShadowRootFound(currentNode.shadowRoot);
27259
27396
  queue.push(currentNode.shadowRoot);
27260
27397
  this.foundShadowRoots = true;
27261
27398
  }
@@ -27376,7 +27513,8 @@ function registerEventHandlers({ events = [] }) {
27376
27513
  let initializeCounter = 0;
27377
27514
  const initializeImmediately = 'initializeImmediately';
27378
27515
  /**
27379
- * Initializes the Pendo Agent in a browser window.
27516
+ * Initializes the Pendo agent in a browser window. This function only needs to be called once per page load. Any subsequent calls, without first having called `teardown`, will be ignored.
27517
+ * Once the agent has been initialized, any updates to identity or metadata should be done using `identify` or `updateOptions`.
27380
27518
  *
27381
27519
  * @access public
27382
27520
  * @function
@@ -27522,13 +27660,14 @@ const initialize = makeSafe(function (options) {
27522
27660
  teardownFns.push(forwardInternalEvents(Events));
27523
27661
  registerEventHandlers(options);
27524
27662
  teardownFns.push(initGuides(observer)); // this is safe. loadGuides actually does the loading.
27525
- initIdentityEvents(); // setup identify and meta event listeners
27663
+ teardownFns.push(initIdentityEvents()); // setup identify and meta event listeners
27526
27664
  teardownFns.push(wirePage());
27527
27665
  teardownFns.push(initializePlugins());
27528
27666
  teardownFns.push(launchDesignerOrPreview(options));
27529
27667
  Events.appUsage.on(GuideActivity.handler);
27530
27668
  Events.appUsage.on(ResourceCenterActivity.handler);
27531
27669
  teardownFns.push(flushEvery(SEND_INTERVAL));
27670
+ teardownFns.push(PerformanceMonitor$1.initialize());
27532
27671
  }
27533
27672
  Events.appHidden.on(() => {
27534
27673
  flushNow(true, { hidden: true });
@@ -29021,11 +29160,14 @@ var attrActionEnum = {
29021
29160
  href: ['Replace', 'ForceSecure'],
29022
29161
  protocol: ['ForceSecure']
29023
29162
  };
29024
- function UrlAttrTransform(attr, action, data) {
29163
+ const TARGETS = ['location', 'attribute', 'both'];
29164
+ const DEFAULT_TARGET = 'location';
29165
+ function UrlTransform(attr, action, data, target) {
29025
29166
  if (_.isObject(attr)) {
29026
29167
  action = attr.action;
29027
29168
  data = attr.data;
29028
29169
  attr = attr.attr;
29170
+ target = attr.target;
29029
29171
  }
29030
29172
  if (!attrActionEnum[attr]) {
29031
29173
  var validAttrs = _.keys(attrActionEnum).join(', ');
@@ -29035,11 +29177,16 @@ function UrlAttrTransform(attr, action, data) {
29035
29177
  var validActions = attrActionEnum[attr].join(', ');
29036
29178
  throw new Error('Invalid transform action: "' + action + '" for attribute "' + attr + '". Valid actions for "' + attr + '" are: ' + validActions + '. Example: {attr: "' + attr + '", action: "' + attrActionEnum[attr][0] + '", data: ...}');
29037
29179
  }
29180
+ // validate 'target'
29181
+ if (TARGETS.indexOf(target) < 0) {
29182
+ target = DEFAULT_TARGET;
29183
+ }
29038
29184
  this.attr = attr;
29039
29185
  this.action = action;
29040
29186
  this.data = data;
29187
+ this.target = target || DEFAULT_TARGET;
29041
29188
  }
29042
- UrlAttrTransform.prototype.applyToURL = function (url) {
29189
+ UrlTransform.prototype.applyTo = function (url) {
29043
29190
  var actionImpls = {
29044
29191
  AllowOnlyKeys(url, attr, data) {
29045
29192
  if (_.isFunction(data)) {
@@ -29112,26 +29259,26 @@ UrlAttrTransform.prototype.applyToURL = function (url) {
29112
29259
  };
29113
29260
  return actionImpls[this.action](url, this.attr, this.data);
29114
29261
  };
29115
- UrlAttrTransform.prototype.toString = function () {
29262
+ UrlTransform.prototype.toString = function () {
29116
29263
  return this.attr + ' - ' + this.action + ' - ' + JSON.stringify(this.data);
29117
29264
  };
29118
29265
  // Static method, not on the instance
29119
- UrlAttrTransform.fromJSON = function (obj) {
29120
- if (obj instanceof UrlAttrTransform) {
29266
+ UrlTransform.fromJSON = function (obj) {
29267
+ if (obj instanceof UrlTransform) {
29121
29268
  return obj;
29122
29269
  }
29123
29270
  // Validate input is an object
29124
29271
  if (!_.isObject(obj)) {
29125
- throw new Error('UrlAttrTransform.fromJSON expects an object. Received: ' + typeof obj + '. Example: {attr: "search", action: "AddTo", data: {key: "value"}}');
29272
+ throw new Error('UrlTransform.fromJSON expects an object. Received: ' + typeof obj + '. Example: {attr: "search", action: "AddTo", data: {key: "value"}}');
29126
29273
  }
29127
29274
  // Validate required properties
29128
29275
  if (!obj.attr) {
29129
29276
  var allValidAttrs = _.keys(attrActionEnum).join(', ');
29130
- throw new Error('UrlAttrTransform is missing required "attr" property. Valid attributes are: ' + allValidAttrs + '. Example: {attr: "search", action: "AddTo", data: {key: "value"}}');
29277
+ throw new Error('UrlTransform is missing required "attr" property. Valid attributes are: ' + allValidAttrs + '. Example: {attr: "search", action: "AddTo", data: {key: "value"}}');
29131
29278
  }
29132
29279
  if (!obj.action) {
29133
29280
  var attrValidActions = attrActionEnum[obj.attr] ? attrActionEnum[obj.attr].join(', ') : 'AllowOnlyKeys, ExcludeKeys, AddTo, Replace, Clear';
29134
- throw new Error('UrlAttrTransform is missing required "action" property. Valid actions depend on the attribute. For "' + obj.attr + '" attribute, valid actions are: ' + attrValidActions + '. Example: {attr: "' + obj.attr + '", action: "AddTo", data: {key: "value"}}');
29281
+ throw new Error('UrlTransform is missing required "action" property. Valid actions depend on the attribute. For "' + obj.attr + '" attribute, valid actions are: ' + attrValidActions + '. Example: {attr: "' + obj.attr + '", action: "AddTo", data: {key: "value"}}');
29135
29282
  }
29136
29283
  // Validate attribute and action combination
29137
29284
  if (!attrActionEnum[obj.attr]) {
@@ -29170,7 +29317,7 @@ UrlAttrTransform.fromJSON = function (obj) {
29170
29317
  }
29171
29318
  }
29172
29319
  try {
29173
- return new UrlAttrTransform(obj.attr, obj.action, obj.data);
29320
+ return new UrlTransform(obj.attr, obj.action, obj.data, obj.target);
29174
29321
  }
29175
29322
  catch (error) {
29176
29323
  // If it's already a detailed error from our validation, re-throw it
@@ -29179,7 +29326,7 @@ UrlAttrTransform.fromJSON = function (obj) {
29179
29326
  throw error;
29180
29327
  }
29181
29328
  // Otherwise, wrap the original error with context
29182
- throw new Error('Failed to create UrlAttrTransform: ' + error.message + '. Transform object: ' + JSON.stringify(obj));
29329
+ throw new Error('Failed to create UrlTransform: ' + error.message + '. Transform object: ' + JSON.stringify(obj));
29183
29330
  }
29184
29331
  };
29185
29332
 
@@ -29189,13 +29336,13 @@ function isURL(u) {
29189
29336
  var LocationModule = (function (global) {
29190
29337
  var createElectronTranforms = function (appname, resourcesPath, directory, userHome) {
29191
29338
  return [
29192
- new UrlAttrTransform('pathname', 'Replace', function (path) {
29339
+ new UrlTransform('pathname', 'Replace', function (path) {
29193
29340
  var newPath = path.replace(resourcesPath, appname);
29194
29341
  newPath = newPath.replace(directory, appname);
29195
29342
  newPath = newPath.replace(userHome, '');
29196
29343
  return newPath;
29197
29344
  }),
29198
- new UrlAttrTransform('href', 'ForceSecure')
29345
+ new UrlTransform('href', 'ForceSecure')
29199
29346
  ];
29200
29347
  };
29201
29348
  var DEFAULT_SRC_FN = function () {
@@ -29234,17 +29381,23 @@ var LocationModule = (function (global) {
29234
29381
  },
29235
29382
  addTransforms(context, transforms) {
29236
29383
  _.each(transforms, function (f) {
29237
- context.commit('addTransform', UrlAttrTransform.fromJSON(f));
29384
+ const t = UrlTransform.fromJSON(f);
29385
+ if (t.target === 'location' || t.target === 'both') {
29386
+ context.commit('addTransform', t);
29387
+ }
29388
+ if (t.target === 'attribute' || t.target === 'both') {
29389
+ store.dispatch('nodeAttr/addAttrTransform', t);
29390
+ }
29238
29391
  });
29239
29392
  },
29240
29393
  addInternalTransforms(context, transforms) {
29241
29394
  _.each(transforms, function (f) {
29242
- context.commit('addInternalTransform', UrlAttrTransform.fromJSON(f));
29395
+ context.commit('addInternalTransform', UrlTransform.fromJSON(f));
29243
29396
  });
29244
29397
  },
29245
29398
  removeInternalTransforms(context, transforms) {
29246
29399
  _.each(transforms, function (f) {
29247
- context.commit('removeInternalTransform', UrlAttrTransform.fromJSON(f));
29400
+ context.commit('removeInternalTransform', UrlTransform.fromJSON(f));
29248
29401
  });
29249
29402
  },
29250
29403
  startPolling(context) {
@@ -29272,6 +29425,7 @@ var LocationModule = (function (global) {
29272
29425
  },
29273
29426
  clearTransforms(state) {
29274
29427
  state.transforms = [];
29428
+ store.commit('nodeAttr/clearURLTransforms');
29275
29429
  },
29276
29430
  clearInternalTransforms(state) {
29277
29431
  state.internalTransforms = [];
@@ -29327,7 +29481,7 @@ var LocationModule = (function (global) {
29327
29481
  };
29328
29482
  var transformUrl = function (transforms, url) {
29329
29483
  return _.reduce(transforms, function (tUrl, f) {
29330
- return f.applyToURL(tUrl);
29484
+ return f.applyTo(tUrl);
29331
29485
  }, url);
29332
29486
  };
29333
29487
  var urlGetter = function (state) {
@@ -32544,10 +32698,12 @@ var GuideUpdateModule = (function () {
32544
32698
  state.scheduledUpdate = scheduledUpdate;
32545
32699
  },
32546
32700
  startUpdate(state, time) {
32701
+ PerformanceMonitor$1.startTimer('guide-loop');
32547
32702
  state.needsUpdate = false;
32548
32703
  state.updateId = time;
32549
32704
  },
32550
32705
  completeUpdate(state, time) {
32706
+ PerformanceMonitor$1.stopTimer('guide-loop');
32551
32707
  state.updateId = null;
32552
32708
  state.updateCompleteTime = time;
32553
32709
  }
@@ -32656,75 +32812,6 @@ var HealthCheckModule = (function () {
32656
32812
  };
32657
32813
  })();
32658
32814
 
32659
- var MonitoringModule = (function () {
32660
- var state = {
32661
- lastFlush: getNow(),
32662
- flushInterval: 5 * 60 * 1000,
32663
- counters: {
32664
- ptmGifFailures: 0,
32665
- guideGifFailures: 0
32666
- },
32667
- timers: {}
32668
- };
32669
- var actions = {
32670
- flush(context) {
32671
- _.each(context.state.counters, function (value, counterName) {
32672
- context.commit('resetCounter', counterName);
32673
- });
32674
- _.each(context.state.timers, function (value, timerName) {
32675
- context.commit('resetTimer', timerName);
32676
- });
32677
- context.commit('setLastFlush', context.getters.now());
32678
- }
32679
- };
32680
- var mutations = {
32681
- setLastFlush(state, lastFlush) {
32682
- state.lastFlush = lastFlush;
32683
- },
32684
- incrementCounter(state, counterName) {
32685
- if (state.counters[counterName] === undefined)
32686
- return;
32687
- state.counters[counterName]++;
32688
- },
32689
- resetCounter(state, counterName) {
32690
- if (state.counters[counterName] === undefined)
32691
- return;
32692
- state.counters[counterName] = 0;
32693
- },
32694
- setTimer(state, { name, time } = {}) {
32695
- if (!name || time == null)
32696
- return;
32697
- state.timers[name] = time;
32698
- },
32699
- resetTimer(state, timerName) {
32700
- delete state.timers[timerName];
32701
- }
32702
- };
32703
- var getters = {
32704
- shouldFlush(state, getters) {
32705
- return (getters.now() - state.lastFlush) >= state.flushInterval;
32706
- },
32707
- payload(state) {
32708
- var counters = _.reduce(state.counters, function (obj, value, key) {
32709
- if (value > 0) {
32710
- obj[key] = value;
32711
- }
32712
- return obj;
32713
- }, {});
32714
- return _.extend({}, counters, state.timers);
32715
- },
32716
- now() {
32717
- return getNow();
32718
- }
32719
- };
32720
- return {
32721
- state,
32722
- actions,
32723
- mutations,
32724
- getters
32725
- };
32726
- })();
32727
-
32728
32815
  var MetadataModule = (function () {
32729
32816
  var state = {
32730
32817
  visitor: {},
@@ -32913,7 +33000,6 @@ const DebuggerModule = (() => {
32913
33000
  context.commit('setTabId', EventTracer.getTabId());
32914
33001
  context.commit('setInstallType', getInstallType());
32915
33002
  const isTop = isLeader() && window.top === window; // only a leader frame that is a top window can launch debugger
32916
- state.isTop !== isTop;
32917
33003
  context.commit('setIsTop', isTop);
32918
33004
  context.commit('isLeader', isLeader());
32919
33005
  if (isTop) {
@@ -32964,6 +33050,8 @@ const DebuggerModule = (() => {
32964
33050
  context.commit('enableEventLogging', enabled);
32965
33051
  },
32966
33052
  eventCaptured: (context, data) => {
33053
+ if (pendo$1.designerEnabled || isInPreviewMode() || isInDesignerPreviewMode())
33054
+ return;
32967
33055
  if (!context.state.isTop) {
32968
33056
  crossFrameChannel.postMessage({
32969
33057
  action: 'debugger/receiveEventCaptured',
@@ -33202,6 +33290,68 @@ const DebuggerModule = (() => {
33202
33290
  };
33203
33291
  })();
33204
33292
 
33293
+ const NodeAttrModule = (function (global) {
33294
+ const state = {
33295
+ transforms: []
33296
+ };
33297
+ const actions = {
33298
+ addAttrTransform(context, urlTransform) {
33299
+ context.commit('addTransform', urlTransform);
33300
+ }
33301
+ };
33302
+ const mutations = {
33303
+ addTransform(state, transform) {
33304
+ state.transforms.push(transform);
33305
+ },
33306
+ clearURLTransforms(state) {
33307
+ // XXX if ever support non url transforms for attributes then we'll need to check the Transform type
33308
+ // or determine some other way how to purge only URL transforms as Location API provides a way for these to be
33309
+ // cleared via the API.
33310
+ state.transforms = [];
33311
+ }
33312
+ };
33313
+ const applyTransforms = (transforms, url) => {
33314
+ return _.reduce(transforms, function (tUrl, f) {
33315
+ return f.applyTo(tUrl);
33316
+ }, url);
33317
+ };
33318
+ const resolveAttrValueAsURL = (attrValue) => {
33319
+ // let's let the browser do this work for us...
33320
+ const a = document.createElement('a'); // this handles relative urls nicely
33321
+ a.href = attrValue;
33322
+ return new URL(a.href);
33323
+ };
33324
+ const getters = {
33325
+ getAttribute(state) {
33326
+ return function (element, attrName) {
33327
+ let attrValue = element.getAttribute ? element.getAttribute(attrName) : element[attrName];
33328
+ if (_.size(state.transforms) < 1) {
33329
+ return attrValue;
33330
+ }
33331
+ try {
33332
+ let url = resolveAttrValueAsURL(attrValue);
33333
+ url = _.reduce([
33334
+ _.partial(applyTransforms, state.transforms)
33335
+ ], (url, fn) => {
33336
+ return fn(url);
33337
+ }, url);
33338
+ return url.href;
33339
+ }
33340
+ catch (e) {
33341
+ log.critical(e);
33342
+ return attrValue;
33343
+ }
33344
+ };
33345
+ }
33346
+ };
33347
+ return {
33348
+ state,
33349
+ actions,
33350
+ mutations,
33351
+ getters
33352
+ };
33353
+ })();
33354
+
33205
33355
  function registerModules(store) {
33206
33356
  store.registerModule('debugger', DebuggerModule);
33207
33357
  store.registerModule('errorLog', ErrorLogModule);
@@ -33210,9 +33360,9 @@ function registerModules(store) {
33210
33360
  store.registerModule('guideState', GuideStateModule);
33211
33361
  store.registerModule('healthCheck', HealthCheckModule);
33212
33362
  store.registerModule('location', LocationModule);
33213
- store.registerModule('monitoring', MonitoringModule);
33214
33363
  store.registerModule('metadata', MetadataModule);
33215
33364
  store.registerModule('preview', PreviewModule);
33365
+ store.registerModule('nodeAttr', NodeAttrModule);
33216
33366
  }
33217
33367
 
33218
33368
  const IFrameMonitor = (function () {
@@ -36255,7 +36405,7 @@ const EventProperties = (function () {
36255
36405
  return [];
36256
36406
  }
36257
36407
  return [
36258
- new UrlAttrTransform('search', 'AddTo', function () { return collectPageEventProperties(); })
36408
+ new UrlTransform('search', 'AddTo', function () { return collectPageEventProperties(); })
36259
36409
  ];
36260
36410
  }
36261
36411
  function createPageEventProperties() {
@@ -47297,6 +47447,7 @@ class SessionRecorder {
47297
47447
  this.sendQueue = new SendQueue(bind(this.transport.send, this.transport));
47298
47448
  this.sendQueue.onTimeout = bind(this.sendFailure, this, 'SEND_TIMEOUT');
47299
47449
  this.isNewSession = false;
47450
+ this.isCheckingVisitorEligibility = false;
47300
47451
  this.addConfigOptions();
47301
47452
  this.config = configReader.get(RECORDING_CONFIG);
47302
47453
  this.onRecordingStart = this.pendo._.isFunction(configReader.get(RECORDING_CONFIG_ON_RECORDING_START))
@@ -47399,19 +47550,32 @@ class SessionRecorder {
47399
47550
  clearTimeout(this._changeIdentityTimer);
47400
47551
  this.visitorId = options.visitor.id;
47401
47552
  this.accountId = options.account.id;
47402
- return this.fetchVisitorConfig().then(visitorConfig => {
47403
- if ((!visitorConfig || !visitorConfig.enable) && this.isRecording()) {
47404
- this.stop();
47405
- }
47406
- else if (visitorConfig && visitorConfig.enable && !this.isRecording()) {
47407
- this._startRecordingForVisitor(visitorConfig);
47408
- }
47409
- }).catch((e) => {
47410
- this.api.log.critical('Failed to re-fetch recording config', { error: e });
47411
- this.logStopReason('VISITOR_CONFIG_ERROR');
47412
- });
47553
+ return this.checkVisitorEligibility();
47413
47554
  }
47414
47555
  }
47556
+ checkVisitorEligibility(continuationCallback) {
47557
+ if (!this.isRecording() && this.pendo._.isNull(this.visitorId) && this.pendo._.isNull(this.accountId))
47558
+ return;
47559
+ this.isCheckingVisitorEligibility = true;
47560
+ return this.fetchVisitorConfig().then(visitorConfig => {
47561
+ if ((!visitorConfig || !visitorConfig.enable) && this.isRecording()) {
47562
+ this.stop();
47563
+ }
47564
+ if (visitorConfig && visitorConfig.enable && this.isRecording()) {
47565
+ if (continuationCallback) {
47566
+ continuationCallback.call(this);
47567
+ }
47568
+ }
47569
+ if (visitorConfig && visitorConfig.enable && !this.isRecording()) {
47570
+ this._startRecordingForVisitor(visitorConfig);
47571
+ }
47572
+ }).catch((e) => {
47573
+ this.api.log.critical('Failed to re-fetch recording config', { error: e });
47574
+ this.logStopReason('VISITOR_CONFIG_ERROR');
47575
+ }).finally(() => {
47576
+ this.isCheckingVisitorEligibility = false;
47577
+ });
47578
+ }
47415
47579
  snapshot() {
47416
47580
  if (!this.isRecording())
47417
47581
  return;
@@ -47673,13 +47837,24 @@ class SessionRecorder {
47673
47837
  if ((!prevLastEmitTime && isMeta)) {
47674
47838
  skipUserInteractionCheck = true;
47675
47839
  }
47676
- this.storeLastUserInteractionEventInformation(event, this.visitorId, this.accountId, skipUserInteractionCheck);
47840
+ // Ensures events emitted while the visitor eligibility check is in flight are compared against events emitted
47841
+ // before the visitor eligibility check occurred. This means these events which fall outside of the inactivity
47842
+ // duration will not be placed in the buffer and captured. This is ok since they occurred outside of the
47843
+ // inactivity period and before the next snapshot.
47844
+ if (!this.isCheckingVisitorEligibility) {
47845
+ this.storeLastUserInteractionEventInformation(event, this.visitorId, this.accountId, skipUserInteractionCheck);
47846
+ }
47677
47847
  const inactivityDuration = this.pendo._.get(this.visitorConfig, 'inactivityDuration', THIRTY_MINUTES);
47678
47848
  if (prevLastEmitTime && event.timestamp - prevLastEmitTime > inactivityDuration && !isSnapshot && !isMeta) {
47679
- this.send();
47680
- this.clearSessionInfo();
47681
- this.snapshot();
47682
- return; // ignore this current event, since we're about to get a fresh snapshot
47849
+ if (!this.isCheckingVisitorEligibility) {
47850
+ const continuationCallback = function () {
47851
+ this.send();
47852
+ this.clearSessionInfo();
47853
+ this.snapshot();
47854
+ };
47855
+ this.checkVisitorEligibility(continuationCallback);
47856
+ }
47857
+ return;
47683
47858
  }
47684
47859
  /*
47685
47860
  * META events and Snapshots are special and need to be packaged together. This is made possible by
@@ -47714,8 +47889,16 @@ class SessionRecorder {
47714
47889
  const exceedsEventFreq = this.eventsSinceLastKeyFrame >= this.pendo._.get(this.visitorConfig, 'keyframeEventFrequency', 4548); // Defaults determined by BE originally, shouldn't really ever be used
47715
47890
  const exceedsRecordingSizeLimit = this.currentRecordingSize >= this.pendo._.get(this.visitorConfig, 'recordingSizeLimit', ONE_HUNDRED_MB_IN_BYTES);
47716
47891
  if (exceeds24Hours || (exceedsTimeFreq && exceedsEventFreq) || exceedsRecordingSizeLimit) {
47717
- this.currentRecordingSize = 0;
47718
- this.snapshot();
47892
+ const continuationCallback = function () {
47893
+ this.currentRecordingSize = 0;
47894
+ this.snapshot();
47895
+ };
47896
+ if (exceeds24Hours && !this.isCheckingVisitorEligibility) {
47897
+ this.checkVisitorEligibility(continuationCallback);
47898
+ }
47899
+ else {
47900
+ continuationCallback.call(this);
47901
+ }
47719
47902
  }
47720
47903
  }
47721
47904
  }
@@ -48954,17 +49137,14 @@ class ConsoleCaptureBuffer {
48954
49137
  constructor(pendo, pluginAPI) {
48955
49138
  this.pendo = pendo;
48956
49139
  this.pluginAPI = pluginAPI;
48957
- this.infoEvents = [];
48958
- this.warnEvents = [];
48959
- this.errorEvents = [];
49140
+ this.events = [];
48960
49141
  this.lastEvent = null;
48961
- this.devLogEvent = null;
48962
49142
  this.tokens = TOKEN_MAX_SIZE;
48963
49143
  this.lastRefillTime = this.pluginAPI.util.getNow();
48964
49144
  this.nextRefillTime = this.lastRefillTime + TOKEN_REFRESH_INTERVAL;
48965
49145
  }
48966
49146
  isEmpty() {
48967
- return this.infoEvents.length === 0 && this.warnEvents.length === 0 && this.errorEvents.length === 0;
49147
+ return this.events.length === 0;
48968
49148
  }
48969
49149
  refillTokens() {
48970
49150
  const now = this.pluginAPI.util.getNow();
@@ -48978,10 +49158,8 @@ class ConsoleCaptureBuffer {
48978
49158
  }
48979
49159
  }
48980
49160
  clear() {
49161
+ this.events = [];
48981
49162
  this.lastEvent = null;
48982
- this.infoEvents.length = 0;
48983
- this.warnEvents.length = 0;
48984
- this.errorEvents.length = 0;
48985
49163
  }
48986
49164
  push(event) {
48987
49165
  const { devLogLevel } = event;
@@ -48991,50 +49169,16 @@ class ConsoleCaptureBuffer {
48991
49169
  if (this.tokens === 0)
48992
49170
  return false;
48993
49171
  this.lastEvent = event;
48994
- this.processEvent(event);
49172
+ this.events.push(event);
48995
49173
  this.tokens = Math.max(this.tokens - 1, 0);
48996
49174
  return true;
48997
49175
  }
48998
- processEvent(event) {
48999
- switch (event.devLogLevel) {
49000
- case 'info':
49001
- this.infoEvents.push(event);
49002
- break;
49003
- case 'warn':
49004
- this.warnEvents.push(event);
49005
- break;
49006
- case 'error':
49007
- this.errorEvents.push(event);
49008
- break;
49009
- }
49010
- }
49011
- createDevLogEventWithPayload({ events, level }) {
49012
- if (events.length === 0)
49013
- return;
49014
- const totalCount = this.pendo._.reduce(events, (sum, event) => sum + (event.devLogCount || 1), 0);
49015
- return Object.assign(Object.assign({}, this.devLogEvent), { devLogLevel: level, devLogCount: totalCount, devLogPayload: this.pendo.compress(events) });
49016
- }
49017
- generateJZB() {
49018
- const payload = [];
49019
- this.pendo._.each(DEV_LOG_LEVELS, level => {
49020
- const events = this[`${level}Events`];
49021
- if (events.length === 0)
49022
- return;
49023
- const devLogEventWithPayload = this.createDevLogEventWithPayload({
49024
- events,
49025
- level
49026
- });
49027
- payload.push(devLogEventWithPayload);
49028
- });
49029
- this.devLogEvent = null;
49030
- return this.pendo.compress(payload);
49031
- }
49032
- pack(url) {
49176
+ pack() {
49033
49177
  if (this.isEmpty())
49034
- return [];
49035
- const jzb = this.generateJZB();
49178
+ return;
49179
+ const jzb = this.pendo.compress(this.events);
49036
49180
  this.clear();
49037
- return [{ url, jzb }];
49181
+ return jzb;
49038
49182
  }
49039
49183
  }
49040
49184
 
@@ -55818,12 +55962,11 @@ function ConsoleCapture() {
55818
55962
  initialize,
55819
55963
  teardown,
55820
55964
  addIntercepts,
55821
- createDevLog,
55965
+ createConsoleEvent,
55822
55966
  captureStackTrace,
55823
55967
  send,
55824
55968
  onAppHidden,
55825
55969
  onAppUnloaded,
55826
- onEventCaptured,
55827
55970
  onPtmPaused,
55828
55971
  onPtmUnpaused,
55829
55972
  get buffer() {
@@ -55857,7 +56000,6 @@ function ConsoleCapture() {
55857
56000
  pluginAPI.Events.ready.on(addIntercepts);
55858
56001
  pluginAPI.Events.appUnloaded.on(onAppUnloaded);
55859
56002
  pluginAPI.Events.appHidden.on(onAppHidden);
55860
- pluginAPI.Events.eventCaptured.on(onEventCaptured);
55861
56003
  pluginAPI.Events['ptm:paused'].on(onPtmPaused);
55862
56004
  pluginAPI.Events['ptm:unpaused'].on(onPtmUnpaused);
55863
56005
  pluginAPI.log.info('Console logs are being captured');
@@ -55868,36 +56010,19 @@ function ConsoleCapture() {
55868
56010
  function onAppUnloaded() {
55869
56011
  send({ unload: true });
55870
56012
  }
55871
- /**
55872
- * Handles eventCaptured events to monitor recordingId changes and/or link devLog events with recordingId
55873
- *
55874
- * @param {object} event - eventCaptured event
55875
- */
55876
- function onEventCaptured(event) {
55877
- if (!event || !event.data || !event.data.length || !buffer.devLogEvent)
55878
- return;
55879
- const capturedEvent = event.data[0];
55880
- const { type, recordingId, recordingSessionId } = capturedEvent;
55881
- if (type === DEV_LOG_TYPE || type === 'identify' || !recordingId || !recordingSessionId)
55882
- return;
55883
- const { recordingId: devLogRecordingId } = buffer.devLogEvent;
55884
- // if recordingId has changed, send current buffer immediately to separate recording sessions
55885
- if (devLogRecordingId && recordingId !== devLogRecordingId) {
55886
- send();
55887
- return;
55888
- }
55889
- }
55890
56013
  function onPtmPaused() {
55891
56014
  isPtmPaused = true;
55892
56015
  }
55893
56016
  function onPtmUnpaused() {
55894
56017
  isPtmPaused = false;
55895
- if (!buffer.devLogEvent) {
55896
- buffer.devLogEvent = createDevLogEvent();
56018
+ if (!buffer.isEmpty()) {
56019
+ for (const event of buffer.events) {
56020
+ pluginAPI.Events.eventCaptured.trigger(event);
56021
+ }
56022
+ send();
55897
56023
  }
55898
- pluginAPI.Events.eventCaptured.trigger(buffer.devLogEvent);
55899
56024
  }
55900
- function createDevLogEvent() {
56025
+ function createDevLogEnvelope() {
55901
56026
  return {
55902
56027
  visitorId: globalPendo.get_visitor_id(),
55903
56028
  accountId: globalPendo.get_account_id(),
@@ -55916,14 +56041,14 @@ function ConsoleCapture() {
55916
56041
  // slice 1 to omit originalFn
55917
56042
  const args = _.toArray(arguments).slice(1);
55918
56043
  originalFn.apply(console, args);
55919
- createDevLog(args, methodName);
56044
+ createConsoleEvent(args, methodName);
55920
56045
  });
55921
56046
  console[methodName]._pendoUnwrap = function () {
55922
56047
  console[methodName] = originalMethod;
55923
56048
  };
55924
56049
  });
55925
56050
  }
55926
- function createDevLog(args, methodName) {
56051
+ function createConsoleEvent(args, methodName) {
55927
56052
  if (!args || args.length === 0)
55928
56053
  return;
55929
56054
  // stringify args
@@ -55951,22 +56076,16 @@ function ConsoleCapture() {
55951
56076
  buffer.lastEvent.devLogCount++;
55952
56077
  return;
55953
56078
  }
55954
- const devLog = {
55955
- devLogLevel: methodName === 'log' ? 'info' : methodName,
55956
- devLogMsg: scrubPII(message),
55957
- devLogTrace: stackTrace,
55958
- devLogTimestamp: pluginAPI.util.getNow(),
55959
- devLogCount: 1
55960
- };
55961
- const wasAccepted = buffer.push(devLog);
56079
+ const devLogEnvelope = createDevLogEnvelope();
56080
+ const consoleEvent = Object.assign(Object.assign({}, devLogEnvelope), { devLogLevel: methodName === 'log' ? 'info' : methodName, devLogMessage: scrubPII(message), devLogTrace: stackTrace, devLogCount: 1 });
56081
+ const wasAccepted = buffer.push(consoleEvent);
55962
56082
  if (wasAccepted) {
55963
- if (buffer.devLogEvent === null && !isPtmPaused) {
55964
- buffer.devLogEvent = createDevLogEvent();
55965
- pluginAPI.Events.eventCaptured.trigger(buffer.devLogEvent);
56083
+ if (!isPtmPaused) {
56084
+ pluginAPI.Events.eventCaptured.trigger(consoleEvent);
55966
56085
  }
55967
56086
  updateLastLog(logKey);
55968
56087
  }
55969
- return devLog;
56088
+ return consoleEvent;
55970
56089
  }
55971
56090
  function captureStackTrace(maxStackFrames) {
55972
56091
  try {
@@ -55986,19 +56105,23 @@ function ConsoleCapture() {
55986
56105
  function send({ unload = false, hidden = false } = {}) {
55987
56106
  if (!buffer || buffer.isEmpty())
55988
56107
  return;
56108
+ if (!globalPendo.isSendingEvents()) {
56109
+ buffer.clear();
56110
+ return;
56111
+ }
55989
56112
  const queryParams = {
55990
56113
  v: globalPendo.VERSION,
55991
56114
  ct: pluginAPI.util.getNow()
55992
56115
  };
55993
56116
  const url = pluginAPI.transmit.buildBaseDataUrl('devlog', globalPendo.apiKey, queryParams);
55994
- const payloads = buffer.pack(url);
55995
- if (!payloads || payloads.length === 0)
56117
+ const jzb = buffer.pack();
56118
+ if (!jzb)
55996
56119
  return;
55997
56120
  if (unload || hidden) {
55998
- sendQueue.drain(payloads, unload);
56121
+ sendQueue.drain([{ url, jzb }], unload);
55999
56122
  }
56000
56123
  else {
56001
- sendQueue.push(...payloads);
56124
+ sendQueue.push({ url, jzb });
56002
56125
  }
56003
56126
  }
56004
56127
  function teardown() {
@@ -56014,7 +56137,6 @@ function ConsoleCapture() {
56014
56137
  }
56015
56138
  pluginAPI.Events.appHidden.off(onAppHidden);
56016
56139
  pluginAPI.Events.appUnloaded.off(onAppUnloaded);
56017
- pluginAPI.Events.eventCaptured.off(onEventCaptured);
56018
56140
  pluginAPI.Events['ptm:paused'].off(onPtmPaused);
56019
56141
  pluginAPI.Events['ptm:unpaused'].off(onPtmUnpaused);
56020
56142
  _.each(CONSOLE_METHODS, function (methodName) {