@faststats/web 0.10.1 → 0.10.2

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,21 +1,18 @@
1
1
  import { c as removeStorageItem, l as setStorageItem, n as createId, s as getStorageItem } from "./send-data-Dplz7m4c.js";
2
2
  //#region src/utils/identifiers.ts
3
3
  const ANONYMOUS_ID_KEY = "faststats_anon_id_";
4
- function getOrCreateAnonymousId(siteKey) {
4
+ function getAnonymousId(siteKey, cookieless = false) {
5
+ if (cookieless) return "";
5
6
  const key = `${ANONYMOUS_ID_KEY}${siteKey}`;
6
7
  const existingId = getStorageItem("localStorage", key);
7
8
  if (existingId) return existingId;
8
9
  const newId = createId();
9
10
  return setStorageItem("localStorage", key, newId) ? newId : "";
10
11
  }
11
- function getAnonymousId(siteKey, cookieless = false) {
12
- if (cookieless) return "";
13
- return getOrCreateAnonymousId(siteKey);
14
- }
15
12
  function resetAnonymousId(siteKey, cookieless) {
16
13
  if (cookieless) return "";
17
14
  if (!removeStorageItem("localStorage", `${ANONYMOUS_ID_KEY}${siteKey}`)) return "";
18
- return getOrCreateAnonymousId(siteKey);
15
+ return getAnonymousId(siteKey);
19
16
  }
20
17
  //#endregion
21
18
  export { resetAnonymousId as n, getAnonymousId as t };
package/dist/error.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { i as resolveBaseUrl, n as URLS, r as getPageContext, t as ANALYTICS_BASE } from "./chunks/api-urls-DWk43fu6.js";
2
2
  import { r as getSessionContext, t as sendData } from "./chunks/send-data-Dplz7m4c.js";
3
- import { t as getAnonymousId } from "./chunks/identifiers-xX7o7oZz.js";
3
+ import { t as getAnonymousId } from "./chunks/identifiers-I5UnTXGR.js";
4
4
  //#region src/error.ts
5
5
  const SDK_NAME = "@faststats/web";
6
- const SDK_VERSION = "0.10.1";
6
+ const SDK_VERSION = "0.10.2";
7
7
  function errorTracking(options = {}) {
8
8
  return {
9
9
  name: "error-tracking",
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { i as resolveBaseUrl, n as URLS, r as getPageContext, t as ANALYTICS_BASE } from "./chunks/api-urls-DWk43fu6.js";
2
2
  import { a as resetSession, n as createId, o as touchActivity, r as getSessionContext, t as sendData } from "./chunks/send-data-Dplz7m4c.js";
3
- import { n as resetAnonymousId, t as getAnonymousId } from "./chunks/identifiers-xX7o7oZz.js";
3
+ import { n as resetAnonymousId, t as getAnonymousId } from "./chunks/identifiers-I5UnTXGR.js";
4
4
  //#region src/extensions.ts
5
5
  var ExtensionHost = class {
6
6
  runtime;
package/dist/replay.d.ts CHANGED
@@ -31,6 +31,7 @@ export interface ReplayTrackerOptions {
31
31
  maxLowLatencyBatchSizeBytes?: number;
32
32
  maxPendingBatches?: number;
33
33
  maxQueueSizeBytes?: number;
34
+ /** Minimum elapsed time per recording stream before upload. Defaults to 3000. */
34
35
  minReplayLengthMs?: number;
35
36
  sampling?: RecordOptions["sampling"];
36
37
  slimDOMOptions?: RecordOptions["slimDOMOptions"];
@@ -67,7 +68,6 @@ export default class ReplayTracker {
67
68
  private readonly minReplayLengthMs;
68
69
  private readonly events;
69
70
  private readonly pending;
70
- private readonly minLengthBlockedBatches;
71
71
  private queuedEventsSizeBytes;
72
72
  private pendingSizeBytes;
73
73
  private viewId;
@@ -76,7 +76,6 @@ export default class ReplayTracker {
76
76
  private started;
77
77
  private disposed;
78
78
  private startTime;
79
- private sequence;
80
79
  private intervalId;
81
80
  private flushTask;
82
81
  private retryTask;
@@ -97,10 +96,7 @@ export default class ReplayTracker {
97
96
  private log;
98
97
  private clearFlushTimers;
99
98
  private clearQueues;
100
- private dropMinLengthBlockedBatches;
101
- private unblockSessionBatches;
102
99
  private finalizeSession;
103
- private nextBatchSequence;
104
100
  setCookielessMode(cookieless: boolean): void;
105
101
  start(): void;
106
102
  trackPageChange(url?: string): void;
@@ -126,6 +122,7 @@ export default class ReplayTracker {
126
122
  private eventSizeBytes;
127
123
  private batchSizeBytes;
128
124
  private removePending;
125
+ private stopCapture;
129
126
  private enqueueBatch;
130
127
  private flush;
131
128
  private sendPending;
package/dist/replay.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { a as sanitizeUrl, i as resolveBaseUrl, n as URLS, t as ANALYTICS_BASE } from "./chunks/api-urls-DWk43fu6.js";
2
- import { i as onSessionRotated, l as setStorageItem, n as createId, o as touchActivity, r as getSessionContext, s as getStorageItem, t as sendData } from "./chunks/send-data-Dplz7m4c.js";
3
- import { t as getAnonymousId } from "./chunks/identifiers-xX7o7oZz.js";
2
+ import { c as removeStorageItem, i as onSessionRotated, l as setStorageItem, n as createId, o as touchActivity, r as getSessionContext, s as getStorageItem, t as sendData } from "./chunks/send-data-Dplz7m4c.js";
3
+ import { t as getAnonymousId } from "./chunks/identifiers-I5UnTXGR.js";
4
4
  import { record } from "@rrweb/record";
5
5
  import { getRecordConsolePlugin } from "@rrweb/rrweb-plugin-console-record";
6
6
  import { getRecordNetworkPlugin } from "@rrweb/rrweb-plugin-network-record";
@@ -52,6 +52,51 @@ var ReplayMutationThrottler = class {
52
52
  }
53
53
  };
54
54
  //#endregion
55
+ //#region src/replay-sequence.ts
56
+ const counters = /* @__PURE__ */ new Map();
57
+ function sameRecording(counter, context) {
58
+ return counter?.sessionId === context.sessionId && counter.windowId === context.windowId;
59
+ }
60
+ function readCounter(value) {
61
+ try {
62
+ const parsed = JSON.parse(value);
63
+ if (parsed && typeof parsed.sessionId === "string" && typeof parsed.windowId === "string" && typeof parsed.next === "number" && Number.isSafeInteger(parsed.next) && parsed.next >= 0 && (parsed.version === 0 || parsed.version === 1)) return parsed;
64
+ } catch {}
65
+ }
66
+ function nextReplaySequence(siteKey, context, cookieless) {
67
+ const key = `faststats_replay_sequence_v1_${siteKey}`;
68
+ const cached = counters.get(siteKey);
69
+ const raw = cookieless ? null : getStorageItem("sessionStorage", key);
70
+ const stored = raw === null ? void 0 : readCounter(raw);
71
+ if (raw !== null && !stored && !sameRecording(cached, context)) return;
72
+ let counter = sameRecording(cached, context) ? cached : void 0;
73
+ if (sameRecording(stored, context) && stored && (!counter || stored.next > counter.next)) counter = stored;
74
+ const legacyKey = `faststats_replay_batch_sequence_${siteKey}_${context.windowId}`;
75
+ if (!counter) {
76
+ const legacy = !cookieless && !stored && !sameRecording(cached, context) ? getStorageItem("sessionStorage", legacyKey) : null;
77
+ const next = legacy === null ? 0 : Number(legacy);
78
+ if (!Number.isSafeInteger(next) || next < 0 || legacy !== null && !/^\d+$/.test(legacy)) return;
79
+ counter = {
80
+ sessionId: context.sessionId,
81
+ windowId: context.windowId,
82
+ next,
83
+ version: legacy === null ? 1 : 0
84
+ };
85
+ }
86
+ if (!Number.isSafeInteger(counter.next + 1)) return;
87
+ const sequence = counter.next;
88
+ const updated = {
89
+ ...counter,
90
+ next: sequence + 1
91
+ };
92
+ counters.set(siteKey, updated);
93
+ if (!cookieless && setStorageItem("sessionStorage", key, JSON.stringify(updated))) removeStorageItem("sessionStorage", legacyKey);
94
+ return {
95
+ sequence,
96
+ ...counter.version === 1 ? { sequenceContractVersion: 1 } : {}
97
+ };
98
+ }
99
+ //#endregion
55
100
  //#region src/replay.ts
56
101
  const MAX_TIMEOUT_MS = 2147483647;
57
102
  const DEFAULT_MAX_QUEUE_SIZE_BYTES = 2097152;
@@ -66,6 +111,10 @@ const RRWEB_EVENT_META = 4;
66
111
  const REPLAY_SEQUENTIAL_ID_KEY = "_faststatsSeqId";
67
112
  const textEncoder = new TextEncoder();
68
113
  const batchSizeCache = /* @__PURE__ */ new WeakMap();
114
+ function boundedInteger(value, fallback, min, max) {
115
+ if (value === void 0 || !Number.isFinite(value) || value < min) return fallback;
116
+ return Math.min(Math.trunc(value), max);
117
+ }
69
118
  function sessionReplay(options = {}) {
70
119
  return {
71
120
  name: "session-replay",
@@ -100,7 +149,6 @@ var ReplayTracker = class {
100
149
  minReplayLengthMs;
101
150
  events = [];
102
151
  pending = [];
103
- minLengthBlockedBatches = /* @__PURE__ */ new WeakSet();
104
152
  queuedEventsSizeBytes = 0;
105
153
  pendingSizeBytes = 0;
106
154
  viewId = createId();
@@ -109,7 +157,6 @@ var ReplayTracker = class {
109
157
  started = false;
110
158
  disposed = false;
111
159
  startTime = 0;
112
- sequence = 0;
113
160
  intervalId = null;
114
161
  flushTask = null;
115
162
  retryTask = null;
@@ -130,13 +177,13 @@ var ReplayTracker = class {
130
177
  this.options = options;
131
178
  this.lastCookielessMode = options.cookieless ?? false;
132
179
  this.endpoint = `${resolveBaseUrl(options.baseUrl, ANALYTICS_BASE)}${URLS.replay}`;
133
- this.flushInterval = options.flushInterval ?? 15e3;
134
- this.maxEvents = options.maxEvents ?? 1e3;
135
- this.maxBatchSizeBytes = options.maxBatchSizeBytes ?? DEFAULT_MAX_BATCH_SIZE_BYTES;
136
- this.maxLowLatencyBatchSizeBytes = options.maxLowLatencyBatchSizeBytes ?? DEFAULT_MAX_LOW_LATENCY_BATCH_SIZE_BYTES;
137
- this.maxPendingBatches = options.maxPendingBatches ?? 30;
138
- this.maxQueueSizeBytes = options.maxQueueSizeBytes ?? DEFAULT_MAX_QUEUE_SIZE_BYTES;
139
- this.minReplayLengthMs = options.minReplayLengthMs ?? 3e3;
180
+ this.flushInterval = boundedInteger(options.flushInterval, 15e3, 1, MAX_TIMEOUT_MS);
181
+ this.maxEvents = boundedInteger(options.maxEvents, 1e3, 1, 1e5);
182
+ this.maxBatchSizeBytes = boundedInteger(options.maxBatchSizeBytes, DEFAULT_MAX_BATCH_SIZE_BYTES, 1, 33554432);
183
+ this.maxLowLatencyBatchSizeBytes = boundedInteger(options.maxLowLatencyBatchSizeBytes, DEFAULT_MAX_LOW_LATENCY_BATCH_SIZE_BYTES, 1, DEFAULT_MAX_LOW_LATENCY_BATCH_SIZE_BYTES);
184
+ this.maxPendingBatches = boundedInteger(options.maxPendingBatches, 30, 1, 1e3);
185
+ this.maxQueueSizeBytes = boundedInteger(options.maxQueueSizeBytes, DEFAULT_MAX_QUEUE_SIZE_BYTES, 1, 33554432);
186
+ this.minReplayLengthMs = boundedInteger(options.minReplayLengthMs, 3e3, 0, MAX_TIMEOUT_MS);
140
187
  this.mutationThrottler = options.mutationThrottle?.enabled === false ? null : new ReplayMutationThrottler(options.mutationThrottle);
141
188
  }
142
189
  log(...args) {
@@ -158,28 +205,10 @@ var ReplayTracker = class {
158
205
  this.pending.length = 0;
159
206
  this.pendingSizeBytes = 0;
160
207
  }
161
- dropMinLengthBlockedBatches() {
162
- this.needsFinalization = false;
163
- for (let index = this.pending.length - 1; index >= 0; index--) {
164
- const batch = this.pending[index];
165
- if (batch && this.minLengthBlockedBatches.has(batch)) this.removePending(batch);
166
- }
167
- }
168
- unblockSessionBatches(sessionId) {
169
- for (const batch of this.pending) if (batch.sessionId === sessionId) this.minLengthBlockedBatches.delete(batch);
170
- }
171
208
  finalizeSession(context, flushReason) {
172
209
  if (!this.needsFinalization) return;
173
- this.enqueueBatch(this.createBatch([], context, true, flushReason));
174
- }
175
- nextBatchSequence(context) {
176
- const key = `faststats_replay_batch_sequence_${this.options.siteKey}_${context.windowId}`;
177
- let sequence = this.sequence;
178
- const parsed = Number.parseInt(getStorageItem("sessionStorage", key) ?? "", 10);
179
- if (Number.isFinite(parsed) && parsed >= 0) sequence = parsed;
180
- setStorageItem("sessionStorage", key, String(sequence + 1));
181
- this.sequence = sequence + 1;
182
- return sequence;
210
+ const batch = this.createBatch([], context, true, flushReason);
211
+ if (batch) this.enqueueBatch(batch);
183
212
  }
184
213
  setCookielessMode(cookieless) {
185
214
  if (this.lastCookielessMode === cookieless) return;
@@ -189,7 +218,7 @@ var ReplayTracker = class {
189
218
  this.clearFlushTimers();
190
219
  const context = getSessionContext(this.options.siteKey, this.lastCookielessMode);
191
220
  this.activeSessionId = context.sessionId;
192
- this.startTime = context.sessionStart;
221
+ this.startTime = Date.now();
193
222
  this.chunkStartedAt = Date.now();
194
223
  this.beginReplayStream();
195
224
  }
@@ -204,7 +233,7 @@ var ReplayTracker = class {
204
233
  this.viewUrl = sanitizeUrl(window.location.href, this.options.trackHash ?? false);
205
234
  const context = getSessionContext(this.options.siteKey, this.lastCookielessMode);
206
235
  this.activeSessionId = context.sessionId;
207
- this.startTime = context.sessionStart;
236
+ this.startTime = Date.now();
208
237
  this.chunkStartedAt = Date.now();
209
238
  this.subscribeToSessionRotation();
210
239
  this.beginRecording();
@@ -227,7 +256,7 @@ var ReplayTracker = class {
227
256
  viewId: this.viewId
228
257
  }
229
258
  }
230
- }, false);
259
+ });
231
260
  }
232
261
  onPageHidden(persisted = false, terminal = false) {
233
262
  if (persisted) return;
@@ -276,7 +305,7 @@ var ReplayTracker = class {
276
305
  return plugins;
277
306
  }
278
307
  beginRecording() {
279
- const stop = record({
308
+ this.stopRecording = record({
280
309
  emit: this.onEvent,
281
310
  sampling: this.options.sampling ?? {
282
311
  mousemove: 50,
@@ -310,7 +339,6 @@ var ReplayTracker = class {
310
339
  checkoutEveryNth: this.options.checkoutEveryNth,
311
340
  plugins: this.recordingPlugins()
312
341
  });
313
- this.stopRecording = stop;
314
342
  }
315
343
  stop(discard = false) {
316
344
  if (!this.started) return;
@@ -332,8 +360,8 @@ var ReplayTracker = class {
332
360
  if (!this.hasReachedMinLength()) {
333
361
  this.events.length = 0;
334
362
  this.queuedEventsSizeBytes = 0;
335
- this.dropMinLengthBlockedBatches();
336
- this.log(`Session too short (${Date.now() - this.startTime}ms), discarding events`);
363
+ this.needsFinalization = false;
364
+ this.log(`Recording too short (${Date.now() - this.startTime}ms), discarding events`);
337
365
  }
338
366
  this.flush(true, true, "stop");
339
367
  this.log("Recording stopped");
@@ -349,12 +377,15 @@ var ReplayTracker = class {
349
377
  }
350
378
  applySessionRotation(prev, next) {
351
379
  if (this.activeSessionId === next.sessionId) return;
352
- this.enqueueEventsIfReady(prev, {
380
+ if (this.hasReachedMinLength()) this.enqueueEventsIfReady(prev, {
353
381
  isFinal: true,
354
382
  flushReason: "sessionRotate"
355
383
  });
384
+ else {
385
+ this.events.length = 0;
386
+ this.queuedEventsSizeBytes = 0;
387
+ }
356
388
  this.finalizeSession(prev, "sessionRotate");
357
- this.unblockSessionBatches(prev.sessionId);
358
389
  this.needsFinalization = false;
359
390
  this.activeSessionId = next.sessionId;
360
391
  this.resetSessionTiming(next);
@@ -380,14 +411,14 @@ var ReplayTracker = class {
380
411
  }
381
412
  }
382
413
  }
383
- resetSessionTiming(next) {
414
+ resetSessionTiming(_next) {
384
415
  if (this.minLengthFlushTask) clearTimeout(this.minLengthFlushTask);
385
416
  this.minLengthFlushTask = null;
386
- this.startTime = next.sessionStart;
417
+ this.startTime = Date.now();
387
418
  this.chunkStartedAt = Date.now();
388
419
  this.initialFlushPending = true;
389
420
  }
390
- onEvent = (event, _isCheckout) => {
421
+ onEvent = (event) => {
391
422
  if (this.overflowed) return;
392
423
  let capturedEvent = event;
393
424
  if (event.type === RRWEB_EVENT_META) {
@@ -406,9 +437,17 @@ var ReplayTracker = class {
406
437
  if (this.mutationThrottler && !throttled) return;
407
438
  if (throttled) capturedEvent = throttled;
408
439
  }
409
- capturedEvent = Object.assign(capturedEvent, { [REPLAY_SEQUENTIAL_ID_KEY]: ++this.replayEventSequence });
410
- this.events.push(capturedEvent);
411
- this.queuedEventsSizeBytes += this.eventSizeBytes(capturedEvent);
440
+ const sequencedEvent = {
441
+ ...capturedEvent,
442
+ [REPLAY_SEQUENTIAL_ID_KEY]: ++this.replayEventSequence
443
+ };
444
+ const eventBytes = this.eventSizeBytes(sequencedEvent);
445
+ if (this.pendingSizeBytes + this.queuedEventsSizeBytes + eventBytes > this.maxQueueSizeBytes) {
446
+ this.stopCapture("Replay buffer limit reached");
447
+ return;
448
+ }
449
+ this.events.push(sequencedEvent);
450
+ this.queuedEventsSizeBytes += eventBytes;
412
451
  let reason;
413
452
  if (this.events.length >= this.maxEvents) reason = "maxEvents";
414
453
  else if (this.queuedEventsSizeBytes >= this.maxBatchSizeBytes) reason = "maxBytes";
@@ -422,7 +461,7 @@ var ReplayTracker = class {
422
461
  if (!this.hasReachedMinLength()) {
423
462
  this.events.length = 0;
424
463
  this.queuedEventsSizeBytes = 0;
425
- this.dropMinLengthBlockedBatches();
464
+ this.needsFinalization = false;
426
465
  return;
427
466
  }
428
467
  this.flush(true, true, reason);
@@ -457,18 +496,16 @@ var ReplayTracker = class {
457
496
  }, Math.min(remainingMs, MAX_TIMEOUT_MS));
458
497
  }
459
498
  enqueueEventsIfReady(context, options = {}) {
460
- const { isFinal = false, flushReason = "manual", maxBatchSizeBytes = this.maxBatchSizeBytes, sealBeforeMinLength = false } = options;
499
+ const { isFinal = false, flushReason = "manual", maxBatchSizeBytes = this.maxBatchSizeBytes } = options;
461
500
  if (this.events.length === 0) return;
462
- if (!isFinal && !sealBeforeMinLength && !this.hasReachedMinLength()) {
501
+ if (!isFinal && !this.hasReachedMinLength()) {
463
502
  this.scheduleMinLengthFlush();
464
503
  return;
465
504
  }
466
505
  const batches = this.takeEventBatches(maxBatchSizeBytes);
467
- const blockedByMinLength = sealBeforeMinLength && !this.hasReachedMinLength();
468
506
  for (const [index, events] of batches.entries()) {
469
507
  const batch = this.createBatch(events, context, isFinal && index === batches.length - 1, flushReason);
470
- if (blockedByMinLength) this.minLengthBlockedBatches.add(batch);
471
- this.enqueueBatch(batch);
508
+ if (!batch || !this.enqueueBatch(batch)) break;
472
509
  }
473
510
  this.queuedEventsSizeBytes = 0;
474
511
  }
@@ -491,7 +528,11 @@ var ReplayTracker = class {
491
528
  }
492
529
  createBatch(events, context, isFinal, flushReason = "manual") {
493
530
  const identifier = getAnonymousId(this.options.siteKey, this.lastCookielessMode);
494
- const sequence = this.nextBatchSequence(context);
531
+ const sequence = nextReplaySequence(this.options.siteKey, context, this.lastCookielessMode);
532
+ if (!sequence) {
533
+ this.stopCapture("Replay sequence state is invalid or exhausted");
534
+ return;
535
+ }
495
536
  const chunkStartedAt = this.chunkStartedAt;
496
537
  const now = Date.now();
497
538
  this.chunkStartedAt = now;
@@ -504,8 +545,8 @@ var ReplayTracker = class {
504
545
  chunkStartedAt,
505
546
  chunkEndedAt: now,
506
547
  ...identifier ? { identifier } : {},
507
- batchId: `${context.sessionId}-${sequence}-${chunkStartedAt}`,
508
- sequence,
548
+ batchId: `${context.sessionId}-${sequence.sequence}-${chunkStartedAt}`,
549
+ ...sequence,
509
550
  timestamp: now,
510
551
  url: this.viewUrl || sanitizeUrl(window.location.href, this.options.trackHash ?? false),
511
552
  ...isFinal ? { isFinal: true } : {},
@@ -523,28 +564,35 @@ var ReplayTracker = class {
523
564
  batchSizeCache.set(batch, size);
524
565
  return size;
525
566
  }
526
- removePending(batch, reason) {
567
+ removePending(batch) {
527
568
  const index = this.pending.indexOf(batch);
528
- if (index < 0) return false;
569
+ if (index < 0) return;
529
570
  this.pending.splice(index, 1);
530
571
  this.pendingSizeBytes = Math.max(0, this.pendingSizeBytes - this.batchSizeBytes(batch));
531
- if (reason) this.log(`${reason}, dropping batch ${batch.sequence}`);
532
- return true;
572
+ this.log(`Sent replay batch ${batch.sequence}`);
573
+ }
574
+ stopCapture(reason) {
575
+ this.log(reason);
576
+ this.overflowed = true;
577
+ this.stopRecording?.();
578
+ this.stopRecording = void 0;
533
579
  }
534
580
  enqueueBatch(batch) {
535
581
  const size = this.batchSizeBytes(batch);
536
582
  if (size > this.maxQueueSizeBytes || this.pending.length >= this.maxPendingBatches || this.pendingSizeBytes + size > this.maxQueueSizeBytes) {
537
- this.log(`Replay queue limit reached at batch ${batch.sequence}; stopping recording at the last complete chain`);
538
- this.overflowed = true;
539
- this.stopRecording?.();
540
- this.stopRecording = void 0;
541
- return;
583
+ this.stopCapture(`Replay queue limit reached at batch ${batch.sequence}`);
584
+ return false;
542
585
  }
543
586
  this.needsFinalization = !batch.isFinal;
544
587
  this.pending.push(batch);
545
588
  this.pendingSizeBytes += size;
589
+ return true;
546
590
  }
547
591
  async flush(lowLatency, isFinal = false, flushReason = "manual") {
592
+ if (this.events.length === 0 && !isFinal) {
593
+ await this.sendPending(lowLatency, false);
594
+ return;
595
+ }
548
596
  const rotation = touchActivity(this.options.siteKey, this.lastCookielessMode);
549
597
  if (rotation) this.applySessionRotation(rotation.prev, rotation.next);
550
598
  const context = getSessionContext(this.options.siteKey, this.lastCookielessMode);
@@ -555,8 +603,6 @@ var ReplayTracker = class {
555
603
  });
556
604
  if (isFinal) this.finalizeSession(context, flushReason);
557
605
  if (this.pending.length === 0) return;
558
- if (isFinal) for (const batch of this.pending) this.minLengthBlockedBatches.delete(batch);
559
- else if (!rotation && flushReason !== "sessionRotate" && this.hasReachedMinLength()) this.unblockSessionBatches(context.sessionId);
560
606
  await this.sendPending(lowLatency, lowLatency && isFinal);
561
607
  }
562
608
  async sendPending(lowLatency, bypassRetryDelay) {
@@ -577,14 +623,13 @@ var ReplayTracker = class {
577
623
  try {
578
624
  while (this.pending.length > 0) {
579
625
  const batch = this.pending[0];
580
- if (this.minLengthBlockedBatches.has(batch)) break;
581
626
  if (!await this.sendBatch(batch, lowLatency)) {
582
627
  this.log(`Failed to send replay batch ${batch.sequence}`);
583
628
  if (!this.disposed) this.scheduleRetry();
584
629
  break;
585
630
  }
586
631
  this.retryAttempt = 0;
587
- this.removePending(batch, "Sent replay batch");
632
+ this.removePending(batch);
588
633
  if (this.queuedFlush?.lowLatency) break;
589
634
  }
590
635
  } finally {
@@ -604,7 +649,7 @@ var ReplayTracker = class {
604
649
  this.retryTask = setTimeout(() => {
605
650
  this.retryTask = null;
606
651
  if (this.retryAttempt === RETRY_MAX_ATTEMPTS) this.retryAttempt = 0;
607
- this.flush(false);
652
+ this.sendPending(false, false);
608
653
  }, delay);
609
654
  }
610
655
  retryDelay(attempt) {
package/package.json CHANGED
@@ -42,7 +42,7 @@
42
42
  "publishConfig": {
43
43
  "access": "public"
44
44
  },
45
- "version": "0.10.1",
45
+ "version": "0.10.2",
46
46
  "scripts": {
47
47
  "build": "tsdown && bun run check-size",
48
48
  "dev": "bun run build",
@@ -60,6 +60,6 @@
60
60
  "@rrweb/record": "^2.1.6",
61
61
  "@rrweb/rrweb-plugin-console-record": "^2.1.6",
62
62
  "@rrweb/rrweb-plugin-network-record": "^2.1.6",
63
- "web-vitals": "^6.2.1"
63
+ "web-vitals": "^6.2.2"
64
64
  }
65
65
  }