@formo/analytics 1.33.0 → 1.33.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.
@@ -18,15 +18,21 @@ declare class EventFactory implements IEventFactory {
18
18
  private getLanguage;
19
19
  private getLibraryVersion;
20
20
  private isExcludedQueryParam;
21
+ /**
22
+ * Normalize URL paths for analytics aggregation by stripping trailing slashes
23
+ * from non-root paths. Query strings and hash fragments are preserved by
24
+ * mutating only the URL pathname.
25
+ */
26
+ private normalizeUrlPath;
21
27
  /**
22
28
  * Strip excluded (sensitive) query parameters from a URL in place. Only the
23
29
  * query string is touched; the path and hash/fragment are left as-is.
24
30
  */
25
31
  private redactQueryParams;
26
32
  /**
27
- * Return the given absolute URL with excluded query parameters removed. The
28
- * input is returned unchanged when it is empty or cannot be parsed (e.g. an
29
- * empty referrer).
33
+ * Return the given absolute URL with excluded query parameters removed and
34
+ * trailing slashes stripped from non-root paths. The input is returned
35
+ * unchanged when it is empty or cannot be parsed (e.g. an empty referrer).
30
36
  */
31
37
  private redactUrl;
32
38
  private extractUTMParameters;
@@ -113,10 +113,9 @@ var EventFactory = /** @class */ (function () {
113
113
  // - If no referral config exists → use defaults
114
114
  // - If referral config exists but queryParams is undefined → use defaults
115
115
  // - If referral config exists with queryParams → use those
116
- var defaultParams = ["ref", "referral", "refcode"];
117
116
  var referralParams = !((_a = _this.options) === null || _a === void 0 ? void 0 : _a.referral)
118
- ? defaultParams // No referral config at all → use defaults
119
- : ((_b = _this.options.referral.queryParams) !== null && _b !== void 0 ? _b : defaultParams); // Has config → use queryParams or defaults
117
+ ? constants_2.DEFAULT_REFERRAL_PARAMS // No referral config at all → use defaults
118
+ : ((_b = _this.options.referral.queryParams) !== null && _b !== void 0 ? _b : constants_2.DEFAULT_REFERRAL_PARAMS); // Has config → use queryParams or defaults
120
119
  // Check query parameters (if any configured)
121
120
  for (var _i = 0, referralParams_1 = referralParams; _i < referralParams_1.length; _i++) {
122
121
  var param = referralParams_1[_i];
@@ -211,13 +210,14 @@ var EventFactory = /** @class */ (function () {
211
210
  try {
212
211
  urlObj = new URL(globalThis.location.href);
213
212
  _this.redactQueryParams(urlObj);
213
+ _this.normalizeUrlPath(urlObj);
214
214
  }
215
215
  catch (_a) { }
216
216
  if ((0, validators_1.isUndefined)(pageProps.url)) {
217
217
  pageProps.url = urlObj ? urlObj.href : globalThis.location.href;
218
218
  }
219
219
  if ((0, validators_1.isUndefined)(pageProps.path)) {
220
- pageProps.path = globalThis.location.pathname;
220
+ pageProps.path = urlObj ? urlObj.pathname : globalThis.location.pathname;
221
221
  }
222
222
  if ((0, validators_1.isUndefined)(pageProps.hash)) {
223
223
  pageProps.hash = globalThis.location.hash;
@@ -312,6 +312,16 @@ var EventFactory = /** @class */ (function () {
312
312
  EventFactory.prototype.isExcludedQueryParam = function (key) {
313
313
  return this.excludedQueryParams.has(key.toLowerCase());
314
314
  };
315
+ /**
316
+ * Normalize URL paths for analytics aggregation by stripping trailing slashes
317
+ * from non-root paths. Query strings and hash fragments are preserved by
318
+ * mutating only the URL pathname.
319
+ */
320
+ EventFactory.prototype.normalizeUrlPath = function (url) {
321
+ if (url.pathname !== "/") {
322
+ url.pathname = url.pathname.replace(/\/+$/, "");
323
+ }
324
+ };
315
325
  /**
316
326
  * Strip excluded (sensitive) query parameters from a URL in place. Only the
317
327
  * query string is touched; the path and hash/fragment are left as-is.
@@ -329,9 +339,9 @@ var EventFactory = /** @class */ (function () {
329
339
  keysToDelete.forEach(function (key) { return url.searchParams.delete(key); });
330
340
  };
331
341
  /**
332
- * Return the given absolute URL with excluded query parameters removed. The
333
- * input is returned unchanged when it is empty or cannot be parsed (e.g. an
334
- * empty referrer).
342
+ * Return the given absolute URL with excluded query parameters removed and
343
+ * trailing slashes stripped from non-root paths. The input is returned
344
+ * unchanged when it is empty or cannot be parsed (e.g. an empty referrer).
335
345
  */
336
346
  EventFactory.prototype.redactUrl = function (href) {
337
347
  if (!href)
@@ -339,6 +349,7 @@ var EventFactory = /** @class */ (function () {
339
349
  try {
340
350
  var url = new URL(href);
341
351
  this.redactQueryParams(url);
352
+ this.normalizeUrlPath(url);
342
353
  return url.href;
343
354
  }
344
355
  catch (_a) {
@@ -18,6 +18,15 @@ declare const CLICK_ID_PARAMS: readonly ["gclid", "gad_source", "fbclid", "msclk
18
18
  * cannot remove these built-ins. Matched case-insensitively.
19
19
  */
20
20
  declare const DEFAULT_EXCLUDED_QUERY_PARAMS: readonly ["privy_oauth_code", "privy_oauth_state", "privy_oauth_provider"];
21
+ /**
22
+ * Default query parameter names checked (in order) for a referral code on the
23
+ * landing-page URL. The first parameter present supplies the `ref` traffic
24
+ * source. Consumers can override this list via `referral.queryParams`.
25
+ *
26
+ * Keep in sync with the ReferralOptions.queryParams @default in
27
+ * src/types/base.ts.
28
+ */
29
+ declare const DEFAULT_REFERRAL_PARAMS: readonly ["ref", "referral", "refcode", "af", "referrer"];
21
30
  /**
22
31
  * Fields that should be excluded from page event properties parsing
23
32
  * These are either:
@@ -25,5 +34,5 @@ declare const DEFAULT_EXCLUDED_QUERY_PARAMS: readonly ["privy_oauth_code", "priv
25
34
  * - Semantic event properties that should not be overridden by URL params
26
35
  */
27
36
  declare const PAGE_PROPERTIES_EXCLUDED_FIELDS: Set<string>;
28
- export { CHANNEL, VERSION, CLICK_ID_PARAMS, DEFAULT_EXCLUDED_QUERY_PARAMS, PAGE_PROPERTIES_EXCLUDED_FIELDS, };
37
+ export { CHANNEL, VERSION, CLICK_ID_PARAMS, DEFAULT_EXCLUDED_QUERY_PARAMS, DEFAULT_REFERRAL_PARAMS, PAGE_PROPERTIES_EXCLUDED_FIELDS, };
29
38
  //# sourceMappingURL=constants.d.ts.map
@@ -9,7 +9,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
9
9
  return to.concat(ar || Array.prototype.slice.call(from));
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.PAGE_PROPERTIES_EXCLUDED_FIELDS = exports.DEFAULT_EXCLUDED_QUERY_PARAMS = exports.CLICK_ID_PARAMS = exports.VERSION = exports.CHANNEL = void 0;
12
+ exports.PAGE_PROPERTIES_EXCLUDED_FIELDS = exports.DEFAULT_REFERRAL_PARAMS = exports.DEFAULT_EXCLUDED_QUERY_PARAMS = exports.CLICK_ID_PARAMS = exports.VERSION = exports.CHANNEL = void 0;
13
13
  var CHANNEL = "web";
14
14
  exports.CHANNEL = CHANNEL;
15
15
  var VERSION = "0";
@@ -47,24 +47,36 @@ var DEFAULT_EXCLUDED_QUERY_PARAMS = [
47
47
  "privy_oauth_provider",
48
48
  ];
49
49
  exports.DEFAULT_EXCLUDED_QUERY_PARAMS = DEFAULT_EXCLUDED_QUERY_PARAMS;
50
+ /**
51
+ * Default query parameter names checked (in order) for a referral code on the
52
+ * landing-page URL. The first parameter present supplies the `ref` traffic
53
+ * source. Consumers can override this list via `referral.queryParams`.
54
+ *
55
+ * Keep in sync with the ReferralOptions.queryParams @default in
56
+ * src/types/base.ts.
57
+ */
58
+ var DEFAULT_REFERRAL_PARAMS = [
59
+ 'ref',
60
+ 'referral',
61
+ 'refcode',
62
+ 'af',
63
+ 'referrer',
64
+ ];
65
+ exports.DEFAULT_REFERRAL_PARAMS = DEFAULT_REFERRAL_PARAMS;
50
66
  /**
51
67
  * Fields that should be excluded from page event properties parsing
52
68
  * These are either:
53
69
  * - Already captured in event context (UTM params, referral params, click IDs)
54
70
  * - Semantic event properties that should not be overridden by URL params
55
71
  */
56
- var PAGE_PROPERTIES_EXCLUDED_FIELDS = new Set(__spreadArray(__spreadArray([
72
+ var PAGE_PROPERTIES_EXCLUDED_FIELDS = new Set(__spreadArray(__spreadArray(__spreadArray([
57
73
  // Context fields (already captured in event context)
58
74
  'utm_source',
59
75
  'utm_medium',
60
76
  'utm_campaign',
61
77
  'utm_term',
62
- 'utm_content',
63
- 'ref',
64
- 'referral',
65
- 'refcode',
66
- 'referrer'
67
- ], CLICK_ID_PARAMS, true), [
78
+ 'utm_content'
79
+ ], DEFAULT_REFERRAL_PARAMS, true), CLICK_ID_PARAMS, true), [
68
80
  // Semantic event properties (should not be overridden by URL params)
69
81
  'category',
70
82
  'name',
@@ -138,8 +138,8 @@ export interface AutocaptureOptions {
138
138
  export interface ReferralOptions {
139
139
  /**
140
140
  * Custom query parameter names to check for referral codes
141
- * @default ["ref", "referral", "refcode"]
142
- * @example ["via", "referrer", "source"] - will check ?via=CODE, ?referrer=CODE, ?source=CODE
141
+ * @default ["ref", "referral", "refcode", "af", "referrer"]
142
+ * @example ["via", "partner", "source"] - will check ?via=CODE, ?partner=CODE, ?source=CODE
143
143
  */
144
144
  queryParams?: string[];
145
145
  /**
@@ -18,15 +18,21 @@ declare class EventFactory implements IEventFactory {
18
18
  private getLanguage;
19
19
  private getLibraryVersion;
20
20
  private isExcludedQueryParam;
21
+ /**
22
+ * Normalize URL paths for analytics aggregation by stripping trailing slashes
23
+ * from non-root paths. Query strings and hash fragments are preserved by
24
+ * mutating only the URL pathname.
25
+ */
26
+ private normalizeUrlPath;
21
27
  /**
22
28
  * Strip excluded (sensitive) query parameters from a URL in place. Only the
23
29
  * query string is touched; the path and hash/fragment are left as-is.
24
30
  */
25
31
  private redactQueryParams;
26
32
  /**
27
- * Return the given absolute URL with excluded query parameters removed. The
28
- * input is returned unchanged when it is empty or cannot be parsed (e.g. an
29
- * empty referrer).
33
+ * Return the given absolute URL with excluded query parameters removed and
34
+ * trailing slashes stripped from non-root paths. The input is returned
35
+ * unchanged when it is empty or cannot be parsed (e.g. an empty referrer).
30
36
  */
31
37
  private redactUrl;
32
38
  private extractUTMParameters;
@@ -63,7 +63,7 @@ import { logger } from "../logger";
63
63
  import mergeDeepRight from "../ramda/mergeDeepRight";
64
64
  import { session } from "../storage";
65
65
  import { version } from "../version";
66
- import { CHANNEL, CLICK_ID_PARAMS, DEFAULT_EXCLUDED_QUERY_PARAMS, PAGE_PROPERTIES_EXCLUDED_FIELDS, VERSION, } from "./constants";
66
+ import { CHANNEL, CLICK_ID_PARAMS, DEFAULT_EXCLUDED_QUERY_PARAMS, DEFAULT_REFERRAL_PARAMS, PAGE_PROPERTIES_EXCLUDED_FIELDS, VERSION, } from "./constants";
67
67
  import { generateAnonymousId } from "./utils";
68
68
  import { detectBrowser } from "../browser/browsers";
69
69
  var ISO_3166_ALPHA_2_REGEX = /^[A-Z]{2}$/;
@@ -107,10 +107,9 @@ var EventFactory = /** @class */ (function () {
107
107
  // - If no referral config exists → use defaults
108
108
  // - If referral config exists but queryParams is undefined → use defaults
109
109
  // - If referral config exists with queryParams → use those
110
- var defaultParams = ["ref", "referral", "refcode"];
111
110
  var referralParams = !((_a = _this.options) === null || _a === void 0 ? void 0 : _a.referral)
112
- ? defaultParams // No referral config at all → use defaults
113
- : ((_b = _this.options.referral.queryParams) !== null && _b !== void 0 ? _b : defaultParams); // Has config → use queryParams or defaults
111
+ ? DEFAULT_REFERRAL_PARAMS // No referral config at all → use defaults
112
+ : ((_b = _this.options.referral.queryParams) !== null && _b !== void 0 ? _b : DEFAULT_REFERRAL_PARAMS); // Has config → use queryParams or defaults
114
113
  // Check query parameters (if any configured)
115
114
  for (var _i = 0, referralParams_1 = referralParams; _i < referralParams_1.length; _i++) {
116
115
  var param = referralParams_1[_i];
@@ -205,13 +204,14 @@ var EventFactory = /** @class */ (function () {
205
204
  try {
206
205
  urlObj = new URL(globalThis.location.href);
207
206
  _this.redactQueryParams(urlObj);
207
+ _this.normalizeUrlPath(urlObj);
208
208
  }
209
209
  catch (_a) { }
210
210
  if (isUndefined(pageProps.url)) {
211
211
  pageProps.url = urlObj ? urlObj.href : globalThis.location.href;
212
212
  }
213
213
  if (isUndefined(pageProps.path)) {
214
- pageProps.path = globalThis.location.pathname;
214
+ pageProps.path = urlObj ? urlObj.pathname : globalThis.location.pathname;
215
215
  }
216
216
  if (isUndefined(pageProps.hash)) {
217
217
  pageProps.hash = globalThis.location.hash;
@@ -306,6 +306,16 @@ var EventFactory = /** @class */ (function () {
306
306
  EventFactory.prototype.isExcludedQueryParam = function (key) {
307
307
  return this.excludedQueryParams.has(key.toLowerCase());
308
308
  };
309
+ /**
310
+ * Normalize URL paths for analytics aggregation by stripping trailing slashes
311
+ * from non-root paths. Query strings and hash fragments are preserved by
312
+ * mutating only the URL pathname.
313
+ */
314
+ EventFactory.prototype.normalizeUrlPath = function (url) {
315
+ if (url.pathname !== "/") {
316
+ url.pathname = url.pathname.replace(/\/+$/, "");
317
+ }
318
+ };
309
319
  /**
310
320
  * Strip excluded (sensitive) query parameters from a URL in place. Only the
311
321
  * query string is touched; the path and hash/fragment are left as-is.
@@ -323,9 +333,9 @@ var EventFactory = /** @class */ (function () {
323
333
  keysToDelete.forEach(function (key) { return url.searchParams.delete(key); });
324
334
  };
325
335
  /**
326
- * Return the given absolute URL with excluded query parameters removed. The
327
- * input is returned unchanged when it is empty or cannot be parsed (e.g. an
328
- * empty referrer).
336
+ * Return the given absolute URL with excluded query parameters removed and
337
+ * trailing slashes stripped from non-root paths. The input is returned
338
+ * unchanged when it is empty or cannot be parsed (e.g. an empty referrer).
329
339
  */
330
340
  EventFactory.prototype.redactUrl = function (href) {
331
341
  if (!href)
@@ -333,6 +343,7 @@ var EventFactory = /** @class */ (function () {
333
343
  try {
334
344
  var url = new URL(href);
335
345
  this.redactQueryParams(url);
346
+ this.normalizeUrlPath(url);
336
347
  return url.href;
337
348
  }
338
349
  catch (_a) {
@@ -18,6 +18,15 @@ declare const CLICK_ID_PARAMS: readonly ["gclid", "gad_source", "fbclid", "msclk
18
18
  * cannot remove these built-ins. Matched case-insensitively.
19
19
  */
20
20
  declare const DEFAULT_EXCLUDED_QUERY_PARAMS: readonly ["privy_oauth_code", "privy_oauth_state", "privy_oauth_provider"];
21
+ /**
22
+ * Default query parameter names checked (in order) for a referral code on the
23
+ * landing-page URL. The first parameter present supplies the `ref` traffic
24
+ * source. Consumers can override this list via `referral.queryParams`.
25
+ *
26
+ * Keep in sync with the ReferralOptions.queryParams @default in
27
+ * src/types/base.ts.
28
+ */
29
+ declare const DEFAULT_REFERRAL_PARAMS: readonly ["ref", "referral", "refcode", "af", "referrer"];
21
30
  /**
22
31
  * Fields that should be excluded from page event properties parsing
23
32
  * These are either:
@@ -25,5 +34,5 @@ declare const DEFAULT_EXCLUDED_QUERY_PARAMS: readonly ["privy_oauth_code", "priv
25
34
  * - Semantic event properties that should not be overridden by URL params
26
35
  */
27
36
  declare const PAGE_PROPERTIES_EXCLUDED_FIELDS: Set<string>;
28
- export { CHANNEL, VERSION, CLICK_ID_PARAMS, DEFAULT_EXCLUDED_QUERY_PARAMS, PAGE_PROPERTIES_EXCLUDED_FIELDS, };
37
+ export { CHANNEL, VERSION, CLICK_ID_PARAMS, DEFAULT_EXCLUDED_QUERY_PARAMS, DEFAULT_REFERRAL_PARAMS, PAGE_PROPERTIES_EXCLUDED_FIELDS, };
29
38
  //# sourceMappingURL=constants.d.ts.map
@@ -40,24 +40,35 @@ var DEFAULT_EXCLUDED_QUERY_PARAMS = [
40
40
  "privy_oauth_state",
41
41
  "privy_oauth_provider",
42
42
  ];
43
+ /**
44
+ * Default query parameter names checked (in order) for a referral code on the
45
+ * landing-page URL. The first parameter present supplies the `ref` traffic
46
+ * source. Consumers can override this list via `referral.queryParams`.
47
+ *
48
+ * Keep in sync with the ReferralOptions.queryParams @default in
49
+ * src/types/base.ts.
50
+ */
51
+ var DEFAULT_REFERRAL_PARAMS = [
52
+ 'ref',
53
+ 'referral',
54
+ 'refcode',
55
+ 'af',
56
+ 'referrer',
57
+ ];
43
58
  /**
44
59
  * Fields that should be excluded from page event properties parsing
45
60
  * These are either:
46
61
  * - Already captured in event context (UTM params, referral params, click IDs)
47
62
  * - Semantic event properties that should not be overridden by URL params
48
63
  */
49
- var PAGE_PROPERTIES_EXCLUDED_FIELDS = new Set(__spreadArray(__spreadArray([
64
+ var PAGE_PROPERTIES_EXCLUDED_FIELDS = new Set(__spreadArray(__spreadArray(__spreadArray([
50
65
  // Context fields (already captured in event context)
51
66
  'utm_source',
52
67
  'utm_medium',
53
68
  'utm_campaign',
54
69
  'utm_term',
55
- 'utm_content',
56
- 'ref',
57
- 'referral',
58
- 'refcode',
59
- 'referrer'
60
- ], CLICK_ID_PARAMS, true), [
70
+ 'utm_content'
71
+ ], DEFAULT_REFERRAL_PARAMS, true), CLICK_ID_PARAMS, true), [
61
72
  // Semantic event properties (should not be overridden by URL params)
62
73
  'category',
63
74
  'name',
@@ -66,5 +77,5 @@ var PAGE_PROPERTIES_EXCLUDED_FIELDS = new Set(__spreadArray(__spreadArray([
66
77
  'hash',
67
78
  'query',
68
79
  ], false));
69
- export { CHANNEL, VERSION, CLICK_ID_PARAMS, DEFAULT_EXCLUDED_QUERY_PARAMS, PAGE_PROPERTIES_EXCLUDED_FIELDS, };
80
+ export { CHANNEL, VERSION, CLICK_ID_PARAMS, DEFAULT_EXCLUDED_QUERY_PARAMS, DEFAULT_REFERRAL_PARAMS, PAGE_PROPERTIES_EXCLUDED_FIELDS, };
70
81
  //# sourceMappingURL=constants.js.map
@@ -138,8 +138,8 @@ export interface AutocaptureOptions {
138
138
  export interface ReferralOptions {
139
139
  /**
140
140
  * Custom query parameter names to check for referral codes
141
- * @default ["ref", "referral", "refcode"]
142
- * @example ["via", "referrer", "source"] - will check ?via=CODE, ?referrer=CODE, ?source=CODE
141
+ * @default ["ref", "referral", "refcode", "af", "referrer"]
142
+ * @example ["via", "partner", "source"] - will check ?via=CODE, ?partner=CODE, ?source=CODE
143
143
  */
144
144
  queryParams?: string[];
145
145
  /**