@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.
- package/dist/{chunk-MSMOH6IH.js → chunk-J576N5MN.js} +2 -1
- package/dist/index.cjs +163 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +162 -8
- package/dist/index.js.map +1 -1
- package/dist/{source-map-uploader-ZFCYOURS.js → source-map-uploader-ZHD654EG.js} +2 -2
- package/package.json +1 -1
- /package/dist/{chunk-MSMOH6IH.js.map → chunk-J576N5MN.js.map} +0 -0
- /package/dist/{source-map-uploader-ZFCYOURS.js.map → source-map-uploader-ZHD654EG.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -394,6 +394,10 @@ declare class GlasstraceExporter implements SpanExporter {
|
|
|
394
394
|
*/
|
|
395
395
|
notifyKeyResolved(): void;
|
|
396
396
|
shutdown(): Promise<void>;
|
|
397
|
+
/**
|
|
398
|
+
* Flushes any pending buffered spans (if the API key has resolved) and
|
|
399
|
+
* delegates to the underlying exporter's forceFlush to drain its queue.
|
|
400
|
+
*/
|
|
397
401
|
forceFlush(): Promise<void>;
|
|
398
402
|
/**
|
|
399
403
|
* Enriches a ReadableSpan with all glasstrace.* attributes.
|
package/dist/index.d.ts
CHANGED
|
@@ -394,6 +394,10 @@ declare class GlasstraceExporter implements SpanExporter {
|
|
|
394
394
|
*/
|
|
395
395
|
notifyKeyResolved(): void;
|
|
396
396
|
shutdown(): Promise<void>;
|
|
397
|
+
/**
|
|
398
|
+
* Flushes any pending buffered spans (if the API key has resolved) and
|
|
399
|
+
* delegates to the underlying exporter's forceFlush to drain its queue.
|
|
400
|
+
*/
|
|
397
401
|
forceFlush(): Promise<void>;
|
|
398
402
|
/**
|
|
399
403
|
* Enriches a ReadableSpan with all glasstrace.* attributes.
|
package/dist/index.js
CHANGED
|
@@ -9,10 +9,11 @@ import {
|
|
|
9
9
|
maybeShowMcpNudge,
|
|
10
10
|
readEnvVars,
|
|
11
11
|
resolveConfig,
|
|
12
|
+
sdkLog,
|
|
12
13
|
uploadSourceMaps,
|
|
13
14
|
uploadSourceMapsAuto,
|
|
14
15
|
uploadSourceMapsPresigned
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-J576N5MN.js";
|
|
16
17
|
import {
|
|
17
18
|
buildImportGraph,
|
|
18
19
|
discoverTestFiles,
|
|
@@ -30,6 +31,7 @@ import {
|
|
|
30
31
|
SessionIdSchema
|
|
31
32
|
} from "./chunk-OKIP4SRG.js";
|
|
32
33
|
import {
|
|
34
|
+
DiagLogLevel,
|
|
33
35
|
INVALID_SPAN_CONTEXT,
|
|
34
36
|
SamplingDecision,
|
|
35
37
|
SpanKind,
|
|
@@ -257,6 +259,7 @@ function loadFsSyncOrNull() {
|
|
|
257
259
|
var currentConfig = null;
|
|
258
260
|
var configCacheChecked = false;
|
|
259
261
|
var rateLimitBackoff = false;
|
|
262
|
+
var lastInitSucceeded = false;
|
|
260
263
|
function loadCachedConfig(projectRoot) {
|
|
261
264
|
const modules = loadFsSyncOrNull();
|
|
262
265
|
if (!modules) return null;
|
|
@@ -426,6 +429,7 @@ async function writeClaimedKey(newApiKey, projectRoot) {
|
|
|
426
429
|
}
|
|
427
430
|
}
|
|
428
431
|
async function performInit(config, anonKey, sdkVersion, healthReport) {
|
|
432
|
+
lastInitSucceeded = false;
|
|
429
433
|
if (rateLimitBackoff) {
|
|
430
434
|
rateLimitBackoff = false;
|
|
431
435
|
return null;
|
|
@@ -454,6 +458,7 @@ async function performInit(config, anonKey, sdkVersion, healthReport) {
|
|
|
454
458
|
if (healthReport) {
|
|
455
459
|
acknowledgeHealthReport(healthReport);
|
|
456
460
|
}
|
|
461
|
+
lastInitSucceeded = true;
|
|
457
462
|
await saveCachedConfig(result);
|
|
458
463
|
if (result.claimResult) {
|
|
459
464
|
try {
|
|
@@ -500,7 +505,6 @@ async function performInit(config, anonKey, sdkVersion, healthReport) {
|
|
|
500
505
|
return null;
|
|
501
506
|
}
|
|
502
507
|
} catch (err) {
|
|
503
|
-
recordInitFailure();
|
|
504
508
|
console.warn(
|
|
505
509
|
`[glasstrace] Unexpected init error: ${err instanceof Error ? err.message : String(err)}`
|
|
506
510
|
);
|
|
@@ -530,6 +534,16 @@ function getClaimResult() {
|
|
|
530
534
|
function _setCurrentConfig(config) {
|
|
531
535
|
currentConfig = config;
|
|
532
536
|
}
|
|
537
|
+
function consumeRateLimitFlag() {
|
|
538
|
+
if (rateLimitBackoff) {
|
|
539
|
+
rateLimitBackoff = false;
|
|
540
|
+
return true;
|
|
541
|
+
}
|
|
542
|
+
return false;
|
|
543
|
+
}
|
|
544
|
+
function didLastInitSucceed() {
|
|
545
|
+
return lastInitSucceeded;
|
|
546
|
+
}
|
|
533
547
|
|
|
534
548
|
// src/span-processor.ts
|
|
535
549
|
var GlasstraceSpanProcessor = class {
|
|
@@ -585,7 +599,12 @@ var GlasstraceExporter = class {
|
|
|
585
599
|
const enrichedSpans = spans.map((span) => this.enrichSpan(span));
|
|
586
600
|
const exporter = this.ensureDelegate();
|
|
587
601
|
if (exporter) {
|
|
588
|
-
exporter.export(enrichedSpans,
|
|
602
|
+
exporter.export(enrichedSpans, (result) => {
|
|
603
|
+
if (result.code !== 0) {
|
|
604
|
+
sdkLog("warn", `[glasstrace] Span export failed: ${result.error?.message ?? "unknown error"}`);
|
|
605
|
+
}
|
|
606
|
+
resultCallback(result);
|
|
607
|
+
});
|
|
589
608
|
recordSpansExported(enrichedSpans.length);
|
|
590
609
|
} else {
|
|
591
610
|
recordSpansDropped(enrichedSpans.length);
|
|
@@ -618,7 +637,14 @@ var GlasstraceExporter = class {
|
|
|
618
637
|
return this.delegate.shutdown();
|
|
619
638
|
}
|
|
620
639
|
}
|
|
640
|
+
/**
|
|
641
|
+
* Flushes any pending buffered spans (if the API key has resolved) and
|
|
642
|
+
* delegates to the underlying exporter's forceFlush to drain its queue.
|
|
643
|
+
*/
|
|
621
644
|
forceFlush() {
|
|
645
|
+
if (this.getApiKey() !== API_KEY_PENDING && this.pendingBatches.length > 0) {
|
|
646
|
+
this.flushPending();
|
|
647
|
+
}
|
|
622
648
|
if (this.delegate?.forceFlush) {
|
|
623
649
|
return this.delegate.forceFlush();
|
|
624
650
|
}
|
|
@@ -787,7 +813,12 @@ var GlasstraceExporter = class {
|
|
|
787
813
|
this.pendingSpanCount = 0;
|
|
788
814
|
for (const batch of batches) {
|
|
789
815
|
const enriched = batch.spans.map((span) => this.enrichSpan(span));
|
|
790
|
-
exporter.export(enriched,
|
|
816
|
+
exporter.export(enriched, (result) => {
|
|
817
|
+
if (result.code !== 0) {
|
|
818
|
+
sdkLog("warn", `[glasstrace] Span export failed: ${result.error?.message ?? "unknown error"}`);
|
|
819
|
+
}
|
|
820
|
+
batch.resultCallback(result);
|
|
821
|
+
});
|
|
791
822
|
recordSpansExported(enriched.length);
|
|
792
823
|
}
|
|
793
824
|
}
|
|
@@ -3578,7 +3609,21 @@ async function configureOtel(config, sessionManager) {
|
|
|
3578
3609
|
_activeExporter = null;
|
|
3579
3610
|
return;
|
|
3580
3611
|
}
|
|
3581
|
-
|
|
3612
|
+
if (config.verbose) {
|
|
3613
|
+
diag.setLogger(
|
|
3614
|
+
{
|
|
3615
|
+
verbose: (msg) => sdkLog("info", `[otel] ${msg}`),
|
|
3616
|
+
debug: (msg) => sdkLog("info", `[otel] ${msg}`),
|
|
3617
|
+
info: (msg) => sdkLog("info", `[otel] ${msg}`),
|
|
3618
|
+
warn: (msg) => sdkLog("warn", `[otel] ${msg}`),
|
|
3619
|
+
error: (msg) => sdkLog("error", `[otel] ${msg}`)
|
|
3620
|
+
},
|
|
3621
|
+
DiagLogLevel.WARN
|
|
3622
|
+
);
|
|
3623
|
+
}
|
|
3624
|
+
const processor = new BatchSpanProcessor(glasstraceExporter, {
|
|
3625
|
+
scheduledDelayMillis: 1e3
|
|
3626
|
+
});
|
|
3582
3627
|
const provider = new BasicTracerProvider({
|
|
3583
3628
|
spanProcessors: [processor]
|
|
3584
3629
|
});
|
|
@@ -3586,6 +3631,109 @@ async function configureOtel(config, sessionManager) {
|
|
|
3586
3631
|
registerShutdownHooks(provider);
|
|
3587
3632
|
}
|
|
3588
3633
|
|
|
3634
|
+
// src/heartbeat.ts
|
|
3635
|
+
var HEARTBEAT_INTERVAL_MS = 5 * 60 * 1e3;
|
|
3636
|
+
var BACKOFF_BASE_MS = HEARTBEAT_INTERVAL_MS;
|
|
3637
|
+
var BACKOFF_MAX_MS = 30 * 60 * 1e3;
|
|
3638
|
+
var BACKOFF_JITTER = 0.2;
|
|
3639
|
+
var heartbeatTimer = null;
|
|
3640
|
+
var heartbeatGeneration = 0;
|
|
3641
|
+
var backoffAttempts = 0;
|
|
3642
|
+
var backoffUntil = 0;
|
|
3643
|
+
var tickInProgress = false;
|
|
3644
|
+
var _shutdownHandler2 = null;
|
|
3645
|
+
function startHeartbeat(config, anonKey, sdkVersion, generation, onClaimTransition) {
|
|
3646
|
+
if (heartbeatTimer !== null) return;
|
|
3647
|
+
heartbeatGeneration = generation;
|
|
3648
|
+
heartbeatTimer = setInterval(() => {
|
|
3649
|
+
void heartbeatTick(config, anonKey, sdkVersion, generation, onClaimTransition);
|
|
3650
|
+
}, HEARTBEAT_INTERVAL_MS);
|
|
3651
|
+
heartbeatTimer.unref();
|
|
3652
|
+
registerShutdownHandlers(config, anonKey, sdkVersion);
|
|
3653
|
+
if (config.verbose) {
|
|
3654
|
+
sdkLog("info", "[glasstrace] Heartbeat started (5-minute interval).");
|
|
3655
|
+
}
|
|
3656
|
+
}
|
|
3657
|
+
function stopHeartbeat() {
|
|
3658
|
+
if (heartbeatTimer !== null) {
|
|
3659
|
+
clearInterval(heartbeatTimer);
|
|
3660
|
+
heartbeatTimer = null;
|
|
3661
|
+
}
|
|
3662
|
+
removeShutdownHandlers();
|
|
3663
|
+
}
|
|
3664
|
+
async function heartbeatTick(config, anonKey, sdkVersion, generation, onClaimTransition) {
|
|
3665
|
+
if (tickInProgress) return;
|
|
3666
|
+
tickInProgress = true;
|
|
3667
|
+
try {
|
|
3668
|
+
if (generation !== heartbeatGeneration) {
|
|
3669
|
+
stopHeartbeat();
|
|
3670
|
+
return;
|
|
3671
|
+
}
|
|
3672
|
+
if (Date.now() < backoffUntil) {
|
|
3673
|
+
if (config.verbose) {
|
|
3674
|
+
sdkLog("info", "[glasstrace] Heartbeat skipped (rate-limit backoff).");
|
|
3675
|
+
}
|
|
3676
|
+
return;
|
|
3677
|
+
}
|
|
3678
|
+
const healthReport = collectHealthReport(sdkVersion);
|
|
3679
|
+
const initResult = await performInit(config, anonKey, sdkVersion, healthReport);
|
|
3680
|
+
if (generation !== heartbeatGeneration) return;
|
|
3681
|
+
if (initResult === null && consumeRateLimitFlag()) {
|
|
3682
|
+
backoffAttempts++;
|
|
3683
|
+
const delay = Math.min(
|
|
3684
|
+
BACKOFF_BASE_MS * Math.pow(2, backoffAttempts - 1),
|
|
3685
|
+
BACKOFF_MAX_MS
|
|
3686
|
+
);
|
|
3687
|
+
const jitter = delay * BACKOFF_JITTER * (Math.random() * 2 - 1);
|
|
3688
|
+
backoffUntil = Date.now() + delay + jitter;
|
|
3689
|
+
if (config.verbose) {
|
|
3690
|
+
sdkLog("info", `[glasstrace] Heartbeat backing off for ${Math.round((delay + jitter) / 1e3)}s.`);
|
|
3691
|
+
}
|
|
3692
|
+
} else {
|
|
3693
|
+
backoffAttempts = 0;
|
|
3694
|
+
backoffUntil = 0;
|
|
3695
|
+
}
|
|
3696
|
+
if (initResult?.claimResult) {
|
|
3697
|
+
onClaimTransition(initResult.claimResult.newApiKey);
|
|
3698
|
+
}
|
|
3699
|
+
if (config.verbose) {
|
|
3700
|
+
sdkLog("info", "[glasstrace] Heartbeat completed.");
|
|
3701
|
+
}
|
|
3702
|
+
} finally {
|
|
3703
|
+
tickInProgress = false;
|
|
3704
|
+
}
|
|
3705
|
+
}
|
|
3706
|
+
function registerShutdownHandlers(config, anonKey, sdkVersion) {
|
|
3707
|
+
if (typeof process === "undefined" || typeof process.once !== "function") {
|
|
3708
|
+
return;
|
|
3709
|
+
}
|
|
3710
|
+
let shutdownFired = false;
|
|
3711
|
+
const handler = (signal) => {
|
|
3712
|
+
if (shutdownFired) return;
|
|
3713
|
+
shutdownFired = true;
|
|
3714
|
+
if (heartbeatTimer !== null) {
|
|
3715
|
+
clearInterval(heartbeatTimer);
|
|
3716
|
+
heartbeatTimer = null;
|
|
3717
|
+
}
|
|
3718
|
+
const healthReport = collectHealthReport(sdkVersion);
|
|
3719
|
+
void performInit(config, anonKey, sdkVersion, healthReport).catch(() => {
|
|
3720
|
+
}).finally(() => {
|
|
3721
|
+
removeShutdownHandlers();
|
|
3722
|
+
process.kill(process.pid, signal);
|
|
3723
|
+
});
|
|
3724
|
+
};
|
|
3725
|
+
_shutdownHandler2 = handler;
|
|
3726
|
+
process.once("SIGTERM", _shutdownHandler2);
|
|
3727
|
+
process.once("SIGINT", _shutdownHandler2);
|
|
3728
|
+
}
|
|
3729
|
+
function removeShutdownHandlers() {
|
|
3730
|
+
if (_shutdownHandler2 && typeof process !== "undefined") {
|
|
3731
|
+
process.removeListener("SIGTERM", _shutdownHandler2);
|
|
3732
|
+
process.removeListener("SIGINT", _shutdownHandler2);
|
|
3733
|
+
_shutdownHandler2 = null;
|
|
3734
|
+
}
|
|
3735
|
+
}
|
|
3736
|
+
|
|
3589
3737
|
// src/register.ts
|
|
3590
3738
|
var consoleCaptureInstalled = false;
|
|
3591
3739
|
var discoveryHandler = null;
|
|
@@ -3739,14 +3887,20 @@ async function backgroundInit(config, anonKeyForInit, generation) {
|
|
|
3739
3887
|
if (config.verbose) {
|
|
3740
3888
|
console.info("[glasstrace] Background init firing.");
|
|
3741
3889
|
}
|
|
3742
|
-
const healthReport = collectHealthReport("0.12.
|
|
3743
|
-
const initResult = await performInit(config, anonKeyForInit, "0.12.
|
|
3890
|
+
const healthReport = collectHealthReport("0.12.4");
|
|
3891
|
+
const initResult = await performInit(config, anonKeyForInit, "0.12.4", healthReport);
|
|
3744
3892
|
if (generation !== registrationGeneration) return;
|
|
3745
3893
|
if (initResult?.claimResult) {
|
|
3746
3894
|
setResolvedApiKey(initResult.claimResult.newApiKey);
|
|
3747
3895
|
notifyApiKeyResolved();
|
|
3748
3896
|
}
|
|
3749
3897
|
maybeInstallConsoleCapture();
|
|
3898
|
+
if (didLastInitSucceed()) {
|
|
3899
|
+
startHeartbeat(config, anonKeyForInit, "0.12.4", generation, (newApiKey) => {
|
|
3900
|
+
setResolvedApiKey(newApiKey);
|
|
3901
|
+
notifyApiKeyResolved();
|
|
3902
|
+
});
|
|
3903
|
+
}
|
|
3750
3904
|
}
|
|
3751
3905
|
function getDiscoveryHandler() {
|
|
3752
3906
|
return discoveryHandler;
|
|
@@ -3814,7 +3968,7 @@ async function handleSourceMapUpload(distDir) {
|
|
|
3814
3968
|
);
|
|
3815
3969
|
return;
|
|
3816
3970
|
}
|
|
3817
|
-
const { discoverSourceMapFiles: discoverSourceMapFiles2, computeBuildHash: computeBuildHash2, uploadSourceMaps: uploadSourceMaps2 } = await import("./source-map-uploader-
|
|
3971
|
+
const { discoverSourceMapFiles: discoverSourceMapFiles2, computeBuildHash: computeBuildHash2, uploadSourceMaps: uploadSourceMaps2 } = await import("./source-map-uploader-ZHD654EG.js");
|
|
3818
3972
|
const files = await discoverSourceMapFiles2(distDir);
|
|
3819
3973
|
if (files.length === 0) {
|
|
3820
3974
|
console.info("[glasstrace] No source map files found. Skipping upload.");
|