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