@adobe/spacecat-shared-rum-api-client 2.22.6 → 2.23.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # [@adobe/spacecat-shared-rum-api-client-v2.23.1](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-rum-api-client-v2.23.0...@adobe/spacecat-shared-rum-api-client-v2.23.1) (2025-04-25)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * eliminating unnecessary data from forms vitals ([#704](https://github.com/adobe/spacecat-shared/issues/704)) ([29be01e](https://github.com/adobe/spacecat-shared/commit/29be01e5d77d41b728a013a4b5532d06a08f7b2c))
7
+
8
+ # [@adobe/spacecat-shared-rum-api-client-v2.23.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-rum-api-client-v2.22.6...@adobe/spacecat-shared-rum-api-client-v2.23.0) (2025-04-16)
9
+
10
+
11
+ ### Features
12
+
13
+ * formsource wise segregation of audit result ([#692](https://github.com/adobe/spacecat-shared/issues/692)) ([0f4f503](https://github.com/adobe/spacecat-shared/commit/0f4f503facbd81538a0d445a462735766e7bfffa))
14
+
1
15
  # [@adobe/spacecat-shared-rum-api-client-v2.22.6](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-rum-api-client-v2.22.5...@adobe/spacecat-shared-rum-api-client-v2.22.6) (2025-04-15)
2
16
 
3
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-rum-api-client",
3
- "version": "2.22.6",
3
+ "version": "2.23.1",
4
4
  "description": "Shared modules of the Spacecat Services - Rum API client",
5
5
  "type": "module",
6
6
  "engines": {
@@ -11,11 +11,9 @@
11
11
  */
12
12
 
13
13
  import { DataChunks } from '@adobe/rum-distiller';
14
- import trafficAcquisition from './traffic-acquisition.js';
15
14
  import { generateKey, DELIMITER, loadBundles } from '../utils.js';
16
15
 
17
- const FORM_SOURCE = [/\bform\b/, /\.marketo/];
18
- const METRICS = ['formview', 'formengagement', 'formsubmit', 'formbuttonclick'];
16
+ const METRICS = ['formview', 'formengagement', 'formsubmit'];
19
17
  const CHECKPOINTS = ['viewblock', 'click', 'fill', 'formsubmit', 'navigate'];
20
18
  const KEYWORDS_TO_FILTER = ['search'];
21
19
 
@@ -25,7 +23,6 @@ function initializeResult(url) {
25
23
  formsubmit: {},
26
24
  formview: {},
27
25
  formengagement: {},
28
- formbuttonclick: {},
29
26
  pageview: {},
30
27
  forminternalnavigation: [],
31
28
  };
@@ -51,39 +48,48 @@ function filterEvents(bundles) {
51
48
  }));
52
49
  }
53
50
 
51
+ function isFormSource(source, eventSource) {
52
+ const excludeSrc = ['form.', 'form#'];
53
+ if (source === 'unknown') {
54
+ return /\bform\b/.test(eventSource?.toLowerCase()) && !excludeSrc.some((exclude) => eventSource?.includes(exclude));
55
+ } else {
56
+ return eventSource?.includes(source);
57
+ }
58
+ }
59
+
54
60
  const metricFns = {
55
- formview: (bundle) => {
56
- const formView = bundle.events.find((e) => e.checkpoint === 'viewblock' && FORM_SOURCE.some((regex) => regex.test(e.source)));
61
+ formview: (source) => (bundle) => {
62
+ const formView = bundle.events.find((e) => e.checkpoint === 'viewblock' && isFormSource(source, e.source));
57
63
  return formView ? bundle.weight : 0;
58
64
  },
59
- formengagement: (bundle) => {
60
- const formClick = bundle.events.find((e) => e.checkpoint === 'click' && e.source && /\bform\b/.test(e.source.toLowerCase()));
65
+ formengagement: (source) => (bundle) => {
66
+ const formClick = bundle.events.find((e) => (e.checkpoint === 'click' || e.checkpoint === 'fill') && isFormSource(source, e.source));
61
67
  return formClick ? bundle.weight : 0;
62
68
  },
63
- formsubmit: (bundle) => {
64
- const formSubmit = bundle.events.find((e) => e.checkpoint === 'formsubmit');
69
+ formsubmit: (source) => (bundle) => {
70
+ const formSubmit = bundle.events.find((e) => e.checkpoint === 'formsubmit' && isFormSource(source, e.source));
65
71
  return formSubmit ? bundle.weight : 0;
66
72
  },
67
- formbuttonclick: (bundle) => {
68
- const formButtonClick = bundle.events.find((e) => e.checkpoint === 'click' && e.source
69
- && /\bform\b/.test(e.source.toLowerCase())
70
- && /\bbutton\b/.test(e.source.toLowerCase()));
71
- return formButtonClick ? bundle.weight : 0;
72
- },
73
73
  };
74
74
 
75
+ function findByUrl(formVitals, url) {
76
+ return Object.values(formVitals).find((item) => item.url === url);
77
+ }
78
+
75
79
  function populateFormsInternalNavigation(bundles, formVitals) {
76
80
  const dataChunks = new DataChunks();
77
81
  loadBundles(bundles, dataChunks);
78
82
  dataChunks.filter = { checkpoint: ['navigate'] };
79
83
  dataChunks.filtered.forEach((bundle) => {
80
- const forminternalnavigation = bundle.events.find((e) => e.checkpoint === 'navigate');
81
- if (forminternalnavigation && formVitals[bundle.url]
82
- && !formVitals[bundle.url].forminternalnavigation
83
- .some((e) => e.url === forminternalnavigation.source)) {
84
- formVitals[bundle.url].forminternalnavigation.push({
85
- url: forminternalnavigation.source,
86
- pageview: formVitals[forminternalnavigation.source]?.pageview || null,
84
+ const formInternalNav = bundle.events.find((e) => e.checkpoint === 'navigate');
85
+ const formVital = findByUrl(formVitals, bundle.url);
86
+ if (formInternalNav && formVital
87
+ && !formVital.forminternalnavigation
88
+ .some((e) => e.url === formInternalNav.source)) {
89
+ const fv = findByUrl(formVitals, formInternalNav.source);
90
+ formVital.forminternalnavigation.push({
91
+ url: formInternalNav.source,
92
+ pageview: fv?.pageview,
87
93
  });
88
94
  }
89
95
  });
@@ -134,34 +140,50 @@ function handler(bundles) {
134
140
  const dataChunks = new DataChunks();
135
141
  loadBundles(bundlesWithFilteredEvents, dataChunks);
136
142
 
137
- // groups by url and user agent
138
- dataChunks.addFacet('urlUserAgents', (bundle) => generateKey(bundle.url, bundle.userAgent));
139
-
140
- // counts metrics per each group
141
- METRICS.forEach((metric) => dataChunks.addSeries(metric, metricFns[metric]));
142
-
143
- // traffic acquisition data per url
144
- const trafficByUrl = trafficAcquisition.handler(bundles);
145
- const trafficByUrlMap = Object.fromEntries(
146
- trafficByUrl.map(({ url, ...item }) => [url, item]),
147
- );
148
-
149
- // aggregates metrics per group (url and user agent)
150
- const formVitals = dataChunks.facets.urlUserAgents.reduce((acc, { value, metrics, weight }) => {
151
- const [url, userAgent] = value.split(DELIMITER);
152
-
153
- acc[url] = acc[url] || initializeResult(url);
154
- acc[url].pageview[userAgent] = weight;
155
- acc[url].trafficacquisition = trafficByUrlMap[url];
156
-
157
- METRICS.filter((metric) => metrics[metric].sum) // filter out user-agents with no form vitals
158
- .forEach((metric) => {
159
- acc[url][metric][userAgent] = metrics[metric].sum;
160
- });
161
-
162
- return acc;
163
- }, {});
164
-
143
+ const formViewdataChunks = new DataChunks();
144
+ loadBundles(bundlesWithFilteredEvents, formViewdataChunks);
145
+ const formSourceMap = {};
146
+ const globalFormSourceSet = new Set();
147
+ formViewdataChunks.filter = { checkpoint: ['viewblock'] };
148
+ formViewdataChunks.filtered.forEach(({ url, events }) => {
149
+ formSourceMap[url] = formSourceMap[url] || new Set();
150
+ events.forEach(({ checkpoint, source }) => {
151
+ if (checkpoint === 'viewblock' && source) {
152
+ formSourceMap[url].add(source);
153
+ globalFormSourceSet.add(source);
154
+ }
155
+ });
156
+ });
157
+ // traffic acquisition data per url - uncomment this when required
158
+ // const trafficByUrl = trafficAcquisition.handler(bundles);
159
+ // const trafficByUrlMap = Object.fromEntries(
160
+ // trafficByUrl.map(({ url, ...item }) => [url, item]),
161
+ // );
162
+ const formVitals = {};
163
+
164
+ globalFormSourceSet.forEach((source) => {
165
+ // counts metrics per each group
166
+ const match = source.match(/form[#.](\w+)/);
167
+ const formsource = match ? match[1] : 'unknown';
168
+ // groups by url and user agent
169
+ dataChunks.addFacet('urlUserAgents', (bundle) => generateKey(bundle.url, bundle.userAgent));
170
+ METRICS.forEach((metric) => dataChunks.addSeries(metric, metricFns[metric](formsource)));
171
+ // aggregates metrics per group (url and user agent)
172
+ dataChunks.facets.urlUserAgents.reduce((acc, { value, metrics, weight }) => {
173
+ const [url, userAgent] = value.split(DELIMITER);
174
+ const key = formSourceMap[url].has(source) ? generateKey(url, source) : url;
175
+ acc[key] = acc[key] || initializeResult(url);
176
+ acc[key].pageview[userAgent] = acc[key].pageview[userAgent] || weight;
177
+ // Enable traffic acquisition for persistence by uncommenting this line
178
+ // acc[key].trafficacquisition = trafficByUrlMap[url];
179
+ acc[key].formsource = source;
180
+ METRICS.filter((metric) => metrics[metric].sum) // filter out user-agents with no form vitals
181
+ .forEach((metric) => {
182
+ acc[key][metric][userAgent] = metrics[metric].sum;
183
+ });
184
+ return acc;
185
+ }, formVitals);
186
+ });
165
187
  // populate internal navigation data
166
188
  populateFormsInternalNavigation(bundles, formVitals);
167
189
  // filter out pages with no form vitals