@adobe/spacecat-shared-rum-api-client 2.38.6 → 2.38.8

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,22 @@
1
+ # [@adobe/spacecat-shared-rum-api-client-v2.38.8](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-rum-api-client-v2.38.7...@adobe/spacecat-shared-rum-api-client-v2.38.8) (2025-10-31)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **traffic-attribution:** limit vendors per source ([#1079](https://github.com/adobe/spacecat-shared/issues/1079)) ([9165913](https://github.com/adobe/spacecat-shared/commit/9165913f379a00df409fe86961ba5df1f5a2a840))
7
+
8
+ # [@adobe/spacecat-shared-rum-api-client-v2.38.7](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-rum-api-client-v2.38.6...@adobe/spacecat-shared-rum-api-client-v2.38.7) (2025-10-29)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **traffic-attribution:** handle direct referrers from rum-distiller ([#1061](https://github.com/adobe/spacecat-shared/issues/1061)) ([99b1262](https://github.com/adobe/spacecat-shared/commit/99b1262638c978579770f63715ed1dd5090bffa4))
14
+
15
+
16
+ ### Reverts
17
+
18
+ * Revert "fix(traffic-attribution): handle non standard referrers ([#1040](https://github.com/adobe/spacecat-shared/issues/1040))" ([3686145](https://github.com/adobe/spacecat-shared/commit/3686145d16b0cc39d0da88c0bd2ca10dc249f93c))
19
+
1
20
  # [@adobe/spacecat-shared-rum-api-client-v2.38.6](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-rum-api-client-v2.38.5...@adobe/spacecat-shared-rum-api-client-v2.38.6) (2025-10-28)
2
21
 
3
22
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-rum-api-client",
3
- "version": "2.38.6",
3
+ "version": "2.38.8",
4
4
  "description": "Shared modules of the Spacecat Services - Rum API client",
5
5
  "type": "module",
6
6
  "engines": {
@@ -26,9 +26,17 @@ import URI from 'urijs';
26
26
  */
27
27
  export function getSecondLevelDomain(url) {
28
28
  if (!hasText(url)) return url;
29
- const uri = new URI(prependSchema(url));
30
- const tld = uri.tld();
31
- return uri.hostname().split(`.${tld}`)[0];
29
+ if (url === '(direct)') return '';
30
+
31
+ try {
32
+ const uri = new URI(prependSchema(url));
33
+ const tld = uri.tld();
34
+ return uri.hostname().split(`.${tld}`)[0];
35
+ /* c8 ignore next 4 */
36
+ } catch (error) {
37
+ // future-proof for the cases where url cannot be parsed for some reason
38
+ return url;
39
+ }
32
40
  }
33
41
 
34
42
  /*
@@ -138,27 +146,61 @@ const not = (truth) => (text) => {
138
146
 
139
147
  const notEmpty = (text) => hasText(text);
140
148
 
141
- /*
142
- * --------- ENFORCEMENTS ----------------
143
- */
149
+ // overrides
150
+ const OVERRIDES = [
151
+ { when: (ctx) => (ctx.utmSource || '').toLowerCase() === 'chatgpt.com', set: { type: 'earned', category: 'llm', vendor: 'openai' } },
152
+ ];
144
153
 
145
- const ENFORCEMENTS = [
146
- // vendors 'openai', 'claude', and 'perplexity' can only be earned/llm
147
- {
148
- when: (state) => state.vendor === 'openai' || state.vendor === 'claude' || state.vendor === 'perplexity',
149
- enforce: (state) => ({ ...state, type: 'earned', category: 'llm' }),
154
+ function applyOverrides(classification, context) {
155
+ const override = OVERRIDES.find((rule) => rule.when(context));
156
+ return override ? { ...classification, ...override.set } : classification;
157
+ }
158
+
159
+ // allowed known vendors per category
160
+ const ALLOWED_VENDORS = {
161
+ earned: {
162
+ llm: ['openai', 'claude', 'perplexity', 'microsoft', 'google'],
163
+ search: ['google', 'bing', 'yahoo', 'yandex', 'baidu', 'duckduckgo', 'brave', 'ecosia', 'aol'],
164
+ social: null, // any vendor allowed
165
+ video: ['youtube', 'vimeo', 'twitch', 'tiktok', 'dailymotion'],
166
+ referral: null, // any vendor allowed
150
167
  },
151
- // if utm_source=chatgpt.com, force earned/llm and vendor=openai
152
- {
153
- when: (state, ctx) => (ctx.utmSourceRaw || '').toLowerCase() === 'chatgpt.com',
154
- enforce: (state) => ({ ...state, type: 'earned', category: 'llm', vendor: 'openai' }),
168
+ paid: {
169
+ search: ['google', 'bing', 'yahoo', 'yandex', 'baidu', 'microsoft'],
170
+ social: null, // any vendor allowed
171
+ video: ['youtube', 'vimeo', 'twitch', 'dailymotion'],
172
+ display: null, // any vendor allowed
173
+ affiliate: null, // any vendor allowed
174
+ uncategorized: null, // any vendor allowed
155
175
  },
156
- ];
176
+ owned: {
177
+ direct: ['direct'],
178
+ internal: null, // any vendor allowed
179
+ email: null, // any vendor allowed
180
+ sms: null, // any vendor allowed
181
+ qr: null, // any vendor allowed
182
+ push: null, // any vendor allowed
183
+ uncategorized: null, // any vendor allowed
184
+ },
185
+ };
186
+
187
+ /**
188
+ * Validates if a vendor is allowed for the given type/category combination.
189
+ * @param {string} type - Traffic type (earned, paid, owned)
190
+ * @param {string} category - Traffic category (llm, search, social, etc.)
191
+ * @param {string} vendor - Vendor name to validate
192
+ * @returns {string} The vendor if allowed, empty string otherwise
193
+ */
194
+ function validateVendor(type, category, vendor) {
195
+ if (!vendor) return '';
157
196
 
158
- function applyEnforcements(initialState, context) {
159
- return ENFORCEMENTS
160
- .reduce((acc, rule) => (
161
- rule.when(acc, context) ? rule.enforce(acc, context) : acc), initialState);
197
+ const allowedVendors = ALLOWED_VENDORS[type]?.[category];
198
+
199
+ // null/undefined means any vendor is allowed
200
+ if (!allowedVendors) return vendor;
201
+
202
+ // Check if vendor is in the allowed list
203
+ return allowedVendors.includes(vendor) ? vendor : '';
162
204
  }
163
205
 
164
206
  /*
@@ -275,23 +317,25 @@ export function classifyTrafficSource(url, referrer, utmSource, utmMedium, track
275
317
  && rule.utmMedium(sanitize(utmMedium))
276
318
  && rule.tracking(trackingParams)
277
319
  ));
278
- const { type, category } = match;
279
- const vendor = classifyVendor(referrerDomain, utmSource, utmMedium);
320
+ let { type, category } = match;
321
+ let vendor = classifyVendor(referrerDomain, utmSource, utmMedium);
280
322
 
281
- const enforced = applyEnforcements(
323
+ // apply overrides
324
+ const overridden = applyOverrides(
282
325
  { type, category, vendor },
283
- {
284
- utmSourceRaw: utmSource,
285
- utmSource: sanitize(utmSource),
286
- utmMedium: sanitize(utmMedium),
287
- referrerDomain,
288
- },
326
+ { utmSource, utmMedium, referrerDomain },
289
327
  );
328
+ type = overridden.type;
329
+ category = overridden.category;
330
+ vendor = overridden.vendor;
331
+
332
+ // validate vendor against allowed vendors for this type/category
333
+ const validatedVendor = validateVendor(type, category, vendor);
290
334
 
291
335
  return {
292
- type: enforced.type,
293
- category: enforced.category,
294
- vendor: enforced.vendor,
336
+ type,
337
+ category,
338
+ vendor: validatedVendor,
295
339
  };
296
340
  }
297
341