@amplitude/session-replay-browser 1.47.0-sr-trc-debug-log.3 → 1.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +203 -0
  2. package/lib/cjs/beacon-transport.d.ts +2 -0
  3. package/lib/cjs/beacon-transport.d.ts.map +1 -1
  4. package/lib/cjs/beacon-transport.js +39 -1
  5. package/lib/cjs/beacon-transport.js.map +1 -1
  6. package/lib/cjs/config/joined-config.d.ts +1 -6
  7. package/lib/cjs/config/joined-config.d.ts.map +1 -1
  8. package/lib/cjs/config/joined-config.js +23 -64
  9. package/lib/cjs/config/joined-config.js.map +1 -1
  10. package/lib/cjs/config/local-config.d.ts +4 -6
  11. package/lib/cjs/config/local-config.d.ts.map +1 -1
  12. package/lib/cjs/config/local-config.js +3 -19
  13. package/lib/cjs/config/local-config.js.map +1 -1
  14. package/lib/cjs/config/types.d.ts +74 -19
  15. package/lib/cjs/config/types.d.ts.map +1 -1
  16. package/lib/cjs/config/types.js.map +1 -1
  17. package/lib/cjs/index.d.ts +1 -0
  18. package/lib/cjs/index.d.ts.map +1 -1
  19. package/lib/cjs/index.js.map +1 -1
  20. package/lib/cjs/plugins/url-tracking-plugin.d.ts +0 -13
  21. package/lib/cjs/plugins/url-tracking-plugin.d.ts.map +1 -1
  22. package/lib/cjs/plugins/url-tracking-plugin.js +2 -6
  23. package/lib/cjs/plugins/url-tracking-plugin.js.map +1 -1
  24. package/lib/cjs/session-replay.d.ts +0 -33
  25. package/lib/cjs/session-replay.d.ts.map +1 -1
  26. package/lib/cjs/session-replay.js +40 -335
  27. package/lib/cjs/session-replay.js.map +1 -1
  28. package/lib/cjs/targeting/targeting-manager.d.ts +1 -4
  29. package/lib/cjs/targeting/targeting-manager.d.ts.map +1 -1
  30. package/lib/cjs/targeting/targeting-manager.js +10 -56
  31. package/lib/cjs/targeting/targeting-manager.js.map +1 -1
  32. package/lib/cjs/track-destination.d.ts +5 -1
  33. package/lib/cjs/track-destination.d.ts.map +1 -1
  34. package/lib/cjs/track-destination.js +212 -55
  35. package/lib/cjs/track-destination.js.map +1 -1
  36. package/lib/cjs/version.d.ts +1 -1
  37. package/lib/cjs/version.d.ts.map +1 -1
  38. package/lib/cjs/version.js +1 -1
  39. package/lib/cjs/version.js.map +1 -1
  40. package/lib/cjs/worker/index.js +1 -1
  41. package/lib/esm/beacon-transport.d.ts +2 -0
  42. package/lib/esm/beacon-transport.d.ts.map +1 -1
  43. package/lib/esm/beacon-transport.js +39 -1
  44. package/lib/esm/beacon-transport.js.map +1 -1
  45. package/lib/esm/config/joined-config.d.ts +1 -6
  46. package/lib/esm/config/joined-config.d.ts.map +1 -1
  47. package/lib/esm/config/joined-config.js +23 -64
  48. package/lib/esm/config/joined-config.js.map +1 -1
  49. package/lib/esm/config/local-config.d.ts +4 -6
  50. package/lib/esm/config/local-config.d.ts.map +1 -1
  51. package/lib/esm/config/local-config.js +4 -20
  52. package/lib/esm/config/local-config.js.map +1 -1
  53. package/lib/esm/config/types.d.ts +74 -19
  54. package/lib/esm/config/types.d.ts.map +1 -1
  55. package/lib/esm/config/types.js.map +1 -1
  56. package/lib/esm/index.d.ts +1 -0
  57. package/lib/esm/index.d.ts.map +1 -1
  58. package/lib/esm/index.js.map +1 -1
  59. package/lib/esm/plugins/url-tracking-plugin.d.ts +0 -13
  60. package/lib/esm/plugins/url-tracking-plugin.d.ts.map +1 -1
  61. package/lib/esm/plugins/url-tracking-plugin.js +2 -6
  62. package/lib/esm/plugins/url-tracking-plugin.js.map +1 -1
  63. package/lib/esm/session-replay.d.ts +0 -33
  64. package/lib/esm/session-replay.d.ts.map +1 -1
  65. package/lib/esm/session-replay.js +40 -335
  66. package/lib/esm/session-replay.js.map +1 -1
  67. package/lib/esm/targeting/targeting-manager.d.ts +1 -4
  68. package/lib/esm/targeting/targeting-manager.d.ts.map +1 -1
  69. package/lib/esm/targeting/targeting-manager.js +10 -56
  70. package/lib/esm/targeting/targeting-manager.js.map +1 -1
  71. package/lib/esm/track-destination.d.ts +5 -1
  72. package/lib/esm/track-destination.d.ts.map +1 -1
  73. package/lib/esm/track-destination.js +212 -55
  74. package/lib/esm/track-destination.js.map +1 -1
  75. package/lib/esm/version.d.ts +1 -1
  76. package/lib/esm/version.d.ts.map +1 -1
  77. package/lib/esm/version.js +1 -1
  78. package/lib/esm/version.js.map +1 -1
  79. package/lib/esm/worker/index.js +1 -1
  80. package/lib/scripts/index-min.js +1 -1
  81. package/lib/scripts/index-min.js.gz +0 -0
  82. package/lib/scripts/index-min.js.map +1 -1
  83. package/lib/scripts/observers-min.js +1 -1
  84. package/lib/scripts/observers-min.js.gz +0 -0
  85. package/lib/scripts/session-replay-browser-min.js +1 -1
  86. package/lib/scripts/session-replay-browser-min.js.gz +0 -0
  87. package/lib/scripts/session-replay-browser-min.js.map +1 -1
  88. package/lib/scripts/targeting-min.js +1 -1
  89. package/lib/scripts/targeting-min.js.gz +0 -0
  90. package/lib/scripts/worker-min.js +1 -1
  91. package/lib/scripts/worker-min.js.gz +0 -0
  92. package/package.json +4 -4
  93. package/lib/cjs/diagnostics.d.ts +0 -50
  94. package/lib/cjs/diagnostics.d.ts.map +0 -1
  95. package/lib/cjs/diagnostics.js +0 -67
  96. package/lib/cjs/diagnostics.js.map +0 -1
  97. package/lib/esm/diagnostics.d.ts +0 -50
  98. package/lib/esm/diagnostics.d.ts.map +0 -1
  99. package/lib/esm/diagnostics.js +0 -64
  100. package/lib/esm/diagnostics.js.map +0 -1
@@ -14,7 +14,6 @@ import { SessionIdentifiers } from './identifiers';
14
14
  import { SafeLoggerProvider } from './logger';
15
15
  import { getOrInitReplayStartTime, pruneStaleReplayStartTimes, removeReplayStartTime, setReplayStartTime, } from './replay-start-time-store';
16
16
  import { evaluateTargetingAndStore } from './targeting/targeting-manager';
17
- import { SrDiagnostic } from './diagnostics';
18
17
  import { isSessionInSample } from './sampling';
19
18
  import { VERSION } from './version';
20
19
  import { createUrlTrackingPlugin, subscribeToUrlChanges } from './plugins/url-tracking-plugin';
@@ -26,10 +25,6 @@ var SessionReplay = /** @class */ (function () {
26
25
  this.recordCancelCallback = null;
27
26
  this.eventCount = 0;
28
27
  this.sessionTargetingMatch = false;
29
- // Session for which the one-per-session TRC diagnostic event was already emitted. The
30
- // diagnostics client caps in-memory events, so per-call signals go through counters and only
31
- // a single rich snapshot event is recorded per session.
32
- this.trcDiagnosticSessionId = undefined;
33
28
  // Public on purpose. `pageLeaveFns` is iterated by `pageLeaveListener`,
34
29
  // `rrwebEventManager` is dereferenced in `asyncSetSessionId` to drop the beacon buffer
35
30
  // at a session boundary, and `sessionStartTime` drives `isBelowMinSessionDuration()`.
@@ -52,9 +47,6 @@ var SessionReplay = /** @class */ (function () {
52
47
  this.recordEventsPendingShouldLogMetadata = null;
53
48
  /** Cleanup for URL change listener used to re-evaluate targeting on SPA route changes */
54
49
  this.urlChangeCleanup = null;
55
- // Ensures the url_poll.first_tick diagnostic event is emitted at most once per listener setup
56
- // (the per-tick counter still increments every tick; only the rich event is one-shot).
57
- this.urlPollFirstTickRecorded = false;
58
50
  this.crossOriginIframeCoordinator = null;
59
51
  this.crossOriginParentSignalCleanup = null;
60
52
  /** Monotonic counter to ignore stale URL-change targeting results */
@@ -123,23 +115,12 @@ var SessionReplay = /** @class */ (function () {
123
115
  if (forceRestart === void 0) { forceRestart = false; }
124
116
  if (forceTargetingReevaluation === void 0) { forceTargetingReevaluation = false; }
125
117
  return __awaiter(_this, void 0, void 0, function () {
126
- var targetingConfig, shouldReEvaluate, urlChangeEvaluationId, eventForTargeting, pageUrl, pageForTargeting, evalStart, targetingMatch, evalDurationMs, trigger;
127
- var _a, _b, _c, _d, _e, _f, _g;
128
- return __generator(this, function (_h) {
129
- switch (_h.label) {
118
+ var targetingConfig, shouldReEvaluate, urlChangeEvaluationId, eventForTargeting, pageUrl, pageForTargeting, targetingMatch;
119
+ var _a, _b, _c, _d, _e, _f;
120
+ return __generator(this, function (_g) {
121
+ switch (_g.label) {
130
122
  case 0:
131
- // What triggered this evaluation (init vs SPA URL change vs analytics event) — shows in
132
- // DataDog how often re-evaluation actually runs.
133
- this.incrementDiagnostic(SrDiagnostic.evalTrigger(isInit ? 'init' : forceTargetingReevaluation ? 'urlchange' : 'event'));
134
123
  if (!this.identifiers || !this.identifiers.sessionId || !this.config) {
135
- // Q4: eval can't run because a prerequisite is missing — record exactly which one.
136
- this.incrementDiagnostic(SrDiagnostic.evalMissingPrereq);
137
- this.recordDiagnosticEvent(SrDiagnostic.evalMissingPrereq, {
138
- hasIdentifiers: !!this.identifiers,
139
- hasSessionId: !!((_a = this.identifiers) === null || _a === void 0 ? void 0 : _a.sessionId),
140
- hasConfig: !!this.config,
141
- hasDeviceId: !!this.getDeviceId(),
142
- });
143
124
  if (this.identifiers && !this.identifiers.sessionId) {
144
125
  this.loggerProvider.log('Session ID has not been set yet, cannot evaluate targeting for Session Replay.');
145
126
  }
@@ -150,7 +131,6 @@ var SessionReplay = /** @class */ (function () {
150
131
  }
151
132
  // Handle cases where there's no targeting config
152
133
  if (!this.config.targetingConfig) {
153
- this.incrementDiagnostic(SrDiagnostic.evalNoConfig);
154
134
  if (isInit) {
155
135
  this.loggerProvider.log('Targeting config has not been set yet, cannot evaluate targeting.');
156
136
  }
@@ -170,20 +150,8 @@ var SessionReplay = /** @class */ (function () {
170
150
  Object.values(SpecialEventType).includes(eventForTargeting.event_type)) {
171
151
  eventForTargeting = undefined;
172
152
  }
173
- pageUrl = (_f = (_c = (_b = targetingParams.page) === null || _b === void 0 ? void 0 : _b.url) !== null && _c !== void 0 ? _c : (_e = (_d = getGlobalScope()) === null || _d === void 0 ? void 0 : _d.location) === null || _e === void 0 ? void 0 : _e.href) !== null && _f !== void 0 ? _f : '';
174
- pageForTargeting = (_g = targetingParams.page) !== null && _g !== void 0 ? _g : (pageUrl !== '' ? { url: pageUrl } : undefined);
175
- // Record the targeting trigger event
176
- this.recordDiagnosticEvent(SrDiagnostic.targetingTrigger, {
177
- sessionId: this.identifiers.sessionId,
178
- deviceId: this.getDeviceId(),
179
- targetingConfig: this.config.targetingConfig,
180
- targetingParams: {
181
- userProperties: targetingParams.userProperties,
182
- event: eventForTargeting,
183
- page: pageForTargeting,
184
- },
185
- });
186
- evalStart = Date.now();
153
+ pageUrl = (_e = (_b = (_a = targetingParams.page) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : (_d = (_c = getGlobalScope()) === null || _c === void 0 ? void 0 : _c.location) === null || _d === void 0 ? void 0 : _d.href) !== null && _e !== void 0 ? _e : '';
154
+ pageForTargeting = (_f = targetingParams.page) !== null && _f !== void 0 ? _f : (pageUrl !== '' ? { url: pageUrl } : undefined);
187
155
  return [4 /*yield*/, evaluateTargetingAndStore({
188
156
  sessionId: this.identifiers.sessionId,
189
157
  targetingConfig: targetingConfig,
@@ -195,76 +163,38 @@ var SessionReplay = /** @class */ (function () {
195
163
  page: pageForTargeting,
196
164
  },
197
165
  urlChange: forceTargetingReevaluation,
198
- diagnosticsClient: this.config.diagnosticsClient,
199
- deviceId: this.getDeviceId(),
200
166
  })];
201
167
  case 1:
202
- targetingMatch = _h.sent();
203
- evalDurationMs = Date.now() - evalStart;
204
- trigger = isInit ? 'init' : forceTargetingReevaluation ? 'urlchange' : 'event';
205
- // Evaluation latency — surfaces the slow-network residual gap (SR-4234) in DataDog as
206
- // sdk.diagnostics.sr.trc.eval.duration_ms.{avg,max,...}.
207
- this.recordDiagnosticHistogram(SrDiagnostic.evalDurationMs, evalDurationMs);
168
+ targetingMatch = _g.sent();
208
169
  if (forceTargetingReevaluation &&
209
170
  urlChangeEvaluationId !== undefined &&
210
171
  urlChangeEvaluationId !== this.latestUrlChangeTargetingEvaluationId) {
211
- this.incrementDiagnostic(SrDiagnostic.evalStaleDiscarded);
212
- this.recordDiagnosticEvent(SrDiagnostic.evalStaleDiscarded, {
213
- sessionId: this.identifiers.sessionId,
214
- pageUrl: pageForTargeting === null || pageForTargeting === void 0 ? void 0 : pageForTargeting.url,
215
- evaluationId: urlChangeEvaluationId,
216
- latestEvaluationId: this.latestUrlChangeTargetingEvaluationId,
217
- evalDurationMs: evalDurationMs,
218
- });
219
172
  this.loggerProvider.debug("Ignoring stale URL-change targeting result #".concat(urlChangeEvaluationId, "; latest is #").concat(this.latestUrlChangeTargetingEvaluationId, "."));
220
173
  return [2 /*return*/];
221
174
  }
222
- // Per-evaluation outcome (distinct from the per-session sr.gate.* gate counters).
223
- this.incrementDiagnostic(targetingMatch ? SrDiagnostic.evalMatch : SrDiagnostic.evalNoMatch);
224
175
  // Keep targeting match monotonic within a session: once true, always true.
225
176
  // This avoids races where an older in-flight evaluation resolves false after
226
177
  // a newer evaluation already resolved true.
227
178
  this.sessionTargetingMatch = this.sessionTargetingMatch || targetingMatch;
228
- // Q5: record ALL evaluation params (→ DataDog Logs) so a single evaluation can be fully
229
- // reconstructed by URL, identifiers, inputs, outcome, trigger and latency. userProperties
230
- // values are intentionally reduced to keys to avoid logging PII.
231
- this.recordDiagnosticEvent(SrDiagnostic.evalEvent, {
232
- // sessionId + deviceId are stamped by recordDiagnosticEvent.
233
- trigger: trigger,
234
- matched: targetingMatch,
235
- sessionTargetingMatch: this.sessionTargetingMatch,
236
- pageUrl: pageForTargeting === null || pageForTargeting === void 0 ? void 0 : pageForTargeting.url,
237
- hasDeviceId: !!this.getDeviceId(),
238
- hasEvent: !!eventForTargeting,
239
- eventType: eventForTargeting === null || eventForTargeting === void 0 ? void 0 : eventForTargeting.event_type,
240
- userPropertyKeys: targetingParams.userProperties ? Object.keys(targetingParams.userProperties) : [],
241
- evalDurationMs: evalDurationMs,
242
- });
243
179
  this.loggerProvider.debug(JSON.stringify({
244
180
  name: 'targeted replay capture config',
245
181
  sessionTargetingMatch: this.sessionTargetingMatch,
246
182
  event: eventForTargeting,
247
183
  targetingParams: targetingParams,
248
184
  }, null, 2));
249
- return [3 /*break*/, 3];
185
+ _g.label = 2;
250
186
  case 2:
251
- if (targetingConfig && this.sessionTargetingMatch) {
252
- // Already matched earlier this session — recording continues without re-evaluation.
253
- this.incrementDiagnostic(SrDiagnostic.evalSkippedAlreadyMatched);
254
- }
255
- _h.label = 3;
256
- case 3:
257
- if (!isInit) return [3 /*break*/, 4];
187
+ if (!isInit) return [3 /*break*/, 3];
258
188
  void this.initialize(true);
259
- return [3 /*break*/, 6];
260
- case 4:
261
- if (!(forceRestart || !this.recordCancelCallback)) return [3 /*break*/, 6];
189
+ return [3 /*break*/, 5];
190
+ case 3:
191
+ if (!(forceRestart || !this.recordCancelCallback)) return [3 /*break*/, 5];
262
192
  this.loggerProvider.log('Recording events for session due to forceRestart or no ongoing recording.');
263
193
  return [4 /*yield*/, this.recordEvents()];
264
- case 5:
265
- _h.sent();
266
- _h.label = 6;
267
- case 6: return [2 /*return*/];
194
+ case 4:
195
+ _g.sent();
196
+ _g.label = 5;
197
+ case 5: return [2 /*return*/];
268
198
  }
269
199
  });
270
200
  });
@@ -340,31 +270,17 @@ var SessionReplay = /** @class */ (function () {
340
270
  */
341
271
  SessionReplay.prototype.setupUrlChangeListener = function () {
342
272
  var _this = this;
343
- var _a, _b, _c, _d, _e, _f;
273
+ var _a, _b;
344
274
  // If init() runs multiple times, remove the previous URL-change subscription first
345
275
  // so we don't leak callbacks and trigger duplicate targeting evaluations.
346
276
  (_a = this.urlChangeCleanup) === null || _a === void 0 ? void 0 : _a.call(this);
347
277
  var globalScope = getGlobalScope();
348
278
  if (!(globalScope === null || globalScope === void 0 ? void 0 : globalScope.location)) {
349
- // No window/location (SSR, worker, or pre-render) — the listener can't attach, so TRC will
350
- // never re-evaluate on navigation. Surface it rather than failing silently.
351
- this.incrementDiagnostic(SrDiagnostic.urlListenerSkipped);
352
- this.recordDiagnosticEvent(SrDiagnostic.urlListenerSkipped, { reason: 'no_global_scope' });
353
- this.loggerProvider.debug('URL-change listener not attached: no global scope/location.');
354
279
  return;
355
280
  }
356
281
  var hasTargeting = !!((_b = this.config) === null || _b === void 0 ? void 0 : _b.targetingConfig);
357
282
  var onUrlChange = function (href) {
358
283
  _this.currentPageUrl = href;
359
- // Team-visible signal that an SPA navigation was detected at all (covers the "is the SDK
360
- // even seeing route changes in this framework?" question — counter + a log with the href
361
- // and whether it triggered a targeting re-eval).
362
- _this.incrementDiagnostic(SrDiagnostic.urlChange);
363
- _this.recordDiagnosticEvent(SrDiagnostic.urlChangeEvent, {
364
- href: href,
365
- hasTargeting: hasTargeting,
366
- alreadyMatched: _this.sessionTargetingMatch,
367
- });
368
284
  if (hasTargeting) {
369
285
  var evaluationId = ++_this.latestUrlChangeTargetingEvaluationId;
370
286
  void _this.evaluateTargetingAndCapture({
@@ -375,39 +291,7 @@ var SessionReplay = /** @class */ (function () {
375
291
  _this.loggerProvider.debug("Queued URL-change targeting re-evaluation #".concat(evaluationId, " for ").concat(href, "."));
376
292
  }
377
293
  };
378
- // Pass the polling options so targeting re-evaluation also respects `enableUrlChangePolling`.
379
- // Without this, the targeting listener only sees history.pushState/replaceState + popstate +
380
- // hashchange — so SPA navigations that bypass the history API never re-evaluate TRC and
381
- // recording never starts on the new URL (enableUrlChangePolling previously only affected the
382
- // rrweb URL-tracking plugin, which runs only once recording is already active).
383
- var enablePolling = (_d = (_c = this.config) === null || _c === void 0 ? void 0 : _c.enableUrlChangePolling) !== null && _d !== void 0 ? _d : false;
384
- this.urlPollFirstTickRecorded = false;
385
- var unsubscribe = subscribeToUrlChanges(globalScope, onUrlChange, {
386
- enablePolling: enablePolling,
387
- pollingInterval: (_e = this.config) === null || _e === void 0 ? void 0 : _e.urlChangePollingInterval,
388
- // Mirror each poll tick to the console (Debug level) so we can confirm polling is firing.
389
- log: this.loggerProvider.debug.bind(this.loggerProvider),
390
- // Prove in DataDog that polling actually FIRES (not just that it was scheduled). Per-tick is a
391
- // cheap aggregated counter; the rich event is emitted once (with href) to avoid flooding the
392
- // diagnostics endpoint with one capture POST per second.
393
- onPoll: function (href, changed) {
394
- _this.incrementDiagnostic(SrDiagnostic.urlPollTick);
395
- if (!_this.urlPollFirstTickRecorded) {
396
- _this.urlPollFirstTickRecorded = true;
397
- // pollingInterval is already on url_listener.attached, so it's omitted here.
398
- _this.recordDiagnosticEvent(SrDiagnostic.urlPollFirstTick, { href: href, changed: changed });
399
- }
400
- },
401
- });
402
- // Confirm the listener is actually live, and under what settings — if recording never starts on
403
- // navigation, this tells us whether the listener existed and whether polling (the fallback for
404
- // SPAs that bypass the History API) was on.
405
- this.recordDiagnosticEvent(SrDiagnostic.urlListenerAttached, {
406
- hasTargeting: hasTargeting,
407
- enablePolling: enablePolling,
408
- pollingInterval: (_f = this.config) === null || _f === void 0 ? void 0 : _f.urlChangePollingInterval,
409
- });
410
- this.loggerProvider.debug("URL-change listener attached (polling: ".concat(String(enablePolling), ")."));
294
+ var unsubscribe = subscribeToUrlChanges(globalScope, onUrlChange);
411
295
  this.urlChangeCleanup = function () {
412
296
  unsubscribe();
413
297
  _this.urlChangeCleanup = null;
@@ -436,34 +320,14 @@ var SessionReplay = /** @class */ (function () {
436
320
  var currentUrl = (_b = (_a = getGlobalScope()) === null || _a === void 0 ? void 0 : _a.location) === null || _b === void 0 ? void 0 : _b.href;
437
321
  return currentUrl != null ? { url: currentUrl } : undefined;
438
322
  };
439
- /**
440
- * Best-effort navigation type from the Navigation Timing API: 'reload' | 'navigate' |
441
- * 'back_forward' | 'prerender'. Surfaced in the init diagnostic so a page refresh ('reload')
442
- * is distinguishable from a fresh load ('navigate') — neither changes the session id, so this
443
- * is the only way to tell them apart. Returns undefined when the API is unavailable.
444
- */
445
- SessionReplay.prototype.getNavigationType = function () {
446
- try {
447
- var globalScope = getGlobalScope();
448
- var performance_1 = globalScope && globalScope.performance;
449
- if (!performance_1 || typeof performance_1.getEntriesByType !== 'function') {
450
- return undefined;
451
- }
452
- var navEntries = performance_1.getEntriesByType('navigation');
453
- return navEntries.length > 0 ? navEntries[0].type : undefined;
454
- }
455
- catch (_a) {
456
- return undefined;
457
- }
458
- };
459
323
  SessionReplay.prototype._init = function (apiKey, options) {
460
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
324
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
461
325
  return __awaiter(this, void 0, void 0, function () {
462
- var now, _u, _v, joinedConfig, localConfig, remoteConfig, scrollWatcher, managers, storeType, compressionWorkerScript, trackDestinationWorkerScript, globalScope, _w, compressionScript, trackDestinationScript, rrwebEventManager, error_1, typedError, payloadBatcher, interactionEventManager, error_2, typedError, onFullSnapshotProcessed, pending_2, pending_1, pending_1_1, _x, event_1, sessionId, messenger, needsUrlTracking;
463
- var e_2, _y;
326
+ var now, _q, _r, joinedConfig, localConfig, remoteConfig, scrollWatcher, managers, storeType, compressionWorkerScript, trackDestinationWorkerScript, globalScope, _s, compressionScript, trackDestinationScript, rrwebEventManager, error_1, typedError, payloadBatcher, interactionEventManager, error_2, typedError, onFullSnapshotProcessed, pending_2, pending_1, pending_1_1, _t, event_1, sessionId, messenger, needsUrlTracking;
327
+ var e_2, _u;
464
328
  var _this = this;
465
- return __generator(this, function (_z) {
466
- switch (_z.label) {
329
+ return __generator(this, function (_v) {
330
+ switch (_v.label) {
467
331
  case 0:
468
332
  // Re-init should always tear down any previous URL-change subscription, even when the
469
333
  // next config has no targeting config and we don't subscribe again.
@@ -479,13 +343,13 @@ var SessionReplay = /** @class */ (function () {
479
343
  options.sessionId !== undefined
480
344
  ? (_b = getOrInitReplayStartTime(apiKey, options.sessionId, now, this.loggerProvider)) !== null && _b !== void 0 ? _b : now
481
345
  : now;
482
- _u = this;
346
+ _q = this;
483
347
  return [4 /*yield*/, createSessionReplayJoinedConfigGenerator(apiKey, options)];
484
348
  case 1:
485
- _u.joinedConfigGenerator = _z.sent();
349
+ _q.joinedConfigGenerator = _v.sent();
486
350
  return [4 /*yield*/, this.joinedConfigGenerator.generateJoinedConfig()];
487
351
  case 2:
488
- _v = _z.sent(), joinedConfig = _v.joinedConfig, localConfig = _v.localConfig, remoteConfig = _v.remoteConfig;
352
+ _r = _v.sent(), joinedConfig = _r.joinedConfig, localConfig = _r.localConfig, remoteConfig = _r.remoteConfig;
489
353
  this.config = joinedConfig;
490
354
  this.setMetadata(options.sessionId, joinedConfig, localConfig, remoteConfig, (_c = options.version) === null || _c === void 0 ? void 0 : _c.version, VERSION, (_d = options.version) === null || _d === void 0 ? void 0 : _d.type);
491
355
  this.pageLeaveFns = [];
@@ -509,12 +373,12 @@ var SessionReplay = /** @class */ (function () {
509
373
  if (!(this.config.useWebWorker && globalScope && globalScope.Worker)) return [3 /*break*/, 4];
510
374
  return [4 /*yield*/, import('./worker')];
511
375
  case 3:
512
- _w = _z.sent(), compressionScript = _w.compressionScript, trackDestinationScript = _w.trackDestinationScript;
376
+ _s = _v.sent(), compressionScript = _s.compressionScript, trackDestinationScript = _s.trackDestinationScript;
513
377
  compressionWorkerScript = compressionScript;
514
378
  trackDestinationWorkerScript = trackDestinationScript;
515
- _z.label = 4;
379
+ _v.label = 4;
516
380
  case 4:
517
- _z.trys.push([4, 6, , 7]);
381
+ _v.trys.push([4, 6, , 7]);
518
382
  return [4 /*yield*/, createEventsManager({
519
383
  config: this.config,
520
384
  type: 'replay',
@@ -526,21 +390,21 @@ var SessionReplay = /** @class */ (function () {
526
390
  shouldSend: function () { return !_this.isBelowMinSessionDuration(); },
527
391
  })];
528
392
  case 5:
529
- rrwebEventManager = _z.sent();
393
+ rrwebEventManager = _v.sent();
530
394
  this.rrwebEventManager = rrwebEventManager;
531
395
  managers.push({ name: 'replay', manager: rrwebEventManager });
532
396
  return [3 /*break*/, 7];
533
397
  case 6:
534
- error_1 = _z.sent();
398
+ error_1 = _v.sent();
535
399
  typedError = error_1;
536
400
  this.loggerProvider.warn("Error occurred while creating replay events manager: ".concat(typedError.toString()));
537
401
  return [3 /*break*/, 7];
538
402
  case 7:
539
403
  if (!((_j = this.config.interactionConfig) === null || _j === void 0 ? void 0 : _j.enabled)) return [3 /*break*/, 11];
540
404
  payloadBatcher = this.config.interactionConfig.batch ? clickBatcher : clickNonBatcher;
541
- _z.label = 8;
405
+ _v.label = 8;
542
406
  case 8:
543
- _z.trys.push([8, 10, , 11]);
407
+ _v.trys.push([8, 10, , 11]);
544
408
  return [4 /*yield*/, createEventsManager({
545
409
  config: this.config,
546
410
  type: 'interaction',
@@ -552,11 +416,11 @@ var SessionReplay = /** @class */ (function () {
552
416
  trackDestinationWorkerScript: trackDestinationWorkerScript,
553
417
  })];
554
418
  case 9:
555
- interactionEventManager = _z.sent();
419
+ interactionEventManager = _v.sent();
556
420
  managers.push({ name: 'interaction', manager: interactionEventManager });
557
421
  return [3 /*break*/, 11];
558
422
  case 10:
559
- error_2 = _z.sent();
423
+ error_2 = _v.sent();
560
424
  typedError = error_2;
561
425
  this.loggerProvider.warn("Error occurred while creating interaction events manager: ".concat(typedError.toString()));
562
426
  return [3 /*break*/, 11];
@@ -574,14 +438,14 @@ var SessionReplay = /** @class */ (function () {
574
438
  pending_2 = this.pendingEmitEvents.splice(0);
575
439
  try {
576
440
  for (pending_1 = __values(pending_2), pending_1_1 = pending_1.next(); !pending_1_1.done; pending_1_1 = pending_1.next()) {
577
- _x = pending_1_1.value, event_1 = _x.event, sessionId = _x.sessionId;
441
+ _t = pending_1_1.value, event_1 = _t.event, sessionId = _t.sessionId;
578
442
  this.eventCompressor.enqueueEvent(event_1, sessionId);
579
443
  }
580
444
  }
581
445
  catch (e_2_1) { e_2 = { error: e_2_1 }; }
582
446
  finally {
583
447
  try {
584
- if (pending_1_1 && !pending_1_1.done && (_y = pending_1.return)) _y.call(pending_1);
448
+ if (pending_1_1 && !pending_1_1.done && (_u = pending_1.return)) _u.call(pending_1);
585
449
  }
586
450
  finally { if (e_2) throw e_2.error; }
587
451
  }
@@ -618,7 +482,7 @@ var SessionReplay = /** @class */ (function () {
618
482
  ], false);
619
483
  return [4 /*yield*/, this.initializeNetworkObservers()];
620
484
  case 12:
621
- _z.sent();
485
+ _v.sent();
622
486
  // Enable background capture when this page is opened by the Amplitude app
623
487
  // (window.opener exists). Uses the shared messenger singleton so that if
624
488
  // autocapture is also loaded, both share a single messenger and script load.
@@ -629,38 +493,10 @@ var SessionReplay = /** @class */ (function () {
629
493
  }
630
494
  this.loggerProvider.log('Installing @amplitude/session-replay-browser.');
631
495
  this.teardownEventListeners(false);
632
- // Q1 "did init happen?": its presence in DataDog proves init() ran to completion for this
633
- // session; the props show whether the prerequisites (session/device id, config) were present.
634
- this.incrementDiagnostic(SrDiagnostic.init);
635
- this.recordDiagnosticEvent(SrDiagnostic.init, {
636
- // sessionId is always stamped by recordDiagnosticEvent, so no separate hasSessionId here.
637
- hasDeviceId: !!this.getDeviceId(),
638
- captureEnabled: this.config.captureEnabled,
639
- hasTargetingConfig: !!this.config.targetingConfig,
640
- sampleRate: this.config.sampleRate,
641
- optOut: this.shouldOptOut(),
642
- currentUrl: (_m = this.getCurrentPageForTargeting()) === null || _m === void 0 ? void 0 : _m.url,
643
- // 'reload' tells a page refresh apart from a fresh load ('navigate') or back/forward
644
- // ('back_forward'). New tabs and refreshes keep the same session id, so this is the only
645
- // way to distinguish a refresh from a brand-new init within a session.
646
- navigationType: this.getNavigationType(),
647
- });
648
496
  return [4 /*yield*/, this.evaluateTargetingAndCapture({ userProperties: options.userProperties, page: this.getCurrentPageForTargeting() }, true)];
649
497
  case 13:
650
- _z.sent();
651
- needsUrlTracking = this.config.targetingConfig || ((_q = (_p = (_o = this.config.privacyConfig) === null || _o === void 0 ? void 0 : _o.urlMaskLevels) === null || _p === void 0 ? void 0 : _p.length) !== null && _q !== void 0 ? _q : 0) > 0;
652
- // Record whether we even attempt to wire up the URL-change listener, and the inputs behind that
653
- // decision. If `needsUrlTracking` is false the listener is never attached, so SPA navigations are
654
- // invisible to TRC — this is the first thing to check when "TRC is on but never re-evaluates".
655
- this.recordDiagnosticEvent(SrDiagnostic.urlListenerSetup, {
656
- needsUrlTracking: !!needsUrlTracking,
657
- hasTargetingConfig: !!this.config.targetingConfig,
658
- urlMaskLevels: (_t = (_s = (_r = this.config.privacyConfig) === null || _r === void 0 ? void 0 : _r.urlMaskLevels) === null || _s === void 0 ? void 0 : _s.length) !== null && _t !== void 0 ? _t : 0,
659
- // config always defaults this to a boolean (see local-config), so no `?? false` needed here.
660
- enableUrlChangePolling: this.config.enableUrlChangePolling,
661
- urlChangePollingInterval: this.config.urlChangePollingInterval,
662
- });
663
- this.loggerProvider.debug("URL-change listener needed: ".concat(String(!!needsUrlTracking), "."));
498
+ _v.sent();
499
+ needsUrlTracking = this.config.targetingConfig || ((_p = (_o = (_m = this.config.privacyConfig) === null || _m === void 0 ? void 0 : _m.urlMaskLevels) === null || _o === void 0 ? void 0 : _o.length) !== null && _p !== void 0 ? _p : 0) > 0;
664
500
  if (needsUrlTracking) {
665
501
  this.setupUrlChangeListener();
666
502
  }
@@ -700,18 +536,6 @@ var SessionReplay = /** @class */ (function () {
700
536
  this.sendEvents(previousSessionId);
701
537
  }
702
538
  isSessionChange = previousSessionId !== sessionId;
703
- // A real session transition (not the first set): recording stops/restarts and targeting is
704
- // re-evaluated here, so session churn (timeout, multi-tab custom ids, explicit setSessionId)
705
- // is a prime suspect for "sometimes records, sometimes not". recordDiagnosticEvent ships to
706
- // DataDog AND mirrors to loggerProvider.debug. New tabs / refreshes keep the same id and won't
707
- // hit this — use the init diagnostic's navigationType for those.
708
- if (isSessionChange && previousSessionId !== undefined) {
709
- this.recordDiagnosticEvent(SrDiagnostic.sessionChanged, {
710
- from: previousSessionId,
711
- to: sessionId,
712
- deviceIdChanged: deviceId !== undefined && deviceId !== currentDeviceId,
713
- });
714
- }
715
539
  // Drop any beacon-buffered events from the previous session BEFORE installing the
716
540
  // new identifiers / start time. Otherwise the page-leave beacon path could attribute
717
541
  // old-session events to the new session id, and the gate (using the new start time)
@@ -808,9 +632,6 @@ var SessionReplay = /** @class */ (function () {
808
632
  // Cross-session leak is prevented in asyncSetSessionId, which drops the buffer
809
633
  // at the session transition. The page-leave path also gates independently.
810
634
  this.suppressedSendCount++;
811
- // gap #1: recording but events held back by min_session_duration — another "recording yet
812
- // no replay in Amplitude" cause.
813
- this.incrementDiagnostic(SrDiagnostic.sendSuppressedMinDuration);
814
635
  return;
815
636
  }
816
637
  // On the first send-after-pass for the session, emit a custom rrweb event so the
@@ -867,120 +688,17 @@ var SessionReplay = /** @class */ (function () {
867
688
  }
868
689
  return identityStoreOptOut !== undefined ? identityStoreOptOut : (_b = this.config) === null || _b === void 0 ? void 0 : _b.optOut;
869
690
  };
870
- /**
871
- * Increment a diagnostics counter so the team can see the distribution of recording decisions
872
- * across a customer's sessions (e.g. lots of sr.gate.trc_no_match => rule isn't matching).
873
- * Ships via the analytics SDK's DiagnosticsClient. No-op when there's no client or diagnostics
874
- * isn't sampled in; never throws — diagnostics must never interfere with recording.
875
- */
876
- SessionReplay.prototype.incrementDiagnostic = function (counter) {
877
- var _a, _b;
878
- try {
879
- // Mirror to the console (Debug level) so the full set of diagnostics is visible in the
880
- // browser, not only in DataDog — helps debugging when a customer can't share a repro env.
881
- this.loggerProvider.debug("[SR diagnostics] ".concat(counter));
882
- (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.diagnosticsClient) === null || _b === void 0 ? void 0 : _b.increment(counter);
883
- }
884
- catch (_c) {
885
- // swallow — diagnostics is best-effort
886
- }
887
- };
888
- /**
889
- * Record a diagnostics histogram value (min/max/avg/count in DataDog). Same best-effort, never-
890
- * throws contract as incrementDiagnostic. Use for latencies/sizes, not per-call counts.
891
- */
892
- SessionReplay.prototype.recordDiagnosticHistogram = function (name, value) {
893
- var _a, _b;
894
- try {
895
- // Mirror to the console (Debug level) — see incrementDiagnostic.
896
- this.loggerProvider.debug("[SR diagnostics] ".concat(name, "=").concat(value));
897
- // The only caller runs inside evaluateTargetingAndCapture's `this.config` guard, so the
898
- // `config == null` arm of this optional chain is unreachable here (kept as defensive parity
899
- // with recordDiagnosticEvent). The diagnosticsClient-absent arm IS exercised by no-client tests.
900
- /* istanbul ignore next */
901
- (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.diagnosticsClient) === null || _b === void 0 ? void 0 : _b.recordHistogram(name, value);
902
- }
903
- catch (_c) {
904
- // swallow — diagnostics is best-effort
905
- }
906
- };
907
- /**
908
- * Record a diagnostics EVENT with properties. Events are forwarded to DataDog Logs, so the
909
- * properties become queryable fields (e.g. @matched, @pageUrl). Use sparingly vs counters: the
910
- * client caps in-memory events (~10 per save interval), so this is for context-rich signals at
911
- * meaningful decision points, not per-call tallies. Best-effort, never throws.
912
- */
913
- SessionReplay.prototype.recordDiagnosticEvent = function (name, properties) {
914
- var _a, _b, _c, _d, _e, _f;
915
- try {
916
- var sessionId = (_a = this.identifiers) === null || _a === void 0 ? void 0 : _a.sessionId;
917
- var deviceId = this.getDeviceId();
918
- // Always stamp sessionId, deviceId and srId so every diagnostics event (→ DataDog Logs) can
919
- // be correlated to a single session/device — and to the actual replay, since the Session
920
- // Replay ID is `${deviceId}/${sessionId}`. Caller props override if they pass their own.
921
- var enriched = __assign({ sessionId: sessionId, deviceId: deviceId, srId: deviceId != null && sessionId != null ? "".concat(deviceId, "/").concat(sessionId) : undefined }, properties);
922
- // Mirror to the console (Debug level) so the full event + props are visible in the browser,
923
- // not only in DataDog — see incrementDiagnostic.
924
- this.loggerProvider.debug("[SR diagnostics] ".concat(name, " ").concat(JSON.stringify(enriched)));
925
- (_c = (_b = this.config) === null || _b === void 0 ? void 0 : _b.diagnosticsClient) === null || _c === void 0 ? void 0 : _c.recordEvent(name, enriched);
926
- // Flush immediately so the event ships now rather than on the client's ~5-min timer (and so
927
- // short sessions that never reach the timer aren't lost). NOTE: this sends one capture POST
928
- // per event — higher request volume; revisit/gate before production.
929
- void ((_f = (_e = (_d = this.config) === null || _d === void 0 ? void 0 : _d.diagnosticsClient) === null || _e === void 0 ? void 0 : _e._flush) === null || _f === void 0 ? void 0 : _f.call(_e));
930
- }
931
- catch (_g) {
932
- // swallow — diagnostics is best-effort
933
- }
934
- };
935
- /**
936
- * Emit a single rich TRC decision snapshot per session to diagnostics — surfaced even when
937
- * nothing records (the exact case customers can't reproduce locally).
938
- */
939
- SessionReplay.prototype.recordTrcDecisionDiagnostic = function (shouldRecord) {
940
- var _a, _b;
941
- var config = this.config;
942
- // Every caller is past getShouldRecord's `!this.identifiers`/`!this.config` guard, so both are
943
- // defined here; the `?.` arms below are unreachable defensive narrowing and excluded from
944
- // coverage. The reachable guards (no diagnosticsClient, undefined/duplicate sessionId) are tested.
945
- /* istanbul ignore next */
946
- if (!config) {
947
- return;
948
- }
949
- /* istanbul ignore next */
950
- var sessionId = (_a = this.identifiers) === null || _a === void 0 ? void 0 : _a.sessionId;
951
- // Once past this guard, config.diagnosticsClient is truthy, so the fields below read config
952
- // directly rather than re-asserting with `?.` on every access.
953
- if (!config.diagnosticsClient || sessionId === undefined || sessionId === this.trcDiagnosticSessionId) {
954
- return;
955
- }
956
- this.trcDiagnosticSessionId = sessionId;
957
- // Goes through recordDiagnosticEvent so it carries sessionId + deviceId like every other event.
958
- this.recordDiagnosticEvent(SrDiagnostic.decision, {
959
- shouldRecord: shouldRecord,
960
- captureEnabled: config.captureEnabled,
961
- hasTargetingConfig: !!config.targetingConfig,
962
- sessionTargetingMatch: this.sessionTargetingMatch,
963
- sampleRate: config.sampleRate,
964
- pageUrl: (_b = this.getCurrentPageForTargeting()) === null || _b === void 0 ? void 0 : _b.url,
965
- sdkVersion: VERSION,
966
- });
967
- };
968
691
  SessionReplay.prototype.getShouldRecord = function () {
969
692
  if (!this.identifiers || !this.config || !this.identifiers.sessionId) {
970
693
  this.loggerProvider.warn("Session is not being recorded due to lack of config, please call sessionReplay.init.");
971
- this.incrementDiagnostic(SrDiagnostic.gateNoIdentifiers);
972
694
  return false;
973
695
  }
974
696
  if (!this.config.captureEnabled) {
975
697
  this.loggerProvider.log("Session ".concat(this.identifiers.sessionId, " not being captured due to capture being disabled for project or because the remote config could not be fetched."));
976
- this.incrementDiagnostic(SrDiagnostic.gateCaptureDisabled);
977
- this.recordTrcDecisionDiagnostic(false);
978
698
  return false;
979
699
  }
980
700
  if (this.shouldOptOut()) {
981
701
  this.loggerProvider.log("Opting session ".concat(this.identifiers.sessionId, " out of recording due to optOut config."));
982
- this.incrementDiagnostic(SrDiagnostic.gateOptOut);
983
- this.recordTrcDecisionDiagnostic(false);
984
702
  return false;
985
703
  }
986
704
  var shouldRecord = false;
@@ -994,14 +712,12 @@ var SessionReplay = /** @class */ (function () {
994
712
  this.loggerProvider.log(message);
995
713
  shouldRecord = false;
996
714
  matched = false;
997
- this.incrementDiagnostic(SrDiagnostic.gateTrcNoMatch);
998
715
  }
999
716
  else {
1000
717
  message = "Capturing replays for session ".concat(this.identifiers.sessionId, " due to matching targeting conditions.");
1001
718
  this.loggerProvider.log(message);
1002
719
  shouldRecord = true;
1003
720
  matched = true;
1004
- this.incrementDiagnostic(SrDiagnostic.gateTrcMatch);
1005
721
  }
1006
722
  }
1007
723
  else {
@@ -1011,12 +727,10 @@ var SessionReplay = /** @class */ (function () {
1011
727
  this.loggerProvider.log(message);
1012
728
  shouldRecord = false;
1013
729
  matched = false;
1014
- this.incrementDiagnostic(SrDiagnostic.gateSampleOut);
1015
730
  }
1016
731
  else {
1017
732
  shouldRecord = true;
1018
733
  matched = true;
1019
- this.incrementDiagnostic(SrDiagnostic.gateSampleIn);
1020
734
  }
1021
735
  }
1022
736
  // Only send custom rrweb event for targeting decision when the decision changes
@@ -1029,7 +743,6 @@ var SessionReplay = /** @class */ (function () {
1029
743
  });
1030
744
  this.lastShouldRecordDecision = shouldRecord;
1031
745
  }
1032
- this.recordTrcDecisionDiagnostic(shouldRecord);
1033
746
  return shouldRecord;
1034
747
  };
1035
748
  SessionReplay.prototype.getBlockSelectors = function () {
@@ -1194,9 +907,6 @@ var SessionReplay = /** @class */ (function () {
1194
907
  recordFunction = _o.sent();
1195
908
  // May be undefined if cannot import rrweb-record
1196
909
  if (!recordFunction) {
1197
- // gap #1: gate said record, but rrweb couldn't load → no replay despite shouldRecord=true.
1198
- this.incrementDiagnostic(SrDiagnostic.recordNoRecordFn);
1199
- this.recordDiagnosticEvent(SrDiagnostic.recordNoRecordFn, {});
1200
910
  return [2 /*return*/];
1201
911
  }
1202
912
  return [4 /*yield*/, this.initializeNetworkObservers()];
@@ -1227,11 +937,6 @@ var SessionReplay = /** @class */ (function () {
1227
937
  : {};
1228
938
  ugcFilterRules = (interactionConfig === null || interactionConfig === void 0 ? void 0 : interactionConfig.enabled) && interactionConfig.ugcFilterRules ? interactionConfig.ugcFilterRules : [];
1229
939
  this.loggerProvider.log("Session Replay capture beginning for ".concat(sessionId, "."));
1230
- // gap #1: rrweb is actually starting. Closes the "gate said yes but no replay" blind spot,
1231
- // and its srId is the id the replay uploads under (compare with analytics events to catch the
1232
- // device-id mismatch that breaks stitching).
1233
- this.incrementDiagnostic(SrDiagnostic.recordStarted);
1234
- this.recordDiagnosticEvent(SrDiagnostic.recordStarted, {});
1235
940
  _o.label = 3;
1236
941
  case 3:
1237
942
  _o.trys.push([3, 5, , 6]);