@spotify-confidence/csr-recorder 0.17.17 → 0.17.18
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/README.md +1 -1
- package/dist/index.cjs +3 -2
- package/dist/index.js +4 -3
- package/package.json +2 -2
- package/src/recorder-routing.test.ts +40 -2
- package/src/recorder.ts +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.17.18](https://github.com/spotify/confidence-sdk-js/compare/csr-recorder-v0.17.17...csr-recorder-v0.17.18) (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
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @spotify-confidence/csr-common bumped to 0.18.10
|
|
16
|
+
|
|
3
17
|
## [0.17.17](https://github.com/spotify/confidence-sdk-js/compare/csr-recorder-v0.17.16...csr-recorder-v0.17.17) (2026-09-07)
|
|
4
18
|
|
|
5
19
|
|
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ const stop = record(event => {}, {
|
|
|
53
53
|
});
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
The same parameterization is also applied to the `href` in rrweb Meta events.
|
|
56
|
+
The same parameterization is also applied to the `href` in rrweb Meta events. Query strings and fragments are removed from Meta event URLs and the session's document referrer before recording.
|
|
57
57
|
|
|
58
58
|
## rrweb version
|
|
59
59
|
|
package/dist/index.cjs
CHANGED
|
@@ -221,12 +221,13 @@ var Recorder = class Recorder {
|
|
|
221
221
|
};
|
|
222
222
|
}
|
|
223
223
|
parameterizeHref(href) {
|
|
224
|
+
const strippedHref = (0, _spotify_confidence_csr_common.stripUrlQueryAndHash)(href);
|
|
224
225
|
try {
|
|
225
|
-
const url = new URL(
|
|
226
|
+
const url = new URL(strippedHref);
|
|
226
227
|
url.pathname = this.parameterizeRoute(url.pathname);
|
|
227
228
|
return url.toString();
|
|
228
229
|
} catch (_e) {
|
|
229
|
-
return this.parameterizeRoute(
|
|
230
|
+
return this.parameterizeRoute(strippedHref);
|
|
230
231
|
}
|
|
231
232
|
}
|
|
232
233
|
emitRouteChange(from, to, trigger) {
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RecordingEventType, RecordingPluginName } from "@spotify-confidence/csr-common";
|
|
1
|
+
import { RecordingEventType, RecordingPluginName, stripUrlQueryAndHash } from "@spotify-confidence/csr-common";
|
|
2
2
|
//#region src/types.ts
|
|
3
3
|
const DEFAULT_MASK_SELECTORS = ["[data-csr-mask]"];
|
|
4
4
|
const DEFAULT_BLOCK_SELECTORS = ["[data-csr-block]", "video"];
|
|
@@ -220,12 +220,13 @@ var Recorder = class Recorder {
|
|
|
220
220
|
};
|
|
221
221
|
}
|
|
222
222
|
parameterizeHref(href) {
|
|
223
|
+
const strippedHref = stripUrlQueryAndHash(href);
|
|
223
224
|
try {
|
|
224
|
-
const url = new URL(
|
|
225
|
+
const url = new URL(strippedHref);
|
|
225
226
|
url.pathname = this.parameterizeRoute(url.pathname);
|
|
226
227
|
return url.toString();
|
|
227
228
|
} catch (_e) {
|
|
228
|
-
return this.parameterizeRoute(
|
|
229
|
+
return this.parameterizeRoute(strippedHref);
|
|
229
230
|
}
|
|
230
231
|
}
|
|
231
232
|
emitRouteChange(from, to, trigger) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spotify-confidence/csr-recorder",
|
|
3
3
|
"license": "Apache-2.0",
|
|
4
|
-
"version": "0.17.
|
|
4
|
+
"version": "0.17.18",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/spotify/confidence-sdk-js.git",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@rrweb/rrweb-plugin-console-record": "^2.0.1",
|
|
38
|
-
"@spotify-confidence/csr-common": "0.18.
|
|
38
|
+
"@spotify-confidence/csr-common": "0.18.10",
|
|
39
39
|
"rrweb": "^2.0.1"
|
|
40
40
|
},
|
|
41
41
|
"module": "./dist/index.js",
|
|
@@ -234,21 +234,59 @@ describe('Recorder route change capture', () => {
|
|
|
234
234
|
recorder.stop();
|
|
235
235
|
});
|
|
236
236
|
|
|
237
|
+
it.each([
|
|
238
|
+
['https://example.com/users/123?email=alice@example.com#token', 'https://example.com/users/:id'],
|
|
239
|
+
['https://example.com/users/123#token?email=alice@example.com', 'https://example.com/users/:id'],
|
|
240
|
+
['https://example.com/users/123?email=alice@example.com', 'https://example.com/users/:id'],
|
|
241
|
+
['https://example.com/users/123#token', 'https://example.com/users/:id'],
|
|
242
|
+
['/users/123?email=alice@example.com#token', '/users/:id'],
|
|
243
|
+
['invalid-url?email=alice@example.com#token', 'invalid-url'],
|
|
244
|
+
['', ''],
|
|
245
|
+
])('strips query/hash from Meta href %s even with route capture disabled', (href, expected) => {
|
|
246
|
+
const engine = new MockEngine();
|
|
247
|
+
const event: RecordingEvent = {
|
|
248
|
+
type: RecordingEventType.Meta,
|
|
249
|
+
timestamp: 1,
|
|
250
|
+
data: { href, width: 1920, height: 1080 },
|
|
251
|
+
};
|
|
252
|
+
engine.eventsOnStart = [event];
|
|
253
|
+
const onEvent = vi.fn();
|
|
254
|
+
const recorder = new Recorder({ engine, onEvent });
|
|
255
|
+
recorder.start({ captureRouteChanges: false });
|
|
256
|
+
// Later snapshots must be sanitized too.
|
|
257
|
+
engine.emit(event);
|
|
258
|
+
|
|
259
|
+
expect(onEvent).toHaveBeenCalledTimes(2);
|
|
260
|
+
for (const [recorded] of onEvent.mock.calls) {
|
|
261
|
+
expect(recorded).toEqual({ ...event, data: { ...event.data, href: expected } });
|
|
262
|
+
}
|
|
263
|
+
expect(event.data).toEqual({ href, width: 1920, height: 1080 });
|
|
264
|
+
|
|
265
|
+
recorder.stop();
|
|
266
|
+
});
|
|
267
|
+
|
|
237
268
|
it('parameterizes meta href using custom parameterizeRoute', () => {
|
|
238
269
|
const engine = new MockEngine();
|
|
239
270
|
engine.eventsOnStart = [
|
|
240
271
|
{
|
|
241
272
|
type: RecordingEventType.Meta,
|
|
242
273
|
timestamp: 1,
|
|
243
|
-
data: {
|
|
274
|
+
data: {
|
|
275
|
+
href: 'https://example.com/teams/acme-corp/dashboard?email=alice@example.com#token',
|
|
276
|
+
width: 1920,
|
|
277
|
+
height: 1080,
|
|
278
|
+
},
|
|
244
279
|
},
|
|
245
280
|
];
|
|
246
281
|
const onEvent = vi.fn();
|
|
247
282
|
const recorder = new Recorder({ engine, onEvent });
|
|
283
|
+
const parameterizeRoute = vi.fn((route: string) => route.replace(/\/teams\/[^/]+/, '/teams/:slug'));
|
|
248
284
|
recorder.start({
|
|
249
|
-
parameterizeRoute
|
|
285
|
+
parameterizeRoute,
|
|
250
286
|
});
|
|
251
287
|
|
|
288
|
+
expect(parameterizeRoute).toHaveBeenCalledWith('/teams/acme-corp/dashboard');
|
|
289
|
+
|
|
252
290
|
const metaEvents = (onEvent.mock.calls as [RecordingEvent][])
|
|
253
291
|
.map(([e]) => e)
|
|
254
292
|
.filter(e => e.type === RecordingEventType.Meta);
|
package/src/recorder.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
RecordingEvent,
|
|
3
3
|
RecordingEventType,
|
|
4
4
|
RecordingPluginName,
|
|
5
|
+
stripUrlQueryAndHash,
|
|
5
6
|
type TabVisibilityPluginData,
|
|
6
7
|
type NetworkRequestPluginData,
|
|
7
8
|
type RouteChangePluginData,
|
|
@@ -202,12 +203,13 @@ export class Recorder {
|
|
|
202
203
|
}
|
|
203
204
|
|
|
204
205
|
private parameterizeHref(href: string): string {
|
|
206
|
+
const strippedHref = stripUrlQueryAndHash(href);
|
|
205
207
|
try {
|
|
206
|
-
const url = new URL(
|
|
208
|
+
const url = new URL(strippedHref);
|
|
207
209
|
url.pathname = this.parameterizeRoute(url.pathname);
|
|
208
210
|
return url.toString();
|
|
209
211
|
} catch (_e) {
|
|
210
|
-
return this.parameterizeRoute(
|
|
212
|
+
return this.parameterizeRoute(strippedHref);
|
|
211
213
|
}
|
|
212
214
|
}
|
|
213
215
|
|