@logspace/sdk 1.1.7 → 1.1.9

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/logspace.esm.js CHANGED
@@ -14490,7 +14490,7 @@ async function updatePendingSessionRetry(sessionId) {
14490
14490
  async function cleanupOldPendingSessions() {
14491
14491
  if (!isIndexedDBAvailable()) return;
14492
14492
  const MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
14493
- const MAX_RETRIES = 5;
14493
+ const MAX_RETRIES = 10;
14494
14494
  const now = Date.now();
14495
14495
  try {
14496
14496
  const sessions = await getPendingSessions();
@@ -14505,6 +14505,18 @@ async function cleanupOldPendingSessions() {
14505
14505
  console.warn("[LogSpace] Failed to cleanup old sessions:", error);
14506
14506
  }
14507
14507
  }
14508
+ function getBackoffInterval(retryCount) {
14509
+ const baseMs = 60 * 1e3;
14510
+ const maxMs = 60 * 60 * 1e3;
14511
+ const backoff = Math.min(baseMs * Math.pow(2, retryCount), maxMs);
14512
+ return backoff;
14513
+ }
14514
+ function isReadyForRetry(session2) {
14515
+ if (!session2.lastRetryAt) return true;
14516
+ const backoffMs = getBackoffInterval(session2.retryCount);
14517
+ const timeSinceLastRetry = Date.now() - session2.lastRetryAt;
14518
+ return timeSinceLastRetry >= backoffMs;
14519
+ }
14508
14520
  function closeDB() {
14509
14521
  if (db) {
14510
14522
  db.close();
@@ -14524,15 +14536,17 @@ let rateLimiter = { count: 0, windowStart: 0 };
14524
14536
  let deduplication = { lastLogHash: null, lastLogCount: 0 };
14525
14537
  let currentSize = 0;
14526
14538
  let rrwebSize = 0;
14527
- let lastRateLimitWarningTime = 0;
14528
- const RATE_LIMIT_WARNING_THROTTLE_MS = 1e3;
14539
+ let rateLimitWarnedThisWindow = false;
14540
+ let rateLimitDroppedCount = 0;
14529
14541
  let rrwebRateLimiter = { count: 0, windowStart: 0 };
14530
14542
  const RRWEB_RATE_LIMIT = 500;
14531
14543
  let idleTimer = null;
14532
14544
  let durationTimer = null;
14533
14545
  let checkpointTimer = null;
14534
14546
  let visibilityTimer = null;
14547
+ let pendingRetryTimer = null;
14535
14548
  let lastMouseMoveTime = 0;
14549
+ const PENDING_RETRY_INTERVAL = 2 * 60 * 1e3;
14536
14550
  let samplingTriggered = false;
14537
14551
  let samplingTriggerType = null;
14538
14552
  let samplingFirstTriggerTime = null;
@@ -14748,18 +14762,23 @@ function checkRateLimit() {
14748
14762
  const now = Date.now();
14749
14763
  const windowMs = 1e3;
14750
14764
  if (now - rateLimiter.windowStart > windowMs) {
14765
+ if (config.debug && rateLimitDroppedCount > 0) {
14766
+ console.warn(`[LogSpace] Rate limit: dropped ${rateLimitDroppedCount} logs in last second`);
14767
+ }
14751
14768
  rateLimiter.windowStart = now;
14752
14769
  rateLimiter.count = 1;
14770
+ rateLimitWarnedThisWindow = false;
14771
+ rateLimitDroppedCount = 0;
14753
14772
  return true;
14754
14773
  }
14755
14774
  rateLimiter.count++;
14756
14775
  if (rateLimiter.count > config.limits.rateLimit) {
14757
- if (config.debug) {
14758
- const now2 = Date.now();
14759
- if (now2 - lastRateLimitWarningTime >= RATE_LIMIT_WARNING_THROTTLE_MS) {
14760
- lastRateLimitWarningTime = now2;
14761
- console.warn("[LogSpace] Rate limit exceeded, dropping log");
14762
- }
14776
+ rateLimitDroppedCount++;
14777
+ if (!rateLimitWarnedThisWindow) {
14778
+ rateLimitWarnedThisWindow = true;
14779
+ console.warn(
14780
+ `[LogSpace] Rate limit exceeded (${config.limits.rateLimit}/sec). Logs are being dropped. Consider increasing limits.rateLimit or disabling noisy captures.`
14781
+ );
14763
14782
  }
14764
14783
  return false;
14765
14784
  }
@@ -15187,6 +15206,48 @@ function stopCheckpointTimer() {
15187
15206
  checkpointTimer = null;
15188
15207
  }
15189
15208
  }
15209
+ function startPendingRetryTimer() {
15210
+ if (pendingRetryTimer || !isIndexedDBAvailable()) return;
15211
+ pendingRetryTimer = setInterval(async () => {
15212
+ if (!config?.serverUrl) return;
15213
+ try {
15214
+ const pendingSessions = await getPendingSessions();
15215
+ if (pendingSessions.length === 0) return;
15216
+ const readySessions = pendingSessions.filter(isReadyForRetry);
15217
+ if (readySessions.length === 0) return;
15218
+ if (config.debug) {
15219
+ console.log(
15220
+ `[LogSpace] Periodic retry: ${readySessions.length} of ${pendingSessions.length} pending sessions ready`
15221
+ );
15222
+ }
15223
+ for (const stored of readySessions) {
15224
+ try {
15225
+ await sendPayloadToServer(stored.data);
15226
+ await removePendingSession(stored.id);
15227
+ if (config.debug) {
15228
+ console.log("[LogSpace] Pending session sent:", stored.id);
15229
+ }
15230
+ } catch (error) {
15231
+ await updatePendingSessionRetry(stored.id);
15232
+ if (config.debug) {
15233
+ const nextBackoff = Math.ceil(getBackoffInterval(stored.retryCount + 1) / 1e3);
15234
+ console.warn(`[LogSpace] Retry failed for ${stored.id}, next retry in ${nextBackoff}s`);
15235
+ }
15236
+ }
15237
+ }
15238
+ } catch (error) {
15239
+ if (config?.debug) {
15240
+ console.warn("[LogSpace] Periodic retry check failed:", error);
15241
+ }
15242
+ }
15243
+ }, PENDING_RETRY_INTERVAL);
15244
+ }
15245
+ function stopPendingRetryTimer() {
15246
+ if (pendingRetryTimer) {
15247
+ clearInterval(pendingRetryTimer);
15248
+ pendingRetryTimer = null;
15249
+ }
15250
+ }
15190
15251
  const EMERGENCY_BACKUP_KEY = "__logspace_emergency_backup";
15191
15252
  const SAMPLING_STATE_KEY = "__logspace_sampling_state";
15192
15253
  function saveSamplingState(sessionId) {
@@ -15837,6 +15898,16 @@ async function recoverPendingSessions() {
15837
15898
  await removePendingSession(stored.id);
15838
15899
  continue;
15839
15900
  }
15901
+ if (!isReadyForRetry(stored)) {
15902
+ if (config.debug) {
15903
+ const backoffMs = getBackoffInterval(stored.retryCount);
15904
+ const waitTime = Math.ceil((backoffMs - (Date.now() - (stored.lastRetryAt || 0))) / 1e3);
15905
+ console.log(
15906
+ `[LogSpace] Pending session ${stored.id} waiting for backoff (${waitTime}s remaining, retry #${stored.retryCount})`
15907
+ );
15908
+ }
15909
+ continue;
15910
+ }
15840
15911
  try {
15841
15912
  await sendPayloadToServer(stored.data);
15842
15913
  processedRecoverySessionIds.add(stored.id);
@@ -15929,6 +16000,7 @@ const LogSpace = {
15929
16000
  }
15930
16001
  unloadHandled = false;
15931
16002
  isNavigatingAway = false;
16003
+ startPendingRetryTimer();
15932
16004
  this.startSession();
15933
16005
  recoverPendingSessions().catch(() => {
15934
16006
  });
@@ -15961,7 +16033,8 @@ const LogSpace = {
15961
16033
  rrwebSize = 0;
15962
16034
  rateLimiter = { count: 0, windowStart: 0 };
15963
16035
  rrwebRateLimiter = { count: 0, windowStart: 0 };
15964
- lastRateLimitWarningTime = 0;
16036
+ rateLimitWarnedThisWindow = false;
16037
+ rateLimitDroppedCount = 0;
15965
16038
  deduplication = { lastLogHash: null, lastLogCount: 0 };
15966
16039
  endReason = "manual";
15967
16040
  let sessionId;
@@ -16299,6 +16372,7 @@ const LogSpace = {
16299
16372
  visibilityTimer = null;
16300
16373
  }
16301
16374
  stopCheckpointTimer();
16375
+ stopPendingRetryTimer();
16302
16376
  stopSamplingTrimTimer();
16303
16377
  if (config?.capture.rrweb) {
16304
16378
  stopRRWebRecording();