@spotify-confidence/session-recording 0.18.10 → 0.18.12
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 +25 -0
- package/dist/index.cjs +72 -11
- package/dist/index.js +72 -11
- package/dist/{uploader-CkAqZXJP.js → uploader-B6-mcWdA.cjs} +106 -1
- package/dist/{uploader-CcDy4aME.cjs → uploader-vqAzevKI.js} +89 -12
- package/dist/worker.cjs +1 -1
- package/dist/worker.js +1 -1
- package/package.json +3 -3
- package/src/index.ts +4 -3
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.18.12](https://github.com/spotify/confidence-sdk-js/compare/session-recording-v0.18.11...session-recording-v0.18.12) (2026-09-07)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### 🐛 Bug Fixes
|
|
7
|
+
|
|
8
|
+
* stop passive recording frames extending sessions ([#449](https://github.com/spotify/confidence-sdk-js/issues/449)) ([df763a1](https://github.com/spotify/confidence-sdk-js/commit/df763a10d6f16ce5b871530ca3fe8b5c153c16d7))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @spotify-confidence/csr-common bumped to 0.18.9
|
|
16
|
+
* @spotify-confidence/csr-recorder bumped to 0.17.17
|
|
17
|
+
|
|
18
|
+
## [0.18.11](https://github.com/spotify/confidence-sdk-js/compare/session-recording-v0.18.10...session-recording-v0.18.11) (2026-08-28)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Dependencies
|
|
22
|
+
|
|
23
|
+
* The following workspace dependencies were updated
|
|
24
|
+
* dependencies
|
|
25
|
+
* @spotify-confidence/csr-common bumped to 0.18.8
|
|
26
|
+
* @spotify-confidence/csr-recorder bumped to 0.17.16
|
|
27
|
+
|
|
3
28
|
## [0.18.10](https://github.com/spotify/confidence-sdk-js/compare/session-recording-v0.18.9...session-recording-v0.18.10) (2026-08-20)
|
|
4
29
|
|
|
5
30
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_uploader = require("./uploader-
|
|
2
|
+
const require_uploader = require("./uploader-B6-mcWdA.cjs");
|
|
3
3
|
const VALID_KEY_PATTERN = /^[a-zA-Z0-9_.-]+$/;
|
|
4
4
|
function validateKey(key) {
|
|
5
5
|
if (typeof key !== "string" || key.length === 0) return "key is empty";
|
|
@@ -21,7 +21,7 @@ function validateMeasureValue(value) {
|
|
|
21
21
|
//#endregion
|
|
22
22
|
//#region ../csr-recorder/src/types.ts
|
|
23
23
|
const DEFAULT_MASK_SELECTORS = ["[data-csr-mask]"];
|
|
24
|
-
const DEFAULT_BLOCK_SELECTORS = ["[data-csr-block]"];
|
|
24
|
+
const DEFAULT_BLOCK_SELECTORS = ["[data-csr-block]", "video"];
|
|
25
25
|
//#endregion
|
|
26
26
|
//#region ../csr-recorder/src/route-parameterizer.ts
|
|
27
27
|
const SEGMENT_PATTERNS = [
|
|
@@ -118,7 +118,7 @@ var Recorder = class Recorder {
|
|
|
118
118
|
if (typeof document !== "undefined") {
|
|
119
119
|
this.visibilityHandler = () => {
|
|
120
120
|
const data = {
|
|
121
|
-
plugin:
|
|
121
|
+
plugin: require_uploader.RecordingPluginName.TabVisibility,
|
|
122
122
|
payload: { hidden: document.hidden }
|
|
123
123
|
};
|
|
124
124
|
this.onEvent({
|
|
@@ -140,7 +140,7 @@ var Recorder = class Recorder {
|
|
|
140
140
|
}
|
|
141
141
|
emitNetworkRequest(payload) {
|
|
142
142
|
const data = {
|
|
143
|
-
plugin:
|
|
143
|
+
plugin: require_uploader.RecordingPluginName.NetworkRequest,
|
|
144
144
|
payload
|
|
145
145
|
};
|
|
146
146
|
this.onEvent({
|
|
@@ -248,7 +248,7 @@ var Recorder = class Recorder {
|
|
|
248
248
|
const paramTo = this.parameterizeRoute(to);
|
|
249
249
|
if (paramFrom === paramTo) return;
|
|
250
250
|
const data = {
|
|
251
|
-
plugin:
|
|
251
|
+
plugin: require_uploader.RecordingPluginName.RouteChange,
|
|
252
252
|
payload: {
|
|
253
253
|
from: paramFrom,
|
|
254
254
|
to: paramTo,
|
|
@@ -11138,6 +11138,63 @@ const ALL_CONSOLE_LEVELS = [
|
|
|
11138
11138
|
"debug",
|
|
11139
11139
|
"info"
|
|
11140
11140
|
];
|
|
11141
|
+
const BLOCKED_ELEMENT_ATTRIBUTE = "data-csr-blocked-element";
|
|
11142
|
+
function labelBlockedElement(node) {
|
|
11143
|
+
if (node.type === 2 && node.tagName !== void 0 && node.attributes !== void 0 && typeof node.attributes.rr_width === "string" && typeof node.attributes.rr_height === "string") {
|
|
11144
|
+
node.attributes[BLOCKED_ELEMENT_ATTRIBUTE] = node.tagName;
|
|
11145
|
+
node.tagName = "div";
|
|
11146
|
+
}
|
|
11147
|
+
node.childNodes?.forEach(labelBlockedElement);
|
|
11148
|
+
}
|
|
11149
|
+
/**
|
|
11150
|
+
* rrweb strips blocked elements down to their dimensions, but retains their
|
|
11151
|
+
* original tag name. Rebuild them as inert divs and keep the tag name as safe
|
|
11152
|
+
* metadata so players can render a useful placeholder label.
|
|
11153
|
+
*/
|
|
11154
|
+
function blockedElementLabelsPlugin() {
|
|
11155
|
+
return {
|
|
11156
|
+
name: require_uploader.RecordingPluginName.BlockedElementLabels,
|
|
11157
|
+
options: {},
|
|
11158
|
+
observer: () => () => {},
|
|
11159
|
+
eventProcessor: (event) => {
|
|
11160
|
+
if (event.type === EventType.FullSnapshot) labelBlockedElement(event.data.node);
|
|
11161
|
+
else if (event.type === EventType.IncrementalSnapshot && event.data.source === IncrementalSource.Mutation) event.data.adds.forEach((add) => labelBlockedElement(add.node));
|
|
11162
|
+
return event;
|
|
11163
|
+
}
|
|
11164
|
+
};
|
|
11165
|
+
}
|
|
11166
|
+
/**
|
|
11167
|
+
* Record clipboard actions and their DOM target without reading clipboard
|
|
11168
|
+
* contents. The resulting rrweb Plugin events can explain otherwise
|
|
11169
|
+
* surprising input changes during analysis.
|
|
11170
|
+
*/
|
|
11171
|
+
function clipboardActionsPlugin() {
|
|
11172
|
+
let getId;
|
|
11173
|
+
return {
|
|
11174
|
+
name: require_uploader.RecordingPluginName.Clipboard,
|
|
11175
|
+
options: {},
|
|
11176
|
+
getMirror: ({ nodeMirror }) => {
|
|
11177
|
+
getId = (node) => nodeMirror.getId(node);
|
|
11178
|
+
},
|
|
11179
|
+
observer: (callback, win) => {
|
|
11180
|
+
const handlers = [
|
|
11181
|
+
"copy",
|
|
11182
|
+
"cut",
|
|
11183
|
+
"paste"
|
|
11184
|
+
].map((action) => {
|
|
11185
|
+
const handler = (event) => {
|
|
11186
|
+
callback({
|
|
11187
|
+
action,
|
|
11188
|
+
targetId: event.target instanceof win.Node ? getId?.(event.target) ?? -1 : -1
|
|
11189
|
+
});
|
|
11190
|
+
};
|
|
11191
|
+
win.document.addEventListener(action, handler, true);
|
|
11192
|
+
return () => win.document.removeEventListener(action, handler, true);
|
|
11193
|
+
});
|
|
11194
|
+
return () => handlers.forEach((remove) => remove());
|
|
11195
|
+
}
|
|
11196
|
+
};
|
|
11197
|
+
}
|
|
11141
11198
|
/**
|
|
11142
11199
|
* rrweb does not include modifier keys in mouse-interaction events. Capture
|
|
11143
11200
|
* the native click first, then add its safe, non-text metadata to the rrweb
|
|
@@ -11146,7 +11203,7 @@ const ALL_CONSOLE_LEVELS = [
|
|
|
11146
11203
|
function clickModifiersPlugin() {
|
|
11147
11204
|
let pendingClick = null;
|
|
11148
11205
|
return {
|
|
11149
|
-
name:
|
|
11206
|
+
name: require_uploader.RecordingPluginName.ClickModifiers,
|
|
11150
11207
|
options: {},
|
|
11151
11208
|
observer: (_callback, win) => {
|
|
11152
11209
|
const onClick = (event) => {
|
|
@@ -11190,7 +11247,11 @@ var RrwebEngine = class {
|
|
|
11190
11247
|
start(config, onEvent) {
|
|
11191
11248
|
const maskSelectors = config.maskSelectors ?? DEFAULT_MASK_SELECTORS;
|
|
11192
11249
|
const blockSelectors = config.blockSelectors ?? DEFAULT_BLOCK_SELECTORS;
|
|
11193
|
-
const plugins = [
|
|
11250
|
+
const plugins = [
|
|
11251
|
+
clickModifiersPlugin(),
|
|
11252
|
+
clipboardActionsPlugin(),
|
|
11253
|
+
blockedElementLabelsPlugin()
|
|
11254
|
+
];
|
|
11194
11255
|
const { captureConsoleLogs } = config;
|
|
11195
11256
|
if (captureConsoleLogs) {
|
|
11196
11257
|
const levels = captureConsoleLogs === true ? ALL_CONSOLE_LEVELS : captureConsoleLogs.levels;
|
|
@@ -11265,7 +11326,7 @@ function observeFlags(onFlagWrite) {
|
|
|
11265
11326
|
}
|
|
11266
11327
|
//#endregion
|
|
11267
11328
|
//#region src/version.ts
|
|
11268
|
-
const SDK_VERSION = "0.18.
|
|
11329
|
+
const SDK_VERSION = "0.18.12";
|
|
11269
11330
|
//#endregion
|
|
11270
11331
|
//#region src/index.ts
|
|
11271
11332
|
const DEFAULT_API_URL = "https://recording.confidence.dev";
|
|
@@ -11343,7 +11404,7 @@ function initSessionRecorder(options) {
|
|
|
11343
11404
|
stopRecorder = record(sendEvent, recordingConfig);
|
|
11344
11405
|
stopObservingFlags = observeFlags(({ flagKey, variant, assignmentOrigin }) => {
|
|
11345
11406
|
const data = {
|
|
11346
|
-
plugin:
|
|
11407
|
+
plugin: require_uploader.RecordingPluginName.FlagEvaluation,
|
|
11347
11408
|
payload: {
|
|
11348
11409
|
flagKey,
|
|
11349
11410
|
variant,
|
|
@@ -11393,7 +11454,7 @@ function initSessionRecorder(options) {
|
|
|
11393
11454
|
return;
|
|
11394
11455
|
}
|
|
11395
11456
|
const data = {
|
|
11396
|
-
plugin:
|
|
11457
|
+
plugin: require_uploader.RecordingPluginName.Tag,
|
|
11397
11458
|
payload: value !== void 0 ? {
|
|
11398
11459
|
key,
|
|
11399
11460
|
value
|
|
@@ -11417,7 +11478,7 @@ function initSessionRecorder(options) {
|
|
|
11417
11478
|
return;
|
|
11418
11479
|
}
|
|
11419
11480
|
const data = {
|
|
11420
|
-
plugin:
|
|
11481
|
+
plugin: require_uploader.RecordingPluginName.Measure,
|
|
11421
11482
|
payload: value !== void 0 ? {
|
|
11422
11483
|
key,
|
|
11423
11484
|
value
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as createUploader } from "./uploader-
|
|
1
|
+
import { r as RecordingPluginName, t as createUploader } from "./uploader-vqAzevKI.js";
|
|
2
2
|
const VALID_KEY_PATTERN = /^[a-zA-Z0-9_.-]+$/;
|
|
3
3
|
function validateKey(key) {
|
|
4
4
|
if (typeof key !== "string" || key.length === 0) return "key is empty";
|
|
@@ -20,7 +20,7 @@ function validateMeasureValue(value) {
|
|
|
20
20
|
//#endregion
|
|
21
21
|
//#region ../csr-recorder/src/types.ts
|
|
22
22
|
const DEFAULT_MASK_SELECTORS = ["[data-csr-mask]"];
|
|
23
|
-
const DEFAULT_BLOCK_SELECTORS = ["[data-csr-block]"];
|
|
23
|
+
const DEFAULT_BLOCK_SELECTORS = ["[data-csr-block]", "video"];
|
|
24
24
|
//#endregion
|
|
25
25
|
//#region ../csr-recorder/src/route-parameterizer.ts
|
|
26
26
|
const SEGMENT_PATTERNS = [
|
|
@@ -117,7 +117,7 @@ var Recorder = class Recorder {
|
|
|
117
117
|
if (typeof document !== "undefined") {
|
|
118
118
|
this.visibilityHandler = () => {
|
|
119
119
|
const data = {
|
|
120
|
-
plugin:
|
|
120
|
+
plugin: RecordingPluginName.TabVisibility,
|
|
121
121
|
payload: { hidden: document.hidden }
|
|
122
122
|
};
|
|
123
123
|
this.onEvent({
|
|
@@ -139,7 +139,7 @@ var Recorder = class Recorder {
|
|
|
139
139
|
}
|
|
140
140
|
emitNetworkRequest(payload) {
|
|
141
141
|
const data = {
|
|
142
|
-
plugin:
|
|
142
|
+
plugin: RecordingPluginName.NetworkRequest,
|
|
143
143
|
payload
|
|
144
144
|
};
|
|
145
145
|
this.onEvent({
|
|
@@ -247,7 +247,7 @@ var Recorder = class Recorder {
|
|
|
247
247
|
const paramTo = this.parameterizeRoute(to);
|
|
248
248
|
if (paramFrom === paramTo) return;
|
|
249
249
|
const data = {
|
|
250
|
-
plugin:
|
|
250
|
+
plugin: RecordingPluginName.RouteChange,
|
|
251
251
|
payload: {
|
|
252
252
|
from: paramFrom,
|
|
253
253
|
to: paramTo,
|
|
@@ -11119,6 +11119,63 @@ const ALL_CONSOLE_LEVELS = [
|
|
|
11119
11119
|
"debug",
|
|
11120
11120
|
"info"
|
|
11121
11121
|
];
|
|
11122
|
+
const BLOCKED_ELEMENT_ATTRIBUTE = "data-csr-blocked-element";
|
|
11123
|
+
function labelBlockedElement(node) {
|
|
11124
|
+
if (node.type === 2 && node.tagName !== void 0 && node.attributes !== void 0 && typeof node.attributes.rr_width === "string" && typeof node.attributes.rr_height === "string") {
|
|
11125
|
+
node.attributes[BLOCKED_ELEMENT_ATTRIBUTE] = node.tagName;
|
|
11126
|
+
node.tagName = "div";
|
|
11127
|
+
}
|
|
11128
|
+
node.childNodes?.forEach(labelBlockedElement);
|
|
11129
|
+
}
|
|
11130
|
+
/**
|
|
11131
|
+
* rrweb strips blocked elements down to their dimensions, but retains their
|
|
11132
|
+
* original tag name. Rebuild them as inert divs and keep the tag name as safe
|
|
11133
|
+
* metadata so players can render a useful placeholder label.
|
|
11134
|
+
*/
|
|
11135
|
+
function blockedElementLabelsPlugin() {
|
|
11136
|
+
return {
|
|
11137
|
+
name: RecordingPluginName.BlockedElementLabels,
|
|
11138
|
+
options: {},
|
|
11139
|
+
observer: () => () => {},
|
|
11140
|
+
eventProcessor: (event) => {
|
|
11141
|
+
if (event.type === EventType.FullSnapshot) labelBlockedElement(event.data.node);
|
|
11142
|
+
else if (event.type === EventType.IncrementalSnapshot && event.data.source === IncrementalSource.Mutation) event.data.adds.forEach((add) => labelBlockedElement(add.node));
|
|
11143
|
+
return event;
|
|
11144
|
+
}
|
|
11145
|
+
};
|
|
11146
|
+
}
|
|
11147
|
+
/**
|
|
11148
|
+
* Record clipboard actions and their DOM target without reading clipboard
|
|
11149
|
+
* contents. The resulting rrweb Plugin events can explain otherwise
|
|
11150
|
+
* surprising input changes during analysis.
|
|
11151
|
+
*/
|
|
11152
|
+
function clipboardActionsPlugin() {
|
|
11153
|
+
let getId;
|
|
11154
|
+
return {
|
|
11155
|
+
name: RecordingPluginName.Clipboard,
|
|
11156
|
+
options: {},
|
|
11157
|
+
getMirror: ({ nodeMirror }) => {
|
|
11158
|
+
getId = (node) => nodeMirror.getId(node);
|
|
11159
|
+
},
|
|
11160
|
+
observer: (callback, win) => {
|
|
11161
|
+
const handlers = [
|
|
11162
|
+
"copy",
|
|
11163
|
+
"cut",
|
|
11164
|
+
"paste"
|
|
11165
|
+
].map((action) => {
|
|
11166
|
+
const handler = (event) => {
|
|
11167
|
+
callback({
|
|
11168
|
+
action,
|
|
11169
|
+
targetId: event.target instanceof win.Node ? getId?.(event.target) ?? -1 : -1
|
|
11170
|
+
});
|
|
11171
|
+
};
|
|
11172
|
+
win.document.addEventListener(action, handler, true);
|
|
11173
|
+
return () => win.document.removeEventListener(action, handler, true);
|
|
11174
|
+
});
|
|
11175
|
+
return () => handlers.forEach((remove) => remove());
|
|
11176
|
+
}
|
|
11177
|
+
};
|
|
11178
|
+
}
|
|
11122
11179
|
/**
|
|
11123
11180
|
* rrweb does not include modifier keys in mouse-interaction events. Capture
|
|
11124
11181
|
* the native click first, then add its safe, non-text metadata to the rrweb
|
|
@@ -11127,7 +11184,7 @@ const ALL_CONSOLE_LEVELS = [
|
|
|
11127
11184
|
function clickModifiersPlugin() {
|
|
11128
11185
|
let pendingClick = null;
|
|
11129
11186
|
return {
|
|
11130
|
-
name:
|
|
11187
|
+
name: RecordingPluginName.ClickModifiers,
|
|
11131
11188
|
options: {},
|
|
11132
11189
|
observer: (_callback, win) => {
|
|
11133
11190
|
const onClick = (event) => {
|
|
@@ -11171,7 +11228,11 @@ var RrwebEngine = class {
|
|
|
11171
11228
|
start(config, onEvent) {
|
|
11172
11229
|
const maskSelectors = config.maskSelectors ?? DEFAULT_MASK_SELECTORS;
|
|
11173
11230
|
const blockSelectors = config.blockSelectors ?? DEFAULT_BLOCK_SELECTORS;
|
|
11174
|
-
const plugins = [
|
|
11231
|
+
const plugins = [
|
|
11232
|
+
clickModifiersPlugin(),
|
|
11233
|
+
clipboardActionsPlugin(),
|
|
11234
|
+
blockedElementLabelsPlugin()
|
|
11235
|
+
];
|
|
11175
11236
|
const { captureConsoleLogs } = config;
|
|
11176
11237
|
if (captureConsoleLogs) {
|
|
11177
11238
|
const levels = captureConsoleLogs === true ? ALL_CONSOLE_LEVELS : captureConsoleLogs.levels;
|
|
@@ -11246,7 +11307,7 @@ function observeFlags(onFlagWrite) {
|
|
|
11246
11307
|
}
|
|
11247
11308
|
//#endregion
|
|
11248
11309
|
//#region src/version.ts
|
|
11249
|
-
const SDK_VERSION = "0.18.
|
|
11310
|
+
const SDK_VERSION = "0.18.12";
|
|
11250
11311
|
//#endregion
|
|
11251
11312
|
//#region src/index.ts
|
|
11252
11313
|
const DEFAULT_API_URL = "https://recording.confidence.dev";
|
|
@@ -11324,7 +11385,7 @@ function initSessionRecorder(options) {
|
|
|
11324
11385
|
stopRecorder = record(sendEvent, recordingConfig);
|
|
11325
11386
|
stopObservingFlags = observeFlags(({ flagKey, variant, assignmentOrigin }) => {
|
|
11326
11387
|
const data = {
|
|
11327
|
-
plugin:
|
|
11388
|
+
plugin: RecordingPluginName.FlagEvaluation,
|
|
11328
11389
|
payload: {
|
|
11329
11390
|
flagKey,
|
|
11330
11391
|
variant,
|
|
@@ -11374,7 +11435,7 @@ function initSessionRecorder(options) {
|
|
|
11374
11435
|
return;
|
|
11375
11436
|
}
|
|
11376
11437
|
const data = {
|
|
11377
|
-
plugin:
|
|
11438
|
+
plugin: RecordingPluginName.Tag,
|
|
11378
11439
|
payload: value !== void 0 ? {
|
|
11379
11440
|
key,
|
|
11380
11441
|
value
|
|
@@ -11398,7 +11459,7 @@ function initSessionRecorder(options) {
|
|
|
11398
11459
|
return;
|
|
11399
11460
|
}
|
|
11400
11461
|
const data = {
|
|
11401
|
-
plugin:
|
|
11462
|
+
plugin: RecordingPluginName.Measure,
|
|
11402
11463
|
payload: value !== void 0 ? {
|
|
11403
11464
|
key,
|
|
11404
11465
|
value
|
|
@@ -21,6 +21,93 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
21
|
enumerable: true
|
|
22
22
|
}) : target, mod));
|
|
23
23
|
//#endregion
|
|
24
|
+
//#region ../csr-common/src/events.ts
|
|
25
|
+
const RecordingCustomEventTag = {
|
|
26
|
+
RageClick: "csr:rageClick",
|
|
27
|
+
FormFieldReEdit: "csr:formFieldReEdit",
|
|
28
|
+
ScrollBack: "csr:scrollBack",
|
|
29
|
+
Click: "csr:click",
|
|
30
|
+
Input: "csr:input",
|
|
31
|
+
DeadClick: "csr:deadClick",
|
|
32
|
+
TabUnfocus: "csr:tabUnfocus",
|
|
33
|
+
TabRefocus: "csr:tabRefocus",
|
|
34
|
+
RouteChange: "csr:routeChange",
|
|
35
|
+
ErrorMessage: "csr:errorMessage",
|
|
36
|
+
DialogOpened: "csr:dialogOpened",
|
|
37
|
+
IdleGap: "csr:idleGap",
|
|
38
|
+
AwayGap: "csr:awayGap"
|
|
39
|
+
};
|
|
40
|
+
const RecordingPluginName = {
|
|
41
|
+
BlockedElementLabels: "csr/blocked-element-labels@1",
|
|
42
|
+
Clipboard: "csr/clipboard@1",
|
|
43
|
+
ClickModifiers: "csr/click-modifiers@1",
|
|
44
|
+
TabVisibility: "csr:tabVisibility",
|
|
45
|
+
ConsoleLog: "rrweb/console@1",
|
|
46
|
+
NetworkRequest: "csr:networkRequest",
|
|
47
|
+
RouteChange: "csr:routeChange",
|
|
48
|
+
Tag: "csr:tag",
|
|
49
|
+
Measure: "csr:measure",
|
|
50
|
+
FlagEvaluation: "csr:flagEvaluation"
|
|
51
|
+
};
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region ../csr-common/src/metrics.ts
|
|
54
|
+
const RecordingMetricKey = {
|
|
55
|
+
Click: "clicks",
|
|
56
|
+
Input: "inputs",
|
|
57
|
+
RageClick: "rageClicks",
|
|
58
|
+
DeadClick: "deadClicks",
|
|
59
|
+
ScrollBack: "scrollBacks",
|
|
60
|
+
TabUnfocus: "tabUnfocuses",
|
|
61
|
+
ErrorMessage: "errorMessages",
|
|
62
|
+
FailedNetworkRequest: "networkRequestsFailed",
|
|
63
|
+
NetworkRequest: "networkRequests",
|
|
64
|
+
ConsoleLog: "consoleLogs",
|
|
65
|
+
ConsoleWarning: "consoleWarnings",
|
|
66
|
+
ConsoleError: "consoleErrors",
|
|
67
|
+
RouteChange: "routeChanges"
|
|
68
|
+
};
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region ../csr-common/src/session-activity.ts
|
|
71
|
+
const USER_INTERACTION_SOURCES = new Set([
|
|
72
|
+
1,
|
|
73
|
+
2,
|
|
74
|
+
3,
|
|
75
|
+
5,
|
|
76
|
+
6,
|
|
77
|
+
7,
|
|
78
|
+
12,
|
|
79
|
+
14
|
|
80
|
+
]);
|
|
81
|
+
const USER_INTERACTION_TAGS = new Set([
|
|
82
|
+
RecordingCustomEventTag.Click,
|
|
83
|
+
RecordingCustomEventTag.Input,
|
|
84
|
+
RecordingCustomEventTag.RageClick,
|
|
85
|
+
RecordingCustomEventTag.DeadClick,
|
|
86
|
+
RecordingCustomEventTag.ScrollBack,
|
|
87
|
+
RecordingCustomEventTag.TabUnfocus,
|
|
88
|
+
RecordingCustomEventTag.TabRefocus,
|
|
89
|
+
RecordingCustomEventTag.FormFieldReEdit,
|
|
90
|
+
RecordingCustomEventTag.RouteChange
|
|
91
|
+
]);
|
|
92
|
+
const USER_INTERACTION_PLUGINS = new Set([RecordingPluginName.RouteChange]);
|
|
93
|
+
new Set([
|
|
94
|
+
RecordingMetricKey.Click,
|
|
95
|
+
RecordingMetricKey.Input,
|
|
96
|
+
RecordingMetricKey.RageClick,
|
|
97
|
+
RecordingMetricKey.DeadClick,
|
|
98
|
+
RecordingMetricKey.ScrollBack,
|
|
99
|
+
RecordingMetricKey.TabUnfocus,
|
|
100
|
+
RecordingMetricKey.RouteChange
|
|
101
|
+
]);
|
|
102
|
+
const isObject = (value) => typeof value === "object" && value !== null;
|
|
103
|
+
const isUserInteractionEvent = (event) => {
|
|
104
|
+
if (!isObject(event) || !isObject(event.data)) return false;
|
|
105
|
+
if (event.type === 3) return typeof event.data.source === "number" && USER_INTERACTION_SOURCES.has(event.data.source);
|
|
106
|
+
if (event.type === 5) return typeof event.data.tag === "string" && USER_INTERACTION_TAGS.has(event.data.tag);
|
|
107
|
+
return event.type === 6 && typeof event.data.plugin === "string" && USER_INTERACTION_PLUGINS.has(event.data.plugin);
|
|
108
|
+
};
|
|
109
|
+
const isSessionActivityEvent = (event) => isObject(event) && event.type === 4 || isUserInteractionEvent(event);
|
|
110
|
+
//#endregion
|
|
24
111
|
//#region ../csr-common/src/uploader/client-context.ts
|
|
25
112
|
var import_es5 = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
26
113
|
(function(e, t) {
|
|
@@ -1897,6 +1984,7 @@ async function createUploader(opts) {
|
|
|
1897
1984
|
tabId: effectiveTabId,
|
|
1898
1985
|
eventCounter: counter,
|
|
1899
1986
|
data: event,
|
|
1987
|
+
userActivity: isSessionActivityEvent(event),
|
|
1900
1988
|
...nextAdoptionMeta ?? {}
|
|
1901
1989
|
};
|
|
1902
1990
|
counter += 1;
|
|
@@ -2060,4 +2148,21 @@ function writeCounter(counter) {
|
|
|
2060
2148
|
sessionStorage.setItem(STORAGE_COUNTER, String(counter));
|
|
2061
2149
|
}
|
|
2062
2150
|
//#endregion
|
|
2063
|
-
|
|
2151
|
+
Object.defineProperty(exports, "RecordingPluginName", {
|
|
2152
|
+
enumerable: true,
|
|
2153
|
+
get: function() {
|
|
2154
|
+
return RecordingPluginName;
|
|
2155
|
+
}
|
|
2156
|
+
});
|
|
2157
|
+
Object.defineProperty(exports, "createUploader", {
|
|
2158
|
+
enumerable: true,
|
|
2159
|
+
get: function() {
|
|
2160
|
+
return createUploader;
|
|
2161
|
+
}
|
|
2162
|
+
});
|
|
2163
|
+
Object.defineProperty(exports, "workerScript", {
|
|
2164
|
+
enumerable: true,
|
|
2165
|
+
get: function() {
|
|
2166
|
+
return workerScript;
|
|
2167
|
+
}
|
|
2168
|
+
});
|
|
@@ -21,6 +21,93 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
21
|
enumerable: true
|
|
22
22
|
}) : target, mod));
|
|
23
23
|
//#endregion
|
|
24
|
+
//#region ../csr-common/src/events.ts
|
|
25
|
+
const RecordingCustomEventTag = {
|
|
26
|
+
RageClick: "csr:rageClick",
|
|
27
|
+
FormFieldReEdit: "csr:formFieldReEdit",
|
|
28
|
+
ScrollBack: "csr:scrollBack",
|
|
29
|
+
Click: "csr:click",
|
|
30
|
+
Input: "csr:input",
|
|
31
|
+
DeadClick: "csr:deadClick",
|
|
32
|
+
TabUnfocus: "csr:tabUnfocus",
|
|
33
|
+
TabRefocus: "csr:tabRefocus",
|
|
34
|
+
RouteChange: "csr:routeChange",
|
|
35
|
+
ErrorMessage: "csr:errorMessage",
|
|
36
|
+
DialogOpened: "csr:dialogOpened",
|
|
37
|
+
IdleGap: "csr:idleGap",
|
|
38
|
+
AwayGap: "csr:awayGap"
|
|
39
|
+
};
|
|
40
|
+
const RecordingPluginName = {
|
|
41
|
+
BlockedElementLabels: "csr/blocked-element-labels@1",
|
|
42
|
+
Clipboard: "csr/clipboard@1",
|
|
43
|
+
ClickModifiers: "csr/click-modifiers@1",
|
|
44
|
+
TabVisibility: "csr:tabVisibility",
|
|
45
|
+
ConsoleLog: "rrweb/console@1",
|
|
46
|
+
NetworkRequest: "csr:networkRequest",
|
|
47
|
+
RouteChange: "csr:routeChange",
|
|
48
|
+
Tag: "csr:tag",
|
|
49
|
+
Measure: "csr:measure",
|
|
50
|
+
FlagEvaluation: "csr:flagEvaluation"
|
|
51
|
+
};
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region ../csr-common/src/metrics.ts
|
|
54
|
+
const RecordingMetricKey = {
|
|
55
|
+
Click: "clicks",
|
|
56
|
+
Input: "inputs",
|
|
57
|
+
RageClick: "rageClicks",
|
|
58
|
+
DeadClick: "deadClicks",
|
|
59
|
+
ScrollBack: "scrollBacks",
|
|
60
|
+
TabUnfocus: "tabUnfocuses",
|
|
61
|
+
ErrorMessage: "errorMessages",
|
|
62
|
+
FailedNetworkRequest: "networkRequestsFailed",
|
|
63
|
+
NetworkRequest: "networkRequests",
|
|
64
|
+
ConsoleLog: "consoleLogs",
|
|
65
|
+
ConsoleWarning: "consoleWarnings",
|
|
66
|
+
ConsoleError: "consoleErrors",
|
|
67
|
+
RouteChange: "routeChanges"
|
|
68
|
+
};
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region ../csr-common/src/session-activity.ts
|
|
71
|
+
const USER_INTERACTION_SOURCES = new Set([
|
|
72
|
+
1,
|
|
73
|
+
2,
|
|
74
|
+
3,
|
|
75
|
+
5,
|
|
76
|
+
6,
|
|
77
|
+
7,
|
|
78
|
+
12,
|
|
79
|
+
14
|
|
80
|
+
]);
|
|
81
|
+
const USER_INTERACTION_TAGS = new Set([
|
|
82
|
+
RecordingCustomEventTag.Click,
|
|
83
|
+
RecordingCustomEventTag.Input,
|
|
84
|
+
RecordingCustomEventTag.RageClick,
|
|
85
|
+
RecordingCustomEventTag.DeadClick,
|
|
86
|
+
RecordingCustomEventTag.ScrollBack,
|
|
87
|
+
RecordingCustomEventTag.TabUnfocus,
|
|
88
|
+
RecordingCustomEventTag.TabRefocus,
|
|
89
|
+
RecordingCustomEventTag.FormFieldReEdit,
|
|
90
|
+
RecordingCustomEventTag.RouteChange
|
|
91
|
+
]);
|
|
92
|
+
const USER_INTERACTION_PLUGINS = new Set([RecordingPluginName.RouteChange]);
|
|
93
|
+
new Set([
|
|
94
|
+
RecordingMetricKey.Click,
|
|
95
|
+
RecordingMetricKey.Input,
|
|
96
|
+
RecordingMetricKey.RageClick,
|
|
97
|
+
RecordingMetricKey.DeadClick,
|
|
98
|
+
RecordingMetricKey.ScrollBack,
|
|
99
|
+
RecordingMetricKey.TabUnfocus,
|
|
100
|
+
RecordingMetricKey.RouteChange
|
|
101
|
+
]);
|
|
102
|
+
const isObject = (value) => typeof value === "object" && value !== null;
|
|
103
|
+
const isUserInteractionEvent = (event) => {
|
|
104
|
+
if (!isObject(event) || !isObject(event.data)) return false;
|
|
105
|
+
if (event.type === 3) return typeof event.data.source === "number" && USER_INTERACTION_SOURCES.has(event.data.source);
|
|
106
|
+
if (event.type === 5) return typeof event.data.tag === "string" && USER_INTERACTION_TAGS.has(event.data.tag);
|
|
107
|
+
return event.type === 6 && typeof event.data.plugin === "string" && USER_INTERACTION_PLUGINS.has(event.data.plugin);
|
|
108
|
+
};
|
|
109
|
+
const isSessionActivityEvent = (event) => isObject(event) && event.type === 4 || isUserInteractionEvent(event);
|
|
110
|
+
//#endregion
|
|
24
111
|
//#region ../csr-common/src/uploader/client-context.ts
|
|
25
112
|
var import_es5 = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
26
113
|
(function(e, t) {
|
|
@@ -1897,6 +1984,7 @@ async function createUploader(opts) {
|
|
|
1897
1984
|
tabId: effectiveTabId,
|
|
1898
1985
|
eventCounter: counter,
|
|
1899
1986
|
data: event,
|
|
1987
|
+
userActivity: isSessionActivityEvent(event),
|
|
1900
1988
|
...nextAdoptionMeta ?? {}
|
|
1901
1989
|
};
|
|
1902
1990
|
counter += 1;
|
|
@@ -2060,15 +2148,4 @@ function writeCounter(counter) {
|
|
|
2060
2148
|
sessionStorage.setItem(STORAGE_COUNTER, String(counter));
|
|
2061
2149
|
}
|
|
2062
2150
|
//#endregion
|
|
2063
|
-
|
|
2064
|
-
enumerable: true,
|
|
2065
|
-
get: function() {
|
|
2066
|
-
return createUploader;
|
|
2067
|
-
}
|
|
2068
|
-
});
|
|
2069
|
-
Object.defineProperty(exports, "workerScript", {
|
|
2070
|
-
enumerable: true,
|
|
2071
|
-
get: function() {
|
|
2072
|
-
return workerScript;
|
|
2073
|
-
}
|
|
2074
|
-
});
|
|
2151
|
+
export { workerScript as n, RecordingPluginName as r, createUploader as t };
|
package/dist/worker.cjs
CHANGED
package/dist/worker.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as workerScript } from "./uploader-
|
|
1
|
+
import { n as workerScript } from "./uploader-vqAzevKI.js";
|
|
2
2
|
export { workerScript };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spotify-confidence/session-recording",
|
|
3
3
|
"license": "Apache-2.0",
|
|
4
|
-
"version": "0.18.
|
|
4
|
+
"version": "0.18.12",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/spotify/confidence-sdk-js.git",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@spotify-confidence/csr-common": "0.18.
|
|
45
|
-
"@spotify-confidence/csr-recorder": "0.17.
|
|
44
|
+
"@spotify-confidence/csr-common": "0.18.9",
|
|
45
|
+
"@spotify-confidence/csr-recorder": "0.17.17"
|
|
46
46
|
},
|
|
47
47
|
"module": "./dist/index.js",
|
|
48
48
|
"exports": {
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { record } from '@spotify-confidence/csr-recorder';
|
|
|
2
2
|
import type { ConsoleLogLevel } from '@spotify-confidence/csr-common';
|
|
3
3
|
import {
|
|
4
4
|
RecordingEventType,
|
|
5
|
+
RecordingPluginName,
|
|
5
6
|
type TagPluginData,
|
|
6
7
|
type MeasurePluginData,
|
|
7
8
|
type FlagEvaluationPluginData,
|
|
@@ -175,7 +176,7 @@ export function initSessionRecorder(options: InitSessionRecorderOptions): Sessio
|
|
|
175
176
|
|
|
176
177
|
stopObservingFlags = observeFlags(({ flagKey, variant, assignmentOrigin }) => {
|
|
177
178
|
const data: FlagEvaluationPluginData = {
|
|
178
|
-
plugin:
|
|
179
|
+
plugin: RecordingPluginName.FlagEvaluation,
|
|
179
180
|
payload: { flagKey, variant, assignmentOrigin },
|
|
180
181
|
};
|
|
181
182
|
sendEvent?.({
|
|
@@ -225,7 +226,7 @@ export function initSessionRecorder(options: InitSessionRecorderOptions): Sessio
|
|
|
225
226
|
return;
|
|
226
227
|
}
|
|
227
228
|
const data: TagPluginData = {
|
|
228
|
-
plugin:
|
|
229
|
+
plugin: RecordingPluginName.Tag,
|
|
229
230
|
payload: value !== undefined ? { key, value } : { key },
|
|
230
231
|
};
|
|
231
232
|
sendEvent?.({
|
|
@@ -246,7 +247,7 @@ export function initSessionRecorder(options: InitSessionRecorderOptions): Sessio
|
|
|
246
247
|
return;
|
|
247
248
|
}
|
|
248
249
|
const data: MeasurePluginData = {
|
|
249
|
-
plugin:
|
|
250
|
+
plugin: RecordingPluginName.Measure,
|
|
250
251
|
payload: value !== undefined ? { key, value } : { key },
|
|
251
252
|
};
|
|
252
253
|
sendEvent?.({
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SDK_VERSION = '0.18.
|
|
1
|
+
export const SDK_VERSION = '0.18.12';
|