@adobe/spacecat-shared-rum-api-client 2.23.4 → 2.24.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.24.1](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-rum-api-client-v2.24.0...@adobe/spacecat-shared-rum-api-client-v2.24.1) (2025-05-10)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **deps:** update adobe fixes ([#727](https://github.com/adobe/spacecat-shared/issues/727)) ([590b973](https://github.com/adobe/spacecat-shared/commit/590b973f01f2dba697250ab4769106d06a908d98))
7
+
8
+ # [@adobe/spacecat-shared-rum-api-client-v2.24.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-rum-api-client-v2.23.4...@adobe/spacecat-shared-rum-api-client-v2.24.0) (2025-05-09)
9
+
10
+
11
+ ### Features
12
+
13
+ * identify iframe forms ([#715](https://github.com/adobe/spacecat-shared/issues/715)) ([d2e0a47](https://github.com/adobe/spacecat-shared/commit/d2e0a47f1020471a6f22f9d713e6bf9c03df2279))
14
+
1
15
  # [@adobe/spacecat-shared-rum-api-client-v2.23.4](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-rum-api-client-v2.23.3...@adobe/spacecat-shared-rum-api-client-v2.23.4) (2025-04-30)
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.23.4",
3
+ "version": "2.24.1",
4
4
  "description": "Shared modules of the Spacecat Services - Rum API client",
5
5
  "type": "module",
6
6
  "engines": {
@@ -35,7 +35,7 @@
35
35
  "access": "public"
36
36
  },
37
37
  "dependencies": {
38
- "@adobe/fetch": "4.2.0",
38
+ "@adobe/fetch": "4.2.1",
39
39
  "@adobe/helix-shared-wrap": "2.0.2",
40
40
  "@adobe/helix-universal": "5.2.0",
41
41
  "@adobe/spacecat-shared-utils": "1.26.4",
@@ -14,7 +14,7 @@ import { DataChunks } from '@adobe/rum-distiller';
14
14
  import { generateKey, DELIMITER, loadBundles } from '../utils.js';
15
15
 
16
16
  const METRICS = ['formview', 'formengagement', 'formsubmit'];
17
- const CHECKPOINTS = ['viewblock', 'click', 'fill', 'formsubmit', 'navigate'];
17
+ const CHECKPOINTS = ['viewblock', 'click', 'fill', 'formsubmit', 'navigate', 'viewmedia'];
18
18
  const KEYWORDS_TO_FILTER = ['search'];
19
19
 
20
20
  function initializeResult(url) {
@@ -41,7 +41,7 @@ function filterEvents(bundles) {
41
41
  }
42
42
 
43
43
  const isFormRelatedEvent = ['fill', 'formsubmit'].includes(event.checkpoint)
44
- || /\bform\b/.test(event.source);
44
+ || /\bform\b|aemform\w*/i.test(event.source);
45
45
  return isFormRelatedEvent && !KEYWORDS_TO_FILTER.some((keyword) => event.source
46
46
  && event.source.toLowerCase().includes(keyword));
47
47
  }),
@@ -82,6 +82,7 @@ function populateFormsInternalNavigation(bundles, formVitals) {
82
82
  dataChunks.filter = { checkpoint: ['navigate'] };
83
83
  dataChunks.filtered.forEach((bundle) => {
84
84
  const formInternalNav = bundle.events.find((e) => e.checkpoint === 'navigate');
85
+
85
86
  const formVital = findByUrl(formVitals, bundle.url);
86
87
  if (formInternalNav && formVital
87
88
  && !formVital.forminternalnavigation
@@ -133,8 +134,58 @@ function containsFormVitals(row) {
133
134
  return METRICS.some((metric) => Object.keys(row[metric]).length > 0);
134
135
  }
135
136
 
137
+ function getParentPageVitalsGroupedByIFrame(bundles, dataChunks, iframeParentMap) {
138
+ const iframeVitals = {};
139
+ if (dataChunks.facets.urlUserAgents) {
140
+ dataChunks.facets.urlUserAgents.reduce((acc, { value, weight }) => {
141
+ const [url, userAgent] = value.split(DELIMITER);
142
+
143
+ let iframeSrc = null;
144
+ for (const iframeUrl of Object.keys(iframeParentMap)) {
145
+ for (const parentUrl of iframeParentMap[iframeUrl]) {
146
+ if (parentUrl === url) {
147
+ iframeSrc = iframeUrl;
148
+ break;
149
+ }
150
+ }
151
+ }
152
+ if (iframeSrc) {
153
+ acc[url] = acc[url] || { url, pageview: {}, forminternalnavigation: [] };
154
+ acc[url].pageview[userAgent] = acc[url].pageview[userAgent] || weight;
155
+ acc[url].iframeSrc = iframeSrc;
156
+ }
157
+ return acc;
158
+ }, iframeVitals);
159
+ }
160
+ const groupedByIframeSrc = {};
161
+ const parentWebVitals = {};
162
+
163
+ // select the parent page with the most views
164
+ for (const [url, obj] of Object.entries(iframeVitals)) {
165
+ const { iframeSrc } = obj;
166
+ const totalViews = (obj.pageview.mobile || 0) + (obj.pageview.desktop || 0);
167
+ if (!groupedByIframeSrc[iframeSrc] || totalViews > groupedByIframeSrc[iframeSrc].totalViews) {
168
+ groupedByIframeSrc[iframeSrc] = { url, totalViews };
169
+ }
170
+ }
171
+
172
+ for (const { url } of Object.values(groupedByIframeSrc)) {
173
+ parentWebVitals[url] = iframeVitals[url];
174
+ }
175
+
176
+ populateFormsInternalNavigation(bundles, parentWebVitals);
177
+ findFormCTAForInternalNavigation(bundles, Object.values(parentWebVitals));
178
+
179
+ const iframeParentVitalsMap = {};
180
+ for (const vitals of Object.values(parentWebVitals)) {
181
+ iframeParentVitalsMap[vitals.iframeSrc] = vitals;
182
+ }
183
+ return iframeParentVitalsMap;
184
+ }
185
+
136
186
  function handler(bundles) {
137
187
  // Filter out search related events
188
+
138
189
  const bundlesWithFilteredEvents = filterEvents(bundles);
139
190
 
140
191
  const dataChunks = new DataChunks();
@@ -143,17 +194,26 @@ function handler(bundles) {
143
194
  const formViewdataChunks = new DataChunks();
144
195
  loadBundles(bundlesWithFilteredEvents, formViewdataChunks);
145
196
  const formSourceMap = {};
197
+ const iframeParentMap = {};
146
198
  const globalFormSourceSet = new Set();
147
- formViewdataChunks.filter = { checkpoint: ['viewblock'] };
199
+ formViewdataChunks.filter = { checkpoint: ['viewblock', 'viewmedia'] };
148
200
  formViewdataChunks.filtered.forEach(({ url, events }) => {
149
201
  formSourceMap[url] = formSourceMap[url] || new Set();
150
- events.forEach(({ checkpoint, source }) => {
202
+ events.forEach(({ checkpoint, source, target }) => {
151
203
  if (checkpoint === 'viewblock' && source) {
152
204
  formSourceMap[url].add(source);
153
205
  globalFormSourceSet.add(source);
154
206
  }
207
+ if (checkpoint === 'viewmedia' && target) {
208
+ const regex = /aemform[\w.]*\.iframe[\w.]*/;
209
+ if (regex.test(target)) {
210
+ iframeParentMap[target] = iframeParentMap[target] || new Set();
211
+ iframeParentMap[target].add(url);
212
+ }
213
+ }
155
214
  });
156
215
  });
216
+
157
217
  // traffic acquisition data per url - uncomment this when required
158
218
  // const trafficByUrl = trafficAcquisition.handler(bundles);
159
219
  // const trafficByUrlMap = Object.fromEntries(
@@ -192,12 +252,41 @@ function handler(bundles) {
192
252
  return acc;
193
253
  }, formVitals);
194
254
  });
255
+
256
+ const iframeParentVitalsMap = getParentPageVitalsGroupedByIFrame(
257
+ bundles,
258
+ dataChunks,
259
+ iframeParentMap,
260
+ );
261
+
195
262
  // populate internal navigation data
196
263
  populateFormsInternalNavigation(bundles, formVitals);
197
264
  // filter out pages with no form vitals
198
265
  const filteredFormVitals = Object.values(formVitals).filter(containsFormVitals);
199
266
  findFormCTAForInternalNavigation(bundles, filteredFormVitals);
200
- return filteredFormVitals;
267
+
268
+ const updatedFormVitals = filteredFormVitals.map((formVital) => {
269
+ const formVitalCopy = { ...formVital };
270
+ const parentFormVital = iframeParentVitalsMap[formVital.url];
271
+ if (parentFormVital) {
272
+ const {
273
+ url,
274
+ pageview,
275
+ forminternalnavigation,
276
+ iframeSrc,
277
+ } = parentFormVital;
278
+ Object.assign(formVitalCopy, {
279
+ url,
280
+ pageview: { ...pageview },
281
+ forminternalnavigation,
282
+
283
+ iframeSrc,
284
+ });
285
+ }
286
+ return formVitalCopy;
287
+ });
288
+
289
+ return [...updatedFormVitals];
201
290
  }
202
291
 
203
292
  export default {