@amplitude/session-replay-browser
Advanced tools
Comparing version 1.13.0 to 1.14.0-srtargeting.0
@@ -62,3 +62,3 @@ var _this = this; | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var config, remoteConfig, samplingConfig_1, privacyConfig, _d, err_1, knownError, samplingConfig, remotePrivacyConfig, localPrivacyConfig, joinedPrivacyConfig, privacyConfigSelectorMap, selectorMap, _e, _f, _g, selector, selectorType; | ||
var config, remoteConfig, samplingConfig_1, privacyConfig, targetingConfig_1, _d, err_1, knownError, samplingConfig, remotePrivacyConfig, targetingConfig, localPrivacyConfig, joinedPrivacyConfig, privacyConfigSelectorMap, selectorMap, _e, _f, _g, selector, selectorType; | ||
var e_1, _h; | ||
@@ -76,3 +76,3 @@ return tslib_1.__generator(this, function (_j) { | ||
case 1: | ||
_j.trys.push([1, 5, , 6]); | ||
_j.trys.push([1, 6, , 7]); | ||
if (!this.remoteConfigFetch) { | ||
@@ -88,6 +88,9 @@ config.captureEnabled = false; | ||
privacyConfig = _j.sent(); | ||
return [4 /*yield*/, this.remoteConfigFetch.getRemoteConfig('sessionReplay', 'sr_targeting_config', sessionId)]; | ||
case 4: | ||
targetingConfig_1 = _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: | ||
case 5: | ||
// This is intentionally forced to only be set through the remote config. | ||
@@ -103,5 +106,8 @@ _d.interactionConfig = _j.sent(); | ||
} | ||
if (targetingConfig_1) { | ||
remoteConfig.sr_targeting_config = targetingConfig_1; | ||
} | ||
} | ||
return [3 /*break*/, 6]; | ||
case 5: | ||
return [3 /*break*/, 7]; | ||
case 6: | ||
err_1 = _j.sent(); | ||
@@ -111,8 +117,8 @@ knownError = err_1; | ||
config.captureEnabled = false; | ||
return [3 /*break*/, 6]; | ||
case 6: | ||
return [3 /*break*/, 7]; | ||
case 7: | ||
if (!remoteConfig) { | ||
return [2 /*return*/, config]; | ||
} | ||
samplingConfig = remoteConfig.sr_sampling_config, remotePrivacyConfig = remoteConfig.sr_privacy_config; | ||
samplingConfig = remoteConfig.sr_sampling_config, remotePrivacyConfig = remoteConfig.sr_privacy_config, targetingConfig = remoteConfig.sr_targeting_config; | ||
if (samplingConfig && Object.keys(samplingConfig).length > 0) { | ||
@@ -229,2 +235,5 @@ if (Object.prototype.hasOwnProperty.call(samplingConfig, 'capture_enabled')) { | ||
} | ||
if (targetingConfig && Object.keys(targetingConfig).length > 0) { | ||
config.targetingConfig = targetingConfig; | ||
} | ||
this.localConfig.loggerProvider.debug(JSON.stringify({ name: 'session replay joined config', config: (0, helpers_1.getDebugConfig)(config) }, null, 2)); | ||
@@ -231,0 +240,0 @@ return [2 /*return*/, config]; |
import { Config, LogLevel, Logger } from '@amplitude/analytics-types'; | ||
import { TargetingFlag } from '@amplitude/targeting'; | ||
export interface SamplingConfig { | ||
@@ -10,2 +11,3 @@ sample_rate: number; | ||
} | ||
export type TargetingConfig = TargetingFlag; | ||
export type SessionReplayRemoteConfig = { | ||
@@ -15,2 +17,3 @@ sr_sampling_config?: SamplingConfig; | ||
sr_interaction_config?: InteractionConfig; | ||
sr_targeting_config?: TargetingConfig; | ||
}; | ||
@@ -41,2 +44,5 @@ export interface SessionReplayRemoteConfigAPIResponse { | ||
version?: SessionReplayVersion; | ||
userProperties?: { | ||
[key: string]: any; | ||
}; | ||
} | ||
@@ -46,2 +52,3 @@ export interface SessionReplayJoinedConfig extends SessionReplayLocalConfig { | ||
interactionConfig?: InteractionConfig; | ||
targetingConfig?: TargetingConfig; | ||
} | ||
@@ -48,0 +55,0 @@ export interface SessionReplayRemoteConfigFetch { |
@@ -23,2 +23,6 @@ import { ServerZone } from '@amplitude/analytics-types'; | ||
export declare const KB_SIZE = 1024; | ||
export declare enum CustomRRwebEvent { | ||
GET_SR_PROPS = "get-sr-props", | ||
DEBUG_INFO = "debug-info" | ||
} | ||
//# sourceMappingURL=constants.d.ts.map |
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.KB_SIZE = 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; | ||
exports.CustomRRwebEvent = exports.KB_SIZE = 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"); | ||
@@ -26,2 +26,7 @@ var analytics_types_1 = require("@amplitude/analytics-types"); | ||
exports.KB_SIZE = 1024; | ||
var CustomRRwebEvent; | ||
(function (CustomRRwebEvent) { | ||
CustomRRwebEvent["GET_SR_PROPS"] = "get-sr-props"; | ||
CustomRRwebEvent["DEBUG_INFO"] = "debug-info"; | ||
})(CustomRRwebEvent = exports.CustomRRwebEvent || (exports.CustomRRwebEvent = {})); | ||
//# sourceMappingURL=constants.js.map |
@@ -14,2 +14,3 @@ import { PrivacyConfig, SessionReplayJoinedConfig } from './config/types'; | ||
interactionConfig?: import("./config/types").InteractionConfig | undefined; | ||
targetingConfig?: import("@amplitude/experiment-core").EvaluationFlag | undefined; | ||
apiKey: string; | ||
@@ -25,2 +26,5 @@ loggerProvider: import("@amplitude/analytics-types").Logger; | ||
version?: import("./config/types").SessionReplayVersion | undefined; | ||
userProperties?: { | ||
[key: string]: any; | ||
} | undefined; | ||
flushIntervalMillis: number; | ||
@@ -27,0 +31,0 @@ flushQueueSize: number; |
@@ -121,6 +121,7 @@ var _this = this; | ||
var getStorageSize = function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var globalScope, _a, usage, quota, usageDetails, totalStorageSize, percentOfQuota; | ||
var globalScope, _a, usage, quota, usageDetails, totalStorageSize, percentOfQuota, e_1; | ||
return tslib_1.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
_b.trys.push([0, 3, , 4]); | ||
globalScope = (0, analytics_client_common_1.getGlobalScope)(); | ||
@@ -134,3 +135,7 @@ if (!globalScope) return [3 /*break*/, 2]; | ||
return [2 /*return*/, { totalStorageSize: totalStorageSize, percentOfQuota: percentOfQuota, usageDetails: JSON.stringify(usageDetails) }]; | ||
case 2: return [2 /*return*/, { totalStorageSize: 0, percentOfQuota: 0, usageDetails: '' }]; | ||
case 2: return [3 /*break*/, 4]; | ||
case 3: | ||
e_1 = _b.sent(); | ||
return [3 /*break*/, 4]; | ||
case 4: return [2 /*return*/, { totalStorageSize: 0, percentOfQuota: 0, usageDetails: '' }]; | ||
} | ||
@@ -137,0 +142,0 @@ }); |
@@ -1,2 +0,6 @@ | ||
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: () => { | ||
export declare const init: (apiKey: string, options: import("./typings/session-replay").SessionReplayOptions) => import("@amplitude/analytics-types").AmplitudeReturn<void>, setSessionId: (sessionId: number, deviceId?: string | undefined, options?: { | ||
userProperties?: { | ||
[key: string]: any; | ||
} | undefined; | ||
} | undefined) => import("@amplitude/analytics-types").AmplitudeReturn<void>, getSessionId: () => number | undefined, evaluateTargetingAndCapture: (targetingParams?: Pick<import("@amplitude/targeting").TargetingParameters, "event" | "userProperties"> | undefined) => Promise<void>, getSessionReplayProperties: () => { | ||
[key: string]: string | boolean | null; | ||
@@ -3,0 +7,0 @@ }, flush: (useRetry: boolean) => Promise<void>, shutdown: () => void; |
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.shutdown = exports.flush = exports.getSessionReplayProperties = exports.getSessionId = exports.setSessionId = exports.init = void 0; | ||
exports.shutdown = exports.flush = exports.getSessionReplayProperties = exports.evaluateTargetingAndCapture = exports.getSessionId = exports.setSessionId = exports.init = void 0; | ||
var tslib_1 = require("tslib"); | ||
var session_replay_factory_1 = tslib_1.__importDefault(require("./session-replay-factory")); | ||
exports.init = session_replay_factory_1.default.init, exports.setSessionId = session_replay_factory_1.default.setSessionId, exports.getSessionId = session_replay_factory_1.default.getSessionId, exports.getSessionReplayProperties = session_replay_factory_1.default.getSessionReplayProperties, exports.flush = session_replay_factory_1.default.flush, exports.shutdown = session_replay_factory_1.default.shutdown; | ||
exports.init = session_replay_factory_1.default.init, exports.setSessionId = session_replay_factory_1.default.setSessionId, exports.getSessionId = session_replay_factory_1.default.getSessionId, exports.evaluateTargetingAndCapture = session_replay_factory_1.default.evaluateTargetingAndCapture, exports.getSessionReplayProperties = session_replay_factory_1.default.getSessionReplayProperties, exports.flush = session_replay_factory_1.default.flush, exports.shutdown = session_replay_factory_1.default.shutdown; | ||
//# sourceMappingURL=index.js.map |
@@ -19,4 +19,5 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
init: (0, analytics_core_1.debugWrapper)(sessionReplay.init.bind(sessionReplay), 'init', (0, exports.getLogConfig)(sessionReplay)), | ||
evaluateTargetingAndCapture: (0, analytics_core_1.debugWrapper)(sessionReplay.evaluateTargetingAndCapture.bind(sessionReplay), 'evaluateTargetingAndRecord', (0, exports.getLogConfig)(sessionReplay)), | ||
setSessionId: (0, analytics_core_1.debugWrapper)(sessionReplay.setSessionId.bind(sessionReplay), 'setSessionId', (0, exports.getLogConfig)(sessionReplay)), | ||
getSessionId: (0, analytics_core_1.debugWrapper)(sessionReplay.getSessionId.bind(sessionReplay), 'getSessionId', (0, exports.getLogConfig)(sessionReplay)), | ||
getSessionId: sessionReplay.getSessionId.bind(sessionReplay), | ||
getSessionReplayProperties: (0, analytics_core_1.debugWrapper)(sessionReplay.getSessionReplayProperties.bind(sessionReplay), 'getSessionReplayProperties', (0, exports.getLogConfig)(sessionReplay)), | ||
@@ -23,0 +24,0 @@ flush: (0, analytics_core_1.debugWrapper)(sessionReplay.flush.bind(sessionReplay), 'flush', (0, exports.getLogConfig)(sessionReplay)), |
import { Logger as ILogger } from '@amplitude/analytics-types'; | ||
import { record } from '@amplitude/rrweb'; | ||
import { TargetingParameters } from '@amplitude/targeting'; | ||
import { SessionReplayJoinedConfig, SessionReplayJoinedConfigGenerator } from './config/types'; | ||
import { AmplitudeSessionReplay, SessionReplayEventsManager as AmplitudeSessionReplayEventsManager, DebugInfo, SessionIdentifiers as ISessionIdentifiers, SessionReplayOptions } from './typings/session-replay'; | ||
import { CustomRRwebEvent } from './constants'; | ||
import { AmplitudeSessionReplay, SessionReplayEventsManager as AmplitudeSessionReplayEventsManager, SessionIdentifiers as ISessionIdentifiers, SessionReplayOptions } from './typings/session-replay'; | ||
type PageLeaveFn = (e: PageTransitionEvent | Event) => void; | ||
@@ -14,2 +16,4 @@ export declare class SessionReplay implements AmplitudeSessionReplay { | ||
recordCancelCallback: ReturnType<typeof record> | null; | ||
eventCount: number; | ||
sessionTargetingMatch: boolean; | ||
pageLeaveFns: PageLeaveFn[]; | ||
@@ -21,4 +25,12 @@ private scrollHook?; | ||
protected _init(apiKey: string, options: SessionReplayOptions): Promise<void>; | ||
setSessionId(sessionId: number, deviceId?: string): import("@amplitude/analytics-types").AmplitudeReturn<void>; | ||
asyncSetSessionId(sessionId: number, deviceId?: string): Promise<void>; | ||
setSessionId(sessionId: number, deviceId?: string, options?: { | ||
userProperties?: { | ||
[key: string]: any; | ||
}; | ||
}): import("@amplitude/analytics-types").AmplitudeReturn<void>; | ||
asyncSetSessionId(sessionId: number, deviceId?: string, options?: { | ||
userProperties?: { | ||
[key: string]: any; | ||
}; | ||
}): Promise<void>; | ||
getSessionReplayDebugPropertyValue(): string; | ||
@@ -36,14 +48,12 @@ getSessionReplayProperties(): { | ||
private pageLeaveListener; | ||
evaluateTargetingAndCapture: (targetingParams?: Pick<TargetingParameters, 'event' | 'userProperties'>) => Promise<void>; | ||
sendEvents(sessionId?: number): void; | ||
initialize(shouldSendStoredEvents?: boolean): void; | ||
shouldOptOut(): boolean | undefined; | ||
getShouldRecord(): boolean; | ||
getShouldCapture(): boolean; | ||
getBlockSelectors(): string | string[] | undefined; | ||
getMaskTextSelectors(): string | undefined; | ||
recordEvents(): void; | ||
/** | ||
* Used to send a debug RRWeb event. Typing is included for ease of debugging later on, but probably not | ||
* used at compile/run time. | ||
*/ | ||
getDebugInfo: () => Promise<DebugInfo | undefined>; | ||
captureEvents(): void; | ||
addCustomRRWebEvent: (eventName: CustomRRwebEvent, eventData?: { | ||
[key: string]: any; | ||
}, addStorageInfo?: boolean) => Promise<void>; | ||
stopRecordingEvents: () => void; | ||
@@ -50,0 +60,0 @@ getDeviceId(): string | undefined; |
@@ -6,2 +6,3 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
var analytics_core_1 = require("@amplitude/analytics-core"); | ||
var analytics_types_1 = require("@amplitude/analytics-types"); | ||
var rrweb_1 = require("@amplitude/rrweb"); | ||
@@ -16,2 +17,3 @@ var joined_config_1 = require("./config/joined-config"); | ||
var identifiers_1 = require("./identifiers"); | ||
var targeting_manager_1 = require("./targeting/targeting-manager"); | ||
var version_1 = require("./version"); | ||
@@ -23,2 +25,4 @@ var SessionReplay = /** @class */ (function () { | ||
this.recordCancelCallback = null; | ||
this.eventCount = 0; | ||
this.sessionTargetingMatch = false; | ||
// Visible for testing | ||
@@ -53,3 +57,4 @@ this.pageLeaveFns = []; | ||
// switches tabs, we take a full snapshot | ||
_this.recordEvents(); | ||
_this.stopRecordingEvents(); | ||
_this.captureEvents(); | ||
}; | ||
@@ -66,24 +71,89 @@ /** | ||
}; | ||
/** | ||
* Used to send a debug RRWeb event. Typing is included for ease of debugging later on, but probably not | ||
* used at compile/run time. | ||
*/ | ||
this.getDebugInfo = function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var storageSizeData; | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
this.evaluateTargetingAndCapture = function (targetingParams) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var eventForTargeting, _a; | ||
return tslib_1.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
if (!this.config) { | ||
if (!this.identifiers || !this.identifiers.sessionId || !this.config) { | ||
if (this.identifiers && !this.identifiers.sessionId) { | ||
this.loggerProvider.log('Session ID has not been set yet, cannot evaluate targeting for Session Replay.'); | ||
} | ||
else { | ||
this.loggerProvider.warn('Session replay init has not been called, cannot evaluate targeting.'); | ||
} | ||
return [2 /*return*/]; | ||
} | ||
return [4 /*yield*/, (0, helpers_1.getStorageSize)()]; | ||
if (!(this.config.targetingConfig && !this.sessionTargetingMatch)) return [3 /*break*/, 2]; | ||
eventForTargeting = targetingParams === null || targetingParams === void 0 ? void 0 : targetingParams.event; | ||
if (eventForTargeting && | ||
Object.values(analytics_types_1.SpecialEventType).includes(eventForTargeting.event_type)) { | ||
eventForTargeting = undefined; | ||
} | ||
// We're setting this on this class because fetching the value from idb | ||
// is async, we need to access this value synchronously (for record | ||
// and for getSessionReplayProperties - both synchronous fns) | ||
_a = this; | ||
return [4 /*yield*/, (0, targeting_manager_1.evaluateTargetingAndStore)({ | ||
sessionId: this.identifiers.sessionId, | ||
targetingConfig: this.config.targetingConfig, | ||
loggerProvider: this.loggerProvider, | ||
apiKey: this.config.apiKey, | ||
targetingParams: { userProperties: targetingParams === null || targetingParams === void 0 ? void 0 : targetingParams.userProperties, event: eventForTargeting }, | ||
})]; | ||
case 1: | ||
storageSizeData = _a.sent(); | ||
return [2 /*return*/, tslib_1.__assign(tslib_1.__assign({}, storageSizeData), { config: (0, helpers_1.getDebugConfig)(this.config), version: version_1.VERSION })]; | ||
// We're setting this on this class because fetching the value from idb | ||
// is async, we need to access this value synchronously (for record | ||
// and for getSessionReplayProperties - both synchronous fns) | ||
_a.sessionTargetingMatch = _b.sent(); | ||
_b.label = 2; | ||
case 2: | ||
this.captureEvents(); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); }; | ||
this.addCustomRRWebEvent = function (eventName, eventData, addStorageInfo) { | ||
if (eventData === void 0) { eventData = {}; } | ||
if (addStorageInfo === void 0) { addStorageInfo = true; } | ||
return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var debugInfo, storageSizeData, e_1; | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
_a.trys.push([0, 3, , 4]); | ||
debugInfo = undefined; | ||
if (!this.config) return [3 /*break*/, 2]; | ||
debugInfo = { | ||
config: (0, helpers_1.getDebugConfig)(this.config), | ||
version: version_1.VERSION, | ||
}; | ||
if (!addStorageInfo) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, (0, helpers_1.getStorageSize)()]; | ||
case 1: | ||
storageSizeData = _a.sent(); | ||
debugInfo = tslib_1.__assign(tslib_1.__assign({}, storageSizeData), debugInfo); | ||
_a.label = 2; | ||
case 2: | ||
// Check first to ensure we are recording | ||
if (this.recordCancelCallback) { | ||
rrweb_1.record.addCustomEvent(eventName, tslib_1.__assign(tslib_1.__assign({}, eventData), debugInfo)); | ||
} | ||
else { | ||
this.loggerProvider.debug("Not able to add custom replay capture event ".concat(eventName, " due to no ongoing recording.")); | ||
} | ||
return [3 /*break*/, 4]; | ||
case 3: | ||
e_1 = _a.sent(); | ||
this.loggerProvider.debug('Error while adding custom replay capture event: ', e_1); | ||
return [3 /*break*/, 4]; | ||
case 4: return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
}; | ||
this.stopRecordingEvents = function () { | ||
try { | ||
_this.loggerProvider.log('Session Replay capture stopping.'); | ||
if (_this.recordCancelCallback) { | ||
_this.loggerProvider.log('Session Replay capture stopping.'); | ||
} | ||
_this.recordCancelCallback && _this.recordCancelCallback(); | ||
@@ -153,5 +223,12 @@ _this.recordCancelCallback = null; | ||
this.eventsManager = new (multi_manager_1.MultiEventManager.bind.apply(multi_manager_1.MultiEventManager, tslib_1.__spreadArray([void 0], tslib_1.__read(managers), false)))(); | ||
this.identifiers.deviceId && | ||
void this.eventsManager.sendStoredEvents({ | ||
deviceId: this.identifiers.deviceId, | ||
}); | ||
this.loggerProvider.log('Installing @amplitude/session-replay-browser.'); | ||
this.teardownEventListeners(false); | ||
this.initialize(true); | ||
this.stopRecordingEvents(); | ||
return [4 /*yield*/, this.evaluateTargetingAndCapture({ userProperties: options.userProperties })]; | ||
case 6: | ||
_f.sent(); | ||
return [2 /*return*/]; | ||
@@ -162,6 +239,6 @@ } | ||
}; | ||
SessionReplay.prototype.setSessionId = function (sessionId, deviceId) { | ||
return (0, analytics_core_1.returnWrapper)(this.asyncSetSessionId(sessionId, deviceId)); | ||
SessionReplay.prototype.setSessionId = function (sessionId, deviceId, options) { | ||
return (0, analytics_core_1.returnWrapper)(this.asyncSetSessionId(sessionId, deviceId, options)); | ||
}; | ||
SessionReplay.prototype.asyncSetSessionId = function (sessionId, deviceId) { | ||
SessionReplay.prototype.asyncSetSessionId = function (sessionId, deviceId, options) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
@@ -172,2 +249,4 @@ var previousSessionId, deviceIdForReplayId, _a; | ||
case 0: | ||
this.stopRecordingEvents(); | ||
this.sessionTargetingMatch = false; | ||
previousSessionId = this.identifiers && this.identifiers.sessionId; | ||
@@ -188,4 +267,5 @@ if (previousSessionId) { | ||
_b.label = 2; | ||
case 2: | ||
this.recordEvents(); | ||
case 2: return [4 /*yield*/, this.evaluateTargetingAndCapture({ userProperties: options === null || options === void 0 ? void 0 : options.userProperties })]; | ||
case 3: | ||
_b.sent(); | ||
return [2 /*return*/]; | ||
@@ -211,5 +291,6 @@ } | ||
} | ||
var shouldRecord = this.getShouldRecord(); | ||
var shouldRecord = this.getShouldCapture(); | ||
var eventProperties = {}; | ||
if (shouldRecord) { | ||
var eventProperties = (_a = {}, | ||
eventProperties = (_a = {}, | ||
_a[constants_1.DEFAULT_SESSION_REPLAY_PROPERTY] = this.identifiers.sessionReplayId ? this.identifiers.sessionReplayId : null, | ||
@@ -220,5 +301,12 @@ _a); | ||
} | ||
return eventProperties; | ||
} | ||
return {}; | ||
void this.addCustomRRWebEvent(constants_1.CustomRRwebEvent.GET_SR_PROPS, { | ||
shouldRecord: shouldRecord, | ||
eventProperties: eventProperties, | ||
}, this.eventCount === 10); | ||
if (this.eventCount === 10) { | ||
this.eventCount = 0; | ||
} | ||
this.eventCount++; | ||
return eventProperties; | ||
}; | ||
@@ -234,17 +322,2 @@ SessionReplay.prototype.sendEvents = function (sessionId) { | ||
}; | ||
SessionReplay.prototype.initialize = function (shouldSendStoredEvents) { | ||
var _a; | ||
if (shouldSendStoredEvents === void 0) { shouldSendStoredEvents = false; } | ||
if (!((_a = this.identifiers) === null || _a === void 0 ? void 0 : _a.sessionId)) { | ||
this.loggerProvider.log("Session is not being recorded due to lack of session id."); | ||
return; | ||
} | ||
var deviceId = this.getDeviceId(); | ||
if (!deviceId) { | ||
this.loggerProvider.log("Session is not being recorded due to lack of device id."); | ||
return; | ||
} | ||
this.eventsManager && shouldSendStoredEvents && this.eventsManager.sendStoredEvents({ deviceId: deviceId }); | ||
this.recordEvents(); | ||
}; | ||
SessionReplay.prototype.shouldOptOut = function () { | ||
@@ -259,5 +332,5 @@ var _a, _b; | ||
}; | ||
SessionReplay.prototype.getShouldRecord = function () { | ||
SessionReplay.prototype.getShouldCapture = function () { | ||
if (!this.identifiers || !this.config || !this.identifiers.sessionId) { | ||
this.loggerProvider.warn("Session is not being recorded due to lack of config, please call sessionReplay.init."); | ||
this.loggerProvider.warn("Session is not being captured due to lack of config, please call sessionReplay.init."); | ||
return false; | ||
@@ -270,10 +343,23 @@ } | ||
if (this.shouldOptOut()) { | ||
this.loggerProvider.log("Opting session ".concat(this.identifiers.sessionId, " out of recording due to optOut config.")); | ||
this.loggerProvider.log("Opting session ".concat(this.identifiers.sessionId, " out of replay capture due to optOut config.")); | ||
return false; | ||
} | ||
var isInSample = (0, helpers_1.isSessionInSample)(this.identifiers.sessionId, this.config.sampleRate); | ||
if (!isInSample) { | ||
this.loggerProvider.log("Opting session ".concat(this.identifiers.sessionId, " out of recording due to sample rate.")); | ||
// If targetingConfig exists, we'll use the sessionTargetingMatch to determine whether to record | ||
// Otherwise, we'll evaluate the session against the overall sample rate | ||
if (this.config.targetingConfig) { | ||
if (!this.sessionTargetingMatch) { | ||
this.loggerProvider.log("Not capturing replays for session ".concat(this.identifiers.sessionId, " due to not matching targeting conditions.")); | ||
return false; | ||
} | ||
this.loggerProvider.log("Capturing replays for session ".concat(this.identifiers.sessionId, " due to matching targeting conditions.")); | ||
} | ||
return isInSample; | ||
else { | ||
var isInSample = (0, helpers_1.isSessionInSample)(this.identifiers.sessionId, this.config.sampleRate); | ||
if (!isInSample) { | ||
this.loggerProvider.log("Opting session ".concat(this.identifiers.sessionId, " out of replay capture due to sample rate.")); | ||
return false; | ||
} | ||
this.loggerProvider.log("Capturing replays for session ".concat(this.identifiers.sessionId, " due to inclusion in sample rate.")); | ||
} | ||
return true; | ||
}; | ||
@@ -302,11 +388,13 @@ SessionReplay.prototype.getBlockSelectors = function () { | ||
}; | ||
SessionReplay.prototype.recordEvents = function () { | ||
SessionReplay.prototype.captureEvents = function () { | ||
var _this = this; | ||
var _a; | ||
var shouldRecord = this.getShouldRecord(); | ||
var sessionId = (_a = this.identifiers) === null || _a === void 0 ? void 0 : _a.sessionId; | ||
if (this.recordCancelCallback) { | ||
this.loggerProvider.debug('captureEvents method fired - Session Replay capture already in progress.'); | ||
return; | ||
} | ||
var shouldRecord = this.getShouldCapture(); | ||
var sessionId = this.identifiers && this.identifiers.sessionId; | ||
if (!shouldRecord || !sessionId || !this.config) { | ||
return; | ||
} | ||
this.stopRecordingEvents(); | ||
var privacyConfig = this.config.privacyConfig; | ||
@@ -317,3 +405,3 @@ this.loggerProvider.log('Session Replay capture beginning.'); | ||
if (_this.shouldOptOut()) { | ||
_this.loggerProvider.log("Opting session ".concat(sessionId, " out of recording due to optOut config.")); | ||
_this.loggerProvider.log("Opting session ".concat(sessionId, " out of replay capture due to optOut config.")); | ||
_this.stopRecordingEvents(); | ||
@@ -367,9 +455,3 @@ _this.sendEvents(); | ||
}); | ||
this.getDebugInfo() | ||
.then(function (debugInfo) { | ||
debugInfo && rrweb_1.record.addCustomEvent('debug-info', debugInfo); | ||
}) | ||
.catch(function () { | ||
// swallow error | ||
}); | ||
void this.addCustomRRWebEvent(constants_1.CustomRRwebEvent.DEBUG_INFO); | ||
}; | ||
@@ -376,0 +458,0 @@ SessionReplay.prototype.getDeviceId = function () { |
import { AmplitudeReturn, ServerZone } from '@amplitude/analytics-types'; | ||
import { SessionReplayJoinedConfig, SessionReplayLocalConfig, SessionReplayVersion } from '../config/types'; | ||
import { TargetingParameters } from '@amplitude/targeting'; | ||
export type StorageData = { | ||
@@ -8,3 +9,3 @@ totalStorageSize: number; | ||
}; | ||
export interface DebugInfo extends StorageData { | ||
export interface DebugInfo extends Partial<StorageData> { | ||
config: SessionReplayJoinedConfig; | ||
@@ -63,3 +64,7 @@ version: string; | ||
init: (apiKey: string, options: SessionReplayOptions) => AmplitudeReturn<void>; | ||
setSessionId: (sessionId: number, deviceId?: string) => AmplitudeReturn<void>; | ||
setSessionId: (sessionId: number, deviceId?: string, options?: { | ||
userProperties?: { | ||
[key: string]: any; | ||
}; | ||
}) => AmplitudeReturn<void>; | ||
getSessionId: () => number | undefined; | ||
@@ -69,2 +74,3 @@ getSessionReplayProperties: () => { | ||
}; | ||
evaluateTargetingAndCapture: (targetingParams?: Pick<TargetingParameters, 'event' | 'userProperties'>) => Promise<void>; | ||
flush: (useRetry: boolean) => Promise<void>; | ||
@@ -71,0 +77,0 @@ shutdown: () => void; |
@@ -1,2 +0,2 @@ | ||
export declare const VERSION = "1.13.0"; | ||
export declare const VERSION = "1.14.0-srtargeting.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.13.0'; | ||
exports.VERSION = '1.14.0-srtargeting.0'; | ||
//# sourceMappingURL=version.js.map |
@@ -58,3 +58,3 @@ import { __assign, __awaiter, __generator, __read, __values } from "tslib"; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var config, remoteConfig, samplingConfig_1, privacyConfig, _d, err_1, knownError, samplingConfig, remotePrivacyConfig, localPrivacyConfig, joinedPrivacyConfig, privacyConfigSelectorMap, selectorMap, _e, _f, _g, selector, selectorType; | ||
var config, remoteConfig, samplingConfig_1, privacyConfig, targetingConfig_1, _d, err_1, knownError, samplingConfig, remotePrivacyConfig, targetingConfig, localPrivacyConfig, joinedPrivacyConfig, privacyConfigSelectorMap, selectorMap, _e, _f, _g, selector, selectorType; | ||
var e_1, _h; | ||
@@ -72,3 +72,3 @@ return __generator(this, function (_j) { | ||
case 1: | ||
_j.trys.push([1, 5, , 6]); | ||
_j.trys.push([1, 6, , 7]); | ||
if (!this.remoteConfigFetch) { | ||
@@ -84,6 +84,9 @@ config.captureEnabled = false; | ||
privacyConfig = _j.sent(); | ||
return [4 /*yield*/, this.remoteConfigFetch.getRemoteConfig('sessionReplay', 'sr_targeting_config', sessionId)]; | ||
case 4: | ||
targetingConfig_1 = _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: | ||
case 5: | ||
// This is intentionally forced to only be set through the remote config. | ||
@@ -99,5 +102,8 @@ _d.interactionConfig = _j.sent(); | ||
} | ||
if (targetingConfig_1) { | ||
remoteConfig.sr_targeting_config = targetingConfig_1; | ||
} | ||
} | ||
return [3 /*break*/, 6]; | ||
case 5: | ||
return [3 /*break*/, 7]; | ||
case 6: | ||
err_1 = _j.sent(); | ||
@@ -107,8 +113,8 @@ knownError = err_1; | ||
config.captureEnabled = false; | ||
return [3 /*break*/, 6]; | ||
case 6: | ||
return [3 /*break*/, 7]; | ||
case 7: | ||
if (!remoteConfig) { | ||
return [2 /*return*/, config]; | ||
} | ||
samplingConfig = remoteConfig.sr_sampling_config, remotePrivacyConfig = remoteConfig.sr_privacy_config; | ||
samplingConfig = remoteConfig.sr_sampling_config, remotePrivacyConfig = remoteConfig.sr_privacy_config, targetingConfig = remoteConfig.sr_targeting_config; | ||
if (samplingConfig && Object.keys(samplingConfig).length > 0) { | ||
@@ -225,2 +231,5 @@ if (Object.prototype.hasOwnProperty.call(samplingConfig, 'capture_enabled')) { | ||
} | ||
if (targetingConfig && Object.keys(targetingConfig).length > 0) { | ||
config.targetingConfig = targetingConfig; | ||
} | ||
this.localConfig.loggerProvider.debug(JSON.stringify({ name: 'session replay joined config', config: getDebugConfig(config) }, null, 2)); | ||
@@ -227,0 +236,0 @@ return [2 /*return*/, config]; |
import { Config, LogLevel, Logger } from '@amplitude/analytics-types'; | ||
import { TargetingFlag } from '@amplitude/targeting'; | ||
export interface SamplingConfig { | ||
@@ -10,2 +11,3 @@ sample_rate: number; | ||
} | ||
export type TargetingConfig = TargetingFlag; | ||
export type SessionReplayRemoteConfig = { | ||
@@ -15,2 +17,3 @@ sr_sampling_config?: SamplingConfig; | ||
sr_interaction_config?: InteractionConfig; | ||
sr_targeting_config?: TargetingConfig; | ||
}; | ||
@@ -41,2 +44,5 @@ export interface SessionReplayRemoteConfigAPIResponse { | ||
version?: SessionReplayVersion; | ||
userProperties?: { | ||
[key: string]: any; | ||
}; | ||
} | ||
@@ -46,2 +52,3 @@ export interface SessionReplayJoinedConfig extends SessionReplayLocalConfig { | ||
interactionConfig?: InteractionConfig; | ||
targetingConfig?: TargetingConfig; | ||
} | ||
@@ -48,0 +55,0 @@ export interface SessionReplayRemoteConfigFetch { |
@@ -23,2 +23,6 @@ import { ServerZone } from '@amplitude/analytics-types'; | ||
export declare const KB_SIZE = 1024; | ||
export declare enum CustomRRwebEvent { | ||
GET_SR_PROPS = "get-sr-props", | ||
DEBUG_INFO = "debug-info" | ||
} | ||
//# sourceMappingURL=constants.d.ts.map |
@@ -24,2 +24,7 @@ import { AMPLITUDE_PREFIX } from '@amplitude/analytics-core'; | ||
export var KB_SIZE = 1024; | ||
export var CustomRRwebEvent; | ||
(function (CustomRRwebEvent) { | ||
CustomRRwebEvent["GET_SR_PROPS"] = "get-sr-props"; | ||
CustomRRwebEvent["DEBUG_INFO"] = "debug-info"; | ||
})(CustomRRwebEvent || (CustomRRwebEvent = {})); | ||
//# sourceMappingURL=constants.js.map |
@@ -14,2 +14,3 @@ import { PrivacyConfig, SessionReplayJoinedConfig } from './config/types'; | ||
interactionConfig?: import("./config/types").InteractionConfig | undefined; | ||
targetingConfig?: import("@amplitude/experiment-core").EvaluationFlag | undefined; | ||
apiKey: string; | ||
@@ -25,2 +26,5 @@ loggerProvider: import("@amplitude/analytics-types").Logger; | ||
version?: import("./config/types").SessionReplayVersion | undefined; | ||
userProperties?: { | ||
[key: string]: any; | ||
} | undefined; | ||
flushIntervalMillis: number; | ||
@@ -27,0 +31,0 @@ flushQueueSize: number; |
@@ -112,6 +112,7 @@ import { __assign, __awaiter, __generator } from "tslib"; | ||
export var getStorageSize = function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var globalScope, _a, usage, quota, usageDetails, totalStorageSize, percentOfQuota; | ||
var globalScope, _a, usage, quota, usageDetails, totalStorageSize, percentOfQuota, e_1; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
_b.trys.push([0, 3, , 4]); | ||
globalScope = getGlobalScope(); | ||
@@ -125,3 +126,7 @@ if (!globalScope) return [3 /*break*/, 2]; | ||
return [2 /*return*/, { totalStorageSize: totalStorageSize, percentOfQuota: percentOfQuota, usageDetails: JSON.stringify(usageDetails) }]; | ||
case 2: return [2 /*return*/, { totalStorageSize: 0, percentOfQuota: 0, usageDetails: '' }]; | ||
case 2: return [3 /*break*/, 4]; | ||
case 3: | ||
e_1 = _b.sent(); | ||
return [3 /*break*/, 4]; | ||
case 4: return [2 /*return*/, { totalStorageSize: 0, percentOfQuota: 0, usageDetails: '' }]; | ||
} | ||
@@ -128,0 +133,0 @@ }); |
@@ -1,2 +0,6 @@ | ||
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: () => { | ||
export declare const init: (apiKey: string, options: import("./typings/session-replay").SessionReplayOptions) => import("@amplitude/analytics-types").AmplitudeReturn<void>, setSessionId: (sessionId: number, deviceId?: string | undefined, options?: { | ||
userProperties?: { | ||
[key: string]: any; | ||
} | undefined; | ||
} | undefined) => import("@amplitude/analytics-types").AmplitudeReturn<void>, getSessionId: () => number | undefined, evaluateTargetingAndCapture: (targetingParams?: Pick<import("@amplitude/targeting").TargetingParameters, "event" | "userProperties"> | undefined) => Promise<void>, getSessionReplayProperties: () => { | ||
[key: string]: string | boolean | null; | ||
@@ -3,0 +7,0 @@ }, flush: (useRetry: boolean) => Promise<void>, shutdown: () => void; |
import sessionReplay from './session-replay-factory'; | ||
export var init = sessionReplay.init, setSessionId = sessionReplay.setSessionId, getSessionId = sessionReplay.getSessionId, getSessionReplayProperties = sessionReplay.getSessionReplayProperties, flush = sessionReplay.flush, shutdown = sessionReplay.shutdown; | ||
export var init = sessionReplay.init, setSessionId = sessionReplay.setSessionId, getSessionId = sessionReplay.getSessionId, evaluateTargetingAndCapture = sessionReplay.evaluateTargetingAndCapture, getSessionReplayProperties = sessionReplay.getSessionReplayProperties, flush = sessionReplay.flush, shutdown = sessionReplay.shutdown; | ||
//# sourceMappingURL=index.js.map |
@@ -16,4 +16,5 @@ import { debugWrapper } from '@amplitude/analytics-core'; | ||
init: debugWrapper(sessionReplay.init.bind(sessionReplay), 'init', getLogConfig(sessionReplay)), | ||
evaluateTargetingAndCapture: debugWrapper(sessionReplay.evaluateTargetingAndCapture.bind(sessionReplay), 'evaluateTargetingAndRecord', getLogConfig(sessionReplay)), | ||
setSessionId: debugWrapper(sessionReplay.setSessionId.bind(sessionReplay), 'setSessionId', getLogConfig(sessionReplay)), | ||
getSessionId: debugWrapper(sessionReplay.getSessionId.bind(sessionReplay), 'getSessionId', getLogConfig(sessionReplay)), | ||
getSessionId: sessionReplay.getSessionId.bind(sessionReplay), | ||
getSessionReplayProperties: debugWrapper(sessionReplay.getSessionReplayProperties.bind(sessionReplay), 'getSessionReplayProperties', getLogConfig(sessionReplay)), | ||
@@ -20,0 +21,0 @@ flush: debugWrapper(sessionReplay.flush.bind(sessionReplay), 'flush', getLogConfig(sessionReplay)), |
import { Logger as ILogger } from '@amplitude/analytics-types'; | ||
import { record } from '@amplitude/rrweb'; | ||
import { TargetingParameters } from '@amplitude/targeting'; | ||
import { SessionReplayJoinedConfig, SessionReplayJoinedConfigGenerator } from './config/types'; | ||
import { AmplitudeSessionReplay, SessionReplayEventsManager as AmplitudeSessionReplayEventsManager, DebugInfo, SessionIdentifiers as ISessionIdentifiers, SessionReplayOptions } from './typings/session-replay'; | ||
import { CustomRRwebEvent } from './constants'; | ||
import { AmplitudeSessionReplay, SessionReplayEventsManager as AmplitudeSessionReplayEventsManager, SessionIdentifiers as ISessionIdentifiers, SessionReplayOptions } from './typings/session-replay'; | ||
type PageLeaveFn = (e: PageTransitionEvent | Event) => void; | ||
@@ -14,2 +16,4 @@ export declare class SessionReplay implements AmplitudeSessionReplay { | ||
recordCancelCallback: ReturnType<typeof record> | null; | ||
eventCount: number; | ||
sessionTargetingMatch: boolean; | ||
pageLeaveFns: PageLeaveFn[]; | ||
@@ -21,4 +25,12 @@ private scrollHook?; | ||
protected _init(apiKey: string, options: SessionReplayOptions): Promise<void>; | ||
setSessionId(sessionId: number, deviceId?: string): import("@amplitude/analytics-types").AmplitudeReturn<void>; | ||
asyncSetSessionId(sessionId: number, deviceId?: string): Promise<void>; | ||
setSessionId(sessionId: number, deviceId?: string, options?: { | ||
userProperties?: { | ||
[key: string]: any; | ||
}; | ||
}): import("@amplitude/analytics-types").AmplitudeReturn<void>; | ||
asyncSetSessionId(sessionId: number, deviceId?: string, options?: { | ||
userProperties?: { | ||
[key: string]: any; | ||
}; | ||
}): Promise<void>; | ||
getSessionReplayDebugPropertyValue(): string; | ||
@@ -36,14 +48,12 @@ getSessionReplayProperties(): { | ||
private pageLeaveListener; | ||
evaluateTargetingAndCapture: (targetingParams?: Pick<TargetingParameters, 'event' | 'userProperties'>) => Promise<void>; | ||
sendEvents(sessionId?: number): void; | ||
initialize(shouldSendStoredEvents?: boolean): void; | ||
shouldOptOut(): boolean | undefined; | ||
getShouldRecord(): boolean; | ||
getShouldCapture(): boolean; | ||
getBlockSelectors(): string | string[] | undefined; | ||
getMaskTextSelectors(): string | undefined; | ||
recordEvents(): void; | ||
/** | ||
* Used to send a debug RRWeb event. Typing is included for ease of debugging later on, but probably not | ||
* used at compile/run time. | ||
*/ | ||
getDebugInfo: () => Promise<DebugInfo | undefined>; | ||
captureEvents(): void; | ||
addCustomRRWebEvent: (eventName: CustomRRwebEvent, eventData?: { | ||
[key: string]: any; | ||
}, addStorageInfo?: boolean) => Promise<void>; | ||
stopRecordingEvents: () => void; | ||
@@ -50,0 +60,0 @@ getDeviceId(): string | undefined; |
import { __assign, __awaiter, __generator, __read, __spreadArray } from "tslib"; | ||
import { getAnalyticsConnector, getGlobalScope } from '@amplitude/analytics-client-common'; | ||
import { Logger, returnWrapper } from '@amplitude/analytics-core'; | ||
import { SpecialEventType } from '@amplitude/analytics-types'; | ||
import { pack, record } from '@amplitude/rrweb'; | ||
import { createSessionReplayJoinedConfigGenerator } from './config/joined-config'; | ||
import { BLOCK_CLASS, DEFAULT_SESSION_REPLAY_PROPERTY, INTERACTION_MAX_INTERVAL, INTERACTION_MIN_INTERVAL, MASK_TEXT_CLASS, SESSION_REPLAY_DEBUG_PROPERTY, } from './constants'; | ||
import { BLOCK_CLASS, CustomRRwebEvent, 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'; | ||
@@ -13,2 +14,3 @@ import { MultiEventManager } from './events/multi-manager'; | ||
import { SessionIdentifiers } from './identifiers'; | ||
import { evaluateTargetingAndStore } from './targeting/targeting-manager'; | ||
import { VERSION } from './version'; | ||
@@ -20,2 +22,4 @@ var SessionReplay = /** @class */ (function () { | ||
this.recordCancelCallback = null; | ||
this.eventCount = 0; | ||
this.sessionTargetingMatch = false; | ||
// Visible for testing | ||
@@ -50,3 +54,4 @@ this.pageLeaveFns = []; | ||
// switches tabs, we take a full snapshot | ||
_this.recordEvents(); | ||
_this.stopRecordingEvents(); | ||
_this.captureEvents(); | ||
}; | ||
@@ -63,24 +68,89 @@ /** | ||
}; | ||
/** | ||
* Used to send a debug RRWeb event. Typing is included for ease of debugging later on, but probably not | ||
* used at compile/run time. | ||
*/ | ||
this.getDebugInfo = function () { return __awaiter(_this, void 0, void 0, function () { | ||
var storageSizeData; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
this.evaluateTargetingAndCapture = function (targetingParams) { return __awaiter(_this, void 0, void 0, function () { | ||
var eventForTargeting, _a; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
if (!this.config) { | ||
if (!this.identifiers || !this.identifiers.sessionId || !this.config) { | ||
if (this.identifiers && !this.identifiers.sessionId) { | ||
this.loggerProvider.log('Session ID has not been set yet, cannot evaluate targeting for Session Replay.'); | ||
} | ||
else { | ||
this.loggerProvider.warn('Session replay init has not been called, cannot evaluate targeting.'); | ||
} | ||
return [2 /*return*/]; | ||
} | ||
return [4 /*yield*/, getStorageSize()]; | ||
if (!(this.config.targetingConfig && !this.sessionTargetingMatch)) return [3 /*break*/, 2]; | ||
eventForTargeting = targetingParams === null || targetingParams === void 0 ? void 0 : targetingParams.event; | ||
if (eventForTargeting && | ||
Object.values(SpecialEventType).includes(eventForTargeting.event_type)) { | ||
eventForTargeting = undefined; | ||
} | ||
// We're setting this on this class because fetching the value from idb | ||
// is async, we need to access this value synchronously (for record | ||
// and for getSessionReplayProperties - both synchronous fns) | ||
_a = this; | ||
return [4 /*yield*/, evaluateTargetingAndStore({ | ||
sessionId: this.identifiers.sessionId, | ||
targetingConfig: this.config.targetingConfig, | ||
loggerProvider: this.loggerProvider, | ||
apiKey: this.config.apiKey, | ||
targetingParams: { userProperties: targetingParams === null || targetingParams === void 0 ? void 0 : targetingParams.userProperties, event: eventForTargeting }, | ||
})]; | ||
case 1: | ||
storageSizeData = _a.sent(); | ||
return [2 /*return*/, __assign(__assign({}, storageSizeData), { config: getDebugConfig(this.config), version: VERSION })]; | ||
// We're setting this on this class because fetching the value from idb | ||
// is async, we need to access this value synchronously (for record | ||
// and for getSessionReplayProperties - both synchronous fns) | ||
_a.sessionTargetingMatch = _b.sent(); | ||
_b.label = 2; | ||
case 2: | ||
this.captureEvents(); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); }; | ||
this.addCustomRRWebEvent = function (eventName, eventData, addStorageInfo) { | ||
if (eventData === void 0) { eventData = {}; } | ||
if (addStorageInfo === void 0) { addStorageInfo = true; } | ||
return __awaiter(_this, void 0, void 0, function () { | ||
var debugInfo, storageSizeData, e_1; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
_a.trys.push([0, 3, , 4]); | ||
debugInfo = undefined; | ||
if (!this.config) return [3 /*break*/, 2]; | ||
debugInfo = { | ||
config: getDebugConfig(this.config), | ||
version: VERSION, | ||
}; | ||
if (!addStorageInfo) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, getStorageSize()]; | ||
case 1: | ||
storageSizeData = _a.sent(); | ||
debugInfo = __assign(__assign({}, storageSizeData), debugInfo); | ||
_a.label = 2; | ||
case 2: | ||
// Check first to ensure we are recording | ||
if (this.recordCancelCallback) { | ||
record.addCustomEvent(eventName, __assign(__assign({}, eventData), debugInfo)); | ||
} | ||
else { | ||
this.loggerProvider.debug("Not able to add custom replay capture event ".concat(eventName, " due to no ongoing recording.")); | ||
} | ||
return [3 /*break*/, 4]; | ||
case 3: | ||
e_1 = _a.sent(); | ||
this.loggerProvider.debug('Error while adding custom replay capture event: ', e_1); | ||
return [3 /*break*/, 4]; | ||
case 4: return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
}; | ||
this.stopRecordingEvents = function () { | ||
try { | ||
_this.loggerProvider.log('Session Replay capture stopping.'); | ||
if (_this.recordCancelCallback) { | ||
_this.loggerProvider.log('Session Replay capture stopping.'); | ||
} | ||
_this.recordCancelCallback && _this.recordCancelCallback(); | ||
@@ -150,5 +220,12 @@ _this.recordCancelCallback = null; | ||
this.eventsManager = new (MultiEventManager.bind.apply(MultiEventManager, __spreadArray([void 0], __read(managers), false)))(); | ||
this.identifiers.deviceId && | ||
void this.eventsManager.sendStoredEvents({ | ||
deviceId: this.identifiers.deviceId, | ||
}); | ||
this.loggerProvider.log('Installing @amplitude/session-replay-browser.'); | ||
this.teardownEventListeners(false); | ||
this.initialize(true); | ||
this.stopRecordingEvents(); | ||
return [4 /*yield*/, this.evaluateTargetingAndCapture({ userProperties: options.userProperties })]; | ||
case 6: | ||
_f.sent(); | ||
return [2 /*return*/]; | ||
@@ -159,6 +236,6 @@ } | ||
}; | ||
SessionReplay.prototype.setSessionId = function (sessionId, deviceId) { | ||
return returnWrapper(this.asyncSetSessionId(sessionId, deviceId)); | ||
SessionReplay.prototype.setSessionId = function (sessionId, deviceId, options) { | ||
return returnWrapper(this.asyncSetSessionId(sessionId, deviceId, options)); | ||
}; | ||
SessionReplay.prototype.asyncSetSessionId = function (sessionId, deviceId) { | ||
SessionReplay.prototype.asyncSetSessionId = function (sessionId, deviceId, options) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
@@ -169,2 +246,4 @@ var previousSessionId, deviceIdForReplayId, _a; | ||
case 0: | ||
this.stopRecordingEvents(); | ||
this.sessionTargetingMatch = false; | ||
previousSessionId = this.identifiers && this.identifiers.sessionId; | ||
@@ -185,4 +264,5 @@ if (previousSessionId) { | ||
_b.label = 2; | ||
case 2: | ||
this.recordEvents(); | ||
case 2: return [4 /*yield*/, this.evaluateTargetingAndCapture({ userProperties: options === null || options === void 0 ? void 0 : options.userProperties })]; | ||
case 3: | ||
_b.sent(); | ||
return [2 /*return*/]; | ||
@@ -208,5 +288,6 @@ } | ||
} | ||
var shouldRecord = this.getShouldRecord(); | ||
var shouldRecord = this.getShouldCapture(); | ||
var eventProperties = {}; | ||
if (shouldRecord) { | ||
var eventProperties = (_a = {}, | ||
eventProperties = (_a = {}, | ||
_a[DEFAULT_SESSION_REPLAY_PROPERTY] = this.identifiers.sessionReplayId ? this.identifiers.sessionReplayId : null, | ||
@@ -217,5 +298,12 @@ _a); | ||
} | ||
return eventProperties; | ||
} | ||
return {}; | ||
void this.addCustomRRWebEvent(CustomRRwebEvent.GET_SR_PROPS, { | ||
shouldRecord: shouldRecord, | ||
eventProperties: eventProperties, | ||
}, this.eventCount === 10); | ||
if (this.eventCount === 10) { | ||
this.eventCount = 0; | ||
} | ||
this.eventCount++; | ||
return eventProperties; | ||
}; | ||
@@ -231,17 +319,2 @@ SessionReplay.prototype.sendEvents = function (sessionId) { | ||
}; | ||
SessionReplay.prototype.initialize = function (shouldSendStoredEvents) { | ||
var _a; | ||
if (shouldSendStoredEvents === void 0) { shouldSendStoredEvents = false; } | ||
if (!((_a = this.identifiers) === null || _a === void 0 ? void 0 : _a.sessionId)) { | ||
this.loggerProvider.log("Session is not being recorded due to lack of session id."); | ||
return; | ||
} | ||
var deviceId = this.getDeviceId(); | ||
if (!deviceId) { | ||
this.loggerProvider.log("Session is not being recorded due to lack of device id."); | ||
return; | ||
} | ||
this.eventsManager && shouldSendStoredEvents && this.eventsManager.sendStoredEvents({ deviceId: deviceId }); | ||
this.recordEvents(); | ||
}; | ||
SessionReplay.prototype.shouldOptOut = function () { | ||
@@ -256,5 +329,5 @@ var _a, _b; | ||
}; | ||
SessionReplay.prototype.getShouldRecord = function () { | ||
SessionReplay.prototype.getShouldCapture = function () { | ||
if (!this.identifiers || !this.config || !this.identifiers.sessionId) { | ||
this.loggerProvider.warn("Session is not being recorded due to lack of config, please call sessionReplay.init."); | ||
this.loggerProvider.warn("Session is not being captured due to lack of config, please call sessionReplay.init."); | ||
return false; | ||
@@ -267,10 +340,23 @@ } | ||
if (this.shouldOptOut()) { | ||
this.loggerProvider.log("Opting session ".concat(this.identifiers.sessionId, " out of recording due to optOut config.")); | ||
this.loggerProvider.log("Opting session ".concat(this.identifiers.sessionId, " out of replay capture due to optOut config.")); | ||
return false; | ||
} | ||
var isInSample = isSessionInSample(this.identifiers.sessionId, this.config.sampleRate); | ||
if (!isInSample) { | ||
this.loggerProvider.log("Opting session ".concat(this.identifiers.sessionId, " out of recording due to sample rate.")); | ||
// If targetingConfig exists, we'll use the sessionTargetingMatch to determine whether to record | ||
// Otherwise, we'll evaluate the session against the overall sample rate | ||
if (this.config.targetingConfig) { | ||
if (!this.sessionTargetingMatch) { | ||
this.loggerProvider.log("Not capturing replays for session ".concat(this.identifiers.sessionId, " due to not matching targeting conditions.")); | ||
return false; | ||
} | ||
this.loggerProvider.log("Capturing replays for session ".concat(this.identifiers.sessionId, " due to matching targeting conditions.")); | ||
} | ||
return isInSample; | ||
else { | ||
var isInSample = isSessionInSample(this.identifiers.sessionId, this.config.sampleRate); | ||
if (!isInSample) { | ||
this.loggerProvider.log("Opting session ".concat(this.identifiers.sessionId, " out of replay capture due to sample rate.")); | ||
return false; | ||
} | ||
this.loggerProvider.log("Capturing replays for session ".concat(this.identifiers.sessionId, " due to inclusion in sample rate.")); | ||
} | ||
return true; | ||
}; | ||
@@ -299,11 +385,13 @@ SessionReplay.prototype.getBlockSelectors = function () { | ||
}; | ||
SessionReplay.prototype.recordEvents = function () { | ||
SessionReplay.prototype.captureEvents = function () { | ||
var _this = this; | ||
var _a; | ||
var shouldRecord = this.getShouldRecord(); | ||
var sessionId = (_a = this.identifiers) === null || _a === void 0 ? void 0 : _a.sessionId; | ||
if (this.recordCancelCallback) { | ||
this.loggerProvider.debug('captureEvents method fired - Session Replay capture already in progress.'); | ||
return; | ||
} | ||
var shouldRecord = this.getShouldCapture(); | ||
var sessionId = this.identifiers && this.identifiers.sessionId; | ||
if (!shouldRecord || !sessionId || !this.config) { | ||
return; | ||
} | ||
this.stopRecordingEvents(); | ||
var privacyConfig = this.config.privacyConfig; | ||
@@ -314,3 +402,3 @@ this.loggerProvider.log('Session Replay capture beginning.'); | ||
if (_this.shouldOptOut()) { | ||
_this.loggerProvider.log("Opting session ".concat(sessionId, " out of recording due to optOut config.")); | ||
_this.loggerProvider.log("Opting session ".concat(sessionId, " out of replay capture due to optOut config.")); | ||
_this.stopRecordingEvents(); | ||
@@ -364,9 +452,3 @@ _this.sendEvents(); | ||
}); | ||
this.getDebugInfo() | ||
.then(function (debugInfo) { | ||
debugInfo && record.addCustomEvent('debug-info', debugInfo); | ||
}) | ||
.catch(function () { | ||
// swallow error | ||
}); | ||
void this.addCustomRRWebEvent(CustomRRwebEvent.DEBUG_INFO); | ||
}; | ||
@@ -373,0 +455,0 @@ SessionReplay.prototype.getDeviceId = function () { |
import { AmplitudeReturn, ServerZone } from '@amplitude/analytics-types'; | ||
import { SessionReplayJoinedConfig, SessionReplayLocalConfig, SessionReplayVersion } from '../config/types'; | ||
import { TargetingParameters } from '@amplitude/targeting'; | ||
export type StorageData = { | ||
@@ -8,3 +9,3 @@ totalStorageSize: number; | ||
}; | ||
export interface DebugInfo extends StorageData { | ||
export interface DebugInfo extends Partial<StorageData> { | ||
config: SessionReplayJoinedConfig; | ||
@@ -63,3 +64,7 @@ version: string; | ||
init: (apiKey: string, options: SessionReplayOptions) => AmplitudeReturn<void>; | ||
setSessionId: (sessionId: number, deviceId?: string) => AmplitudeReturn<void>; | ||
setSessionId: (sessionId: number, deviceId?: string, options?: { | ||
userProperties?: { | ||
[key: string]: any; | ||
}; | ||
}) => AmplitudeReturn<void>; | ||
getSessionId: () => number | undefined; | ||
@@ -69,2 +74,3 @@ getSessionReplayProperties: () => { | ||
}; | ||
evaluateTargetingAndCapture: (targetingParams?: Pick<TargetingParameters, 'event' | 'userProperties'>) => Promise<void>; | ||
flush: (useRetry: boolean) => Promise<void>; | ||
@@ -71,0 +77,0 @@ shutdown: () => void; |
@@ -1,2 +0,2 @@ | ||
export declare const VERSION = "1.13.0"; | ||
export declare const VERSION = "1.14.0-srtargeting.0"; | ||
//# sourceMappingURL=version.d.ts.map |
// Autogenerated by `yarn version-file`. DO NOT EDIT | ||
export var VERSION = '1.13.0'; | ||
export var VERSION = '1.14.0-srtargeting.0'; | ||
//# sourceMappingURL=version.js.map |
import { Config, LogLevel, Logger } from '@amplitude/analytics-types'; | ||
import { TargetingFlag } from '@amplitude/targeting'; | ||
export interface SamplingConfig { | ||
@@ -10,2 +11,3 @@ sample_rate: number; | ||
} | ||
export type TargetingConfig = TargetingFlag; | ||
export type SessionReplayRemoteConfig = { | ||
@@ -15,2 +17,3 @@ sr_sampling_config?: SamplingConfig; | ||
sr_interaction_config?: InteractionConfig; | ||
sr_targeting_config?: TargetingConfig; | ||
}; | ||
@@ -41,2 +44,5 @@ export interface SessionReplayRemoteConfigAPIResponse { | ||
version?: SessionReplayVersion; | ||
userProperties?: { | ||
[key: string]: any; | ||
}; | ||
} | ||
@@ -46,2 +52,3 @@ export interface SessionReplayJoinedConfig extends SessionReplayLocalConfig { | ||
interactionConfig?: InteractionConfig; | ||
targetingConfig?: TargetingConfig; | ||
} | ||
@@ -48,0 +55,0 @@ export interface SessionReplayRemoteConfigFetch { |
@@ -23,2 +23,6 @@ import { ServerZone } from '@amplitude/analytics-types'; | ||
export declare const KB_SIZE = 1024; | ||
export declare enum CustomRRwebEvent { | ||
GET_SR_PROPS = "get-sr-props", | ||
DEBUG_INFO = "debug-info" | ||
} | ||
//# sourceMappingURL=constants.d.ts.map |
@@ -14,2 +14,3 @@ import { PrivacyConfig, SessionReplayJoinedConfig } from './config/types'; | ||
interactionConfig?: import("./config/types").InteractionConfig | undefined; | ||
targetingConfig?: import("@amplitude/experiment-core").EvaluationFlag | undefined; | ||
apiKey: string; | ||
@@ -25,2 +26,5 @@ loggerProvider: import("@amplitude/analytics-types").Logger; | ||
version?: import("./config/types").SessionReplayVersion | undefined; | ||
userProperties?: { | ||
[key: string]: any; | ||
} | undefined; | ||
flushIntervalMillis: number; | ||
@@ -27,0 +31,0 @@ flushQueueSize: number; |
@@ -1,2 +0,6 @@ | ||
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: () => { | ||
export declare const init: (apiKey: string, options: import("./typings/session-replay").SessionReplayOptions) => import("@amplitude/analytics-types").AmplitudeReturn<void>, setSessionId: (sessionId: number, deviceId?: string | undefined, options?: { | ||
userProperties?: { | ||
[key: string]: any; | ||
} | undefined; | ||
} | undefined) => import("@amplitude/analytics-types").AmplitudeReturn<void>, getSessionId: () => number | undefined, evaluateTargetingAndCapture: (targetingParams?: Pick<import("@amplitude/targeting").TargetingParameters, "userProperties" | "event"> | undefined) => Promise<void>, getSessionReplayProperties: () => { | ||
[key: string]: string | boolean | null; | ||
@@ -3,0 +7,0 @@ }, flush: (useRetry: boolean) => Promise<void>, shutdown: () => void; |
import { Logger as ILogger } from '@amplitude/analytics-types'; | ||
import { record } from '@amplitude/rrweb'; | ||
import { TargetingParameters } from '@amplitude/targeting'; | ||
import { SessionReplayJoinedConfig, SessionReplayJoinedConfigGenerator } from './config/types'; | ||
import { AmplitudeSessionReplay, SessionReplayEventsManager as AmplitudeSessionReplayEventsManager, DebugInfo, SessionIdentifiers as ISessionIdentifiers, SessionReplayOptions } from './typings/session-replay'; | ||
import { CustomRRwebEvent } from './constants'; | ||
import { AmplitudeSessionReplay, SessionReplayEventsManager as AmplitudeSessionReplayEventsManager, SessionIdentifiers as ISessionIdentifiers, SessionReplayOptions } from './typings/session-replay'; | ||
type PageLeaveFn = (e: PageTransitionEvent | Event) => void; | ||
@@ -14,2 +16,4 @@ export declare class SessionReplay implements AmplitudeSessionReplay { | ||
recordCancelCallback: ReturnType<typeof record> | null; | ||
eventCount: number; | ||
sessionTargetingMatch: boolean; | ||
pageLeaveFns: PageLeaveFn[]; | ||
@@ -21,4 +25,12 @@ private scrollHook?; | ||
protected _init(apiKey: string, options: SessionReplayOptions): Promise<void>; | ||
setSessionId(sessionId: number, deviceId?: string): import("@amplitude/analytics-types").AmplitudeReturn<void>; | ||
asyncSetSessionId(sessionId: number, deviceId?: string): Promise<void>; | ||
setSessionId(sessionId: number, deviceId?: string, options?: { | ||
userProperties?: { | ||
[key: string]: any; | ||
}; | ||
}): import("@amplitude/analytics-types").AmplitudeReturn<void>; | ||
asyncSetSessionId(sessionId: number, deviceId?: string, options?: { | ||
userProperties?: { | ||
[key: string]: any; | ||
}; | ||
}): Promise<void>; | ||
getSessionReplayDebugPropertyValue(): string; | ||
@@ -36,14 +48,12 @@ getSessionReplayProperties(): { | ||
private pageLeaveListener; | ||
evaluateTargetingAndCapture: (targetingParams?: Pick<TargetingParameters, 'event' | 'userProperties'>) => Promise<void>; | ||
sendEvents(sessionId?: number): void; | ||
initialize(shouldSendStoredEvents?: boolean): void; | ||
shouldOptOut(): boolean | undefined; | ||
getShouldRecord(): boolean; | ||
getShouldCapture(): boolean; | ||
getBlockSelectors(): string | string[] | undefined; | ||
getMaskTextSelectors(): string | undefined; | ||
recordEvents(): void; | ||
/** | ||
* Used to send a debug RRWeb event. Typing is included for ease of debugging later on, but probably not | ||
* used at compile/run time. | ||
*/ | ||
getDebugInfo: () => Promise<DebugInfo | undefined>; | ||
captureEvents(): void; | ||
addCustomRRWebEvent: (eventName: CustomRRwebEvent, eventData?: { | ||
[key: string]: any; | ||
}, addStorageInfo?: boolean) => Promise<void>; | ||
stopRecordingEvents: () => void; | ||
@@ -50,0 +60,0 @@ getDeviceId(): string | undefined; |
import { AmplitudeReturn, ServerZone } from '@amplitude/analytics-types'; | ||
import { SessionReplayJoinedConfig, SessionReplayLocalConfig, SessionReplayVersion } from '../config/types'; | ||
import { TargetingParameters } from '@amplitude/targeting'; | ||
export type StorageData = { | ||
@@ -8,3 +9,3 @@ totalStorageSize: number; | ||
}; | ||
export interface DebugInfo extends StorageData { | ||
export interface DebugInfo extends Partial<StorageData> { | ||
config: SessionReplayJoinedConfig; | ||
@@ -63,3 +64,7 @@ version: string; | ||
init: (apiKey: string, options: SessionReplayOptions) => AmplitudeReturn<void>; | ||
setSessionId: (sessionId: number, deviceId?: string) => AmplitudeReturn<void>; | ||
setSessionId: (sessionId: number, deviceId?: string, options?: { | ||
userProperties?: { | ||
[key: string]: any; | ||
}; | ||
}) => AmplitudeReturn<void>; | ||
getSessionId: () => number | undefined; | ||
@@ -69,2 +74,3 @@ getSessionReplayProperties: () => { | ||
}; | ||
evaluateTargetingAndCapture: (targetingParams?: Pick<TargetingParameters, 'event' | 'userProperties'>) => Promise<void>; | ||
flush: (useRetry: boolean) => Promise<void>; | ||
@@ -71,0 +77,0 @@ shutdown: () => void; |
@@ -1,2 +0,2 @@ | ||
export declare const VERSION = "1.13.0"; | ||
export declare const VERSION = "1.14.0-srtargeting.0"; | ||
//# sourceMappingURL=version.d.ts.map |
{ | ||
"name": "@amplitude/session-replay-browser", | ||
"version": "1.13.0", | ||
"version": "1.14.0-srtargeting.0", | ||
"description": "", | ||
@@ -46,2 +46,3 @@ "author": "Amplitude Inc", | ||
"@amplitude/rrweb": "2.0.0-alpha.19", | ||
"@amplitude/targeting": "0.2.0", | ||
"idb": "^8.0.0", | ||
@@ -67,3 +68,3 @@ "tslib": "^2.4.1" | ||
], | ||
"gitHead": "4514fbd5e5ac24426e4091ddb8d2604228099b14" | ||
"gitHead": "ffe85701ecb0fea995ac90fa22efb49007a3a1e6" | ||
} |
@@ -50,5 +50,15 @@ <p align="center"> | ||
### 3. Get session replay event properties | ||
Any event that occurs within the span of a session replay must be tagged with properties that signal to Amplitude to include it in the scope of the replay. The following shows an example of how to use the properties | ||
### 3. Evaluate targeting (optional) | ||
Any event that occurs within the span of a session replay must be passed to the SDK to evaluate against targeting conditions. This should be done *before* step 4, getting the event properties. If you are not using the targeting condition logic provided via the Amplitude UI, this step is not required. | ||
```typescript | ||
const sessionTargetingMatch = sessionReplay.evaluateTargetingAndCapture({ event: { | ||
event_type: EVENT_NAME, | ||
time: EVENT_TIMESTAMP, | ||
event_properties: eventProperties | ||
} }); | ||
``` | ||
### 4. Get session replay event properties | ||
Any event must be tagged with properties that signal to Amplitude to include it in the scope of the replay. The following shows an example of how to use the properties. | ||
```typescript | ||
const sessionReplayProperties = sessionReplay.getSessionReplayProperties(); | ||
@@ -61,3 +71,3 @@ track(EVENT_NAME, { | ||
### 4. Update session id | ||
### 5. Update session id | ||
Any time that the session id for the user changes, the session replay SDK must be notified of that change. Update the session id via the following method: | ||
@@ -72,3 +82,3 @@ ```typescript | ||
### 5. Shutdown (optional) | ||
### 6. Shutdown (optional) | ||
If at any point you would like to discontinue collection of session replays, for example in a part of your application where you would not like sessions to be collected, you can use the following method to stop collection and remove collection event listeners. | ||
@@ -75,0 +85,0 @@ ```typescript |
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
1164878
237
8476
123
8
1
+ Added@amplitude/targeting@0.2.0
+ Added@amplitude/experiment-core@0.7.2(transitive)
+ Added@amplitude/targeting@0.2.0(transitive)