@sentry/replay 7.61.1 → 7.62.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.
package/esm/index.js CHANGED
@@ -4025,21 +4025,45 @@ function logInfo(message, shouldAddBreadcrumb) {
4025
4025
  logger.info(message);
4026
4026
 
4027
4027
  if (shouldAddBreadcrumb) {
4028
- const hub = getCurrentHub();
4029
- hub.addBreadcrumb(
4030
- {
4031
- category: 'console',
4032
- data: {
4033
- logger: 'replay',
4034
- },
4035
- level: 'info',
4036
- message,
4037
- },
4038
- { level: 'info' },
4039
- );
4028
+ addBreadcrumb(message);
4040
4029
  }
4041
4030
  }
4042
4031
 
4032
+ /**
4033
+ * Log a message, and add a breadcrumb in the next tick.
4034
+ * This is necessary when the breadcrumb may be added before the replay is initialized.
4035
+ */
4036
+ function logInfoNextTick(message, shouldAddBreadcrumb) {
4037
+ if (!(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
4038
+ return;
4039
+ }
4040
+
4041
+ logger.info(message);
4042
+
4043
+ if (shouldAddBreadcrumb) {
4044
+ // Wait a tick here to avoid race conditions for some initial logs
4045
+ // which may be added before replay is initialized
4046
+ setTimeout(() => {
4047
+ addBreadcrumb(message);
4048
+ }, 0);
4049
+ }
4050
+ }
4051
+
4052
+ function addBreadcrumb(message) {
4053
+ const hub = getCurrentHub();
4054
+ hub.addBreadcrumb(
4055
+ {
4056
+ category: 'console',
4057
+ data: {
4058
+ logger: 'replay',
4059
+ },
4060
+ level: 'info',
4061
+ message,
4062
+ },
4063
+ { level: 'info' },
4064
+ );
4065
+ }
4066
+
4043
4067
  /** This error indicates that the event buffer size exceeded the limit.. */
4044
4068
  class EventBufferSizeExceededError extends Error {
4045
4069
  constructor() {
@@ -4054,9 +4078,12 @@ class EventBufferSizeExceededError extends Error {
4054
4078
  class EventBufferArray {
4055
4079
  /** All the events that are buffered to be sent. */
4056
4080
 
4081
+ /** @inheritdoc */
4082
+
4057
4083
  constructor() {
4058
4084
  this.events = [];
4059
4085
  this._totalSize = 0;
4086
+ this.hasCheckout = false;
4060
4087
  }
4061
4088
 
4062
4089
  /** @inheritdoc */
@@ -4101,6 +4128,7 @@ class EventBufferArray {
4101
4128
  clear() {
4102
4129
  this.events = [];
4103
4130
  this._totalSize = 0;
4131
+ this.hasCheckout = false;
4104
4132
  }
4105
4133
 
4106
4134
  /** @inheritdoc */
@@ -4220,11 +4248,13 @@ class WorkerHandler {
4220
4248
  * Exported only for testing.
4221
4249
  */
4222
4250
  class EventBufferCompressionWorker {
4251
+ /** @inheritdoc */
4223
4252
 
4224
4253
  constructor(worker) {
4225
4254
  this._worker = new WorkerHandler(worker);
4226
4255
  this._earliestTimestamp = null;
4227
4256
  this._totalSize = 0;
4257
+ this.hasCheckout = false;
4228
4258
  }
4229
4259
 
4230
4260
  /** @inheritdoc */
@@ -4284,6 +4314,8 @@ class EventBufferCompressionWorker {
4284
4314
  clear() {
4285
4315
  this._earliestTimestamp = null;
4286
4316
  this._totalSize = 0;
4317
+ this.hasCheckout = false;
4318
+
4287
4319
  // We do not wait on this, as we assume the order of messages is consistent for the worker
4288
4320
  void this._worker.postMessage('clear');
4289
4321
  }
@@ -4338,6 +4370,15 @@ class EventBufferProxy {
4338
4370
  return this._used.hasEvents;
4339
4371
  }
4340
4372
 
4373
+ /** @inheritdoc */
4374
+ get hasCheckout() {
4375
+ return this._used.hasCheckout;
4376
+ }
4377
+ /** @inheritdoc */
4378
+ set hasCheckout(value) {
4379
+ this._used.hasCheckout = value;
4380
+ }
4381
+
4341
4382
  /** @inheritDoc */
4342
4383
  destroy() {
4343
4384
  this._fallback.destroy();
@@ -4599,7 +4640,7 @@ function fetchSession(traceInternals) {
4599
4640
 
4600
4641
  const sessionObj = JSON.parse(sessionStringFromStorage) ;
4601
4642
 
4602
- logInfo('[Replay] Loading existing session', traceInternals);
4643
+ logInfoNextTick('[Replay] Loading existing session', traceInternals);
4603
4644
 
4604
4645
  return makeSession(sessionObj);
4605
4646
  } catch (e) {
@@ -4635,10 +4676,10 @@ function getSession({
4635
4676
  // and when this session is expired, it will not be renewed until user
4636
4677
  // reloads.
4637
4678
  const discardedSession = makeSession({ sampled: false });
4638
- logInfo('[Replay] Session should not be refreshed', traceInternals);
4679
+ logInfoNextTick('[Replay] Session should not be refreshed', traceInternals);
4639
4680
  return { type: 'new', session: discardedSession };
4640
4681
  } else {
4641
- logInfo('[Replay] Session has expired', traceInternals);
4682
+ logInfoNextTick('[Replay] Session has expired', traceInternals);
4642
4683
  }
4643
4684
  // Otherwise continue to create a new session
4644
4685
  }
@@ -4648,7 +4689,7 @@ function getSession({
4648
4689
  sessionSampleRate,
4649
4690
  allowBuffering,
4650
4691
  });
4651
- logInfo('[Replay] Created new session', traceInternals);
4692
+ logInfoNextTick('[Replay] Created new session', traceInternals);
4652
4693
 
4653
4694
  return { type: 'new', session: newSession };
4654
4695
  }
@@ -4687,8 +4728,9 @@ async function addEvent(
4687
4728
  }
4688
4729
 
4689
4730
  try {
4690
- if (isCheckout) {
4731
+ if (isCheckout && replay.recordingMode === 'buffer') {
4691
4732
  replay.eventBuffer.clear();
4733
+ replay.eventBuffer.hasCheckout = true;
4692
4734
  }
4693
4735
 
4694
4736
  const replayOptions = replay.getOptions();
@@ -7264,7 +7306,10 @@ class ReplayContainer {
7264
7306
  this.recordingMode = 'buffer';
7265
7307
  }
7266
7308
 
7267
- logInfo(`[Replay] Starting replay in ${this.recordingMode} mode`, this._options._experiments.traceInternals);
7309
+ logInfoNextTick(
7310
+ `[Replay] Starting replay in ${this.recordingMode} mode`,
7311
+ this._options._experiments.traceInternals,
7312
+ );
7268
7313
 
7269
7314
  this._initializeRecording();
7270
7315
  }
@@ -7285,7 +7330,7 @@ class ReplayContainer {
7285
7330
  throw new Error('Replay buffering is in progress, call `flush()` to save the replay');
7286
7331
  }
7287
7332
 
7288
- logInfo('[Replay] Starting replay in session mode', this._options._experiments.traceInternals);
7333
+ logInfoNextTick('[Replay] Starting replay in session mode', this._options._experiments.traceInternals);
7289
7334
 
7290
7335
  const previousSessionId = this.session && this.session.id;
7291
7336
 
@@ -7314,7 +7359,7 @@ class ReplayContainer {
7314
7359
  throw new Error('Replay recording is already in progress');
7315
7360
  }
7316
7361
 
7317
- logInfo('[Replay] Starting replay in buffer mode', this._options._experiments.traceInternals);
7362
+ logInfoNextTick('[Replay] Starting replay in buffer mode', this._options._experiments.traceInternals);
7318
7363
 
7319
7364
  const previousSessionId = this.session && this.session.id;
7320
7365
 
@@ -8139,6 +8184,9 @@ class ReplayContainer {
8139
8184
  const now = Date.now();
8140
8185
  const duration = now - start;
8141
8186
 
8187
+ // A flush is about to happen, cancel any queued flushes
8188
+ this._debouncedFlush.cancel();
8189
+
8142
8190
  // If session is too short, or too long (allow some wiggle room over maxSessionLife), do not send it
8143
8191
  // This _should_ not happen, but it may happen if flush is triggered due to a page activity change or similar
8144
8192
  const tooShort = duration < this._options.minReplayDuration;
@@ -8148,6 +8196,7 @@ class ReplayContainer {
8148
8196
  `[Replay] Session duration (${Math.floor(duration / 1000)}s) is too ${
8149
8197
  tooShort ? 'short' : 'long'
8150
8198
  }, not sending replay.`,
8199
+ this._options._experiments.traceInternals,
8151
8200
  );
8152
8201
 
8153
8202
  if (tooShort) {
@@ -8156,8 +8205,11 @@ class ReplayContainer {
8156
8205
  return;
8157
8206
  }
8158
8207
 
8159
- // A flush is about to happen, cancel any queued flushes
8160
- this._debouncedFlush.cancel();
8208
+ const eventBuffer = this.eventBuffer;
8209
+ if (eventBuffer && this.session.segmentId === 0 && !eventBuffer.hasCheckout) {
8210
+ logInfo('[Replay] Flushing initial segment without checkout.', this._options._experiments.traceInternals);
8211
+ // TODO FN: Evaluate if we want to stop here, or remove this again?
8212
+ }
8161
8213
 
8162
8214
  // this._flushLock acts as a lock so that future calls to `_flush()`
8163
8215
  // will be blocked until this promise resolves