@spotify-confidence/csr-common 0.18.9 → 0.18.10

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,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.18.10](https://github.com/spotify/confidence-sdk-js/compare/csr-common-v0.18.9...csr-common-v0.18.10) (2026-09-09)
4
+
5
+
6
+ ### 🐛 Bug Fixes
7
+
8
+ * strip query and hash from recording URLs ([#452](https://github.com/spotify/confidence-sdk-js/issues/452)) ([1ce37f3](https://github.com/spotify/confidence-sdk-js/commit/1ce37f3f43c05bfea4a90839a6de42314096bb40))
9
+
3
10
  ## [0.18.9](https://github.com/spotify/confidence-sdk-js/compare/csr-common-v0.18.8...csr-common-v0.18.9) (2026-09-07)
4
11
 
5
12
 
package/dist/index.cjs CHANGED
@@ -1,18 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_session_activity = require("./session-activity-HfuXKqGd.cjs");
3
- //#region src/url.ts
4
- /**
5
- * Extract only the pathname from a URL, stripping origin, query string, and
6
- * hash. Used across recorder and analyzer to avoid capturing PII in route data.
7
- */
8
- function stripUrl(url) {
9
- try {
10
- return new URL(url).pathname;
11
- } catch (_e) {
12
- return url;
13
- }
14
- }
15
- //#endregion
2
+ const require_session_activity = require("./session-activity-B8swR5Wg.cjs");
16
3
  //#region src/custom-event-limits.ts
17
4
  const MAX_KEY_LENGTH = 128;
18
5
  const MAX_TAG_VALUE_LENGTH = 256;
@@ -51,7 +38,8 @@ exports.SerializedNodeType = require_session_activity.SerializedNodeType;
51
38
  exports.isSessionActivityEvent = require_session_activity.isSessionActivityEvent;
52
39
  exports.isUserInteractionEvent = require_session_activity.isUserInteractionEvent;
53
40
  exports.isUserInteractionMetric = require_session_activity.isUserInteractionMetric;
54
- exports.stripUrl = stripUrl;
41
+ exports.stripUrl = require_session_activity.stripUrl;
42
+ exports.stripUrlQueryAndHash = require_session_activity.stripUrlQueryAndHash;
55
43
  exports.validateKey = validateKey;
56
44
  exports.validateMeasureValue = validateMeasureValue;
57
45
  exports.validateTagValue = validateTagValue;
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { i as ClientContext, n as Frame, o as UserAgentContext } from "./types-Bg0UKTVQ.cjs";
1
+ import { i as ClientContext, n as Frame, o as UserAgentContext } from "./types-C3mO_2YH.cjs";
2
2
 
3
3
  //#region src/events.d.ts
4
4
  /**
@@ -370,6 +370,8 @@ type RecordingEvent = {
370
370
  };
371
371
  //#endregion
372
372
  //#region src/url.d.ts
373
+ /** Remove query strings and fragments, including from relative or malformed URLs. */
374
+ declare function stripUrlQueryAndHash(url: string): string;
373
375
  /**
374
376
  * Extract only the pathname from a URL, stripping origin, query string, and
375
377
  * hash. Used across recorder and analyzer to avoid capturing PII in route data.
@@ -407,4 +409,4 @@ declare function validateKey(key: string): string | null;
407
409
  declare function validateTagValue(value: string | undefined): string | null;
408
410
  declare function validateMeasureValue(value: number | undefined): string | null;
409
411
  //#endregion
410
- export { type AwayGapCustomData, type ClickCustomData, type ClientContext, type ClipboardAction, type ClipboardPluginData, type ConsoleLogLevel, type ConsoleLogPluginData, type CustomEventData, type DeadClickCustomData, type DialogOpenedCustomData, type ElementDescriptor, type ErrorMessageCustomData, type FlagEvaluationPluginData, type FormFieldReEditCustomData, type Frame, type GraphQLRequestMetadata, type IdleGapCustomData, type IncrementalSnapshotData, IncrementalSource, type InputCustomData, MAX_DISTINCT_KEYS, MAX_KEY_LENGTH, MAX_TAG_VALUE_LENGTH, MAX_VALUES_PER_KEY, type MeasurePluginData, type MouseInteractionData, MouseInteractions, type NetworkRequestInitiator, type NetworkRequestPluginData, type OpaqueIncrementalData, type PluginEventData, type RageClickCustomData, RecordingCustomEventTag, type RecordingEvent, RecordingEventType, RecordingMetricKey, RecordingPluginName, type RouteChangeCustomData, type RouteChangePayload, type RouteChangePluginData, type RouteChangeTrigger, type ScrollBackCustomData, type SelectionData, type SelectionRange, SerializedNodeType, type TabRefocusCustomData, type TabUnfocusCustomData, type TabVisibilityPluginData, type TagPluginData, type UserAgentContext, isSessionActivityEvent, isUserInteractionEvent, isUserInteractionMetric, stripUrl, validateKey, validateMeasureValue, validateTagValue };
412
+ export { type AwayGapCustomData, type ClickCustomData, type ClientContext, type ClipboardAction, type ClipboardPluginData, type ConsoleLogLevel, type ConsoleLogPluginData, type CustomEventData, type DeadClickCustomData, type DialogOpenedCustomData, type ElementDescriptor, type ErrorMessageCustomData, type FlagEvaluationPluginData, type FormFieldReEditCustomData, type Frame, type GraphQLRequestMetadata, type IdleGapCustomData, type IncrementalSnapshotData, IncrementalSource, type InputCustomData, MAX_DISTINCT_KEYS, MAX_KEY_LENGTH, MAX_TAG_VALUE_LENGTH, MAX_VALUES_PER_KEY, type MeasurePluginData, type MouseInteractionData, MouseInteractions, type NetworkRequestInitiator, type NetworkRequestPluginData, type OpaqueIncrementalData, type PluginEventData, type RageClickCustomData, RecordingCustomEventTag, type RecordingEvent, RecordingEventType, RecordingMetricKey, RecordingPluginName, type RouteChangeCustomData, type RouteChangePayload, type RouteChangePluginData, type RouteChangeTrigger, type ScrollBackCustomData, type SelectionData, type SelectionRange, SerializedNodeType, type TabRefocusCustomData, type TabUnfocusCustomData, type TabVisibilityPluginData, type TagPluginData, type UserAgentContext, isSessionActivityEvent, isUserInteractionEvent, isUserInteractionMetric, stripUrl, stripUrlQueryAndHash, validateKey, validateMeasureValue, validateTagValue };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { i as ClientContext, n as Frame, o as UserAgentContext } from "./types-Bg0UKTVQ.js";
1
+ import { i as ClientContext, n as Frame, o as UserAgentContext } from "./types-C3mO_2YH.js";
2
2
 
3
3
  //#region src/events.d.ts
4
4
  /**
@@ -370,6 +370,8 @@ type RecordingEvent = {
370
370
  };
371
371
  //#endregion
372
372
  //#region src/url.d.ts
373
+ /** Remove query strings and fragments, including from relative or malformed URLs. */
374
+ declare function stripUrlQueryAndHash(url: string): string;
373
375
  /**
374
376
  * Extract only the pathname from a URL, stripping origin, query string, and
375
377
  * hash. Used across recorder and analyzer to avoid capturing PII in route data.
@@ -407,4 +409,4 @@ declare function validateKey(key: string): string | null;
407
409
  declare function validateTagValue(value: string | undefined): string | null;
408
410
  declare function validateMeasureValue(value: number | undefined): string | null;
409
411
  //#endregion
410
- export { type AwayGapCustomData, type ClickCustomData, type ClientContext, type ClipboardAction, type ClipboardPluginData, type ConsoleLogLevel, type ConsoleLogPluginData, type CustomEventData, type DeadClickCustomData, type DialogOpenedCustomData, type ElementDescriptor, type ErrorMessageCustomData, type FlagEvaluationPluginData, type FormFieldReEditCustomData, type Frame, type GraphQLRequestMetadata, type IdleGapCustomData, type IncrementalSnapshotData, IncrementalSource, type InputCustomData, MAX_DISTINCT_KEYS, MAX_KEY_LENGTH, MAX_TAG_VALUE_LENGTH, MAX_VALUES_PER_KEY, type MeasurePluginData, type MouseInteractionData, MouseInteractions, type NetworkRequestInitiator, type NetworkRequestPluginData, type OpaqueIncrementalData, type PluginEventData, type RageClickCustomData, RecordingCustomEventTag, type RecordingEvent, RecordingEventType, RecordingMetricKey, RecordingPluginName, type RouteChangeCustomData, type RouteChangePayload, type RouteChangePluginData, type RouteChangeTrigger, type ScrollBackCustomData, type SelectionData, type SelectionRange, SerializedNodeType, type TabRefocusCustomData, type TabUnfocusCustomData, type TabVisibilityPluginData, type TagPluginData, type UserAgentContext, isSessionActivityEvent, isUserInteractionEvent, isUserInteractionMetric, stripUrl, validateKey, validateMeasureValue, validateTagValue };
412
+ export { type AwayGapCustomData, type ClickCustomData, type ClientContext, type ClipboardAction, type ClipboardPluginData, type ConsoleLogLevel, type ConsoleLogPluginData, type CustomEventData, type DeadClickCustomData, type DialogOpenedCustomData, type ElementDescriptor, type ErrorMessageCustomData, type FlagEvaluationPluginData, type FormFieldReEditCustomData, type Frame, type GraphQLRequestMetadata, type IdleGapCustomData, type IncrementalSnapshotData, IncrementalSource, type InputCustomData, MAX_DISTINCT_KEYS, MAX_KEY_LENGTH, MAX_TAG_VALUE_LENGTH, MAX_VALUES_PER_KEY, type MeasurePluginData, type MouseInteractionData, MouseInteractions, type NetworkRequestInitiator, type NetworkRequestPluginData, type OpaqueIncrementalData, type PluginEventData, type RageClickCustomData, RecordingCustomEventTag, type RecordingEvent, RecordingEventType, RecordingMetricKey, RecordingPluginName, type RouteChangeCustomData, type RouteChangePayload, type RouteChangePluginData, type RouteChangeTrigger, type ScrollBackCustomData, type SelectionData, type SelectionRange, SerializedNodeType, type TabRefocusCustomData, type TabUnfocusCustomData, type TabVisibilityPluginData, type TagPluginData, type UserAgentContext, isSessionActivityEvent, isUserInteractionEvent, isUserInteractionMetric, stripUrl, stripUrlQueryAndHash, validateKey, validateMeasureValue, validateTagValue };
package/dist/index.js CHANGED
@@ -1,17 +1,4 @@
1
- import { a as IncrementalSource, c as RecordingEventType, i as RecordingMetricKey, l as RecordingPluginName, n as isUserInteractionEvent, o as MouseInteractions, r as isUserInteractionMetric, s as RecordingCustomEventTag, t as isSessionActivityEvent, u as SerializedNodeType } from "./session-activity-CJ1wae06.js";
2
- //#region src/url.ts
3
- /**
4
- * Extract only the pathname from a URL, stripping origin, query string, and
5
- * hash. Used across recorder and analyzer to avoid capturing PII in route data.
6
- */
7
- function stripUrl(url) {
8
- try {
9
- return new URL(url).pathname;
10
- } catch (_e) {
11
- return url;
12
- }
13
- }
14
- //#endregion
1
+ import { a as stripUrl, c as MouseInteractions, d as RecordingPluginName, f as SerializedNodeType, i as RecordingMetricKey, l as RecordingCustomEventTag, n as isUserInteractionEvent, o as stripUrlQueryAndHash, r as isUserInteractionMetric, s as IncrementalSource, t as isSessionActivityEvent, u as RecordingEventType } from "./session-activity-tshS9Hua.js";
15
2
  //#region src/custom-event-limits.ts
16
3
  const MAX_KEY_LENGTH = 128;
17
4
  const MAX_TAG_VALUE_LENGTH = 256;
@@ -36,4 +23,4 @@ function validateMeasureValue(value) {
36
23
  return null;
37
24
  }
38
25
  //#endregion
39
- export { IncrementalSource, MAX_DISTINCT_KEYS, MAX_KEY_LENGTH, MAX_TAG_VALUE_LENGTH, MAX_VALUES_PER_KEY, MouseInteractions, RecordingCustomEventTag, RecordingEventType, RecordingMetricKey, RecordingPluginName, SerializedNodeType, isSessionActivityEvent, isUserInteractionEvent, isUserInteractionMetric, stripUrl, validateKey, validateMeasureValue, validateTagValue };
26
+ export { IncrementalSource, MAX_DISTINCT_KEYS, MAX_KEY_LENGTH, MAX_TAG_VALUE_LENGTH, MAX_VALUES_PER_KEY, MouseInteractions, RecordingCustomEventTag, RecordingEventType, RecordingMetricKey, RecordingPluginName, SerializedNodeType, isSessionActivityEvent, isUserInteractionEvent, isUserInteractionMetric, stripUrl, stripUrlQueryAndHash, validateKey, validateMeasureValue, validateTagValue };
@@ -91,6 +91,23 @@ let MouseInteractions = /* @__PURE__ */ function(MouseInteractions) {
91
91
  return MouseInteractions;
92
92
  }({});
93
93
  //#endregion
94
+ //#region src/url.ts
95
+ /** Remove query strings and fragments, including from relative or malformed URLs. */
96
+ function stripUrlQueryAndHash(url) {
97
+ return url.split(/[?#]/, 1)[0];
98
+ }
99
+ /**
100
+ * Extract only the pathname from a URL, stripping origin, query string, and
101
+ * hash. Used across recorder and analyzer to avoid capturing PII in route data.
102
+ */
103
+ function stripUrl(url) {
104
+ try {
105
+ return new URL(url).pathname;
106
+ } catch (_e) {
107
+ return url;
108
+ }
109
+ }
110
+ //#endregion
94
111
  //#region src/metrics.ts
95
112
  const RecordingMetricKey = {
96
113
  Click: "clicks",
@@ -210,3 +227,15 @@ Object.defineProperty(exports, "isUserInteractionMetric", {
210
227
  return isUserInteractionMetric;
211
228
  }
212
229
  });
230
+ Object.defineProperty(exports, "stripUrl", {
231
+ enumerable: true,
232
+ get: function() {
233
+ return stripUrl;
234
+ }
235
+ });
236
+ Object.defineProperty(exports, "stripUrlQueryAndHash", {
237
+ enumerable: true,
238
+ get: function() {
239
+ return stripUrlQueryAndHash;
240
+ }
241
+ });
@@ -91,6 +91,23 @@ let MouseInteractions = /* @__PURE__ */ function(MouseInteractions) {
91
91
  return MouseInteractions;
92
92
  }({});
93
93
  //#endregion
94
+ //#region src/url.ts
95
+ /** Remove query strings and fragments, including from relative or malformed URLs. */
96
+ function stripUrlQueryAndHash(url) {
97
+ return url.split(/[?#]/, 1)[0];
98
+ }
99
+ /**
100
+ * Extract only the pathname from a URL, stripping origin, query string, and
101
+ * hash. Used across recorder and analyzer to avoid capturing PII in route data.
102
+ */
103
+ function stripUrl(url) {
104
+ try {
105
+ return new URL(url).pathname;
106
+ } catch (_e) {
107
+ return url;
108
+ }
109
+ }
110
+ //#endregion
94
111
  //#region src/metrics.ts
95
112
  const RecordingMetricKey = {
96
113
  Click: "clicks",
@@ -150,4 +167,4 @@ const isUserInteractionEvent = (event) => {
150
167
  const isUserInteractionMetric = (metricKey) => USER_INTERACTION_METRIC_KEYS.has(metricKey);
151
168
  const isSessionActivityEvent = (event) => isObject(event) && event.type === 4 || isUserInteractionEvent(event);
152
169
  //#endregion
153
- export { IncrementalSource as a, RecordingEventType as c, RecordingMetricKey as i, RecordingPluginName as l, isUserInteractionEvent as n, MouseInteractions as o, isUserInteractionMetric as r, RecordingCustomEventTag as s, isSessionActivityEvent as t, SerializedNodeType as u };
170
+ export { stripUrl as a, MouseInteractions as c, RecordingPluginName as d, SerializedNodeType as f, RecordingMetricKey as i, RecordingCustomEventTag as l, isUserInteractionEvent as n, stripUrlQueryAndHash as o, isUserInteractionMetric as r, IncrementalSource as s, isSessionActivityEvent as t, RecordingEventType as u };
@@ -22,7 +22,7 @@ type UserAgentContext = {
22
22
  screenWidth?: number;
23
23
  screenHeight?: number;
24
24
  devicePixelRatio?: number; /** Initial document URI — without query/hash to avoid leaking PII. */
25
- uri?: string;
25
+ uri?: string; /** Document referrer — without query/hash to avoid leaking PII. */
26
26
  referrer?: string;
27
27
  };
28
28
  interface ClientContext {
@@ -22,7 +22,7 @@ type UserAgentContext = {
22
22
  screenWidth?: number;
23
23
  screenHeight?: number;
24
24
  devicePixelRatio?: number; /** Initial document URI — without query/hash to avoid leaking PII. */
25
- uri?: string;
25
+ uri?: string; /** Document referrer — without query/hash to avoid leaking PII. */
26
26
  referrer?: string;
27
27
  };
28
28
  interface ClientContext {
@@ -21,7 +21,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  enumerable: true
22
22
  }) : target, mod));
23
23
  //#endregion
24
- const require_session_activity = require("../session-activity-HfuXKqGd.cjs");
24
+ const require_session_activity = require("../session-activity-B8swR5Wg.cjs");
25
25
  let bowser = require("bowser");
26
26
  bowser = __toESM(bowser, 1);
27
27
  //#region src/uploader/client-context.ts
@@ -46,7 +46,7 @@ function collectUserAgentContext() {
46
46
  screenHeight: window.screen.height,
47
47
  devicePixelRatio: window.devicePixelRatio,
48
48
  uri: `${window.location.origin}${window.location.pathname}`,
49
- referrer: document.referrer
49
+ referrer: require_session_activity.stripUrlQueryAndHash(document.referrer)
50
50
  };
51
51
  }
52
52
  //#endregion
@@ -1,4 +1,4 @@
1
- import { a as ContextValue, i as ClientContext, o as UserAgentContext, r as Uploader, s as collectUserAgentContext, t as CreateUploaderOptions } from "../types-Bg0UKTVQ.cjs";
1
+ import { a as ContextValue, i as ClientContext, o as UserAgentContext, r as Uploader, s as collectUserAgentContext, t as CreateUploaderOptions } from "../types-C3mO_2YH.cjs";
2
2
 
3
3
  //#region src/uploader/create-uploader.d.ts
4
4
  declare function createUploader(opts: CreateUploaderOptions): Promise<Uploader | null>;
@@ -1,4 +1,4 @@
1
- import { a as ContextValue, i as ClientContext, o as UserAgentContext, r as Uploader, s as collectUserAgentContext, t as CreateUploaderOptions } from "../types-Bg0UKTVQ.js";
1
+ import { a as ContextValue, i as ClientContext, o as UserAgentContext, r as Uploader, s as collectUserAgentContext, t as CreateUploaderOptions } from "../types-C3mO_2YH.js";
2
2
 
3
3
  //#region src/uploader/create-uploader.d.ts
4
4
  declare function createUploader(opts: CreateUploaderOptions): Promise<Uploader | null>;
@@ -1,4 +1,4 @@
1
- import { t as isSessionActivityEvent } from "../session-activity-CJ1wae06.js";
1
+ import { o as stripUrlQueryAndHash, t as isSessionActivityEvent } from "../session-activity-tshS9Hua.js";
2
2
  import Bowser from "bowser";
3
3
  //#region src/uploader/client-context.ts
4
4
  function collectUserAgentContext() {
@@ -22,7 +22,7 @@ function collectUserAgentContext() {
22
22
  screenHeight: window.screen.height,
23
23
  devicePixelRatio: window.devicePixelRatio,
24
24
  uri: `${window.location.origin}${window.location.pathname}`,
25
- referrer: document.referrer
25
+ referrer: stripUrlQueryAndHash(document.referrer)
26
26
  };
27
27
  }
28
28
  //#endregion
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@spotify-confidence/csr-common",
3
3
  "license": "Apache-2.0",
4
- "version": "0.18.9",
4
+ "version": "0.18.10",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/spotify/confidence-sdk-js.git",
package/src/index.ts CHANGED
@@ -43,7 +43,7 @@ export {
43
43
  type FlagEvaluationPluginData,
44
44
  } from './events';
45
45
 
46
- export { stripUrl } from './url';
46
+ export { stripUrl, stripUrlQueryAndHash } from './url';
47
47
 
48
48
  export { RecordingMetricKey } from './metrics';
49
49
 
@@ -84,6 +84,33 @@ describe('collectUserAgentContext', () => {
84
84
  });
85
85
  });
86
86
 
87
+ it.each([
88
+ ['https://referrer.example/path?email=alice@example.com#token', 'https://referrer.example/path'],
89
+ ['https://referrer.example/path#token?email=alice@example.com', 'https://referrer.example/path'],
90
+ ['https://referrer.example/path?email=alice@example.com', 'https://referrer.example/path'],
91
+ ['https://referrer.example/path#token', 'https://referrer.example/path'],
92
+ ['', ''],
93
+ ['invalid-url?email=alice@example.com#token', 'invalid-url'],
94
+ ])('strips query/hash from referrer %s', (referrer, expected) => {
95
+ stubBrowser({ document: { referrer } });
96
+ expect(collectUserAgentContext()?.referrer).toBe(expected);
97
+ });
98
+
99
+ it('excludes query/hash from the initial document URI', () => {
100
+ stubBrowser({
101
+ window: {
102
+ location: {
103
+ origin: 'https://example.com',
104
+ pathname: '/path',
105
+ search: '?email=alice@example.com',
106
+ hash: '#token',
107
+ href: 'https://example.com/path?email=alice@example.com#token',
108
+ },
109
+ },
110
+ });
111
+ expect(collectUserAgentContext()?.uri).toBe('https://example.com/path');
112
+ });
113
+
87
114
  it('flags `mobile` platform type as mobile=true', () => {
88
115
  parse.mockReturnValueOnce({
89
116
  os: {},
@@ -1,4 +1,5 @@
1
1
  import Bowser from 'bowser';
2
+ import { stripUrlQueryAndHash } from '../url';
2
3
 
3
4
  /**
4
5
  * JSON-shaped values accepted in a Context — matches `google.protobuf.Struct`.
@@ -31,6 +32,7 @@ export type UserAgentContext = {
31
32
  devicePixelRatio?: number;
32
33
  /** Initial document URI — without query/hash to avoid leaking PII. */
33
34
  uri?: string;
35
+ /** Document referrer — without query/hash to avoid leaking PII. */
34
36
  referrer?: string;
35
37
  };
36
38
 
@@ -65,6 +67,6 @@ export function collectUserAgentContext(): UserAgentContext | undefined {
65
67
  screenHeight: window.screen.height,
66
68
  devicePixelRatio: window.devicePixelRatio,
67
69
  uri: `${window.location.origin}${window.location.pathname}`,
68
- referrer: document.referrer,
70
+ referrer: stripUrlQueryAndHash(document.referrer),
69
71
  };
70
72
  }
package/src/url.ts CHANGED
@@ -1,3 +1,8 @@
1
+ /** Remove query strings and fragments, including from relative or malformed URLs. */
2
+ export function stripUrlQueryAndHash(url: string): string {
3
+ return url.split(/[?#]/, 1)[0];
4
+ }
5
+
1
6
  /**
2
7
  * Extract only the pathname from a URL, stripping origin, query string, and
3
8
  * hash. Used across recorder and analyzer to avoid capturing PII in route data.