@glasstrace/sdk 0.12.3 → 0.12.4

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/dist/index.cjs CHANGED
@@ -17036,6 +17036,7 @@ function loadFsSyncOrNull() {
17036
17036
  var currentConfig = null;
17037
17037
  var configCacheChecked = false;
17038
17038
  var rateLimitBackoff = false;
17039
+ var lastInitSucceeded = false;
17039
17040
  function loadCachedConfig(projectRoot) {
17040
17041
  const modules = loadFsSyncOrNull();
17041
17042
  if (!modules) return null;
@@ -17205,6 +17206,7 @@ async function writeClaimedKey(newApiKey, projectRoot) {
17205
17206
  }
17206
17207
  }
17207
17208
  async function performInit(config2, anonKey, sdkVersion, healthReport) {
17209
+ lastInitSucceeded = false;
17208
17210
  if (rateLimitBackoff) {
17209
17211
  rateLimitBackoff = false;
17210
17212
  return null;
@@ -17233,6 +17235,7 @@ async function performInit(config2, anonKey, sdkVersion, healthReport) {
17233
17235
  if (healthReport) {
17234
17236
  acknowledgeHealthReport(healthReport);
17235
17237
  }
17238
+ lastInitSucceeded = true;
17236
17239
  await saveCachedConfig(result);
17237
17240
  if (result.claimResult) {
17238
17241
  try {
@@ -17279,7 +17282,6 @@ async function performInit(config2, anonKey, sdkVersion, healthReport) {
17279
17282
  return null;
17280
17283
  }
17281
17284
  } catch (err) {
17282
- recordInitFailure();
17283
17285
  console.warn(
17284
17286
  `[glasstrace] Unexpected init error: ${err instanceof Error ? err.message : String(err)}`
17285
17287
  );
@@ -17309,6 +17311,16 @@ function getClaimResult() {
17309
17311
  function _setCurrentConfig(config2) {
17310
17312
  currentConfig = config2;
17311
17313
  }
17314
+ function consumeRateLimitFlag() {
17315
+ if (rateLimitBackoff) {
17316
+ rateLimitBackoff = false;
17317
+ return true;
17318
+ }
17319
+ return false;
17320
+ }
17321
+ function didLastInitSucceed() {
17322
+ return lastInitSucceeded;
17323
+ }
17312
17324
 
17313
17325
  // src/span-processor.ts
17314
17326
  var GlasstraceSpanProcessor = class {
@@ -20435,6 +20447,112 @@ async function configureOtel(config2, sessionManager) {
20435
20447
 
20436
20448
  // src/register.ts
20437
20449
  init_console_capture();
20450
+
20451
+ // src/heartbeat.ts
20452
+ init_console_capture();
20453
+ var HEARTBEAT_INTERVAL_MS = 5 * 60 * 1e3;
20454
+ var BACKOFF_BASE_MS = HEARTBEAT_INTERVAL_MS;
20455
+ var BACKOFF_MAX_MS = 30 * 60 * 1e3;
20456
+ var BACKOFF_JITTER = 0.2;
20457
+ var heartbeatTimer = null;
20458
+ var heartbeatGeneration = 0;
20459
+ var backoffAttempts = 0;
20460
+ var backoffUntil = 0;
20461
+ var tickInProgress = false;
20462
+ var _shutdownHandler2 = null;
20463
+ function startHeartbeat(config2, anonKey, sdkVersion, generation, onClaimTransition) {
20464
+ if (heartbeatTimer !== null) return;
20465
+ heartbeatGeneration = generation;
20466
+ heartbeatTimer = setInterval(() => {
20467
+ void heartbeatTick(config2, anonKey, sdkVersion, generation, onClaimTransition);
20468
+ }, HEARTBEAT_INTERVAL_MS);
20469
+ heartbeatTimer.unref();
20470
+ registerShutdownHandlers(config2, anonKey, sdkVersion);
20471
+ if (config2.verbose) {
20472
+ sdkLog("info", "[glasstrace] Heartbeat started (5-minute interval).");
20473
+ }
20474
+ }
20475
+ function stopHeartbeat() {
20476
+ if (heartbeatTimer !== null) {
20477
+ clearInterval(heartbeatTimer);
20478
+ heartbeatTimer = null;
20479
+ }
20480
+ removeShutdownHandlers();
20481
+ }
20482
+ async function heartbeatTick(config2, anonKey, sdkVersion, generation, onClaimTransition) {
20483
+ if (tickInProgress) return;
20484
+ tickInProgress = true;
20485
+ try {
20486
+ if (generation !== heartbeatGeneration) {
20487
+ stopHeartbeat();
20488
+ return;
20489
+ }
20490
+ if (Date.now() < backoffUntil) {
20491
+ if (config2.verbose) {
20492
+ sdkLog("info", "[glasstrace] Heartbeat skipped (rate-limit backoff).");
20493
+ }
20494
+ return;
20495
+ }
20496
+ const healthReport = collectHealthReport(sdkVersion);
20497
+ const initResult = await performInit(config2, anonKey, sdkVersion, healthReport);
20498
+ if (generation !== heartbeatGeneration) return;
20499
+ if (initResult === null && consumeRateLimitFlag()) {
20500
+ backoffAttempts++;
20501
+ const delay = Math.min(
20502
+ BACKOFF_BASE_MS * Math.pow(2, backoffAttempts - 1),
20503
+ BACKOFF_MAX_MS
20504
+ );
20505
+ const jitter = delay * BACKOFF_JITTER * (Math.random() * 2 - 1);
20506
+ backoffUntil = Date.now() + delay + jitter;
20507
+ if (config2.verbose) {
20508
+ sdkLog("info", `[glasstrace] Heartbeat backing off for ${Math.round((delay + jitter) / 1e3)}s.`);
20509
+ }
20510
+ } else {
20511
+ backoffAttempts = 0;
20512
+ backoffUntil = 0;
20513
+ }
20514
+ if (initResult?.claimResult) {
20515
+ onClaimTransition(initResult.claimResult.newApiKey);
20516
+ }
20517
+ if (config2.verbose) {
20518
+ sdkLog("info", "[glasstrace] Heartbeat completed.");
20519
+ }
20520
+ } finally {
20521
+ tickInProgress = false;
20522
+ }
20523
+ }
20524
+ function registerShutdownHandlers(config2, anonKey, sdkVersion) {
20525
+ if (typeof process === "undefined" || typeof process.once !== "function") {
20526
+ return;
20527
+ }
20528
+ let shutdownFired = false;
20529
+ const handler = (signal) => {
20530
+ if (shutdownFired) return;
20531
+ shutdownFired = true;
20532
+ if (heartbeatTimer !== null) {
20533
+ clearInterval(heartbeatTimer);
20534
+ heartbeatTimer = null;
20535
+ }
20536
+ const healthReport = collectHealthReport(sdkVersion);
20537
+ void performInit(config2, anonKey, sdkVersion, healthReport).catch(() => {
20538
+ }).finally(() => {
20539
+ removeShutdownHandlers();
20540
+ process.kill(process.pid, signal);
20541
+ });
20542
+ };
20543
+ _shutdownHandler2 = handler;
20544
+ process.once("SIGTERM", _shutdownHandler2);
20545
+ process.once("SIGINT", _shutdownHandler2);
20546
+ }
20547
+ function removeShutdownHandlers() {
20548
+ if (_shutdownHandler2 && typeof process !== "undefined") {
20549
+ process.removeListener("SIGTERM", _shutdownHandler2);
20550
+ process.removeListener("SIGINT", _shutdownHandler2);
20551
+ _shutdownHandler2 = null;
20552
+ }
20553
+ }
20554
+
20555
+ // src/register.ts
20438
20556
  var consoleCaptureInstalled = false;
20439
20557
  var discoveryHandler = null;
20440
20558
  var isRegistered = false;
@@ -20587,14 +20705,20 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
20587
20705
  if (config2.verbose) {
20588
20706
  console.info("[glasstrace] Background init firing.");
20589
20707
  }
20590
- const healthReport = collectHealthReport("0.12.3");
20591
- const initResult = await performInit(config2, anonKeyForInit, "0.12.3", healthReport);
20708
+ const healthReport = collectHealthReport("0.12.4");
20709
+ const initResult = await performInit(config2, anonKeyForInit, "0.12.4", healthReport);
20592
20710
  if (generation !== registrationGeneration) return;
20593
20711
  if (initResult?.claimResult) {
20594
20712
  setResolvedApiKey(initResult.claimResult.newApiKey);
20595
20713
  notifyApiKeyResolved();
20596
20714
  }
20597
20715
  maybeInstallConsoleCapture();
20716
+ if (didLastInitSucceed()) {
20717
+ startHeartbeat(config2, anonKeyForInit, "0.12.4", generation, (newApiKey) => {
20718
+ setResolvedApiKey(newApiKey);
20719
+ notifyApiKeyResolved();
20720
+ });
20721
+ }
20598
20722
  }
20599
20723
  function getDiscoveryHandler() {
20600
20724
  return discoveryHandler;