@adobe/helix-rum-enhancer 2.48.0 → 2.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [2.49.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.48.0...v2.49.0) (2026-07-10)
2
+
3
+
4
+ ### Features
5
+
6
+ * flag untrusted (synthetic) clicks as bots ([94b2893](https://github.com/adobe/helix-rum-enhancer/commit/94b289333d0c8a33435752c8f48f080b5dfa203d))
7
+
1
8
  # [2.48.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.47.3...v2.48.0) (2026-07-08)
2
9
 
3
10
 
@@ -11,6 +11,6 @@
11
11
  */
12
12
  import { fflags } from './fflags.js';
13
13
 
14
- export const KNOWN_PROPERTIES = ['weight', 'id', 'referer', 'checkpoint', 't', 'source', 'target', 'cwv', 'CLS', 'FID', 'LCP', 'INP', 'TTFB'];
14
+ export const KNOWN_PROPERTIES = ['weight', 'id', 'referer', 'checkpoint', 't', 'source', 'target', 'cwv', 'CLS', 'FID', 'LCP', 'INP', 'TTFB', 'ua'];
15
15
  export const DEFAULT_TRACKING_EVENTS = ['click', 'cwv', 'form', 'viewblock', 'viewmedia', 'loadresource', 'utm', 'paid', 'email', 'consent'];
16
16
  fflags.enabled('example', () => DEFAULT_TRACKING_EVENTS.push('example'));
package/modules/dom.js CHANGED
@@ -32,12 +32,20 @@ export const targetSelector = (el) => {
32
32
  }
33
33
  };
34
34
 
35
- function walk(el, checkFn) {
35
+ export const untrustedClickPayload = (event) => {
36
+ if (event && event.isTrusted === false) {
37
+ const ua = navigator.userAgent;
38
+ return { ua: ua.includes('+http') ? ua : `${ua} +http://event.untrusted` };
39
+ }
40
+ return {};
41
+ };
42
+
43
+ function walk(el, check) {
36
44
  if (!el || el === document.body || el === document.documentElement) {
37
45
  return undefined;
38
46
  }
39
47
 
40
- return checkFn(el) || walk(el.parentElement || (el.parentNode && el.parentNode.host), checkFn);
48
+ return check(el) || walk(el.parentElement || (el.parentNode && el.parentNode.host), check);
41
49
  }
42
50
 
43
51
  function isDialog(el) {
@@ -53,19 +61,19 @@ function isButton(el) {
53
61
  return true;
54
62
  }
55
63
  if (el.tagName === 'A') {
56
- return Array.from(el.classList).some((className) => className.match(/button|cta/));
64
+ return Array.from(el.classList).some((cls) => cls.match(/button|cta/));
57
65
  }
58
66
  return el.getAttribute('role') === 'button';
59
67
  }
60
68
 
61
- function getSourceContext(el) {
62
- const formEl = el.closest('form');
63
- if (formEl) {
64
- const id = formEl.getAttribute('id');
69
+ function srcContext(el) {
70
+ const form = el.closest('form');
71
+ if (form) {
72
+ const id = form.getAttribute('id');
65
73
  if (id) {
66
74
  return `form#${CSS.escape(id)}`;
67
75
  }
68
- return `form${formEl.classList.length > 0 ? `.${CSS.escape(formEl.classList[0])}` : ''}`;
76
+ return `form${form.classList.length > 0 ? `.${CSS.escape(form.classList[0])}` : ''}`;
69
77
  }
70
78
  const block = el.closest('.block[data-block-name]');
71
79
  return ((block && `.${block.getAttribute('data-block-name')}`)
@@ -75,7 +83,7 @@ function getSourceContext(el) {
75
83
  || walk(el, (e) => e.id && `#${CSS.escape(e.id)}`));
76
84
  }
77
85
 
78
- function getSourceElement(el) {
86
+ function srcElement(el) {
79
87
  const f = el.closest('form');
80
88
  if (f && Array.from(f.elements).includes(el)) {
81
89
  return (el.tagName.toLowerCase()
@@ -87,7 +95,7 @@ function getSourceElement(el) {
87
95
  || (el.tagName.toLowerCase().match(/^(a|img|video|form)$/) && el.tagName.toLowerCase());
88
96
  }
89
97
 
90
- function getSourceIdentifier(el) {
98
+ function srcId(el) {
91
99
  return (el.id && `#${CSS.escape(el.id)}`)
92
100
  || (el.getAttribute('data-block-name') && `.${el.getAttribute('data-block-name')}`)
93
101
  || (el.classList.length > 0 && `.${CSS.escape(el.classList[0])}`);
@@ -101,9 +109,9 @@ export const sourceSelector = (el) => {
101
109
  if (el.getAttribute('data-rum-source')) {
102
110
  return el.getAttribute('data-rum-source');
103
111
  }
104
- const ctx = getSourceContext(el.parentElement) || '';
105
- const name = getSourceElement(el) || '';
106
- const id = getSourceIdentifier(el) || '';
112
+ const ctx = srcContext(el.parentElement) || '';
113
+ const name = srcElement(el) || '';
114
+ const id = srcId(el) || '';
107
115
  return `${ctx} ${name}${id}`.trim() || `"${el.textContent.substring(0, 10)}"`;
108
116
  /* c8 ignore next 3 */
109
117
  } catch (error) {
package/modules/index.js CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  import { KNOWN_PROPERTIES, DEFAULT_TRACKING_EVENTS } from './defaults.js';
15
15
  import { urlSanitizers } from './utils.js';
16
- import { targetSelector, sourceSelector } from './dom.js';
16
+ import { targetSelector, sourceSelector, untrustedClickPayload } from './dom.js';
17
17
  import { fflags } from './fflags.js';
18
18
 
19
19
  const { sampleRUM, queue, isSelected } = (window.hlx && window.hlx.rum) ? window.hlx.rum
@@ -27,19 +27,19 @@ const createMO = (cb) => (window.MutationObserver ? new MutationObserver(cb)
27
27
  const [blocksMO, mediaMO] = [blocksMCB, mediaMCB].map(createMO);
28
28
 
29
29
  // Check for the presence of a given cookie
30
- const hasCookieKey = (key) => document.cookie.split(';').some((c) => c.trim().startsWith(`${key}=`));
30
+ const hasCookie = (key) => document.cookie.split(';').some((c) => c.trim().startsWith(`${key}=`));
31
31
 
32
32
  // Set the base path for the plugins
33
- const pluginBasePath = new URL(document.currentScript.src).href.replace(/index(\.map)?\.js/, 'plugins');
33
+ const pluginBase = new URL(document.currentScript.src).href.replace(/index(\.map)?\.js/, 'plugins');
34
34
 
35
35
  const CONSENT_PROVIDERS = [
36
36
  {
37
37
  name: 'onetrust',
38
- detect: () => hasCookieKey('OptanonAlertBoxClosed') || document.querySelector('#onetrust-banner-sdk, #onetrust-pc-sdk'),
38
+ detect: () => hasCookie('OptanonAlertBoxClosed') || document.querySelector('#onetrust-banner-sdk, #onetrust-pc-sdk'),
39
39
  },
40
40
  {
41
41
  name: 'trustarc',
42
- detect: () => ['notice_gdpr_prefs', 'notice_preferences'].some(hasCookieKey) || document.querySelector('#truste-consent-track'),
42
+ detect: () => ['notice_gdpr_prefs', 'notice_preferences'].some(hasCookie) || document.querySelector('#truste-consent-track'),
43
43
  },
44
44
  {
45
45
  name: 'usercentrics',
@@ -47,40 +47,40 @@ const CONSENT_PROVIDERS = [
47
47
  },
48
48
  ];
49
49
 
50
- const getConsentProvider = () => CONSENT_PROVIDERS.find(({ detect }) => detect());
50
+ const getConsent = () => CONSENT_PROVIDERS.find(({ detect }) => detect());
51
51
  const bodyChildMO = {
52
52
  target: document.body,
53
53
  options: { attributes: false, childList: true, subtree: false },
54
54
  };
55
55
 
56
56
  const PLUGINS = {
57
- cwv: `${pluginBasePath}/cwv.js`,
58
- a11y: `${pluginBasePath}/a11y.js`,
57
+ cwv: `${pluginBase}/cwv.js`,
58
+ a11y: `${pluginBase}/a11y.js`,
59
59
  // Interactive elements
60
60
  form: {
61
- url: `${pluginBasePath}/form.js`,
61
+ url: `${pluginBase}/form.js`,
62
62
  when: () => document.querySelector('form'),
63
63
  isBlockDependent: true,
64
- mutationObserverParams: bodyChildMO,
64
+ moParams: bodyChildMO,
65
65
  },
66
66
  redirect: {
67
- url: `${pluginBasePath}/redirect.js`,
67
+ url: `${pluginBase}/redirect.js`,
68
68
  when: ({ perfEntry: pe, urlParameters: usp }) => (
69
69
  pe && (usp.get('redirect_from') || pe.redirectCount > 0 || pe.fetchStart > 50)
70
70
  ),
71
71
  },
72
- video: { url: `${pluginBasePath}/video.js`, when: () => document.querySelector('video'), isBlockDependent: true },
72
+ video: { url: `${pluginBase}/video.js`, when: () => document.querySelector('video'), isBlockDependent: true },
73
73
  webcomponent: {
74
- url: `${pluginBasePath}/webcomponent.js`,
74
+ url: `${pluginBase}/webcomponent.js`,
75
75
  when: () => [...document.querySelectorAll('*')].some((el) => el.tagName && el.tagName.includes('-')),
76
76
  isBlockDependent: true,
77
77
  },
78
78
  // Martech
79
- martech: { url: `${pluginBasePath}/martech.js`, when: ({ urlParameters }) => urlParameters.size > 0 },
79
+ martech: { url: `${pluginBase}/martech.js`, when: ({ urlParameters }) => urlParameters.size > 0 },
80
80
  consent: {
81
- when: () => getConsentProvider(),
81
+ when: () => getConsent(),
82
82
  isBlockDependent: true,
83
- mutationObserverParams: bodyChildMO,
83
+ moParams: bodyChildMO,
84
84
  },
85
85
  // test: broken-plugin
86
86
  };
@@ -94,12 +94,12 @@ function getIntersectionObserver(checkpoint) {
94
94
  if (!window.IntersectionObserver) {
95
95
  return null;
96
96
  }
97
- const observer = new IntersectionObserver((entries) => {
97
+ const obs = new IntersectionObserver((entries) => {
98
98
  try {
99
99
  entries
100
100
  .filter((e) => e.isIntersecting)
101
101
  .forEach((e) => {
102
- observer.unobserve(e.target); // observe only once
102
+ obs.unobserve(e.target); // observe only once
103
103
  const target = targetSelector(e.target);
104
104
  const source = sourceSelector(e.target);
105
105
  if (checkpoint === 'viewmedia') {
@@ -118,15 +118,16 @@ function getIntersectionObserver(checkpoint) {
118
118
  // something went wrong
119
119
  }
120
120
  });
121
- return observer;
121
+ return obs;
122
122
  }
123
123
 
124
- const PLUGIN_PARAMETERS = {
124
+ const PLUGIN_PARAMS = {
125
125
  context: document.body,
126
126
  fflags,
127
127
  sampleRUM,
128
128
  sourceSelector,
129
129
  targetSelector,
130
+ untrustedClickPayload,
130
131
  getIntersectionObserver,
131
132
  createMO,
132
133
  };
@@ -137,14 +138,14 @@ function loadPlugin(key, params) {
137
138
  const plugin = PLUGINS[key];
138
139
  const usp = new URLSearchParams(window.location.search);
139
140
  if (!pluginCache.has(key) && plugin.when && !plugin.when({ ...params, urlParameters: usp })) {
140
- if (plugin.mutationObserverParams && !plugin.isBeingObserved) {
141
+ if (plugin.moParams && !plugin.isBeingObserved) {
141
142
  // eslint-disable-next-line no-use-before-define
142
143
  createPluginMO(key, params, usp);
143
144
  }
144
145
  return null;
145
146
  }
146
147
  if (key === 'consent') {
147
- plugin.url = `${pluginBasePath}/${getConsentProvider().name}.js`;
148
+ plugin.url = `${pluginBase}/${getConsent().name}.js`;
148
149
  }
149
150
 
150
151
  if (!pluginCache.has(key)) {
@@ -156,7 +157,7 @@ function loadPlugin(key, params) {
156
157
  .catch(() => { /* silent plugin error catching */ });
157
158
  }
158
159
 
159
- function loadPlugins(filter = () => true, params = PLUGIN_PARAMETERS) {
160
+ function loadPlugins(filter = () => true, params = PLUGIN_PARAMS) {
160
161
  Object.entries(PLUGINS)
161
162
  .filter(([, plugin]) => filter(plugin))
162
163
  .map(([key]) => loadPlugin(key, params));
@@ -164,19 +165,19 @@ function loadPlugins(filter = () => true, params = PLUGIN_PARAMETERS) {
164
165
 
165
166
  function createPluginMO(key, params, usp) {
166
167
  const plugin = PLUGINS[key];
167
- const observer = createMO(() => {
168
+ const obs = createMO(() => {
168
169
  if (plugin.when({ urlParameters: usp })) {
169
170
  plugin.isBeingObserved = false;
170
- observer.disconnect();
171
+ obs.disconnect();
171
172
  loadPlugin(key, params);
172
173
  }
173
174
  });
174
175
 
175
- if (observer instanceof MutationObserver) {
176
+ if (obs instanceof MutationObserver) {
176
177
  plugin.isBeingObserved = true;
177
- observer.observe(
178
- plugin.mutationObserverParams.target,
179
- plugin.mutationObserverParams.options,
178
+ obs.observe(
179
+ plugin.moParams.target,
180
+ plugin.moParams.options,
180
181
  );
181
182
  }
182
183
  }
@@ -242,7 +243,7 @@ function addNavigationTracking() {
242
243
  } else {
243
244
  sampleRUM('enter', payload); // enter site
244
245
  }
245
- loadPlugin('redirect', { ...PLUGIN_PARAMETERS, perfEntry });
246
+ loadPlugin('redirect', { ...PLUGIN_PARAMS, perfEntry });
246
247
  };
247
248
  const processed = new Set(); // avoid processing duplicate types
248
249
  new PerformanceObserver((list) => list
@@ -257,7 +258,7 @@ function addNavigationTracking() {
257
258
  }
258
259
 
259
260
  function addLoadResourceTracking() {
260
- const observer = new PerformanceObserver((list) => {
261
+ const obs = new PerformanceObserver((list) => {
261
262
  try {
262
263
  const entries = list.getEntries();
263
264
  entries
@@ -265,14 +266,14 @@ function addLoadResourceTracking() {
265
266
  .filter((e) => window.location.hostname === new URL(e.name).hostname || fflags.has('allresources'))
266
267
  .filter((e) => {
267
268
  const { pathname, hostname } = new URL(e.name);
268
- const extensionMatch = pathname.match(
269
+ const extMatch = pathname.match(
269
270
  hostname !== window.location.hostname
270
271
  ? '.*(\\.html$|\\.json|\\.js|graphql|api)'
271
272
  : '.*(\\.plain\\.html$|\\.json|graphql|api)',
272
273
  );
273
274
  const isDropIn = fflags.has('allresources') && (pathname.includes('__dropins__/storefront-') || pathname.includes('scripts/dropins/storefront-'));
274
275
  const isImage = fflags.has('allresources') && pathname.match(/\.(png|jpe?g|svg)$/i);
275
- return extensionMatch || isDropIn || isImage;
276
+ return extMatch || isDropIn || isImage;
276
277
  })
277
278
  .forEach((e) => {
278
279
  sampleRUM('loadresource', { source: e.name, target: Math.round(e.duration) });
@@ -288,7 +289,7 @@ function addLoadResourceTracking() {
288
289
  // something went wrong
289
290
  }
290
291
  });
291
- observer.observe({ type: 'resource', buffered: true });
292
+ obs.observe({ type: 'resource', buffered: true });
292
293
  }
293
294
 
294
295
  // activate blocks mutation observer
@@ -317,22 +318,22 @@ function activateMediaMO() {
317
318
  );
318
319
  }
319
320
 
320
- function addViewBlockTracking(element) {
321
- const blockobserver = getIntersectionObserver('viewblock');
322
- if (blockobserver) {
323
- const blocks = element.getAttribute('data-block-status') ? [element] : element.querySelectorAll('div[data-block-status="loaded"]');
324
- blocks.forEach((b) => blockobserver.observe(b));
321
+ function addViewBlockTracking(el) {
322
+ const blockObs = getIntersectionObserver('viewblock');
323
+ if (blockObs) {
324
+ const blocks = el.getAttribute('data-block-status') ? [el] : el.querySelectorAll('div[data-block-status="loaded"]');
325
+ blocks.forEach((b) => blockObs.observe(b));
325
326
  }
326
327
  }
327
328
 
328
329
  const observedMedia = new Set();
329
330
  function addViewMediaTracking(parent) {
330
- const mediaobserver = getIntersectionObserver('viewmedia');
331
- if (mediaobserver) {
331
+ const mediaObs = getIntersectionObserver('viewmedia');
332
+ if (mediaObs) {
332
333
  parent.querySelectorAll('img, video, audio, iframe').forEach((m) => {
333
334
  if (!observedMedia.has(m)) {
334
335
  observedMedia.add(m);
335
- mediaobserver.observe(m);
336
+ mediaObs.observe(m);
336
337
  }
337
338
  });
338
339
  }
@@ -349,7 +350,7 @@ function blocksMCB(mutations) {
349
350
  .filter((m) => m.type === 'attributes' && m.attributeName === 'data-block-status')
350
351
  .filter((m) => m.target.dataset.blockStatus === 'loaded')
351
352
  .forEach((m) => {
352
- addObserver('form', (el) => loadPlugins((p) => p.isBlockDependent, { ...PLUGIN_PARAMETERS, context: el }), m.target);
353
+ addObserver('form', (el) => loadPlugins((p) => p.isBlockDependent, { ...PLUGIN_PARAMS, context: el }), m.target);
353
354
  addObserver('viewblock', addViewBlockTracking, m.target);
354
355
  });
355
356
  }
@@ -371,7 +372,8 @@ function addTrackingFromConfig() {
371
372
  if (event.optelHandled) {
372
373
  return;
373
374
  }
374
- sampleRUM('click', { target: targetSelector(event.target), source: sourceSelector(event.target) });
375
+ // eslint-disable-next-line max-len
376
+ sampleRUM('click', { target: targetSelector(event.target), source: sourceSelector(event.target), ...untrustedClickPayload(event) });
375
377
  });
376
378
 
377
379
  // Core tracking
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/helix-rum-enhancer",
3
- "version": "2.48.0",
3
+ "version": "2.49.0",
4
4
  "description": "Helix RUM Enhancer",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -23,6 +23,7 @@ export default function addWebComponentTracking({
23
23
  sampleRUM,
24
24
  sourceSelector,
25
25
  targetSelector,
26
+ untrustedClickPayload,
26
27
  createMO,
27
28
  }) {
28
29
  /**
@@ -90,7 +91,8 @@ export default function addWebComponentTracking({
90
91
  }
91
92
  // eslint-disable-next-line no-param-reassign
92
93
  event.optelHandled = true;
93
- sampleRUM('click', { target: targetSelector(event.target), source: sourceSelector(event.target) });
94
+ // eslint-disable-next-line max-len
95
+ sampleRUM('click', { target: targetSelector(event.target), source: sourceSelector(event.target), ...untrustedClickPayload(event) });
94
96
  });
95
97
  }
96
98
  // look for web components below this element
package/src/index.js CHANGED
@@ -23,7 +23,7 @@
23
23
  a11y: [557, 781, 897, 955, 959]
24
24
  };
25
25
 
26
- const KNOWN_PROPERTIES = ['weight', 'id', 'referer', 'checkpoint', 't', 'source', 'target', 'cwv', 'CLS', 'FID', 'LCP', 'INP', 'TTFB'];
26
+ const KNOWN_PROPERTIES = ['weight', 'id', 'referer', 'checkpoint', 't', 'source', 'target', 'cwv', 'CLS', 'FID', 'LCP', 'INP', 'TTFB', 'ua'];
27
27
  const DEFAULT_TRACKING_EVENTS = ['click', 'cwv', 'form', 'viewblock', 'viewmedia', 'loadresource', 'utm', 'paid', 'email', 'consent'];
28
28
  fflags.enabled('example', () => DEFAULT_TRACKING_EVENTS.push('example'));
29
29
 
@@ -57,11 +57,20 @@
57
57
  return null;
58
58
  }
59
59
  };
60
- function walk(el, checkFn) {
60
+ const untrustedClickPayload = event => {
61
+ if (event && event.isTrusted === false) {
62
+ const ua = navigator.userAgent;
63
+ return {
64
+ ua: ua.includes('+http') ? ua : `${ua} +http://event.untrusted`
65
+ };
66
+ }
67
+ return {};
68
+ };
69
+ function walk(el, check) {
61
70
  if (!el || el === document.body || el === document.documentElement) {
62
71
  return undefined;
63
72
  }
64
- return checkFn(el) || walk(el.parentElement || el.parentNode && el.parentNode.host, checkFn);
73
+ return check(el) || walk(el.parentElement || el.parentNode && el.parentNode.host, check);
65
74
  }
66
75
  function isDialog(el) {
67
76
  const cs = window.getComputedStyle(el);
@@ -72,30 +81,30 @@
72
81
  return true;
73
82
  }
74
83
  if (el.tagName === 'A') {
75
- return Array.from(el.classList).some(className => className.match(/button|cta/));
84
+ return Array.from(el.classList).some(cls => cls.match(/button|cta/));
76
85
  }
77
86
  return el.getAttribute('role') === 'button';
78
87
  }
79
- function getSourceContext(el) {
80
- const formEl = el.closest('form');
81
- if (formEl) {
82
- const id = formEl.getAttribute('id');
88
+ function srcContext(el) {
89
+ const form = el.closest('form');
90
+ if (form) {
91
+ const id = form.getAttribute('id');
83
92
  if (id) {
84
93
  return `form#${CSS.escape(id)}`;
85
94
  }
86
- return `form${formEl.classList.length > 0 ? `.${CSS.escape(formEl.classList[0])}` : ''}`;
95
+ return `form${form.classList.length > 0 ? `.${CSS.escape(form.classList[0])}` : ''}`;
87
96
  }
88
97
  const block = el.closest('.block[data-block-name]');
89
98
  return block && `.${block.getAttribute('data-block-name')}` || walk(el, isDialog) && 'dialog' || walk(el, e => e.tagName && e.tagName.includes('-') && e.tagName.toLowerCase()) || ['nav', 'header', 'footer', 'aside'].find(t => el.closest(t)) || walk(el, e => e.id && `#${CSS.escape(e.id)}`);
90
99
  }
91
- function getSourceElement(el) {
100
+ function srcElement(el) {
92
101
  const f = el.closest('form');
93
102
  if (f && Array.from(f.elements).includes(el)) {
94
103
  return el.tagName.toLowerCase() + (['INPUT', 'BUTTON'].includes(el.tagName) ? `[type='${el.getAttribute('type') || ''}']` : '');
95
104
  }
96
105
  return walk(el, isButton) && 'button' || el.tagName.toLowerCase().match(/^(a|img|video|form)$/) && el.tagName.toLowerCase();
97
106
  }
98
- function getSourceIdentifier(el) {
107
+ function srcId(el) {
99
108
  return el.id && `#${CSS.escape(el.id)}` || el.getAttribute('data-block-name') && `.${el.getAttribute('data-block-name')}` || el.classList.length > 0 && `.${CSS.escape(el.classList[0])}`;
100
109
  }
101
110
  const sourceSelector = el => {
@@ -106,9 +115,9 @@
106
115
  if (el.getAttribute('data-rum-source')) {
107
116
  return el.getAttribute('data-rum-source');
108
117
  }
109
- const ctx = getSourceContext(el.parentElement) || '';
110
- const name = getSourceElement(el) || '';
111
- const id = getSourceIdentifier(el) || '';
118
+ const ctx = srcContext(el.parentElement) || '';
119
+ const name = srcElement(el) || '';
120
+ const id = srcId(el) || '';
112
121
  return `${ctx} ${name}${id}`.trim() || `"${el.textContent.substring(0, 10)}"`;
113
122
  } catch (error) {
114
123
  return null;
@@ -122,19 +131,19 @@
122
131
  } = window.hlx && window.hlx.rum ? window.hlx.rum : {};
123
132
  const createMO = cb => window.MutationObserver ? new MutationObserver(cb) : {};
124
133
  const [blocksMO, mediaMO] = [blocksMCB, mediaMCB].map(createMO);
125
- const hasCookieKey = key => document.cookie.split(';').some(c => c.trim().startsWith(`${key}=`));
126
- const pluginBasePath = new URL(document.currentScript.src).href.replace(/index(\.map)?\.js/, 'plugins');
134
+ const hasCookie = key => document.cookie.split(';').some(c => c.trim().startsWith(`${key}=`));
135
+ const pluginBase = new URL(document.currentScript.src).href.replace(/index(\.map)?\.js/, 'plugins');
127
136
  const CONSENT_PROVIDERS = [{
128
137
  name: 'onetrust',
129
- detect: () => hasCookieKey('OptanonAlertBoxClosed') || document.querySelector('#onetrust-banner-sdk, #onetrust-pc-sdk')
138
+ detect: () => hasCookie('OptanonAlertBoxClosed') || document.querySelector('#onetrust-banner-sdk, #onetrust-pc-sdk')
130
139
  }, {
131
140
  name: 'trustarc',
132
- detect: () => ['notice_gdpr_prefs', 'notice_preferences'].some(hasCookieKey) || document.querySelector('#truste-consent-track')
141
+ detect: () => ['notice_gdpr_prefs', 'notice_preferences'].some(hasCookie) || document.querySelector('#truste-consent-track')
133
142
  }, {
134
143
  name: 'usercentrics',
135
144
  detect: () => window.localStorage.getItem('uc_gcm') || document.querySelector('#usercentrics-root')
136
145
  }];
137
- const getConsentProvider = () => CONSENT_PROVIDERS.find(({
146
+ const getConsent = () => CONSENT_PROVIDERS.find(({
138
147
  detect
139
148
  }) => detect());
140
149
  const bodyChildMO = {
@@ -146,41 +155,41 @@
146
155
  }
147
156
  };
148
157
  const PLUGINS = {
149
- cwv: `${pluginBasePath}/cwv.js`,
150
- a11y: `${pluginBasePath}/a11y.js`,
158
+ cwv: `${pluginBase}/cwv.js`,
159
+ a11y: `${pluginBase}/a11y.js`,
151
160
  form: {
152
- url: `${pluginBasePath}/form.js`,
161
+ url: `${pluginBase}/form.js`,
153
162
  when: () => document.querySelector('form'),
154
163
  isBlockDependent: true,
155
- mutationObserverParams: bodyChildMO
164
+ moParams: bodyChildMO
156
165
  },
157
166
  redirect: {
158
- url: `${pluginBasePath}/redirect.js`,
167
+ url: `${pluginBase}/redirect.js`,
159
168
  when: ({
160
169
  perfEntry: pe,
161
170
  urlParameters: usp
162
171
  }) => pe && (usp.get('redirect_from') || pe.redirectCount > 0 || pe.fetchStart > 50)
163
172
  },
164
173
  video: {
165
- url: `${pluginBasePath}/video.js`,
174
+ url: `${pluginBase}/video.js`,
166
175
  when: () => document.querySelector('video'),
167
176
  isBlockDependent: true
168
177
  },
169
178
  webcomponent: {
170
- url: `${pluginBasePath}/webcomponent.js`,
179
+ url: `${pluginBase}/webcomponent.js`,
171
180
  when: () => [...document.querySelectorAll('*')].some(el => el.tagName && el.tagName.includes('-')),
172
181
  isBlockDependent: true
173
182
  },
174
183
  martech: {
175
- url: `${pluginBasePath}/martech.js`,
184
+ url: `${pluginBase}/martech.js`,
176
185
  when: ({
177
186
  urlParameters
178
187
  }) => urlParameters.size > 0
179
188
  },
180
189
  consent: {
181
- when: () => getConsentProvider(),
190
+ when: () => getConsent(),
182
191
  isBlockDependent: true,
183
- mutationObserverParams: bodyChildMO
192
+ moParams: bodyChildMO
184
193
  }
185
194
  };
186
195
  const MAX_EV = 1023;
@@ -189,10 +198,10 @@
189
198
  if (!window.IntersectionObserver) {
190
199
  return null;
191
200
  }
192
- const observer = new IntersectionObserver(entries => {
201
+ const obs = new IntersectionObserver(entries => {
193
202
  try {
194
203
  entries.filter(e => e.isIntersecting).forEach(e => {
195
- observer.unobserve(e.target);
204
+ obs.unobserve(e.target);
196
205
  const target = targetSelector(e.target);
197
206
  const source = sourceSelector(e.target);
198
207
  if (checkpoint === 'viewmedia') {
@@ -211,14 +220,15 @@
211
220
  });
212
221
  } catch (error) {}
213
222
  });
214
- return observer;
223
+ return obs;
215
224
  }
216
- const PLUGIN_PARAMETERS = {
225
+ const PLUGIN_PARAMS = {
217
226
  context: document.body,
218
227
  fflags,
219
228
  sampleRUM,
220
229
  sourceSelector,
221
230
  targetSelector,
231
+ untrustedClickPayload,
222
232
  getIntersectionObserver,
223
233
  createMO
224
234
  };
@@ -230,36 +240,36 @@
230
240
  ...params,
231
241
  urlParameters: usp
232
242
  })) {
233
- if (plugin.mutationObserverParams && !plugin.isBeingObserved) {
243
+ if (plugin.moParams && !plugin.isBeingObserved) {
234
244
  createPluginMO(key, params, usp);
235
245
  }
236
246
  return null;
237
247
  }
238
248
  if (key === 'consent') {
239
- plugin.url = `${pluginBasePath}/${getConsentProvider().name}.js`;
249
+ plugin.url = `${pluginBase}/${getConsent().name}.js`;
240
250
  }
241
251
  if (!pluginCache.has(key)) {
242
252
  pluginCache.set(key, import(`${plugin.url || plugin}`));
243
253
  }
244
254
  return pluginCache.get(key).then(p => p.default && p.default(params) || typeof p === 'function' && p(params)).catch(() => {});
245
255
  }
246
- function loadPlugins(filter = () => true, params = PLUGIN_PARAMETERS) {
256
+ function loadPlugins(filter = () => true, params = PLUGIN_PARAMS) {
247
257
  Object.entries(PLUGINS).filter(([, plugin]) => filter(plugin)).map(([key]) => loadPlugin(key, params));
248
258
  }
249
259
  function createPluginMO(key, params, usp) {
250
260
  const plugin = PLUGINS[key];
251
- const observer = createMO(() => {
261
+ const obs = createMO(() => {
252
262
  if (plugin.when({
253
263
  urlParameters: usp
254
264
  })) {
255
265
  plugin.isBeingObserved = false;
256
- observer.disconnect();
266
+ obs.disconnect();
257
267
  loadPlugin(key, params);
258
268
  }
259
269
  });
260
- if (observer instanceof MutationObserver) {
270
+ if (obs instanceof MutationObserver) {
261
271
  plugin.isBeingObserved = true;
262
- observer.observe(plugin.mutationObserverParams.target, plugin.mutationObserverParams.options);
272
+ obs.observe(plugin.moParams.target, plugin.moParams.options);
263
273
  }
264
274
  }
265
275
  let maxEvents = MAX_EV;
@@ -326,7 +336,7 @@
326
336
  sampleRUM('enter', payload);
327
337
  }
328
338
  loadPlugin('redirect', {
329
- ...PLUGIN_PARAMETERS,
339
+ ...PLUGIN_PARAMS,
330
340
  perfEntry
331
341
  });
332
342
  };
@@ -339,7 +349,7 @@
339
349
  });
340
350
  }
341
351
  function addLoadResourceTracking() {
342
- const observer = new PerformanceObserver(list => {
352
+ const obs = new PerformanceObserver(list => {
343
353
  try {
344
354
  const entries = list.getEntries();
345
355
  entries.filter(e => !e.responseStatus || e.responseStatus < 400).filter(e => window.location.hostname === new URL(e.name).hostname || fflags.has('allresources')).filter(e => {
@@ -347,10 +357,10 @@
347
357
  pathname,
348
358
  hostname
349
359
  } = new URL(e.name);
350
- const extensionMatch = pathname.match(hostname !== window.location.hostname ? '.*(\\.html$|\\.json|\\.js|graphql|api)' : '.*(\\.plain\\.html$|\\.json|graphql|api)');
360
+ const extMatch = pathname.match(hostname !== window.location.hostname ? '.*(\\.html$|\\.json|\\.js|graphql|api)' : '.*(\\.plain\\.html$|\\.json|graphql|api)');
351
361
  const isDropIn = fflags.has('allresources') && (pathname.includes('__dropins__/storefront-') || pathname.includes('scripts/dropins/storefront-'));
352
362
  const isImage = fflags.has('allresources') && pathname.match(/\.(png|jpe?g|svg)$/i);
353
- return extensionMatch || isDropIn || isImage;
363
+ return extMatch || isDropIn || isImage;
354
364
  }).forEach(e => {
355
365
  sampleRUM('loadresource', {
356
366
  source: e.name,
@@ -365,7 +375,7 @@
365
375
  });
366
376
  } catch (error) {}
367
377
  });
368
- observer.observe({
378
+ obs.observe({
369
379
  type: 'resource',
370
380
  buffered: true
371
381
  });
@@ -392,21 +402,21 @@
392
402
  childList: true
393
403
  });
394
404
  }
395
- function addViewBlockTracking(element) {
396
- const blockobserver = getIntersectionObserver('viewblock');
397
- if (blockobserver) {
398
- const blocks = element.getAttribute('data-block-status') ? [element] : element.querySelectorAll('div[data-block-status="loaded"]');
399
- blocks.forEach(b => blockobserver.observe(b));
405
+ function addViewBlockTracking(el) {
406
+ const blockObs = getIntersectionObserver('viewblock');
407
+ if (blockObs) {
408
+ const blocks = el.getAttribute('data-block-status') ? [el] : el.querySelectorAll('div[data-block-status="loaded"]');
409
+ blocks.forEach(b => blockObs.observe(b));
400
410
  }
401
411
  }
402
412
  const observedMedia = new Set();
403
413
  function addViewMediaTracking(parent) {
404
- const mediaobserver = getIntersectionObserver('viewmedia');
405
- if (mediaobserver) {
414
+ const mediaObs = getIntersectionObserver('viewmedia');
415
+ if (mediaObs) {
406
416
  parent.querySelectorAll('img, video, audio, iframe').forEach(m => {
407
417
  if (!observedMedia.has(m)) {
408
418
  observedMedia.add(m);
409
- mediaobserver.observe(m);
419
+ mediaObs.observe(m);
410
420
  }
411
421
  });
412
422
  }
@@ -417,7 +427,7 @@
417
427
  function blocksMCB(mutations) {
418
428
  mutations.filter(m => m.type === 'attributes' && m.attributeName === 'data-block-status').filter(m => m.target.dataset.blockStatus === 'loaded').forEach(m => {
419
429
  addObserver('form', el => loadPlugins(p => p.isBlockDependent, {
420
- ...PLUGIN_PARAMETERS,
430
+ ...PLUGIN_PARAMS,
421
431
  context: el
422
432
  }), m.target);
423
433
  addObserver('viewblock', addViewBlockTracking, m.target);
@@ -437,7 +447,8 @@
437
447
  }
438
448
  sampleRUM('click', {
439
449
  target: targetSelector(event.target),
440
- source: sourceSelector(event.target)
450
+ source: sourceSelector(event.target),
451
+ ...untrustedClickPayload(event)
441
452
  });
442
453
  });
443
454
  addNavigationTracking();
package/src/index.md5 CHANGED
@@ -1 +1 @@
1
- fa307b6aa9f67e9f3e13a064b9d0d9d1
1
+ 7b41a36b2c1fe6f67ae750a38cc144db
package/src/index.sri CHANGED
@@ -1 +1 @@
1
- sha384-LDEOuwnv1QygFu3bCEAHTg6z4MeF1qxPVmZFOdVyUNmMbptaV4/+WwXyADbV1Uom
1
+ sha384-Bj6YB2m5ENO7H/0f3agpgLqday7DeSX2gyCAHRh0eRjrkzsEKXSIWq6eadByRqut
@@ -1 +1 @@
1
- 4d477d96ade6db3644031c8335095934
1
+ 83098edb2dc04573f9aac3987a7f1bae
@@ -1 +1 @@
1
- b4b27fd1bc3bb7a309c377448c22529c
1
+ 907a29e9b683d52ab45c0fc02038916e
@@ -1 +1 @@
1
- d241929d3af96465ac32a4158c0e0fe8
1
+ ebe320b3bc258db22786d472559793c1
@@ -1 +1 @@
1
- 20d1f82b8a8c89e965f951484f200f35
1
+ 90fa0790108137f0cb4c44345d2e577f
@@ -17,6 +17,7 @@ function addWebComponentTracking({
17
17
  sampleRUM,
18
18
  sourceSelector,
19
19
  targetSelector,
20
+ untrustedClickPayload,
20
21
  createMO
21
22
  }) {
22
23
  function activateMutationObserver(mo, root = document.body) {
@@ -65,7 +66,8 @@ function addWebComponentTracking({
65
66
  event.optelHandled = true;
66
67
  sampleRUM('click', {
67
68
  target: targetSelector(event.target),
68
- source: sourceSelector(event.target)
69
+ source: sourceSelector(event.target),
70
+ ...untrustedClickPayload(event)
69
71
  });
70
72
  });
71
73
  }
@@ -17,6 +17,7 @@ function addWebComponentTracking({
17
17
  sampleRUM,
18
18
  sourceSelector,
19
19
  targetSelector,
20
+ untrustedClickPayload,
20
21
  createMO
21
22
  }) {
22
23
  function activateMutationObserver(mo, root = document.body) {
@@ -65,7 +66,8 @@ function addWebComponentTracking({
65
66
  event.optelHandled = true;
66
67
  sampleRUM('click', {
67
68
  target: targetSelector(event.target),
68
- source: sourceSelector(event.target)
69
+ source: sourceSelector(event.target),
70
+ ...untrustedClickPayload(event)
69
71
  });
70
72
  });
71
73
  }
@@ -82,4 +84,4 @@ function addWebComponentTracking({
82
84
  }
83
85
 
84
86
  export { addWebComponentTracking as default };
85
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViY29tcG9uZW50Lm1hcC5qcyIsInNvdXJjZXMiOlsiLi4vLi4vcGx1Z2lucy93ZWJjb21wb25lbnQuanMiXSwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIENvcHlyaWdodCAyMDI1IEFkb2JlLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogVGhpcyBmaWxlIGlzIGxpY2Vuc2VkIHRvIHlvdSB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLiBZb3UgbWF5IG9idGFpbiBhIGNvcHlcbiAqIG9mIHRoZSBMaWNlbnNlIGF0IGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmUgZGlzdHJpYnV0ZWQgdW5kZXJcbiAqIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUywgV0lUSE9VVCBXQVJSQU5USUVTIE9SIFJFUFJFU0VOVEFUSU9OU1xuICogT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlXG4gKiBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICovXG5cbi8qKiBAdHlwZSB7V2Vha01hcDxIVE1MRWxlbWVudCwgYm9vbGVhbj59ICovXG5jb25zdCBvYnNlcnZlZFdDID0gbmV3IFdlYWtNYXAoKTtcblxuLyoqIEB0eXBlIHtNdXRhdGlvbk9ic2VydmVyJnthY3RpdmU/OmJvb2xlYW59fHVuZGVmaW5lZH0gKi9cbmxldCByb290TU87XG5cbmNvbnN0IGlzVmFsaWRUYWdOYW1lID0gKHRhZ05hbWUpID0+IC9eW2Etel1bYS16MC05XSooPzotW2EtejAtOV0rKSokLy50ZXN0KHRhZ05hbWUudG9Mb3dlckNhc2UoKSk7XG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGFkZFdlYkNvbXBvbmVudFRyYWNraW5nKHtcbiAgY29udGV4dCxcbiAgc2FtcGxlUlVNLFxuICBzb3VyY2VTZWxlY3RvcixcbiAgdGFyZ2V0U2VsZWN0b3IsXG4gIGNyZWF0ZU1PLFxufSkge1xuICAvKipcbiAgICogYWN0aXZhdGUgbXV0YXRpb24gb2JzZXJ2ZXJcbiAgICogQHBhcmFtIHtNdXRhdGlvbk9ic2VydmVyJnthY3RpdmU/OmJvb2xlYW59fSBtb1xuICAgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBbcm9vdD1kb2N1bWVudC5ib2R5XVxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIGZ1bmN0aW9uIGFjdGl2YXRlTXV0YXRpb25PYnNlcnZlcihtbywgcm9vdCA9IGRvY3VtZW50LmJvZHkpIHtcbiAgICAvKiBjOCBpZ25vcmUgbmV4dCAzICovXG4gICAgaWYgKCFtbyB8fCBtby5hY3RpdmUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXBhcmFtLXJlYXNzaWduXG4gICAgbW8uYWN0aXZlID0gdHJ1ZTtcbiAgICBtby5vYnNlcnZlKFxuICAgICAgcm9vdCxcbiAgICAgIHsgc3VidHJlZTogdHJ1ZSwgYXR0cmlidXRlczogZmFsc2UsIGNoaWxkTGlzdDogdHJ1ZSB9LFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogQGNhbGxiYWNrIE11dGF0aW9uQ2FsbGJhY2tcbiAgICogQHBhcmFtIHtNdXRhdGlvblJlY29yZFtdfSBtdXRhdGlvbnNcbiAgICogQHBhcmFtIHtNdXRhdGlvbk9ic2VydmVyfSBvYnNlcnZlclxuICAgKi9cbiAgZnVuY3Rpb24gbXV0YXRpb25DQihtdXRhdGlvbnMpIHtcbiAgICBtdXRhdGlvbnNcbiAgICAgIC5mb3JFYWNoKChtKSA9PiB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11c2UtYmVmb3JlLWRlZmluZVxuICAgICAgICBfYWRkV2ViQ29tcG9uZW50VHJhY2tpbmcobS50YXJnZXQpO1xuICAgICAgfSk7XG4gIH1cblxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZXJzY29yZS1kYW5nbGVcbiAgZnVuY3Rpb24gX2FkZFdlYkNvbXBvbmVudFRyYWNraW5nKG9iaikge1xuICAgIC8qIGM4IGlnbm9yZSBuZXh0IDMgKi9cbiAgICBpZiAoIW9iaikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHsgdGFnTmFtZSB9ID0gb2JqO1xuICAgIGlmICh0YWdOYW1lICYmIHRhZ05hbWUuaW5jbHVkZXMoJy0nKSAmJiBpc1ZhbGlkVGFnTmFtZSh0YWdOYW1lKSkge1xuICAgICAgd2luZG93LmN1c3RvbUVsZW1lbnRzLndoZW5EZWZpbmVkKHRhZ05hbWUudG9Mb3dlckNhc2UoKSlcbiAgICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICAgIGlmIChvYmouc2hhZG93Um9vdCAmJiAhb2JzZXJ2ZWRXQy5oYXMob2JqKSkge1xuICAgICAgICAgICAgb2JzZXJ2ZWRXQy5zZXQob2JqLCB0cnVlKTtcbiAgICAgICAgICAgIGNvbnN0IG1vID0gY3JlYXRlTU8obXV0YXRpb25DQik7XG4gICAgICAgICAgICBhY3RpdmF0ZU11dGF0aW9uT2JzZXJ2ZXIobW8sIG9iai5zaGFkb3dSb290KTtcbiAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlcnNjb3JlLWRhbmdsZSwgbm8tcGFyYW0tcmVhc3NpZ25cbiAgICAgICAgICAgIG9iai5fX29wdGVsTU8gPSBtbztcbiAgICAgICAgICAgIF9hZGRXZWJDb21wb25lbnRUcmFja2luZyhvYmouc2hhZG93Um9vdCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgbGV0IGhhc1NoYWRvd1Jvb3QgPSBmYWxzZTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGhhc1NoYWRvd1Jvb3QgPSBPYmplY3QuZ2V0UHJvdG90eXBlT2Yob2JqKS50b1N0cmluZygpLmluY2x1ZGVzKCdTaGFkb3dSb290Jyk7XG4gICAgICB9IGNhdGNoIChlKSB7IC8qIGRvIG5vdGhpbmcgKi8gfVxuICAgICAgaWYgKGhhc1NoYWRvd1Jvb3QpIHtcbiAgICAgICAgLy8gb2JqIGlzIGEgc2hhZG93Um9vdCwgYWRkIGNsaWNrIHRyYWNraW5nXG4gICAgICAgIG9iai5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIChldmVudCkgPT4ge1xuICAgICAgICAgIGlmIChldmVudC5vcHRlbEhhbmRsZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXBhcmFtLXJlYXNzaWduXG4gICAgICAgICAgZXZlbnQub3B0ZWxIYW5kbGVkID0gdHJ1ZTtcbiAgICAgICAgICBzYW1wbGVSVU0oJ2NsaWNrJywgeyB0YXJnZXQ6IHRhcmdldFNlbGVjdG9yKGV2ZW50LnRhcmdldCksIHNvdXJjZTogc291cmNlU2VsZWN0b3IoZXZlbnQudGFyZ2V0KSB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICAvLyBsb29rIGZvciB3ZWIgY29tcG9uZW50cyBiZWxvdyB0aGlzIGVsZW1lbnRcbiAgICAgIFsuLi5vYmoucXVlcnlTZWxlY3RvckFsbCgnKicpXVxuICAgICAgICAuZmlsdGVyKChlbCkgPT4gZWwudGFnTmFtZSAmJiBlbC50YWdOYW1lLmluY2x1ZGVzKCctJykgJiYgIW9ic2VydmVkV0MuaGFzKGVsKSlcbiAgICAgICAgLmZvckVhY2goKGVsKSA9PiB7XG4gICAgICAgICAgX2FkZFdlYkNvbXBvbmVudFRyYWNraW5nKGVsKTtcbiAgICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgaWYgKCFyb290TU8pIHtcbiAgICByb290TU8gPSBjcmVhdGVNTyhtdXRhdGlvbkNCKTtcbiAgICBhY3RpdmF0ZU11dGF0aW9uT2JzZXJ2ZXIocm9vdE1PKTtcbiAgfVxuICBfYWRkV2ViQ29tcG9uZW50VHJhY2tpbmcoY29udGV4dCk7XG59XG4iXSwibmFtZXMiOlsib2JzZXJ2ZWRXQyIsIldlYWtNYXAiLCJyb290TU8iLCJpc1ZhbGlkVGFnTmFtZSIsInRhZ05hbWUiLCJ0ZXN0IiwidG9Mb3dlckNhc2UiLCJhZGRXZWJDb21wb25lbnRUcmFja2luZyIsImNvbnRleHQiLCJzYW1wbGVSVU0iLCJzb3VyY2VTZWxlY3RvciIsInRhcmdldFNlbGVjdG9yIiwiY3JlYXRlTU8iLCJhY3RpdmF0ZU11dGF0aW9uT2JzZXJ2ZXIiLCJtbyIsInJvb3QiLCJkb2N1bWVudCIsImJvZHkiLCJhY3RpdmUiLCJvYnNlcnZlIiwic3VidHJlZSIsImF0dHJpYnV0ZXMiLCJjaGlsZExpc3QiLCJtdXRhdGlvbkNCIiwibXV0YXRpb25zIiwiZm9yRWFjaCIsIm0iLCJfYWRkV2ViQ29tcG9uZW50VHJhY2tpbmciLCJ0YXJnZXQiLCJvYmoiLCJpbmNsdWRlcyIsIndpbmRvdyIsImN1c3RvbUVsZW1lbnRzIiwid2hlbkRlZmluZWQiLCJ0aGVuIiwic2hhZG93Um9vdCIsImhhcyIsInNldCIsIl9fb3B0ZWxNTyIsImhhc1NoYWRvd1Jvb3QiLCJPYmplY3QiLCJnZXRQcm90b3R5cGVPZiIsInRvU3RyaW5nIiwiZSIsImFkZEV2ZW50TGlzdGVuZXIiLCJldmVudCIsIm9wdGVsSGFuZGxlZCIsInNvdXJjZSIsInF1ZXJ5U2VsZWN0b3JBbGwiLCJmaWx0ZXIiLCJlbCJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFhQSxNQUFNQSxVQUFVLEdBQUcsSUFBSUMsT0FBTyxFQUFFO0FBR2hDLElBQUlDLE1BQU07QUFFVixNQUFNQyxjQUFjLEdBQUlDLE9BQU8sSUFBSyxpQ0FBaUMsQ0FBQ0MsSUFBSSxDQUFDRCxPQUFPLENBQUNF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
87
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViY29tcG9uZW50Lm1hcC5qcyIsInNvdXJjZXMiOlsiLi4vLi4vcGx1Z2lucy93ZWJjb21wb25lbnQuanMiXSwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIENvcHlyaWdodCAyMDI1IEFkb2JlLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogVGhpcyBmaWxlIGlzIGxpY2Vuc2VkIHRvIHlvdSB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLiBZb3UgbWF5IG9idGFpbiBhIGNvcHlcbiAqIG9mIHRoZSBMaWNlbnNlIGF0IGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmUgZGlzdHJpYnV0ZWQgdW5kZXJcbiAqIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUywgV0lUSE9VVCBXQVJSQU5USUVTIE9SIFJFUFJFU0VOVEFUSU9OU1xuICogT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlXG4gKiBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICovXG5cbi8qKiBAdHlwZSB7V2Vha01hcDxIVE1MRWxlbWVudCwgYm9vbGVhbj59ICovXG5jb25zdCBvYnNlcnZlZFdDID0gbmV3IFdlYWtNYXAoKTtcblxuLyoqIEB0eXBlIHtNdXRhdGlvbk9ic2VydmVyJnthY3RpdmU/OmJvb2xlYW59fHVuZGVmaW5lZH0gKi9cbmxldCByb290TU87XG5cbmNvbnN0IGlzVmFsaWRUYWdOYW1lID0gKHRhZ05hbWUpID0+IC9eW2Etel1bYS16MC05XSooPzotW2EtejAtOV0rKSokLy50ZXN0KHRhZ05hbWUudG9Mb3dlckNhc2UoKSk7XG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGFkZFdlYkNvbXBvbmVudFRyYWNraW5nKHtcbiAgY29udGV4dCxcbiAgc2FtcGxlUlVNLFxuICBzb3VyY2VTZWxlY3RvcixcbiAgdGFyZ2V0U2VsZWN0b3IsXG4gIHVudHJ1c3RlZENsaWNrUGF5bG9hZCxcbiAgY3JlYXRlTU8sXG59KSB7XG4gIC8qKlxuICAgKiBhY3RpdmF0ZSBtdXRhdGlvbiBvYnNlcnZlclxuICAgKiBAcGFyYW0ge011dGF0aW9uT2JzZXJ2ZXIme2FjdGl2ZT86Ym9vbGVhbn19IG1vXG4gICAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IFtyb290PWRvY3VtZW50LmJvZHldXG4gICAqIEByZXR1cm5zIHt2b2lkfVxuICAgKi9cbiAgZnVuY3Rpb24gYWN0aXZhdGVNdXRhdGlvbk9ic2VydmVyKG1vLCByb290ID0gZG9jdW1lbnQuYm9keSkge1xuICAgIC8qIGM4IGlnbm9yZSBuZXh0IDMgKi9cbiAgICBpZiAoIW1vIHx8IG1vLmFjdGl2ZSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tcGFyYW0tcmVhc3NpZ25cbiAgICBtby5hY3RpdmUgPSB0cnVlO1xuICAgIG1vLm9ic2VydmUoXG4gICAgICByb290LFxuICAgICAgeyBzdWJ0cmVlOiB0cnVlLCBhdHRyaWJ1dGVzOiBmYWxzZSwgY2hpbGRMaXN0OiB0cnVlIH0sXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAY2FsbGJhY2sgTXV0YXRpb25DYWxsYmFja1xuICAgKiBAcGFyYW0ge011dGF0aW9uUmVjb3JkW119IG11dGF0aW9uc1xuICAgKiBAcGFyYW0ge011dGF0aW9uT2JzZXJ2ZXJ9IG9ic2VydmVyXG4gICAqL1xuICBmdW5jdGlvbiBtdXRhdGlvbkNCKG11dGF0aW9ucykge1xuICAgIG11dGF0aW9uc1xuICAgICAgLmZvckVhY2goKG0pID0+IHtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVzZS1iZWZvcmUtZGVmaW5lXG4gICAgICAgIF9hZGRXZWJDb21wb25lbnRUcmFja2luZyhtLnRhcmdldCk7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlcnNjb3JlLWRhbmdsZVxuICBmdW5jdGlvbiBfYWRkV2ViQ29tcG9uZW50VHJhY2tpbmcob2JqKSB7XG4gICAgLyogYzggaWdub3JlIG5leHQgMyAqL1xuICAgIGlmICghb2JqKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgeyB0YWdOYW1lIH0gPSBvYmo7XG4gICAgaWYgKHRhZ05hbWUgJiYgdGFnTmFtZS5pbmNsdWRlcygnLScpICYmIGlzVmFsaWRUYWdOYW1lKHRhZ05hbWUpKSB7XG4gICAgICB3aW5kb3cuY3VzdG9tRWxlbWVudHMud2hlbkRlZmluZWQodGFnTmFtZS50b0xvd2VyQ2FzZSgpKVxuICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgaWYgKG9iai5zaGFkb3dSb290ICYmICFvYnNlcnZlZFdDLmhhcyhvYmopKSB7XG4gICAgICAgICAgICBvYnNlcnZlZFdDLnNldChvYmosIHRydWUpO1xuICAgICAgICAgICAgY29uc3QgbW8gPSBjcmVhdGVNTyhtdXRhdGlvbkNCKTtcbiAgICAgICAgICAgIGFjdGl2YXRlTXV0YXRpb25PYnNlcnZlcihtbywgb2JqLnNoYWRvd1Jvb3QpO1xuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVyc2NvcmUtZGFuZ2xlLCBuby1wYXJhbS1yZWFzc2lnblxuICAgICAgICAgICAgb2JqLl9fb3B0ZWxNTyA9IG1vO1xuICAgICAgICAgICAgX2FkZFdlYkNvbXBvbmVudFRyYWNraW5nKG9iai5zaGFkb3dSb290KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBsZXQgaGFzU2hhZG93Um9vdCA9IGZhbHNlO1xuICAgICAgdHJ5IHtcbiAgICAgICAgaGFzU2hhZG93Um9vdCA9IE9iamVjdC5nZXRQcm90b3R5cGVPZihvYmopLnRvU3RyaW5nKCkuaW5jbHVkZXMoJ1NoYWRvd1Jvb3QnKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHsgLyogZG8gbm90aGluZyAqLyB9XG4gICAgICBpZiAoaGFzU2hhZG93Um9vdCkge1xuICAgICAgICAvLyBvYmogaXMgYSBzaGFkb3dSb290LCBhZGQgY2xpY2sgdHJhY2tpbmdcbiAgICAgICAgb2JqLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgaWYgKGV2ZW50Lm9wdGVsSGFuZGxlZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tcGFyYW0tcmVhc3NpZ25cbiAgICAgICAgICBldmVudC5vcHRlbEhhbmRsZWQgPSB0cnVlO1xuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtbGVuXG4gICAgICAgICAgc2FtcGxlUlVNKCdjbGljaycsIHsgdGFyZ2V0OiB0YXJnZXRTZWxlY3RvcihldmVudC50YXJnZXQpLCBzb3VyY2U6IHNvdXJjZVNlbGVjdG9yKGV2ZW50LnRhcmdldCksIC4uLnVudHJ1c3RlZENsaWNrUGF5bG9hZChldmVudCkgfSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgLy8gbG9vayBmb3Igd2ViIGNvbXBvbmVudHMgYmVsb3cgdGhpcyBlbGVtZW50XG4gICAgICBbLi4ub2JqLnF1ZXJ5U2VsZWN0b3JBbGwoJyonKV1cbiAgICAgICAgLmZpbHRlcigoZWwpID0+IGVsLnRhZ05hbWUgJiYgZWwudGFnTmFtZS5pbmNsdWRlcygnLScpICYmICFvYnNlcnZlZFdDLmhhcyhlbCkpXG4gICAgICAgIC5mb3JFYWNoKChlbCkgPT4ge1xuICAgICAgICAgIF9hZGRXZWJDb21wb25lbnRUcmFja2luZyhlbCk7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIGlmICghcm9vdE1PKSB7XG4gICAgcm9vdE1PID0gY3JlYXRlTU8obXV0YXRpb25DQik7XG4gICAgYWN0aXZhdGVNdXRhdGlvbk9ic2VydmVyKHJvb3RNTyk7XG4gIH1cbiAgX2FkZFdlYkNvbXBvbmVudFRyYWNraW5nKGNvbnRleHQpO1xufVxuIl0sIm5hbWVzIjpbIm9ic2VydmVkV0MiLCJXZWFrTWFwIiwicm9vdE1PIiwiaXNWYWxpZFRhZ05hbWUiLCJ0YWdOYW1lIiwidGVzdCIsInRvTG93ZXJDYXNlIiwiYWRkV2ViQ29tcG9uZW50VHJhY2tpbmciLCJjb250ZXh0Iiwic2FtcGxlUlVNIiwic291cmNlU2VsZWN0b3IiLCJ0YXJnZXRTZWxlY3RvciIsInVudHJ1c3RlZENsaWNrUGF5bG9hZCIsImNyZWF0ZU1PIiwiYWN0aXZhdGVNdXRhdGlvbk9ic2VydmVyIiwibW8iLCJyb290IiwiZG9jdW1lbnQiLCJib2R5IiwiYWN0aXZlIiwib2JzZXJ2ZSIsInN1YnRyZWUiLCJhdHRyaWJ1dGVzIiwiY2hpbGRMaXN0IiwibXV0YXRpb25DQiIsIm11dGF0aW9ucyIsImZvckVhY2giLCJtIiwiX2FkZFdlYkNvbXBvbmVudFRyYWNraW5nIiwidGFyZ2V0Iiwib2JqIiwiaW5jbHVkZXMiLCJ3aW5kb3ciLCJjdXN0b21FbGVtZW50cyIsIndoZW5EZWZpbmVkIiwidGhlbiIsInNoYWRvd1Jvb3QiLCJoYXMiLCJzZXQiLCJfX29wdGVsTU8iLCJoYXNTaGFkb3dSb290IiwiT2JqZWN0IiwiZ2V0UHJvdG90eXBlT2YiLCJ0b1N0cmluZyIsImUiLCJhZGRFdmVudExpc3RlbmVyIiwiZXZlbnQiLCJvcHRlbEhhbmRsZWQiLCJzb3VyY2UiLCJxdWVyeVNlbGVjdG9yQWxsIiwiZmlsdGVyIiwiZWwiXSwibWFwcGluZ3MiOiI7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
@@ -1 +1 @@
1
- 3476ee246a6b4c1599651d8a7580e2c7
1
+ 1971ead6d6bc23d0eee1ff5705b6fc48