@adobe/spacecat-shared-utils 1.29.0 → 1.30.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 +14 -0
- package/package.json +2 -2
- package/src/formcalc.js +98 -0
- package/src/index.d.ts +19 -2
- package/src/index.js +1 -1
- package/src/url-helpers.js +14 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [@adobe/spacecat-shared-utils-v1.30.1](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.30.0...@adobe/spacecat-shared-utils-v1.30.1) (2025-02-06)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* composeAuditURL user agent failing for some sites ([#583](https://github.com/adobe/spacecat-shared/issues/583)) ([81bd136](https://github.com/adobe/spacecat-shared/commit/81bd136693ded29130b73b1c0258b6727104f5e1))
|
|
7
|
+
|
|
8
|
+
# [@adobe/spacecat-shared-utils-v1.30.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.29.0...@adobe/spacecat-shared-utils-v1.30.0) (2025-02-06)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* adding more opportunities utils for forms ([#580](https://github.com/adobe/spacecat-shared/issues/580)) ([4cb7d5d](https://github.com/adobe/spacecat-shared/commit/4cb7d5d94ff887932809416b3cf918fc3b56a58d))
|
|
14
|
+
|
|
1
15
|
# [@adobe/spacecat-shared-utils-v1.29.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.28.4...@adobe/spacecat-shared-utils-v1.29.0) (2025-02-03)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/spacecat-shared-utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.30.1",
|
|
4
4
|
"description": "Shared modules of the Spacecat Services - utils",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"chai": "5.1.2",
|
|
40
40
|
"chai-as-promised": "8.0.1",
|
|
41
41
|
"husky": "9.1.7",
|
|
42
|
-
"nock": "
|
|
42
|
+
"nock": "14.0.0",
|
|
43
43
|
"sinon": "19.0.2",
|
|
44
44
|
"sinon-chai": "4.0.0"
|
|
45
45
|
},
|
package/src/formcalc.js
CHANGED
|
@@ -68,6 +68,16 @@ function hasLowerConversionRate(formSubmit, formViews) {
|
|
|
68
68
|
return formSubmit / formViews < CR_THRESHOLD_RATIO;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
function hasLowFormViews(pageViews, formViews) {
|
|
72
|
+
return formViews > 0 && (formViews / pageViews) < 0.7;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function hasHighPageViewLowFormCtr(ctaPageViews, ctaClicks, ctaPageTotalClicks, formPageViews) {
|
|
76
|
+
return ctaPageTotalClicks > 0
|
|
77
|
+
&& (ctaClicks / ctaPageTotalClicks) < 0.4
|
|
78
|
+
&& (formPageViews / ctaPageViews) < 0.1;
|
|
79
|
+
}
|
|
80
|
+
|
|
71
81
|
/**
|
|
72
82
|
* Returns the form urls with high form views and low conversion rate
|
|
73
83
|
*
|
|
@@ -96,3 +106,91 @@ export function getHighFormViewsLowConversionMetrics(formVitalsCollection, inter
|
|
|
96
106
|
});
|
|
97
107
|
return urls;
|
|
98
108
|
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Returns the form urls with high page views and low form views
|
|
112
|
+
*
|
|
113
|
+
* @param resultMap
|
|
114
|
+
* @returns {*[]}
|
|
115
|
+
*/
|
|
116
|
+
export function getHighPageViewsLowFormViewsMetrics(formVitalsCollection, interval) {
|
|
117
|
+
const urls = [];
|
|
118
|
+
const resultMap = aggregateFormVitalsByDevice(formVitalsCollection);
|
|
119
|
+
resultMap.forEach((metrics, url) => {
|
|
120
|
+
const { total: pageViews } = metrics.pageview;
|
|
121
|
+
const { total: formViews } = metrics.formview;
|
|
122
|
+
const { total: formEngagement } = metrics.formengagement;
|
|
123
|
+
|
|
124
|
+
if (hasHighPageViews(interval, pageViews) && hasLowFormViews(pageViews, formViews)) {
|
|
125
|
+
urls.push({
|
|
126
|
+
url,
|
|
127
|
+
pageViews,
|
|
128
|
+
formViews,
|
|
129
|
+
formEngagement,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
return urls;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Returns the form urls with high page views containing ctr and low form views
|
|
138
|
+
* @param formVitalsCollection
|
|
139
|
+
* @param formVitalsByDevice
|
|
140
|
+
* @returns {*[]}
|
|
141
|
+
*/
|
|
142
|
+
export function getHighPageViewsLowFormCtrMetrics(formVitalsCollection, interval) {
|
|
143
|
+
const urls = [];
|
|
144
|
+
const formVitalsByDevice = aggregateFormVitalsByDevice(formVitalsCollection);
|
|
145
|
+
formVitalsCollection.forEach((entry) => {
|
|
146
|
+
const { forminternalnavigation, pageview } = entry;
|
|
147
|
+
// Calculate `x`: sum of pageview for the URL with the highest sum
|
|
148
|
+
let x = 0;
|
|
149
|
+
let maxPageviewUrl = null;
|
|
150
|
+
if (forminternalnavigation) {
|
|
151
|
+
forminternalnavigation.forEach((nav) => {
|
|
152
|
+
if (nav.pageview) {
|
|
153
|
+
const pageviewSum = Object.values(nav.pageview).reduce((sum, val) => sum + val, 0);
|
|
154
|
+
if (pageviewSum > x) {
|
|
155
|
+
x = pageviewSum;
|
|
156
|
+
maxPageviewUrl = nav;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Skip entry if no valid maxPageviewUrl is found
|
|
163
|
+
if (!maxPageviewUrl) return;
|
|
164
|
+
|
|
165
|
+
// Calculate `y`: find the CTA with the highest clicks and include the source
|
|
166
|
+
const y = maxPageviewUrl.CTAs.reduce((maxCta, cta) => {
|
|
167
|
+
if (cta.clicks > (maxCta.clicks || 0)) {
|
|
168
|
+
return cta;
|
|
169
|
+
}
|
|
170
|
+
return maxCta;
|
|
171
|
+
}, { clicks: 0, source: '' });
|
|
172
|
+
|
|
173
|
+
// Get `z`: totalClicksOnPage for the matched URL
|
|
174
|
+
const z = maxPageviewUrl.totalClicksOnPage || 0;
|
|
175
|
+
// Calculate `f`: sum of `pageview` for `formengagement`
|
|
176
|
+
const f = Object.values(pageview).reduce((sum, val) => sum + val, 0);
|
|
177
|
+
|
|
178
|
+
// Evaluate conditions and add URL to the result if all are met
|
|
179
|
+
if (hasHighPageViews(interval, x) && hasHighPageViewLowFormCtr(x, y.clicks, z, f)) {
|
|
180
|
+
const deviceData = formVitalsByDevice.get(entry.url);
|
|
181
|
+
if (deviceData != null) {
|
|
182
|
+
urls.push({
|
|
183
|
+
url: entry.url,
|
|
184
|
+
pageViews: deviceData.pageview.total,
|
|
185
|
+
formViews: deviceData.formview.total,
|
|
186
|
+
formEngagement: deviceData.formengagement.total,
|
|
187
|
+
CTA: {
|
|
188
|
+
url: maxPageviewUrl.url,
|
|
189
|
+
source: y.source,
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
return urls;
|
|
196
|
+
}
|
package/src/index.d.ts
CHANGED
|
@@ -99,10 +99,11 @@ declare function composeBaseURL(domain: string): string;
|
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
101
|
* Composes an audit URL by applying a series of transformations to the given url.
|
|
102
|
-
* @param url - The url to compose the audit URL from.
|
|
102
|
+
* @param {string} url - The url to compose the audit URL from.
|
|
103
|
+
* @param {string} [userAgent] - Optional user agent to use in the audit URL.
|
|
103
104
|
* @returns a promise that resolves the composed audit URL.
|
|
104
105
|
*/
|
|
105
|
-
declare function composeAuditURL(url: string): Promise<string>;
|
|
106
|
+
declare function composeAuditURL(url: string, userAgent: string): Promise<string>;
|
|
106
107
|
|
|
107
108
|
/**
|
|
108
109
|
* Resolves the name of the secret based on the function version.
|
|
@@ -174,6 +175,22 @@ declare function getPrompt(placeholders: object, filename: string, log: object):
|
|
|
174
175
|
declare function getHighFormViewsLowConversionMetrics(formVitals: object[], interval: number):
|
|
175
176
|
object[];
|
|
176
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Retrieves the high-page-view-low-form-view metrics from the provided array of form vitals.
|
|
180
|
+
* @param {Object[]} formVitals - An array of form vitals.
|
|
181
|
+
* @returns {Object[]} - An array of high-page-view-low-form-view metrics.
|
|
182
|
+
*/
|
|
183
|
+
declare function getHighPageViewsLowFormViewsMetrics(formVitals: object[], interval: number):
|
|
184
|
+
object[];
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Retrieves the high-page-view-low-form-ctr metrics from the provided array of form vitals.
|
|
188
|
+
* @param {Object[]} formVitals - An array of form vitals.
|
|
189
|
+
* @returns {Object[]} - An array of high-page-view-low-form-ctr metrics.
|
|
190
|
+
*/
|
|
191
|
+
declare function getHighPageViewsLowFormCtrMetrics(formVitals: object[], interval: number):
|
|
192
|
+
object[];
|
|
193
|
+
|
|
177
194
|
/**
|
|
178
195
|
* Retrieves stored metrics from S3.
|
|
179
196
|
* @param config - Configuration object
|
package/src/index.js
CHANGED
|
@@ -61,4 +61,4 @@ export { s3Wrapper } from './s3.js';
|
|
|
61
61
|
|
|
62
62
|
export { fetch } from './adobe-fetch.js';
|
|
63
63
|
export { tracingFetch } from './tracing-fetch.js';
|
|
64
|
-
export { getHighFormViewsLowConversionMetrics } from './formcalc.js';
|
|
64
|
+
export { getHighFormViewsLowConversionMetrics, getHighPageViewsLowFormViewsMetrics, getHighPageViewsLowFormCtrMetrics } from './formcalc.js';
|
package/src/url-helpers.js
CHANGED
|
@@ -83,13 +83,23 @@ function composeBaseURL(domain) {
|
|
|
83
83
|
return baseURL;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Composes an audit URL by applying a series of transformations to the given url.
|
|
88
|
+
* @param {string} url - The url to compose the audit URL from.
|
|
89
|
+
* @param {string} [userAgent] - Optional user agent to use in the audit URL.
|
|
90
|
+
* @returns a promise that resolves the composed audit URL.
|
|
91
|
+
*/
|
|
92
|
+
async function composeAuditURL(url, userAgent) {
|
|
87
93
|
const urlWithScheme = prependSchema(url);
|
|
94
|
+
|
|
95
|
+
const headers = {};
|
|
96
|
+
if (userAgent) {
|
|
97
|
+
headers['User-Agent'] = userAgent;
|
|
98
|
+
}
|
|
99
|
+
|
|
88
100
|
const resp = await fetch(urlWithScheme, {
|
|
89
101
|
method: 'GET',
|
|
90
|
-
headers
|
|
91
|
-
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
|
92
|
-
},
|
|
102
|
+
headers,
|
|
93
103
|
});
|
|
94
104
|
const finalUrl = resp.url.split('://')[1];
|
|
95
105
|
return stripTrailingSlash(finalUrl);
|