@amplitude/plugin-session-replay-browser 0.1.3 → 0.2.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.
@@ -1 +1 @@
1
- {"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"AAMA,OAAO,EAKL,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AA6TlC,eAAO,MAAM,mBAAmB,EAAE,mBAEjC,CAAC"}
1
+ {"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"AAOA,OAAO,EAML,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AAoXlC,eAAO,MAAM,mBAAmB,EAAE,mBAEjC,CAAC"}
@@ -1,17 +1,19 @@
1
1
  Object.defineProperty(exports, "__esModule", { value: true });
2
2
  exports.sessionReplayPlugin = void 0;
3
3
  var tslib_1 = require("tslib");
4
+ var analytics_client_common_1 = require("@amplitude/analytics-client-common");
4
5
  var analytics_core_1 = require("@amplitude/analytics-core");
5
6
  var analytics_types_1 = require("@amplitude/analytics-types");
6
7
  var IDBKeyVal = tslib_1.__importStar(require("idb-keyval"));
7
8
  var rrweb_1 = require("rrweb");
8
9
  var constants_1 = require("./constants");
9
10
  var messages_1 = require("./messages");
11
+ var session_replay_1 = require("./typings/session-replay");
10
12
  var SESSION_REPLAY_SERVER_URL = 'https://api-secure.amplitude.com/sessions/track';
11
13
  var STORAGE_PREFIX = "".concat(analytics_core_1.AMPLITUDE_PREFIX, "_replay_unsent");
12
14
  var PAYLOAD_ESTIMATED_SIZE_IN_BYTES_WITHOUT_EVENTS = 200; // derived by JSON stringifying an example payload without events
13
15
  var MAX_EVENT_LIST_SIZE_IN_BYTES = 20 * 1000000 - PAYLOAD_ESTIMATED_SIZE_IN_BYTES_WITHOUT_EVENTS;
14
- var MIN_INTERVAL = 1 * 1000; // 1 second
16
+ var MIN_INTERVAL = 500; // 500 ms
15
17
  var MAX_INTERVAL = 10 * 1000; // 10 seconds
16
18
  var SessionReplay = /** @class */ (function () {
17
19
  function SessionReplay() {
@@ -40,8 +42,9 @@ var SessionReplay = /** @class */ (function () {
40
42
  if (sizeOfEventsList + sizeOfNextEvent >= _this.maxPersistedEventsSize) {
41
43
  return true;
42
44
  }
43
- if (_this.timeAtLastSend !== null && Date.now() - _this.timeAtLastSend > _this.interval) {
45
+ if (_this.timeAtLastSend !== null && Date.now() - _this.timeAtLastSend > _this.interval && _this.events.length) {
44
46
  _this.interval = Math.min(MAX_INTERVAL, _this.interval + MIN_INTERVAL);
47
+ _this.timeAtLastSend = Date.now();
45
48
  return true;
46
49
  }
47
50
  return false;
@@ -49,12 +52,29 @@ var SessionReplay = /** @class */ (function () {
49
52
  }
50
53
  SessionReplay.prototype.setup = function (config) {
51
54
  return tslib_1.__awaiter(this, void 0, void 0, function () {
55
+ var GlobalScope;
56
+ var _this = this;
52
57
  return tslib_1.__generator(this, function (_a) {
53
- config.loggerProvider.log('Installing @amplitude/plugin-session-replay.');
54
- this.config = config;
55
- this.storageKey = "".concat(STORAGE_PREFIX, "_").concat(this.config.apiKey.substring(0, 10));
56
- void this.emptyStoreAndReset();
57
- return [2 /*return*/];
58
+ switch (_a.label) {
59
+ case 0:
60
+ config.loggerProvider.log('Installing @amplitude/plugin-session-replay.');
61
+ this.config = config;
62
+ this.storageKey = "".concat(STORAGE_PREFIX, "_").concat(this.config.apiKey.substring(0, 10));
63
+ return [4 /*yield*/, this.initialize(true)];
64
+ case 1:
65
+ _a.sent();
66
+ GlobalScope = (0, analytics_client_common_1.getGlobalScope)();
67
+ if (GlobalScope && GlobalScope.window) {
68
+ GlobalScope.window.addEventListener('blur', function () {
69
+ _this.stopRecordingEvents && _this.stopRecordingEvents();
70
+ _this.stopRecordingEvents = null;
71
+ });
72
+ GlobalScope.window.addEventListener('focus', function () {
73
+ void _this.initialize();
74
+ });
75
+ }
76
+ return [2 /*return*/];
77
+ }
58
78
  });
59
79
  });
60
80
  };
@@ -75,6 +95,7 @@ var SessionReplay = /** @class */ (function () {
75
95
  });
76
96
  }
77
97
  this.stopRecordingEvents && this.stopRecordingEvents();
98
+ this.stopRecordingEvents = null;
78
99
  this.events = [];
79
100
  this.currentSequenceId = 0;
80
101
  }
@@ -82,52 +103,70 @@ var SessionReplay = /** @class */ (function () {
82
103
  });
83
104
  });
84
105
  };
85
- SessionReplay.prototype.emptyStoreAndReset = function () {
106
+ SessionReplay.prototype.initialize = function (shouldSendStoredEvents) {
107
+ if (shouldSendStoredEvents === void 0) { shouldSendStoredEvents = false; }
86
108
  return tslib_1.__awaiter(this, void 0, void 0, function () {
87
- var storedReplaySessions, sessionId, storedReplayEvents, currentSessionStoredEvents;
109
+ var storedReplaySessions, storedSequencesForSession, storedSeqId, lastSequence;
88
110
  return tslib_1.__generator(this, function (_a) {
89
111
  switch (_a.label) {
90
- case 0: return [4 /*yield*/, this.getAllSessionEventsFromStore()];
112
+ case 0:
113
+ this.timeAtLastSend = Date.now(); // Initialize this so we have a point of comparison when events are recorded
114
+ if (!this.config.sessionId) {
115
+ return [2 /*return*/];
116
+ }
117
+ return [4 /*yield*/, this.getAllSessionEventsFromStore()];
91
118
  case 1:
92
119
  storedReplaySessions = _a.sent();
93
- if (storedReplaySessions) {
94
- for (sessionId in storedReplaySessions) {
95
- storedReplayEvents = storedReplaySessions[sessionId];
96
- if (storedReplayEvents.events.length) {
97
- this.sendEventsList({
98
- events: storedReplayEvents.events,
99
- sequenceId: storedReplayEvents.sequenceId,
100
- sessionId: parseInt(sessionId, 10),
101
- });
102
- }
120
+ storedSequencesForSession = storedReplaySessions && storedReplaySessions[this.config.sessionId];
121
+ if (storedReplaySessions && storedSequencesForSession && storedSequencesForSession.sessionSequences) {
122
+ storedSeqId = storedSequencesForSession.currentSequenceId;
123
+ lastSequence = storedSequencesForSession.sessionSequences[storedSeqId];
124
+ if (lastSequence.status !== session_replay_1.RecordingStatus.RECORDING) {
125
+ this.currentSequenceId = storedSeqId + 1;
126
+ this.events = [];
103
127
  }
104
- this.events = [];
105
- currentSessionStoredEvents = this.config.sessionId && storedReplaySessions[this.config.sessionId];
106
- this.currentSequenceId = currentSessionStoredEvents ? currentSessionStoredEvents.sequenceId + 1 : 0;
107
- void this.storeEventsForSession([], this.currentSequenceId);
128
+ else {
129
+ // Pick up recording where it was left off in another tab or window
130
+ this.currentSequenceId = storedSeqId;
131
+ this.events = lastSequence.events;
132
+ }
133
+ }
134
+ if (shouldSendStoredEvents && storedReplaySessions) {
135
+ this.sendStoredEvents(storedReplaySessions);
136
+ }
137
+ if (!this.stopRecordingEvents) {
138
+ this.recordEvents();
108
139
  }
109
- this.recordEvents();
110
140
  return [2 /*return*/];
111
141
  }
112
142
  });
113
143
  });
114
144
  };
145
+ SessionReplay.prototype.sendStoredEvents = function (storedReplaySessions) {
146
+ for (var sessionId in storedReplaySessions) {
147
+ var storedSequences = storedReplaySessions[sessionId].sessionSequences;
148
+ for (var storedSeqId in storedSequences) {
149
+ var seq = storedSequences[storedSeqId];
150
+ var numericSeqId = parseInt(storedSeqId, 10);
151
+ var numericSessionId = parseInt(sessionId, 10);
152
+ if (numericSessionId === this.config.sessionId && numericSeqId === this.currentSequenceId) {
153
+ continue;
154
+ }
155
+ if (seq.events.length && seq.status === session_replay_1.RecordingStatus.RECORDING) {
156
+ this.sendEventsList({
157
+ events: seq.events,
158
+ sequenceId: numericSeqId,
159
+ sessionId: numericSessionId,
160
+ });
161
+ }
162
+ }
163
+ }
164
+ };
115
165
  SessionReplay.prototype.recordEvents = function () {
116
166
  var _this = this;
117
167
  this.stopRecordingEvents = (0, rrweb_1.record)({
118
168
  emit: function (event) {
119
169
  var eventString = JSON.stringify(event);
120
- // Send the first two recorded events immediately
121
- if (_this.events.length === 1 && _this.currentSequenceId === 0) {
122
- _this.sendEventsList({
123
- events: _this.events.concat(eventString),
124
- sequenceId: _this.currentSequenceId,
125
- sessionId: _this.config.sessionId,
126
- });
127
- _this.events = [];
128
- _this.currentSequenceId++;
129
- return;
130
- }
131
170
  var shouldSplit = _this.shouldSplitEventsList(eventString);
132
171
  if (shouldSplit) {
133
172
  _this.sendEventsList({
@@ -139,7 +178,7 @@ var SessionReplay = /** @class */ (function () {
139
178
  _this.currentSequenceId++;
140
179
  }
141
180
  _this.events.push(eventString);
142
- void _this.storeEventsForSession(_this.events, _this.currentSequenceId);
181
+ void _this.storeEventsForSession(_this.events, _this.currentSequenceId, _this.config.sessionId);
143
182
  },
144
183
  packFn: rrweb_1.pack,
145
184
  maskAllInputs: true,
@@ -315,22 +354,25 @@ var SessionReplay = /** @class */ (function () {
315
354
  });
316
355
  });
317
356
  };
318
- SessionReplay.prototype.storeEventsForSession = function (events, sequenceId) {
357
+ SessionReplay.prototype.storeEventsForSession = function (events, sequenceId, sessionId) {
319
358
  return tslib_1.__awaiter(this, void 0, void 0, function () {
320
359
  var e_3;
321
- var _this = this;
322
360
  return tslib_1.__generator(this, function (_a) {
323
361
  switch (_a.label) {
324
362
  case 0:
325
363
  _a.trys.push([0, 2, , 3]);
326
364
  return [4 /*yield*/, IDBKeyVal.update(this.storageKey, function (sessionMap) {
327
- var _a;
328
- return tslib_1.__assign(tslib_1.__assign({}, sessionMap), (_this.config.sessionId && (_a = {},
329
- _a[_this.config.sessionId] = {
330
- events: events,
331
- sequenceId: sequenceId,
332
- },
333
- _a)));
365
+ var _a, _b;
366
+ if (sessionMap === void 0) { sessionMap = {}; }
367
+ var session = sessionMap[sessionId] || {
368
+ currentSequenceId: 0,
369
+ sessionSequences: [],
370
+ };
371
+ session.currentSequenceId = sequenceId;
372
+ var currentSequence = (session.sessionSequences && session.sessionSequences[sequenceId]) || {};
373
+ currentSequence.events = events;
374
+ currentSequence.status = session_replay_1.RecordingStatus.RECORDING;
375
+ return tslib_1.__assign(tslib_1.__assign({}, sessionMap), (_a = {}, _a[sessionId] = tslib_1.__assign(tslib_1.__assign({}, session), { sessionSequences: tslib_1.__assign(tslib_1.__assign({}, session.sessionSequences), (_b = {}, _b[sequenceId] = currentSequence, _b)) }), _a));
334
376
  })];
335
377
  case 1:
336
378
  _a.sent();
@@ -344,7 +386,7 @@ var SessionReplay = /** @class */ (function () {
344
386
  });
345
387
  });
346
388
  };
347
- SessionReplay.prototype.removeSessionEventsStore = function (sessionId) {
389
+ SessionReplay.prototype.cleanUpSessionEventsStore = function (sessionId, sequenceId) {
348
390
  return tslib_1.__awaiter(this, void 0, void 0, function () {
349
391
  var e_4;
350
392
  return tslib_1.__generator(this, function (_a) {
@@ -353,7 +395,20 @@ var SessionReplay = /** @class */ (function () {
353
395
  _a.trys.push([0, 2, , 3]);
354
396
  return [4 /*yield*/, IDBKeyVal.update(this.storageKey, function (sessionMap) {
355
397
  if (sessionMap === void 0) { sessionMap = {}; }
356
- delete sessionMap[sessionId];
398
+ var session = sessionMap[sessionId];
399
+ var sequenceToUpdate = (session === null || session === void 0 ? void 0 : session.sessionSequences) && session.sessionSequences[sequenceId];
400
+ if (!sequenceToUpdate) {
401
+ return sessionMap;
402
+ }
403
+ sequenceToUpdate.events = [];
404
+ sequenceToUpdate.status = session_replay_1.RecordingStatus.SENT;
405
+ Object.entries(session.sessionSequences).forEach(function (_a) {
406
+ var _b = tslib_1.__read(_a, 2), storedSeqId = _b[0], sequence = _b[1];
407
+ var numericStoredSeqId = parseInt(storedSeqId, 10);
408
+ if (sequence.status === session_replay_1.RecordingStatus.SENT && sequenceId !== numericStoredSeqId) {
409
+ delete session.sessionSequences[numericStoredSeqId];
410
+ }
411
+ });
357
412
  return sessionMap;
358
413
  })];
359
414
  case 1:
@@ -370,12 +425,11 @@ var SessionReplay = /** @class */ (function () {
370
425
  };
371
426
  SessionReplay.prototype.completeRequest = function (_a) {
372
427
  var context = _a.context, err = _a.err, success = _a.success, _b = _a.removeEvents, removeEvents = _b === void 0 ? true : _b;
373
- removeEvents && context.sessionId && this.removeSessionEventsStore(context.sessionId);
428
+ removeEvents && context.sessionId && this.cleanUpSessionEventsStore(context.sessionId, context.sequenceId);
374
429
  if (err) {
375
430
  this.config.loggerProvider.error(err);
376
431
  }
377
432
  else if (success) {
378
- this.timeAtLastSend = Date.now();
379
433
  this.config.loggerProvider.log(success);
380
434
  }
381
435
  };
@@ -1 +1 @@
1
- {"version":3,"file":"session-replay.js","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"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","sourcesContent":["import { 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 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 = 200; // derived by JSON stringifying an example payload without events\nconst MAX_EVENT_LIST_SIZE_IN_BYTES = 20 * 1000000 - PAYLOAD_ESTIMATED_SIZE_IN_BYTES_WITHOUT_EVENTS;\nconst MIN_INTERVAL = 1 * 1000; // 1 second\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 void this.emptyStoreAndReset();\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.events = [];\n this.currentSequenceId = 0;\n }\n return Promise.resolve(event);\n }\n\n async emptyStoreAndReset() {\n const storedReplaySessions = await this.getAllSessionEventsFromStore();\n if (storedReplaySessions) {\n for (const sessionId in storedReplaySessions) {\n const storedReplayEvents = storedReplaySessions[sessionId];\n if (storedReplayEvents.events.length) {\n this.sendEventsList({\n events: storedReplayEvents.events,\n sequenceId: storedReplayEvents.sequenceId,\n sessionId: parseInt(sessionId, 10),\n });\n }\n }\n this.events = [];\n const currentSessionStoredEvents = this.config.sessionId && storedReplaySessions[this.config.sessionId];\n this.currentSequenceId = currentSessionStoredEvents ? currentSessionStoredEvents.sequenceId + 1 : 0;\n void this.storeEventsForSession([], this.currentSequenceId);\n }\n this.recordEvents();\n }\n\n recordEvents() {\n this.stopRecordingEvents = record({\n emit: (event) => {\n const eventString = JSON.stringify(event);\n // Send the first two recorded events immediately\n if (this.events.length === 1 && this.currentSequenceId === 0) {\n this.sendEventsList({\n events: this.events.concat(eventString),\n sequenceId: this.currentSequenceId,\n sessionId: this.config.sessionId as number,\n });\n this.events = [];\n this.currentSequenceId++;\n return;\n }\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);\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) {\n this.interval = Math.min(MAX_INTERVAL, this.interval + MIN_INTERVAL);\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) {\n try {\n await IDBKeyVal.update(this.storageKey, (sessionMap: IDBStore | undefined): IDBStore => {\n return {\n ...sessionMap,\n ...(this.config.sessionId && {\n [this.config.sessionId]: {\n events: events,\n sequenceId,\n },\n }),\n };\n });\n } catch (e) {\n this.config.loggerProvider.error(`${STORAGE_FAILURE}: ${e as string}`);\n }\n }\n\n async removeSessionEventsStore(sessionId: number) {\n try {\n await IDBKeyVal.update(this.storageKey, (sessionMap: IDBStore = {}): IDBStore => {\n delete sessionMap[sessionId];\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.removeSessionEventsStore(context.sessionId);\n if (err) {\n this.config.loggerProvider.error(err);\n } else if (success) {\n this.timeAtLastSend = Date.now();\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":";;;AAAA,8EAAoE;AACpE,4DAA4E;AAC5E,8DAA0E;AAC1E,4DAAwC;AACxC,+BAAqC;AACrC,yCAAsH;AACtH,uCAAsH;AACtH,2DAOkC;AAElC,IAAM,yBAAyB,GAAG,iDAAiD,CAAC;AACpF,IAAM,cAAc,GAAG,UAAG,iCAAgB,mBAAgB,CAAC;AAC3D,IAAM,8CAA8C,GAAG,GAAG,CAAC,CAAC,iEAAiE;AAC7H,IAAM,4BAA4B,GAAG,EAAE,GAAG,OAAO,GAAG,8CAA8C,CAAC;AACnG,IAAM,YAAY,GAAG,GAAG,CAAC,CAAC,SAAS;AACnC,IAAM,YAAY,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,aAAa;AAE7C;IAAA;QAAA,iBAyWC;QAxWC,SAAI,GAAG,0CAA0C,CAAC;QAClD,SAAI,GAAG,YAAqB,CAAC;QAK7B,eAAU,GAAG,EAAE,CAAC;QAChB,iBAAY,GAAG,IAAI,CAAC;QACpB,WAAM,GAAW,EAAE,CAAC;QACpB,sBAAiB,GAAG,CAAC,CAAC;QACd,cAAS,GAAyC,IAAI,CAAC;QAC/D,UAAK,GAA2B,EAAE,CAAC;QACnC,wBAAmB,GAAqC,IAAI,CAAC;QAC7D,2BAAsB,GAAG,4BAA4B,CAAC;QACtD,aAAQ,GAAG,YAAY,CAAC;QACxB,mBAAc,GAAkB,IAAI,CAAC;QAmHrC;;;;;WAKG;QACH,0BAAqB,GAAG,UAAC,eAAuB;YAC9C,IAAM,eAAe,GAAG,IAAI,IAAI,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC;YACzD,IAAM,gBAAgB,GAAG,IAAI,IAAI,CAAC,KAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;YACpD,IAAI,gBAAgB,GAAG,eAAe,IAAI,KAAI,CAAC,sBAAsB,EAAE;gBACrE,OAAO,IAAI,CAAC;aACb;YACD,IAAI,KAAI,CAAC,cAAc,KAAK,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAI,CAAC,cAAc,GAAG,KAAI,CAAC,QAAQ,IAAI,KAAI,CAAC,MAAM,CAAC,MAAM,EAAE;gBAC1G,KAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,KAAI,CAAC,QAAQ,GAAG,YAAY,CAAC,CAAC;gBACrE,KAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACjC,OAAO,IAAI,CAAC;aACb;YACD,OAAO,KAAK,CAAC;QACf,CAAC,CAAC;IAoNJ,CAAC;IAvVO,6BAAK,GAAX,UAAY,MAAqB;;;;;;;wBAC/B,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;wBAE1E,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;wBACrB,IAAI,CAAC,UAAU,GAAG,UAAG,cAAc,cAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAE,CAAC;wBAC7E,qBAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAA;;wBAA3B,SAA2B,CAAC;wBAEtB,WAAW,GAAG,IAAA,wCAAc,GAAE,CAAC;wBACrC,IAAI,WAAW,IAAI,WAAW,CAAC,MAAM,EAAE;4BACrC,WAAW,CAAC,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE;gCAC1C,KAAI,CAAC,mBAAmB,IAAI,KAAI,CAAC,mBAAmB,EAAE,CAAC;gCACvD,KAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;4BAClC,CAAC,CAAC,CAAC;4BACH,WAAW,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE;gCAC3C,KAAK,KAAI,CAAC,UAAU,EAAE,CAAC;4BACzB,CAAC,CAAC,CAAC;yBACJ;;;;;KACF;IAEK,+BAAO,GAAb,UAAc,KAAY;;;;gBACxB,KAAK,CAAC,gBAAgB,yCACjB,KAAK,CAAC,gBAAgB,gBACxB,2CAA+B,IAAG,IAAI,MACxC,CAAC;gBACF,IAAI,KAAK,CAAC,UAAU,KAAK,uCAA2B,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE;oBACjF,IAAI,CAAC,YAAY,EAAE,CAAC;iBACrB;qBAAM,IAAI,KAAK,CAAC,UAAU,KAAK,qCAAyB,EAAE;oBACzD,IAAI,KAAK,CAAC,UAAU,EAAE;wBACpB,IAAI,CAAC,cAAc,CAAC;4BAClB,MAAM,EAAE,IAAI,CAAC,MAAM;4BACnB,UAAU,EAAE,IAAI,CAAC,iBAAiB;4BAClC,SAAS,EAAE,KAAK,CAAC,UAAU;yBAC5B,CAAC,CAAC;qBACJ;oBACD,IAAI,CAAC,mBAAmB,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;oBACvD,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;oBAChC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;oBACjB,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;iBAC5B;gBACD,sBAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAC;;;KAC/B;IAEK,kCAAU,GAAhB,UAAiB,sBAA8B;QAA9B,uCAAA,EAAA,8BAA8B;;;;;;wBAC7C,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,4EAA4E;wBAC9G,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;4BAC1B,sBAAO;yBACR;wBAC4B,qBAAM,IAAI,CAAC,4BAA4B,EAAE,EAAA;;wBAAhE,oBAAoB,GAAG,SAAyC;wBAChE,yBAAyB,GAAG,oBAAoB,IAAI,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;wBACtG,IAAI,oBAAoB,IAAI,yBAAyB,IAAI,yBAAyB,CAAC,gBAAgB,EAAE;4BAC7F,WAAW,GAAG,yBAAyB,CAAC,iBAAiB,CAAC;4BAC1D,YAAY,GAAG,yBAAyB,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;4BAC7E,IAAI,YAAY,CAAC,MAAM,KAAK,gCAAe,CAAC,SAAS,EAAE;gCACrD,IAAI,CAAC,iBAAiB,GAAG,WAAW,GAAG,CAAC,CAAC;gCACzC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;6BAClB;iCAAM;gCACL,mEAAmE;gCACnE,IAAI,CAAC,iBAAiB,GAAG,WAAW,CAAC;gCACrC,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC;6BACnC;yBACF;wBACD,IAAI,sBAAsB,IAAI,oBAAoB,EAAE;4BAClD,IAAI,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,CAAC;yBAC7C;wBACD,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE;4BAC7B,IAAI,CAAC,YAAY,EAAE,CAAC;yBACrB;;;;;KACF;IAED,wCAAgB,GAAhB,UAAiB,oBAA8B;QAC7C,KAAK,IAAM,SAAS,IAAI,oBAAoB,EAAE;YAC5C,IAAM,eAAe,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC,gBAAgB,CAAC;YACzE,KAAK,IAAM,WAAW,IAAI,eAAe,EAAE;gBACzC,IAAM,GAAG,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;gBACzC,IAAM,YAAY,GAAG,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;gBAC/C,IAAM,gBAAgB,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;gBACjD,IAAI,gBAAgB,KAAK,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,YAAY,KAAK,IAAI,CAAC,iBAAiB,EAAE;oBACzF,SAAS;iBACV;gBACD,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,KAAK,gCAAe,CAAC,SAAS,EAAE;oBACjE,IAAI,CAAC,cAAc,CAAC;wBAClB,MAAM,EAAE,GAAG,CAAC,MAAM;wBAClB,UAAU,EAAE,YAAY;wBACxB,SAAS,EAAE,gBAAgB;qBAC5B,CAAC,CAAC;iBACJ;aACF;SACF;IACH,CAAC;IAED,oCAAY,GAAZ;QAAA,iBAqBC;QApBC,IAAI,CAAC,mBAAmB,GAAG,IAAA,cAAM,EAAC;YAChC,IAAI,EAAE,UAAC,KAAK;gBACV,IAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;gBAE1C,IAAM,WAAW,GAAG,KAAI,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC;gBAC5D,IAAI,WAAW,EAAE;oBACf,KAAI,CAAC,cAAc,CAAC;wBAClB,MAAM,EAAE,KAAI,CAAC,MAAM;wBACnB,UAAU,EAAE,KAAI,CAAC,iBAAiB;wBAClC,SAAS,EAAE,KAAI,CAAC,MAAM,CAAC,SAAmB;qBAC3C,CAAC,CAAC;oBACH,KAAI,CAAC,MAAM,GAAG,EAAE,CAAC;oBACjB,KAAI,CAAC,iBAAiB,EAAE,CAAC;iBAC1B;gBACD,KAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC9B,KAAK,KAAI,CAAC,qBAAqB,CAAC,KAAI,CAAC,MAAM,EAAE,KAAI,CAAC,iBAAiB,EAAE,KAAI,CAAC,MAAM,CAAC,SAAmB,CAAC,CAAC;YACxG,CAAC;YACD,MAAM,EAAE,YAAI;YACZ,aAAa,EAAE,IAAI;SACpB,CAAC,CAAC;IACL,CAAC;IAsBD,sCAAc,GAAd,UAAe,EAA8F;YAA5F,MAAM,YAAA,EAAE,UAAU,gBAAA,EAAE,SAAS,eAAA;QAC5C,IAAI,CAAC,UAAU,CAAC;YACd,MAAM,QAAA;YACN,UAAU,YAAA;YACV,QAAQ,EAAE,CAAC;YACX,OAAO,EAAE,CAAC;YACV,SAAS,WAAA;SACV,CAAC,CAAC;IACL,CAAC;IAED,kCAAU,GAAV;QAAA,iBAwBC;QAxBU,cAA+B;aAA/B,UAA+B,EAA/B,qBAA+B,EAA/B,IAA+B;YAA/B,yBAA+B;;QACxC,IAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAC,OAAO;YAClC,IAAI,OAAO,CAAC,QAAQ,GAAG,KAAI,CAAC,MAAM,CAAC,eAAe,EAAE;gBAClD,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC;gBACtB,OAAO,IAAI,CAAC;aACb;YACD,KAAI,CAAC,eAAe,CAAC;gBACnB,OAAO,SAAA;gBACP,GAAG,EAAE,UAAG,uCAA4B,kCAAwB,OAAO,CAAC,UAAU,CAAE;aACjF,CAAC,CAAC;YACH,OAAO,KAAK,CAAC;QACf,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,OAAO,CAAC,UAAC,OAAO;YACtB,KAAI,CAAC,KAAK,GAAG,KAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACxC,IAAI,OAAO,CAAC,OAAO,KAAK,CAAC,EAAE;gBACzB,KAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACjB,OAAO;aACR;YAED,UAAU,CAAC;gBACT,OAAO,CAAC,OAAO,GAAG,CAAC,CAAC;gBACpB,KAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YACnB,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QACtB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,gCAAQ,GAAR,UAAS,OAAe;QAAxB,iBASC;QARC,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAC3B,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC;YAC1B,KAAK,KAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;gBACzB,IAAI,KAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;oBACzB,KAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;iBACxB;YACH,CAAC,CAAC,CAAC;QACL,CAAC,EAAE,OAAO,CAAC,CAAC;IACd,CAAC;IAEK,6BAAK,GAAX,UAAY,QAAgB;QAAhB,yBAAA,EAAA,gBAAgB;;;;;;;wBACpB,IAAI,GAA2B,EAAE,CAAC;wBAClC,KAAK,GAA2B,EAAE,CAAC;wBACzC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAC,OAAO,IAAK,OAAA,CAAC,OAAO,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAlE,CAAkE,CAAC,CAAC;wBACpG,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;wBAEnB,IAAI,IAAI,CAAC,SAAS,EAAE;4BAClB,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;4BAC7B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;yBACvB;wBAED,qBAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,UAAC,OAAO,IAAK,OAAA,KAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,EAA5B,CAA4B,CAAC,CAAC,EAAA;;wBAAtE,SAAsE,CAAC;;;;;KACxE;IAEK,4BAAI,GAAV,UAAW,OAA6B,EAAE,QAAe;QAAf,yBAAA,EAAA,eAAe;;;;;;wBACjD,OAAO,GAAG;4BACd,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;4BAC3B,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;4BAC/B,UAAU,EAAE,OAAO,CAAC,SAAS;4BAC7B,eAAe,EAAE,OAAO,CAAC,SAAS;4BAClC,YAAY,EAAE;gCACZ,OAAO,EAAE,CAAC;gCACV,MAAM,EAAE,OAAO,CAAC,MAAM;gCACtB,UAAU,EAAE,OAAO,CAAC,UAAU;6BAC/B;yBACF,CAAC;;;;wBAEM,OAAO,GAAgB;4BAC3B,OAAO,EAAE;gCACP,cAAc,EAAE,kBAAkB;gCAClC,MAAM,EAAE,KAAK;6BACd;4BACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;4BAC7B,MAAM,EAAE,MAAM;yBACf,CAAC;wBACU,qBAAM,KAAK,CAAC,yBAAyB,EAAE,OAAO,CAAC,EAAA;;wBAArD,GAAG,GAAG,SAA+C;wBAC3D,IAAI,GAAG,KAAK,IAAI,EAAE;4BAChB,IAAI,CAAC,eAAe,CAAC,EAAE,OAAO,SAAA,EAAE,GAAG,EAAE,mCAAwB,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;4BACtF,sBAAO;yBACR;wBACD,IAAI,CAAC,QAAQ,EAAE;4BACT,YAAY,GAAG,EAAE,CAAC;4BACtB,IAAI;gCACF,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;6BAClD;4BAAC,WAAM;gCACN,8FAA8F;6BAC/F;4BACD,IAAI,CAAC,eAAe,CAAC,EAAE,OAAO,SAAA,EAAE,OAAO,EAAE,UAAG,GAAG,CAAC,MAAM,eAAK,YAAY,CAAE,EAAE,CAAC,CAAC;yBAC9E;6BAAM;4BACL,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;yBACzC;;;;wBAED,IAAI,CAAC,eAAe,CAAC,EAAE,OAAO,SAAA,EAAE,GAAG,EAAE,GAAW,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;;;;;;KAE5E;IAED,qCAAa,GAAb,UAAc,MAAc,EAAE,OAA6B;QACzD,IAAM,YAAY,GAAG,IAAI,8BAAa,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC7D,QAAQ,YAAY,EAAE;YACpB,KAAK,wBAAM,CAAC,OAAO;gBACjB,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC;gBACpC,MAAM;YACR;gBACE,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;SACrC;IACH,CAAC;IAED,6CAAqB,GAArB,UAAsB,OAA6B;QACjD,IAAI,CAAC,eAAe,CAAC,EAAE,OAAO,SAAA,EAAE,OAAO,EAAE,0BAAe,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,2CAAmB,GAAnB,UAAoB,OAA6B;QAC/C,IAAI,CAAC,UAAU,uCACV,OAAO,KACV,OAAO,EAAE,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,YAAY,IAC7C,CAAC;IACL,CAAC;IAEK,oDAA4B,GAAlC;;;;;;;wBAE8D,qBAAM,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAA;;wBAAxF,2BAA2B,GAAyB,SAAoC;wBAE9F,sBAAO,2BAA2B,EAAC;;;wBAEnC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,UAAG,0BAAe,eAAK,GAAW,CAAE,CAAC,CAAC;;4BAEzE,sBAAO,SAAS,EAAC;;;;KAClB;IAEK,6CAAqB,GAA3B,UAA4B,MAAc,EAAE,UAAkB,EAAE,SAAiB;;;;;;;wBAE7E,qBAAM,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,UAAC,UAAyB;;gCAAzB,2BAAA,EAAA,eAAyB;gCAChE,IAAM,OAAO,GAAG,UAAU,CAAC,SAAS,CAAC,IAAI;oCACvC,iBAAiB,EAAE,CAAC;oCACpB,gBAAgB,EAAE,EAAE;iCACrB,CAAC;gCACF,OAAO,CAAC,iBAAiB,GAAG,UAAU,CAAC;gCAEvC,IAAM,eAAe,GAAG,CAAC,OAAO,CAAC,gBAAgB,IAAI,OAAO,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;gCAEjG,eAAe,CAAC,MAAM,GAAG,MAAM,CAAC;gCAChC,eAAe,CAAC,MAAM,GAAG,gCAAe,CAAC,SAAS,CAAC;gCAEnD,6CACK,UAAU,gBACZ,SAAS,0CACL,OAAO,KACV,gBAAgB,wCACX,OAAO,CAAC,gBAAgB,gBAC1B,UAAU,IAAG,eAAe,gBAGjC;4BACJ,CAAC,CAAC,EAAA;;wBAtBF,SAsBE,CAAC;;;;wBAEH,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,UAAG,0BAAe,eAAK,GAAW,CAAE,CAAC,CAAC;;;;;;KAE1E;IAEK,iDAAyB,GAA/B,UAAgC,SAAiB,EAAE,UAAkB;;;;;;;wBAEjE,qBAAM,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,UAAC,UAAyB;gCAAzB,2BAAA,EAAA,eAAyB;gCAChE,IAAM,OAAO,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;gCACtC,IAAM,gBAAgB,GAAG,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,gBAAgB,KAAI,OAAO,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;gCAC3F,IAAI,CAAC,gBAAgB,EAAE;oCACrB,OAAO,UAAU,CAAC;iCACnB;gCAED,gBAAgB,CAAC,MAAM,GAAG,EAAE,CAAC;gCAC7B,gBAAgB,CAAC,MAAM,GAAG,gCAAe,CAAC,IAAI,CAAC;gCAE/C,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,UAAC,EAAuB;wCAAvB,KAAA,qBAAuB,EAAtB,WAAW,QAAA,EAAE,QAAQ,QAAA;oCACtE,IAAM,kBAAkB,GAAG,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;oCACrD,IAAI,QAAQ,CAAC,MAAM,KAAK,gCAAe,CAAC,IAAI,IAAI,UAAU,KAAK,kBAAkB,EAAE;wCACjF,OAAO,OAAO,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;qCACrD;gCACH,CAAC,CAAC,CAAC;gCAEH,OAAO,UAAU,CAAC;4BACpB,CAAC,CAAC,EAAA;;wBAlBF,SAkBE,CAAC;;;;wBAEH,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,UAAG,0BAAe,eAAK,GAAW,CAAE,CAAC,CAAC;;;;;;KAE1E;IAED,uCAAe,GAAf,UAAgB,EAUf;YATC,OAAO,aAAA,EACP,GAAG,SAAA,EACH,OAAO,aAAA,EACP,oBAAmB,EAAnB,YAAY,mBAAG,IAAI,KAAA;QAOnB,YAAY,IAAI,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,yBAAyB,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QAC3G,IAAI,GAAG,EAAE;YACP,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;SACvC;aAAM,IAAI,OAAO,EAAE;YAClB,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;SACzC;IACH,CAAC;IACH,oBAAC;AAAD,CAAC,AAzWD,IAyWC;AAEM,IAAM,mBAAmB,GAAwB;IACtD,OAAO,IAAI,aAAa,EAAE,CAAC;AAC7B,CAAC,CAAC;AAFW,QAAA,mBAAmB,uBAE9B","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 = 200; // derived by JSON stringifying an example payload without events\nconst MAX_EVENT_LIST_SIZE_IN_BYTES = 20 * 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 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"]}
@@ -10,10 +10,21 @@ export interface SessionReplayContext {
10
10
  timeout: number;
11
11
  sessionId: number;
12
12
  }
13
+ export declare enum RecordingStatus {
14
+ RECORDING = "recording",
15
+ SENDING = "sending",
16
+ SENT = "sent"
17
+ }
18
+ export interface IDBStoreSequence {
19
+ events: Events;
20
+ status: RecordingStatus;
21
+ }
13
22
  export interface IDBStore {
14
23
  [sessionId: number]: {
15
- events: Events;
16
- sequenceId: number;
24
+ currentSequenceId: number;
25
+ sessionSequences: {
26
+ [sequenceId: number]: IDBStoreSequence;
27
+ };
17
28
  };
18
29
  }
19
30
  export interface SessionReplayEnrichmentPlugin extends EnrichmentPlugin {
@@ -27,7 +38,7 @@ export interface SessionReplayEnrichmentPlugin extends EnrichmentPlugin {
27
38
  timeAtLastSend: number | null;
28
39
  stopRecordingEvents: ReturnType<typeof record> | null;
29
40
  maxPersistedEventsSize: number;
30
- emptyStoreAndReset: () => Promise<void>;
41
+ initialize: (shouldSendStoredEvents?: boolean) => Promise<void>;
31
42
  recordEvents: () => void;
32
43
  shouldSplitEventsList: (nextEventString: string) => boolean;
33
44
  sendEventsList: ({ events, sequenceId, sessionId, }: {
@@ -46,8 +57,8 @@ export interface SessionReplayEnrichmentPlugin extends EnrichmentPlugin {
46
57
  removeEvents?: boolean | undefined;
47
58
  }): void;
48
59
  getAllSessionEventsFromStore: () => Promise<IDBStore | undefined>;
49
- storeEventsForSession: (events: Events, sequenceId: number) => Promise<void>;
50
- removeSessionEventsStore: (sessionId: number) => Promise<void>;
60
+ storeEventsForSession: (events: Events, sequenceId: number, sessionId: number) => Promise<void>;
61
+ cleanUpSessionEventsStore: (sessionId: number, sequenceId: number) => Promise<void>;
51
62
  }
52
63
  export interface SessionReplayPlugin {
53
64
  (client: BrowserClient, options?: Options): SessionReplayEnrichmentPlugin;
@@ -1 +1 @@
1
- {"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../../src/typings/session-replay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../../src/typings/session-replay.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,9 @@
1
1
  Object.defineProperty(exports, "__esModule", { value: true });
2
+ exports.RecordingStatus = void 0;
3
+ var RecordingStatus;
4
+ (function (RecordingStatus) {
5
+ RecordingStatus["RECORDING"] = "recording";
6
+ RecordingStatus["SENDING"] = "sending";
7
+ RecordingStatus["SENT"] = "sent";
8
+ })(RecordingStatus = exports.RecordingStatus || (exports.RecordingStatus = {}));
2
9
  //# sourceMappingURL=session-replay.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-replay.js","sourceRoot":"","sources":["../../../src/typings/session-replay.ts"],"names":[],"mappings":"","sourcesContent":["import { BrowserClient, BrowserConfig, EnrichmentPlugin } from '@amplitude/analytics-types';\nimport { record } from 'rrweb';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface Options {}\n\nexport type Events = string[];\n\nexport interface SessionReplayContext {\n events: Events;\n sequenceId: number;\n attempts: number;\n timeout: number;\n sessionId: number;\n}\n\nexport interface IDBStore {\n [sessionId: number]: {\n events: Events;\n sequenceId: number;\n };\n}\nexport interface SessionReplayEnrichmentPlugin extends EnrichmentPlugin {\n config: BrowserConfig;\n storageKey: string;\n retryTimeout: number;\n events: Events;\n currentSequenceId: number;\n interval: number;\n queue: SessionReplayContext[];\n timeAtLastSend: number | null;\n stopRecordingEvents: ReturnType<typeof record> | null;\n maxPersistedEventsSize: number;\n emptyStoreAndReset: () => Promise<void>;\n recordEvents: () => void;\n shouldSplitEventsList: (nextEventString: string) => boolean;\n sendEventsList: ({\n events,\n sequenceId,\n sessionId,\n }: {\n events: string[];\n sequenceId: number;\n sessionId: number;\n }) => void;\n addToQueue: (...list: SessionReplayContext[]) => void;\n schedule: (timeout: number) => void;\n flush: (useRetry?: boolean) => Promise<void>;\n send: (context: SessionReplayContext, useRetry?: boolean) => Promise<void>;\n completeRequest({\n context,\n err,\n success,\n removeEvents,\n }: {\n context: SessionReplayContext;\n err?: string | undefined;\n success?: string | undefined;\n removeEvents?: boolean | undefined;\n }): void;\n getAllSessionEventsFromStore: () => Promise<IDBStore | undefined>;\n storeEventsForSession: (events: Events, sequenceId: number) => Promise<void>;\n removeSessionEventsStore: (sessionId: number) => Promise<void>;\n}\n\nexport interface SessionReplayPlugin {\n (client: BrowserClient, options?: Options): SessionReplayEnrichmentPlugin;\n (options?: Options): SessionReplayEnrichmentPlugin;\n}\n\nexport type SessionReplayPluginParameters = [BrowserClient, Options?] | [Options?];\n"]}
1
+ {"version":3,"file":"session-replay.js","sourceRoot":"","sources":["../../../src/typings/session-replay.ts"],"names":[],"mappings":";;AAgBA,IAAY,eAIX;AAJD,WAAY,eAAe;IACzB,0CAAuB,CAAA;IACvB,sCAAmB,CAAA;IACnB,gCAAa,CAAA;AACf,CAAC,EAJW,eAAe,GAAf,uBAAe,KAAf,uBAAe,QAI1B","sourcesContent":["import { BrowserClient, BrowserConfig, EnrichmentPlugin } from '@amplitude/analytics-types';\nimport { record } from 'rrweb';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface Options {}\n\nexport type Events = string[];\n\nexport interface SessionReplayContext {\n events: Events;\n sequenceId: number;\n attempts: number;\n timeout: number;\n sessionId: number;\n}\n\nexport enum RecordingStatus {\n RECORDING = 'recording',\n SENDING = 'sending',\n SENT = 'sent',\n}\n\nexport interface IDBStoreSequence {\n events: Events;\n status: RecordingStatus;\n}\n\nexport interface IDBStore {\n [sessionId: number]: {\n currentSequenceId: number;\n sessionSequences: { [sequenceId: number]: IDBStoreSequence };\n };\n}\nexport interface SessionReplayEnrichmentPlugin extends EnrichmentPlugin {\n config: BrowserConfig;\n storageKey: string;\n retryTimeout: number;\n events: Events;\n currentSequenceId: number;\n interval: number;\n queue: SessionReplayContext[];\n timeAtLastSend: number | null;\n stopRecordingEvents: ReturnType<typeof record> | null;\n maxPersistedEventsSize: number;\n initialize: (shouldSendStoredEvents?: boolean) => Promise<void>;\n recordEvents: () => void;\n shouldSplitEventsList: (nextEventString: string) => boolean;\n sendEventsList: ({\n events,\n sequenceId,\n sessionId,\n }: {\n events: string[];\n sequenceId: number;\n sessionId: number;\n }) => void;\n addToQueue: (...list: SessionReplayContext[]) => void;\n schedule: (timeout: number) => void;\n flush: (useRetry?: boolean) => Promise<void>;\n send: (context: SessionReplayContext, useRetry?: boolean) => Promise<void>;\n completeRequest({\n context,\n err,\n success,\n removeEvents,\n }: {\n context: SessionReplayContext;\n err?: string | undefined;\n success?: string | undefined;\n removeEvents?: boolean | undefined;\n }): void;\n getAllSessionEventsFromStore: () => Promise<IDBStore | undefined>;\n storeEventsForSession: (events: Events, sequenceId: number, sessionId: number) => Promise<void>;\n cleanUpSessionEventsStore: (sessionId: number, sequenceId: number) => Promise<void>;\n}\n\nexport interface SessionReplayPlugin {\n (client: BrowserClient, options?: Options): SessionReplayEnrichmentPlugin;\n (options?: Options): SessionReplayEnrichmentPlugin;\n}\n\nexport type SessionReplayPluginParameters = [BrowserClient, Options?] | [Options?];\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"AAMA,OAAO,EAKL,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AA6TlC,eAAO,MAAM,mBAAmB,EAAE,mBAEjC,CAAC"}
1
+ {"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"AAOA,OAAO,EAML,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AAoXlC,eAAO,MAAM,mBAAmB,EAAE,mBAEjC,CAAC"}