@amplitude/session-replay-browser 1.36.0-SR-3115.1 → 1.36.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"event-compressor.d.ts","sourceRoot":"","sources":["../../../src/events/event-compressor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAEvE,UAAU,SAAS;IACjB,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B;AAGD,qBAAa,eAAe;IAC1B,SAAS,EAAE,SAAS,EAAE,CAAM;IAC5B,YAAY,UAAS;IACrB,aAAa,CAAC,EAAE,0BAA0B,CAAC,QAAQ,GAAG,aAAa,EAAE,MAAM,CAAC,CAAC;IAC7E,MAAM,EAAE,yBAAyB,CAAC;IAClC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,kBAAkB,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uBAAuB,CAAC,EAAE,MAAM,IAAI,CAAC;gBAGnC,aAAa,EAAE,0BAA0B,CAAC,QAAQ,GAAG,aAAa,EAAE,MAAM,CAAC,EAC3E,MAAM,EAAE,yBAAyB,EACjC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,YAAY,CAAC,EAAE,MAAM,EACrB,uBAAuB,CAAC,EAAE,MAAM,IAAI;IAuC/B,sBAAsB,IAAI,IAAI;IAa9B,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAuBpE,YAAY,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI;IAuBrD,aAAa,UAAW,aAAa,KAAG,MAAM,CAS5C;IAEF,OAAO,CAAC,2BAA2B,CAQjC;IAEK,kBAAkB,UAAW,aAAa,aAAa,MAAM,GAAG,MAAM,UAkB3E;IAEK,SAAS,aAEd;CACH"}
1
+ {"version":3,"file":"event-compressor.d.ts","sourceRoot":"","sources":["../../../src/events/event-compressor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAEvE,UAAU,SAAS;IACjB,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B;AAGD,qBAAa,eAAe;IAC1B,SAAS,EAAE,SAAS,EAAE,CAAM;IAC5B,YAAY,UAAS;IACrB,aAAa,CAAC,EAAE,0BAA0B,CAAC,QAAQ,GAAG,aAAa,EAAE,MAAM,CAAC,CAAC;IAC7E,MAAM,EAAE,yBAAyB,CAAC;IAClC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,kBAAkB,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uBAAuB,CAAC,EAAE,MAAM,IAAI,CAAC;gBAGnC,aAAa,EAAE,0BAA0B,CAAC,QAAQ,GAAG,aAAa,EAAE,MAAM,CAAC,EAC3E,MAAM,EAAE,yBAAyB,EACjC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,YAAY,CAAC,EAAE,MAAM,EACrB,uBAAuB,CAAC,EAAE,MAAM,IAAI;IAuC/B,sBAAsB,IAAI,IAAI;IAa9B,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAkCpE,YAAY,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI;IAuBrD,aAAa,UAAW,aAAa,KAAG,MAAM,CAS5C;IAEF,OAAO,CAAC,2BAA2B,CAQjC;IAEK,kBAAkB,UAAW,aAAa,aAAa,MAAM,GAAG,MAAM,UAkB3E;IAEK,SAAS,aAEd;CACH"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EventCompressor = void 0;
4
+ var tslib_1 = require("tslib");
4
5
  var analytics_core_1 = require("@amplitude/analytics-core");
5
6
  var rrweb_types_1 = require("@amplitude/rrweb-types");
6
7
  var DEFAULT_TIMEOUT = 2000;
@@ -97,18 +98,40 @@ var EventCompressor = /** @class */ (function () {
97
98
  };
98
99
  // Add an event to the task queue if idle callback is supported or compress the event directly
99
100
  EventCompressor.prototype.enqueueEvent = function (event, sessionId) {
100
- var _a, _b;
101
+ var e_1, _a;
102
+ var _b, _c;
101
103
  // Full snapshot (type 2) is the most critical event — a replay cannot be played without it.
102
104
  // Process and flush immediately rather than waiting for the idle scheduler or web worker,
103
105
  // maximising the chance it is delivered before the user exits the page.
104
106
  if (event.type === rrweb_types_1.EventType.FullSnapshot) {
105
107
  this.config.loggerProvider.debug('Processing full snapshot immediately.');
108
+ // Drain any events still pending in the idle-callback queue first.
109
+ // Those events reference the pre-snapshot DOM and must be sent before
110
+ // the full snapshot; if we let them be processed later they'd arrive at
111
+ // the server after the snapshot and cause "node not found" replay errors.
112
+ if (this.taskQueue.length > 0) {
113
+ try {
114
+ for (var _d = tslib_1.__values(this.taskQueue.splice(0)), _e = _d.next(); !_e.done; _e = _d.next()) {
115
+ var task = _e.value;
116
+ var compressed = this.compressEvent(task.event);
117
+ this.addCompressedEventToManager(compressed, task.sessionId);
118
+ }
119
+ }
120
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
121
+ finally {
122
+ try {
123
+ if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
124
+ }
125
+ finally { if (e_1) throw e_1.error; }
126
+ }
127
+ this.isProcessing = false;
128
+ }
106
129
  var compressedEvent = this.compressEvent(event);
107
130
  this.addCompressedEventToManager(compressedEvent, sessionId);
108
- (_a = this.onFullSnapshotProcessed) === null || _a === void 0 ? void 0 : _a.call(this);
131
+ (_b = this.onFullSnapshotProcessed) === null || _b === void 0 ? void 0 : _b.call(this);
109
132
  return;
110
133
  }
111
- if (this.canUseIdleCallback && ((_b = this.config.performanceConfig) === null || _b === void 0 ? void 0 : _b.enabled)) {
134
+ if (this.canUseIdleCallback && ((_c = this.config.performanceConfig) === null || _c === void 0 ? void 0 : _c.enabled)) {
112
135
  this.config.loggerProvider.debug('Enqueuing event for processing during idle time.');
113
136
  this.taskQueue.push({ event: event, sessionId: sessionId });
114
137
  this.scheduleIdleProcessing();
@@ -1 +1 @@
1
- {"version":3,"file":"event-compressor.js","sourceRoot":"","sources":["../../../src/events/event-compressor.ts"],"names":[],"mappings":"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","sourcesContent":["import { getGlobalScope } from '@amplitude/analytics-core';\nimport { EventType as RRWebEventType } from '@amplitude/rrweb-types';\nimport type { eventWithTime } from '@amplitude/rrweb-types';\nimport { SessionReplayJoinedConfig } from '../config/types';\nimport { SessionReplayEventsManager } from '../typings/session-replay';\n\ninterface TaskQueue {\n event: eventWithTime;\n sessionId: string | number;\n}\n\nconst DEFAULT_TIMEOUT = 2000;\nexport class EventCompressor {\n taskQueue: TaskQueue[] = [];\n isProcessing = false;\n eventsManager?: SessionReplayEventsManager<'replay' | 'interaction', string>;\n config: SessionReplayJoinedConfig;\n deviceId: string | undefined;\n canUseIdleCallback: boolean | undefined;\n timeout: number;\n worker?: Worker;\n onFullSnapshotProcessed?: () => void;\n\n constructor(\n eventsManager: SessionReplayEventsManager<'replay' | 'interaction', string>,\n config: SessionReplayJoinedConfig,\n deviceId: string | undefined,\n workerScript?: string,\n onFullSnapshotProcessed?: () => void,\n ) {\n const globalScope = getGlobalScope();\n this.canUseIdleCallback = globalScope && 'requestIdleCallback' in globalScope;\n this.eventsManager = eventsManager;\n this.config = config;\n this.deviceId = deviceId;\n this.timeout = config.performanceConfig?.timeout || DEFAULT_TIMEOUT;\n this.onFullSnapshotProcessed = onFullSnapshotProcessed;\n\n if (workerScript) {\n config.loggerProvider.log('Enabling web worker for compression');\n\n try {\n const blob = new Blob([workerScript], { type: 'application/javascript' });\n const blobUrl = URL.createObjectURL(blob);\n const worker = new Worker(blobUrl);\n\n worker.onerror = (e) => {\n e.preventDefault();\n config.loggerProvider.error(\n `Worker failed, falling back to non-worker compression: ${e.message} (${e.filename}:${e.lineno})`,\n );\n worker.terminate();\n this.worker = undefined;\n };\n worker.onmessage = (e) => {\n const { compressedEvent, sessionId } = e.data as Record<string, string>;\n this.addCompressedEventToManager(compressedEvent, sessionId);\n };\n\n this.worker = worker;\n } catch (error) {\n config.loggerProvider.error('Failed to create worker, falling back to non-worker compression:', error);\n }\n }\n }\n\n // Schedule processing during idle time\n public scheduleIdleProcessing(): void {\n if (!this.isProcessing) {\n this.isProcessing = true;\n requestIdleCallback(\n (idleDeadline) => {\n this.processQueue(idleDeadline);\n },\n { timeout: this.timeout },\n );\n }\n }\n\n // Add an event to the task queue if idle callback is supported or compress the event directly\n public enqueueEvent(event: eventWithTime, sessionId: string | number): void {\n // Full snapshot (type 2) is the most critical event — a replay cannot be played without it.\n // Process and flush immediately rather than waiting for the idle scheduler or web worker,\n // maximising the chance it is delivered before the user exits the page.\n if (event.type === RRWebEventType.FullSnapshot) {\n this.config.loggerProvider.debug('Processing full snapshot immediately.');\n const compressedEvent = this.compressEvent(event);\n this.addCompressedEventToManager(compressedEvent, sessionId);\n this.onFullSnapshotProcessed?.();\n return;\n }\n\n if (this.canUseIdleCallback && this.config.performanceConfig?.enabled) {\n this.config.loggerProvider.debug('Enqueuing event for processing during idle time.');\n this.taskQueue.push({ event, sessionId });\n this.scheduleIdleProcessing();\n } else {\n this.config.loggerProvider.debug('Processing event without idle callback.');\n this.addCompressedEvent(event, sessionId);\n }\n }\n\n // Process the task queue during idle time\n public processQueue(idleDeadline: IdleDeadline): void {\n // Process tasks while there's idle time or until the max number of tasks is reached\n while (this.taskQueue.length > 0 && (idleDeadline.timeRemaining() > 0 || idleDeadline.didTimeout)) {\n const task = this.taskQueue.shift();\n if (task) {\n const { event, sessionId } = task;\n this.addCompressedEvent(event, sessionId);\n }\n }\n\n // If there are still tasks in the queue, schedule the next idle callback\n if (this.taskQueue.length > 0) {\n requestIdleCallback(\n (idleDeadline) => {\n this.processQueue(idleDeadline);\n },\n { timeout: this.timeout },\n );\n } else {\n this.isProcessing = false;\n }\n }\n\n compressEvent = (event: eventWithTime): string => {\n // Serialize with type+timestamp first for streaming parser compatibility.\n // JS engines serialize non-integer string keys in insertion order (ES2015 spec,\n // reliable across V8/SpiderMonkey/JSC), so explicit construction controls key order.\n // `delay` is an rrweb player field: an optional ms offset applied on top of\n // `timestamp` during replay to smooth out batched/throttled events. Preserve\n // it when present so playback timing is accurate.\n const { type, timestamp, delay, data } = event as eventWithTime & { delay?: number };\n return delay != null ? JSON.stringify({ type, timestamp, delay, data }) : JSON.stringify({ type, timestamp, data });\n };\n\n private addCompressedEventToManager = (compressedEvent: string, sessionId: string | number) => {\n if (this.eventsManager && this.deviceId) {\n this.eventsManager.addEvent({\n event: { type: 'replay', data: compressedEvent },\n sessionId,\n deviceId: this.deviceId,\n });\n }\n };\n\n public addCompressedEvent = (event: eventWithTime, sessionId: string | number) => {\n if (this.worker) {\n // This indirectly compresses the event.\n try {\n this.worker.postMessage({ event, sessionId });\n } catch (err: any) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n if (err.name === 'DataCloneError') {\n // fallback: serialize\n this.worker.postMessage(JSON.stringify({ event, sessionId }));\n } else {\n this.config.loggerProvider.warn('Unexpected error while posting message to worker:', err);\n }\n }\n } else {\n const compressedEvent = this.compressEvent(event);\n this.addCompressedEventToManager(compressedEvent, sessionId);\n }\n };\n\n public terminate = () => {\n this.worker?.terminate();\n };\n}\n"]}
1
+ {"version":3,"file":"event-compressor.js","sourceRoot":"","sources":["../../../src/events/event-compressor.ts"],"names":[],"mappings":"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","sourcesContent":["import { getGlobalScope } from '@amplitude/analytics-core';\nimport { EventType as RRWebEventType } from '@amplitude/rrweb-types';\nimport type { eventWithTime } from '@amplitude/rrweb-types';\nimport { SessionReplayJoinedConfig } from '../config/types';\nimport { SessionReplayEventsManager } from '../typings/session-replay';\n\ninterface TaskQueue {\n event: eventWithTime;\n sessionId: string | number;\n}\n\nconst DEFAULT_TIMEOUT = 2000;\nexport class EventCompressor {\n taskQueue: TaskQueue[] = [];\n isProcessing = false;\n eventsManager?: SessionReplayEventsManager<'replay' | 'interaction', string>;\n config: SessionReplayJoinedConfig;\n deviceId: string | undefined;\n canUseIdleCallback: boolean | undefined;\n timeout: number;\n worker?: Worker;\n onFullSnapshotProcessed?: () => void;\n\n constructor(\n eventsManager: SessionReplayEventsManager<'replay' | 'interaction', string>,\n config: SessionReplayJoinedConfig,\n deviceId: string | undefined,\n workerScript?: string,\n onFullSnapshotProcessed?: () => void,\n ) {\n const globalScope = getGlobalScope();\n this.canUseIdleCallback = globalScope && 'requestIdleCallback' in globalScope;\n this.eventsManager = eventsManager;\n this.config = config;\n this.deviceId = deviceId;\n this.timeout = config.performanceConfig?.timeout || DEFAULT_TIMEOUT;\n this.onFullSnapshotProcessed = onFullSnapshotProcessed;\n\n if (workerScript) {\n config.loggerProvider.log('Enabling web worker for compression');\n\n try {\n const blob = new Blob([workerScript], { type: 'application/javascript' });\n const blobUrl = URL.createObjectURL(blob);\n const worker = new Worker(blobUrl);\n\n worker.onerror = (e) => {\n e.preventDefault();\n config.loggerProvider.error(\n `Worker failed, falling back to non-worker compression: ${e.message} (${e.filename}:${e.lineno})`,\n );\n worker.terminate();\n this.worker = undefined;\n };\n worker.onmessage = (e) => {\n const { compressedEvent, sessionId } = e.data as Record<string, string>;\n this.addCompressedEventToManager(compressedEvent, sessionId);\n };\n\n this.worker = worker;\n } catch (error) {\n config.loggerProvider.error('Failed to create worker, falling back to non-worker compression:', error);\n }\n }\n }\n\n // Schedule processing during idle time\n public scheduleIdleProcessing(): void {\n if (!this.isProcessing) {\n this.isProcessing = true;\n requestIdleCallback(\n (idleDeadline) => {\n this.processQueue(idleDeadline);\n },\n { timeout: this.timeout },\n );\n }\n }\n\n // Add an event to the task queue if idle callback is supported or compress the event directly\n public enqueueEvent(event: eventWithTime, sessionId: string | number): void {\n // Full snapshot (type 2) is the most critical event — a replay cannot be played without it.\n // Process and flush immediately rather than waiting for the idle scheduler or web worker,\n // maximising the chance it is delivered before the user exits the page.\n if (event.type === RRWebEventType.FullSnapshot) {\n this.config.loggerProvider.debug('Processing full snapshot immediately.');\n // Drain any events still pending in the idle-callback queue first.\n // Those events reference the pre-snapshot DOM and must be sent before\n // the full snapshot; if we let them be processed later they'd arrive at\n // the server after the snapshot and cause \"node not found\" replay errors.\n if (this.taskQueue.length > 0) {\n for (const task of this.taskQueue.splice(0)) {\n const compressed = this.compressEvent(task.event);\n this.addCompressedEventToManager(compressed, task.sessionId);\n }\n this.isProcessing = false;\n }\n const compressedEvent = this.compressEvent(event);\n this.addCompressedEventToManager(compressedEvent, sessionId);\n this.onFullSnapshotProcessed?.();\n return;\n }\n\n if (this.canUseIdleCallback && this.config.performanceConfig?.enabled) {\n this.config.loggerProvider.debug('Enqueuing event for processing during idle time.');\n this.taskQueue.push({ event, sessionId });\n this.scheduleIdleProcessing();\n } else {\n this.config.loggerProvider.debug('Processing event without idle callback.');\n this.addCompressedEvent(event, sessionId);\n }\n }\n\n // Process the task queue during idle time\n public processQueue(idleDeadline: IdleDeadline): void {\n // Process tasks while there's idle time or until the max number of tasks is reached\n while (this.taskQueue.length > 0 && (idleDeadline.timeRemaining() > 0 || idleDeadline.didTimeout)) {\n const task = this.taskQueue.shift();\n if (task) {\n const { event, sessionId } = task;\n this.addCompressedEvent(event, sessionId);\n }\n }\n\n // If there are still tasks in the queue, schedule the next idle callback\n if (this.taskQueue.length > 0) {\n requestIdleCallback(\n (idleDeadline) => {\n this.processQueue(idleDeadline);\n },\n { timeout: this.timeout },\n );\n } else {\n this.isProcessing = false;\n }\n }\n\n compressEvent = (event: eventWithTime): string => {\n // Serialize with type+timestamp first for streaming parser compatibility.\n // JS engines serialize non-integer string keys in insertion order (ES2015 spec,\n // reliable across V8/SpiderMonkey/JSC), so explicit construction controls key order.\n // `delay` is an rrweb player field: an optional ms offset applied on top of\n // `timestamp` during replay to smooth out batched/throttled events. Preserve\n // it when present so playback timing is accurate.\n const { type, timestamp, delay, data } = event as eventWithTime & { delay?: number };\n return delay != null ? JSON.stringify({ type, timestamp, delay, data }) : JSON.stringify({ type, timestamp, data });\n };\n\n private addCompressedEventToManager = (compressedEvent: string, sessionId: string | number) => {\n if (this.eventsManager && this.deviceId) {\n this.eventsManager.addEvent({\n event: { type: 'replay', data: compressedEvent },\n sessionId,\n deviceId: this.deviceId,\n });\n }\n };\n\n public addCompressedEvent = (event: eventWithTime, sessionId: string | number) => {\n if (this.worker) {\n // This indirectly compresses the event.\n try {\n this.worker.postMessage({ event, sessionId });\n } catch (err: any) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n if (err.name === 'DataCloneError') {\n // fallback: serialize\n this.worker.postMessage(JSON.stringify({ event, sessionId }));\n } else {\n this.config.loggerProvider.warn('Unexpected error while posting message to worker:', err);\n }\n }\n } else {\n const compressedEvent = this.compressEvent(event);\n this.addCompressedEventToManager(compressedEvent, sessionId);\n }\n };\n\n public terminate = () => {\n this.worker?.terminate();\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"track-destination.d.ts","sourceRoot":"","sources":["../../src/track-destination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,OAAO,EAAE,UAAU,EAAU,MAAM,2BAA2B,CAAC;AASvG,OAAO,EACL,6BAA6B,IAAI,sCAAsC,EACvE,wBAAwB,EACxB,+BAA+B,EAChC,MAAM,0BAA0B,CAAC;AAiBlC,MAAM,MAAM,cAAc,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,KAAK;IAC3F,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB,CAAC;AAEF,qBAAa,6BAA8B,YAAW,sCAAsC;IAC1F,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,SAAM;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,SAAQ;IACpB,OAAO,CAAC,SAAS,CAA8C;IAC/D,cAAc,EAAE,cAAc,CAAC;IAC/B,KAAK,EAAE,+BAA+B,EAAE,CAAM;IAC9C,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,qBAAqB,CAAwF;gBAEzG,EACV,cAAc,EACd,cAAc,EACd,cAAc,EACd,YAAY,GACb,EAAE;QACD,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,OAAO,CAAC;QACxB,cAAc,CAAC,EAAE,cAAc,CAAC;QAChC,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB;IA6CD,cAAc,CAAC,eAAe,EAAE,wBAAwB;IAQxD;;;;;;OAMG;IACH,UAAU,CAAC,EACT,MAAM,EACN,SAAS,EACT,QAAQ,EACR,MAAM,EACN,UAAU,GACX,EAAE;QACD,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;QAC3B,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,OAAO,UAAU,CAAC;KACtC;IAiBD,UAAU,CAAC,GAAG,IAAI,EAAE,+BAA+B,EAAE;IAkBrD,QAAQ,CAAC,OAAO,EAAE,MAAM;IAWlB,KAAK,CAAC,QAAQ,UAAQ;IActB,IAAI,CAAC,OAAO,EAAE,+BAA+B,EAAE,QAAQ,UAAO;YA4BtD,aAAa;YAgCb,gBAAgB;IA+DxB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,+BAA+B;IAc5E,qBAAqB,CAAC,OAAO,EAAE,+BAA+B;IAQxD,mBAAmB,CAAC,OAAO,EAAE,+BAA+B;IAWlE,eAAe,CAAC,EACd,OAAO,EACP,GAAG,EACH,OAAO,GACR,EAAE;QACD,OAAO,EAAE,+BAA+B,CAAC;QACzC,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB;CAQF"}
1
+ {"version":3,"file":"track-destination.d.ts","sourceRoot":"","sources":["../../src/track-destination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,OAAO,EAAE,UAAU,EAAU,MAAM,2BAA2B,CAAC;AASvG,OAAO,EACL,6BAA6B,IAAI,sCAAsC,EACvE,wBAAwB,EACxB,+BAA+B,EAChC,MAAM,0BAA0B,CAAC;AAiBlC,MAAM,MAAM,cAAc,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,KAAK;IAC3F,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB,CAAC;AAEF,qBAAa,6BAA8B,YAAW,sCAAsC;IAC1F,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,SAAM;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,SAAQ;IACpB,OAAO,CAAC,SAAS,CAA8C;IAC/D,cAAc,EAAE,cAAc,CAAC;IAC/B,KAAK,EAAE,+BAA+B,EAAE,CAAM;IAC9C,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,qBAAqB,CAAwF;gBAEzG,EACV,cAAc,EACd,cAAc,EACd,cAAc,EACd,YAAY,GACb,EAAE;QACD,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,OAAO,CAAC;QACxB,cAAc,CAAC,EAAE,cAAc,CAAC;QAChC,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB;IAgDD,cAAc,CAAC,eAAe,EAAE,wBAAwB;IAQxD;;;;;;OAMG;IACH,UAAU,CAAC,EACT,MAAM,EACN,SAAS,EACT,QAAQ,EACR,MAAM,EACN,UAAU,GACX,EAAE;QACD,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;QAC3B,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,OAAO,UAAU,CAAC;KACtC;IAgDD,UAAU,CAAC,GAAG,IAAI,EAAE,+BAA+B,EAAE;IAkBrD,QAAQ,CAAC,OAAO,EAAE,MAAM;IAWlB,KAAK,CAAC,QAAQ,UAAQ;IActB,IAAI,CAAC,OAAO,EAAE,+BAA+B,EAAE,QAAQ,UAAO;YA4BtD,aAAa;YAgCb,gBAAgB;IA+DxB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,+BAA+B;IAc5E,qBAAqB,CAAC,OAAO,EAAE,+BAA+B;IAQxD,mBAAmB,CAAC,OAAO,EAAE,+BAA+B;IAWlE,eAAe,CAAC,EACd,OAAO,EACP,GAAG,EACH,OAAO,GACR,EAAE;QACD,OAAO,EAAE,+BAA+B,CAAC;QACzC,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB;CAQF"}
@@ -33,9 +33,12 @@ var SessionReplayTrackDestination = /** @class */ (function () {
33
33
  worker_1.terminate();
34
34
  _this.worker = undefined;
35
35
  try {
36
- // Resolve all pending requests so flush() doesn't hang
36
+ // Resolve pending promises so flush() doesn't hang. Do NOT call completeRequest
37
+ // here — the events were never delivered, so onComplete must not fire and the
38
+ // IDB/memory store entries must remain intact for recovery by sendStoredEvents.
37
39
  for (var _b = tslib_1.__values(_this.pendingWorkerRequests), _c = _b.next(); !_c.done; _c = _b.next()) {
38
40
  var _d = tslib_1.__read(_c.value, 2), pending_1 = _d[1];
41
+ loggerProvider.warn("Session replay event send failed due to worker crash: ".concat(e.message));
39
42
  pending_1.resolve();
40
43
  }
41
44
  }
@@ -85,7 +88,31 @@ var SessionReplayTrackDestination = /** @class */ (function () {
85
88
  SessionReplayTrackDestination.prototype.sendBeacon = function (_a) {
86
89
  var _b, _c;
87
90
  var events = _a.events, sessionId = _a.sessionId, deviceId = _a.deviceId, apiKey = _a.apiKey, serverZone = _a.serverZone;
88
- var payload = JSON.stringify({ version: 2, events: events });
91
+ var MAX_BEACON_BYTES = 64 * 1024;
92
+ var byteLength = function (s) { return new Blob([s]).size; };
93
+ var trimmedEvents = events;
94
+ var payload = JSON.stringify({ version: 2, events: trimmedEvents });
95
+ if (byteLength(payload) > MAX_BEACON_BYTES) {
96
+ // Binary search for the largest prefix that fits within the beacon size limit.
97
+ // Uses Blob.size to get the UTF-8 byte count, which is what sendBeacon measures.
98
+ var lo = 0;
99
+ var hi = trimmedEvents.length;
100
+ while (lo < hi) {
101
+ var mid = Math.floor((lo + hi + 1) / 2);
102
+ if (byteLength(JSON.stringify({ version: 2, events: trimmedEvents.slice(0, mid) })) <= MAX_BEACON_BYTES) {
103
+ lo = mid;
104
+ }
105
+ else {
106
+ hi = mid - 1;
107
+ }
108
+ }
109
+ trimmedEvents = trimmedEvents.slice(0, lo);
110
+ payload = JSON.stringify({ version: 2, events: trimmedEvents });
111
+ this.loggerProvider.warn("sendBeacon payload exceeded 64 KB limit, trimmed from ".concat(events.length, " to ").concat(trimmedEvents.length, " events"));
112
+ }
113
+ if (trimmedEvents.length === 0) {
114
+ return;
115
+ }
89
116
  var urlParams = new URLSearchParams({
90
117
  device_id: deviceId,
91
118
  session_id: String(sessionId),
@@ -95,7 +122,13 @@ var SessionReplayTrackDestination = /** @class */ (function () {
95
122
  var serverUrl = "".concat((0, helpers_1.getServerUrl)(serverZone, this.trackServerUrl), "?").concat(urlParams.toString());
96
123
  var globalScope = (0, analytics_core_1.getGlobalScope)();
97
124
  try {
98
- (_c = (_b = globalScope === null || globalScope === void 0 ? void 0 : globalScope.navigator) === null || _b === void 0 ? void 0 : _b.sendBeacon) === null || _c === void 0 ? void 0 : _c.call(_b, serverUrl, payload);
125
+ // Wrap in a Blob to set Content-Type: application/json; a plain string would
126
+ // cause the browser to send Content-Type: text/plain, which the server rejects.
127
+ var payloadBlob = new Blob([payload], { type: 'application/json' });
128
+ var sent = (_c = (_b = globalScope === null || globalScope === void 0 ? void 0 : globalScope.navigator) === null || _b === void 0 ? void 0 : _b.sendBeacon) === null || _c === void 0 ? void 0 : _c.call(_b, serverUrl, payloadBlob);
129
+ if (sent === false) {
130
+ this.loggerProvider.warn('sendBeacon failed to queue session replay payload');
131
+ }
99
132
  }
100
133
  catch (_d) {
101
134
  // Best effort — no fallback on page exit.
@@ -1 +1 @@
1
- {"version":3,"file":"track-destination.js","sourceRoot":"","sources":["../../src/track-destination.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseTransport, getGlobalScope, ILogger, ServerZone, Status } from '@amplitude/analytics-core';\nimport { getCurrentUrl, getServerUrl } from './helpers';\nimport {\n MAX_RETRIES_EXCEEDED_MESSAGE,\n MISSING_API_KEY_MESSAGE,\n MISSING_DEVICE_ID_MESSAGE,\n UNEXPECTED_ERROR_MESSAGE,\n UNEXPECTED_NETWORK_ERROR_MESSAGE,\n} from './messages';\nimport {\n SessionReplayTrackDestination as AmplitudeSessionReplayTrackDestination,\n SessionReplayDestination,\n SessionReplayDestinationContext,\n} from './typings/session-replay';\nimport { VERSION } from './version';\nimport { MAX_URL_LENGTH, KB_SIZE } from './constants';\nimport { gzipJson } from './utils/gzip';\n\ninterface WorkerCompleteMessage {\n type: 'complete';\n id: string;\n err?: string;\n}\ninterface WorkerLogMessage {\n type: 'log' | 'warn';\n id: string;\n message: string;\n}\ntype WorkerMessage = WorkerCompleteMessage | WorkerLogMessage;\n\nexport type PayloadBatcher = ({ version, events }: { version: number; events: string[] }) => {\n version: number;\n events: unknown[];\n};\n\nexport class SessionReplayTrackDestination implements AmplitudeSessionReplayTrackDestination {\n loggerProvider: ILogger;\n storageKey = '';\n trackServerUrl?: string;\n retryTimeout = 1000;\n private scheduled: ReturnType<typeof setTimeout> | null = null;\n payloadBatcher: PayloadBatcher;\n queue: SessionReplayDestinationContext[] = [];\n private worker?: Worker;\n private sendIdCounter = 0;\n private pendingWorkerRequests = new Map<string, { context: SessionReplayDestinationContext; resolve: () => void }>();\n\n constructor({\n trackServerUrl,\n loggerProvider,\n payloadBatcher,\n workerScript,\n }: {\n trackServerUrl?: string;\n loggerProvider: ILogger;\n payloadBatcher?: PayloadBatcher;\n workerScript?: string;\n }) {\n this.loggerProvider = loggerProvider;\n this.payloadBatcher = payloadBatcher ? payloadBatcher : (payload) => payload;\n this.trackServerUrl = trackServerUrl;\n\n if (workerScript) {\n try {\n const blob = new Blob([workerScript], { type: 'application/javascript' });\n const blobUrl = URL.createObjectURL(blob);\n const worker = new Worker(blobUrl);\n worker.onerror = (e) => {\n e.preventDefault();\n loggerProvider.error(\n `Track destination worker failed, falling back to main-thread sending: ${e.message} (${e.filename}:${e.lineno})`,\n );\n worker.terminate();\n this.worker = undefined;\n // Resolve all pending requests so flush() doesn't hang\n for (const [, pending] of this.pendingWorkerRequests) {\n pending.resolve();\n }\n this.pendingWorkerRequests.clear();\n };\n worker.onmessage = (e: MessageEvent<WorkerMessage>) => {\n const msg = e.data;\n if (msg.type === 'log') {\n loggerProvider.log(msg.message);\n } else if (msg.type === 'warn') {\n loggerProvider.warn(msg.message);\n } else if (msg.type === 'complete') {\n const pending = this.pendingWorkerRequests.get(msg.id);\n if (pending) {\n this.completeRequest({ context: pending.context });\n pending.resolve();\n this.pendingWorkerRequests.delete(msg.id);\n }\n }\n };\n this.worker = worker;\n } catch (error) {\n loggerProvider.error('Failed to create track destination worker, falling back to main-thread sending:', error);\n }\n }\n }\n\n sendEventsList(destinationData: SessionReplayDestination) {\n this.addToQueue({\n ...destinationData,\n attempts: 0,\n timeout: 0,\n });\n }\n\n /**\n * Sends events via navigator.sendBeacon on page exit.\n * Beacon payloads are sent as uncompressed JSON because sendBeacon does not support\n * Content-Encoding, and small incremental batches don't benefit much from compression.\n * The full snapshot has already been sent eagerly via fetch, so the beacon only needs\n * to cover the remaining incremental events since the last fetch flush.\n */\n sendBeacon({\n events,\n sessionId,\n deviceId,\n apiKey,\n serverZone,\n }: {\n events: string[];\n sessionId: string | number;\n deviceId: string;\n apiKey: string;\n serverZone?: keyof typeof ServerZone;\n }) {\n const payload = JSON.stringify({ version: 2, events });\n const urlParams = new URLSearchParams({\n device_id: deviceId,\n session_id: String(sessionId),\n type: 'replay',\n api_key: apiKey,\n });\n const serverUrl = `${getServerUrl(serverZone, this.trackServerUrl)}?${urlParams.toString()}`;\n const globalScope = getGlobalScope();\n try {\n globalScope?.navigator?.sendBeacon?.(serverUrl, payload);\n } catch {\n // Best effort — no fallback on page exit.\n }\n }\n\n addToQueue(...list: SessionReplayDestinationContext[]) {\n const tryable = list.filter((context) => {\n if (context.attempts < (context.flushMaxRetries || 0)) {\n context.attempts += 1;\n return true;\n }\n this.completeRequest({\n context,\n err: MAX_RETRIES_EXCEEDED_MESSAGE,\n });\n return false;\n });\n tryable.forEach((context) => {\n this.queue = this.queue.concat(context);\n this.schedule(0);\n });\n }\n\n schedule(timeout: number) {\n if (this.scheduled) return;\n this.scheduled = setTimeout(() => {\n void this.flush(true).then(() => {\n if (this.queue.length > 0) {\n this.schedule(timeout);\n }\n });\n }, timeout);\n }\n\n async flush(useRetry = false) {\n const list = this.queue;\n this.queue = [];\n\n if (this.scheduled) {\n clearTimeout(this.scheduled);\n this.scheduled = null;\n }\n\n for (const context of list) {\n await this.send(context, useRetry);\n }\n }\n\n async send(context: SessionReplayDestinationContext, useRetry = true) {\n const apiKey = context.apiKey;\n if (!apiKey) {\n return this.completeRequest({ context, err: MISSING_API_KEY_MESSAGE });\n }\n const deviceId = context.deviceId;\n if (!deviceId) {\n return this.completeRequest({ context, err: MISSING_DEVICE_ID_MESSAGE });\n }\n\n const payload = this.payloadBatcher({\n version: 1,\n events: context.events,\n });\n\n if (payload.events.length === 0) {\n this.completeRequest({ context });\n return;\n }\n\n const { worker } = this;\n if (worker) {\n return this.sendViaWorker(worker, context, payload, useRetry);\n }\n\n return this.sendOnMainThread(apiKey, deviceId, context, payload, useRetry);\n }\n\n private async sendViaWorker(\n worker: Worker,\n context: SessionReplayDestinationContext,\n payload: { version: number; events: unknown[] },\n useRetry: boolean,\n ): Promise<void> {\n const id = `${++this.sendIdCounter}`;\n return new Promise<void>((resolve) => {\n this.pendingWorkerRequests.set(id, { context, resolve });\n worker.postMessage({\n type: 'send',\n id,\n payload,\n useRetry,\n context: {\n apiKey: context.apiKey,\n deviceId: context.deviceId,\n sessionId: context.sessionId,\n events: context.events,\n eventType: context.type,\n flushMaxRetries: context.flushMaxRetries ?? 0,\n sampleRate: context.sampleRate,\n serverZone: context.serverZone,\n trackServerUrl: this.trackServerUrl,\n version: context.version,\n currentUrl: getCurrentUrl(),\n sdkVersion: VERSION,\n },\n });\n });\n }\n\n private async sendOnMainThread(\n apiKey: string,\n deviceId: string,\n context: SessionReplayDestinationContext,\n payload: { version: number; events: unknown[] },\n useRetry: boolean,\n ): Promise<void> {\n const url = getCurrentUrl();\n const version = VERSION;\n const sampleRate = context.sampleRate;\n const urlParams = new URLSearchParams({\n device_id: deviceId,\n session_id: `${context.sessionId}`,\n type: `${context.type}`,\n });\n const sessionReplayLibrary = `${context.version?.type ?? 'standalone'}/${context.version?.version ?? version}`;\n\n try {\n const payloadJson = JSON.stringify(payload);\n // Only await gzip when CompressionStream is actually available; skipping the\n // await entirely preserves the synchronous fast-path for browsers/environments\n // (e.g. Jest) that don't support it, keeping retry-timing tests unaffected.\n const globalScope = getGlobalScope();\n const gzipped =\n globalScope && 'CompressionStream' in globalScope ? await gzipJson(payloadJson, globalScope) : null;\n const options: RequestInit = {\n headers: {\n 'Content-Type': 'application/json',\n Accept: '*/*',\n Authorization: `Bearer ${apiKey}`,\n 'X-Client-Version': version,\n 'X-Client-Library': sessionReplayLibrary,\n 'X-Client-Url': url.substring(0, MAX_URL_LENGTH), // limit url length to 1000 characters to avoid ELB 400 error\n 'X-Client-Sample-Rate': `${sampleRate}`,\n 'X-Sampling-Hash-Alg': 'xxhash32',\n ...(gzipped ? { 'Content-Encoding': 'gzip' } : {}),\n },\n body: (gzipped ?? payloadJson) as BodyInit,\n method: 'POST',\n };\n\n const serverUrl = `${getServerUrl(context.serverZone, this.trackServerUrl)}?${urlParams.toString()}`;\n const res = await fetch(serverUrl, options);\n if (res === null) {\n this.completeRequest({ context, err: UNEXPECTED_ERROR_MESSAGE });\n return;\n }\n if (!useRetry) {\n let responseBody = '';\n try {\n responseBody = JSON.stringify(res.body, null, 2);\n } catch {\n // to avoid crash, but don't care about the error, add comment to avoid empty block lint error\n }\n this.completeRequest({ context, success: `${res.status}: ${responseBody}` });\n } else {\n await this.handleReponse(res.status, context);\n }\n } catch (e) {\n this.completeRequest({ context, err: e as string });\n }\n }\n\n async handleReponse(status: number, context: SessionReplayDestinationContext) {\n const parsedStatus = new BaseTransport().buildStatus(status);\n switch (parsedStatus) {\n case Status.Success:\n this.handleSuccessResponse(context);\n break;\n case Status.Failed:\n await this.handleOtherResponse(context);\n break;\n default:\n this.completeRequest({ context, err: UNEXPECTED_NETWORK_ERROR_MESSAGE });\n }\n }\n\n handleSuccessResponse(context: SessionReplayDestinationContext) {\n const sizeOfEventsList = Math.round(new Blob(context.events).size / KB_SIZE);\n this.completeRequest({\n context,\n success: `Session replay event batch tracked successfully for session id ${context.sessionId}, size of events: ${sizeOfEventsList} KB`,\n });\n }\n\n async handleOtherResponse(context: SessionReplayDestinationContext) {\n const delay = Math.random() * context.attempts * this.retryTimeout;\n context.attempts++;\n if (context.attempts > (context.flushMaxRetries || 0)) {\n this.completeRequest({ context, err: MAX_RETRIES_EXCEEDED_MESSAGE });\n return;\n }\n await new Promise<void>((resolve) => setTimeout(resolve, delay));\n await this.send(context, true);\n }\n\n completeRequest({\n context,\n err,\n success,\n }: {\n context: SessionReplayDestinationContext;\n err?: string;\n success?: string;\n }) {\n void context.onComplete();\n if (err) {\n this.loggerProvider.warn(err);\n } else if (success) {\n this.loggerProvider.log(success);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"track-destination.js","sourceRoot":"","sources":["../../src/track-destination.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseTransport, getGlobalScope, ILogger, ServerZone, Status } from '@amplitude/analytics-core';\nimport { getCurrentUrl, getServerUrl } from './helpers';\nimport {\n MAX_RETRIES_EXCEEDED_MESSAGE,\n MISSING_API_KEY_MESSAGE,\n MISSING_DEVICE_ID_MESSAGE,\n UNEXPECTED_ERROR_MESSAGE,\n UNEXPECTED_NETWORK_ERROR_MESSAGE,\n} from './messages';\nimport {\n SessionReplayTrackDestination as AmplitudeSessionReplayTrackDestination,\n SessionReplayDestination,\n SessionReplayDestinationContext,\n} from './typings/session-replay';\nimport { VERSION } from './version';\nimport { MAX_URL_LENGTH, KB_SIZE } from './constants';\nimport { gzipJson } from './utils/gzip';\n\ninterface WorkerCompleteMessage {\n type: 'complete';\n id: string;\n err?: string;\n}\ninterface WorkerLogMessage {\n type: 'log' | 'warn';\n id: string;\n message: string;\n}\ntype WorkerMessage = WorkerCompleteMessage | WorkerLogMessage;\n\nexport type PayloadBatcher = ({ version, events }: { version: number; events: string[] }) => {\n version: number;\n events: unknown[];\n};\n\nexport class SessionReplayTrackDestination implements AmplitudeSessionReplayTrackDestination {\n loggerProvider: ILogger;\n storageKey = '';\n trackServerUrl?: string;\n retryTimeout = 1000;\n private scheduled: ReturnType<typeof setTimeout> | null = null;\n payloadBatcher: PayloadBatcher;\n queue: SessionReplayDestinationContext[] = [];\n private worker?: Worker;\n private sendIdCounter = 0;\n private pendingWorkerRequests = new Map<string, { context: SessionReplayDestinationContext; resolve: () => void }>();\n\n constructor({\n trackServerUrl,\n loggerProvider,\n payloadBatcher,\n workerScript,\n }: {\n trackServerUrl?: string;\n loggerProvider: ILogger;\n payloadBatcher?: PayloadBatcher;\n workerScript?: string;\n }) {\n this.loggerProvider = loggerProvider;\n this.payloadBatcher = payloadBatcher ? payloadBatcher : (payload) => payload;\n this.trackServerUrl = trackServerUrl;\n\n if (workerScript) {\n try {\n const blob = new Blob([workerScript], { type: 'application/javascript' });\n const blobUrl = URL.createObjectURL(blob);\n const worker = new Worker(blobUrl);\n worker.onerror = (e) => {\n e.preventDefault();\n loggerProvider.error(\n `Track destination worker failed, falling back to main-thread sending: ${e.message} (${e.filename}:${e.lineno})`,\n );\n worker.terminate();\n this.worker = undefined;\n // Resolve pending promises so flush() doesn't hang. Do NOT call completeRequest\n // here — the events were never delivered, so onComplete must not fire and the\n // IDB/memory store entries must remain intact for recovery by sendStoredEvents.\n for (const [, pending] of this.pendingWorkerRequests) {\n loggerProvider.warn(`Session replay event send failed due to worker crash: ${e.message}`);\n pending.resolve();\n }\n this.pendingWorkerRequests.clear();\n };\n worker.onmessage = (e: MessageEvent<WorkerMessage>) => {\n const msg = e.data;\n if (msg.type === 'log') {\n loggerProvider.log(msg.message);\n } else if (msg.type === 'warn') {\n loggerProvider.warn(msg.message);\n } else if (msg.type === 'complete') {\n const pending = this.pendingWorkerRequests.get(msg.id);\n if (pending) {\n this.completeRequest({ context: pending.context });\n pending.resolve();\n this.pendingWorkerRequests.delete(msg.id);\n }\n }\n };\n this.worker = worker;\n } catch (error) {\n loggerProvider.error('Failed to create track destination worker, falling back to main-thread sending:', error);\n }\n }\n }\n\n sendEventsList(destinationData: SessionReplayDestination) {\n this.addToQueue({\n ...destinationData,\n attempts: 0,\n timeout: 0,\n });\n }\n\n /**\n * Sends events via navigator.sendBeacon on page exit.\n * Beacon payloads are sent as uncompressed JSON because sendBeacon does not support\n * Content-Encoding, and small incremental batches don't benefit much from compression.\n * The full snapshot has already been sent eagerly via fetch, so the beacon only needs\n * to cover the remaining incremental events since the last fetch flush.\n */\n sendBeacon({\n events,\n sessionId,\n deviceId,\n apiKey,\n serverZone,\n }: {\n events: string[];\n sessionId: string | number;\n deviceId: string;\n apiKey: string;\n serverZone?: keyof typeof ServerZone;\n }) {\n const MAX_BEACON_BYTES = 64 * 1024;\n const byteLength = (s: string) => new Blob([s]).size;\n let trimmedEvents = events;\n let payload = JSON.stringify({ version: 2, events: trimmedEvents });\n if (byteLength(payload) > MAX_BEACON_BYTES) {\n // Binary search for the largest prefix that fits within the beacon size limit.\n // Uses Blob.size to get the UTF-8 byte count, which is what sendBeacon measures.\n let lo = 0;\n let hi = trimmedEvents.length;\n while (lo < hi) {\n const mid = Math.floor((lo + hi + 1) / 2);\n if (byteLength(JSON.stringify({ version: 2, events: trimmedEvents.slice(0, mid) })) <= MAX_BEACON_BYTES) {\n lo = mid;\n } else {\n hi = mid - 1;\n }\n }\n trimmedEvents = trimmedEvents.slice(0, lo);\n payload = JSON.stringify({ version: 2, events: trimmedEvents });\n this.loggerProvider.warn(\n `sendBeacon payload exceeded 64 KB limit, trimmed from ${events.length} to ${trimmedEvents.length} events`,\n );\n }\n if (trimmedEvents.length === 0) {\n return;\n }\n const urlParams = new URLSearchParams({\n device_id: deviceId,\n session_id: String(sessionId),\n type: 'replay',\n api_key: apiKey,\n });\n const serverUrl = `${getServerUrl(serverZone, this.trackServerUrl)}?${urlParams.toString()}`;\n const globalScope = getGlobalScope();\n try {\n // Wrap in a Blob to set Content-Type: application/json; a plain string would\n // cause the browser to send Content-Type: text/plain, which the server rejects.\n const payloadBlob = new Blob([payload], { type: 'application/json' });\n const sent = globalScope?.navigator?.sendBeacon?.(serverUrl, payloadBlob);\n if (sent === false) {\n this.loggerProvider.warn('sendBeacon failed to queue session replay payload');\n }\n } catch {\n // Best effort — no fallback on page exit.\n }\n }\n\n addToQueue(...list: SessionReplayDestinationContext[]) {\n const tryable = list.filter((context) => {\n if (context.attempts < (context.flushMaxRetries || 0)) {\n context.attempts += 1;\n return true;\n }\n this.completeRequest({\n context,\n err: MAX_RETRIES_EXCEEDED_MESSAGE,\n });\n return false;\n });\n tryable.forEach((context) => {\n this.queue = this.queue.concat(context);\n this.schedule(0);\n });\n }\n\n schedule(timeout: number) {\n if (this.scheduled) return;\n this.scheduled = setTimeout(() => {\n void this.flush(true).then(() => {\n if (this.queue.length > 0) {\n this.schedule(timeout);\n }\n });\n }, timeout);\n }\n\n async flush(useRetry = false) {\n const list = this.queue;\n this.queue = [];\n\n if (this.scheduled) {\n clearTimeout(this.scheduled);\n this.scheduled = null;\n }\n\n for (const context of list) {\n await this.send(context, useRetry);\n }\n }\n\n async send(context: SessionReplayDestinationContext, useRetry = true) {\n const apiKey = context.apiKey;\n if (!apiKey) {\n return this.completeRequest({ context, err: MISSING_API_KEY_MESSAGE });\n }\n const deviceId = context.deviceId;\n if (!deviceId) {\n return this.completeRequest({ context, err: MISSING_DEVICE_ID_MESSAGE });\n }\n\n const payload = this.payloadBatcher({\n version: 1,\n events: context.events,\n });\n\n if (payload.events.length === 0) {\n this.completeRequest({ context });\n return;\n }\n\n const { worker } = this;\n if (worker) {\n return this.sendViaWorker(worker, context, payload, useRetry);\n }\n\n return this.sendOnMainThread(apiKey, deviceId, context, payload, useRetry);\n }\n\n private async sendViaWorker(\n worker: Worker,\n context: SessionReplayDestinationContext,\n payload: { version: number; events: unknown[] },\n useRetry: boolean,\n ): Promise<void> {\n const id = `${++this.sendIdCounter}`;\n return new Promise<void>((resolve) => {\n this.pendingWorkerRequests.set(id, { context, resolve });\n worker.postMessage({\n type: 'send',\n id,\n payload,\n useRetry,\n context: {\n apiKey: context.apiKey,\n deviceId: context.deviceId,\n sessionId: context.sessionId,\n events: context.events,\n eventType: context.type,\n flushMaxRetries: context.flushMaxRetries ?? 0,\n sampleRate: context.sampleRate,\n serverZone: context.serverZone,\n trackServerUrl: this.trackServerUrl,\n version: context.version,\n currentUrl: getCurrentUrl(),\n sdkVersion: VERSION,\n },\n });\n });\n }\n\n private async sendOnMainThread(\n apiKey: string,\n deviceId: string,\n context: SessionReplayDestinationContext,\n payload: { version: number; events: unknown[] },\n useRetry: boolean,\n ): Promise<void> {\n const url = getCurrentUrl();\n const version = VERSION;\n const sampleRate = context.sampleRate;\n const urlParams = new URLSearchParams({\n device_id: deviceId,\n session_id: `${context.sessionId}`,\n type: `${context.type}`,\n });\n const sessionReplayLibrary = `${context.version?.type ?? 'standalone'}/${context.version?.version ?? version}`;\n\n try {\n const payloadJson = JSON.stringify(payload);\n // Only await gzip when CompressionStream is actually available; skipping the\n // await entirely preserves the synchronous fast-path for browsers/environments\n // (e.g. Jest) that don't support it, keeping retry-timing tests unaffected.\n const globalScope = getGlobalScope();\n const gzipped =\n globalScope && 'CompressionStream' in globalScope ? await gzipJson(payloadJson, globalScope) : null;\n const options: RequestInit = {\n headers: {\n 'Content-Type': 'application/json',\n Accept: '*/*',\n Authorization: `Bearer ${apiKey}`,\n 'X-Client-Version': version,\n 'X-Client-Library': sessionReplayLibrary,\n 'X-Client-Url': url.substring(0, MAX_URL_LENGTH), // limit url length to 1000 characters to avoid ELB 400 error\n 'X-Client-Sample-Rate': `${sampleRate}`,\n 'X-Sampling-Hash-Alg': 'xxhash32',\n ...(gzipped ? { 'Content-Encoding': 'gzip' } : {}),\n },\n body: (gzipped ?? payloadJson) as BodyInit,\n method: 'POST',\n };\n\n const serverUrl = `${getServerUrl(context.serverZone, this.trackServerUrl)}?${urlParams.toString()}`;\n const res = await fetch(serverUrl, options);\n if (res === null) {\n this.completeRequest({ context, err: UNEXPECTED_ERROR_MESSAGE });\n return;\n }\n if (!useRetry) {\n let responseBody = '';\n try {\n responseBody = JSON.stringify(res.body, null, 2);\n } catch {\n // to avoid crash, but don't care about the error, add comment to avoid empty block lint error\n }\n this.completeRequest({ context, success: `${res.status}: ${responseBody}` });\n } else {\n await this.handleReponse(res.status, context);\n }\n } catch (e) {\n this.completeRequest({ context, err: e as string });\n }\n }\n\n async handleReponse(status: number, context: SessionReplayDestinationContext) {\n const parsedStatus = new BaseTransport().buildStatus(status);\n switch (parsedStatus) {\n case Status.Success:\n this.handleSuccessResponse(context);\n break;\n case Status.Failed:\n await this.handleOtherResponse(context);\n break;\n default:\n this.completeRequest({ context, err: UNEXPECTED_NETWORK_ERROR_MESSAGE });\n }\n }\n\n handleSuccessResponse(context: SessionReplayDestinationContext) {\n const sizeOfEventsList = Math.round(new Blob(context.events).size / KB_SIZE);\n this.completeRequest({\n context,\n success: `Session replay event batch tracked successfully for session id ${context.sessionId}, size of events: ${sizeOfEventsList} KB`,\n });\n }\n\n async handleOtherResponse(context: SessionReplayDestinationContext) {\n const delay = Math.random() * context.attempts * this.retryTimeout;\n context.attempts++;\n if (context.attempts > (context.flushMaxRetries || 0)) {\n this.completeRequest({ context, err: MAX_RETRIES_EXCEEDED_MESSAGE });\n return;\n }\n await new Promise<void>((resolve) => setTimeout(resolve, delay));\n await this.send(context, true);\n }\n\n completeRequest({\n context,\n err,\n success,\n }: {\n context: SessionReplayDestinationContext;\n err?: string;\n success?: string;\n }) {\n void context.onComplete();\n if (err) {\n this.loggerProvider.warn(err);\n } else if (success) {\n this.loggerProvider.log(success);\n }\n }\n}\n"]}
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "1.36.0-SR-3115.1";
1
+ export declare const VERSION = "1.36.1";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,OAAO,qBAAqB,CAAC"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,OAAO,WAAW,CAAC"}
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
4
  // Autogenerated by `pnpm version-file`. DO NOT EDIT
5
- exports.VERSION = '1.36.0-SR-3115.1';
5
+ exports.VERSION = '1.36.1';
6
6
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":";;;AAAA,oDAAoD;AACvC,QAAA,OAAO,GAAG,kBAAkB,CAAC","sourcesContent":["// Autogenerated by `pnpm version-file`. DO NOT EDIT\nexport const VERSION = '1.36.0-SR-3115.1';\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":";;;AAAA,oDAAoD;AACvC,QAAA,OAAO,GAAG,QAAQ,CAAC","sourcesContent":["// Autogenerated by `pnpm version-file`. DO NOT EDIT\nexport const VERSION = '1.36.1';\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"event-compressor.d.ts","sourceRoot":"","sources":["../../../src/events/event-compressor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAEvE,UAAU,SAAS;IACjB,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B;AAGD,qBAAa,eAAe;IAC1B,SAAS,EAAE,SAAS,EAAE,CAAM;IAC5B,YAAY,UAAS;IACrB,aAAa,CAAC,EAAE,0BAA0B,CAAC,QAAQ,GAAG,aAAa,EAAE,MAAM,CAAC,CAAC;IAC7E,MAAM,EAAE,yBAAyB,CAAC;IAClC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,kBAAkB,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uBAAuB,CAAC,EAAE,MAAM,IAAI,CAAC;gBAGnC,aAAa,EAAE,0BAA0B,CAAC,QAAQ,GAAG,aAAa,EAAE,MAAM,CAAC,EAC3E,MAAM,EAAE,yBAAyB,EACjC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,YAAY,CAAC,EAAE,MAAM,EACrB,uBAAuB,CAAC,EAAE,MAAM,IAAI;IAuC/B,sBAAsB,IAAI,IAAI;IAa9B,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAuBpE,YAAY,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI;IAuBrD,aAAa,UAAW,aAAa,KAAG,MAAM,CAS5C;IAEF,OAAO,CAAC,2BAA2B,CAQjC;IAEK,kBAAkB,UAAW,aAAa,aAAa,MAAM,GAAG,MAAM,UAkB3E;IAEK,SAAS,aAEd;CACH"}
1
+ {"version":3,"file":"event-compressor.d.ts","sourceRoot":"","sources":["../../../src/events/event-compressor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAEvE,UAAU,SAAS;IACjB,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B;AAGD,qBAAa,eAAe;IAC1B,SAAS,EAAE,SAAS,EAAE,CAAM;IAC5B,YAAY,UAAS;IACrB,aAAa,CAAC,EAAE,0BAA0B,CAAC,QAAQ,GAAG,aAAa,EAAE,MAAM,CAAC,CAAC;IAC7E,MAAM,EAAE,yBAAyB,CAAC;IAClC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,kBAAkB,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uBAAuB,CAAC,EAAE,MAAM,IAAI,CAAC;gBAGnC,aAAa,EAAE,0BAA0B,CAAC,QAAQ,GAAG,aAAa,EAAE,MAAM,CAAC,EAC3E,MAAM,EAAE,yBAAyB,EACjC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,YAAY,CAAC,EAAE,MAAM,EACrB,uBAAuB,CAAC,EAAE,MAAM,IAAI;IAuC/B,sBAAsB,IAAI,IAAI;IAa9B,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAkCpE,YAAY,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI;IAuBrD,aAAa,UAAW,aAAa,KAAG,MAAM,CAS5C;IAEF,OAAO,CAAC,2BAA2B,CAQjC;IAEK,kBAAkB,UAAW,aAAa,aAAa,MAAM,GAAG,MAAM,UAkB3E;IAEK,SAAS,aAEd;CACH"}
@@ -1,3 +1,4 @@
1
+ import { __values } from "tslib";
1
2
  import { getGlobalScope } from '@amplitude/analytics-core';
2
3
  import { EventType as RRWebEventType } from '@amplitude/rrweb-types';
3
4
  var DEFAULT_TIMEOUT = 2000;
@@ -94,18 +95,40 @@ var EventCompressor = /** @class */ (function () {
94
95
  };
95
96
  // Add an event to the task queue if idle callback is supported or compress the event directly
96
97
  EventCompressor.prototype.enqueueEvent = function (event, sessionId) {
97
- var _a, _b;
98
+ var e_1, _a;
99
+ var _b, _c;
98
100
  // Full snapshot (type 2) is the most critical event — a replay cannot be played without it.
99
101
  // Process and flush immediately rather than waiting for the idle scheduler or web worker,
100
102
  // maximising the chance it is delivered before the user exits the page.
101
103
  if (event.type === RRWebEventType.FullSnapshot) {
102
104
  this.config.loggerProvider.debug('Processing full snapshot immediately.');
105
+ // Drain any events still pending in the idle-callback queue first.
106
+ // Those events reference the pre-snapshot DOM and must be sent before
107
+ // the full snapshot; if we let them be processed later they'd arrive at
108
+ // the server after the snapshot and cause "node not found" replay errors.
109
+ if (this.taskQueue.length > 0) {
110
+ try {
111
+ for (var _d = __values(this.taskQueue.splice(0)), _e = _d.next(); !_e.done; _e = _d.next()) {
112
+ var task = _e.value;
113
+ var compressed = this.compressEvent(task.event);
114
+ this.addCompressedEventToManager(compressed, task.sessionId);
115
+ }
116
+ }
117
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
118
+ finally {
119
+ try {
120
+ if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
121
+ }
122
+ finally { if (e_1) throw e_1.error; }
123
+ }
124
+ this.isProcessing = false;
125
+ }
103
126
  var compressedEvent = this.compressEvent(event);
104
127
  this.addCompressedEventToManager(compressedEvent, sessionId);
105
- (_a = this.onFullSnapshotProcessed) === null || _a === void 0 ? void 0 : _a.call(this);
128
+ (_b = this.onFullSnapshotProcessed) === null || _b === void 0 ? void 0 : _b.call(this);
106
129
  return;
107
130
  }
108
- if (this.canUseIdleCallback && ((_b = this.config.performanceConfig) === null || _b === void 0 ? void 0 : _b.enabled)) {
131
+ if (this.canUseIdleCallback && ((_c = this.config.performanceConfig) === null || _c === void 0 ? void 0 : _c.enabled)) {
109
132
  this.config.loggerProvider.debug('Enqueuing event for processing during idle time.');
110
133
  this.taskQueue.push({ event: event, sessionId: sessionId });
111
134
  this.scheduleIdleProcessing();
@@ -1 +1 @@
1
- {"version":3,"file":"event-compressor.js","sourceRoot":"","sources":["../../../src/events/event-compressor.ts"],"names":[],"mappings":"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","sourcesContent":["import { getGlobalScope } from '@amplitude/analytics-core';\nimport { EventType as RRWebEventType } from '@amplitude/rrweb-types';\nimport type { eventWithTime } from '@amplitude/rrweb-types';\nimport { SessionReplayJoinedConfig } from '../config/types';\nimport { SessionReplayEventsManager } from '../typings/session-replay';\n\ninterface TaskQueue {\n event: eventWithTime;\n sessionId: string | number;\n}\n\nconst DEFAULT_TIMEOUT = 2000;\nexport class EventCompressor {\n taskQueue: TaskQueue[] = [];\n isProcessing = false;\n eventsManager?: SessionReplayEventsManager<'replay' | 'interaction', string>;\n config: SessionReplayJoinedConfig;\n deviceId: string | undefined;\n canUseIdleCallback: boolean | undefined;\n timeout: number;\n worker?: Worker;\n onFullSnapshotProcessed?: () => void;\n\n constructor(\n eventsManager: SessionReplayEventsManager<'replay' | 'interaction', string>,\n config: SessionReplayJoinedConfig,\n deviceId: string | undefined,\n workerScript?: string,\n onFullSnapshotProcessed?: () => void,\n ) {\n const globalScope = getGlobalScope();\n this.canUseIdleCallback = globalScope && 'requestIdleCallback' in globalScope;\n this.eventsManager = eventsManager;\n this.config = config;\n this.deviceId = deviceId;\n this.timeout = config.performanceConfig?.timeout || DEFAULT_TIMEOUT;\n this.onFullSnapshotProcessed = onFullSnapshotProcessed;\n\n if (workerScript) {\n config.loggerProvider.log('Enabling web worker for compression');\n\n try {\n const blob = new Blob([workerScript], { type: 'application/javascript' });\n const blobUrl = URL.createObjectURL(blob);\n const worker = new Worker(blobUrl);\n\n worker.onerror = (e) => {\n e.preventDefault();\n config.loggerProvider.error(\n `Worker failed, falling back to non-worker compression: ${e.message} (${e.filename}:${e.lineno})`,\n );\n worker.terminate();\n this.worker = undefined;\n };\n worker.onmessage = (e) => {\n const { compressedEvent, sessionId } = e.data as Record<string, string>;\n this.addCompressedEventToManager(compressedEvent, sessionId);\n };\n\n this.worker = worker;\n } catch (error) {\n config.loggerProvider.error('Failed to create worker, falling back to non-worker compression:', error);\n }\n }\n }\n\n // Schedule processing during idle time\n public scheduleIdleProcessing(): void {\n if (!this.isProcessing) {\n this.isProcessing = true;\n requestIdleCallback(\n (idleDeadline) => {\n this.processQueue(idleDeadline);\n },\n { timeout: this.timeout },\n );\n }\n }\n\n // Add an event to the task queue if idle callback is supported or compress the event directly\n public enqueueEvent(event: eventWithTime, sessionId: string | number): void {\n // Full snapshot (type 2) is the most critical event — a replay cannot be played without it.\n // Process and flush immediately rather than waiting for the idle scheduler or web worker,\n // maximising the chance it is delivered before the user exits the page.\n if (event.type === RRWebEventType.FullSnapshot) {\n this.config.loggerProvider.debug('Processing full snapshot immediately.');\n const compressedEvent = this.compressEvent(event);\n this.addCompressedEventToManager(compressedEvent, sessionId);\n this.onFullSnapshotProcessed?.();\n return;\n }\n\n if (this.canUseIdleCallback && this.config.performanceConfig?.enabled) {\n this.config.loggerProvider.debug('Enqueuing event for processing during idle time.');\n this.taskQueue.push({ event, sessionId });\n this.scheduleIdleProcessing();\n } else {\n this.config.loggerProvider.debug('Processing event without idle callback.');\n this.addCompressedEvent(event, sessionId);\n }\n }\n\n // Process the task queue during idle time\n public processQueue(idleDeadline: IdleDeadline): void {\n // Process tasks while there's idle time or until the max number of tasks is reached\n while (this.taskQueue.length > 0 && (idleDeadline.timeRemaining() > 0 || idleDeadline.didTimeout)) {\n const task = this.taskQueue.shift();\n if (task) {\n const { event, sessionId } = task;\n this.addCompressedEvent(event, sessionId);\n }\n }\n\n // If there are still tasks in the queue, schedule the next idle callback\n if (this.taskQueue.length > 0) {\n requestIdleCallback(\n (idleDeadline) => {\n this.processQueue(idleDeadline);\n },\n { timeout: this.timeout },\n );\n } else {\n this.isProcessing = false;\n }\n }\n\n compressEvent = (event: eventWithTime): string => {\n // Serialize with type+timestamp first for streaming parser compatibility.\n // JS engines serialize non-integer string keys in insertion order (ES2015 spec,\n // reliable across V8/SpiderMonkey/JSC), so explicit construction controls key order.\n // `delay` is an rrweb player field: an optional ms offset applied on top of\n // `timestamp` during replay to smooth out batched/throttled events. Preserve\n // it when present so playback timing is accurate.\n const { type, timestamp, delay, data } = event as eventWithTime & { delay?: number };\n return delay != null ? JSON.stringify({ type, timestamp, delay, data }) : JSON.stringify({ type, timestamp, data });\n };\n\n private addCompressedEventToManager = (compressedEvent: string, sessionId: string | number) => {\n if (this.eventsManager && this.deviceId) {\n this.eventsManager.addEvent({\n event: { type: 'replay', data: compressedEvent },\n sessionId,\n deviceId: this.deviceId,\n });\n }\n };\n\n public addCompressedEvent = (event: eventWithTime, sessionId: string | number) => {\n if (this.worker) {\n // This indirectly compresses the event.\n try {\n this.worker.postMessage({ event, sessionId });\n } catch (err: any) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n if (err.name === 'DataCloneError') {\n // fallback: serialize\n this.worker.postMessage(JSON.stringify({ event, sessionId }));\n } else {\n this.config.loggerProvider.warn('Unexpected error while posting message to worker:', err);\n }\n }\n } else {\n const compressedEvent = this.compressEvent(event);\n this.addCompressedEventToManager(compressedEvent, sessionId);\n }\n };\n\n public terminate = () => {\n this.worker?.terminate();\n };\n}\n"]}
1
+ {"version":3,"file":"event-compressor.js","sourceRoot":"","sources":["../../../src/events/event-compressor.ts"],"names":[],"mappings":"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","sourcesContent":["import { getGlobalScope } from '@amplitude/analytics-core';\nimport { EventType as RRWebEventType } from '@amplitude/rrweb-types';\nimport type { eventWithTime } from '@amplitude/rrweb-types';\nimport { SessionReplayJoinedConfig } from '../config/types';\nimport { SessionReplayEventsManager } from '../typings/session-replay';\n\ninterface TaskQueue {\n event: eventWithTime;\n sessionId: string | number;\n}\n\nconst DEFAULT_TIMEOUT = 2000;\nexport class EventCompressor {\n taskQueue: TaskQueue[] = [];\n isProcessing = false;\n eventsManager?: SessionReplayEventsManager<'replay' | 'interaction', string>;\n config: SessionReplayJoinedConfig;\n deviceId: string | undefined;\n canUseIdleCallback: boolean | undefined;\n timeout: number;\n worker?: Worker;\n onFullSnapshotProcessed?: () => void;\n\n constructor(\n eventsManager: SessionReplayEventsManager<'replay' | 'interaction', string>,\n config: SessionReplayJoinedConfig,\n deviceId: string | undefined,\n workerScript?: string,\n onFullSnapshotProcessed?: () => void,\n ) {\n const globalScope = getGlobalScope();\n this.canUseIdleCallback = globalScope && 'requestIdleCallback' in globalScope;\n this.eventsManager = eventsManager;\n this.config = config;\n this.deviceId = deviceId;\n this.timeout = config.performanceConfig?.timeout || DEFAULT_TIMEOUT;\n this.onFullSnapshotProcessed = onFullSnapshotProcessed;\n\n if (workerScript) {\n config.loggerProvider.log('Enabling web worker for compression');\n\n try {\n const blob = new Blob([workerScript], { type: 'application/javascript' });\n const blobUrl = URL.createObjectURL(blob);\n const worker = new Worker(blobUrl);\n\n worker.onerror = (e) => {\n e.preventDefault();\n config.loggerProvider.error(\n `Worker failed, falling back to non-worker compression: ${e.message} (${e.filename}:${e.lineno})`,\n );\n worker.terminate();\n this.worker = undefined;\n };\n worker.onmessage = (e) => {\n const { compressedEvent, sessionId } = e.data as Record<string, string>;\n this.addCompressedEventToManager(compressedEvent, sessionId);\n };\n\n this.worker = worker;\n } catch (error) {\n config.loggerProvider.error('Failed to create worker, falling back to non-worker compression:', error);\n }\n }\n }\n\n // Schedule processing during idle time\n public scheduleIdleProcessing(): void {\n if (!this.isProcessing) {\n this.isProcessing = true;\n requestIdleCallback(\n (idleDeadline) => {\n this.processQueue(idleDeadline);\n },\n { timeout: this.timeout },\n );\n }\n }\n\n // Add an event to the task queue if idle callback is supported or compress the event directly\n public enqueueEvent(event: eventWithTime, sessionId: string | number): void {\n // Full snapshot (type 2) is the most critical event — a replay cannot be played without it.\n // Process and flush immediately rather than waiting for the idle scheduler or web worker,\n // maximising the chance it is delivered before the user exits the page.\n if (event.type === RRWebEventType.FullSnapshot) {\n this.config.loggerProvider.debug('Processing full snapshot immediately.');\n // Drain any events still pending in the idle-callback queue first.\n // Those events reference the pre-snapshot DOM and must be sent before\n // the full snapshot; if we let them be processed later they'd arrive at\n // the server after the snapshot and cause \"node not found\" replay errors.\n if (this.taskQueue.length > 0) {\n for (const task of this.taskQueue.splice(0)) {\n const compressed = this.compressEvent(task.event);\n this.addCompressedEventToManager(compressed, task.sessionId);\n }\n this.isProcessing = false;\n }\n const compressedEvent = this.compressEvent(event);\n this.addCompressedEventToManager(compressedEvent, sessionId);\n this.onFullSnapshotProcessed?.();\n return;\n }\n\n if (this.canUseIdleCallback && this.config.performanceConfig?.enabled) {\n this.config.loggerProvider.debug('Enqueuing event for processing during idle time.');\n this.taskQueue.push({ event, sessionId });\n this.scheduleIdleProcessing();\n } else {\n this.config.loggerProvider.debug('Processing event without idle callback.');\n this.addCompressedEvent(event, sessionId);\n }\n }\n\n // Process the task queue during idle time\n public processQueue(idleDeadline: IdleDeadline): void {\n // Process tasks while there's idle time or until the max number of tasks is reached\n while (this.taskQueue.length > 0 && (idleDeadline.timeRemaining() > 0 || idleDeadline.didTimeout)) {\n const task = this.taskQueue.shift();\n if (task) {\n const { event, sessionId } = task;\n this.addCompressedEvent(event, sessionId);\n }\n }\n\n // If there are still tasks in the queue, schedule the next idle callback\n if (this.taskQueue.length > 0) {\n requestIdleCallback(\n (idleDeadline) => {\n this.processQueue(idleDeadline);\n },\n { timeout: this.timeout },\n );\n } else {\n this.isProcessing = false;\n }\n }\n\n compressEvent = (event: eventWithTime): string => {\n // Serialize with type+timestamp first for streaming parser compatibility.\n // JS engines serialize non-integer string keys in insertion order (ES2015 spec,\n // reliable across V8/SpiderMonkey/JSC), so explicit construction controls key order.\n // `delay` is an rrweb player field: an optional ms offset applied on top of\n // `timestamp` during replay to smooth out batched/throttled events. Preserve\n // it when present so playback timing is accurate.\n const { type, timestamp, delay, data } = event as eventWithTime & { delay?: number };\n return delay != null ? JSON.stringify({ type, timestamp, delay, data }) : JSON.stringify({ type, timestamp, data });\n };\n\n private addCompressedEventToManager = (compressedEvent: string, sessionId: string | number) => {\n if (this.eventsManager && this.deviceId) {\n this.eventsManager.addEvent({\n event: { type: 'replay', data: compressedEvent },\n sessionId,\n deviceId: this.deviceId,\n });\n }\n };\n\n public addCompressedEvent = (event: eventWithTime, sessionId: string | number) => {\n if (this.worker) {\n // This indirectly compresses the event.\n try {\n this.worker.postMessage({ event, sessionId });\n } catch (err: any) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n if (err.name === 'DataCloneError') {\n // fallback: serialize\n this.worker.postMessage(JSON.stringify({ event, sessionId }));\n } else {\n this.config.loggerProvider.warn('Unexpected error while posting message to worker:', err);\n }\n }\n } else {\n const compressedEvent = this.compressEvent(event);\n this.addCompressedEventToManager(compressedEvent, sessionId);\n }\n };\n\n public terminate = () => {\n this.worker?.terminate();\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"track-destination.d.ts","sourceRoot":"","sources":["../../src/track-destination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,OAAO,EAAE,UAAU,EAAU,MAAM,2BAA2B,CAAC;AASvG,OAAO,EACL,6BAA6B,IAAI,sCAAsC,EACvE,wBAAwB,EACxB,+BAA+B,EAChC,MAAM,0BAA0B,CAAC;AAiBlC,MAAM,MAAM,cAAc,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,KAAK;IAC3F,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB,CAAC;AAEF,qBAAa,6BAA8B,YAAW,sCAAsC;IAC1F,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,SAAM;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,SAAQ;IACpB,OAAO,CAAC,SAAS,CAA8C;IAC/D,cAAc,EAAE,cAAc,CAAC;IAC/B,KAAK,EAAE,+BAA+B,EAAE,CAAM;IAC9C,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,qBAAqB,CAAwF;gBAEzG,EACV,cAAc,EACd,cAAc,EACd,cAAc,EACd,YAAY,GACb,EAAE;QACD,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,OAAO,CAAC;QACxB,cAAc,CAAC,EAAE,cAAc,CAAC;QAChC,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB;IA6CD,cAAc,CAAC,eAAe,EAAE,wBAAwB;IAQxD;;;;;;OAMG;IACH,UAAU,CAAC,EACT,MAAM,EACN,SAAS,EACT,QAAQ,EACR,MAAM,EACN,UAAU,GACX,EAAE;QACD,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;QAC3B,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,OAAO,UAAU,CAAC;KACtC;IAiBD,UAAU,CAAC,GAAG,IAAI,EAAE,+BAA+B,EAAE;IAkBrD,QAAQ,CAAC,OAAO,EAAE,MAAM;IAWlB,KAAK,CAAC,QAAQ,UAAQ;IActB,IAAI,CAAC,OAAO,EAAE,+BAA+B,EAAE,QAAQ,UAAO;YA4BtD,aAAa;YAgCb,gBAAgB;IA+DxB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,+BAA+B;IAc5E,qBAAqB,CAAC,OAAO,EAAE,+BAA+B;IAQxD,mBAAmB,CAAC,OAAO,EAAE,+BAA+B;IAWlE,eAAe,CAAC,EACd,OAAO,EACP,GAAG,EACH,OAAO,GACR,EAAE;QACD,OAAO,EAAE,+BAA+B,CAAC;QACzC,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB;CAQF"}
1
+ {"version":3,"file":"track-destination.d.ts","sourceRoot":"","sources":["../../src/track-destination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,OAAO,EAAE,UAAU,EAAU,MAAM,2BAA2B,CAAC;AASvG,OAAO,EACL,6BAA6B,IAAI,sCAAsC,EACvE,wBAAwB,EACxB,+BAA+B,EAChC,MAAM,0BAA0B,CAAC;AAiBlC,MAAM,MAAM,cAAc,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,KAAK;IAC3F,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB,CAAC;AAEF,qBAAa,6BAA8B,YAAW,sCAAsC;IAC1F,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,SAAM;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,SAAQ;IACpB,OAAO,CAAC,SAAS,CAA8C;IAC/D,cAAc,EAAE,cAAc,CAAC;IAC/B,KAAK,EAAE,+BAA+B,EAAE,CAAM;IAC9C,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,qBAAqB,CAAwF;gBAEzG,EACV,cAAc,EACd,cAAc,EACd,cAAc,EACd,YAAY,GACb,EAAE;QACD,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,OAAO,CAAC;QACxB,cAAc,CAAC,EAAE,cAAc,CAAC;QAChC,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB;IAgDD,cAAc,CAAC,eAAe,EAAE,wBAAwB;IAQxD;;;;;;OAMG;IACH,UAAU,CAAC,EACT,MAAM,EACN,SAAS,EACT,QAAQ,EACR,MAAM,EACN,UAAU,GACX,EAAE;QACD,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;QAC3B,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,OAAO,UAAU,CAAC;KACtC;IAgDD,UAAU,CAAC,GAAG,IAAI,EAAE,+BAA+B,EAAE;IAkBrD,QAAQ,CAAC,OAAO,EAAE,MAAM;IAWlB,KAAK,CAAC,QAAQ,UAAQ;IActB,IAAI,CAAC,OAAO,EAAE,+BAA+B,EAAE,QAAQ,UAAO;YA4BtD,aAAa;YAgCb,gBAAgB;IA+DxB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,+BAA+B;IAc5E,qBAAqB,CAAC,OAAO,EAAE,+BAA+B;IAQxD,mBAAmB,CAAC,OAAO,EAAE,+BAA+B;IAWlE,eAAe,CAAC,EACd,OAAO,EACP,GAAG,EACH,OAAO,GACR,EAAE;QACD,OAAO,EAAE,+BAA+B,CAAC;QACzC,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB;CAQF"}
@@ -30,9 +30,12 @@ var SessionReplayTrackDestination = /** @class */ (function () {
30
30
  worker_1.terminate();
31
31
  _this.worker = undefined;
32
32
  try {
33
- // Resolve all pending requests so flush() doesn't hang
33
+ // Resolve pending promises so flush() doesn't hang. Do NOT call completeRequest
34
+ // here — the events were never delivered, so onComplete must not fire and the
35
+ // IDB/memory store entries must remain intact for recovery by sendStoredEvents.
34
36
  for (var _b = __values(_this.pendingWorkerRequests), _c = _b.next(); !_c.done; _c = _b.next()) {
35
37
  var _d = __read(_c.value, 2), pending_1 = _d[1];
38
+ loggerProvider.warn("Session replay event send failed due to worker crash: ".concat(e.message));
36
39
  pending_1.resolve();
37
40
  }
38
41
  }
@@ -82,7 +85,31 @@ var SessionReplayTrackDestination = /** @class */ (function () {
82
85
  SessionReplayTrackDestination.prototype.sendBeacon = function (_a) {
83
86
  var _b, _c;
84
87
  var events = _a.events, sessionId = _a.sessionId, deviceId = _a.deviceId, apiKey = _a.apiKey, serverZone = _a.serverZone;
85
- var payload = JSON.stringify({ version: 2, events: events });
88
+ var MAX_BEACON_BYTES = 64 * 1024;
89
+ var byteLength = function (s) { return new Blob([s]).size; };
90
+ var trimmedEvents = events;
91
+ var payload = JSON.stringify({ version: 2, events: trimmedEvents });
92
+ if (byteLength(payload) > MAX_BEACON_BYTES) {
93
+ // Binary search for the largest prefix that fits within the beacon size limit.
94
+ // Uses Blob.size to get the UTF-8 byte count, which is what sendBeacon measures.
95
+ var lo = 0;
96
+ var hi = trimmedEvents.length;
97
+ while (lo < hi) {
98
+ var mid = Math.floor((lo + hi + 1) / 2);
99
+ if (byteLength(JSON.stringify({ version: 2, events: trimmedEvents.slice(0, mid) })) <= MAX_BEACON_BYTES) {
100
+ lo = mid;
101
+ }
102
+ else {
103
+ hi = mid - 1;
104
+ }
105
+ }
106
+ trimmedEvents = trimmedEvents.slice(0, lo);
107
+ payload = JSON.stringify({ version: 2, events: trimmedEvents });
108
+ this.loggerProvider.warn("sendBeacon payload exceeded 64 KB limit, trimmed from ".concat(events.length, " to ").concat(trimmedEvents.length, " events"));
109
+ }
110
+ if (trimmedEvents.length === 0) {
111
+ return;
112
+ }
86
113
  var urlParams = new URLSearchParams({
87
114
  device_id: deviceId,
88
115
  session_id: String(sessionId),
@@ -92,7 +119,13 @@ var SessionReplayTrackDestination = /** @class */ (function () {
92
119
  var serverUrl = "".concat(getServerUrl(serverZone, this.trackServerUrl), "?").concat(urlParams.toString());
93
120
  var globalScope = getGlobalScope();
94
121
  try {
95
- (_c = (_b = globalScope === null || globalScope === void 0 ? void 0 : globalScope.navigator) === null || _b === void 0 ? void 0 : _b.sendBeacon) === null || _c === void 0 ? void 0 : _c.call(_b, serverUrl, payload);
122
+ // Wrap in a Blob to set Content-Type: application/json; a plain string would
123
+ // cause the browser to send Content-Type: text/plain, which the server rejects.
124
+ var payloadBlob = new Blob([payload], { type: 'application/json' });
125
+ var sent = (_c = (_b = globalScope === null || globalScope === void 0 ? void 0 : globalScope.navigator) === null || _b === void 0 ? void 0 : _b.sendBeacon) === null || _c === void 0 ? void 0 : _c.call(_b, serverUrl, payloadBlob);
126
+ if (sent === false) {
127
+ this.loggerProvider.warn('sendBeacon failed to queue session replay payload');
128
+ }
96
129
  }
97
130
  catch (_d) {
98
131
  // Best effort — no fallback on page exit.