@glasstrace/sdk 0.12.2 → 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.
@@ -473,6 +473,7 @@ export {
473
473
  isAnonymousMode,
474
474
  maybeShowMcpNudge,
475
475
  installConsoleCapture,
476
+ sdkLog,
476
477
  discoverSourceMapFiles,
477
478
  collectSourceMaps,
478
479
  computeBuildHash,
@@ -484,4 +485,4 @@ export {
484
485
  uploadSourceMapsPresigned,
485
486
  uploadSourceMapsAuto
486
487
  };
487
- //# sourceMappingURL=chunk-MSMOH6IH.js.map
488
+ //# sourceMappingURL=chunk-J576N5MN.js.map
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 {
@@ -17334,6 +17346,7 @@ var GlasstraceSpanProcessor = class {
17334
17346
  // src/enriching-exporter.ts
17335
17347
  init_esm();
17336
17348
  init_dist();
17349
+ init_console_capture();
17337
17350
  var ATTR = GLASSTRACE_ATTRIBUTE_NAMES;
17338
17351
  var API_KEY_PENDING = "pending";
17339
17352
  var MAX_PENDING_SPANS = 1024;
@@ -17366,7 +17379,12 @@ var GlasstraceExporter = class {
17366
17379
  const enrichedSpans = spans.map((span) => this.enrichSpan(span));
17367
17380
  const exporter = this.ensureDelegate();
17368
17381
  if (exporter) {
17369
- exporter.export(enrichedSpans, resultCallback);
17382
+ exporter.export(enrichedSpans, (result) => {
17383
+ if (result.code !== 0) {
17384
+ sdkLog("warn", `[glasstrace] Span export failed: ${result.error?.message ?? "unknown error"}`);
17385
+ }
17386
+ resultCallback(result);
17387
+ });
17370
17388
  recordSpansExported(enrichedSpans.length);
17371
17389
  } else {
17372
17390
  recordSpansDropped(enrichedSpans.length);
@@ -17399,7 +17417,14 @@ var GlasstraceExporter = class {
17399
17417
  return this.delegate.shutdown();
17400
17418
  }
17401
17419
  }
17420
+ /**
17421
+ * Flushes any pending buffered spans (if the API key has resolved) and
17422
+ * delegates to the underlying exporter's forceFlush to drain its queue.
17423
+ */
17402
17424
  forceFlush() {
17425
+ if (this.getApiKey() !== API_KEY_PENDING && this.pendingBatches.length > 0) {
17426
+ this.flushPending();
17427
+ }
17403
17428
  if (this.delegate?.forceFlush) {
17404
17429
  return this.delegate.forceFlush();
17405
17430
  }
@@ -17568,7 +17593,12 @@ var GlasstraceExporter = class {
17568
17593
  this.pendingSpanCount = 0;
17569
17594
  for (const batch of batches) {
17570
17595
  const enriched = batch.spans.map((span) => this.enrichSpan(span));
17571
- exporter.export(enriched, batch.resultCallback);
17596
+ exporter.export(enriched, (result) => {
17597
+ if (result.code !== 0) {
17598
+ sdkLog("warn", `[glasstrace] Span export failed: ${result.error?.message ?? "unknown error"}`);
17599
+ }
17600
+ batch.resultCallback(result);
17601
+ });
17572
17602
  recordSpansExported(enriched.length);
17573
17603
  }
17574
17604
  }
@@ -20309,6 +20339,7 @@ var BasicTracerProvider = class {
20309
20339
 
20310
20340
  // src/otel-config.ts
20311
20341
  init_esm();
20342
+ init_console_capture();
20312
20343
  var _resolvedApiKey = API_KEY_PENDING;
20313
20344
  var _activeExporter = null;
20314
20345
  var _shutdownHandler = null;
@@ -20392,7 +20423,21 @@ async function configureOtel(config2, sessionManager) {
20392
20423
  _activeExporter = null;
20393
20424
  return;
20394
20425
  }
20395
- const processor = new BatchSpanProcessor(glasstraceExporter);
20426
+ if (config2.verbose) {
20427
+ diag2.setLogger(
20428
+ {
20429
+ verbose: (msg) => sdkLog("info", `[otel] ${msg}`),
20430
+ debug: (msg) => sdkLog("info", `[otel] ${msg}`),
20431
+ info: (msg) => sdkLog("info", `[otel] ${msg}`),
20432
+ warn: (msg) => sdkLog("warn", `[otel] ${msg}`),
20433
+ error: (msg) => sdkLog("error", `[otel] ${msg}`)
20434
+ },
20435
+ DiagLogLevel.WARN
20436
+ );
20437
+ }
20438
+ const processor = new BatchSpanProcessor(glasstraceExporter, {
20439
+ scheduledDelayMillis: 1e3
20440
+ });
20396
20441
  const provider = new BasicTracerProvider({
20397
20442
  spanProcessors: [processor]
20398
20443
  });
@@ -20402,6 +20447,112 @@ async function configureOtel(config2, sessionManager) {
20402
20447
 
20403
20448
  // src/register.ts
20404
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
20405
20556
  var consoleCaptureInstalled = false;
20406
20557
  var discoveryHandler = null;
20407
20558
  var isRegistered = false;
@@ -20554,14 +20705,20 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
20554
20705
  if (config2.verbose) {
20555
20706
  console.info("[glasstrace] Background init firing.");
20556
20707
  }
20557
- const healthReport = collectHealthReport("0.12.2");
20558
- const initResult = await performInit(config2, anonKeyForInit, "0.12.2", healthReport);
20708
+ const healthReport = collectHealthReport("0.12.4");
20709
+ const initResult = await performInit(config2, anonKeyForInit, "0.12.4", healthReport);
20559
20710
  if (generation !== registrationGeneration) return;
20560
20711
  if (initResult?.claimResult) {
20561
20712
  setResolvedApiKey(initResult.claimResult.newApiKey);
20562
20713
  notifyApiKeyResolved();
20563
20714
  }
20564
20715
  maybeInstallConsoleCapture();
20716
+ if (didLastInitSucceed()) {
20717
+ startHeartbeat(config2, anonKeyForInit, "0.12.4", generation, (newApiKey) => {
20718
+ setResolvedApiKey(newApiKey);
20719
+ notifyApiKeyResolved();
20720
+ });
20721
+ }
20565
20722
  }
20566
20723
  function getDiscoveryHandler() {
20567
20724
  return discoveryHandler;