@amplitude/plugin-session-replay-browser 0.2.1 → 0.4.0
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/README.md +32 -4
- package/lib/cjs/constants.d.ts +10 -0
- package/lib/cjs/constants.d.ts.map +1 -1
- package/lib/cjs/constants.js +16 -1
- package/lib/cjs/constants.js.map +1 -1
- package/lib/cjs/helpers.d.ts +2 -0
- package/lib/cjs/helpers.d.ts.map +1 -0
- package/lib/cjs/helpers.js +12 -0
- package/lib/cjs/helpers.js.map +1 -0
- package/lib/cjs/messages.d.ts +1 -1
- package/lib/cjs/messages.d.ts.map +1 -1
- package/lib/cjs/messages.js +5 -2
- package/lib/cjs/messages.js.map +1 -1
- package/lib/cjs/session-replay.d.ts.map +1 -1
- package/lib/cjs/session-replay.js +85 -26
- package/lib/cjs/session-replay.js.map +1 -1
- package/lib/cjs/typings/session-replay.d.ts +16 -11
- package/lib/cjs/typings/session-replay.d.ts.map +1 -1
- package/lib/cjs/typings/session-replay.js.map +1 -1
- package/lib/esm/constants.d.ts +10 -0
- package/lib/esm/constants.d.ts.map +1 -1
- package/lib/esm/constants.js +15 -0
- package/lib/esm/constants.js.map +1 -1
- package/lib/esm/helpers.d.ts +2 -0
- package/lib/esm/helpers.d.ts.map +1 -0
- package/lib/esm/helpers.js +9 -0
- package/lib/esm/helpers.js.map +1 -0
- package/lib/esm/messages.d.ts +1 -1
- package/lib/esm/messages.d.ts.map +1 -1
- package/lib/esm/messages.js +3 -1
- package/lib/esm/messages.js.map +1 -1
- package/lib/esm/session-replay.d.ts.map +1 -1
- package/lib/esm/session-replay.js +83 -24
- package/lib/esm/session-replay.js.map +1 -1
- package/lib/esm/typings/session-replay.d.ts +16 -11
- package/lib/esm/typings/session-replay.d.ts.map +1 -1
- package/lib/esm/typings/session-replay.js.map +1 -1
- package/lib/scripts/amplitude-min.js +1 -1
- package/lib/scripts/amplitude-min.js.gz +0 -0
- package/lib/scripts/amplitude-min.umd.js +1 -1
- package/lib/scripts/amplitude-min.umd.js.gz +0 -0
- package/lib/scripts/constants.d.ts +10 -0
- package/lib/scripts/constants.d.ts.map +1 -1
- package/lib/scripts/helpers.d.ts +2 -0
- package/lib/scripts/helpers.d.ts.map +1 -0
- package/lib/scripts/messages.d.ts +1 -1
- package/lib/scripts/messages.d.ts.map +1 -1
- package/lib/scripts/session-replay.d.ts.map +1 -1
- package/lib/scripts/typings/session-replay.d.ts +16 -11
- package/lib/scripts/typings/session-replay.d.ts.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -25,6 +25,8 @@ yarn add @amplitude/plugin-session-replay-browser
|
|
|
25
25
|
|
|
26
26
|
This plugin works on top of Amplitude Browser SDK and adds session replay features to built-in features. To use this plugin, you need to install `@amplitude/analytics-browser` version `v1.0.0` or later.
|
|
27
27
|
|
|
28
|
+
This plugin requires that default tracking for sessions is enabled. If default tracking for sessions is not enabled in the config, the plugin will automatically enable it.
|
|
29
|
+
|
|
28
30
|
### 1. Import Amplitude packages
|
|
29
31
|
|
|
30
32
|
* `@amplitude/analytics-browser`
|
|
@@ -35,12 +37,38 @@ import * as amplitude from '@amplitude/analytics-browser';
|
|
|
35
37
|
import { sessionReplayPlugin } from '@amplitude/plugin-session-replay-browser';
|
|
36
38
|
```
|
|
37
39
|
|
|
38
|
-
### 2. Instantiate
|
|
40
|
+
### 2. Instantiate Session Replay plugin
|
|
39
41
|
|
|
40
|
-
The plugin must be registered with the amplitude instance via the following code
|
|
42
|
+
The plugin must be registered with the amplitude instance via the following code. The plugin accepts an optional parameter which is an `Object` to configure the plugin based on your use case.
|
|
41
43
|
|
|
42
44
|
```typescript
|
|
43
45
|
amplitude.init(API_KEY);
|
|
44
|
-
const sessionReplayTracking = sessionReplayPlugin(
|
|
46
|
+
const sessionReplayTracking = sessionReplayPlugin({
|
|
47
|
+
sampleRate: undefined
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
#### Options
|
|
53
|
+
|
|
54
|
+
|Name|Type|Default|Description|
|
|
55
|
+
|-|-|-|-|
|
|
56
|
+
|`sampleRate`|`number`|`undefined`|Use this option to control how many sessions will be selected for recording. A selected session will be recorded, while sessions that are not selected will not be recorded. <br></br>The number should be a decimal between 0 and 1, ie `0.4`, representing the fraction of sessions you would like to have randomly selected for recording. Over a large number of sessions, `0.4` would select `40%` of those sessions.|
|
|
57
|
+
|
|
58
|
+
### 3. Install plugin to Amplitude SDK
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
45
61
|
amplitude.add(sessionReplayTracking);
|
|
46
|
-
```
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Privacy
|
|
65
|
+
By default, the session recording will mask all inputs, meaning the text in inputs will appear in a session replay as asterisks: `***`. You may require more specific masking controls based on your use case, so we offer the following controls:
|
|
66
|
+
|
|
67
|
+
#### 1. Unmask inputs
|
|
68
|
+
In your application code, add the class `.amp-unmask` to any __input__ whose text you'd like to have unmasked in the recording. In the replay of a recorded session, it will be possible to read the exact text entered into an input with this class, the text will not be converted to asterisks.
|
|
69
|
+
|
|
70
|
+
#### 2. Mask non-input elements
|
|
71
|
+
In your application code, add the class `.amp-mask` to any __non-input element__ whose text you'd like to have masked from the recording. The text in the element, as well as it's children, will all be converted to asterisks.
|
|
72
|
+
|
|
73
|
+
#### 3. Block non-text elements
|
|
74
|
+
In your application code, add the class `.amp-block` to any element you would like to have blocked from the recording. The element will appear in the replay as a placeholder with the same dimensions.
|
package/lib/cjs/constants.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
+
import { IDBStoreSession } from './typings/session-replay';
|
|
1
2
|
export declare const DEFAULT_EVENT_PROPERTY_PREFIX = "[Amplitude]";
|
|
2
3
|
export declare const DEFAULT_SESSION_REPLAY_PROPERTY: string;
|
|
3
4
|
export declare const DEFAULT_SESSION_START_EVENT = "session_start";
|
|
4
5
|
export declare const DEFAULT_SESSION_END_EVENT = "session_end";
|
|
6
|
+
export declare const BLOCK_CLASS = "amp-block";
|
|
7
|
+
export declare const MASK_TEXT_CLASS = "amp-mask";
|
|
8
|
+
export declare const UNMASK_TEXT_CLASS = "amp-unmask";
|
|
9
|
+
export declare const SESSION_REPLAY_SERVER_URL = "https://api-secure.amplitude.com/sessions/track";
|
|
10
|
+
export declare const STORAGE_PREFIX: string;
|
|
11
|
+
export declare const MAX_EVENT_LIST_SIZE_IN_BYTES: number;
|
|
12
|
+
export declare const MIN_INTERVAL = 500;
|
|
13
|
+
export declare const MAX_INTERVAL: number;
|
|
14
|
+
export declare const defaultSessionStore: IDBStoreSession;
|
|
5
15
|
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE3D,eAAO,MAAM,6BAA6B,gBAAgB,CAAC;AAE3D,eAAO,MAAM,+BAA+B,QAAsD,CAAC;AACnG,eAAO,MAAM,2BAA2B,kBAAkB,CAAC;AAC3D,eAAO,MAAM,yBAAyB,gBAAgB,CAAC;AAEvD,eAAO,MAAM,WAAW,cAAc,CAAC;AACvC,eAAO,MAAM,eAAe,aAAa,CAAC;AAC1C,eAAO,MAAM,iBAAiB,eAAe,CAAC;AAC9C,eAAO,MAAM,yBAAyB,oDAAoD,CAAC;AAC3F,eAAO,MAAM,cAAc,QAAsC,CAAC;AAElE,eAAO,MAAM,4BAA4B,QAAgE,CAAC;AAC1G,eAAO,MAAM,YAAY,MAAM,CAAC;AAChC,eAAO,MAAM,YAAY,QAAY,CAAC;AACtC,eAAO,MAAM,mBAAmB,EAAE,eAIjC,CAAC"}
|
package/lib/cjs/constants.js
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
|
-
exports.DEFAULT_SESSION_END_EVENT = exports.DEFAULT_SESSION_START_EVENT = exports.DEFAULT_SESSION_REPLAY_PROPERTY = exports.DEFAULT_EVENT_PROPERTY_PREFIX = void 0;
|
|
2
|
+
exports.defaultSessionStore = exports.MAX_INTERVAL = exports.MIN_INTERVAL = exports.MAX_EVENT_LIST_SIZE_IN_BYTES = exports.STORAGE_PREFIX = exports.SESSION_REPLAY_SERVER_URL = exports.UNMASK_TEXT_CLASS = exports.MASK_TEXT_CLASS = exports.BLOCK_CLASS = exports.DEFAULT_SESSION_END_EVENT = exports.DEFAULT_SESSION_START_EVENT = exports.DEFAULT_SESSION_REPLAY_PROPERTY = exports.DEFAULT_EVENT_PROPERTY_PREFIX = void 0;
|
|
3
|
+
var analytics_core_1 = require("@amplitude/analytics-core");
|
|
3
4
|
exports.DEFAULT_EVENT_PROPERTY_PREFIX = '[Amplitude]';
|
|
4
5
|
exports.DEFAULT_SESSION_REPLAY_PROPERTY = "".concat(exports.DEFAULT_EVENT_PROPERTY_PREFIX, " Session Recorded");
|
|
5
6
|
exports.DEFAULT_SESSION_START_EVENT = 'session_start';
|
|
6
7
|
exports.DEFAULT_SESSION_END_EVENT = 'session_end';
|
|
8
|
+
exports.BLOCK_CLASS = 'amp-block';
|
|
9
|
+
exports.MASK_TEXT_CLASS = 'amp-mask';
|
|
10
|
+
exports.UNMASK_TEXT_CLASS = 'amp-unmask';
|
|
11
|
+
exports.SESSION_REPLAY_SERVER_URL = 'https://api-secure.amplitude.com/sessions/track';
|
|
12
|
+
exports.STORAGE_PREFIX = "".concat(analytics_core_1.AMPLITUDE_PREFIX, "_replay_unsent");
|
|
13
|
+
var PAYLOAD_ESTIMATED_SIZE_IN_BYTES_WITHOUT_EVENTS = 500; // derived by JSON stringifying an example payload without events
|
|
14
|
+
exports.MAX_EVENT_LIST_SIZE_IN_BYTES = 10 * 1000000 - PAYLOAD_ESTIMATED_SIZE_IN_BYTES_WITHOUT_EVENTS;
|
|
15
|
+
exports.MIN_INTERVAL = 500; // 500 ms
|
|
16
|
+
exports.MAX_INTERVAL = 10 * 1000; // 10 seconds
|
|
17
|
+
exports.defaultSessionStore = {
|
|
18
|
+
shouldRecord: true,
|
|
19
|
+
currentSequenceId: 0,
|
|
20
|
+
sessionSequences: {},
|
|
21
|
+
};
|
|
7
22
|
//# sourceMappingURL=constants.js.map
|
package/lib/cjs/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":";;AAAA,4DAA6D;AAGhD,QAAA,6BAA6B,GAAG,aAAa,CAAC;AAE9C,QAAA,+BAA+B,GAAG,UAAG,qCAA6B,sBAAmB,CAAC;AACtF,QAAA,2BAA2B,GAAG,eAAe,CAAC;AAC9C,QAAA,yBAAyB,GAAG,aAAa,CAAC;AAE1C,QAAA,WAAW,GAAG,WAAW,CAAC;AAC1B,QAAA,eAAe,GAAG,UAAU,CAAC;AAC7B,QAAA,iBAAiB,GAAG,YAAY,CAAC;AACjC,QAAA,yBAAyB,GAAG,iDAAiD,CAAC;AAC9E,QAAA,cAAc,GAAG,UAAG,iCAAgB,mBAAgB,CAAC;AAClE,IAAM,8CAA8C,GAAG,GAAG,CAAC,CAAC,iEAAiE;AAChH,QAAA,4BAA4B,GAAG,EAAE,GAAG,OAAO,GAAG,8CAA8C,CAAC;AAC7F,QAAA,YAAY,GAAG,GAAG,CAAC,CAAC,SAAS;AAC7B,QAAA,YAAY,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,aAAa;AACvC,QAAA,mBAAmB,GAAoB;IAClD,YAAY,EAAE,IAAI;IAClB,iBAAiB,EAAE,CAAC;IACpB,gBAAgB,EAAE,EAAE;CACrB,CAAC","sourcesContent":["import { AMPLITUDE_PREFIX } from '@amplitude/analytics-core';\nimport { IDBStoreSession } from './typings/session-replay';\n\nexport const DEFAULT_EVENT_PROPERTY_PREFIX = '[Amplitude]';\n\nexport const DEFAULT_SESSION_REPLAY_PROPERTY = `${DEFAULT_EVENT_PROPERTY_PREFIX} Session Recorded`;\nexport const DEFAULT_SESSION_START_EVENT = 'session_start';\nexport const DEFAULT_SESSION_END_EVENT = 'session_end';\n\nexport const BLOCK_CLASS = 'amp-block';\nexport const MASK_TEXT_CLASS = 'amp-mask';\nexport const UNMASK_TEXT_CLASS = 'amp-unmask';\nexport const SESSION_REPLAY_SERVER_URL = 'https://api-secure.amplitude.com/sessions/track';\nexport const STORAGE_PREFIX = `${AMPLITUDE_PREFIX}_replay_unsent`;\nconst PAYLOAD_ESTIMATED_SIZE_IN_BYTES_WITHOUT_EVENTS = 500; // derived by JSON stringifying an example payload without events\nexport const MAX_EVENT_LIST_SIZE_IN_BYTES = 10 * 1000000 - PAYLOAD_ESTIMATED_SIZE_IN_BYTES_WITHOUT_EVENTS;\nexport const MIN_INTERVAL = 500; // 500 ms\nexport const MAX_INTERVAL = 10 * 1000; // 10 seconds\nexport const defaultSessionStore: IDBStoreSession = {\n shouldRecord: true,\n currentSequenceId: 0,\n sessionSequences: {},\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,SAAU,MAAM,WAAW,WAAW,WAK7D,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
|
+
exports.maskInputFn = void 0;
|
|
3
|
+
var constants_1 = require("./constants");
|
|
4
|
+
var maskInputFn = function (text, element) {
|
|
5
|
+
var _a;
|
|
6
|
+
if ((_a = element.classList) === null || _a === void 0 ? void 0 : _a.contains(constants_1.UNMASK_TEXT_CLASS)) {
|
|
7
|
+
return text;
|
|
8
|
+
}
|
|
9
|
+
return '*'.repeat(text.length);
|
|
10
|
+
};
|
|
11
|
+
exports.maskInputFn = maskInputFn;
|
|
12
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":";;AAAA,yCAAgD;AAEzC,IAAM,WAAW,GAAG,UAAC,IAAY,EAAE,OAAoB;;IAC5D,IAAI,MAAA,OAAO,CAAC,SAAS,0CAAE,QAAQ,CAAC,6BAAiB,CAAC,EAAE;QAClD,OAAO,IAAI,CAAC;KACb;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACjC,CAAC,CAAC;AALW,QAAA,WAAW,eAKtB","sourcesContent":["import { UNMASK_TEXT_CLASS } from './constants';\n\nexport const maskInputFn = (text: string, element: HTMLElement) => {\n if (element.classList?.contains(UNMASK_TEXT_CLASS)) {\n return text;\n }\n return '*'.repeat(text.length);\n};\n"]}
|
package/lib/cjs/messages.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const
|
|
1
|
+
export declare const getSuccessMessage: (sessionId: number) => string;
|
|
2
2
|
export declare const UNEXPECTED_ERROR_MESSAGE = "Unexpected error occurred";
|
|
3
3
|
export declare const MAX_RETRIES_EXCEEDED_MESSAGE = "Session replay event batch rejected due to exceeded retry count";
|
|
4
4
|
export declare const STORAGE_FAILURE = "Failed to store session replay events in IndexedDB";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/messages.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/messages.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,cAAe,MAAM,WAC4B,CAAC;AAChF,eAAO,MAAM,wBAAwB,8BAA8B,CAAC;AACpE,eAAO,MAAM,4BAA4B,oEAAoE,CAAC;AAC9G,eAAO,MAAM,eAAe,uDAAuD,CAAC"}
|
package/lib/cjs/messages.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
|
-
exports.STORAGE_FAILURE = exports.MAX_RETRIES_EXCEEDED_MESSAGE = exports.UNEXPECTED_ERROR_MESSAGE = exports.
|
|
3
|
-
|
|
2
|
+
exports.STORAGE_FAILURE = exports.MAX_RETRIES_EXCEEDED_MESSAGE = exports.UNEXPECTED_ERROR_MESSAGE = exports.getSuccessMessage = void 0;
|
|
3
|
+
var getSuccessMessage = function (sessionId) {
|
|
4
|
+
return "Session replay event batch tracked successfully for session id ".concat(sessionId);
|
|
5
|
+
};
|
|
6
|
+
exports.getSuccessMessage = getSuccessMessage;
|
|
4
7
|
exports.UNEXPECTED_ERROR_MESSAGE = 'Unexpected error occurred';
|
|
5
8
|
exports.MAX_RETRIES_EXCEEDED_MESSAGE = 'Session replay event batch rejected due to exceeded retry count';
|
|
6
9
|
exports.STORAGE_FAILURE = 'Failed to store session replay events in IndexedDB';
|
package/lib/cjs/messages.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/messages.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/messages.ts"],"names":[],"mappings":";;AAAO,IAAM,iBAAiB,GAAG,UAAC,SAAiB;IACjD,OAAA,yEAAkE,SAAS,CAAE;AAA7E,CAA6E,CAAC;AADnE,QAAA,iBAAiB,qBACkD;AACnE,QAAA,wBAAwB,GAAG,2BAA2B,CAAC;AACvD,QAAA,4BAA4B,GAAG,iEAAiE,CAAC;AACjG,QAAA,eAAe,GAAG,oDAAoD,CAAC","sourcesContent":["export const getSuccessMessage = (sessionId: number) =>\n `Session replay event batch tracked successfully for session id ${sessionId}`;\nexport const UNEXPECTED_ERROR_MESSAGE = 'Unexpected error occurred';\nexport const MAX_RETRIES_EXCEEDED_MESSAGE = 'Session replay event batch rejected due to exceeded retry count';\nexport const STORAGE_FAILURE = 'Failed to store session replay events in IndexedDB';\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"AAoBA,OAAO,EAQL,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AA+alC,eAAO,MAAM,mBAAmB,EAAE,mBAEjC,CAAC"}
|
|
@@ -7,16 +7,11 @@ var analytics_types_1 = require("@amplitude/analytics-types");
|
|
|
7
7
|
var IDBKeyVal = tslib_1.__importStar(require("idb-keyval"));
|
|
8
8
|
var rrweb_1 = require("rrweb");
|
|
9
9
|
var constants_1 = require("./constants");
|
|
10
|
+
var helpers_1 = require("./helpers");
|
|
10
11
|
var messages_1 = require("./messages");
|
|
11
12
|
var session_replay_1 = require("./typings/session-replay");
|
|
12
|
-
var SESSION_REPLAY_SERVER_URL = 'https://api-secure.amplitude.com/sessions/track';
|
|
13
|
-
var STORAGE_PREFIX = "".concat(analytics_core_1.AMPLITUDE_PREFIX, "_replay_unsent");
|
|
14
|
-
var PAYLOAD_ESTIMATED_SIZE_IN_BYTES_WITHOUT_EVENTS = 500; // derived by JSON stringifying an example payload without events
|
|
15
|
-
var MAX_EVENT_LIST_SIZE_IN_BYTES = 10 * 1000000 - PAYLOAD_ESTIMATED_SIZE_IN_BYTES_WITHOUT_EVENTS;
|
|
16
|
-
var MIN_INTERVAL = 500; // 500 ms
|
|
17
|
-
var MAX_INTERVAL = 10 * 1000; // 10 seconds
|
|
18
13
|
var SessionReplay = /** @class */ (function () {
|
|
19
|
-
function SessionReplay() {
|
|
14
|
+
function SessionReplay(options) {
|
|
20
15
|
var _this = this;
|
|
21
16
|
this.name = '@amplitude/plugin-session-replay-browser';
|
|
22
17
|
this.type = 'enrichment';
|
|
@@ -27,9 +22,10 @@ var SessionReplay = /** @class */ (function () {
|
|
|
27
22
|
this.scheduled = null;
|
|
28
23
|
this.queue = [];
|
|
29
24
|
this.stopRecordingEvents = null;
|
|
30
|
-
this.maxPersistedEventsSize = MAX_EVENT_LIST_SIZE_IN_BYTES;
|
|
31
|
-
this.interval = MIN_INTERVAL;
|
|
25
|
+
this.maxPersistedEventsSize = constants_1.MAX_EVENT_LIST_SIZE_IN_BYTES;
|
|
26
|
+
this.interval = constants_1.MIN_INTERVAL;
|
|
32
27
|
this.timeAtLastSend = null;
|
|
28
|
+
this.shouldRecord = true;
|
|
33
29
|
/**
|
|
34
30
|
* Determines whether to send the events list to the backend and start a new
|
|
35
31
|
* empty events list, based on the size of the list as well as the last time sent
|
|
@@ -43,12 +39,13 @@ var SessionReplay = /** @class */ (function () {
|
|
|
43
39
|
return true;
|
|
44
40
|
}
|
|
45
41
|
if (_this.timeAtLastSend !== null && Date.now() - _this.timeAtLastSend > _this.interval && _this.events.length) {
|
|
46
|
-
_this.interval = Math.min(MAX_INTERVAL, _this.interval + MIN_INTERVAL);
|
|
42
|
+
_this.interval = Math.min(constants_1.MAX_INTERVAL, _this.interval + constants_1.MIN_INTERVAL);
|
|
47
43
|
_this.timeAtLastSend = Date.now();
|
|
48
44
|
return true;
|
|
49
45
|
}
|
|
50
46
|
return false;
|
|
51
47
|
};
|
|
48
|
+
this.options = tslib_1.__assign({}, options);
|
|
52
49
|
}
|
|
53
50
|
SessionReplay.prototype.setup = function (config) {
|
|
54
51
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
@@ -59,7 +56,21 @@ var SessionReplay = /** @class */ (function () {
|
|
|
59
56
|
case 0:
|
|
60
57
|
config.loggerProvider.log('Installing @amplitude/plugin-session-replay.');
|
|
61
58
|
this.config = config;
|
|
62
|
-
this.
|
|
59
|
+
this.config.sessionId = config.sessionId;
|
|
60
|
+
this.storageKey = "".concat(constants_1.STORAGE_PREFIX, "_").concat(this.config.apiKey.substring(0, 10));
|
|
61
|
+
if (typeof config.defaultTracking === 'boolean') {
|
|
62
|
+
if (config.defaultTracking === false) {
|
|
63
|
+
config.defaultTracking = {
|
|
64
|
+
pageViews: false,
|
|
65
|
+
formInteractions: false,
|
|
66
|
+
fileDownloads: false,
|
|
67
|
+
sessions: true,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
config.defaultTracking = tslib_1.__assign(tslib_1.__assign({}, config.defaultTracking), { sessions: true });
|
|
73
|
+
}
|
|
63
74
|
return [4 /*yield*/, this.initialize(true)];
|
|
64
75
|
case 1:
|
|
65
76
|
_a.sent();
|
|
@@ -82,12 +93,15 @@ var SessionReplay = /** @class */ (function () {
|
|
|
82
93
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
83
94
|
var _a;
|
|
84
95
|
return tslib_1.__generator(this, function (_b) {
|
|
85
|
-
|
|
96
|
+
if (this.shouldRecord) {
|
|
97
|
+
event.event_properties = tslib_1.__assign(tslib_1.__assign({}, event.event_properties), (_a = {}, _a[constants_1.DEFAULT_SESSION_REPLAY_PROPERTY] = true, _a));
|
|
98
|
+
}
|
|
86
99
|
if (event.event_type === constants_1.DEFAULT_SESSION_START_EVENT && !this.stopRecordingEvents) {
|
|
100
|
+
this.setShouldRecord();
|
|
87
101
|
this.recordEvents();
|
|
88
102
|
}
|
|
89
103
|
else if (event.event_type === constants_1.DEFAULT_SESSION_END_EVENT) {
|
|
90
|
-
if (event.session_id) {
|
|
104
|
+
if (event.session_id && this.events.length) {
|
|
91
105
|
this.sendEventsList({
|
|
92
106
|
events: this.events,
|
|
93
107
|
sequenceId: this.currentSequenceId,
|
|
@@ -121,16 +135,17 @@ var SessionReplay = /** @class */ (function () {
|
|
|
121
135
|
if (storedReplaySessions && storedSequencesForSession && storedSequencesForSession.sessionSequences) {
|
|
122
136
|
storedSeqId = storedSequencesForSession.currentSequenceId;
|
|
123
137
|
lastSequence = storedSequencesForSession.sessionSequences[storedSeqId];
|
|
124
|
-
if (lastSequence.status !== session_replay_1.RecordingStatus.RECORDING) {
|
|
138
|
+
if (lastSequence && lastSequence.status !== session_replay_1.RecordingStatus.RECORDING) {
|
|
125
139
|
this.currentSequenceId = storedSeqId + 1;
|
|
126
140
|
this.events = [];
|
|
127
141
|
}
|
|
128
142
|
else {
|
|
129
143
|
// Pick up recording where it was left off in another tab or window
|
|
130
144
|
this.currentSequenceId = storedSeqId;
|
|
131
|
-
this.events = lastSequence.events;
|
|
145
|
+
this.events = (lastSequence === null || lastSequence === void 0 ? void 0 : lastSequence.events) || [];
|
|
132
146
|
}
|
|
133
147
|
}
|
|
148
|
+
this.setShouldRecord(storedSequencesForSession);
|
|
134
149
|
if (shouldSendStoredEvents && storedReplaySessions) {
|
|
135
150
|
this.sendStoredEvents(storedReplaySessions);
|
|
136
151
|
}
|
|
@@ -142,6 +157,21 @@ var SessionReplay = /** @class */ (function () {
|
|
|
142
157
|
});
|
|
143
158
|
});
|
|
144
159
|
};
|
|
160
|
+
SessionReplay.prototype.setShouldRecord = function (sessionStore) {
|
|
161
|
+
if ((sessionStore === null || sessionStore === void 0 ? void 0 : sessionStore.shouldRecord) === false) {
|
|
162
|
+
this.shouldRecord = false;
|
|
163
|
+
}
|
|
164
|
+
else if (this.config.optOut) {
|
|
165
|
+
this.shouldRecord = false;
|
|
166
|
+
}
|
|
167
|
+
else if (this.options && this.options.sampleRate) {
|
|
168
|
+
this.shouldRecord = Math.random() < this.options.sampleRate;
|
|
169
|
+
}
|
|
170
|
+
this.config.sessionId && void this.storeShouldRecordForSession(this.config.sessionId, this.shouldRecord);
|
|
171
|
+
if (!this.shouldRecord && this.config.sessionId) {
|
|
172
|
+
this.config.loggerProvider.log("Opting session ".concat(this.config.sessionId, " out of recording."));
|
|
173
|
+
}
|
|
174
|
+
};
|
|
145
175
|
SessionReplay.prototype.sendStoredEvents = function (storedReplaySessions) {
|
|
146
176
|
for (var sessionId in storedReplaySessions) {
|
|
147
177
|
var storedSequences = storedReplaySessions[sessionId].sessionSequences;
|
|
@@ -164,6 +194,9 @@ var SessionReplay = /** @class */ (function () {
|
|
|
164
194
|
};
|
|
165
195
|
SessionReplay.prototype.recordEvents = function () {
|
|
166
196
|
var _this = this;
|
|
197
|
+
if (!this.shouldRecord) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
167
200
|
this.stopRecordingEvents = (0, rrweb_1.record)({
|
|
168
201
|
emit: function (event) {
|
|
169
202
|
var GlobalScope = (0, analytics_client_common_1.getGlobalScope)();
|
|
@@ -187,6 +220,9 @@ var SessionReplay = /** @class */ (function () {
|
|
|
187
220
|
},
|
|
188
221
|
packFn: rrweb_1.pack,
|
|
189
222
|
maskAllInputs: true,
|
|
223
|
+
maskTextClass: constants_1.MASK_TEXT_CLASS,
|
|
224
|
+
blockClass: constants_1.BLOCK_CLASS,
|
|
225
|
+
maskInputFn: helpers_1.maskInputFn,
|
|
190
226
|
});
|
|
191
227
|
};
|
|
192
228
|
SessionReplay.prototype.sendEventsList = function (_a) {
|
|
@@ -293,7 +329,7 @@ var SessionReplay = /** @class */ (function () {
|
|
|
293
329
|
body: JSON.stringify(payload),
|
|
294
330
|
method: 'POST',
|
|
295
331
|
};
|
|
296
|
-
return [4 /*yield*/, fetch(SESSION_REPLAY_SERVER_URL, options)];
|
|
332
|
+
return [4 /*yield*/, fetch(constants_1.SESSION_REPLAY_SERVER_URL, options)];
|
|
297
333
|
case 2:
|
|
298
334
|
res = _a.sent();
|
|
299
335
|
if (res === null) {
|
|
@@ -334,7 +370,7 @@ var SessionReplay = /** @class */ (function () {
|
|
|
334
370
|
}
|
|
335
371
|
};
|
|
336
372
|
SessionReplay.prototype.handleSuccessResponse = function (context) {
|
|
337
|
-
this.completeRequest({ context: context, success: messages_1.
|
|
373
|
+
this.completeRequest({ context: context, success: (0, messages_1.getSuccessMessage)(context.sessionId) });
|
|
338
374
|
};
|
|
339
375
|
SessionReplay.prototype.handleOtherResponse = function (context) {
|
|
340
376
|
this.addToQueue(tslib_1.__assign(tslib_1.__assign({}, context), { timeout: context.attempts * this.retryTimeout }));
|
|
@@ -369,10 +405,7 @@ var SessionReplay = /** @class */ (function () {
|
|
|
369
405
|
return [4 /*yield*/, IDBKeyVal.update(this.storageKey, function (sessionMap) {
|
|
370
406
|
var _a, _b;
|
|
371
407
|
if (sessionMap === void 0) { sessionMap = {}; }
|
|
372
|
-
var session = sessionMap[sessionId] || {
|
|
373
|
-
currentSequenceId: 0,
|
|
374
|
-
sessionSequences: [],
|
|
375
|
-
};
|
|
408
|
+
var session = sessionMap[sessionId] || tslib_1.__assign({}, constants_1.defaultSessionStore);
|
|
376
409
|
session.currentSequenceId = sequenceId;
|
|
377
410
|
var currentSequence = (session.sessionSequences && session.sessionSequences[sequenceId]) || {};
|
|
378
411
|
currentSequence.events = events;
|
|
@@ -391,9 +424,35 @@ var SessionReplay = /** @class */ (function () {
|
|
|
391
424
|
});
|
|
392
425
|
});
|
|
393
426
|
};
|
|
394
|
-
SessionReplay.prototype.
|
|
427
|
+
SessionReplay.prototype.storeShouldRecordForSession = function (sessionId, shouldRecord) {
|
|
395
428
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
396
429
|
var e_4;
|
|
430
|
+
return tslib_1.__generator(this, function (_a) {
|
|
431
|
+
switch (_a.label) {
|
|
432
|
+
case 0:
|
|
433
|
+
_a.trys.push([0, 2, , 3]);
|
|
434
|
+
return [4 /*yield*/, IDBKeyVal.update(this.storageKey, function (sessionMap) {
|
|
435
|
+
var _a;
|
|
436
|
+
if (sessionMap === void 0) { sessionMap = {}; }
|
|
437
|
+
var session = sessionMap[sessionId] || tslib_1.__assign({}, constants_1.defaultSessionStore);
|
|
438
|
+
session.shouldRecord = shouldRecord;
|
|
439
|
+
return tslib_1.__assign(tslib_1.__assign({}, sessionMap), (_a = {}, _a[sessionId] = session, _a));
|
|
440
|
+
})];
|
|
441
|
+
case 1:
|
|
442
|
+
_a.sent();
|
|
443
|
+
return [3 /*break*/, 3];
|
|
444
|
+
case 2:
|
|
445
|
+
e_4 = _a.sent();
|
|
446
|
+
this.config.loggerProvider.error("".concat(messages_1.STORAGE_FAILURE, ": ").concat(e_4));
|
|
447
|
+
return [3 /*break*/, 3];
|
|
448
|
+
case 3: return [2 /*return*/];
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
};
|
|
453
|
+
SessionReplay.prototype.cleanUpSessionEventsStore = function (sessionId, sequenceId) {
|
|
454
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
455
|
+
var e_5;
|
|
397
456
|
return tslib_1.__generator(this, function (_a) {
|
|
398
457
|
switch (_a.label) {
|
|
399
458
|
case 0:
|
|
@@ -420,8 +479,8 @@ var SessionReplay = /** @class */ (function () {
|
|
|
420
479
|
_a.sent();
|
|
421
480
|
return [3 /*break*/, 3];
|
|
422
481
|
case 2:
|
|
423
|
-
|
|
424
|
-
this.config.loggerProvider.error("".concat(messages_1.STORAGE_FAILURE, ": ").concat(
|
|
482
|
+
e_5 = _a.sent();
|
|
483
|
+
this.config.loggerProvider.error("".concat(messages_1.STORAGE_FAILURE, ": ").concat(e_5));
|
|
425
484
|
return [3 /*break*/, 3];
|
|
426
485
|
case 3: return [2 /*return*/];
|
|
427
486
|
}
|
|
@@ -440,8 +499,8 @@ var SessionReplay = /** @class */ (function () {
|
|
|
440
499
|
};
|
|
441
500
|
return SessionReplay;
|
|
442
501
|
}());
|
|
443
|
-
var sessionReplayPlugin = function () {
|
|
444
|
-
return new SessionReplay();
|
|
502
|
+
var sessionReplayPlugin = function (options) {
|
|
503
|
+
return new SessionReplay(options);
|
|
445
504
|
};
|
|
446
505
|
exports.sessionReplayPlugin = sessionReplayPlugin;
|
|
447
506
|
//# sourceMappingURL=session-replay.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-replay.js","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"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","sourcesContent":["import { getGlobalScope } from '@amplitude/analytics-client-common';\nimport { AMPLITUDE_PREFIX, BaseTransport } from '@amplitude/analytics-core';\nimport { BrowserConfig, Event, Status } from '@amplitude/analytics-types';\nimport * as IDBKeyVal from 'idb-keyval';\nimport { pack, record } from 'rrweb';\nimport { DEFAULT_SESSION_END_EVENT, DEFAULT_SESSION_REPLAY_PROPERTY, DEFAULT_SESSION_START_EVENT } from './constants';\nimport { MAX_RETRIES_EXCEEDED_MESSAGE, STORAGE_FAILURE, SUCCESS_MESSAGE, UNEXPECTED_ERROR_MESSAGE } from './messages';\nimport {\n Events,\n IDBStore,\n RecordingStatus,\n SessionReplayContext,\n SessionReplayEnrichmentPlugin,\n SessionReplayPlugin,\n} from './typings/session-replay';\n\nconst SESSION_REPLAY_SERVER_URL = 'https://api-secure.amplitude.com/sessions/track';\nconst STORAGE_PREFIX = `${AMPLITUDE_PREFIX}_replay_unsent`;\nconst PAYLOAD_ESTIMATED_SIZE_IN_BYTES_WITHOUT_EVENTS = 500; // derived by JSON stringifying an example payload without events\nconst MAX_EVENT_LIST_SIZE_IN_BYTES = 10 * 1000000 - PAYLOAD_ESTIMATED_SIZE_IN_BYTES_WITHOUT_EVENTS;\nconst MIN_INTERVAL = 500; // 500 ms\nconst MAX_INTERVAL = 10 * 1000; // 10 seconds\n\nclass SessionReplay implements SessionReplayEnrichmentPlugin {\n name = '@amplitude/plugin-session-replay-browser';\n type = 'enrichment' as const;\n // this.config is defined in setup() which will always be called first\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n config: BrowserConfig;\n storageKey = '';\n retryTimeout = 1000;\n events: Events = [];\n currentSequenceId = 0;\n private scheduled: ReturnType<typeof setTimeout> | null = null;\n queue: SessionReplayContext[] = [];\n stopRecordingEvents: ReturnType<typeof record> | null = null;\n maxPersistedEventsSize = MAX_EVENT_LIST_SIZE_IN_BYTES;\n interval = MIN_INTERVAL;\n timeAtLastSend: number | null = null;\n\n async setup(config: BrowserConfig) {\n config.loggerProvider.log('Installing @amplitude/plugin-session-replay.');\n\n this.config = config;\n this.storageKey = `${STORAGE_PREFIX}_${this.config.apiKey.substring(0, 10)}`;\n await this.initialize(true);\n\n const GlobalScope = getGlobalScope();\n if (GlobalScope && GlobalScope.window) {\n GlobalScope.window.addEventListener('blur', () => {\n this.stopRecordingEvents && this.stopRecordingEvents();\n this.stopRecordingEvents = null;\n });\n GlobalScope.window.addEventListener('focus', () => {\n void this.initialize();\n });\n }\n }\n\n async execute(event: Event) {\n event.event_properties = {\n ...event.event_properties,\n [DEFAULT_SESSION_REPLAY_PROPERTY]: true,\n };\n if (event.event_type === DEFAULT_SESSION_START_EVENT && !this.stopRecordingEvents) {\n this.recordEvents();\n } else if (event.event_type === DEFAULT_SESSION_END_EVENT) {\n if (event.session_id) {\n this.sendEventsList({\n events: this.events,\n sequenceId: this.currentSequenceId,\n sessionId: event.session_id,\n });\n }\n this.stopRecordingEvents && this.stopRecordingEvents();\n this.stopRecordingEvents = null;\n this.events = [];\n this.currentSequenceId = 0;\n }\n return Promise.resolve(event);\n }\n\n async initialize(shouldSendStoredEvents = false) {\n this.timeAtLastSend = Date.now(); // Initialize this so we have a point of comparison when events are recorded\n if (!this.config.sessionId) {\n return;\n }\n const storedReplaySessions = await this.getAllSessionEventsFromStore();\n const storedSequencesForSession = storedReplaySessions && storedReplaySessions[this.config.sessionId];\n if (storedReplaySessions && storedSequencesForSession && storedSequencesForSession.sessionSequences) {\n const storedSeqId = storedSequencesForSession.currentSequenceId;\n const lastSequence = storedSequencesForSession.sessionSequences[storedSeqId];\n if (lastSequence.status !== RecordingStatus.RECORDING) {\n this.currentSequenceId = storedSeqId + 1;\n this.events = [];\n } else {\n // Pick up recording where it was left off in another tab or window\n this.currentSequenceId = storedSeqId;\n this.events = lastSequence.events;\n }\n }\n if (shouldSendStoredEvents && storedReplaySessions) {\n this.sendStoredEvents(storedReplaySessions);\n }\n if (!this.stopRecordingEvents) {\n this.recordEvents();\n }\n }\n\n sendStoredEvents(storedReplaySessions: IDBStore) {\n for (const sessionId in storedReplaySessions) {\n const storedSequences = storedReplaySessions[sessionId].sessionSequences;\n for (const storedSeqId in storedSequences) {\n const seq = storedSequences[storedSeqId];\n const numericSeqId = parseInt(storedSeqId, 10);\n const numericSessionId = parseInt(sessionId, 10);\n if (numericSessionId === this.config.sessionId && numericSeqId === this.currentSequenceId) {\n continue;\n }\n if (seq.events.length && seq.status === RecordingStatus.RECORDING) {\n this.sendEventsList({\n events: seq.events,\n sequenceId: numericSeqId,\n sessionId: numericSessionId,\n });\n }\n }\n }\n }\n\n recordEvents() {\n this.stopRecordingEvents = record({\n emit: (event) => {\n const GlobalScope = getGlobalScope();\n if (GlobalScope && GlobalScope.document && !GlobalScope.document.hasFocus()) {\n this.stopRecordingEvents && this.stopRecordingEvents();\n return;\n }\n const eventString = JSON.stringify(event);\n\n const shouldSplit = this.shouldSplitEventsList(eventString);\n if (shouldSplit) {\n this.sendEventsList({\n events: this.events,\n sequenceId: this.currentSequenceId,\n sessionId: this.config.sessionId as number,\n });\n this.events = [];\n this.currentSequenceId++;\n }\n this.events.push(eventString);\n void this.storeEventsForSession(this.events, this.currentSequenceId, this.config.sessionId as number);\n },\n packFn: pack,\n maskAllInputs: true,\n });\n }\n\n /**\n * Determines whether to send the events list to the backend and start a new\n * empty events list, based on the size of the list as well as the last time sent\n * @param nextEventString\n * @returns boolean\n */\n shouldSplitEventsList = (nextEventString: string): boolean => {\n const sizeOfNextEvent = new Blob([nextEventString]).size;\n const sizeOfEventsList = new Blob(this.events).size;\n if (sizeOfEventsList + sizeOfNextEvent >= this.maxPersistedEventsSize) {\n return true;\n }\n if (this.timeAtLastSend !== null && Date.now() - this.timeAtLastSend > this.interval && this.events.length) {\n this.interval = Math.min(MAX_INTERVAL, this.interval + MIN_INTERVAL);\n this.timeAtLastSend = Date.now();\n return true;\n }\n return false;\n };\n\n sendEventsList({ events, sequenceId, sessionId }: { events: string[]; sequenceId: number; sessionId: number }) {\n this.addToQueue({\n events,\n sequenceId,\n attempts: 0,\n timeout: 0,\n sessionId,\n });\n }\n\n addToQueue(...list: SessionReplayContext[]) {\n const tryable = list.filter((context) => {\n if (context.attempts < this.config.flushMaxRetries) {\n context.attempts += 1;\n return true;\n }\n this.completeRequest({\n context,\n err: `${MAX_RETRIES_EXCEEDED_MESSAGE}, batch sequence id, ${context.sequenceId}`,\n });\n return false;\n });\n tryable.forEach((context) => {\n this.queue = this.queue.concat(context);\n if (context.timeout === 0) {\n this.schedule(0);\n return;\n }\n\n setTimeout(() => {\n context.timeout = 0;\n this.schedule(0);\n }, context.timeout);\n });\n }\n\n schedule(timeout: number) {\n if (this.scheduled) return;\n this.scheduled = setTimeout(() => {\n void this.flush(true).then(() => {\n if (this.queue.length > 0) {\n this.schedule(timeout);\n }\n });\n }, timeout);\n }\n\n async flush(useRetry = false) {\n const list: SessionReplayContext[] = [];\n const later: SessionReplayContext[] = [];\n this.queue.forEach((context) => (context.timeout === 0 ? list.push(context) : later.push(context)));\n this.queue = later;\n\n if (this.scheduled) {\n clearTimeout(this.scheduled);\n this.scheduled = null;\n }\n\n await Promise.all(list.map((context) => this.send(context, useRetry)));\n }\n\n async send(context: SessionReplayContext, useRetry = true) {\n const payload = {\n api_key: this.config.apiKey,\n device_id: this.config.deviceId,\n session_id: context.sessionId,\n start_timestamp: context.sessionId,\n events_batch: {\n version: 1,\n events: context.events,\n seq_number: context.sequenceId,\n },\n };\n try {\n const options: RequestInit = {\n headers: {\n 'Content-Type': 'application/json',\n Accept: '*/*',\n },\n body: JSON.stringify(payload),\n method: 'POST',\n };\n const res = await fetch(SESSION_REPLAY_SERVER_URL, options);\n if (res === null) {\n this.completeRequest({ context, err: UNEXPECTED_ERROR_MESSAGE, removeEvents: false });\n return;\n }\n if (!useRetry) {\n let responseBody = '';\n try {\n responseBody = JSON.stringify(res.body, null, 2);\n } catch {\n // to avoid crash, but don't care about the error, add comment to avoid empty block lint error\n }\n this.completeRequest({ context, success: `${res.status}: ${responseBody}` });\n } else {\n this.handleReponse(res.status, context);\n }\n } catch (e) {\n this.completeRequest({ context, err: e as string, removeEvents: false });\n }\n }\n\n handleReponse(status: number, context: SessionReplayContext) {\n const parsedStatus = new BaseTransport().buildStatus(status);\n switch (parsedStatus) {\n case Status.Success:\n this.handleSuccessResponse(context);\n break;\n default:\n this.handleOtherResponse(context);\n }\n }\n\n handleSuccessResponse(context: SessionReplayContext) {\n this.completeRequest({ context, success: SUCCESS_MESSAGE });\n }\n\n handleOtherResponse(context: SessionReplayContext) {\n this.addToQueue({\n ...context,\n timeout: context.attempts * this.retryTimeout,\n });\n }\n\n async getAllSessionEventsFromStore() {\n try {\n const storedReplaySessionContexts: IDBStore | undefined = await IDBKeyVal.get(this.storageKey);\n\n return storedReplaySessionContexts;\n } catch (e) {\n this.config.loggerProvider.error(`${STORAGE_FAILURE}: ${e as string}`);\n }\n return undefined;\n }\n\n async storeEventsForSession(events: Events, sequenceId: number, sessionId: number) {\n try {\n await IDBKeyVal.update(this.storageKey, (sessionMap: IDBStore = {}): IDBStore => {\n const session = sessionMap[sessionId] || {\n currentSequenceId: 0,\n sessionSequences: [],\n };\n session.currentSequenceId = sequenceId;\n\n const currentSequence = (session.sessionSequences && session.sessionSequences[sequenceId]) || {};\n\n currentSequence.events = events;\n currentSequence.status = RecordingStatus.RECORDING;\n\n return {\n ...sessionMap,\n [sessionId]: {\n ...session,\n sessionSequences: {\n ...session.sessionSequences,\n [sequenceId]: currentSequence,\n },\n },\n };\n });\n } catch (e) {\n this.config.loggerProvider.error(`${STORAGE_FAILURE}: ${e as string}`);\n }\n }\n\n async cleanUpSessionEventsStore(sessionId: number, sequenceId: number) {\n try {\n await IDBKeyVal.update(this.storageKey, (sessionMap: IDBStore = {}): IDBStore => {\n const session = sessionMap[sessionId];\n const sequenceToUpdate = session?.sessionSequences && session.sessionSequences[sequenceId];\n if (!sequenceToUpdate) {\n return sessionMap;\n }\n\n sequenceToUpdate.events = [];\n sequenceToUpdate.status = RecordingStatus.SENT;\n\n Object.entries(session.sessionSequences).forEach(([storedSeqId, sequence]) => {\n const numericStoredSeqId = parseInt(storedSeqId, 10);\n if (sequence.status === RecordingStatus.SENT && sequenceId !== numericStoredSeqId) {\n delete session.sessionSequences[numericStoredSeqId];\n }\n });\n\n return sessionMap;\n });\n } catch (e) {\n this.config.loggerProvider.error(`${STORAGE_FAILURE}: ${e as string}`);\n }\n }\n\n completeRequest({\n context,\n err,\n success,\n removeEvents = true,\n }: {\n context: SessionReplayContext;\n err?: string;\n success?: string;\n removeEvents?: boolean;\n }) {\n removeEvents && context.sessionId && this.cleanUpSessionEventsStore(context.sessionId, context.sequenceId);\n if (err) {\n this.config.loggerProvider.error(err);\n } else if (success) {\n this.config.loggerProvider.log(success);\n }\n }\n}\n\nexport const sessionReplayPlugin: SessionReplayPlugin = () => {\n return new SessionReplay();\n};\n"]}
|
|
1
|
+
{"version":3,"file":"session-replay.js","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"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","sourcesContent":["import { getGlobalScope } from '@amplitude/analytics-client-common';\nimport { BaseTransport } from '@amplitude/analytics-core';\nimport { BrowserConfig, Event, Status } from '@amplitude/analytics-types';\nimport * as IDBKeyVal from 'idb-keyval';\nimport { pack, record } from 'rrweb';\nimport {\n BLOCK_CLASS,\n DEFAULT_SESSION_END_EVENT,\n DEFAULT_SESSION_REPLAY_PROPERTY,\n DEFAULT_SESSION_START_EVENT,\n MASK_TEXT_CLASS,\n MAX_EVENT_LIST_SIZE_IN_BYTES,\n MAX_INTERVAL,\n MIN_INTERVAL,\n SESSION_REPLAY_SERVER_URL,\n STORAGE_PREFIX,\n defaultSessionStore,\n} from './constants';\nimport { maskInputFn } from './helpers';\nimport { MAX_RETRIES_EXCEEDED_MESSAGE, STORAGE_FAILURE, UNEXPECTED_ERROR_MESSAGE, getSuccessMessage } from './messages';\nimport {\n Events,\n IDBStore,\n IDBStoreSession,\n RecordingStatus,\n SessionReplayContext,\n SessionReplayEnrichmentPlugin,\n SessionReplayOptions,\n SessionReplayPlugin,\n} from './typings/session-replay';\nclass SessionReplay implements SessionReplayEnrichmentPlugin {\n name = '@amplitude/plugin-session-replay-browser';\n type = 'enrichment' as const;\n // this.config is defined in setup() which will always be called first\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n config: BrowserConfig;\n storageKey = '';\n retryTimeout = 1000;\n events: Events = [];\n currentSequenceId = 0;\n private scheduled: ReturnType<typeof setTimeout> | null = null;\n queue: SessionReplayContext[] = [];\n stopRecordingEvents: ReturnType<typeof record> | null = null;\n maxPersistedEventsSize = MAX_EVENT_LIST_SIZE_IN_BYTES;\n interval = MIN_INTERVAL;\n timeAtLastSend: number | null = null;\n options: SessionReplayOptions;\n shouldRecord = true;\n\n constructor(options?: SessionReplayOptions) {\n this.options = { ...options };\n }\n\n async setup(config: BrowserConfig) {\n config.loggerProvider.log('Installing @amplitude/plugin-session-replay.');\n\n this.config = config;\n this.config.sessionId = config.sessionId;\n this.storageKey = `${STORAGE_PREFIX}_${this.config.apiKey.substring(0, 10)}`;\n\n if (typeof config.defaultTracking === 'boolean') {\n if (config.defaultTracking === false) {\n config.defaultTracking = {\n pageViews: false,\n formInteractions: false,\n fileDownloads: false,\n sessions: true,\n };\n }\n } else {\n config.defaultTracking = {\n ...config.defaultTracking,\n sessions: true,\n };\n }\n\n await this.initialize(true);\n\n const GlobalScope = getGlobalScope();\n if (GlobalScope && GlobalScope.window) {\n GlobalScope.window.addEventListener('blur', () => {\n this.stopRecordingEvents && this.stopRecordingEvents();\n this.stopRecordingEvents = null;\n });\n GlobalScope.window.addEventListener('focus', () => {\n void this.initialize();\n });\n }\n }\n\n async execute(event: Event) {\n if (this.shouldRecord) {\n event.event_properties = {\n ...event.event_properties,\n [DEFAULT_SESSION_REPLAY_PROPERTY]: true,\n };\n }\n if (event.event_type === DEFAULT_SESSION_START_EVENT && !this.stopRecordingEvents) {\n this.setShouldRecord();\n this.recordEvents();\n } else if (event.event_type === DEFAULT_SESSION_END_EVENT) {\n if (event.session_id && this.events.length) {\n this.sendEventsList({\n events: this.events,\n sequenceId: this.currentSequenceId,\n sessionId: event.session_id,\n });\n }\n this.stopRecordingEvents && this.stopRecordingEvents();\n this.stopRecordingEvents = null;\n this.events = [];\n this.currentSequenceId = 0;\n }\n return Promise.resolve(event);\n }\n\n async initialize(shouldSendStoredEvents = false) {\n this.timeAtLastSend = Date.now(); // Initialize this so we have a point of comparison when events are recorded\n if (!this.config.sessionId) {\n return;\n }\n const storedReplaySessions = await this.getAllSessionEventsFromStore();\n const storedSequencesForSession = storedReplaySessions && storedReplaySessions[this.config.sessionId];\n if (storedReplaySessions && storedSequencesForSession && storedSequencesForSession.sessionSequences) {\n const storedSeqId = storedSequencesForSession.currentSequenceId;\n const lastSequence = storedSequencesForSession.sessionSequences[storedSeqId];\n if (lastSequence && lastSequence.status !== RecordingStatus.RECORDING) {\n this.currentSequenceId = storedSeqId + 1;\n this.events = [];\n } else {\n // Pick up recording where it was left off in another tab or window\n this.currentSequenceId = storedSeqId;\n this.events = lastSequence?.events || [];\n }\n }\n this.setShouldRecord(storedSequencesForSession);\n if (shouldSendStoredEvents && storedReplaySessions) {\n this.sendStoredEvents(storedReplaySessions);\n }\n if (!this.stopRecordingEvents) {\n this.recordEvents();\n }\n }\n\n setShouldRecord(sessionStore?: IDBStoreSession) {\n if (sessionStore?.shouldRecord === false) {\n this.shouldRecord = false;\n } else if (this.config.optOut) {\n this.shouldRecord = false;\n } else if (this.options && this.options.sampleRate) {\n this.shouldRecord = Math.random() < this.options.sampleRate;\n }\n\n this.config.sessionId && void this.storeShouldRecordForSession(this.config.sessionId, this.shouldRecord);\n if (!this.shouldRecord && this.config.sessionId) {\n this.config.loggerProvider.log(`Opting session ${this.config.sessionId} out of recording.`);\n }\n }\n\n sendStoredEvents(storedReplaySessions: IDBStore) {\n for (const sessionId in storedReplaySessions) {\n const storedSequences = storedReplaySessions[sessionId].sessionSequences;\n for (const storedSeqId in storedSequences) {\n const seq = storedSequences[storedSeqId];\n const numericSeqId = parseInt(storedSeqId, 10);\n const numericSessionId = parseInt(sessionId, 10);\n if (numericSessionId === this.config.sessionId && numericSeqId === this.currentSequenceId) {\n continue;\n }\n if (seq.events.length && seq.status === RecordingStatus.RECORDING) {\n this.sendEventsList({\n events: seq.events,\n sequenceId: numericSeqId,\n sessionId: numericSessionId,\n });\n }\n }\n }\n }\n\n recordEvents() {\n if (!this.shouldRecord) {\n return;\n }\n this.stopRecordingEvents = record({\n emit: (event) => {\n const GlobalScope = getGlobalScope();\n if (GlobalScope && GlobalScope.document && !GlobalScope.document.hasFocus()) {\n this.stopRecordingEvents && this.stopRecordingEvents();\n return;\n }\n const eventString = JSON.stringify(event);\n\n const shouldSplit = this.shouldSplitEventsList(eventString);\n if (shouldSplit) {\n this.sendEventsList({\n events: this.events,\n sequenceId: this.currentSequenceId,\n sessionId: this.config.sessionId as number,\n });\n this.events = [];\n this.currentSequenceId++;\n }\n this.events.push(eventString);\n void this.storeEventsForSession(this.events, this.currentSequenceId, this.config.sessionId as number);\n },\n packFn: pack,\n maskAllInputs: true,\n maskTextClass: MASK_TEXT_CLASS,\n blockClass: BLOCK_CLASS,\n maskInputFn,\n });\n }\n\n /**\n * Determines whether to send the events list to the backend and start a new\n * empty events list, based on the size of the list as well as the last time sent\n * @param nextEventString\n * @returns boolean\n */\n shouldSplitEventsList = (nextEventString: string): boolean => {\n const sizeOfNextEvent = new Blob([nextEventString]).size;\n const sizeOfEventsList = new Blob(this.events).size;\n if (sizeOfEventsList + sizeOfNextEvent >= this.maxPersistedEventsSize) {\n return true;\n }\n if (this.timeAtLastSend !== null && Date.now() - this.timeAtLastSend > this.interval && this.events.length) {\n this.interval = Math.min(MAX_INTERVAL, this.interval + MIN_INTERVAL);\n this.timeAtLastSend = Date.now();\n return true;\n }\n return false;\n };\n\n sendEventsList({ events, sequenceId, sessionId }: { events: string[]; sequenceId: number; sessionId: number }) {\n this.addToQueue({\n events,\n sequenceId,\n attempts: 0,\n timeout: 0,\n sessionId,\n });\n }\n\n addToQueue(...list: SessionReplayContext[]) {\n const tryable = list.filter((context) => {\n if (context.attempts < this.config.flushMaxRetries) {\n context.attempts += 1;\n return true;\n }\n this.completeRequest({\n context,\n err: `${MAX_RETRIES_EXCEEDED_MESSAGE}, batch sequence id, ${context.sequenceId}`,\n });\n return false;\n });\n tryable.forEach((context) => {\n this.queue = this.queue.concat(context);\n if (context.timeout === 0) {\n this.schedule(0);\n return;\n }\n\n setTimeout(() => {\n context.timeout = 0;\n this.schedule(0);\n }, context.timeout);\n });\n }\n\n schedule(timeout: number) {\n if (this.scheduled) return;\n this.scheduled = setTimeout(() => {\n void this.flush(true).then(() => {\n if (this.queue.length > 0) {\n this.schedule(timeout);\n }\n });\n }, timeout);\n }\n\n async flush(useRetry = false) {\n const list: SessionReplayContext[] = [];\n const later: SessionReplayContext[] = [];\n this.queue.forEach((context) => (context.timeout === 0 ? list.push(context) : later.push(context)));\n this.queue = later;\n\n if (this.scheduled) {\n clearTimeout(this.scheduled);\n this.scheduled = null;\n }\n\n await Promise.all(list.map((context) => this.send(context, useRetry)));\n }\n\n async send(context: SessionReplayContext, useRetry = true) {\n const payload = {\n api_key: this.config.apiKey,\n device_id: this.config.deviceId,\n session_id: context.sessionId,\n start_timestamp: context.sessionId,\n events_batch: {\n version: 1,\n events: context.events,\n seq_number: context.sequenceId,\n },\n };\n try {\n const options: RequestInit = {\n headers: {\n 'Content-Type': 'application/json',\n Accept: '*/*',\n },\n body: JSON.stringify(payload),\n method: 'POST',\n };\n const res = await fetch(SESSION_REPLAY_SERVER_URL, options);\n if (res === null) {\n this.completeRequest({ context, err: UNEXPECTED_ERROR_MESSAGE, removeEvents: false });\n return;\n }\n if (!useRetry) {\n let responseBody = '';\n try {\n responseBody = JSON.stringify(res.body, null, 2);\n } catch {\n // to avoid crash, but don't care about the error, add comment to avoid empty block lint error\n }\n this.completeRequest({ context, success: `${res.status}: ${responseBody}` });\n } else {\n this.handleReponse(res.status, context);\n }\n } catch (e) {\n this.completeRequest({ context, err: e as string, removeEvents: false });\n }\n }\n\n handleReponse(status: number, context: SessionReplayContext) {\n const parsedStatus = new BaseTransport().buildStatus(status);\n switch (parsedStatus) {\n case Status.Success:\n this.handleSuccessResponse(context);\n break;\n default:\n this.handleOtherResponse(context);\n }\n }\n\n handleSuccessResponse(context: SessionReplayContext) {\n this.completeRequest({ context, success: getSuccessMessage(context.sessionId) });\n }\n\n handleOtherResponse(context: SessionReplayContext) {\n this.addToQueue({\n ...context,\n timeout: context.attempts * this.retryTimeout,\n });\n }\n\n async getAllSessionEventsFromStore() {\n try {\n const storedReplaySessionContexts: IDBStore | undefined = await IDBKeyVal.get(this.storageKey);\n\n return storedReplaySessionContexts;\n } catch (e) {\n this.config.loggerProvider.error(`${STORAGE_FAILURE}: ${e as string}`);\n }\n return undefined;\n }\n\n async storeEventsForSession(events: Events, sequenceId: number, sessionId: number) {\n try {\n await IDBKeyVal.update(this.storageKey, (sessionMap: IDBStore = {}): IDBStore => {\n const session: IDBStoreSession = sessionMap[sessionId] || { ...defaultSessionStore };\n session.currentSequenceId = sequenceId;\n\n const currentSequence = (session.sessionSequences && session.sessionSequences[sequenceId]) || {};\n\n currentSequence.events = events;\n currentSequence.status = RecordingStatus.RECORDING;\n\n return {\n ...sessionMap,\n [sessionId]: {\n ...session,\n sessionSequences: {\n ...session.sessionSequences,\n [sequenceId]: currentSequence,\n },\n },\n };\n });\n } catch (e) {\n this.config.loggerProvider.error(`${STORAGE_FAILURE}: ${e as string}`);\n }\n }\n\n async storeShouldRecordForSession(sessionId: number, shouldRecord: boolean) {\n try {\n await IDBKeyVal.update(this.storageKey, (sessionMap: IDBStore = {}): IDBStore => {\n const session: IDBStoreSession = sessionMap[sessionId] || { ...defaultSessionStore };\n session.shouldRecord = shouldRecord;\n\n return {\n ...sessionMap,\n [sessionId]: session,\n };\n });\n } catch (e) {\n this.config.loggerProvider.error(`${STORAGE_FAILURE}: ${e as string}`);\n }\n }\n\n async cleanUpSessionEventsStore(sessionId: number, sequenceId: number) {\n try {\n await IDBKeyVal.update(this.storageKey, (sessionMap: IDBStore = {}): IDBStore => {\n const session: IDBStoreSession = sessionMap[sessionId];\n const sequenceToUpdate = session?.sessionSequences && session.sessionSequences[sequenceId];\n if (!sequenceToUpdate) {\n return sessionMap;\n }\n\n sequenceToUpdate.events = [];\n sequenceToUpdate.status = RecordingStatus.SENT;\n\n Object.entries(session.sessionSequences).forEach(([storedSeqId, sequence]) => {\n const numericStoredSeqId = parseInt(storedSeqId, 10);\n if (sequence.status === RecordingStatus.SENT && sequenceId !== numericStoredSeqId) {\n delete session.sessionSequences[numericStoredSeqId];\n }\n });\n\n return sessionMap;\n });\n } catch (e) {\n this.config.loggerProvider.error(`${STORAGE_FAILURE}: ${e as string}`);\n }\n }\n\n completeRequest({\n context,\n err,\n success,\n removeEvents = true,\n }: {\n context: SessionReplayContext;\n err?: string;\n success?: string;\n removeEvents?: boolean;\n }) {\n removeEvents && context.sessionId && this.cleanUpSessionEventsStore(context.sessionId, context.sequenceId);\n if (err) {\n this.config.loggerProvider.error(err);\n } else if (success) {\n this.config.loggerProvider.log(success);\n }\n }\n}\n\nexport const sessionReplayPlugin: SessionReplayPlugin = (options?: SessionReplayOptions) => {\n return new SessionReplay(options);\n};\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BrowserConfig, EnrichmentPlugin } from '@amplitude/analytics-types';
|
|
2
2
|
import { record } from 'rrweb';
|
|
3
|
-
export interface
|
|
3
|
+
export interface SessionReplayOptions {
|
|
4
|
+
sampleRate?: number;
|
|
4
5
|
}
|
|
5
6
|
export type Events = string[];
|
|
6
7
|
export interface SessionReplayContext {
|
|
@@ -19,26 +20,31 @@ export interface IDBStoreSequence {
|
|
|
19
20
|
events: Events;
|
|
20
21
|
status: RecordingStatus;
|
|
21
22
|
}
|
|
22
|
-
export interface
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
};
|
|
23
|
+
export interface IDBStoreSession {
|
|
24
|
+
shouldRecord: boolean;
|
|
25
|
+
currentSequenceId: number;
|
|
26
|
+
sessionSequences: {
|
|
27
|
+
[sequenceId: number]: IDBStoreSequence;
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
+
export interface IDBStore {
|
|
31
|
+
[sessionId: number]: IDBStoreSession;
|
|
32
|
+
}
|
|
30
33
|
export interface SessionReplayEnrichmentPlugin extends EnrichmentPlugin {
|
|
34
|
+
setup: (config: BrowserConfig) => Promise<void>;
|
|
31
35
|
config: BrowserConfig;
|
|
32
36
|
storageKey: string;
|
|
33
37
|
retryTimeout: number;
|
|
34
38
|
events: Events;
|
|
35
39
|
currentSequenceId: number;
|
|
36
40
|
interval: number;
|
|
41
|
+
shouldRecord: boolean;
|
|
37
42
|
queue: SessionReplayContext[];
|
|
38
43
|
timeAtLastSend: number | null;
|
|
39
44
|
stopRecordingEvents: ReturnType<typeof record> | null;
|
|
40
45
|
maxPersistedEventsSize: number;
|
|
41
46
|
initialize: (shouldSendStoredEvents?: boolean) => Promise<void>;
|
|
47
|
+
setShouldRecord: (sessionStore?: IDBStoreSession) => void;
|
|
42
48
|
recordEvents: () => void;
|
|
43
49
|
shouldSplitEventsList: (nextEventString: string) => boolean;
|
|
44
50
|
sendEventsList: ({ events, sequenceId, sessionId, }: {
|
|
@@ -58,11 +64,10 @@ export interface SessionReplayEnrichmentPlugin extends EnrichmentPlugin {
|
|
|
58
64
|
}): void;
|
|
59
65
|
getAllSessionEventsFromStore: () => Promise<IDBStore | undefined>;
|
|
60
66
|
storeEventsForSession: (events: Events, sequenceId: number, sessionId: number) => Promise<void>;
|
|
67
|
+
storeShouldRecordForSession: (sessionId: number, shouldRecord: boolean) => Promise<void>;
|
|
61
68
|
cleanUpSessionEventsStore: (sessionId: number, sequenceId: number) => Promise<void>;
|
|
62
69
|
}
|
|
63
70
|
export interface SessionReplayPlugin {
|
|
64
|
-
(
|
|
65
|
-
(options?: Options): SessionReplayEnrichmentPlugin;
|
|
71
|
+
(options?: SessionReplayOptions): SessionReplayEnrichmentPlugin;
|
|
66
72
|
}
|
|
67
|
-
export type SessionReplayPluginParameters = [BrowserClient, Options?] | [Options?];
|
|
68
73
|
//# sourceMappingURL=session-replay.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../../src/typings/session-replay.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../../src/typings/session-replay.ts"],"names":[],"mappings":"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"}
|