@amplitude/session-replay-browser
Advanced tools
Comparing version 1.14.3 to 1.15.0
import { FetchTransport } from '@amplitude/analytics-client-common'; | ||
import { Config, Logger } from '@amplitude/analytics-core'; | ||
import { LogLevel } from '@amplitude/analytics-types'; | ||
import { SessionReplayOptions } from '../typings/session-replay'; | ||
import { SessionReplayOptions, StoreType } from '../typings/session-replay'; | ||
import { SessionReplayLocalConfig as ISessionReplayLocalConfig, InteractionConfig, PrivacyConfig, SessionReplayPerformanceConfig, SessionReplayVersion } from './types'; | ||
@@ -21,2 +21,3 @@ export declare const getDefaultConfig: () => { | ||
version?: SessionReplayVersion; | ||
storeType: StoreType; | ||
performanceConfig?: SessionReplayPerformanceConfig; | ||
@@ -23,0 +24,0 @@ constructor(apiKey: string, options: SessionReplayOptions); |
@@ -19,2 +19,3 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
var _this = this; | ||
var _a; | ||
var defaultConfig = (0, exports.getDefaultConfig)(); | ||
@@ -33,2 +34,3 @@ _this = _super.call(this, tslib_1.__assign(tslib_1.__assign({ transportProvider: defaultConfig.transportProvider }, options), { apiKey: apiKey })) || this; | ||
_this.performanceConfig = options.performanceConfig; | ||
_this.storeType = (_a = options.storeType) !== null && _a !== void 0 ? _a : 'idb'; | ||
if (options.privacyConfig) { | ||
@@ -35,0 +37,0 @@ _this.privacyConfig = options.privacyConfig; |
import { Config, LogLevel, Logger } from '@amplitude/analytics-types'; | ||
import { StoreType } from '../typings/session-replay'; | ||
export interface SamplingConfig { | ||
@@ -41,2 +42,3 @@ sample_rate: number; | ||
performanceConfig?: SessionReplayPerformanceConfig; | ||
storeType: StoreType; | ||
} | ||
@@ -43,0 +45,0 @@ export interface SessionReplayJoinedConfig extends SessionReplayLocalConfig { |
@@ -1,4 +0,4 @@ | ||
import { Logger as ILogger } from '@amplitude/analytics-types'; | ||
import { DBSchema, IDBPDatabase } from 'idb'; | ||
import { SessionReplayEventsIDBStore as AmplitudeSessionReplayEventsIDBStore, EventType, Events, SendingSequencesIDBInput } from '../typings/session-replay'; | ||
import { EventType, Events, SendingSequencesReturn } from '../typings/session-replay'; | ||
import { BaseEventsStore, InstanceArgs as BaseInstanceArgs } from './base-events-store'; | ||
export declare const currentSequenceKey = "sessionCurrentSequence"; | ||
@@ -10,10 +10,7 @@ export declare const sequencesToSendKey = "sequencesToSend"; | ||
key: number; | ||
value: { | ||
sessionId: number; | ||
events: Events; | ||
}; | ||
value: Omit<SendingSequencesReturn<number>, 'sequenceId'>; | ||
}; | ||
sequencesToSend: { | ||
key: number; | ||
value: SendingSequencesIDBInput; | ||
value: Omit<SendingSequencesReturn<number>, 'sequenceId'>; | ||
indexes: { | ||
@@ -30,27 +27,13 @@ sessionId: number; | ||
export declare const createStore: (dbName: string) => Promise<IDBPDatabase<SessionReplayDB>>; | ||
export declare class SessionReplayEventsIDBStore implements AmplitudeSessionReplayEventsIDBStore { | ||
type InstanceArgs = { | ||
apiKey: string; | ||
db: IDBPDatabase<SessionReplayDB> | undefined; | ||
loggerProvider: ILogger; | ||
storageKey: string; | ||
maxPersistedEventsSize: number; | ||
interval: number; | ||
timeAtLastSplit: number | null; | ||
private readonly minInterval; | ||
private readonly maxInterval; | ||
constructor({ loggerProvider, apiKey, minInterval, maxInterval, }: { | ||
loggerProvider: ILogger; | ||
apiKey: string; | ||
minInterval?: number; | ||
maxInterval?: number; | ||
}); | ||
initialize(type: EventType, sessionId?: number): Promise<void>; | ||
/** | ||
* Determines whether to send the events list to the backend and start a new | ||
* empty events list, based on the size of the list as well as the last time sent | ||
* @param nextEventString | ||
* @returns boolean | ||
*/ | ||
shouldSplitEventsList: (events: Events, nextEventString: string) => boolean; | ||
getSequencesToSend: () => Promise<Required<SendingSequencesIDBInput>[] | undefined>; | ||
db: IDBPDatabase<SessionReplayDB>; | ||
} & BaseInstanceArgs; | ||
export declare class SessionReplayEventsIDBStore extends BaseEventsStore<number> { | ||
private readonly apiKey; | ||
private readonly db; | ||
constructor(args: InstanceArgs); | ||
static new(type: EventType, args: Omit<InstanceArgs, 'db'>, sessionId?: number): Promise<SessionReplayEventsIDBStore | undefined>; | ||
getCurrentSequenceEvents(sessionId?: number): Promise<Omit<SendingSequencesReturn<number>, "sequenceId">[] | undefined>; | ||
getSequencesToSend: () => Promise<SendingSequencesReturn<number>[] | undefined>; | ||
storeCurrentSequence: (sessionId: number) => Promise<{ | ||
@@ -67,13 +50,6 @@ sessionId: number; | ||
storeSendingEvents: (sessionId: number, events: Events) => Promise<number | undefined>; | ||
cleanUpSessionEventsStore: (sequenceId: number) => Promise<void>; | ||
cleanUpSessionEventsStore: (_sessionId: number, sequenceId?: number) => Promise<void>; | ||
transitionFromKeyValStore: (sessionId?: number) => Promise<void>; | ||
} | ||
export declare const createEventsIDBStore: ({ loggerProvider, apiKey, sessionId, type, minInterval, maxInterval, }: { | ||
loggerProvider: ILogger; | ||
apiKey: string; | ||
type: EventType; | ||
minInterval?: number | undefined; | ||
maxInterval?: number | undefined; | ||
sessionId?: number | undefined; | ||
}) => Promise<SessionReplayEventsIDBStore>; | ||
export {}; | ||
//# sourceMappingURL=events-idb-store.d.ts.map |
var _this = this; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.createEventsIDBStore = exports.SessionReplayEventsIDBStore = exports.createStore = exports.defineObjectStores = exports.keyValDatabaseExists = exports.remoteConfigKey = exports.sequencesToSendKey = exports.currentSequenceKey = void 0; | ||
exports.SessionReplayEventsIDBStore = exports.createStore = exports.defineObjectStores = exports.keyValDatabaseExists = exports.remoteConfigKey = exports.sequencesToSendKey = exports.currentSequenceKey = void 0; | ||
var tslib_1 = require("tslib"); | ||
@@ -8,4 +8,4 @@ var analytics_client_common_1 = require("@amplitude/analytics-client-common"); | ||
var idb_1 = require("idb"); | ||
var constants_1 = require("../constants"); | ||
var messages_1 = require("../messages"); | ||
var base_events_store_1 = require("./base-events-store"); | ||
var legacy_idb_types_1 = require("./legacy-idb-types"); | ||
@@ -92,51 +92,39 @@ exports.currentSequenceKey = 'sessionCurrentSequence'; | ||
exports.createStore = createStore; | ||
var SessionReplayEventsIDBStore = /** @class */ (function () { | ||
function SessionReplayEventsIDBStore(_a) { | ||
var loggerProvider = _a.loggerProvider, apiKey = _a.apiKey, minInterval = _a.minInterval, maxInterval = _a.maxInterval; | ||
var _this = this; | ||
this.storageKey = ''; | ||
this.maxPersistedEventsSize = constants_1.MAX_EVENT_LIST_SIZE_IN_BYTES; | ||
this.timeAtLastSplit = null; | ||
/** | ||
* Determines whether to send the events list to the backend and start a new | ||
* empty events list, based on the size of the list as well as the last time sent | ||
* @param nextEventString | ||
* @returns boolean | ||
*/ | ||
this.shouldSplitEventsList = function (events, nextEventString) { | ||
var sizeOfNextEvent = new Blob([nextEventString]).size; | ||
var sizeOfEventsList = new Blob(events).size; | ||
if (sizeOfEventsList + sizeOfNextEvent >= _this.maxPersistedEventsSize) { | ||
return true; | ||
} | ||
if (_this.timeAtLastSplit !== null && | ||
_this.interval && | ||
Date.now() - _this.timeAtLastSplit > _this.interval && | ||
events.length) { | ||
_this.interval = Math.min(_this.maxInterval, _this.interval + _this.minInterval); | ||
_this.timeAtLastSplit = Date.now(); | ||
return true; | ||
} | ||
return false; | ||
}; | ||
this.getSequencesToSend = function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var sequencesToSend, e_1; | ||
var _a; | ||
var SessionReplayEventsIDBStore = /** @class */ (function (_super) { | ||
tslib_1.__extends(SessionReplayEventsIDBStore, _super); | ||
function SessionReplayEventsIDBStore(args) { | ||
var _this = _super.call(this, args) || this; | ||
_this.getSequencesToSend = function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var sequences, cursor, _a, sessionId, events, e_1; | ||
return tslib_1.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
_b.trys.push([0, 2, , 3]); | ||
return [4 /*yield*/, ((_a = this.db) === null || _a === void 0 ? void 0 : _a.getAll(exports.sequencesToSendKey))]; | ||
_b.trys.push([0, 5, , 6]); | ||
sequences = []; | ||
return [4 /*yield*/, this.db.transaction('sequencesToSend').store.openCursor()]; | ||
case 1: | ||
sequencesToSend = (_b.sent()); | ||
return [2 /*return*/, sequencesToSend]; | ||
cursor = _b.sent(); | ||
_b.label = 2; | ||
case 2: | ||
if (!cursor) return [3 /*break*/, 4]; | ||
_a = cursor.value, sessionId = _a.sessionId, events = _a.events; | ||
sequences.push({ | ||
events: events, | ||
sequenceId: cursor.key, | ||
sessionId: sessionId, | ||
}); | ||
return [4 /*yield*/, cursor.continue()]; | ||
case 3: | ||
cursor = _b.sent(); | ||
return [3 /*break*/, 2]; | ||
case 4: return [2 /*return*/, sequences]; | ||
case 5: | ||
e_1 = _b.sent(); | ||
this.loggerProvider.warn("".concat(messages_1.STORAGE_FAILURE, ": ").concat(e_1)); | ||
return [3 /*break*/, 3]; | ||
case 3: return [2 /*return*/, undefined]; | ||
return [3 /*break*/, 6]; | ||
case 6: return [2 /*return*/, undefined]; | ||
} | ||
}); | ||
}); }; | ||
this.storeCurrentSequence = function (sessionId) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
_this.storeCurrentSequence = function (sessionId) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var currentSequenceData, sequenceId, e_2; | ||
@@ -147,5 +135,2 @@ return tslib_1.__generator(this, function (_a) { | ||
_a.trys.push([0, 4, , 5]); | ||
if (!this.db) { | ||
return [2 /*return*/, undefined]; | ||
} | ||
return [4 /*yield*/, this.db.get(exports.currentSequenceKey, sessionId)]; | ||
@@ -175,45 +160,36 @@ case 1: | ||
}); }; | ||
this.addEventToCurrentSequence = function (sessionId, event) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
_this.addEventToCurrentSequence = function (sessionId, event) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var tx, sequenceEvents, eventsToSend, updatedEvents, sequenceId, e_3; | ||
var _a; | ||
return tslib_1.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
if (this.interval === 0) { | ||
this.interval = this.minInterval; | ||
} | ||
_b.label = 1; | ||
_a.trys.push([0, 10, , 11]); | ||
tx = this.db.transaction(exports.currentSequenceKey, 'readwrite'); | ||
return [4 /*yield*/, tx.store.get(sessionId)]; | ||
case 1: | ||
_b.trys.push([1, 11, , 12]); | ||
tx = (_a = this.db) === null || _a === void 0 ? void 0 : _a.transaction(exports.currentSequenceKey, 'readwrite'); | ||
if (!tx) { | ||
return [2 /*return*/]; | ||
} | ||
return [4 /*yield*/, tx.store.get(sessionId)]; | ||
sequenceEvents = _a.sent(); | ||
if (!!sequenceEvents) return [3 /*break*/, 3]; | ||
return [4 /*yield*/, tx.store.put({ sessionId: sessionId, events: [event] })]; | ||
case 2: | ||
sequenceEvents = _b.sent(); | ||
if (!!sequenceEvents) return [3 /*break*/, 4]; | ||
return [4 /*yield*/, tx.store.put({ sessionId: sessionId, events: [event] })]; | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
case 3: | ||
_b.sent(); | ||
return [2 /*return*/]; | ||
case 4: | ||
eventsToSend = void 0; | ||
if (!this.shouldSplitEventsList(sequenceEvents.events, event)) return [3 /*break*/, 6]; | ||
if (!this.shouldSplitEventsList(sequenceEvents.events, event)) return [3 /*break*/, 5]; | ||
eventsToSend = sequenceEvents.events; | ||
// set store to empty array | ||
return [4 /*yield*/, tx.store.put({ sessionId: sessionId, events: [event] })]; | ||
case 4: | ||
// set store to empty array | ||
_a.sent(); | ||
return [3 /*break*/, 7]; | ||
case 5: | ||
// set store to empty array | ||
_b.sent(); | ||
return [3 /*break*/, 8]; | ||
case 6: | ||
updatedEvents = sequenceEvents.events.concat(event); | ||
return [4 /*yield*/, tx.store.put({ sessionId: sessionId, events: updatedEvents })]; | ||
case 7: | ||
_b.sent(); | ||
_b.label = 8; | ||
case 8: return [4 /*yield*/, tx.done]; | ||
case 9: | ||
_b.sent(); | ||
case 6: | ||
_a.sent(); | ||
_a.label = 7; | ||
case 7: return [4 /*yield*/, tx.done]; | ||
case 8: | ||
_a.sent(); | ||
if (!eventsToSend) { | ||
@@ -223,4 +199,4 @@ return [2 /*return*/, undefined]; | ||
return [4 /*yield*/, this.storeSendingEvents(sessionId, eventsToSend)]; | ||
case 10: | ||
sequenceId = _b.sent(); | ||
case 9: | ||
sequenceId = _a.sent(); | ||
if (!sequenceId) { | ||
@@ -234,26 +210,25 @@ return [2 /*return*/, undefined]; | ||
}]; | ||
case 11: | ||
e_3 = _b.sent(); | ||
case 10: | ||
e_3 = _a.sent(); | ||
this.loggerProvider.warn("".concat(messages_1.STORAGE_FAILURE, ": ").concat(e_3)); | ||
return [3 /*break*/, 12]; | ||
case 12: return [2 /*return*/, undefined]; | ||
return [3 /*break*/, 11]; | ||
case 11: return [2 /*return*/, undefined]; | ||
} | ||
}); | ||
}); }; | ||
this.storeSendingEvents = function (sessionId, events) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
_this.storeSendingEvents = function (sessionId, events) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var sequenceId, e_4; | ||
var _a; | ||
return tslib_1.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
_b.trys.push([0, 2, , 3]); | ||
return [4 /*yield*/, ((_a = this.db) === null || _a === void 0 ? void 0 : _a.put(exports.sequencesToSendKey, { | ||
_a.trys.push([0, 2, , 3]); | ||
return [4 /*yield*/, this.db.put(exports.sequencesToSendKey, { | ||
sessionId: sessionId, | ||
events: events, | ||
}))]; | ||
})]; | ||
case 1: | ||
sequenceId = _b.sent(); | ||
sequenceId = _a.sent(); | ||
return [2 /*return*/, sequenceId]; | ||
case 2: | ||
e_4 = _b.sent(); | ||
e_4 = _a.sent(); | ||
this.loggerProvider.warn("".concat(messages_1.STORAGE_FAILURE, ": ").concat(e_4)); | ||
@@ -265,22 +240,26 @@ return [3 /*break*/, 3]; | ||
}); }; | ||
this.cleanUpSessionEventsStore = function (sequenceId) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
_this.cleanUpSessionEventsStore = function (_sessionId, sequenceId) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var e_5; | ||
var _a; | ||
return tslib_1.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
_b.trys.push([0, 2, , 3]); | ||
return [4 /*yield*/, ((_a = this.db) === null || _a === void 0 ? void 0 : _a.delete(exports.sequencesToSendKey, sequenceId))]; | ||
if (!sequenceId) { | ||
return [2 /*return*/]; | ||
} | ||
_a.label = 1; | ||
case 1: | ||
_b.sent(); | ||
return [3 /*break*/, 3]; | ||
_a.trys.push([1, 3, , 4]); | ||
return [4 /*yield*/, this.db.delete(exports.sequencesToSendKey, sequenceId)]; | ||
case 2: | ||
e_5 = _b.sent(); | ||
_a.sent(); | ||
return [3 /*break*/, 4]; | ||
case 3: | ||
e_5 = _a.sent(); | ||
this.loggerProvider.warn("".concat(messages_1.STORAGE_FAILURE, ": ").concat(e_5)); | ||
return [3 /*break*/, 3]; | ||
case 3: return [2 /*return*/]; | ||
return [3 /*break*/, 4]; | ||
case 4: return [2 /*return*/]; | ||
} | ||
}); | ||
}); }; | ||
this.transitionFromKeyValStore = function (sessionId) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
_this.transitionFromKeyValStore = function (sessionId) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var keyValDb, transitionCurrentSessionSequences_1, storageKey, getAllRequest_1, transitionPromise, globalScope, e_6, e_7; | ||
@@ -390,29 +369,26 @@ var _this = this; | ||
}); }; | ||
this.loggerProvider = loggerProvider; | ||
this.apiKey = apiKey; | ||
this.maxInterval = maxInterval !== null && maxInterval !== void 0 ? maxInterval : constants_1.MAX_INTERVAL; | ||
this.minInterval = minInterval !== null && minInterval !== void 0 ? minInterval : constants_1.MIN_INTERVAL; | ||
this.interval = 0; | ||
_this.apiKey = args.apiKey; | ||
_this.db = args.db; | ||
return _this; | ||
} | ||
SessionReplayEventsIDBStore.prototype.initialize = function (type, sessionId) { | ||
SessionReplayEventsIDBStore.new = function (type, args, sessionId) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var dbSuffix, dbName, _a, e_8; | ||
return tslib_1.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
var dbSuffix, dbName, db, eventsIDBStore, e_8; | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
_b.trys.push([0, 3, , 4]); | ||
_a.trys.push([0, 3, , 4]); | ||
dbSuffix = type === 'replay' ? '' : "_".concat(type); | ||
dbName = "".concat(this.apiKey.substring(0, 10), "_amp_session_replay_events").concat(dbSuffix); | ||
_a = this; | ||
dbName = "".concat(args.apiKey.substring(0, 10), "_amp_session_replay_events").concat(dbSuffix); | ||
return [4 /*yield*/, (0, exports.createStore)(dbName)]; | ||
case 1: | ||
_a.db = _b.sent(); | ||
this.timeAtLastSplit = Date.now(); // Initialize this so we have a point of comparison when events are recorded | ||
return [4 /*yield*/, this.transitionFromKeyValStore(sessionId)]; | ||
db = _a.sent(); | ||
eventsIDBStore = new SessionReplayEventsIDBStore(tslib_1.__assign(tslib_1.__assign({}, args), { db: db })); | ||
return [4 /*yield*/, eventsIDBStore.transitionFromKeyValStore(sessionId)]; | ||
case 2: | ||
_b.sent(); | ||
return [3 /*break*/, 4]; | ||
_a.sent(); | ||
return [2 /*return*/, eventsIDBStore]; | ||
case 3: | ||
e_8 = _b.sent(); | ||
this.loggerProvider.warn("".concat(messages_1.STORAGE_FAILURE, ": ").concat(e_8)); | ||
e_8 = _a.sent(); | ||
args.loggerProvider.warn("".concat(messages_1.STORAGE_FAILURE, ": ").concat(e_8)); | ||
return [3 /*break*/, 4]; | ||
@@ -424,22 +400,53 @@ case 4: return [2 /*return*/]; | ||
}; | ||
SessionReplayEventsIDBStore.prototype.getCurrentSequenceEvents = function (sessionId) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var events, allEvents, _a, _b, events, e_9_1; | ||
var e_9, _c; | ||
return tslib_1.__generator(this, function (_d) { | ||
switch (_d.label) { | ||
case 0: | ||
if (!sessionId) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, this.db.get('sessionCurrentSequence', sessionId)]; | ||
case 1: | ||
events = _d.sent(); | ||
if (!events) { | ||
return [2 /*return*/, undefined]; | ||
} | ||
return [2 /*return*/, [events]]; | ||
case 2: | ||
allEvents = []; | ||
_d.label = 3; | ||
case 3: | ||
_d.trys.push([3, 8, 9, 10]); | ||
return [4 /*yield*/, this.db.getAll('sessionCurrentSequence')]; | ||
case 4: | ||
_a = tslib_1.__values.apply(void 0, [_d.sent()]), _b = _a.next(); | ||
_d.label = 5; | ||
case 5: | ||
if (!!_b.done) return [3 /*break*/, 7]; | ||
events = _b.value; | ||
allEvents.push(events); | ||
_d.label = 6; | ||
case 6: | ||
_b = _a.next(); | ||
return [3 /*break*/, 5]; | ||
case 7: return [3 /*break*/, 10]; | ||
case 8: | ||
e_9_1 = _d.sent(); | ||
e_9 = { error: e_9_1 }; | ||
return [3 /*break*/, 10]; | ||
case 9: | ||
try { | ||
if (_b && !_b.done && (_c = _a.return)) _c.call(_a); | ||
} | ||
finally { if (e_9) throw e_9.error; } | ||
return [7 /*endfinally*/]; | ||
case 10: return [2 /*return*/, allEvents]; | ||
} | ||
}); | ||
}); | ||
}; | ||
return SessionReplayEventsIDBStore; | ||
}()); | ||
}(base_events_store_1.BaseEventsStore)); | ||
exports.SessionReplayEventsIDBStore = SessionReplayEventsIDBStore; | ||
var createEventsIDBStore = function (_a) { | ||
var loggerProvider = _a.loggerProvider, apiKey = _a.apiKey, sessionId = _a.sessionId, type = _a.type, minInterval = _a.minInterval, maxInterval = _a.maxInterval; | ||
return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var eventsIDBStore; | ||
return tslib_1.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
eventsIDBStore = new SessionReplayEventsIDBStore({ loggerProvider: loggerProvider, apiKey: apiKey, minInterval: minInterval, maxInterval: maxInterval }); | ||
return [4 /*yield*/, eventsIDBStore.initialize(type, sessionId)]; | ||
case 1: | ||
_b.sent(); | ||
return [2 /*return*/, eventsIDBStore]; | ||
} | ||
}); | ||
}); | ||
}; | ||
exports.createEventsIDBStore = createEventsIDBStore; | ||
//# sourceMappingURL=events-idb-store.js.map |
@@ -1,5 +0,5 @@ | ||
import { SessionReplayEventsManager as AmplitudeSessionReplayEventsManager, EventType } from '../typings/session-replay'; | ||
import { SessionReplayEventsManager as AmplitudeSessionReplayEventsManager, EventType, StoreType } from '../typings/session-replay'; | ||
import { SessionReplayJoinedConfig } from '../config/types'; | ||
import { PayloadBatcher } from '../track-destination'; | ||
export declare const createEventsManager: <Type extends EventType>({ config, sessionId, minInterval, maxInterval, type, payloadBatcher, }: { | ||
export declare const createEventsManager: <Type extends EventType>({ config, sessionId, minInterval, maxInterval, type, payloadBatcher, storeType, }: { | ||
config: SessionReplayJoinedConfig; | ||
@@ -11,3 +11,4 @@ type: Type; | ||
payloadBatcher?: PayloadBatcher | undefined; | ||
storeType: StoreType; | ||
}) => Promise<AmplitudeSessionReplayEventsManager<Type, string>>; | ||
//# sourceMappingURL=events-manager.d.ts.map |
@@ -5,7 +5,8 @@ var _this = this; | ||
var tslib_1 = require("tslib"); | ||
var helpers_1 = require("../helpers"); | ||
var track_destination_1 = require("../track-destination"); | ||
var events_idb_store_1 = require("./events-idb-store"); | ||
var track_destination_1 = require("../track-destination"); | ||
var helpers_1 = require("../helpers"); | ||
var events_memory_store_1 = require("./events-memory-store"); | ||
var createEventsManager = function (_a) { | ||
var config = _a.config, sessionId = _a.sessionId, minInterval = _a.minInterval, maxInterval = _a.maxInterval, type = _a.type, payloadBatcher = _a.payloadBatcher; | ||
var config = _a.config, sessionId = _a.sessionId, minInterval = _a.minInterval, maxInterval = _a.maxInterval, type = _a.type, payloadBatcher = _a.payloadBatcher, storeType = _a.storeType; | ||
return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
@@ -20,18 +21,42 @@ function flush(useRetry) { | ||
} | ||
var trackDestination, eventsIDBStore, sendEventsList, sendCurrentSequenceEvents, sendStoredEvents, addEvent; | ||
var trackDestination, getMemoryStore, getIdbStoreOrFallback, store, _b, sendEventsList, sendCurrentSequenceEvents, sendStoredEvents, addEvent; | ||
var _this = this; | ||
return tslib_1.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
return tslib_1.__generator(this, function (_c) { | ||
switch (_c.label) { | ||
case 0: | ||
trackDestination = new track_destination_1.SessionReplayTrackDestination({ loggerProvider: config.loggerProvider, payloadBatcher: payloadBatcher }); | ||
return [4 /*yield*/, (0, events_idb_store_1.createEventsIDBStore)({ | ||
getMemoryStore = function () { | ||
return new events_memory_store_1.InMemoryEventsStore({ | ||
loggerProvider: config.loggerProvider, | ||
apiKey: config.apiKey, | ||
sessionId: sessionId, | ||
maxInterval: maxInterval, | ||
minInterval: minInterval, | ||
maxInterval: maxInterval, | ||
type: type, | ||
})]; | ||
}); | ||
}; | ||
getIdbStoreOrFallback = function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var store; | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, events_idb_store_1.SessionReplayEventsIDBStore.new(type, { | ||
loggerProvider: config.loggerProvider, | ||
minInterval: minInterval, | ||
maxInterval: maxInterval, | ||
apiKey: config.apiKey, | ||
}, sessionId)]; | ||
case 1: | ||
store = _a.sent(); | ||
config.loggerProvider.log('Failed to initialize idb store, falling back to memory store.'); | ||
return [2 /*return*/, store !== null && store !== void 0 ? store : getMemoryStore()]; | ||
} | ||
}); | ||
}); }; | ||
if (!(storeType === 'idb')) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, getIdbStoreOrFallback()]; | ||
case 1: | ||
eventsIDBStore = _b.sent(); | ||
_b = _c.sent(); | ||
return [3 /*break*/, 3]; | ||
case 2: | ||
_b = getMemoryStore(); | ||
_c.label = 3; | ||
case 3: | ||
store = _b; | ||
sendEventsList = function (_a) { | ||
@@ -51,3 +76,2 @@ var events = _a.events, sessionId = _a.sessionId, deviceId = _a.deviceId, sequenceId = _a.sequenceId; | ||
events: events, | ||
sequenceId: sequenceId, | ||
sessionId: sessionId, | ||
@@ -61,3 +85,12 @@ flushMaxRetries: config.flushMaxRetries, | ||
type: type, | ||
onComplete: eventsIDBStore.cleanUpSessionEventsStore.bind(eventsIDBStore), | ||
onComplete: function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, store.cleanUpSessionEventsStore(sessionId, sequenceId)]; | ||
case 1: | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); }, | ||
}); | ||
@@ -67,3 +100,3 @@ }; | ||
var sessionId = _a.sessionId, deviceId = _a.deviceId; | ||
eventsIDBStore | ||
store | ||
.storeCurrentSequence(sessionId) | ||
@@ -90,3 +123,3 @@ .then(function (currentSequence) { | ||
switch (_b.label) { | ||
case 0: return [4 /*yield*/, eventsIDBStore.getSequencesToSend()]; | ||
case 0: return [4 /*yield*/, store.getSequencesToSend()]; | ||
case 1: | ||
@@ -110,3 +143,3 @@ sequencesToSend = _b.sent(); | ||
var event = _a.event, sessionId = _a.sessionId, deviceId = _a.deviceId; | ||
eventsIDBStore | ||
store | ||
.addEventToCurrentSequence(sessionId, event.data) | ||
@@ -113,0 +146,0 @@ .then(function (sequenceToSend) { |
@@ -25,2 +25,3 @@ import { PrivacyConfig, SessionReplayJoinedConfig } from './config/types'; | ||
performanceConfig?: import("./config/types").SessionReplayPerformanceConfig | undefined; | ||
storeType: import("./typings/session-replay").StoreType; | ||
flushIntervalMillis: number; | ||
@@ -27,0 +28,0 @@ flushQueueSize: number; |
export declare const init: (apiKey: string, options: import("./typings/session-replay").SessionReplayOptions) => import("@amplitude/analytics-types").AmplitudeReturn<void>, setSessionId: (sessionId: number, deviceId?: string | undefined) => import("@amplitude/analytics-types").AmplitudeReturn<void>, getSessionId: () => number | undefined, getSessionReplayProperties: () => { | ||
[key: string]: string | boolean | null; | ||
}, flush: (useRetry: boolean) => Promise<void>, shutdown: () => void; | ||
export { SessionReplayOptions } from './typings/session-replay'; | ||
export { SessionReplayOptions, StoreType } from './typings/session-replay'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -121,7 +121,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
SessionReplay.prototype._init = function (apiKey, options) { | ||
var _a, _b, _c; | ||
var _a, _b, _c, _d; | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var _d, _e, scrollWatcher, managers, rrwebEventManager, error_1, typedError, payloadBatcher, interactionEventManager, error_2, typedError; | ||
return tslib_1.__generator(this, function (_f) { | ||
switch (_f.label) { | ||
var _e, _f, scrollWatcher, managers, storeType, rrwebEventManager, error_1, typedError, payloadBatcher, interactionEventManager, error_2, typedError; | ||
return tslib_1.__generator(this, function (_g) { | ||
switch (_g.label) { | ||
case 0: | ||
@@ -132,10 +132,10 @@ this.loggerProvider = options.loggerProvider || new analytics_core_1.Logger(); | ||
this.identifiers = new identifiers_1.SessionIdentifiers({ sessionId: options.sessionId, deviceId: options.deviceId }); | ||
_d = this; | ||
_e = this; | ||
return [4 /*yield*/, (0, joined_config_1.createSessionReplayJoinedConfigGenerator)(apiKey, options)]; | ||
case 1: | ||
_d.joinedConfigGenerator = _f.sent(); | ||
_e = this; | ||
_e.joinedConfigGenerator = _g.sent(); | ||
_f = this; | ||
return [4 /*yield*/, this.joinedConfigGenerator.generateJoinedConfig(this.identifiers.sessionId)]; | ||
case 2: | ||
_e.config = _f.sent(); | ||
_f.config = _g.sent(); | ||
if (options.sessionId && ((_a = this.config.interactionConfig) === null || _a === void 0 ? void 0 : _a.enabled)) { | ||
@@ -150,5 +150,11 @@ scrollWatcher = scroll_1.ScrollWatcher.default({ | ||
managers = []; | ||
_f.label = 3; | ||
storeType = this.config.storeType; | ||
if (storeType === 'idb' && !((_b = (0, analytics_client_common_1.getGlobalScope)()) === null || _b === void 0 ? void 0 : _b.indexedDB)) { | ||
storeType = 'memory'; | ||
this.loggerProvider.warn('Could not use preferred indexedDB storage, reverting to in memory option.'); | ||
} | ||
this.loggerProvider.log("Using ".concat(storeType, " for event storage.")); | ||
_g.label = 3; | ||
case 3: | ||
_f.trys.push([3, 5, , 6]); | ||
_g.trys.push([3, 5, , 6]); | ||
return [4 /*yield*/, (0, events_manager_1.createEventsManager)({ | ||
@@ -158,9 +164,10 @@ config: this.config, | ||
type: 'replay', | ||
storeType: storeType, | ||
})]; | ||
case 4: | ||
rrwebEventManager = _f.sent(); | ||
rrwebEventManager = _g.sent(); | ||
managers.push({ name: 'replay', manager: rrwebEventManager }); | ||
return [3 /*break*/, 6]; | ||
case 5: | ||
error_1 = _f.sent(); | ||
error_1 = _g.sent(); | ||
typedError = error_1; | ||
@@ -170,7 +177,7 @@ this.loggerProvider.warn("Error occurred while creating replay events manager: ".concat(typedError.toString())); | ||
case 6: | ||
if (!((_b = this.config.interactionConfig) === null || _b === void 0 ? void 0 : _b.enabled)) return [3 /*break*/, 10]; | ||
if (!((_c = this.config.interactionConfig) === null || _c === void 0 ? void 0 : _c.enabled)) return [3 /*break*/, 10]; | ||
payloadBatcher = this.config.interactionConfig.batch ? click_1.clickBatcher : click_1.clickNonBatcher; | ||
_f.label = 7; | ||
_g.label = 7; | ||
case 7: | ||
_f.trys.push([7, 9, , 10]); | ||
_g.trys.push([7, 9, , 10]); | ||
return [4 /*yield*/, (0, events_manager_1.createEventsManager)({ | ||
@@ -180,12 +187,13 @@ config: this.config, | ||
type: 'interaction', | ||
minInterval: (_c = this.config.interactionConfig.trackEveryNms) !== null && _c !== void 0 ? _c : constants_1.INTERACTION_MIN_INTERVAL, | ||
minInterval: (_d = this.config.interactionConfig.trackEveryNms) !== null && _d !== void 0 ? _d : constants_1.INTERACTION_MIN_INTERVAL, | ||
maxInterval: constants_1.INTERACTION_MAX_INTERVAL, | ||
payloadBatcher: payloadBatcher, | ||
storeType: storeType, | ||
})]; | ||
case 8: | ||
interactionEventManager = _f.sent(); | ||
interactionEventManager = _g.sent(); | ||
managers.push({ name: 'interaction', manager: interactionEventManager }); | ||
return [3 /*break*/, 10]; | ||
case 9: | ||
error_2 = _f.sent(); | ||
error_2 = _g.sent(); | ||
typedError = error_2; | ||
@@ -192,0 +200,0 @@ this.loggerProvider.warn("Error occurred while creating interaction events manager: ".concat(typedError.toString())); |
@@ -36,3 +36,3 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
context: context, | ||
err: "".concat(messages_1.MAX_RETRIES_EXCEEDED_MESSAGE, ", batch sequence id, ").concat(context.sequenceId), | ||
err: messages_1.MAX_RETRIES_EXCEEDED_MESSAGE, | ||
}); | ||
@@ -111,3 +111,2 @@ return false; | ||
session_id: "".concat(context.sessionId), | ||
seq_number: "".concat(context.sequenceId), | ||
type: "".concat(context.type), | ||
@@ -188,3 +187,3 @@ }); | ||
context: context, | ||
success: "Session replay event batch with seq id ".concat(context.sequenceId, " tracked successfully for session id ").concat(context.sessionId, ", size of events: ").concat(sizeOfEventsList, " KB"), | ||
success: "Session replay event batch tracked successfully for session id ".concat(context.sessionId, ", size of events: ").concat(sizeOfEventsList, " KB"), | ||
}); | ||
@@ -197,3 +196,3 @@ }; | ||
var context = _a.context, err = _a.err, success = _a.success; | ||
void context.onComplete(context.sequenceId); | ||
void context.onComplete(); | ||
if (err) { | ||
@@ -200,0 +199,0 @@ this.loggerProvider.warn(err); |
@@ -13,2 +13,3 @@ import { AmplitudeReturn, ServerZone } from '@amplitude/analytics-types'; | ||
export type Events = string[]; | ||
export type StoreType = 'memory' | 'idb'; | ||
export type EventType = 'replay' | 'interaction'; | ||
@@ -23,3 +24,2 @@ export interface SessionReplayDestinationSessionMetadata { | ||
events: Events; | ||
sequenceId: number; | ||
flushMaxRetries?: number; | ||
@@ -29,3 +29,3 @@ apiKey?: string; | ||
serverZone?: keyof typeof ServerZone; | ||
onComplete: (sequenceId: number) => Promise<void>; | ||
onComplete: () => Promise<void>; | ||
} & SessionReplayDestinationSessionMetadata; | ||
@@ -36,15 +36,16 @@ export interface SessionReplayDestinationContext extends SessionReplayDestination { | ||
} | ||
export interface SendingSequencesIDBInput { | ||
sequenceId?: number; | ||
export interface SendingSequencesReturn<KeyType> { | ||
sequenceId: KeyType; | ||
sessionId: number; | ||
events: Events; | ||
} | ||
export type SendingSequencesIDBReturn = Required<SendingSequencesIDBInput>; | ||
export interface SessionReplayEventsIDBStore { | ||
initialize(type: EventType): Promise<void>; | ||
getSequencesToSend(): Promise<SendingSequencesIDBReturn[] | undefined>; | ||
/** | ||
* This interface is not guaranteed to be stable, yet. | ||
*/ | ||
export interface EventsStore<KeyType> { | ||
getSequencesToSend(): Promise<SendingSequencesReturn<KeyType>[] | undefined>; | ||
/** | ||
* Moves current sequence of events to long term storage and resets short term storage. | ||
*/ | ||
storeCurrentSequence(sessionId: number): Promise<SendingSequencesIDBInput | undefined>; | ||
storeCurrentSequence(sessionId: number): Promise<SendingSequencesReturn<KeyType> | undefined>; | ||
/** | ||
@@ -54,5 +55,12 @@ * Adds events to the current IDB sequence. Returns events that should be | ||
*/ | ||
addEventToCurrentSequence(sessionId: number, event: string): Promise<SendingSequencesIDBReturn | undefined>; | ||
storeSendingEvents(sessionId: number, events: Events): Promise<number | undefined>; | ||
cleanUpSessionEventsStore(sessionId: number, sequenceId: number): Promise<void>; | ||
addEventToCurrentSequence(sessionId: number, event: string): Promise<SendingSequencesReturn<KeyType> | undefined>; | ||
/** | ||
* Returns the sequence id associated with the events batch. | ||
* @returns the new sequence id or undefined if it cannot be determined or on any error. | ||
*/ | ||
storeSendingEvents(sessionId: number, events: Events): Promise<KeyType | undefined>; | ||
/** | ||
* Permanently removes the events batch for the session/sequence pair. | ||
*/ | ||
cleanUpSessionEventsStore(sessionId: number, sequenceId?: KeyType): Promise<void>; | ||
} | ||
@@ -59,0 +67,0 @@ export interface SessionIdentifiers { |
@@ -1,2 +0,2 @@ | ||
export declare const VERSION = "1.14.3"; | ||
export declare const VERSION = "1.15.0"; | ||
//# sourceMappingURL=version.d.ts.map |
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.VERSION = void 0; | ||
// Autogenerated by `yarn version-file`. DO NOT EDIT | ||
exports.VERSION = '1.14.3'; | ||
exports.VERSION = '1.15.0'; | ||
//# sourceMappingURL=version.js.map |
import { FetchTransport } from '@amplitude/analytics-client-common'; | ||
import { Config, Logger } from '@amplitude/analytics-core'; | ||
import { LogLevel } from '@amplitude/analytics-types'; | ||
import { SessionReplayOptions } from '../typings/session-replay'; | ||
import { SessionReplayOptions, StoreType } from '../typings/session-replay'; | ||
import { SessionReplayLocalConfig as ISessionReplayLocalConfig, InteractionConfig, PrivacyConfig, SessionReplayPerformanceConfig, SessionReplayVersion } from './types'; | ||
@@ -21,2 +21,3 @@ export declare const getDefaultConfig: () => { | ||
version?: SessionReplayVersion; | ||
storeType: StoreType; | ||
performanceConfig?: SessionReplayPerformanceConfig; | ||
@@ -23,0 +24,0 @@ constructor(apiKey: string, options: SessionReplayOptions); |
@@ -16,2 +16,3 @@ import { __assign, __extends } from "tslib"; | ||
var _this = this; | ||
var _a; | ||
var defaultConfig = getDefaultConfig(); | ||
@@ -30,2 +31,3 @@ _this = _super.call(this, __assign(__assign({ transportProvider: defaultConfig.transportProvider }, options), { apiKey: apiKey })) || this; | ||
_this.performanceConfig = options.performanceConfig; | ||
_this.storeType = (_a = options.storeType) !== null && _a !== void 0 ? _a : 'idb'; | ||
if (options.privacyConfig) { | ||
@@ -32,0 +34,0 @@ _this.privacyConfig = options.privacyConfig; |
import { Config, LogLevel, Logger } from '@amplitude/analytics-types'; | ||
import { StoreType } from '../typings/session-replay'; | ||
export interface SamplingConfig { | ||
@@ -41,2 +42,3 @@ sample_rate: number; | ||
performanceConfig?: SessionReplayPerformanceConfig; | ||
storeType: StoreType; | ||
} | ||
@@ -43,0 +45,0 @@ export interface SessionReplayJoinedConfig extends SessionReplayLocalConfig { |
@@ -1,4 +0,4 @@ | ||
import { Logger as ILogger } from '@amplitude/analytics-types'; | ||
import { DBSchema, IDBPDatabase } from 'idb'; | ||
import { SessionReplayEventsIDBStore as AmplitudeSessionReplayEventsIDBStore, EventType, Events, SendingSequencesIDBInput } from '../typings/session-replay'; | ||
import { EventType, Events, SendingSequencesReturn } from '../typings/session-replay'; | ||
import { BaseEventsStore, InstanceArgs as BaseInstanceArgs } from './base-events-store'; | ||
export declare const currentSequenceKey = "sessionCurrentSequence"; | ||
@@ -10,10 +10,7 @@ export declare const sequencesToSendKey = "sequencesToSend"; | ||
key: number; | ||
value: { | ||
sessionId: number; | ||
events: Events; | ||
}; | ||
value: Omit<SendingSequencesReturn<number>, 'sequenceId'>; | ||
}; | ||
sequencesToSend: { | ||
key: number; | ||
value: SendingSequencesIDBInput; | ||
value: Omit<SendingSequencesReturn<number>, 'sequenceId'>; | ||
indexes: { | ||
@@ -30,27 +27,13 @@ sessionId: number; | ||
export declare const createStore: (dbName: string) => Promise<IDBPDatabase<SessionReplayDB>>; | ||
export declare class SessionReplayEventsIDBStore implements AmplitudeSessionReplayEventsIDBStore { | ||
type InstanceArgs = { | ||
apiKey: string; | ||
db: IDBPDatabase<SessionReplayDB> | undefined; | ||
loggerProvider: ILogger; | ||
storageKey: string; | ||
maxPersistedEventsSize: number; | ||
interval: number; | ||
timeAtLastSplit: number | null; | ||
private readonly minInterval; | ||
private readonly maxInterval; | ||
constructor({ loggerProvider, apiKey, minInterval, maxInterval, }: { | ||
loggerProvider: ILogger; | ||
apiKey: string; | ||
minInterval?: number; | ||
maxInterval?: number; | ||
}); | ||
initialize(type: EventType, sessionId?: number): Promise<void>; | ||
/** | ||
* Determines whether to send the events list to the backend and start a new | ||
* empty events list, based on the size of the list as well as the last time sent | ||
* @param nextEventString | ||
* @returns boolean | ||
*/ | ||
shouldSplitEventsList: (events: Events, nextEventString: string) => boolean; | ||
getSequencesToSend: () => Promise<Required<SendingSequencesIDBInput>[] | undefined>; | ||
db: IDBPDatabase<SessionReplayDB>; | ||
} & BaseInstanceArgs; | ||
export declare class SessionReplayEventsIDBStore extends BaseEventsStore<number> { | ||
private readonly apiKey; | ||
private readonly db; | ||
constructor(args: InstanceArgs); | ||
static new(type: EventType, args: Omit<InstanceArgs, 'db'>, sessionId?: number): Promise<SessionReplayEventsIDBStore | undefined>; | ||
getCurrentSequenceEvents(sessionId?: number): Promise<Omit<SendingSequencesReturn<number>, "sequenceId">[] | undefined>; | ||
getSequencesToSend: () => Promise<SendingSequencesReturn<number>[] | undefined>; | ||
storeCurrentSequence: (sessionId: number) => Promise<{ | ||
@@ -67,13 +50,6 @@ sessionId: number; | ||
storeSendingEvents: (sessionId: number, events: Events) => Promise<number | undefined>; | ||
cleanUpSessionEventsStore: (sequenceId: number) => Promise<void>; | ||
cleanUpSessionEventsStore: (_sessionId: number, sequenceId?: number) => Promise<void>; | ||
transitionFromKeyValStore: (sessionId?: number) => Promise<void>; | ||
} | ||
export declare const createEventsIDBStore: ({ loggerProvider, apiKey, sessionId, type, minInterval, maxInterval, }: { | ||
loggerProvider: ILogger; | ||
apiKey: string; | ||
type: EventType; | ||
minInterval?: number | undefined; | ||
maxInterval?: number | undefined; | ||
sessionId?: number | undefined; | ||
}) => Promise<SessionReplayEventsIDBStore>; | ||
export {}; | ||
//# sourceMappingURL=events-idb-store.d.ts.map |
@@ -1,7 +0,7 @@ | ||
import { __assign, __awaiter, __generator } from "tslib"; | ||
import { __assign, __awaiter, __extends, __generator, __values } from "tslib"; | ||
import { getGlobalScope } from '@amplitude/analytics-client-common'; | ||
import { STORAGE_PREFIX } from '@amplitude/analytics-core'; | ||
import { openDB } from 'idb'; | ||
import { MAX_EVENT_LIST_SIZE_IN_BYTES, MAX_INTERVAL, MIN_INTERVAL } from '../constants'; | ||
import { STORAGE_FAILURE } from '../messages'; | ||
import { BaseEventsStore } from './base-events-store'; | ||
import { RecordingStatus } from './legacy-idb-types'; | ||
@@ -85,51 +85,39 @@ export var currentSequenceKey = 'sessionCurrentSequence'; | ||
}); }; | ||
var SessionReplayEventsIDBStore = /** @class */ (function () { | ||
function SessionReplayEventsIDBStore(_a) { | ||
var loggerProvider = _a.loggerProvider, apiKey = _a.apiKey, minInterval = _a.minInterval, maxInterval = _a.maxInterval; | ||
var _this = this; | ||
this.storageKey = ''; | ||
this.maxPersistedEventsSize = MAX_EVENT_LIST_SIZE_IN_BYTES; | ||
this.timeAtLastSplit = null; | ||
/** | ||
* Determines whether to send the events list to the backend and start a new | ||
* empty events list, based on the size of the list as well as the last time sent | ||
* @param nextEventString | ||
* @returns boolean | ||
*/ | ||
this.shouldSplitEventsList = function (events, nextEventString) { | ||
var sizeOfNextEvent = new Blob([nextEventString]).size; | ||
var sizeOfEventsList = new Blob(events).size; | ||
if (sizeOfEventsList + sizeOfNextEvent >= _this.maxPersistedEventsSize) { | ||
return true; | ||
} | ||
if (_this.timeAtLastSplit !== null && | ||
_this.interval && | ||
Date.now() - _this.timeAtLastSplit > _this.interval && | ||
events.length) { | ||
_this.interval = Math.min(_this.maxInterval, _this.interval + _this.minInterval); | ||
_this.timeAtLastSplit = Date.now(); | ||
return true; | ||
} | ||
return false; | ||
}; | ||
this.getSequencesToSend = function () { return __awaiter(_this, void 0, void 0, function () { | ||
var sequencesToSend, e_1; | ||
var _a; | ||
var SessionReplayEventsIDBStore = /** @class */ (function (_super) { | ||
__extends(SessionReplayEventsIDBStore, _super); | ||
function SessionReplayEventsIDBStore(args) { | ||
var _this = _super.call(this, args) || this; | ||
_this.getSequencesToSend = function () { return __awaiter(_this, void 0, void 0, function () { | ||
var sequences, cursor, _a, sessionId, events, e_1; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
_b.trys.push([0, 2, , 3]); | ||
return [4 /*yield*/, ((_a = this.db) === null || _a === void 0 ? void 0 : _a.getAll(sequencesToSendKey))]; | ||
_b.trys.push([0, 5, , 6]); | ||
sequences = []; | ||
return [4 /*yield*/, this.db.transaction('sequencesToSend').store.openCursor()]; | ||
case 1: | ||
sequencesToSend = (_b.sent()); | ||
return [2 /*return*/, sequencesToSend]; | ||
cursor = _b.sent(); | ||
_b.label = 2; | ||
case 2: | ||
if (!cursor) return [3 /*break*/, 4]; | ||
_a = cursor.value, sessionId = _a.sessionId, events = _a.events; | ||
sequences.push({ | ||
events: events, | ||
sequenceId: cursor.key, | ||
sessionId: sessionId, | ||
}); | ||
return [4 /*yield*/, cursor.continue()]; | ||
case 3: | ||
cursor = _b.sent(); | ||
return [3 /*break*/, 2]; | ||
case 4: return [2 /*return*/, sequences]; | ||
case 5: | ||
e_1 = _b.sent(); | ||
this.loggerProvider.warn("".concat(STORAGE_FAILURE, ": ").concat(e_1)); | ||
return [3 /*break*/, 3]; | ||
case 3: return [2 /*return*/, undefined]; | ||
return [3 /*break*/, 6]; | ||
case 6: return [2 /*return*/, undefined]; | ||
} | ||
}); | ||
}); }; | ||
this.storeCurrentSequence = function (sessionId) { return __awaiter(_this, void 0, void 0, function () { | ||
_this.storeCurrentSequence = function (sessionId) { return __awaiter(_this, void 0, void 0, function () { | ||
var currentSequenceData, sequenceId, e_2; | ||
@@ -140,5 +128,2 @@ return __generator(this, function (_a) { | ||
_a.trys.push([0, 4, , 5]); | ||
if (!this.db) { | ||
return [2 /*return*/, undefined]; | ||
} | ||
return [4 /*yield*/, this.db.get(currentSequenceKey, sessionId)]; | ||
@@ -168,45 +153,36 @@ case 1: | ||
}); }; | ||
this.addEventToCurrentSequence = function (sessionId, event) { return __awaiter(_this, void 0, void 0, function () { | ||
_this.addEventToCurrentSequence = function (sessionId, event) { return __awaiter(_this, void 0, void 0, function () { | ||
var tx, sequenceEvents, eventsToSend, updatedEvents, sequenceId, e_3; | ||
var _a; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
if (this.interval === 0) { | ||
this.interval = this.minInterval; | ||
} | ||
_b.label = 1; | ||
_a.trys.push([0, 10, , 11]); | ||
tx = this.db.transaction(currentSequenceKey, 'readwrite'); | ||
return [4 /*yield*/, tx.store.get(sessionId)]; | ||
case 1: | ||
_b.trys.push([1, 11, , 12]); | ||
tx = (_a = this.db) === null || _a === void 0 ? void 0 : _a.transaction(currentSequenceKey, 'readwrite'); | ||
if (!tx) { | ||
return [2 /*return*/]; | ||
} | ||
return [4 /*yield*/, tx.store.get(sessionId)]; | ||
sequenceEvents = _a.sent(); | ||
if (!!sequenceEvents) return [3 /*break*/, 3]; | ||
return [4 /*yield*/, tx.store.put({ sessionId: sessionId, events: [event] })]; | ||
case 2: | ||
sequenceEvents = _b.sent(); | ||
if (!!sequenceEvents) return [3 /*break*/, 4]; | ||
return [4 /*yield*/, tx.store.put({ sessionId: sessionId, events: [event] })]; | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
case 3: | ||
_b.sent(); | ||
return [2 /*return*/]; | ||
case 4: | ||
eventsToSend = void 0; | ||
if (!this.shouldSplitEventsList(sequenceEvents.events, event)) return [3 /*break*/, 6]; | ||
if (!this.shouldSplitEventsList(sequenceEvents.events, event)) return [3 /*break*/, 5]; | ||
eventsToSend = sequenceEvents.events; | ||
// set store to empty array | ||
return [4 /*yield*/, tx.store.put({ sessionId: sessionId, events: [event] })]; | ||
case 4: | ||
// set store to empty array | ||
_a.sent(); | ||
return [3 /*break*/, 7]; | ||
case 5: | ||
// set store to empty array | ||
_b.sent(); | ||
return [3 /*break*/, 8]; | ||
case 6: | ||
updatedEvents = sequenceEvents.events.concat(event); | ||
return [4 /*yield*/, tx.store.put({ sessionId: sessionId, events: updatedEvents })]; | ||
case 7: | ||
_b.sent(); | ||
_b.label = 8; | ||
case 8: return [4 /*yield*/, tx.done]; | ||
case 9: | ||
_b.sent(); | ||
case 6: | ||
_a.sent(); | ||
_a.label = 7; | ||
case 7: return [4 /*yield*/, tx.done]; | ||
case 8: | ||
_a.sent(); | ||
if (!eventsToSend) { | ||
@@ -216,4 +192,4 @@ return [2 /*return*/, undefined]; | ||
return [4 /*yield*/, this.storeSendingEvents(sessionId, eventsToSend)]; | ||
case 10: | ||
sequenceId = _b.sent(); | ||
case 9: | ||
sequenceId = _a.sent(); | ||
if (!sequenceId) { | ||
@@ -227,26 +203,25 @@ return [2 /*return*/, undefined]; | ||
}]; | ||
case 11: | ||
e_3 = _b.sent(); | ||
case 10: | ||
e_3 = _a.sent(); | ||
this.loggerProvider.warn("".concat(STORAGE_FAILURE, ": ").concat(e_3)); | ||
return [3 /*break*/, 12]; | ||
case 12: return [2 /*return*/, undefined]; | ||
return [3 /*break*/, 11]; | ||
case 11: return [2 /*return*/, undefined]; | ||
} | ||
}); | ||
}); }; | ||
this.storeSendingEvents = function (sessionId, events) { return __awaiter(_this, void 0, void 0, function () { | ||
_this.storeSendingEvents = function (sessionId, events) { return __awaiter(_this, void 0, void 0, function () { | ||
var sequenceId, e_4; | ||
var _a; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
_b.trys.push([0, 2, , 3]); | ||
return [4 /*yield*/, ((_a = this.db) === null || _a === void 0 ? void 0 : _a.put(sequencesToSendKey, { | ||
_a.trys.push([0, 2, , 3]); | ||
return [4 /*yield*/, this.db.put(sequencesToSendKey, { | ||
sessionId: sessionId, | ||
events: events, | ||
}))]; | ||
})]; | ||
case 1: | ||
sequenceId = _b.sent(); | ||
sequenceId = _a.sent(); | ||
return [2 /*return*/, sequenceId]; | ||
case 2: | ||
e_4 = _b.sent(); | ||
e_4 = _a.sent(); | ||
this.loggerProvider.warn("".concat(STORAGE_FAILURE, ": ").concat(e_4)); | ||
@@ -258,22 +233,26 @@ return [3 /*break*/, 3]; | ||
}); }; | ||
this.cleanUpSessionEventsStore = function (sequenceId) { return __awaiter(_this, void 0, void 0, function () { | ||
_this.cleanUpSessionEventsStore = function (_sessionId, sequenceId) { return __awaiter(_this, void 0, void 0, function () { | ||
var e_5; | ||
var _a; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
_b.trys.push([0, 2, , 3]); | ||
return [4 /*yield*/, ((_a = this.db) === null || _a === void 0 ? void 0 : _a.delete(sequencesToSendKey, sequenceId))]; | ||
if (!sequenceId) { | ||
return [2 /*return*/]; | ||
} | ||
_a.label = 1; | ||
case 1: | ||
_b.sent(); | ||
return [3 /*break*/, 3]; | ||
_a.trys.push([1, 3, , 4]); | ||
return [4 /*yield*/, this.db.delete(sequencesToSendKey, sequenceId)]; | ||
case 2: | ||
e_5 = _b.sent(); | ||
_a.sent(); | ||
return [3 /*break*/, 4]; | ||
case 3: | ||
e_5 = _a.sent(); | ||
this.loggerProvider.warn("".concat(STORAGE_FAILURE, ": ").concat(e_5)); | ||
return [3 /*break*/, 3]; | ||
case 3: return [2 /*return*/]; | ||
return [3 /*break*/, 4]; | ||
case 4: return [2 /*return*/]; | ||
} | ||
}); | ||
}); }; | ||
this.transitionFromKeyValStore = function (sessionId) { return __awaiter(_this, void 0, void 0, function () { | ||
_this.transitionFromKeyValStore = function (sessionId) { return __awaiter(_this, void 0, void 0, function () { | ||
var keyValDb, transitionCurrentSessionSequences_1, storageKey, getAllRequest_1, transitionPromise, globalScope, e_6, e_7; | ||
@@ -383,29 +362,26 @@ var _this = this; | ||
}); }; | ||
this.loggerProvider = loggerProvider; | ||
this.apiKey = apiKey; | ||
this.maxInterval = maxInterval !== null && maxInterval !== void 0 ? maxInterval : MAX_INTERVAL; | ||
this.minInterval = minInterval !== null && minInterval !== void 0 ? minInterval : MIN_INTERVAL; | ||
this.interval = 0; | ||
_this.apiKey = args.apiKey; | ||
_this.db = args.db; | ||
return _this; | ||
} | ||
SessionReplayEventsIDBStore.prototype.initialize = function (type, sessionId) { | ||
SessionReplayEventsIDBStore.new = function (type, args, sessionId) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var dbSuffix, dbName, _a, e_8; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
var dbSuffix, dbName, db, eventsIDBStore, e_8; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
_b.trys.push([0, 3, , 4]); | ||
_a.trys.push([0, 3, , 4]); | ||
dbSuffix = type === 'replay' ? '' : "_".concat(type); | ||
dbName = "".concat(this.apiKey.substring(0, 10), "_amp_session_replay_events").concat(dbSuffix); | ||
_a = this; | ||
dbName = "".concat(args.apiKey.substring(0, 10), "_amp_session_replay_events").concat(dbSuffix); | ||
return [4 /*yield*/, createStore(dbName)]; | ||
case 1: | ||
_a.db = _b.sent(); | ||
this.timeAtLastSplit = Date.now(); // Initialize this so we have a point of comparison when events are recorded | ||
return [4 /*yield*/, this.transitionFromKeyValStore(sessionId)]; | ||
db = _a.sent(); | ||
eventsIDBStore = new SessionReplayEventsIDBStore(__assign(__assign({}, args), { db: db })); | ||
return [4 /*yield*/, eventsIDBStore.transitionFromKeyValStore(sessionId)]; | ||
case 2: | ||
_b.sent(); | ||
return [3 /*break*/, 4]; | ||
_a.sent(); | ||
return [2 /*return*/, eventsIDBStore]; | ||
case 3: | ||
e_8 = _b.sent(); | ||
this.loggerProvider.warn("".concat(STORAGE_FAILURE, ": ").concat(e_8)); | ||
e_8 = _a.sent(); | ||
args.loggerProvider.warn("".concat(STORAGE_FAILURE, ": ").concat(e_8)); | ||
return [3 /*break*/, 4]; | ||
@@ -417,21 +393,53 @@ case 4: return [2 /*return*/]; | ||
}; | ||
SessionReplayEventsIDBStore.prototype.getCurrentSequenceEvents = function (sessionId) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var events, allEvents, _a, _b, events, e_9_1; | ||
var e_9, _c; | ||
return __generator(this, function (_d) { | ||
switch (_d.label) { | ||
case 0: | ||
if (!sessionId) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, this.db.get('sessionCurrentSequence', sessionId)]; | ||
case 1: | ||
events = _d.sent(); | ||
if (!events) { | ||
return [2 /*return*/, undefined]; | ||
} | ||
return [2 /*return*/, [events]]; | ||
case 2: | ||
allEvents = []; | ||
_d.label = 3; | ||
case 3: | ||
_d.trys.push([3, 8, 9, 10]); | ||
return [4 /*yield*/, this.db.getAll('sessionCurrentSequence')]; | ||
case 4: | ||
_a = __values.apply(void 0, [_d.sent()]), _b = _a.next(); | ||
_d.label = 5; | ||
case 5: | ||
if (!!_b.done) return [3 /*break*/, 7]; | ||
events = _b.value; | ||
allEvents.push(events); | ||
_d.label = 6; | ||
case 6: | ||
_b = _a.next(); | ||
return [3 /*break*/, 5]; | ||
case 7: return [3 /*break*/, 10]; | ||
case 8: | ||
e_9_1 = _d.sent(); | ||
e_9 = { error: e_9_1 }; | ||
return [3 /*break*/, 10]; | ||
case 9: | ||
try { | ||
if (_b && !_b.done && (_c = _a.return)) _c.call(_a); | ||
} | ||
finally { if (e_9) throw e_9.error; } | ||
return [7 /*endfinally*/]; | ||
case 10: return [2 /*return*/, allEvents]; | ||
} | ||
}); | ||
}); | ||
}; | ||
return SessionReplayEventsIDBStore; | ||
}()); | ||
}(BaseEventsStore)); | ||
export { SessionReplayEventsIDBStore }; | ||
export var createEventsIDBStore = function (_a) { | ||
var loggerProvider = _a.loggerProvider, apiKey = _a.apiKey, sessionId = _a.sessionId, type = _a.type, minInterval = _a.minInterval, maxInterval = _a.maxInterval; | ||
return __awaiter(void 0, void 0, void 0, function () { | ||
var eventsIDBStore; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
eventsIDBStore = new SessionReplayEventsIDBStore({ loggerProvider: loggerProvider, apiKey: apiKey, minInterval: minInterval, maxInterval: maxInterval }); | ||
return [4 /*yield*/, eventsIDBStore.initialize(type, sessionId)]; | ||
case 1: | ||
_b.sent(); | ||
return [2 /*return*/, eventsIDBStore]; | ||
} | ||
}); | ||
}); | ||
}; | ||
//# sourceMappingURL=events-idb-store.js.map |
@@ -1,5 +0,5 @@ | ||
import { SessionReplayEventsManager as AmplitudeSessionReplayEventsManager, EventType } from '../typings/session-replay'; | ||
import { SessionReplayEventsManager as AmplitudeSessionReplayEventsManager, EventType, StoreType } from '../typings/session-replay'; | ||
import { SessionReplayJoinedConfig } from '../config/types'; | ||
import { PayloadBatcher } from '../track-destination'; | ||
export declare const createEventsManager: <Type extends EventType>({ config, sessionId, minInterval, maxInterval, type, payloadBatcher, }: { | ||
export declare const createEventsManager: <Type extends EventType>({ config, sessionId, minInterval, maxInterval, type, payloadBatcher, storeType, }: { | ||
config: SessionReplayJoinedConfig; | ||
@@ -11,3 +11,4 @@ type: Type; | ||
payloadBatcher?: PayloadBatcher | undefined; | ||
storeType: StoreType; | ||
}) => Promise<AmplitudeSessionReplayEventsManager<Type, string>>; | ||
//# sourceMappingURL=events-manager.d.ts.map |
import { __awaiter, __generator } from "tslib"; | ||
import { createEventsIDBStore } from './events-idb-store'; | ||
import { getStorageSize } from '../helpers'; | ||
import { SessionReplayTrackDestination } from '../track-destination'; | ||
import { getStorageSize } from '../helpers'; | ||
import { SessionReplayEventsIDBStore } from './events-idb-store'; | ||
import { InMemoryEventsStore } from './events-memory-store'; | ||
export var createEventsManager = function (_a) { | ||
var config = _a.config, sessionId = _a.sessionId, minInterval = _a.minInterval, maxInterval = _a.maxInterval, type = _a.type, payloadBatcher = _a.payloadBatcher; | ||
var config = _a.config, sessionId = _a.sessionId, minInterval = _a.minInterval, maxInterval = _a.maxInterval, type = _a.type, payloadBatcher = _a.payloadBatcher, storeType = _a.storeType; | ||
return __awaiter(void 0, void 0, void 0, function () { | ||
@@ -16,17 +17,41 @@ function flush(useRetry) { | ||
} | ||
var trackDestination, eventsIDBStore, sendEventsList, sendCurrentSequenceEvents, sendStoredEvents, addEvent; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
var trackDestination, getMemoryStore, getIdbStoreOrFallback, store, _b, sendEventsList, sendCurrentSequenceEvents, sendStoredEvents, addEvent; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
case 0: | ||
trackDestination = new SessionReplayTrackDestination({ loggerProvider: config.loggerProvider, payloadBatcher: payloadBatcher }); | ||
return [4 /*yield*/, createEventsIDBStore({ | ||
getMemoryStore = function () { | ||
return new InMemoryEventsStore({ | ||
loggerProvider: config.loggerProvider, | ||
apiKey: config.apiKey, | ||
sessionId: sessionId, | ||
maxInterval: maxInterval, | ||
minInterval: minInterval, | ||
maxInterval: maxInterval, | ||
type: type, | ||
})]; | ||
}); | ||
}; | ||
getIdbStoreOrFallback = function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var store; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, SessionReplayEventsIDBStore.new(type, { | ||
loggerProvider: config.loggerProvider, | ||
minInterval: minInterval, | ||
maxInterval: maxInterval, | ||
apiKey: config.apiKey, | ||
}, sessionId)]; | ||
case 1: | ||
store = _a.sent(); | ||
config.loggerProvider.log('Failed to initialize idb store, falling back to memory store.'); | ||
return [2 /*return*/, store !== null && store !== void 0 ? store : getMemoryStore()]; | ||
} | ||
}); | ||
}); }; | ||
if (!(storeType === 'idb')) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, getIdbStoreOrFallback()]; | ||
case 1: | ||
eventsIDBStore = _b.sent(); | ||
_b = _c.sent(); | ||
return [3 /*break*/, 3]; | ||
case 2: | ||
_b = getMemoryStore(); | ||
_c.label = 3; | ||
case 3: | ||
store = _b; | ||
sendEventsList = function (_a) { | ||
@@ -46,3 +71,2 @@ var events = _a.events, sessionId = _a.sessionId, deviceId = _a.deviceId, sequenceId = _a.sequenceId; | ||
events: events, | ||
sequenceId: sequenceId, | ||
sessionId: sessionId, | ||
@@ -56,3 +80,12 @@ flushMaxRetries: config.flushMaxRetries, | ||
type: type, | ||
onComplete: eventsIDBStore.cleanUpSessionEventsStore.bind(eventsIDBStore), | ||
onComplete: function () { return __awaiter(void 0, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, store.cleanUpSessionEventsStore(sessionId, sequenceId)]; | ||
case 1: | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); }, | ||
}); | ||
@@ -62,3 +95,3 @@ }; | ||
var sessionId = _a.sessionId, deviceId = _a.deviceId; | ||
eventsIDBStore | ||
store | ||
.storeCurrentSequence(sessionId) | ||
@@ -85,3 +118,3 @@ .then(function (currentSequence) { | ||
switch (_b.label) { | ||
case 0: return [4 /*yield*/, eventsIDBStore.getSequencesToSend()]; | ||
case 0: return [4 /*yield*/, store.getSequencesToSend()]; | ||
case 1: | ||
@@ -105,3 +138,3 @@ sequencesToSend = _b.sent(); | ||
var event = _a.event, sessionId = _a.sessionId, deviceId = _a.deviceId; | ||
eventsIDBStore | ||
store | ||
.addEventToCurrentSequence(sessionId, event.data) | ||
@@ -108,0 +141,0 @@ .then(function (sequenceToSend) { |
@@ -25,2 +25,3 @@ import { PrivacyConfig, SessionReplayJoinedConfig } from './config/types'; | ||
performanceConfig?: import("./config/types").SessionReplayPerformanceConfig | undefined; | ||
storeType: import("./typings/session-replay").StoreType; | ||
flushIntervalMillis: number; | ||
@@ -27,0 +28,0 @@ flushQueueSize: number; |
export declare const init: (apiKey: string, options: import("./typings/session-replay").SessionReplayOptions) => import("@amplitude/analytics-types").AmplitudeReturn<void>, setSessionId: (sessionId: number, deviceId?: string | undefined) => import("@amplitude/analytics-types").AmplitudeReturn<void>, getSessionId: () => number | undefined, getSessionReplayProperties: () => { | ||
[key: string]: string | boolean | null; | ||
}, flush: (useRetry: boolean) => Promise<void>, shutdown: () => void; | ||
export { SessionReplayOptions } from './typings/session-replay'; | ||
export { SessionReplayOptions, StoreType } from './typings/session-replay'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -119,7 +119,7 @@ import { __assign, __awaiter, __generator, __read, __spreadArray } from "tslib"; | ||
SessionReplay.prototype._init = function (apiKey, options) { | ||
var _a, _b, _c; | ||
var _a, _b, _c, _d; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var _d, _e, scrollWatcher, managers, rrwebEventManager, error_1, typedError, payloadBatcher, interactionEventManager, error_2, typedError; | ||
return __generator(this, function (_f) { | ||
switch (_f.label) { | ||
var _e, _f, scrollWatcher, managers, storeType, rrwebEventManager, error_1, typedError, payloadBatcher, interactionEventManager, error_2, typedError; | ||
return __generator(this, function (_g) { | ||
switch (_g.label) { | ||
case 0: | ||
@@ -130,10 +130,10 @@ this.loggerProvider = options.loggerProvider || new Logger(); | ||
this.identifiers = new SessionIdentifiers({ sessionId: options.sessionId, deviceId: options.deviceId }); | ||
_d = this; | ||
_e = this; | ||
return [4 /*yield*/, createSessionReplayJoinedConfigGenerator(apiKey, options)]; | ||
case 1: | ||
_d.joinedConfigGenerator = _f.sent(); | ||
_e = this; | ||
_e.joinedConfigGenerator = _g.sent(); | ||
_f = this; | ||
return [4 /*yield*/, this.joinedConfigGenerator.generateJoinedConfig(this.identifiers.sessionId)]; | ||
case 2: | ||
_e.config = _f.sent(); | ||
_f.config = _g.sent(); | ||
if (options.sessionId && ((_a = this.config.interactionConfig) === null || _a === void 0 ? void 0 : _a.enabled)) { | ||
@@ -148,5 +148,11 @@ scrollWatcher = ScrollWatcher.default({ | ||
managers = []; | ||
_f.label = 3; | ||
storeType = this.config.storeType; | ||
if (storeType === 'idb' && !((_b = getGlobalScope()) === null || _b === void 0 ? void 0 : _b.indexedDB)) { | ||
storeType = 'memory'; | ||
this.loggerProvider.warn('Could not use preferred indexedDB storage, reverting to in memory option.'); | ||
} | ||
this.loggerProvider.log("Using ".concat(storeType, " for event storage.")); | ||
_g.label = 3; | ||
case 3: | ||
_f.trys.push([3, 5, , 6]); | ||
_g.trys.push([3, 5, , 6]); | ||
return [4 /*yield*/, createEventsManager({ | ||
@@ -156,9 +162,10 @@ config: this.config, | ||
type: 'replay', | ||
storeType: storeType, | ||
})]; | ||
case 4: | ||
rrwebEventManager = _f.sent(); | ||
rrwebEventManager = _g.sent(); | ||
managers.push({ name: 'replay', manager: rrwebEventManager }); | ||
return [3 /*break*/, 6]; | ||
case 5: | ||
error_1 = _f.sent(); | ||
error_1 = _g.sent(); | ||
typedError = error_1; | ||
@@ -168,7 +175,7 @@ this.loggerProvider.warn("Error occurred while creating replay events manager: ".concat(typedError.toString())); | ||
case 6: | ||
if (!((_b = this.config.interactionConfig) === null || _b === void 0 ? void 0 : _b.enabled)) return [3 /*break*/, 10]; | ||
if (!((_c = this.config.interactionConfig) === null || _c === void 0 ? void 0 : _c.enabled)) return [3 /*break*/, 10]; | ||
payloadBatcher = this.config.interactionConfig.batch ? clickBatcher : clickNonBatcher; | ||
_f.label = 7; | ||
_g.label = 7; | ||
case 7: | ||
_f.trys.push([7, 9, , 10]); | ||
_g.trys.push([7, 9, , 10]); | ||
return [4 /*yield*/, createEventsManager({ | ||
@@ -178,12 +185,13 @@ config: this.config, | ||
type: 'interaction', | ||
minInterval: (_c = this.config.interactionConfig.trackEveryNms) !== null && _c !== void 0 ? _c : INTERACTION_MIN_INTERVAL, | ||
minInterval: (_d = this.config.interactionConfig.trackEveryNms) !== null && _d !== void 0 ? _d : INTERACTION_MIN_INTERVAL, | ||
maxInterval: INTERACTION_MAX_INTERVAL, | ||
payloadBatcher: payloadBatcher, | ||
storeType: storeType, | ||
})]; | ||
case 8: | ||
interactionEventManager = _f.sent(); | ||
interactionEventManager = _g.sent(); | ||
managers.push({ name: 'interaction', manager: interactionEventManager }); | ||
return [3 /*break*/, 10]; | ||
case 9: | ||
error_2 = _f.sent(); | ||
error_2 = _g.sent(); | ||
typedError = error_2; | ||
@@ -190,0 +198,0 @@ this.loggerProvider.warn("Error occurred while creating interaction events manager: ".concat(typedError.toString())); |
@@ -34,3 +34,3 @@ import { __assign, __awaiter, __generator } from "tslib"; | ||
context: context, | ||
err: "".concat(MAX_RETRIES_EXCEEDED_MESSAGE, ", batch sequence id, ").concat(context.sequenceId), | ||
err: MAX_RETRIES_EXCEEDED_MESSAGE, | ||
}); | ||
@@ -109,3 +109,2 @@ return false; | ||
session_id: "".concat(context.sessionId), | ||
seq_number: "".concat(context.sequenceId), | ||
type: "".concat(context.type), | ||
@@ -186,3 +185,3 @@ }); | ||
context: context, | ||
success: "Session replay event batch with seq id ".concat(context.sequenceId, " tracked successfully for session id ").concat(context.sessionId, ", size of events: ").concat(sizeOfEventsList, " KB"), | ||
success: "Session replay event batch tracked successfully for session id ".concat(context.sessionId, ", size of events: ").concat(sizeOfEventsList, " KB"), | ||
}); | ||
@@ -195,3 +194,3 @@ }; | ||
var context = _a.context, err = _a.err, success = _a.success; | ||
void context.onComplete(context.sequenceId); | ||
void context.onComplete(); | ||
if (err) { | ||
@@ -198,0 +197,0 @@ this.loggerProvider.warn(err); |
@@ -13,2 +13,3 @@ import { AmplitudeReturn, ServerZone } from '@amplitude/analytics-types'; | ||
export type Events = string[]; | ||
export type StoreType = 'memory' | 'idb'; | ||
export type EventType = 'replay' | 'interaction'; | ||
@@ -23,3 +24,2 @@ export interface SessionReplayDestinationSessionMetadata { | ||
events: Events; | ||
sequenceId: number; | ||
flushMaxRetries?: number; | ||
@@ -29,3 +29,3 @@ apiKey?: string; | ||
serverZone?: keyof typeof ServerZone; | ||
onComplete: (sequenceId: number) => Promise<void>; | ||
onComplete: () => Promise<void>; | ||
} & SessionReplayDestinationSessionMetadata; | ||
@@ -36,15 +36,16 @@ export interface SessionReplayDestinationContext extends SessionReplayDestination { | ||
} | ||
export interface SendingSequencesIDBInput { | ||
sequenceId?: number; | ||
export interface SendingSequencesReturn<KeyType> { | ||
sequenceId: KeyType; | ||
sessionId: number; | ||
events: Events; | ||
} | ||
export type SendingSequencesIDBReturn = Required<SendingSequencesIDBInput>; | ||
export interface SessionReplayEventsIDBStore { | ||
initialize(type: EventType): Promise<void>; | ||
getSequencesToSend(): Promise<SendingSequencesIDBReturn[] | undefined>; | ||
/** | ||
* This interface is not guaranteed to be stable, yet. | ||
*/ | ||
export interface EventsStore<KeyType> { | ||
getSequencesToSend(): Promise<SendingSequencesReturn<KeyType>[] | undefined>; | ||
/** | ||
* Moves current sequence of events to long term storage and resets short term storage. | ||
*/ | ||
storeCurrentSequence(sessionId: number): Promise<SendingSequencesIDBInput | undefined>; | ||
storeCurrentSequence(sessionId: number): Promise<SendingSequencesReturn<KeyType> | undefined>; | ||
/** | ||
@@ -54,5 +55,12 @@ * Adds events to the current IDB sequence. Returns events that should be | ||
*/ | ||
addEventToCurrentSequence(sessionId: number, event: string): Promise<SendingSequencesIDBReturn | undefined>; | ||
storeSendingEvents(sessionId: number, events: Events): Promise<number | undefined>; | ||
cleanUpSessionEventsStore(sessionId: number, sequenceId: number): Promise<void>; | ||
addEventToCurrentSequence(sessionId: number, event: string): Promise<SendingSequencesReturn<KeyType> | undefined>; | ||
/** | ||
* Returns the sequence id associated with the events batch. | ||
* @returns the new sequence id or undefined if it cannot be determined or on any error. | ||
*/ | ||
storeSendingEvents(sessionId: number, events: Events): Promise<KeyType | undefined>; | ||
/** | ||
* Permanently removes the events batch for the session/sequence pair. | ||
*/ | ||
cleanUpSessionEventsStore(sessionId: number, sequenceId?: KeyType): Promise<void>; | ||
} | ||
@@ -59,0 +67,0 @@ export interface SessionIdentifiers { |
@@ -1,2 +0,2 @@ | ||
export declare const VERSION = "1.14.3"; | ||
export declare const VERSION = "1.15.0"; | ||
//# sourceMappingURL=version.d.ts.map |
// Autogenerated by `yarn version-file`. DO NOT EDIT | ||
export var VERSION = '1.14.3'; | ||
export var VERSION = '1.15.0'; | ||
//# sourceMappingURL=version.js.map |
import { FetchTransport } from '@amplitude/analytics-client-common'; | ||
import { Config, Logger } from '@amplitude/analytics-core'; | ||
import { LogLevel } from '@amplitude/analytics-types'; | ||
import { SessionReplayOptions } from '../typings/session-replay'; | ||
import { SessionReplayOptions, StoreType } from '../typings/session-replay'; | ||
import { SessionReplayLocalConfig as ISessionReplayLocalConfig, InteractionConfig, PrivacyConfig, SessionReplayPerformanceConfig, SessionReplayVersion } from './types'; | ||
@@ -21,2 +21,3 @@ export declare const getDefaultConfig: () => { | ||
version?: SessionReplayVersion; | ||
storeType: StoreType; | ||
performanceConfig?: SessionReplayPerformanceConfig; | ||
@@ -23,0 +24,0 @@ constructor(apiKey: string, options: SessionReplayOptions); |
import { Config, LogLevel, Logger } from '@amplitude/analytics-types'; | ||
import { StoreType } from '../typings/session-replay'; | ||
export interface SamplingConfig { | ||
@@ -41,2 +42,3 @@ sample_rate: number; | ||
performanceConfig?: SessionReplayPerformanceConfig; | ||
storeType: StoreType; | ||
} | ||
@@ -43,0 +45,0 @@ export interface SessionReplayJoinedConfig extends SessionReplayLocalConfig { |
@@ -1,4 +0,4 @@ | ||
import { Logger as ILogger } from '@amplitude/analytics-types'; | ||
import { DBSchema, IDBPDatabase } from 'idb'; | ||
import { SessionReplayEventsIDBStore as AmplitudeSessionReplayEventsIDBStore, EventType, Events, SendingSequencesIDBInput } from '../typings/session-replay'; | ||
import { EventType, Events, SendingSequencesReturn } from '../typings/session-replay'; | ||
import { BaseEventsStore, InstanceArgs as BaseInstanceArgs } from './base-events-store'; | ||
export declare const currentSequenceKey = "sessionCurrentSequence"; | ||
@@ -10,10 +10,7 @@ export declare const sequencesToSendKey = "sequencesToSend"; | ||
key: number; | ||
value: { | ||
sessionId: number; | ||
events: Events; | ||
}; | ||
value: Omit<SendingSequencesReturn<number>, 'sequenceId'>; | ||
}; | ||
sequencesToSend: { | ||
key: number; | ||
value: SendingSequencesIDBInput; | ||
value: Omit<SendingSequencesReturn<number>, 'sequenceId'>; | ||
indexes: { | ||
@@ -30,27 +27,13 @@ sessionId: number; | ||
export declare const createStore: (dbName: string) => Promise<IDBPDatabase<SessionReplayDB>>; | ||
export declare class SessionReplayEventsIDBStore implements AmplitudeSessionReplayEventsIDBStore { | ||
type InstanceArgs = { | ||
apiKey: string; | ||
db: IDBPDatabase<SessionReplayDB> | undefined; | ||
loggerProvider: ILogger; | ||
storageKey: string; | ||
maxPersistedEventsSize: number; | ||
interval: number; | ||
timeAtLastSplit: number | null; | ||
private readonly minInterval; | ||
private readonly maxInterval; | ||
constructor({ loggerProvider, apiKey, minInterval, maxInterval, }: { | ||
loggerProvider: ILogger; | ||
apiKey: string; | ||
minInterval?: number; | ||
maxInterval?: number; | ||
}); | ||
initialize(type: EventType, sessionId?: number): Promise<void>; | ||
/** | ||
* Determines whether to send the events list to the backend and start a new | ||
* empty events list, based on the size of the list as well as the last time sent | ||
* @param nextEventString | ||
* @returns boolean | ||
*/ | ||
shouldSplitEventsList: (events: Events, nextEventString: string) => boolean; | ||
getSequencesToSend: () => Promise<Required<SendingSequencesIDBInput>[] | undefined>; | ||
db: IDBPDatabase<SessionReplayDB>; | ||
} & BaseInstanceArgs; | ||
export declare class SessionReplayEventsIDBStore extends BaseEventsStore<number> { | ||
private readonly apiKey; | ||
private readonly db; | ||
constructor(args: InstanceArgs); | ||
static new(type: EventType, args: Omit<InstanceArgs, 'db'>, sessionId?: number): Promise<SessionReplayEventsIDBStore | undefined>; | ||
getCurrentSequenceEvents(sessionId?: number): Promise<Omit<SendingSequencesReturn<number>, "sequenceId">[] | undefined>; | ||
getSequencesToSend: () => Promise<SendingSequencesReturn<number>[] | undefined>; | ||
storeCurrentSequence: (sessionId: number) => Promise<{ | ||
@@ -67,13 +50,6 @@ sessionId: number; | ||
storeSendingEvents: (sessionId: number, events: Events) => Promise<number | undefined>; | ||
cleanUpSessionEventsStore: (sequenceId: number) => Promise<void>; | ||
cleanUpSessionEventsStore: (_sessionId: number, sequenceId?: number) => Promise<void>; | ||
transitionFromKeyValStore: (sessionId?: number) => Promise<void>; | ||
} | ||
export declare const createEventsIDBStore: ({ loggerProvider, apiKey, sessionId, type, minInterval, maxInterval, }: { | ||
loggerProvider: ILogger; | ||
apiKey: string; | ||
type: EventType; | ||
minInterval?: number | undefined; | ||
maxInterval?: number | undefined; | ||
sessionId?: number | undefined; | ||
}) => Promise<SessionReplayEventsIDBStore>; | ||
export {}; | ||
//# sourceMappingURL=events-idb-store.d.ts.map |
@@ -1,5 +0,5 @@ | ||
import { SessionReplayEventsManager as AmplitudeSessionReplayEventsManager, EventType } from '../typings/session-replay'; | ||
import { SessionReplayEventsManager as AmplitudeSessionReplayEventsManager, EventType, StoreType } from '../typings/session-replay'; | ||
import { SessionReplayJoinedConfig } from '../config/types'; | ||
import { PayloadBatcher } from '../track-destination'; | ||
export declare const createEventsManager: <Type extends EventType>({ config, sessionId, minInterval, maxInterval, type, payloadBatcher, }: { | ||
export declare const createEventsManager: <Type extends EventType>({ config, sessionId, minInterval, maxInterval, type, payloadBatcher, storeType, }: { | ||
config: SessionReplayJoinedConfig; | ||
@@ -11,3 +11,4 @@ type: Type; | ||
payloadBatcher?: PayloadBatcher | undefined; | ||
storeType: StoreType; | ||
}) => Promise<AmplitudeSessionReplayEventsManager<Type, string>>; | ||
//# sourceMappingURL=events-manager.d.ts.map |
@@ -25,2 +25,3 @@ import { PrivacyConfig, SessionReplayJoinedConfig } from './config/types'; | ||
performanceConfig?: import("./config/types").SessionReplayPerformanceConfig | undefined; | ||
storeType: import("./typings/session-replay").StoreType; | ||
flushIntervalMillis: number; | ||
@@ -27,0 +28,0 @@ flushQueueSize: number; |
export declare const init: (apiKey: string, options: import("./typings/session-replay").SessionReplayOptions) => import("@amplitude/analytics-types").AmplitudeReturn<void>, setSessionId: (sessionId: number, deviceId?: string | undefined) => import("@amplitude/analytics-types").AmplitudeReturn<void>, getSessionId: () => number | undefined, getSessionReplayProperties: () => { | ||
[key: string]: string | boolean | null; | ||
}, flush: (useRetry: boolean) => Promise<void>, shutdown: () => void; | ||
export { SessionReplayOptions } from './typings/session-replay'; | ||
export { SessionReplayOptions, StoreType } from './typings/session-replay'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -13,2 +13,3 @@ import { AmplitudeReturn, ServerZone } from '@amplitude/analytics-types'; | ||
export type Events = string[]; | ||
export type StoreType = 'memory' | 'idb'; | ||
export type EventType = 'replay' | 'interaction'; | ||
@@ -23,3 +24,2 @@ export interface SessionReplayDestinationSessionMetadata { | ||
events: Events; | ||
sequenceId: number; | ||
flushMaxRetries?: number; | ||
@@ -29,3 +29,3 @@ apiKey?: string; | ||
serverZone?: keyof typeof ServerZone; | ||
onComplete: (sequenceId: number) => Promise<void>; | ||
onComplete: () => Promise<void>; | ||
} & SessionReplayDestinationSessionMetadata; | ||
@@ -36,15 +36,16 @@ export interface SessionReplayDestinationContext extends SessionReplayDestination { | ||
} | ||
export interface SendingSequencesIDBInput { | ||
sequenceId?: number; | ||
export interface SendingSequencesReturn<KeyType> { | ||
sequenceId: KeyType; | ||
sessionId: number; | ||
events: Events; | ||
} | ||
export type SendingSequencesIDBReturn = Required<SendingSequencesIDBInput>; | ||
export interface SessionReplayEventsIDBStore { | ||
initialize(type: EventType): Promise<void>; | ||
getSequencesToSend(): Promise<SendingSequencesIDBReturn[] | undefined>; | ||
/** | ||
* This interface is not guaranteed to be stable, yet. | ||
*/ | ||
export interface EventsStore<KeyType> { | ||
getSequencesToSend(): Promise<SendingSequencesReturn<KeyType>[] | undefined>; | ||
/** | ||
* Moves current sequence of events to long term storage and resets short term storage. | ||
*/ | ||
storeCurrentSequence(sessionId: number): Promise<SendingSequencesIDBInput | undefined>; | ||
storeCurrentSequence(sessionId: number): Promise<SendingSequencesReturn<KeyType> | undefined>; | ||
/** | ||
@@ -54,5 +55,12 @@ * Adds events to the current IDB sequence. Returns events that should be | ||
*/ | ||
addEventToCurrentSequence(sessionId: number, event: string): Promise<SendingSequencesIDBReturn | undefined>; | ||
storeSendingEvents(sessionId: number, events: Events): Promise<number | undefined>; | ||
cleanUpSessionEventsStore(sessionId: number, sequenceId: number): Promise<void>; | ||
addEventToCurrentSequence(sessionId: number, event: string): Promise<SendingSequencesReturn<KeyType> | undefined>; | ||
/** | ||
* Returns the sequence id associated with the events batch. | ||
* @returns the new sequence id or undefined if it cannot be determined or on any error. | ||
*/ | ||
storeSendingEvents(sessionId: number, events: Events): Promise<KeyType | undefined>; | ||
/** | ||
* Permanently removes the events batch for the session/sequence pair. | ||
*/ | ||
cleanUpSessionEventsStore(sessionId: number, sequenceId?: KeyType): Promise<void>; | ||
} | ||
@@ -59,0 +67,0 @@ export interface SessionIdentifiers { |
@@ -1,2 +0,2 @@ | ||
export declare const VERSION = "1.14.3"; | ||
export declare const VERSION = "1.15.0"; | ||
//# sourceMappingURL=version.d.ts.map |
{ | ||
"name": "@amplitude/session-replay-browser", | ||
"version": "1.14.3", | ||
"version": "1.15.0", | ||
"description": "", | ||
@@ -66,3 +66,3 @@ "author": "Amplitude Inc", | ||
], | ||
"gitHead": "bc3483c26fdac0062ceaa14dc2a18e8f1fdf638f" | ||
"gitHead": "50690c121a35df702c1c6bc3da2ac6af57df95f4" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1120755
247
8338