@amplitude/plugin-session-replay-browser 0.4.1 → 0.5.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.
@@ -7,9 +7,11 @@ export declare const BLOCK_CLASS = "amp-block";
7
7
  export declare const MASK_TEXT_CLASS = "amp-mask";
8
8
  export declare const UNMASK_TEXT_CLASS = "amp-unmask";
9
9
  export declare const SESSION_REPLAY_SERVER_URL = "https://api-secure.amplitude.com/sessions/track";
10
+ export declare const SESSION_REPLAY_EU_URL = "https://api.eu.amplitude.com/sessions/track";
10
11
  export declare const STORAGE_PREFIX: string;
11
12
  export declare const MAX_EVENT_LIST_SIZE_IN_BYTES: number;
12
13
  export declare const MIN_INTERVAL = 500;
13
14
  export declare const MAX_INTERVAL: number;
14
15
  export declare const defaultSessionStore: IDBStoreSession;
16
+ export declare const MAX_IDB_STORAGE_LENGTH: number;
15
17
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
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"}
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,qBAAqB,gDAAgD,CAAC;AACnF,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;AACF,eAAO,MAAM,sBAAsB,QAA0B,CAAC"}
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, "__esModule", { value: true });
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;
2
+ exports.MAX_IDB_STORAGE_LENGTH = exports.defaultSessionStore = exports.MAX_INTERVAL = exports.MIN_INTERVAL = exports.MAX_EVENT_LIST_SIZE_IN_BYTES = exports.STORAGE_PREFIX = exports.SESSION_REPLAY_EU_URL = 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
3
  var analytics_core_1 = require("@amplitude/analytics-core");
4
4
  exports.DEFAULT_EVENT_PROPERTY_PREFIX = '[Amplitude]';
5
5
  exports.DEFAULT_SESSION_REPLAY_PROPERTY = "".concat(exports.DEFAULT_EVENT_PROPERTY_PREFIX, " Session Recorded");
@@ -9,6 +9,7 @@ exports.BLOCK_CLASS = 'amp-block';
9
9
  exports.MASK_TEXT_CLASS = 'amp-mask';
10
10
  exports.UNMASK_TEXT_CLASS = 'amp-unmask';
11
11
  exports.SESSION_REPLAY_SERVER_URL = 'https://api-secure.amplitude.com/sessions/track';
12
+ exports.SESSION_REPLAY_EU_URL = 'https://api.eu.amplitude.com/sessions/track';
12
13
  exports.STORAGE_PREFIX = "".concat(analytics_core_1.AMPLITUDE_PREFIX, "_replay_unsent");
13
14
  var PAYLOAD_ESTIMATED_SIZE_IN_BYTES_WITHOUT_EVENTS = 500; // derived by JSON stringifying an example payload without events
14
15
  exports.MAX_EVENT_LIST_SIZE_IN_BYTES = 10 * 1000000 - PAYLOAD_ESTIMATED_SIZE_IN_BYTES_WITHOUT_EVENTS;
@@ -19,4 +20,5 @@ exports.defaultSessionStore = {
19
20
  currentSequenceId: 0,
20
21
  sessionSequences: {},
21
22
  };
23
+ exports.MAX_IDB_STORAGE_LENGTH = 1000 * 60 * 60 * 24 * 3; // 3 days
22
24
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
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"]}
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,qBAAqB,GAAG,6CAA6C,CAAC;AACtE,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;AACW,QAAA,sBAAsB,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS","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 SESSION_REPLAY_EU_URL = 'https://api.eu.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};\nexport const MAX_IDB_STORAGE_LENGTH = 1000 * 60 * 60 * 24 * 3; // 3 days\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"AAoBA,OAAO,EAQL,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AAsblC,eAAO,MAAM,mBAAmB,EAAE,mBAEjC,CAAC"}
1
+ {"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"AAsBA,OAAO,EAQL,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AAkclC,eAAO,MAAM,mBAAmB,EAAE,mBAEjC,CAAC"}
@@ -138,6 +138,12 @@ var SessionReplay = /** @class */ (function () {
138
138
  return [4 /*yield*/, this.getAllSessionEventsFromStore()];
139
139
  case 1:
140
140
  storedReplaySessions = _a.sent();
141
+ // This resolves a timing issue when focus is fired multiple times in short succession,
142
+ // we only want the rest of this function to run once. We can be sure that initialize has
143
+ // already been called if this.stopRecordingEvents is defined
144
+ if (this.stopRecordingEvents) {
145
+ return [2 /*return*/];
146
+ }
141
147
  storedSequencesForSession = storedReplaySessions && storedReplaySessions[this.config.sessionId];
142
148
  if (storedReplaySessions && storedSequencesForSession && storedSequencesForSession.sessionSequences) {
143
149
  storedSeqId = storedSequencesForSession.currentSequenceId;
@@ -156,17 +162,15 @@ var SessionReplay = /** @class */ (function () {
156
162
  if (shouldSendStoredEvents && storedReplaySessions) {
157
163
  this.sendStoredEvents(storedReplaySessions);
158
164
  }
159
- if (!this.stopRecordingEvents) {
160
- this.recordEvents();
161
- }
165
+ this.recordEvents();
162
166
  return [2 /*return*/];
163
167
  }
164
168
  });
165
169
  });
166
170
  };
167
171
  SessionReplay.prototype.setShouldRecord = function (sessionStore) {
168
- if ((sessionStore === null || sessionStore === void 0 ? void 0 : sessionStore.shouldRecord) === false) {
169
- this.shouldRecord = false;
172
+ if (sessionStore && typeof sessionStore.shouldRecord === 'boolean') {
173
+ this.shouldRecord = sessionStore.shouldRecord;
170
174
  }
171
175
  else if (this.config.optOut) {
172
176
  this.shouldRecord = false;
@@ -307,10 +311,16 @@ var SessionReplay = /** @class */ (function () {
307
311
  });
308
312
  });
309
313
  };
314
+ SessionReplay.prototype.getServerUrl = function () {
315
+ if (this.config.serverZone === analytics_types_1.ServerZone.EU) {
316
+ return constants_1.SESSION_REPLAY_EU_URL;
317
+ }
318
+ return constants_1.SESSION_REPLAY_SERVER_URL;
319
+ };
310
320
  SessionReplay.prototype.send = function (context, useRetry) {
311
321
  if (useRetry === void 0) { useRetry = true; }
312
322
  return tslib_1.__awaiter(this, void 0, void 0, function () {
313
- var payload, options, res, responseBody, e_1;
323
+ var payload, options, server_url, res, responseBody, e_1;
314
324
  return tslib_1.__generator(this, function (_a) {
315
325
  switch (_a.label) {
316
326
  case 0:
@@ -336,11 +346,12 @@ var SessionReplay = /** @class */ (function () {
336
346
  body: JSON.stringify(payload),
337
347
  method: 'POST',
338
348
  };
339
- return [4 /*yield*/, fetch(constants_1.SESSION_REPLAY_SERVER_URL, options)];
349
+ server_url = this.getServerUrl();
350
+ return [4 /*yield*/, fetch(server_url, options)];
340
351
  case 2:
341
352
  res = _a.sent();
342
353
  if (res === null) {
343
- this.completeRequest({ context: context, err: messages_1.UNEXPECTED_ERROR_MESSAGE, removeEvents: false });
354
+ this.completeRequest({ context: context, err: messages_1.UNEXPECTED_ERROR_MESSAGE });
344
355
  return [2 /*return*/];
345
356
  }
346
357
  if (!useRetry) {
@@ -359,7 +370,7 @@ var SessionReplay = /** @class */ (function () {
359
370
  return [3 /*break*/, 4];
360
371
  case 3:
361
372
  e_1 = _a.sent();
362
- this.completeRequest({ context: context, err: e_1, removeEvents: false });
373
+ this.completeRequest({ context: context, err: e_1 });
363
374
  return [3 /*break*/, 4];
364
375
  case 4: return [2 /*return*/];
365
376
  }
@@ -473,6 +484,7 @@ var SessionReplay = /** @class */ (function () {
473
484
  }
474
485
  sequenceToUpdate.events = [];
475
486
  sequenceToUpdate.status = session_replay_1.RecordingStatus.SENT;
487
+ // Delete sent sequences for current session
476
488
  Object.entries(session.sessionSequences).forEach(function (_a) {
477
489
  var _b = tslib_1.__read(_a, 2), storedSeqId = _b[0], sequence = _b[1];
478
490
  var numericStoredSeqId = parseInt(storedSeqId, 10);
@@ -480,6 +492,13 @@ var SessionReplay = /** @class */ (function () {
480
492
  delete session.sessionSequences[numericStoredSeqId];
481
493
  }
482
494
  });
495
+ // Delete any sessions that are older than 3 days
496
+ Object.keys(sessionMap).forEach(function (sessionId) {
497
+ var numericSessionId = parseInt(sessionId, 10);
498
+ if (Date.now() - numericSessionId >= constants_1.MAX_IDB_STORAGE_LENGTH) {
499
+ delete sessionMap[numericSessionId];
500
+ }
501
+ });
483
502
  return sessionMap;
484
503
  })];
485
504
  case 1:
@@ -495,8 +514,8 @@ var SessionReplay = /** @class */ (function () {
495
514
  });
496
515
  };
497
516
  SessionReplay.prototype.completeRequest = function (_a) {
498
- var context = _a.context, err = _a.err, success = _a.success, _b = _a.removeEvents, removeEvents = _b === void 0 ? true : _b;
499
- removeEvents && context.sessionId && this.cleanUpSessionEventsStore(context.sessionId, context.sequenceId);
517
+ var context = _a.context, err = _a.err, success = _a.success;
518
+ context.sessionId && this.cleanUpSessionEventsStore(context.sessionId, context.sequenceId);
500
519
  if (err) {
501
520
  this.config.loggerProvider.error(err);
502
521
  }
@@ -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 { 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 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 if (GlobalScope && GlobalScope.document && GlobalScope.document.hasFocus()) {\n await this.initialize(true);\n }\n }\n\n async execute(event: Event) {\n const GlobalScope = getGlobalScope();\n if (GlobalScope && GlobalScope.document && !GlobalScope.document.hasFocus()) {\n return Promise.resolve(event);\n }\n\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
+ {"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, ServerZone, 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_IDB_STORAGE_LENGTH,\n MAX_INTERVAL,\n MIN_INTERVAL,\n SESSION_REPLAY_SERVER_URL,\n STORAGE_PREFIX,\n defaultSessionStore,\n SESSION_REPLAY_EU_URL as SESSION_REPLAY_EU_SERVER_URL,\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 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 if (GlobalScope && GlobalScope.document && GlobalScope.document.hasFocus()) {\n await this.initialize(true);\n }\n }\n\n async execute(event: Event) {\n const GlobalScope = getGlobalScope();\n if (GlobalScope && GlobalScope.document && !GlobalScope.document.hasFocus()) {\n return Promise.resolve(event);\n }\n\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 // This resolves a timing issue when focus is fired multiple times in short succession,\n // we only want the rest of this function to run once. We can be sure that initialize has\n // already been called if this.stopRecordingEvents is defined\n if (this.stopRecordingEvents) {\n return;\n }\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\n this.recordEvents();\n }\n\n setShouldRecord(sessionStore?: IDBStoreSession) {\n if (sessionStore && typeof sessionStore.shouldRecord === 'boolean') {\n this.shouldRecord = sessionStore.shouldRecord;\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 getServerUrl() {\n if (this.config.serverZone === ServerZone.EU) {\n return SESSION_REPLAY_EU_SERVER_URL;\n }\n return SESSION_REPLAY_SERVER_URL;\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 server_url = this.getServerUrl();\n const res = await fetch(server_url, options);\n if (res === null) {\n this.completeRequest({ context, err: UNEXPECTED_ERROR_MESSAGE });\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 });\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 // Delete sent sequences for current session\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 // Delete any sessions that are older than 3 days\n Object.keys(sessionMap).forEach((sessionId: string) => {\n const numericSessionId = parseInt(sessionId, 10);\n if (Date.now() - numericSessionId >= MAX_IDB_STORAGE_LENGTH) {\n delete sessionMap[numericSessionId];\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({ context, err, success }: { context: SessionReplayContext; err?: string; success?: string }) {\n 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"]}
@@ -7,9 +7,11 @@ export declare const BLOCK_CLASS = "amp-block";
7
7
  export declare const MASK_TEXT_CLASS = "amp-mask";
8
8
  export declare const UNMASK_TEXT_CLASS = "amp-unmask";
9
9
  export declare const SESSION_REPLAY_SERVER_URL = "https://api-secure.amplitude.com/sessions/track";
10
+ export declare const SESSION_REPLAY_EU_URL = "https://api.eu.amplitude.com/sessions/track";
10
11
  export declare const STORAGE_PREFIX: string;
11
12
  export declare const MAX_EVENT_LIST_SIZE_IN_BYTES: number;
12
13
  export declare const MIN_INTERVAL = 500;
13
14
  export declare const MAX_INTERVAL: number;
14
15
  export declare const defaultSessionStore: IDBStoreSession;
16
+ export declare const MAX_IDB_STORAGE_LENGTH: number;
15
17
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
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"}
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,qBAAqB,gDAAgD,CAAC;AACnF,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;AACF,eAAO,MAAM,sBAAsB,QAA0B,CAAC"}
@@ -7,6 +7,7 @@ export var BLOCK_CLASS = 'amp-block';
7
7
  export var MASK_TEXT_CLASS = 'amp-mask';
8
8
  export var UNMASK_TEXT_CLASS = 'amp-unmask';
9
9
  export var SESSION_REPLAY_SERVER_URL = 'https://api-secure.amplitude.com/sessions/track';
10
+ export var SESSION_REPLAY_EU_URL = 'https://api.eu.amplitude.com/sessions/track';
10
11
  export var STORAGE_PREFIX = "".concat(AMPLITUDE_PREFIX, "_replay_unsent");
11
12
  var PAYLOAD_ESTIMATED_SIZE_IN_BYTES_WITHOUT_EVENTS = 500; // derived by JSON stringifying an example payload without events
12
13
  export var MAX_EVENT_LIST_SIZE_IN_BYTES = 10 * 1000000 - PAYLOAD_ESTIMATED_SIZE_IN_BYTES_WITHOUT_EVENTS;
@@ -17,4 +18,5 @@ export var defaultSessionStore = {
17
18
  currentSequenceId: 0,
18
19
  sessionSequences: {},
19
20
  };
21
+ export var MAX_IDB_STORAGE_LENGTH = 1000 * 60 * 60 * 24 * 3; // 3 days
20
22
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAG7D,MAAM,CAAC,IAAM,6BAA6B,GAAG,aAAa,CAAC;AAE3D,MAAM,CAAC,IAAM,+BAA+B,GAAG,UAAG,6BAA6B,sBAAmB,CAAC;AACnG,MAAM,CAAC,IAAM,2BAA2B,GAAG,eAAe,CAAC;AAC3D,MAAM,CAAC,IAAM,yBAAyB,GAAG,aAAa,CAAC;AAEvD,MAAM,CAAC,IAAM,WAAW,GAAG,WAAW,CAAC;AACvC,MAAM,CAAC,IAAM,eAAe,GAAG,UAAU,CAAC;AAC1C,MAAM,CAAC,IAAM,iBAAiB,GAAG,YAAY,CAAC;AAC9C,MAAM,CAAC,IAAM,yBAAyB,GAAG,iDAAiD,CAAC;AAC3F,MAAM,CAAC,IAAM,cAAc,GAAG,UAAG,gBAAgB,mBAAgB,CAAC;AAClE,IAAM,8CAA8C,GAAG,GAAG,CAAC,CAAC,iEAAiE;AAC7H,MAAM,CAAC,IAAM,4BAA4B,GAAG,EAAE,GAAG,OAAO,GAAG,8CAA8C,CAAC;AAC1G,MAAM,CAAC,IAAM,YAAY,GAAG,GAAG,CAAC,CAAC,SAAS;AAC1C,MAAM,CAAC,IAAM,YAAY,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,aAAa;AACpD,MAAM,CAAC,IAAM,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"]}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAG7D,MAAM,CAAC,IAAM,6BAA6B,GAAG,aAAa,CAAC;AAE3D,MAAM,CAAC,IAAM,+BAA+B,GAAG,UAAG,6BAA6B,sBAAmB,CAAC;AACnG,MAAM,CAAC,IAAM,2BAA2B,GAAG,eAAe,CAAC;AAC3D,MAAM,CAAC,IAAM,yBAAyB,GAAG,aAAa,CAAC;AAEvD,MAAM,CAAC,IAAM,WAAW,GAAG,WAAW,CAAC;AACvC,MAAM,CAAC,IAAM,eAAe,GAAG,UAAU,CAAC;AAC1C,MAAM,CAAC,IAAM,iBAAiB,GAAG,YAAY,CAAC;AAC9C,MAAM,CAAC,IAAM,yBAAyB,GAAG,iDAAiD,CAAC;AAC3F,MAAM,CAAC,IAAM,qBAAqB,GAAG,6CAA6C,CAAC;AACnF,MAAM,CAAC,IAAM,cAAc,GAAG,UAAG,gBAAgB,mBAAgB,CAAC;AAClE,IAAM,8CAA8C,GAAG,GAAG,CAAC,CAAC,iEAAiE;AAC7H,MAAM,CAAC,IAAM,4BAA4B,GAAG,EAAE,GAAG,OAAO,GAAG,8CAA8C,CAAC;AAC1G,MAAM,CAAC,IAAM,YAAY,GAAG,GAAG,CAAC,CAAC,SAAS;AAC1C,MAAM,CAAC,IAAM,YAAY,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,aAAa;AACpD,MAAM,CAAC,IAAM,mBAAmB,GAAoB;IAClD,YAAY,EAAE,IAAI;IAClB,iBAAiB,EAAE,CAAC;IACpB,gBAAgB,EAAE,EAAE;CACrB,CAAC;AACF,MAAM,CAAC,IAAM,sBAAsB,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS","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 SESSION_REPLAY_EU_URL = 'https://api.eu.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};\nexport const MAX_IDB_STORAGE_LENGTH = 1000 * 60 * 60 * 24 * 3; // 3 days\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"AAoBA,OAAO,EAQL,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AAsblC,eAAO,MAAM,mBAAmB,EAAE,mBAEjC,CAAC"}
1
+ {"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"AAsBA,OAAO,EAQL,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AAkclC,eAAO,MAAM,mBAAmB,EAAE,mBAEjC,CAAC"}
@@ -1,10 +1,10 @@
1
1
  import { __assign, __awaiter, __generator, __read } from "tslib";
2
2
  import { getGlobalScope } from '@amplitude/analytics-client-common';
3
3
  import { BaseTransport } from '@amplitude/analytics-core';
4
- import { Status } from '@amplitude/analytics-types';
4
+ import { ServerZone, Status } from '@amplitude/analytics-types';
5
5
  import * as IDBKeyVal from 'idb-keyval';
6
6
  import { pack, record } from 'rrweb';
7
- import { BLOCK_CLASS, DEFAULT_SESSION_END_EVENT, DEFAULT_SESSION_REPLAY_PROPERTY, DEFAULT_SESSION_START_EVENT, MASK_TEXT_CLASS, MAX_EVENT_LIST_SIZE_IN_BYTES, MAX_INTERVAL, MIN_INTERVAL, SESSION_REPLAY_SERVER_URL, STORAGE_PREFIX, defaultSessionStore, } from './constants';
7
+ import { BLOCK_CLASS, DEFAULT_SESSION_END_EVENT, DEFAULT_SESSION_REPLAY_PROPERTY, DEFAULT_SESSION_START_EVENT, MASK_TEXT_CLASS, MAX_EVENT_LIST_SIZE_IN_BYTES, MAX_IDB_STORAGE_LENGTH, MAX_INTERVAL, MIN_INTERVAL, SESSION_REPLAY_SERVER_URL, STORAGE_PREFIX, defaultSessionStore, SESSION_REPLAY_EU_URL as SESSION_REPLAY_EU_SERVER_URL, } from './constants';
8
8
  import { maskInputFn } from './helpers';
9
9
  import { MAX_RETRIES_EXCEEDED_MESSAGE, STORAGE_FAILURE, UNEXPECTED_ERROR_MESSAGE, getSuccessMessage } from './messages';
10
10
  import { RecordingStatus, } from './typings/session-replay';
@@ -136,6 +136,12 @@ var SessionReplay = /** @class */ (function () {
136
136
  return [4 /*yield*/, this.getAllSessionEventsFromStore()];
137
137
  case 1:
138
138
  storedReplaySessions = _a.sent();
139
+ // This resolves a timing issue when focus is fired multiple times in short succession,
140
+ // we only want the rest of this function to run once. We can be sure that initialize has
141
+ // already been called if this.stopRecordingEvents is defined
142
+ if (this.stopRecordingEvents) {
143
+ return [2 /*return*/];
144
+ }
139
145
  storedSequencesForSession = storedReplaySessions && storedReplaySessions[this.config.sessionId];
140
146
  if (storedReplaySessions && storedSequencesForSession && storedSequencesForSession.sessionSequences) {
141
147
  storedSeqId = storedSequencesForSession.currentSequenceId;
@@ -154,17 +160,15 @@ var SessionReplay = /** @class */ (function () {
154
160
  if (shouldSendStoredEvents && storedReplaySessions) {
155
161
  this.sendStoredEvents(storedReplaySessions);
156
162
  }
157
- if (!this.stopRecordingEvents) {
158
- this.recordEvents();
159
- }
163
+ this.recordEvents();
160
164
  return [2 /*return*/];
161
165
  }
162
166
  });
163
167
  });
164
168
  };
165
169
  SessionReplay.prototype.setShouldRecord = function (sessionStore) {
166
- if ((sessionStore === null || sessionStore === void 0 ? void 0 : sessionStore.shouldRecord) === false) {
167
- this.shouldRecord = false;
170
+ if (sessionStore && typeof sessionStore.shouldRecord === 'boolean') {
171
+ this.shouldRecord = sessionStore.shouldRecord;
168
172
  }
169
173
  else if (this.config.optOut) {
170
174
  this.shouldRecord = false;
@@ -305,10 +309,16 @@ var SessionReplay = /** @class */ (function () {
305
309
  });
306
310
  });
307
311
  };
312
+ SessionReplay.prototype.getServerUrl = function () {
313
+ if (this.config.serverZone === ServerZone.EU) {
314
+ return SESSION_REPLAY_EU_SERVER_URL;
315
+ }
316
+ return SESSION_REPLAY_SERVER_URL;
317
+ };
308
318
  SessionReplay.prototype.send = function (context, useRetry) {
309
319
  if (useRetry === void 0) { useRetry = true; }
310
320
  return __awaiter(this, void 0, void 0, function () {
311
- var payload, options, res, responseBody, e_1;
321
+ var payload, options, server_url, res, responseBody, e_1;
312
322
  return __generator(this, function (_a) {
313
323
  switch (_a.label) {
314
324
  case 0:
@@ -334,11 +344,12 @@ var SessionReplay = /** @class */ (function () {
334
344
  body: JSON.stringify(payload),
335
345
  method: 'POST',
336
346
  };
337
- return [4 /*yield*/, fetch(SESSION_REPLAY_SERVER_URL, options)];
347
+ server_url = this.getServerUrl();
348
+ return [4 /*yield*/, fetch(server_url, options)];
338
349
  case 2:
339
350
  res = _a.sent();
340
351
  if (res === null) {
341
- this.completeRequest({ context: context, err: UNEXPECTED_ERROR_MESSAGE, removeEvents: false });
352
+ this.completeRequest({ context: context, err: UNEXPECTED_ERROR_MESSAGE });
342
353
  return [2 /*return*/];
343
354
  }
344
355
  if (!useRetry) {
@@ -357,7 +368,7 @@ var SessionReplay = /** @class */ (function () {
357
368
  return [3 /*break*/, 4];
358
369
  case 3:
359
370
  e_1 = _a.sent();
360
- this.completeRequest({ context: context, err: e_1, removeEvents: false });
371
+ this.completeRequest({ context: context, err: e_1 });
361
372
  return [3 /*break*/, 4];
362
373
  case 4: return [2 /*return*/];
363
374
  }
@@ -471,6 +482,7 @@ var SessionReplay = /** @class */ (function () {
471
482
  }
472
483
  sequenceToUpdate.events = [];
473
484
  sequenceToUpdate.status = RecordingStatus.SENT;
485
+ // Delete sent sequences for current session
474
486
  Object.entries(session.sessionSequences).forEach(function (_a) {
475
487
  var _b = __read(_a, 2), storedSeqId = _b[0], sequence = _b[1];
476
488
  var numericStoredSeqId = parseInt(storedSeqId, 10);
@@ -478,6 +490,13 @@ var SessionReplay = /** @class */ (function () {
478
490
  delete session.sessionSequences[numericStoredSeqId];
479
491
  }
480
492
  });
493
+ // Delete any sessions that are older than 3 days
494
+ Object.keys(sessionMap).forEach(function (sessionId) {
495
+ var numericSessionId = parseInt(sessionId, 10);
496
+ if (Date.now() - numericSessionId >= MAX_IDB_STORAGE_LENGTH) {
497
+ delete sessionMap[numericSessionId];
498
+ }
499
+ });
481
500
  return sessionMap;
482
501
  })];
483
502
  case 1:
@@ -493,8 +512,8 @@ var SessionReplay = /** @class */ (function () {
493
512
  });
494
513
  };
495
514
  SessionReplay.prototype.completeRequest = function (_a) {
496
- var context = _a.context, err = _a.err, success = _a.success, _b = _a.removeEvents, removeEvents = _b === void 0 ? true : _b;
497
- removeEvents && context.sessionId && this.cleanUpSessionEventsStore(context.sessionId, context.sequenceId);
515
+ var context = _a.context, err = _a.err, success = _a.success;
516
+ context.sessionId && this.cleanUpSessionEventsStore(context.sessionId, context.sequenceId);
498
517
  if (err) {
499
518
  this.config.loggerProvider.error(err);
500
519
  }