Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@amplitude/session-replay-browser

Package Overview
Dependencies
Maintainers
21
Versions
79
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@amplitude/session-replay-browser - npm Package Compare versions

Comparing version 1.8.0 to 1.9.0

lib/cjs/events/multi-manager.d.ts

38

lib/cjs/config/joined-config.js

@@ -32,6 +32,6 @@ var _this = this;

return tslib_1.__awaiter(this, void 0, void 0, function () {
var config, remoteConfig, samplingConfig_1, privacyConfig, err_1, knownError, samplingConfig, remotePrivacyConfig, localPrivacyConfig, joinedPrivacyConfig, privacyConfigSelectorMap, selectorMap, _d, _e, _f, selector, selectorType;
var e_1, _g;
return tslib_1.__generator(this, function (_h) {
switch (_h.label) {
var config, remoteConfig, samplingConfig_1, privacyConfig, _d, err_1, knownError, samplingConfig, remotePrivacyConfig, localPrivacyConfig, joinedPrivacyConfig, privacyConfigSelectorMap, selectorMap, _e, _f, _g, selector, selectorType;
var e_1, _h;
return tslib_1.__generator(this, function (_j) {
switch (_j.label) {
case 0:

@@ -44,5 +44,5 @@ config = tslib_1.__assign({}, this.localConfig);

config.captureEnabled = true;
_h.label = 1;
_j.label = 1;
case 1:
_h.trys.push([1, 4, , 5]);
_j.trys.push([1, 5, , 6]);
if (!this.remoteConfigFetch) {

@@ -53,6 +53,12 @@ return [2 /*return*/, config];

case 2:
samplingConfig_1 = _h.sent();
samplingConfig_1 = _j.sent();
return [4 /*yield*/, this.remoteConfigFetch.getRemoteConfig('sessionReplay', 'sr_privacy_config', sessionId)];
case 3:
privacyConfig = _h.sent();
privacyConfig = _j.sent();
// This is intentionally forced to only be set through the remote config.
_d = config;
return [4 /*yield*/, this.remoteConfigFetch.getRemoteConfig('sessionReplay', 'sr_interaction_config', sessionId)];
case 4:
// This is intentionally forced to only be set through the remote config.
_d.interactionConfig = _j.sent();
if (samplingConfig_1 || privacyConfig) {

@@ -67,10 +73,10 @@ remoteConfig = {};

}
return [3 /*break*/, 5];
case 4:
err_1 = _h.sent();
return [3 /*break*/, 6];
case 5:
err_1 = _j.sent();
knownError = err_1;
this.localConfig.loggerProvider.warn(knownError.message);
config.captureEnabled = true;
return [3 /*break*/, 5];
case 5:
return [3 /*break*/, 6];
case 6:
if (!remoteConfig) {

@@ -169,4 +175,4 @@ return [2 /*return*/, config];

try {
for (_d = tslib_1.__values(Object.entries(selectorMap)), _e = _d.next(); !_e.done; _e = _d.next()) {
_f = tslib_1.__read(_e.value, 2), selector = _f[0], selectorType = _f[1];
for (_e = tslib_1.__values(Object.entries(selectorMap)), _f = _e.next(); !_f.done; _f = _e.next()) {
_g = tslib_1.__read(_f.value, 2), selector = _g[0], selectorType = _g[1];
if (selectorType === 'mask') {

@@ -186,3 +192,3 @@ joinedPrivacyConfig.maskSelector.push(selector);

try {
if (_e && !_e.done && (_g = _d.return)) _g.call(_d);
if (_f && !_f.done && (_h = _e.return)) _h.call(_e);
}

@@ -189,0 +195,0 @@ finally { if (e_1) throw e_1.error; }

@@ -5,3 +5,3 @@ import { FetchTransport } from '@amplitude/analytics-client-common';

import { SessionReplayOptions } from '../typings/session-replay';
import { SessionReplayLocalConfig as ISessionReplayLocalConfig, PrivacyConfig } from './types';
import { SessionReplayLocalConfig as ISessionReplayLocalConfig, InteractionConfig, PrivacyConfig } from './types';
export declare const getDefaultConfig: () => {

@@ -17,2 +17,3 @@ flushMaxRetries: number;

privacyConfig?: PrivacyConfig;
interactionConfig?: InteractionConfig;
debugMode?: boolean;

@@ -19,0 +20,0 @@ configEndpointUrl?: string;

@@ -6,5 +6,10 @@ import { Config, LogLevel, Logger } from '@amplitude/analytics-types';

}
export interface InteractionConfig {
trackEveryNms?: number;
enabled: boolean;
}
export type SessionReplayRemoteConfig = {
sr_sampling_config?: SamplingConfig;
sr_privacy_config?: PrivacyConfig;
sr_interaction_config?: InteractionConfig;
};

@@ -37,2 +42,3 @@ export interface SessionReplayRemoteConfigAPIResponse {

captureEnabled?: boolean;
interactionConfig?: InteractionConfig;
}

@@ -39,0 +45,0 @@ export interface SessionReplayRemoteConfigFetch {

@@ -17,2 +17,4 @@ import { ServerZone } from '@amplitude/analytics-types';

export declare const MAX_EVENT_LIST_SIZE_IN_BYTES: number;
export declare const INTERACTION_MIN_INTERVAL = 30000;
export declare const INTERACTION_MAX_INTERVAL = 60000;
export declare const MIN_INTERVAL = 500;

@@ -19,0 +21,0 @@ export declare const MAX_INTERVAL: number;

Object.defineProperty(exports, "__esModule", { value: true });
exports.MAX_IDB_STORAGE_LENGTH = exports.MAX_INTERVAL = exports.MIN_INTERVAL = exports.MAX_EVENT_LIST_SIZE_IN_BYTES = exports.STORAGE_PREFIX = exports.SESSION_REPLAY_STAGING_URL = exports.SESSION_REPLAY_EU_URL = exports.SESSION_REPLAY_SERVER_URL = exports.UNMASK_TEXT_CLASS = exports.MASK_TEXT_CLASS = exports.BLOCK_CLASS = exports.SESSION_REPLAY_DEBUG_PROPERTY = exports.DEFAULT_SERVER_ZONE = exports.DEFAULT_SAMPLE_RATE = exports.DEFAULT_SESSION_END_EVENT = exports.DEFAULT_SESSION_START_EVENT = exports.DEFAULT_SESSION_REPLAY_PROPERTY = exports.DEFAULT_EVENT_PROPERTY_PREFIX = void 0;
exports.MAX_IDB_STORAGE_LENGTH = exports.MAX_INTERVAL = exports.MIN_INTERVAL = exports.INTERACTION_MAX_INTERVAL = exports.INTERACTION_MIN_INTERVAL = exports.MAX_EVENT_LIST_SIZE_IN_BYTES = exports.STORAGE_PREFIX = exports.SESSION_REPLAY_STAGING_URL = exports.SESSION_REPLAY_EU_URL = exports.SESSION_REPLAY_SERVER_URL = exports.UNMASK_TEXT_CLASS = exports.MASK_TEXT_CLASS = exports.BLOCK_CLASS = exports.SESSION_REPLAY_DEBUG_PROPERTY = exports.DEFAULT_SERVER_ZONE = exports.DEFAULT_SAMPLE_RATE = exports.DEFAULT_SESSION_END_EVENT = exports.DEFAULT_SESSION_START_EVENT = exports.DEFAULT_SESSION_REPLAY_PROPERTY = exports.DEFAULT_EVENT_PROPERTY_PREFIX = void 0;
var analytics_core_1 = require("@amplitude/analytics-core");

@@ -20,2 +20,4 @@ var analytics_types_1 = require("@amplitude/analytics-types");

exports.MAX_EVENT_LIST_SIZE_IN_BYTES = 1 * 1000000; // 1 MB
exports.INTERACTION_MIN_INTERVAL = 30000; // 30 seconds
exports.INTERACTION_MAX_INTERVAL = 60000; // 1 minute
exports.MIN_INTERVAL = 500; // 500 ms

@@ -22,0 +24,0 @@ exports.MAX_INTERVAL = 10 * 1000; // 10 seconds

import { Logger as ILogger } from '@amplitude/analytics-types';
import { DBSchema, IDBPDatabase } from 'idb';
import { SessionReplayEventsIDBStore as AmplitudeSessionReplayEventsIDBStore, Events, SendingSequencesIDBInput } from '../typings/session-replay';
import { SessionReplayEventsIDBStore as AmplitudeSessionReplayEventsIDBStore, EventType, Events, SendingSequencesIDBInput } from '../typings/session-replay';
export declare const currentSequenceKey = "sessionCurrentSequence";

@@ -37,7 +37,11 @@ export declare const sequencesToSendKey = "sequencesToSend";

timeAtLastSplit: number | null;
constructor({ loggerProvider, apiKey }: {
private readonly minInterval;
private readonly maxInterval;
constructor({ loggerProvider, apiKey, minInterval, maxInterval, }: {
loggerProvider: ILogger;
apiKey: string;
minInterval?: number;
maxInterval?: number;
});
initialize(sessionId?: number): Promise<void>;
initialize(type: EventType, sessionId?: number): Promise<void>;
/**

@@ -65,7 +69,10 @@ * Determines whether to send the events list to the backend and start a new

}
export declare const createEventsIDBStore: ({ loggerProvider, apiKey, sessionId, }: {
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>;
//# sourceMappingURL=events-idb-store.d.ts.map

@@ -93,7 +93,6 @@ var _this = this;

function SessionReplayEventsIDBStore(_a) {
var loggerProvider = _a.loggerProvider, apiKey = _a.apiKey;
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.interval = constants_1.MIN_INTERVAL;
this.timeAtLastSplit = null;

@@ -112,4 +111,7 @@ /**

}
if (_this.timeAtLastSplit !== null && Date.now() - _this.timeAtLastSplit > _this.interval && events.length) {
_this.interval = Math.min(constants_1.MAX_INTERVAL, _this.interval + constants_1.MIN_INTERVAL);
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();

@@ -178,3 +180,8 @@ return true;

case 0:
_b.trys.push([0, 10, , 11]);
if (this.interval === 0) {
this.interval = this.minInterval;
}
_b.label = 1;
case 1:
_b.trys.push([1, 11, , 12]);
tx = (_a = this.db) === null || _a === void 0 ? void 0 : _a.transaction(exports.currentSequenceKey, 'readwrite');

@@ -185,27 +192,27 @@ if (!tx) {

return [4 /*yield*/, tx.store.get(sessionId)];
case 1:
case 2:
sequenceEvents = _b.sent();
if (!!sequenceEvents) return [3 /*break*/, 3];
if (!!sequenceEvents) return [3 /*break*/, 4];
return [4 /*yield*/, tx.store.put({ sessionId: sessionId, events: [event] })];
case 2:
case 3:
_b.sent();
return [2 /*return*/];
case 3:
case 4:
eventsToSend = void 0;
if (!this.shouldSplitEventsList(sequenceEvents.events, event)) return [3 /*break*/, 5];
if (!this.shouldSplitEventsList(sequenceEvents.events, event)) return [3 /*break*/, 6];
eventsToSend = sequenceEvents.events;
// set store to empty array
return [4 /*yield*/, tx.store.put({ sessionId: sessionId, events: [event] })];
case 4:
case 5:
// set store to empty array
_b.sent();
return [3 /*break*/, 7];
case 5:
return [3 /*break*/, 8];
case 6:
updatedEvents = sequenceEvents.events.concat(event);
return [4 /*yield*/, tx.store.put({ sessionId: sessionId, events: updatedEvents })];
case 6:
case 7:
_b.sent();
_b.label = 7;
case 7: return [4 /*yield*/, tx.done];
case 8:
_b.label = 8;
case 8: return [4 /*yield*/, tx.done];
case 9:
_b.sent();

@@ -216,3 +223,3 @@ if (!eventsToSend) {

return [4 /*yield*/, this.storeSendingEvents(sessionId, eventsToSend)];
case 9:
case 10:
sequenceId = _b.sent();

@@ -227,7 +234,7 @@ if (!sequenceId) {

}];
case 10:
case 11:
e_3 = _b.sent();
this.loggerProvider.warn("".concat(messages_1.STORAGE_FAILURE, ": ").concat(e_3));
return [3 /*break*/, 11];
case 11: return [2 /*return*/, undefined];
return [3 /*break*/, 12];
case 12: return [2 /*return*/, undefined];
}

@@ -384,10 +391,14 @@ });

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;
}
SessionReplayEventsIDBStore.prototype.initialize = function (sessionId) {
SessionReplayEventsIDBStore.prototype.initialize = function (type, sessionId) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var dbName, _a;
var dbSuffix, dbName, _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
dbName = "".concat(this.apiKey.substring(0, 10), "_amp_session_replay_events");
dbSuffix = type === 'replay' ? '' : "_".concat(type);
dbName = "".concat(this.apiKey.substring(0, 10), "_amp_session_replay_events").concat(dbSuffix);
_a = this;

@@ -410,3 +421,3 @@ return [4 /*yield*/, (0, exports.createStore)(dbName)];

var createEventsIDBStore = function (_a) {
var loggerProvider = _a.loggerProvider, apiKey = _a.apiKey, sessionId = _a.sessionId;
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 () {

@@ -417,4 +428,4 @@ var eventsIDBStore;

case 0:
eventsIDBStore = new SessionReplayEventsIDBStore({ loggerProvider: loggerProvider, apiKey: apiKey });
return [4 /*yield*/, eventsIDBStore.initialize(sessionId)];
eventsIDBStore = new SessionReplayEventsIDBStore({ loggerProvider: loggerProvider, apiKey: apiKey, minInterval: minInterval, maxInterval: maxInterval });
return [4 /*yield*/, eventsIDBStore.initialize(type, sessionId)];
case 1:

@@ -421,0 +432,0 @@ _b.sent();

@@ -1,7 +0,12 @@

import { SessionReplayEventsManager as AmplitudeSessionReplayEventsManager } from '../typings/session-replay';
import { SessionReplayEventsManager as AmplitudeSessionReplayEventsManager, EventType } from '../typings/session-replay';
import { SessionReplayJoinedConfig } from '../config/types';
export declare const createEventsManager: ({ config, sessionId, }: {
import { PayloadBatcher } from '../track-destination';
export declare const createEventsManager: <Type extends EventType>({ config, sessionId, minInterval, maxInterval, type, payloadBatcher, }: {
config: SessionReplayJoinedConfig;
type: Type;
minInterval?: number | undefined;
maxInterval?: number | undefined;
sessionId?: number | undefined;
}) => Promise<AmplitudeSessionReplayEventsManager>;
payloadBatcher?: PayloadBatcher | undefined;
}) => Promise<AmplitudeSessionReplayEventsManager<Type, string>>;
//# sourceMappingURL=events-manager.d.ts.map

@@ -5,6 +5,6 @@ var _this = this;

var tslib_1 = require("tslib");
var events_idb_store_1 = require("./events-idb-store");
var track_destination_1 = require("../track-destination");
var events_idb_store_1 = require("./events-idb-store");
var createEventsManager = function (_a) {
var config = _a.config, sessionId = _a.sessionId;
var config = _a.config, sessionId = _a.sessionId, minInterval = _a.minInterval, maxInterval = _a.maxInterval, type = _a.type, payloadBatcher = _a.payloadBatcher;
return tslib_1.__awaiter(_this, void 0, void 0, function () {

@@ -15,6 +15,3 @@ function flush(useRetry) {

return tslib_1.__generator(this, function (_a) {
if (trackDestination) {
return [2 /*return*/, trackDestination.flush(useRetry)];
}
return [2 /*return*/];
return [2 /*return*/, trackDestination.flush(useRetry)];
});

@@ -28,3 +25,3 @@ });

case 0:
trackDestination = new track_destination_1.SessionReplayTrackDestination({ loggerProvider: config.loggerProvider });
trackDestination = new track_destination_1.SessionReplayTrackDestination({ loggerProvider: config.loggerProvider, payloadBatcher: payloadBatcher });
return [4 /*yield*/, (0, events_idb_store_1.createEventsIDBStore)({

@@ -34,2 +31,5 @@ loggerProvider: config.loggerProvider,

sessionId: sessionId,
minInterval: minInterval,
maxInterval: maxInterval,
type: type,
})];

@@ -49,2 +49,3 @@ case 1:

serverZone: config.serverZone,
type: type,
onComplete: eventsIDBStore.cleanUpSessionEventsStore.bind(eventsIDBStore),

@@ -97,3 +98,3 @@ });

eventsIDBStore
.addEventToCurrentSequence(sessionId, event)
.addEventToCurrentSequence(sessionId, event.data)
.then(function (sequenceToSend) {

@@ -100,0 +101,0 @@ return (sequenceToSend &&

@@ -10,3 +10,3 @@ import { Logger as ILogger } from '@amplitude/analytics-types';

identifiers: ISessionIdentifiers | undefined;
eventsManager: AmplitudeSessionReplayEventsManager | undefined;
eventsManager?: AmplitudeSessionReplayEventsManager<'replay' | 'interaction', string>;
loggerProvider: ILogger;

@@ -36,5 +36,5 @@ recordCancelCallback: ReturnType<typeof record> | null;

getSessionId(): number | undefined;
flush(useRetry?: boolean): Promise<void>;
flush(useRetry?: boolean): Promise<void | undefined>;
shutdown(): void;
}
//# sourceMappingURL=session-replay.d.ts.map

@@ -12,2 +12,4 @@ Object.defineProperty(exports, "__esModule", { value: true });

var identifiers_1 = require("./identifiers");
var click_1 = require("./hooks/click");
var multi_manager_1 = require("./events/multi-manager");
var SessionReplay = /** @class */ (function () {

@@ -72,26 +74,44 @@ function SessionReplay() {

SessionReplay.prototype._init = function (apiKey, options) {
var _a, _b;
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _a, _b, _c, globalScope;
return tslib_1.__generator(this, function (_d) {
switch (_d.label) {
var _c, _d, managers, rrwebEventManager, interactionEventManager, globalScope;
return tslib_1.__generator(this, function (_e) {
switch (_e.label) {
case 0:
this.loggerProvider = options.loggerProvider || new analytics_core_1.Logger();
this.identifiers = new identifiers_1.SessionIdentifiers({ sessionId: options.sessionId, deviceId: options.deviceId });
_a = this;
_c = this;
return [4 /*yield*/, (0, joined_config_1.createSessionReplayJoinedConfigGenerator)(apiKey, options)];
case 1:
_a.joinedConfigGenerator = _d.sent();
_b = this;
_c.joinedConfigGenerator = _e.sent();
_d = this;
return [4 /*yield*/, this.joinedConfigGenerator.generateJoinedConfig(this.identifiers.sessionId)];
case 2:
_b.config = _d.sent();
_d.config = _e.sent();
this.loggerProvider.debug(JSON.stringify({ name: 'session replay joined privacy config', privacyConfig: this.config.privacyConfig }, null, 2));
this.removeInvalidSelectors();
_c = this;
managers = [];
return [4 /*yield*/, (0, events_manager_1.createEventsManager)({
config: this.config,
sessionId: this.identifiers.sessionId,
type: 'replay',
})];
case 3:
_c.eventsManager = _d.sent();
rrwebEventManager = _e.sent();
managers.push({ name: 'replay', manager: rrwebEventManager });
if (!((_a = this.config.interactionConfig) === null || _a === void 0 ? void 0 : _a.enabled)) return [3 /*break*/, 5];
return [4 /*yield*/, (0, events_manager_1.createEventsManager)({
config: this.config,
sessionId: this.identifiers.sessionId,
type: 'interaction',
minInterval: (_b = this.config.interactionConfig.trackEveryNms) !== null && _b !== void 0 ? _b : constants_1.INTERACTION_MIN_INTERVAL,
maxInterval: constants_1.INTERACTION_MAX_INTERVAL,
payloadBatcher: click_1.clickBatcher,
})];
case 4:
interactionEventManager = _e.sent();
managers.push({ name: 'interaction', manager: interactionEventManager });
_e.label = 5;
case 5:
this.eventsManager = new (multi_manager_1.MultiEventManager.bind.apply(multi_manager_1.MultiEventManager, tslib_1.__spreadArray([void 0], tslib_1.__read(managers), false)))();
this.loggerProvider.log('Installing @amplitude/session-replay-browser.');

@@ -196,7 +216,3 @@ globalScope = (0, analytics_client_common_1.getGlobalScope)();

}
this.eventsManager &&
shouldSendStoredEvents &&
this.eventsManager.sendStoredEvents({
deviceId: deviceId,
});
this.eventsManager && shouldSendStoredEvents && this.eventsManager.sendStoredEvents({ deviceId: deviceId });
this.recordEvents();

@@ -279,6 +295,16 @@ };

var deviceId = _this.getDeviceId();
deviceId && _this.eventsManager && _this.eventsManager.addEvent({ event: eventString, sessionId: sessionId, deviceId: deviceId });
_this.eventsManager &&
deviceId &&
_this.eventsManager.addEvent({ event: { type: 'replay', data: eventString }, sessionId: sessionId, deviceId: deviceId });
},
packFn: rrweb_1.pack,
inlineStylesheet: this.config.shouldInlineStylesheet,
hooks: {
mouseInteraction: this.eventsManager &&
(0, click_1.clickHook)({
eventsManager: this.eventsManager,
sessionId: sessionId,
deviceIdFn: this.getDeviceId.bind(this),
}),
},
maskAllInputs: true,

@@ -326,9 +352,7 @@ maskTextClass: constants_1.MASK_TEXT_CLASS,

SessionReplay.prototype.flush = function (useRetry) {
var _a;
if (useRetry === void 0) { useRetry = false; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
if (this.eventsManager) {
return [2 /*return*/, this.eventsManager.flush(useRetry)];
}
return [2 /*return*/];
return tslib_1.__generator(this, function (_b) {
return [2 /*return*/, (_a = this.eventsManager) === null || _a === void 0 ? void 0 : _a.flush(useRetry)];
});

@@ -335,0 +359,0 @@ });

import { Logger as ILogger, ServerZone } from '@amplitude/analytics-types';
import { SessionReplayTrackDestination as AmplitudeSessionReplayTrackDestination, SessionReplayDestination, SessionReplayDestinationContext } from './typings/session-replay';
export type PayloadBatcher = ({ version, events }: {
version: number;
events: string[];
}) => {
version: number;
events: unknown[];
};
export declare class SessionReplayTrackDestination implements AmplitudeSessionReplayTrackDestination {

@@ -8,5 +15,7 @@ loggerProvider: ILogger;

private scheduled;
payloadBatcher: PayloadBatcher;
queue: SessionReplayDestinationContext[];
constructor({ loggerProvider }: {
constructor({ loggerProvider, payloadBatcher }: {
loggerProvider: ILogger;
payloadBatcher?: PayloadBatcher;
});

@@ -13,0 +22,0 @@ sendEventsList(destinationData: SessionReplayDestination): void;

@@ -12,3 +12,3 @@ Object.defineProperty(exports, "__esModule", { value: true });

function SessionReplayTrackDestination(_a) {
var loggerProvider = _a.loggerProvider;
var loggerProvider = _a.loggerProvider, payloadBatcher = _a.payloadBatcher;
this.storageKey = '';

@@ -19,2 +19,3 @@ this.retryTimeout = 1000;

this.loggerProvider = loggerProvider;
this.payloadBatcher = payloadBatcher ? payloadBatcher : function (payload) { return payload; };
}

@@ -120,7 +121,12 @@ SessionReplayTrackDestination.prototype.sendEventsList = function (destinationData) {

seq_number: "".concat(context.sequenceId),
type: "".concat(context.type),
});
payload = {
payload = this.payloadBatcher({
version: 1,
events: context.events,
};
});
if (payload.events.length === 0) {
this.completeRequest({ context: context });
return [2 /*return*/];
}
_a.label = 1;

@@ -127,0 +133,0 @@ case 1:

import { AmplitudeReturn, ServerZone } from '@amplitude/analytics-types';
import { SessionReplayLocalConfig } from '../config/types';
export type Events = string[];
export type EventType = 'replay' | 'interaction';
export interface SessionReplayDestination {
events: Events;
sequenceId: number;
type: EventType;
sessionId: number;

@@ -26,5 +28,12 @@ flushMaxRetries?: number;

export interface SessionReplayEventsIDBStore {
initialize(): Promise<void>;
initialize(type: EventType): Promise<void>;
getSequencesToSend(): Promise<SendingSequencesIDBReturn[] | undefined>;
/**
* Moves current sequence of events to long term storage and resets short term storage.
*/
storeCurrentSequence(sessionId: number): Promise<SendingSequencesIDBInput | undefined>;
/**
* Adds events to the current IDB sequence. Returns events that should be
* sent to the track destination right away if should split events is true.
*/
addEventToCurrentSequence(sessionId: number, event: string): Promise<SendingSequencesIDBReturn | undefined>;

@@ -51,14 +60,36 @@ storeSendingEvents(sessionId: number, events: Events): Promise<number | undefined>;

export interface SessionReplayTrackDestination {
/**
* Enqueues events to be sent.
*/
sendEventsList: (destinationData: SessionReplayDestination) => void;
/**
* Immediately sends queued events.
*/
flush: (useRetry: boolean) => Promise<void>;
}
export interface SessionReplayEventsManager {
export type EventsManagerWithType<EventType, EventDataType> = {
name: EventType;
manager: SessionReplayEventsManager<EventType, EventDataType>;
};
export interface SessionReplayEventsManager<Type, Event> {
/**
* For each sequence stored in the long term indexed DB send immediately to the track destination.
*/
sendStoredEvents({ deviceId }: {
deviceId: string;
}): Promise<void>;
addEvent({ sessionId, event, deviceId }: {
/**
* Adds an event to the short term storage. If should split based on size or last sent, then send immediately.
*/
addEvent({ sessionId, event, deviceId, }: {
sessionId: number;
event: string;
event: {
type: Type;
data: Event;
};
deviceId: string;
}): void;
/**
* Move events in short term storage to long term storage and send immediately to the track destination.
*/
sendCurrentSequenceEvents({ sessionId, deviceId }: {

@@ -68,4 +99,7 @@ sessionId: number;

}): void;
/**
* Flush the track destination queue immediately. This should invoke sends for all the events in the queue.
*/
flush(useRetry?: boolean): Promise<void>;
}
//# sourceMappingURL=session-replay.d.ts.map

@@ -29,6 +29,6 @@ import { __assign, __awaiter, __generator, __read, __values } from "tslib";

return __awaiter(this, void 0, void 0, function () {
var config, remoteConfig, samplingConfig_1, privacyConfig, err_1, knownError, samplingConfig, remotePrivacyConfig, localPrivacyConfig, joinedPrivacyConfig, privacyConfigSelectorMap, selectorMap, _d, _e, _f, selector, selectorType;
var e_1, _g;
return __generator(this, function (_h) {
switch (_h.label) {
var config, remoteConfig, samplingConfig_1, privacyConfig, _d, err_1, knownError, samplingConfig, remotePrivacyConfig, localPrivacyConfig, joinedPrivacyConfig, privacyConfigSelectorMap, selectorMap, _e, _f, _g, selector, selectorType;
var e_1, _h;
return __generator(this, function (_j) {
switch (_j.label) {
case 0:

@@ -41,5 +41,5 @@ config = __assign({}, this.localConfig);

config.captureEnabled = true;
_h.label = 1;
_j.label = 1;
case 1:
_h.trys.push([1, 4, , 5]);
_j.trys.push([1, 5, , 6]);
if (!this.remoteConfigFetch) {

@@ -50,6 +50,12 @@ return [2 /*return*/, config];

case 2:
samplingConfig_1 = _h.sent();
samplingConfig_1 = _j.sent();
return [4 /*yield*/, this.remoteConfigFetch.getRemoteConfig('sessionReplay', 'sr_privacy_config', sessionId)];
case 3:
privacyConfig = _h.sent();
privacyConfig = _j.sent();
// This is intentionally forced to only be set through the remote config.
_d = config;
return [4 /*yield*/, this.remoteConfigFetch.getRemoteConfig('sessionReplay', 'sr_interaction_config', sessionId)];
case 4:
// This is intentionally forced to only be set through the remote config.
_d.interactionConfig = _j.sent();
if (samplingConfig_1 || privacyConfig) {

@@ -64,10 +70,10 @@ remoteConfig = {};

}
return [3 /*break*/, 5];
case 4:
err_1 = _h.sent();
return [3 /*break*/, 6];
case 5:
err_1 = _j.sent();
knownError = err_1;
this.localConfig.loggerProvider.warn(knownError.message);
config.captureEnabled = true;
return [3 /*break*/, 5];
case 5:
return [3 /*break*/, 6];
case 6:
if (!remoteConfig) {

@@ -166,4 +172,4 @@ return [2 /*return*/, config];

try {
for (_d = __values(Object.entries(selectorMap)), _e = _d.next(); !_e.done; _e = _d.next()) {
_f = __read(_e.value, 2), selector = _f[0], selectorType = _f[1];
for (_e = __values(Object.entries(selectorMap)), _f = _e.next(); !_f.done; _f = _e.next()) {
_g = __read(_f.value, 2), selector = _g[0], selectorType = _g[1];
if (selectorType === 'mask') {

@@ -183,3 +189,3 @@ joinedPrivacyConfig.maskSelector.push(selector);

try {
if (_e && !_e.done && (_g = _d.return)) _g.call(_d);
if (_f && !_f.done && (_h = _e.return)) _h.call(_e);
}

@@ -186,0 +192,0 @@ finally { if (e_1) throw e_1.error; }

@@ -5,3 +5,3 @@ import { FetchTransport } from '@amplitude/analytics-client-common';

import { SessionReplayOptions } from '../typings/session-replay';
import { SessionReplayLocalConfig as ISessionReplayLocalConfig, PrivacyConfig } from './types';
import { SessionReplayLocalConfig as ISessionReplayLocalConfig, InteractionConfig, PrivacyConfig } from './types';
export declare const getDefaultConfig: () => {

@@ -17,2 +17,3 @@ flushMaxRetries: number;

privacyConfig?: PrivacyConfig;
interactionConfig?: InteractionConfig;
debugMode?: boolean;

@@ -19,0 +20,0 @@ configEndpointUrl?: string;

@@ -6,5 +6,10 @@ import { Config, LogLevel, Logger } from '@amplitude/analytics-types';

}
export interface InteractionConfig {
trackEveryNms?: number;
enabled: boolean;
}
export type SessionReplayRemoteConfig = {
sr_sampling_config?: SamplingConfig;
sr_privacy_config?: PrivacyConfig;
sr_interaction_config?: InteractionConfig;
};

@@ -37,2 +42,3 @@ export interface SessionReplayRemoteConfigAPIResponse {

captureEnabled?: boolean;
interactionConfig?: InteractionConfig;
}

@@ -39,0 +45,0 @@ export interface SessionReplayRemoteConfigFetch {

@@ -17,2 +17,4 @@ import { ServerZone } from '@amplitude/analytics-types';

export declare const MAX_EVENT_LIST_SIZE_IN_BYTES: number;
export declare const INTERACTION_MIN_INTERVAL = 30000;
export declare const INTERACTION_MAX_INTERVAL = 60000;
export declare const MIN_INTERVAL = 500;

@@ -19,0 +21,0 @@ export declare const MAX_INTERVAL: number;

@@ -18,2 +18,4 @@ import { AMPLITUDE_PREFIX } from '@amplitude/analytics-core';

export var MAX_EVENT_LIST_SIZE_IN_BYTES = 1 * 1000000; // 1 MB
export var INTERACTION_MIN_INTERVAL = 30000; // 30 seconds
export var INTERACTION_MAX_INTERVAL = 60000; // 1 minute
export var MIN_INTERVAL = 500; // 500 ms

@@ -20,0 +22,0 @@ export var MAX_INTERVAL = 10 * 1000; // 10 seconds

import { Logger as ILogger } from '@amplitude/analytics-types';
import { DBSchema, IDBPDatabase } from 'idb';
import { SessionReplayEventsIDBStore as AmplitudeSessionReplayEventsIDBStore, Events, SendingSequencesIDBInput } from '../typings/session-replay';
import { SessionReplayEventsIDBStore as AmplitudeSessionReplayEventsIDBStore, EventType, Events, SendingSequencesIDBInput } from '../typings/session-replay';
export declare const currentSequenceKey = "sessionCurrentSequence";

@@ -37,7 +37,11 @@ export declare const sequencesToSendKey = "sequencesToSend";

timeAtLastSplit: number | null;
constructor({ loggerProvider, apiKey }: {
private readonly minInterval;
private readonly maxInterval;
constructor({ loggerProvider, apiKey, minInterval, maxInterval, }: {
loggerProvider: ILogger;
apiKey: string;
minInterval?: number;
maxInterval?: number;
});
initialize(sessionId?: number): Promise<void>;
initialize(type: EventType, sessionId?: number): Promise<void>;
/**

@@ -65,7 +69,10 @@ * Determines whether to send the events list to the backend and start a new

}
export declare const createEventsIDBStore: ({ loggerProvider, apiKey, sessionId, }: {
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>;
//# sourceMappingURL=events-idb-store.d.ts.map

@@ -87,7 +87,6 @@ import { __assign, __awaiter, __generator } from "tslib";

function SessionReplayEventsIDBStore(_a) {
var loggerProvider = _a.loggerProvider, apiKey = _a.apiKey;
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.interval = MIN_INTERVAL;
this.timeAtLastSplit = null;

@@ -106,4 +105,7 @@ /**

}
if (_this.timeAtLastSplit !== null && Date.now() - _this.timeAtLastSplit > _this.interval && events.length) {
_this.interval = Math.min(MAX_INTERVAL, _this.interval + MIN_INTERVAL);
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();

@@ -172,3 +174,8 @@ return true;

case 0:
_b.trys.push([0, 10, , 11]);
if (this.interval === 0) {
this.interval = this.minInterval;
}
_b.label = 1;
case 1:
_b.trys.push([1, 11, , 12]);
tx = (_a = this.db) === null || _a === void 0 ? void 0 : _a.transaction(currentSequenceKey, 'readwrite');

@@ -179,27 +186,27 @@ if (!tx) {

return [4 /*yield*/, tx.store.get(sessionId)];
case 1:
case 2:
sequenceEvents = _b.sent();
if (!!sequenceEvents) return [3 /*break*/, 3];
if (!!sequenceEvents) return [3 /*break*/, 4];
return [4 /*yield*/, tx.store.put({ sessionId: sessionId, events: [event] })];
case 2:
case 3:
_b.sent();
return [2 /*return*/];
case 3:
case 4:
eventsToSend = void 0;
if (!this.shouldSplitEventsList(sequenceEvents.events, event)) return [3 /*break*/, 5];
if (!this.shouldSplitEventsList(sequenceEvents.events, event)) return [3 /*break*/, 6];
eventsToSend = sequenceEvents.events;
// set store to empty array
return [4 /*yield*/, tx.store.put({ sessionId: sessionId, events: [event] })];
case 4:
case 5:
// set store to empty array
_b.sent();
return [3 /*break*/, 7];
case 5:
return [3 /*break*/, 8];
case 6:
updatedEvents = sequenceEvents.events.concat(event);
return [4 /*yield*/, tx.store.put({ sessionId: sessionId, events: updatedEvents })];
case 6:
case 7:
_b.sent();
_b.label = 7;
case 7: return [4 /*yield*/, tx.done];
case 8:
_b.label = 8;
case 8: return [4 /*yield*/, tx.done];
case 9:
_b.sent();

@@ -210,3 +217,3 @@ if (!eventsToSend) {

return [4 /*yield*/, this.storeSendingEvents(sessionId, eventsToSend)];
case 9:
case 10:
sequenceId = _b.sent();

@@ -221,7 +228,7 @@ if (!sequenceId) {

}];
case 10:
case 11:
e_3 = _b.sent();
this.loggerProvider.warn("".concat(STORAGE_FAILURE, ": ").concat(e_3));
return [3 /*break*/, 11];
case 11: return [2 /*return*/, undefined];
return [3 /*break*/, 12];
case 12: return [2 /*return*/, undefined];
}

@@ -378,10 +385,14 @@ });

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;
}
SessionReplayEventsIDBStore.prototype.initialize = function (sessionId) {
SessionReplayEventsIDBStore.prototype.initialize = function (type, sessionId) {
return __awaiter(this, void 0, void 0, function () {
var dbName, _a;
var dbSuffix, dbName, _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
dbName = "".concat(this.apiKey.substring(0, 10), "_amp_session_replay_events");
dbSuffix = type === 'replay' ? '' : "_".concat(type);
dbName = "".concat(this.apiKey.substring(0, 10), "_amp_session_replay_events").concat(dbSuffix);
_a = this;

@@ -404,3 +415,3 @@ return [4 /*yield*/, createStore(dbName)];

export var createEventsIDBStore = function (_a) {
var loggerProvider = _a.loggerProvider, apiKey = _a.apiKey, sessionId = _a.sessionId;
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 () {

@@ -411,4 +422,4 @@ var eventsIDBStore;

case 0:
eventsIDBStore = new SessionReplayEventsIDBStore({ loggerProvider: loggerProvider, apiKey: apiKey });
return [4 /*yield*/, eventsIDBStore.initialize(sessionId)];
eventsIDBStore = new SessionReplayEventsIDBStore({ loggerProvider: loggerProvider, apiKey: apiKey, minInterval: minInterval, maxInterval: maxInterval });
return [4 /*yield*/, eventsIDBStore.initialize(type, sessionId)];
case 1:

@@ -415,0 +426,0 @@ _b.sent();

@@ -1,7 +0,12 @@

import { SessionReplayEventsManager as AmplitudeSessionReplayEventsManager } from '../typings/session-replay';
import { SessionReplayEventsManager as AmplitudeSessionReplayEventsManager, EventType } from '../typings/session-replay';
import { SessionReplayJoinedConfig } from '../config/types';
export declare const createEventsManager: ({ config, sessionId, }: {
import { PayloadBatcher } from '../track-destination';
export declare const createEventsManager: <Type extends EventType>({ config, sessionId, minInterval, maxInterval, type, payloadBatcher, }: {
config: SessionReplayJoinedConfig;
type: Type;
minInterval?: number | undefined;
maxInterval?: number | undefined;
sessionId?: number | undefined;
}) => Promise<AmplitudeSessionReplayEventsManager>;
payloadBatcher?: PayloadBatcher | undefined;
}) => Promise<AmplitudeSessionReplayEventsManager<Type, string>>;
//# sourceMappingURL=events-manager.d.ts.map
import { __awaiter, __generator } from "tslib";
import { createEventsIDBStore } from './events-idb-store';
import { SessionReplayTrackDestination } from '../track-destination';
import { createEventsIDBStore } from './events-idb-store';
export var createEventsManager = function (_a) {
var config = _a.config, sessionId = _a.sessionId;
var config = _a.config, sessionId = _a.sessionId, minInterval = _a.minInterval, maxInterval = _a.maxInterval, type = _a.type, payloadBatcher = _a.payloadBatcher;
return __awaiter(void 0, void 0, void 0, function () {

@@ -11,6 +11,3 @@ function flush(useRetry) {

return __generator(this, function (_a) {
if (trackDestination) {
return [2 /*return*/, trackDestination.flush(useRetry)];
}
return [2 /*return*/];
return [2 /*return*/, trackDestination.flush(useRetry)];
});

@@ -23,3 +20,3 @@ });

case 0:
trackDestination = new SessionReplayTrackDestination({ loggerProvider: config.loggerProvider });
trackDestination = new SessionReplayTrackDestination({ loggerProvider: config.loggerProvider, payloadBatcher: payloadBatcher });
return [4 /*yield*/, createEventsIDBStore({

@@ -29,2 +26,5 @@ loggerProvider: config.loggerProvider,

sessionId: sessionId,
minInterval: minInterval,
maxInterval: maxInterval,
type: type,
})];

@@ -44,2 +44,3 @@ case 1:

serverZone: config.serverZone,
type: type,
onComplete: eventsIDBStore.cleanUpSessionEventsStore.bind(eventsIDBStore),

@@ -92,3 +93,3 @@ });

eventsIDBStore
.addEventToCurrentSequence(sessionId, event)
.addEventToCurrentSequence(sessionId, event.data)
.then(function (sequenceToSend) {

@@ -95,0 +96,0 @@ return (sequenceToSend &&

@@ -10,3 +10,3 @@ import { Logger as ILogger } from '@amplitude/analytics-types';

identifiers: ISessionIdentifiers | undefined;
eventsManager: AmplitudeSessionReplayEventsManager | undefined;
eventsManager?: AmplitudeSessionReplayEventsManager<'replay' | 'interaction', string>;
loggerProvider: ILogger;

@@ -36,5 +36,5 @@ recordCancelCallback: ReturnType<typeof record> | null;

getSessionId(): number | undefined;
flush(useRetry?: boolean): Promise<void>;
flush(useRetry?: boolean): Promise<void | undefined>;
shutdown(): void;
}
//# sourceMappingURL=session-replay.d.ts.map

@@ -1,2 +0,2 @@

import { __awaiter, __generator } from "tslib";
import { __awaiter, __generator, __read, __spreadArray } from "tslib";
import { getAnalyticsConnector, getGlobalScope } from '@amplitude/analytics-client-common';

@@ -6,6 +6,8 @@ import { Logger, returnWrapper } from '@amplitude/analytics-core';

import { createSessionReplayJoinedConfigGenerator } from './config/joined-config';
import { BLOCK_CLASS, DEFAULT_SESSION_REPLAY_PROPERTY, MASK_TEXT_CLASS, SESSION_REPLAY_DEBUG_PROPERTY, } from './constants';
import { BLOCK_CLASS, DEFAULT_SESSION_REPLAY_PROPERTY, INTERACTION_MAX_INTERVAL, INTERACTION_MIN_INTERVAL, MASK_TEXT_CLASS, SESSION_REPLAY_DEBUG_PROPERTY, } from './constants';
import { createEventsManager } from './events/events-manager';
import { generateHashCode, isSessionInSample, maskFn } from './helpers';
import { SessionIdentifiers } from './identifiers';
import { clickBatcher, clickHook } from './hooks/click';
import { MultiEventManager } from './events/multi-manager';
var SessionReplay = /** @class */ (function () {

@@ -70,26 +72,44 @@ function SessionReplay() {

SessionReplay.prototype._init = function (apiKey, options) {
var _a, _b;
return __awaiter(this, void 0, void 0, function () {
var _a, _b, _c, globalScope;
return __generator(this, function (_d) {
switch (_d.label) {
var _c, _d, managers, rrwebEventManager, interactionEventManager, globalScope;
return __generator(this, function (_e) {
switch (_e.label) {
case 0:
this.loggerProvider = options.loggerProvider || new Logger();
this.identifiers = new SessionIdentifiers({ sessionId: options.sessionId, deviceId: options.deviceId });
_a = this;
_c = this;
return [4 /*yield*/, createSessionReplayJoinedConfigGenerator(apiKey, options)];
case 1:
_a.joinedConfigGenerator = _d.sent();
_b = this;
_c.joinedConfigGenerator = _e.sent();
_d = this;
return [4 /*yield*/, this.joinedConfigGenerator.generateJoinedConfig(this.identifiers.sessionId)];
case 2:
_b.config = _d.sent();
_d.config = _e.sent();
this.loggerProvider.debug(JSON.stringify({ name: 'session replay joined privacy config', privacyConfig: this.config.privacyConfig }, null, 2));
this.removeInvalidSelectors();
_c = this;
managers = [];
return [4 /*yield*/, createEventsManager({
config: this.config,
sessionId: this.identifiers.sessionId,
type: 'replay',
})];
case 3:
_c.eventsManager = _d.sent();
rrwebEventManager = _e.sent();
managers.push({ name: 'replay', manager: rrwebEventManager });
if (!((_a = this.config.interactionConfig) === null || _a === void 0 ? void 0 : _a.enabled)) return [3 /*break*/, 5];
return [4 /*yield*/, createEventsManager({
config: this.config,
sessionId: this.identifiers.sessionId,
type: 'interaction',
minInterval: (_b = this.config.interactionConfig.trackEveryNms) !== null && _b !== void 0 ? _b : INTERACTION_MIN_INTERVAL,
maxInterval: INTERACTION_MAX_INTERVAL,
payloadBatcher: clickBatcher,
})];
case 4:
interactionEventManager = _e.sent();
managers.push({ name: 'interaction', manager: interactionEventManager });
_e.label = 5;
case 5:
this.eventsManager = new (MultiEventManager.bind.apply(MultiEventManager, __spreadArray([void 0], __read(managers), false)))();
this.loggerProvider.log('Installing @amplitude/session-replay-browser.');

@@ -194,7 +214,3 @@ globalScope = getGlobalScope();

}
this.eventsManager &&
shouldSendStoredEvents &&
this.eventsManager.sendStoredEvents({
deviceId: deviceId,
});
this.eventsManager && shouldSendStoredEvents && this.eventsManager.sendStoredEvents({ deviceId: deviceId });
this.recordEvents();

@@ -277,6 +293,16 @@ };

var deviceId = _this.getDeviceId();
deviceId && _this.eventsManager && _this.eventsManager.addEvent({ event: eventString, sessionId: sessionId, deviceId: deviceId });
_this.eventsManager &&
deviceId &&
_this.eventsManager.addEvent({ event: { type: 'replay', data: eventString }, sessionId: sessionId, deviceId: deviceId });
},
packFn: pack,
inlineStylesheet: this.config.shouldInlineStylesheet,
hooks: {
mouseInteraction: this.eventsManager &&
clickHook({
eventsManager: this.eventsManager,
sessionId: sessionId,
deviceIdFn: this.getDeviceId.bind(this),
}),
},
maskAllInputs: true,

@@ -324,9 +350,7 @@ maskTextClass: MASK_TEXT_CLASS,

SessionReplay.prototype.flush = function (useRetry) {
var _a;
if (useRetry === void 0) { useRetry = false; }
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
if (this.eventsManager) {
return [2 /*return*/, this.eventsManager.flush(useRetry)];
}
return [2 /*return*/];
return __generator(this, function (_b) {
return [2 /*return*/, (_a = this.eventsManager) === null || _a === void 0 ? void 0 : _a.flush(useRetry)];
});

@@ -333,0 +357,0 @@ });

import { Logger as ILogger, ServerZone } from '@amplitude/analytics-types';
import { SessionReplayTrackDestination as AmplitudeSessionReplayTrackDestination, SessionReplayDestination, SessionReplayDestinationContext } from './typings/session-replay';
export type PayloadBatcher = ({ version, events }: {
version: number;
events: string[];
}) => {
version: number;
events: unknown[];
};
export declare class SessionReplayTrackDestination implements AmplitudeSessionReplayTrackDestination {

@@ -8,5 +15,7 @@ loggerProvider: ILogger;

private scheduled;
payloadBatcher: PayloadBatcher;
queue: SessionReplayDestinationContext[];
constructor({ loggerProvider }: {
constructor({ loggerProvider, payloadBatcher }: {
loggerProvider: ILogger;
payloadBatcher?: PayloadBatcher;
});

@@ -13,0 +22,0 @@ sendEventsList(destinationData: SessionReplayDestination): void;

@@ -10,3 +10,3 @@ import { __assign, __awaiter, __generator } from "tslib";

function SessionReplayTrackDestination(_a) {
var loggerProvider = _a.loggerProvider;
var loggerProvider = _a.loggerProvider, payloadBatcher = _a.payloadBatcher;
this.storageKey = '';

@@ -17,2 +17,3 @@ this.retryTimeout = 1000;

this.loggerProvider = loggerProvider;
this.payloadBatcher = payloadBatcher ? payloadBatcher : function (payload) { return payload; };
}

@@ -118,7 +119,12 @@ SessionReplayTrackDestination.prototype.sendEventsList = function (destinationData) {

seq_number: "".concat(context.sequenceId),
type: "".concat(context.type),
});
payload = {
payload = this.payloadBatcher({
version: 1,
events: context.events,
};
});
if (payload.events.length === 0) {
this.completeRequest({ context: context });
return [2 /*return*/];
}
_a.label = 1;

@@ -125,0 +131,0 @@ case 1:

import { AmplitudeReturn, ServerZone } from '@amplitude/analytics-types';
import { SessionReplayLocalConfig } from '../config/types';
export type Events = string[];
export type EventType = 'replay' | 'interaction';
export interface SessionReplayDestination {
events: Events;
sequenceId: number;
type: EventType;
sessionId: number;

@@ -26,5 +28,12 @@ flushMaxRetries?: number;

export interface SessionReplayEventsIDBStore {
initialize(): Promise<void>;
initialize(type: EventType): Promise<void>;
getSequencesToSend(): Promise<SendingSequencesIDBReturn[] | undefined>;
/**
* Moves current sequence of events to long term storage and resets short term storage.
*/
storeCurrentSequence(sessionId: number): Promise<SendingSequencesIDBInput | undefined>;
/**
* Adds events to the current IDB sequence. Returns events that should be
* sent to the track destination right away if should split events is true.
*/
addEventToCurrentSequence(sessionId: number, event: string): Promise<SendingSequencesIDBReturn | undefined>;

@@ -51,14 +60,36 @@ storeSendingEvents(sessionId: number, events: Events): Promise<number | undefined>;

export interface SessionReplayTrackDestination {
/**
* Enqueues events to be sent.
*/
sendEventsList: (destinationData: SessionReplayDestination) => void;
/**
* Immediately sends queued events.
*/
flush: (useRetry: boolean) => Promise<void>;
}
export interface SessionReplayEventsManager {
export type EventsManagerWithType<EventType, EventDataType> = {
name: EventType;
manager: SessionReplayEventsManager<EventType, EventDataType>;
};
export interface SessionReplayEventsManager<Type, Event> {
/**
* For each sequence stored in the long term indexed DB send immediately to the track destination.
*/
sendStoredEvents({ deviceId }: {
deviceId: string;
}): Promise<void>;
addEvent({ sessionId, event, deviceId }: {
/**
* Adds an event to the short term storage. If should split based on size or last sent, then send immediately.
*/
addEvent({ sessionId, event, deviceId, }: {
sessionId: number;
event: string;
event: {
type: Type;
data: Event;
};
deviceId: string;
}): void;
/**
* Move events in short term storage to long term storage and send immediately to the track destination.
*/
sendCurrentSequenceEvents({ sessionId, deviceId }: {

@@ -68,4 +99,7 @@ sessionId: number;

}): void;
/**
* Flush the track destination queue immediately. This should invoke sends for all the events in the queue.
*/
flush(useRetry?: boolean): Promise<void>;
}
//# sourceMappingURL=session-replay.d.ts.map

@@ -5,3 +5,3 @@ import { FetchTransport } from '@amplitude/analytics-client-common';

import { SessionReplayOptions } from '../typings/session-replay';
import { SessionReplayLocalConfig as ISessionReplayLocalConfig, PrivacyConfig } from './types';
import { SessionReplayLocalConfig as ISessionReplayLocalConfig, InteractionConfig, PrivacyConfig } from './types';
export declare const getDefaultConfig: () => {

@@ -17,2 +17,3 @@ flushMaxRetries: number;

privacyConfig?: PrivacyConfig;
interactionConfig?: InteractionConfig;
debugMode?: boolean;

@@ -19,0 +20,0 @@ configEndpointUrl?: string;

@@ -6,5 +6,10 @@ import { Config, LogLevel, Logger } from '@amplitude/analytics-types';

}
export interface InteractionConfig {
trackEveryNms?: number;
enabled: boolean;
}
export type SessionReplayRemoteConfig = {
sr_sampling_config?: SamplingConfig;
sr_privacy_config?: PrivacyConfig;
sr_interaction_config?: InteractionConfig;
};

@@ -37,2 +42,3 @@ export interface SessionReplayRemoteConfigAPIResponse {

captureEnabled?: boolean;
interactionConfig?: InteractionConfig;
}

@@ -39,0 +45,0 @@ export interface SessionReplayRemoteConfigFetch {

@@ -17,2 +17,4 @@ import { ServerZone } from '@amplitude/analytics-types';

export declare const MAX_EVENT_LIST_SIZE_IN_BYTES: number;
export declare const INTERACTION_MIN_INTERVAL = 30000;
export declare const INTERACTION_MAX_INTERVAL = 60000;
export declare const MIN_INTERVAL = 500;

@@ -19,0 +21,0 @@ export declare const MAX_INTERVAL: number;

import { Logger as ILogger } from '@amplitude/analytics-types';
import { DBSchema, IDBPDatabase } from 'idb';
import { SessionReplayEventsIDBStore as AmplitudeSessionReplayEventsIDBStore, Events, SendingSequencesIDBInput } from '../typings/session-replay';
import { SessionReplayEventsIDBStore as AmplitudeSessionReplayEventsIDBStore, EventType, Events, SendingSequencesIDBInput } from '../typings/session-replay';
export declare const currentSequenceKey = "sessionCurrentSequence";

@@ -37,7 +37,11 @@ export declare const sequencesToSendKey = "sequencesToSend";

timeAtLastSplit: number | null;
constructor({ loggerProvider, apiKey }: {
private readonly minInterval;
private readonly maxInterval;
constructor({ loggerProvider, apiKey, minInterval, maxInterval, }: {
loggerProvider: ILogger;
apiKey: string;
minInterval?: number;
maxInterval?: number;
});
initialize(sessionId?: number): Promise<void>;
initialize(type: EventType, sessionId?: number): Promise<void>;
/**

@@ -65,7 +69,10 @@ * Determines whether to send the events list to the backend and start a new

}
export declare const createEventsIDBStore: ({ loggerProvider, apiKey, sessionId, }: {
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>;
//# sourceMappingURL=events-idb-store.d.ts.map

@@ -1,7 +0,12 @@

import { SessionReplayEventsManager as AmplitudeSessionReplayEventsManager } from '../typings/session-replay';
import { SessionReplayEventsManager as AmplitudeSessionReplayEventsManager, EventType } from '../typings/session-replay';
import { SessionReplayJoinedConfig } from '../config/types';
export declare const createEventsManager: ({ config, sessionId, }: {
import { PayloadBatcher } from '../track-destination';
export declare const createEventsManager: <Type extends EventType>({ config, sessionId, minInterval, maxInterval, type, payloadBatcher, }: {
config: SessionReplayJoinedConfig;
type: Type;
minInterval?: number | undefined;
maxInterval?: number | undefined;
sessionId?: number | undefined;
}) => Promise<AmplitudeSessionReplayEventsManager>;
payloadBatcher?: PayloadBatcher | undefined;
}) => Promise<AmplitudeSessionReplayEventsManager<Type, string>>;
//# sourceMappingURL=events-manager.d.ts.map

@@ -10,3 +10,3 @@ import { Logger as ILogger } from '@amplitude/analytics-types';

identifiers: ISessionIdentifiers | undefined;
eventsManager: AmplitudeSessionReplayEventsManager | undefined;
eventsManager?: AmplitudeSessionReplayEventsManager<'replay' | 'interaction', string>;
loggerProvider: ILogger;

@@ -36,5 +36,5 @@ recordCancelCallback: ReturnType<typeof record> | null;

getSessionId(): number | undefined;
flush(useRetry?: boolean): Promise<void>;
flush(useRetry?: boolean): Promise<void | undefined>;
shutdown(): void;
}
//# sourceMappingURL=session-replay.d.ts.map
import { Logger as ILogger, ServerZone } from '@amplitude/analytics-types';
import { SessionReplayTrackDestination as AmplitudeSessionReplayTrackDestination, SessionReplayDestination, SessionReplayDestinationContext } from './typings/session-replay';
export type PayloadBatcher = ({ version, events }: {
version: number;
events: string[];
}) => {
version: number;
events: unknown[];
};
export declare class SessionReplayTrackDestination implements AmplitudeSessionReplayTrackDestination {

@@ -8,5 +15,7 @@ loggerProvider: ILogger;

private scheduled;
payloadBatcher: PayloadBatcher;
queue: SessionReplayDestinationContext[];
constructor({ loggerProvider }: {
constructor({ loggerProvider, payloadBatcher }: {
loggerProvider: ILogger;
payloadBatcher?: PayloadBatcher;
});

@@ -13,0 +22,0 @@ sendEventsList(destinationData: SessionReplayDestination): void;

import { AmplitudeReturn, ServerZone } from '@amplitude/analytics-types';
import { SessionReplayLocalConfig } from '../config/types';
export type Events = string[];
export type EventType = 'replay' | 'interaction';
export interface SessionReplayDestination {
events: Events;
sequenceId: number;
type: EventType;
sessionId: number;

@@ -26,5 +28,12 @@ flushMaxRetries?: number;

export interface SessionReplayEventsIDBStore {
initialize(): Promise<void>;
initialize(type: EventType): Promise<void>;
getSequencesToSend(): Promise<SendingSequencesIDBReturn[] | undefined>;
/**
* Moves current sequence of events to long term storage and resets short term storage.
*/
storeCurrentSequence(sessionId: number): Promise<SendingSequencesIDBInput | undefined>;
/**
* Adds events to the current IDB sequence. Returns events that should be
* sent to the track destination right away if should split events is true.
*/
addEventToCurrentSequence(sessionId: number, event: string): Promise<SendingSequencesIDBReturn | undefined>;

@@ -51,14 +60,36 @@ storeSendingEvents(sessionId: number, events: Events): Promise<number | undefined>;

export interface SessionReplayTrackDestination {
/**
* Enqueues events to be sent.
*/
sendEventsList: (destinationData: SessionReplayDestination) => void;
/**
* Immediately sends queued events.
*/
flush: (useRetry: boolean) => Promise<void>;
}
export interface SessionReplayEventsManager {
export type EventsManagerWithType<EventType, EventDataType> = {
name: EventType;
manager: SessionReplayEventsManager<EventType, EventDataType>;
};
export interface SessionReplayEventsManager<Type, Event> {
/**
* For each sequence stored in the long term indexed DB send immediately to the track destination.
*/
sendStoredEvents({ deviceId }: {
deviceId: string;
}): Promise<void>;
addEvent({ sessionId, event, deviceId }: {
/**
* Adds an event to the short term storage. If should split based on size or last sent, then send immediately.
*/
addEvent({ sessionId, event, deviceId, }: {
sessionId: number;
event: string;
event: {
type: Type;
data: Event;
};
deviceId: string;
}): void;
/**
* Move events in short term storage to long term storage and send immediately to the track destination.
*/
sendCurrentSequenceEvents({ sessionId, deviceId }: {

@@ -68,4 +99,7 @@ sessionId: number;

}): void;
/**
* Flush the track destination queue immediately. This should invoke sends for all the events in the queue.
*/
flush(useRetry?: boolean): Promise<void>;
}
//# sourceMappingURL=session-replay.d.ts.map
{
"name": "@amplitude/session-replay-browser",
"version": "1.8.0",
"version": "1.9.0",
"description": "",

@@ -31,2 +31,3 @@ "author": "Amplitude Inc",

"lint:prettier": "prettier --check \"{src,test}/**/*.ts\"",
"postinstall": "rimraf ../../node_modules/@medv/finder/finder.ts # This is required until the package is fixed upstream",
"publish": "node ../../scripts/publish/upload-to-s3.js",

@@ -47,2 +48,3 @@ "test": "jest",

"@amplitude/rrweb": "^2.0.0-alpha.14",
"@medv/finder": "^3.2.0",
"idb": "^8.0.0",

@@ -52,2 +54,4 @@ "tslib": "^2.4.1"

"devDependencies": {
"@babel/core": "^7.24.7",
"@babel/plugin-transform-modules-commonjs": "^7.24.7",
"@rollup/plugin-commonjs": "^23.0.4",

@@ -57,2 +61,3 @@ "@rollup/plugin-node-resolve": "^15.0.1",

"@ungap/structured-clone": "^1.2.0",
"babel-jest": "^29.7.0",
"fake-indexeddb": "4.0.2",

@@ -67,3 +72,3 @@ "rollup": "^2.79.1",

],
"gitHead": "0fb81b5ab9736d9761912b85f4b86931f4d0f2a5"
"gitHead": "b90360189f0fd3a2687755da6e2d3db534bd909a"
}

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc