@glasstrace/sdk 0.13.5 → 0.14.0

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.js CHANGED
@@ -13,23 +13,23 @@ import {
13
13
  uploadSourceMaps,
14
14
  uploadSourceMapsAuto,
15
15
  uploadSourceMapsPresigned
16
- } from "./chunk-7MHQRVVW.js";
16
+ } from "./chunk-ERGEG4ZQ.js";
17
17
  import {
18
18
  buildImportGraph,
19
19
  discoverTestFiles,
20
20
  extractImports
21
- } from "./chunk-AMFO5UL4.js";
21
+ } from "./chunk-UPS5BGER.js";
22
22
  import {
23
23
  getOrCreateAnonKey,
24
24
  readAnonKey
25
- } from "./chunk-DF52INSK.js";
25
+ } from "./chunk-ECEN724Y.js";
26
26
  import {
27
27
  DEFAULT_CAPTURE_CONFIG,
28
28
  GLASSTRACE_ATTRIBUTE_NAMES,
29
29
  SdkCachedConfigSchema,
30
30
  SdkInitResponseSchema,
31
31
  SessionIdSchema
32
- } from "./chunk-UJ74MD4Y.js";
32
+ } from "./chunk-YMEXDDTA.js";
33
33
  import {
34
34
  DiagLogLevel,
35
35
  INVALID_SPAN_CONTEXT,
@@ -325,7 +325,6 @@ async function sendInitRequest(config, anonKey, sdkVersion, importGraph, healthR
325
325
  throw new Error("No API key available for init request");
326
326
  }
327
327
  const payload = {
328
- apiKey: effectiveKey,
329
328
  sdkVersion
330
329
  };
331
330
  if (config.apiKey && anonKey) {
@@ -562,7 +561,7 @@ init_esm_shims();
562
561
  var GlasstraceSpanProcessor = class {
563
562
  wrappedProcessor;
564
563
  /* eslint-disable @typescript-eslint/no-unused-vars -- backward compat signature */
565
- constructor(wrappedProcessor, _sessionManager, _apiKey, _getConfig, _environment) {
564
+ constructor(wrappedProcessor, _sessionManager2, _apiKey, _getConfig, _environment) {
566
565
  this.wrappedProcessor = wrappedProcessor;
567
566
  }
568
567
  onStart(span, parentContext) {
@@ -591,6 +590,7 @@ var GlasstraceExporter = class {
591
590
  environment;
592
591
  endpointUrl;
593
592
  createDelegateFn;
593
+ verbose;
594
594
  delegate = null;
595
595
  delegateKey = null;
596
596
  pendingBatches = [];
@@ -603,6 +603,8 @@ var GlasstraceExporter = class {
603
603
  this.environment = options.environment;
604
604
  this.endpointUrl = options.endpointUrl;
605
605
  this.createDelegateFn = options.createDelegate;
606
+ this.verbose = options.verbose ?? false;
607
+ this[/* @__PURE__ */ Symbol.for("glasstrace.exporter")] = true;
606
608
  }
607
609
  export(spans, resultCallback) {
608
610
  const currentKey = this.getApiKey();
@@ -700,6 +702,22 @@ var GlasstraceExporter = class {
700
702
  if (route) {
701
703
  extra[ATTR.ROUTE] = route;
702
704
  }
705
+ const rawUrl = attrs["http.url"] ?? attrs["url.full"] ?? attrs["http.target"];
706
+ const trpcUrl = typeof rawUrl === "string" ? rawUrl : void 0;
707
+ if (trpcUrl) {
708
+ const trpcMatch = trpcUrl.match(/\/api\/trpc\/([^/?#]+)/);
709
+ if (trpcMatch) {
710
+ let procedure;
711
+ try {
712
+ procedure = decodeURIComponent(trpcMatch[1]);
713
+ } catch {
714
+ procedure = trpcMatch[1];
715
+ }
716
+ if (procedure) {
717
+ extra[ATTR.TRPC_PROCEDURE] = procedure;
718
+ }
719
+ }
720
+ }
703
721
  const method = attrs["http.method"] ?? attrs["http.request.method"];
704
722
  if (method) {
705
723
  extra[ATTR.HTTP_METHOD] = method;
@@ -708,7 +726,17 @@ var GlasstraceExporter = class {
708
726
  if (statusCode !== void 0) {
709
727
  extra[ATTR.HTTP_STATUS_CODE] = statusCode;
710
728
  }
711
- if (method && span.status?.code === SpanStatusCode.ERROR) {
729
+ const isErrorByStatus = span.status?.code === SpanStatusCode.ERROR;
730
+ const isErrorByEvent = hasExceptionEvent(span);
731
+ const isErrorByAttrs = typeof attrs["exception.type"] === "string" || typeof attrs["exception.message"] === "string";
732
+ const statusNotExplicitlyOK = span.status?.code !== SpanStatusCode.OK;
733
+ if (this.verbose && method) {
734
+ sdkLog(
735
+ "info",
736
+ `[glasstrace] enrichSpan "${name}": status.code=${span.status?.code}, http.status_code=${statusCode}, isErrorByStatus=${isErrorByStatus}, isErrorByEvent=${isErrorByEvent}, isErrorByAttrs=${isErrorByAttrs}`
737
+ );
738
+ }
739
+ if (method && statusNotExplicitlyOK && (isErrorByStatus || isErrorByEvent || isErrorByAttrs)) {
712
740
  if (statusCode === void 0 || statusCode === 0 || statusCode === 200) {
713
741
  const httpErrorType = attrs["error.type"];
714
742
  if (typeof httpErrorType === "string") {
@@ -721,6 +749,12 @@ var GlasstraceExporter = class {
721
749
  } else {
722
750
  extra[ATTR.HTTP_STATUS_CODE] = 500;
723
751
  }
752
+ if (this.verbose) {
753
+ sdkLog(
754
+ "info",
755
+ `[glasstrace] enrichSpan "${name}": inferred status_code=${extra[ATTR.HTTP_STATUS_CODE]} (was ${statusCode}), error.type=${attrs["error.type"]}`
756
+ );
757
+ }
724
758
  }
725
759
  }
726
760
  if (span.startTime && span.endTime) {
@@ -731,19 +765,39 @@ var GlasstraceExporter = class {
731
765
  extra[ATTR.HTTP_DURATION_MS] = durationMs;
732
766
  }
733
767
  }
768
+ const eventDetails = statusNotExplicitlyOK ? getExceptionEventDetails(span) : { type: void 0, message: void 0 };
734
769
  const errorMessage = attrs["exception.message"];
735
770
  if (typeof errorMessage === "string") {
736
771
  extra[ATTR.ERROR_MESSAGE] = errorMessage;
772
+ } else if (eventDetails.message) {
773
+ extra[ATTR.ERROR_MESSAGE] = eventDetails.message;
737
774
  }
738
775
  const errorType = attrs["exception.type"];
739
776
  if (typeof errorType === "string") {
740
777
  extra[ATTR.ERROR_CODE] = errorType;
741
778
  extra[ATTR.ERROR_CATEGORY] = deriveErrorCategory(errorType);
779
+ } else if (eventDetails.type) {
780
+ extra[ATTR.ERROR_CODE] = eventDetails.type;
781
+ extra[ATTR.ERROR_CATEGORY] = deriveErrorCategory(eventDetails.type);
782
+ }
783
+ if (this.verbose && (extra[ATTR.ERROR_MESSAGE] || extra[ATTR.ERROR_CODE])) {
784
+ const msgSource = typeof errorMessage === "string" ? "attrs" : eventDetails.message ? "event" : "none";
785
+ const typeSource = typeof errorType === "string" ? "attrs" : eventDetails.type ? "event" : "none";
786
+ sdkLog(
787
+ "info",
788
+ `[glasstrace] enrichSpan "${name}": error.message source=${msgSource}, error.code source=${typeSource}`
789
+ );
742
790
  }
743
791
  const errorField = attrs["error.field"];
744
792
  if (typeof errorField === "string") {
745
793
  extra[ATTR.ERROR_FIELD] = errorField;
746
794
  }
795
+ if (this.getConfig().errorResponseBodies) {
796
+ const responseBody = attrs["glasstrace.internal.response_body"];
797
+ if (typeof responseBody === "string") {
798
+ extra[ATTR.ERROR_RESPONSE_BODY] = responseBody.slice(0, 500);
799
+ }
800
+ }
747
801
  const spanAny = span;
748
802
  const instrumentationName = spanAny.instrumentationScope?.name ?? spanAny.instrumentationLibrary?.name ?? "";
749
803
  const ormProvider = deriveOrmProvider(instrumentationName);
@@ -861,6 +915,21 @@ function createEnrichedSpan(span, extra) {
861
915
  }
862
916
  });
863
917
  }
918
+ function hasExceptionEvent(span) {
919
+ return span.events?.some((e) => e.name === "exception") ?? false;
920
+ }
921
+ function getExceptionEventDetails(span) {
922
+ const event = span.events?.find((e) => e.name === "exception");
923
+ if (!event?.attributes) {
924
+ return { type: void 0, message: void 0 };
925
+ }
926
+ const type = event.attributes["exception.type"];
927
+ const message = event.attributes["exception.message"];
928
+ return {
929
+ type: typeof type === "string" ? type : void 0,
930
+ message: typeof message === "string" ? message : void 0
931
+ };
932
+ }
864
933
  function deriveOrmProvider(instrumentationName) {
865
934
  const lower = instrumentationName.toLowerCase();
866
935
  if (lower.includes("prisma")) {
@@ -3707,10 +3776,458 @@ var BasicTracerProvider = class {
3707
3776
  }
3708
3777
  };
3709
3778
 
3779
+ // src/lifecycle.ts
3780
+ init_esm_shims();
3781
+ import { EventEmitter } from "events";
3782
+ var CoreState = {
3783
+ IDLE: "IDLE",
3784
+ REGISTERING: "REGISTERING",
3785
+ KEY_PENDING: "KEY_PENDING",
3786
+ KEY_RESOLVED: "KEY_RESOLVED",
3787
+ ACTIVE: "ACTIVE",
3788
+ ACTIVE_DEGRADED: "ACTIVE_DEGRADED",
3789
+ SHUTTING_DOWN: "SHUTTING_DOWN",
3790
+ SHUTDOWN: "SHUTDOWN",
3791
+ PRODUCTION_DISABLED: "PRODUCTION_DISABLED",
3792
+ REGISTRATION_FAILED: "REGISTRATION_FAILED"
3793
+ };
3794
+ var AuthState = {
3795
+ ANONYMOUS: "ANONYMOUS",
3796
+ AUTHENTICATED: "AUTHENTICATED",
3797
+ CLAIMING: "CLAIMING",
3798
+ CLAIMED: "CLAIMED"
3799
+ };
3800
+ var OtelState = {
3801
+ UNCONFIGURED: "UNCONFIGURED",
3802
+ CONFIGURING: "CONFIGURING",
3803
+ OWNS_PROVIDER: "OWNS_PROVIDER",
3804
+ AUTO_ATTACHED: "AUTO_ATTACHED",
3805
+ PROCESSOR_PRESENT: "PROCESSOR_PRESENT",
3806
+ COEXISTENCE_FAILED: "COEXISTENCE_FAILED"
3807
+ };
3808
+ var VALID_CORE_TRANSITIONS = {
3809
+ [CoreState.IDLE]: [CoreState.REGISTERING, CoreState.REGISTRATION_FAILED, CoreState.SHUTTING_DOWN],
3810
+ [CoreState.REGISTERING]: [
3811
+ CoreState.KEY_PENDING,
3812
+ CoreState.PRODUCTION_DISABLED,
3813
+ CoreState.REGISTRATION_FAILED,
3814
+ CoreState.SHUTTING_DOWN
3815
+ ],
3816
+ [CoreState.KEY_PENDING]: [
3817
+ CoreState.KEY_RESOLVED,
3818
+ CoreState.REGISTRATION_FAILED,
3819
+ CoreState.SHUTTING_DOWN
3820
+ ],
3821
+ [CoreState.KEY_RESOLVED]: [
3822
+ CoreState.ACTIVE,
3823
+ CoreState.ACTIVE_DEGRADED,
3824
+ CoreState.SHUTTING_DOWN
3825
+ ],
3826
+ [CoreState.ACTIVE]: [
3827
+ CoreState.ACTIVE_DEGRADED,
3828
+ CoreState.SHUTTING_DOWN
3829
+ ],
3830
+ [CoreState.ACTIVE_DEGRADED]: [
3831
+ CoreState.ACTIVE,
3832
+ CoreState.SHUTTING_DOWN
3833
+ ],
3834
+ [CoreState.SHUTTING_DOWN]: [CoreState.SHUTDOWN],
3835
+ [CoreState.SHUTDOWN]: [],
3836
+ [CoreState.PRODUCTION_DISABLED]: [],
3837
+ [CoreState.REGISTRATION_FAILED]: []
3838
+ };
3839
+ var VALID_AUTH_TRANSITIONS = {
3840
+ [AuthState.ANONYMOUS]: [AuthState.CLAIMING],
3841
+ [AuthState.AUTHENTICATED]: [AuthState.CLAIMING],
3842
+ [AuthState.CLAIMING]: [AuthState.CLAIMED],
3843
+ [AuthState.CLAIMED]: [AuthState.CLAIMING]
3844
+ };
3845
+ var VALID_OTEL_TRANSITIONS = {
3846
+ [OtelState.UNCONFIGURED]: [OtelState.CONFIGURING],
3847
+ [OtelState.CONFIGURING]: [
3848
+ OtelState.OWNS_PROVIDER,
3849
+ OtelState.AUTO_ATTACHED,
3850
+ OtelState.PROCESSOR_PRESENT,
3851
+ OtelState.COEXISTENCE_FAILED
3852
+ ],
3853
+ [OtelState.OWNS_PROVIDER]: [],
3854
+ [OtelState.AUTO_ATTACHED]: [],
3855
+ [OtelState.PROCESSOR_PRESENT]: [],
3856
+ [OtelState.COEXISTENCE_FAILED]: []
3857
+ };
3858
+ var _coreState = CoreState.IDLE;
3859
+ var _authState = AuthState.ANONYMOUS;
3860
+ var _otelState = OtelState.UNCONFIGURED;
3861
+ var _emitter = new EventEmitter();
3862
+ var _logger = null;
3863
+ var _initialized = false;
3864
+ var _initWarned = false;
3865
+ var _coreReadyEmitted = false;
3866
+ var _authInitialized = false;
3867
+ var _emitting = false;
3868
+ function initLifecycle(options) {
3869
+ if (_initialized) {
3870
+ options.logger("warn", "[glasstrace] initLifecycle() called twice \u2014 ignored.");
3871
+ return;
3872
+ }
3873
+ _logger = options.logger;
3874
+ _initialized = true;
3875
+ }
3876
+ function warnIfNotInitialized() {
3877
+ if (!_initialized && !_initWarned) {
3878
+ _initWarned = true;
3879
+ console.warn(
3880
+ "[glasstrace] Lifecycle state changed before initLifecycle() was called. Logger not available \u2014 errors will be silent."
3881
+ );
3882
+ }
3883
+ }
3884
+ function setCoreState(to) {
3885
+ warnIfNotInitialized();
3886
+ const from = _coreState;
3887
+ if (from === to) return;
3888
+ const valid = VALID_CORE_TRANSITIONS[from];
3889
+ if (!valid.includes(to)) {
3890
+ _logger?.(
3891
+ "warn",
3892
+ `[glasstrace] Invalid core state transition: ${from} \u2192 ${to}. Ignored.`
3893
+ );
3894
+ return;
3895
+ }
3896
+ _coreState = to;
3897
+ if (_emitting) return;
3898
+ _emitting = true;
3899
+ try {
3900
+ emitSafe("core:state_changed", { from, to });
3901
+ const current = _coreState;
3902
+ if (!_coreReadyEmitted && (current === CoreState.ACTIVE || current === CoreState.ACTIVE_DEGRADED)) {
3903
+ _coreReadyEmitted = true;
3904
+ emitSafe("core:ready", {});
3905
+ }
3906
+ if (current === CoreState.SHUTTING_DOWN) {
3907
+ emitSafe("core:shutdown_started", {});
3908
+ }
3909
+ if (current === CoreState.SHUTDOWN) {
3910
+ emitSafe("core:shutdown_completed", {});
3911
+ }
3912
+ } finally {
3913
+ _emitting = false;
3914
+ }
3915
+ }
3916
+ function initAuthState(state) {
3917
+ if (_authInitialized) {
3918
+ _logger?.(
3919
+ "warn",
3920
+ "[glasstrace] initAuthState() called after auth state already initialized. Ignored."
3921
+ );
3922
+ return;
3923
+ }
3924
+ _authInitialized = true;
3925
+ _authState = state;
3926
+ }
3927
+ function setAuthState(to) {
3928
+ warnIfNotInitialized();
3929
+ const from = _authState;
3930
+ if (from === to) return;
3931
+ const valid = VALID_AUTH_TRANSITIONS[from];
3932
+ if (!valid.includes(to)) {
3933
+ _logger?.(
3934
+ "warn",
3935
+ `[glasstrace] Invalid auth state transition: ${from} \u2192 ${to}. Ignored.`
3936
+ );
3937
+ return;
3938
+ }
3939
+ _authState = to;
3940
+ }
3941
+ function setOtelState(to) {
3942
+ warnIfNotInitialized();
3943
+ const from = _otelState;
3944
+ if (from === to) return;
3945
+ const valid = VALID_OTEL_TRANSITIONS[from];
3946
+ if (!valid.includes(to)) {
3947
+ _logger?.(
3948
+ "warn",
3949
+ `[glasstrace] Invalid OTel state transition: ${from} \u2192 ${to}. Ignored.`
3950
+ );
3951
+ return;
3952
+ }
3953
+ _otelState = to;
3954
+ }
3955
+ function getCoreState() {
3956
+ return _coreState;
3957
+ }
3958
+ function getSdkState() {
3959
+ return {
3960
+ core: _coreState,
3961
+ auth: _authState,
3962
+ otel: _otelState
3963
+ };
3964
+ }
3965
+ function onLifecycleEvent(event, listener) {
3966
+ _emitter.on(event, listener);
3967
+ }
3968
+ function emitLifecycleEvent(event, payload) {
3969
+ emitSafe(event, payload);
3970
+ }
3971
+ function offLifecycleEvent(event, listener) {
3972
+ _emitter.off(event, listener);
3973
+ }
3974
+ function emitSafe(event, payload) {
3975
+ const listeners = _emitter.listeners(event);
3976
+ for (const listener of listeners) {
3977
+ try {
3978
+ const result = listener(payload);
3979
+ if (result && typeof result.catch === "function") {
3980
+ result.catch((err) => {
3981
+ _logger?.(
3982
+ "error",
3983
+ `[glasstrace] Async error in lifecycle event listener for "${event}": ${err instanceof Error ? err.message : String(err)}`
3984
+ );
3985
+ });
3986
+ }
3987
+ } catch (err) {
3988
+ _logger?.(
3989
+ "error",
3990
+ `[glasstrace] Error in lifecycle event listener for "${event}": ${err instanceof Error ? err.message : String(err)}`
3991
+ );
3992
+ }
3993
+ }
3994
+ }
3995
+ function isReady() {
3996
+ return _coreState === CoreState.ACTIVE || _coreState === CoreState.ACTIVE_DEGRADED;
3997
+ }
3998
+ function waitForReady(timeoutMs = 3e4) {
3999
+ if (isReady()) {
4000
+ return Promise.resolve();
4001
+ }
4002
+ if (_coreState === CoreState.PRODUCTION_DISABLED || _coreState === CoreState.REGISTRATION_FAILED || _coreState === CoreState.SHUTTING_DOWN || _coreState === CoreState.SHUTDOWN) {
4003
+ return Promise.reject(new Error(`SDK is in terminal state: ${_coreState}`));
4004
+ }
4005
+ return new Promise((resolve2, reject) => {
4006
+ let settled = false;
4007
+ const listener = ({ to }) => {
4008
+ if (settled) return;
4009
+ if (to === CoreState.ACTIVE || to === CoreState.ACTIVE_DEGRADED) {
4010
+ settled = true;
4011
+ offLifecycleEvent("core:state_changed", listener);
4012
+ resolve2();
4013
+ } else if (to === CoreState.PRODUCTION_DISABLED || to === CoreState.REGISTRATION_FAILED || to === CoreState.SHUTTING_DOWN || to === CoreState.SHUTDOWN) {
4014
+ settled = true;
4015
+ offLifecycleEvent("core:state_changed", listener);
4016
+ reject(new Error(`SDK reached terminal state: ${to}`));
4017
+ }
4018
+ };
4019
+ onLifecycleEvent("core:state_changed", listener);
4020
+ if (timeoutMs > 0) {
4021
+ const timer = setTimeout(() => {
4022
+ if (settled) return;
4023
+ settled = true;
4024
+ offLifecycleEvent("core:state_changed", listener);
4025
+ reject(new Error(`waitForReady timed out after ${timeoutMs}ms (state: ${_coreState})`));
4026
+ }, timeoutMs);
4027
+ if (typeof timer === "object" && "unref" in timer) {
4028
+ timer.unref();
4029
+ }
4030
+ }
4031
+ });
4032
+ }
4033
+ function getStatus() {
4034
+ let mode;
4035
+ if (_coreState === CoreState.PRODUCTION_DISABLED) {
4036
+ mode = "disabled";
4037
+ } else if (_authState === AuthState.CLAIMING || _authState === AuthState.CLAIMED) {
4038
+ mode = "claiming";
4039
+ } else if (_authState === AuthState.AUTHENTICATED) {
4040
+ mode = "authenticated";
4041
+ } else {
4042
+ mode = "anonymous";
4043
+ }
4044
+ let tracing;
4045
+ if (_otelState === OtelState.COEXISTENCE_FAILED || _otelState === OtelState.UNCONFIGURED || _otelState === OtelState.CONFIGURING) {
4046
+ tracing = "not-configured";
4047
+ } else if (_coreState === CoreState.ACTIVE_DEGRADED) {
4048
+ tracing = "degraded";
4049
+ } else if (_otelState === OtelState.AUTO_ATTACHED || _otelState === OtelState.PROCESSOR_PRESENT) {
4050
+ tracing = "coexistence";
4051
+ } else {
4052
+ tracing = "active";
4053
+ }
4054
+ return {
4055
+ ready: isReady(),
4056
+ mode,
4057
+ tracing
4058
+ };
4059
+ }
4060
+ var _shutdownHooks = [];
4061
+ var _signalHandlersRegistered = false;
4062
+ var _signalHandler = null;
4063
+ var _beforeExitRegistered = false;
4064
+ var _beforeExitHandler = null;
4065
+ var _shutdownExecuted = false;
4066
+ function registerShutdownHook(hook) {
4067
+ _shutdownHooks.push(hook);
4068
+ _shutdownHooks.sort((a, b) => a.priority - b.priority);
4069
+ }
4070
+ async function executeShutdown(timeoutMs = 5e3) {
4071
+ if (_shutdownExecuted) return;
4072
+ _shutdownExecuted = true;
4073
+ setCoreState(CoreState.SHUTTING_DOWN);
4074
+ for (const hook of _shutdownHooks) {
4075
+ try {
4076
+ const hookPromise = hook.fn();
4077
+ hookPromise.catch(() => {
4078
+ });
4079
+ await Promise.race([
4080
+ hookPromise,
4081
+ new Promise((_, reject) => {
4082
+ const timer = setTimeout(() => reject(new Error(`Shutdown hook "${hook.name}" timed out`)), timeoutMs);
4083
+ if (typeof timer === "object" && "unref" in timer) {
4084
+ timer.unref();
4085
+ }
4086
+ })
4087
+ ]);
4088
+ } catch (err) {
4089
+ _logger?.(
4090
+ "warn",
4091
+ `[glasstrace] Shutdown hook "${hook.name}" failed: ${err instanceof Error ? err.message : String(err)}`
4092
+ );
4093
+ }
4094
+ }
4095
+ setCoreState(CoreState.SHUTDOWN);
4096
+ }
4097
+ function registerSignalHandlers() {
4098
+ if (_signalHandlersRegistered) return;
4099
+ if (typeof process === "undefined" || typeof process.once !== "function") return;
4100
+ _signalHandlersRegistered = true;
4101
+ const handler = (signal) => {
4102
+ void executeShutdown().finally(() => {
4103
+ if (_signalHandler) {
4104
+ process.removeListener("SIGTERM", _signalHandler);
4105
+ process.removeListener("SIGINT", _signalHandler);
4106
+ }
4107
+ process.kill(process.pid, signal);
4108
+ });
4109
+ };
4110
+ _signalHandler = handler;
4111
+ process.once("SIGTERM", handler);
4112
+ process.once("SIGINT", handler);
4113
+ }
4114
+ function registerBeforeExitTrigger() {
4115
+ if (_beforeExitRegistered) return;
4116
+ if (typeof process === "undefined" || typeof process.once !== "function") return;
4117
+ _beforeExitRegistered = true;
4118
+ const handler = () => {
4119
+ void executeShutdown();
4120
+ };
4121
+ _beforeExitHandler = handler;
4122
+ process.once("beforeExit", handler);
4123
+ }
4124
+
4125
+ // src/coexistence.ts
4126
+ init_esm_shims();
4127
+ function createGlasstraceSpanProcessor(options) {
4128
+ const config = resolveConfig(options);
4129
+ const exporterUrl = `${config.endpoint}/v1/traces`;
4130
+ const createOtlpExporter = (url, headers) => new OTLPTraceExporter({ url, headers });
4131
+ const exporter = new GlasstraceExporter({
4132
+ getApiKey: getResolvedApiKey,
4133
+ sessionManager: getSessionManager(),
4134
+ getConfig: () => getActiveConfig(),
4135
+ environment: config.environment,
4136
+ endpointUrl: exporterUrl,
4137
+ createDelegate: createOtlpExporter
4138
+ });
4139
+ registerExporterForKeyNotification(exporter);
4140
+ return new BatchSpanProcessor(exporter, {
4141
+ scheduledDelayMillis: 1e3
4142
+ });
4143
+ }
4144
+ function emitNudgeMessage() {
4145
+ const isSentry = detectSentry();
4146
+ if (isSentry) {
4147
+ sdkLog(
4148
+ "info",
4149
+ `[glasstrace] Detected existing OTel provider \u2014 auto-attached Glasstrace span processor.
4150
+ For a cleaner setup, add Glasstrace to your Sentry config:
4151
+
4152
+ import { createGlasstraceSpanProcessor } from '@glasstrace/sdk';
4153
+
4154
+ Sentry.init({
4155
+ dsn: '...',
4156
+ openTelemetrySpanProcessors: [createGlasstraceSpanProcessor()],
4157
+ });
4158
+
4159
+ This message will not appear once Glasstrace is added to your provider config.`
4160
+ );
4161
+ } else {
4162
+ sdkLog(
4163
+ "info",
4164
+ `[glasstrace] Detected existing OTel provider \u2014 auto-attached Glasstrace span processor.
4165
+ For a cleaner setup, add Glasstrace to your provider config:
4166
+
4167
+ import { createGlasstraceSpanProcessor } from '@glasstrace/sdk';
4168
+
4169
+ const provider = new BasicTracerProvider({
4170
+ spanProcessors: [
4171
+ // ... your existing processors,
4172
+ createGlasstraceSpanProcessor(),
4173
+ ],
4174
+ });
4175
+
4176
+ This message will not appear once Glasstrace is added to your provider config.`
4177
+ );
4178
+ }
4179
+ }
4180
+ function emitGuidanceMessage() {
4181
+ const isSentry = detectSentry();
4182
+ if (isSentry) {
4183
+ sdkLog(
4184
+ "warn",
4185
+ `[glasstrace] An existing OTel TracerProvider is registered but Glasstrace could not auto-attach its span processor.
4186
+ Add Glasstrace to your Sentry config:
4187
+
4188
+ import { createGlasstraceSpanProcessor } from '@glasstrace/sdk';
4189
+
4190
+ Sentry.init({
4191
+ dsn: '...',
4192
+ openTelemetrySpanProcessors: [createGlasstraceSpanProcessor()],
4193
+ });`
4194
+ );
4195
+ } else {
4196
+ sdkLog(
4197
+ "warn",
4198
+ `[glasstrace] An existing OTel TracerProvider is registered but Glasstrace could not auto-attach its span processor.
4199
+ Add Glasstrace to your provider configuration:
4200
+
4201
+ import { createGlasstraceSpanProcessor } from '@glasstrace/sdk';
4202
+
4203
+ const provider = new BasicTracerProvider({
4204
+ spanProcessors: [
4205
+ // ... your existing processors,
4206
+ createGlasstraceSpanProcessor(),
4207
+ ],
4208
+ });`
4209
+ );
4210
+ }
4211
+ }
4212
+ function detectSentry() {
4213
+ try {
4214
+ __require.resolve("@sentry/node");
4215
+ return true;
4216
+ } catch {
4217
+ try {
4218
+ __require.resolve("@sentry/nextjs");
4219
+ return true;
4220
+ } catch {
4221
+ return false;
4222
+ }
4223
+ }
4224
+ }
4225
+
3710
4226
  // src/otel-config.ts
3711
4227
  var _resolvedApiKey = API_KEY_PENDING;
3712
4228
  var _activeExporter = null;
3713
- var _shutdownHandler = null;
4229
+ var _additionalExporters = [];
4230
+ var _injectedProcessor = null;
3714
4231
  function setResolvedApiKey(key) {
3715
4232
  _resolvedApiKey = key;
3716
4233
  }
@@ -3719,6 +4236,12 @@ function getResolvedApiKey() {
3719
4236
  }
3720
4237
  function notifyApiKeyResolved() {
3721
4238
  _activeExporter?.notifyKeyResolved();
4239
+ for (const exporter of _additionalExporters) {
4240
+ exporter.notifyKeyResolved();
4241
+ }
4242
+ }
4243
+ function registerExporterForKeyNotification(exporter) {
4244
+ _additionalExporters.push(exporter);
3722
4245
  }
3723
4246
  async function tryImport(moduleId) {
3724
4247
  try {
@@ -3727,34 +4250,65 @@ async function tryImport(moduleId) {
3727
4250
  return null;
3728
4251
  }
3729
4252
  }
3730
- function registerShutdownHooks(provider) {
3731
- if (typeof process === "undefined" || typeof process.once !== "function") {
3732
- return;
3733
- }
3734
- if (_shutdownHandler) {
3735
- process.removeListener("SIGTERM", _shutdownHandler);
3736
- process.removeListener("SIGINT", _shutdownHandler);
4253
+ function tryInjectProcessor(tracerProvider, glasstraceExporter) {
4254
+ try {
4255
+ const proxy = tracerProvider;
4256
+ const delegate = typeof proxy.getDelegate === "function" ? proxy.getDelegate() : tracerProvider;
4257
+ const withAdd = delegate;
4258
+ if (typeof withAdd.addSpanProcessor === "function") {
4259
+ if (typeof withAdd.getActiveSpanProcessor === "function") {
4260
+ const active = withAdd.getActiveSpanProcessor();
4261
+ const brand = /* @__PURE__ */ Symbol.for("glasstrace.exporter");
4262
+ const processors = active?._spanProcessors;
4263
+ if (Array.isArray(processors) && processors.some((p) => {
4264
+ const exp = p._exporter;
4265
+ return exp?.[brand] === true;
4266
+ })) {
4267
+ return "already_present";
4268
+ }
4269
+ }
4270
+ const processor2 = new BatchSpanProcessor(glasstraceExporter, {
4271
+ scheduledDelayMillis: 1e3
4272
+ });
4273
+ withAdd.addSpanProcessor(processor2);
4274
+ _injectedProcessor = processor2;
4275
+ return "v1_public";
4276
+ }
4277
+ const provider = delegate;
4278
+ const multiProcessor = provider._activeSpanProcessor;
4279
+ if (!multiProcessor || !Array.isArray(multiProcessor._spanProcessors)) {
4280
+ return null;
4281
+ }
4282
+ const processor = new BatchSpanProcessor(glasstraceExporter, {
4283
+ scheduledDelayMillis: 1e3
4284
+ });
4285
+ multiProcessor._spanProcessors.push(processor);
4286
+ _injectedProcessor = processor;
4287
+ return "v2_private";
4288
+ } catch {
4289
+ return null;
3737
4290
  }
3738
- let shutdownCalled = false;
3739
- const shutdown = (signal) => {
3740
- if (shutdownCalled) return;
3741
- shutdownCalled = true;
3742
- void provider.shutdown().catch((err) => {
3743
- console.warn(
3744
- `[glasstrace] Error during OTel shutdown: ${err instanceof Error ? err.message : String(err)}`
3745
- );
3746
- }).finally(() => {
3747
- process.removeListener("SIGTERM", _shutdownHandler);
3748
- process.removeListener("SIGINT", _shutdownHandler);
3749
- process.kill(process.pid, signal);
4291
+ }
4292
+ function isGlasstraceProcessorPresent(tracerProvider) {
4293
+ try {
4294
+ const proxy = tracerProvider;
4295
+ const delegate = typeof proxy.getDelegate === "function" ? proxy.getDelegate() : tracerProvider;
4296
+ const provider = delegate;
4297
+ const processors = provider._activeSpanProcessor?._spanProcessors;
4298
+ if (!Array.isArray(processors)) {
4299
+ return false;
4300
+ }
4301
+ const brand = /* @__PURE__ */ Symbol.for("glasstrace.exporter");
4302
+ return processors.some((p) => {
4303
+ const exporter = p._exporter;
4304
+ return exporter?.[brand] === true;
3750
4305
  });
3751
- };
3752
- const handler = (signal) => shutdown(signal);
3753
- _shutdownHandler = handler;
3754
- process.once("SIGTERM", handler);
3755
- process.once("SIGINT", handler);
4306
+ } catch {
4307
+ return false;
4308
+ }
3756
4309
  }
3757
4310
  async function configureOtel(config, sessionManager) {
4311
+ setOtelState(OtelState.CONFIGURING);
3758
4312
  const exporterUrl = `${config.endpoint}/v1/traces`;
3759
4313
  const createOtlpExporter = (url, headers) => new OTLPTraceExporter({ url, headers });
3760
4314
  const glasstraceExporter = new GlasstraceExporter({
@@ -3763,32 +4317,91 @@ async function configureOtel(config, sessionManager) {
3763
4317
  getConfig: () => getActiveConfig(),
3764
4318
  environment: config.environment,
3765
4319
  endpointUrl: exporterUrl,
3766
- createDelegate: createOtlpExporter
4320
+ createDelegate: createOtlpExporter,
4321
+ verbose: config.verbose
3767
4322
  });
3768
4323
  _activeExporter = glasstraceExporter;
4324
+ await new Promise((resolve2) => {
4325
+ if (typeof setImmediate === "function") {
4326
+ setImmediate(resolve2);
4327
+ } else {
4328
+ setTimeout(resolve2, 0);
4329
+ }
4330
+ });
4331
+ const existingProvider = trace.getTracerProvider();
4332
+ const probeTracer = existingProvider.getTracer("glasstrace-probe");
4333
+ const anotherProviderRegistered = probeTracer.constructor.name !== "ProxyTracer";
4334
+ if (anotherProviderRegistered) {
4335
+ if (isGlasstraceProcessorPresent(existingProvider)) {
4336
+ if (config.verbose) {
4337
+ sdkLog("info", "[glasstrace] Existing provider detected \u2014 Glasstrace processor already present.");
4338
+ }
4339
+ _activeExporter = null;
4340
+ setOtelState(OtelState.PROCESSOR_PRESENT);
4341
+ emitLifecycleEvent("otel:configured", { state: OtelState.PROCESSOR_PRESENT, scenario: "B-clean" });
4342
+ return;
4343
+ }
4344
+ const injectionMethod = tryInjectProcessor(existingProvider, glasstraceExporter);
4345
+ if (injectionMethod === "already_present") {
4346
+ if (config.verbose) {
4347
+ sdkLog("info", "[glasstrace] Existing provider detected \u2014 Glasstrace processor already present (v1 check).");
4348
+ }
4349
+ _activeExporter = null;
4350
+ setOtelState(OtelState.PROCESSOR_PRESENT);
4351
+ emitLifecycleEvent("otel:configured", { state: OtelState.PROCESSOR_PRESENT, scenario: "B-clean" });
4352
+ return;
4353
+ }
4354
+ if (injectionMethod) {
4355
+ if (config.verbose) {
4356
+ sdkLog("info", "[glasstrace] Existing provider detected \u2014 auto-attaching Glasstrace processor.");
4357
+ }
4358
+ registerShutdownHook({
4359
+ name: "coexistence-flush",
4360
+ priority: 5,
4361
+ fn: async () => {
4362
+ if (_injectedProcessor) {
4363
+ await _injectedProcessor.forceFlush();
4364
+ }
4365
+ }
4366
+ });
4367
+ registerBeforeExitTrigger();
4368
+ const scenario = injectionMethod === "v1_public" ? "D1" : "B-auto";
4369
+ setOtelState(OtelState.AUTO_ATTACHED);
4370
+ emitLifecycleEvent("otel:configured", { state: OtelState.AUTO_ATTACHED, scenario });
4371
+ emitLifecycleEvent("otel:injection_succeeded", { method: injectionMethod });
4372
+ emitNudgeMessage();
4373
+ return;
4374
+ }
4375
+ if (config.verbose) {
4376
+ sdkLog("info", "[glasstrace] Existing provider detected \u2014 could not auto-attach.");
4377
+ }
4378
+ emitGuidanceMessage();
4379
+ _activeExporter = null;
4380
+ setOtelState(OtelState.COEXISTENCE_FAILED);
4381
+ emitLifecycleEvent("otel:configured", { state: OtelState.COEXISTENCE_FAILED, scenario: "C/F" });
4382
+ emitLifecycleEvent("otel:injection_failed", { reason: "provider internals inaccessible" });
4383
+ const coreState = getCoreState();
4384
+ if (coreState === CoreState.ACTIVE || coreState === CoreState.KEY_RESOLVED) {
4385
+ setCoreState(CoreState.ACTIVE_DEGRADED);
4386
+ }
4387
+ return;
4388
+ }
3769
4389
  const vercelOtel = await tryImport("@vercel/otel");
3770
4390
  if (vercelOtel && typeof vercelOtel.registerOTel === "function") {
3771
4391
  const otelConfig = {
3772
4392
  serviceName: "glasstrace-sdk",
3773
4393
  traceExporter: glasstraceExporter
3774
4394
  };
3775
- const prismaModule = await tryImport("@prisma/instrumentation");
3776
- if (prismaModule) {
3777
- const PrismaInstrumentation = prismaModule.PrismaInstrumentation;
4395
+ const prismaModule2 = await tryImport("@prisma/instrumentation");
4396
+ if (prismaModule2) {
4397
+ const PrismaInstrumentation = prismaModule2.PrismaInstrumentation;
3778
4398
  if (PrismaInstrumentation) {
3779
4399
  otelConfig.instrumentations = [new PrismaInstrumentation()];
3780
4400
  }
3781
4401
  }
3782
4402
  vercelOtel.registerOTel(otelConfig);
3783
- return;
3784
- }
3785
- const existingProvider = trace.getTracerProvider();
3786
- const probeTracer = existingProvider.getTracer("glasstrace-probe");
3787
- if (probeTracer.constructor.name !== "ProxyTracer") {
3788
- console.warn(
3789
- "[glasstrace] An existing OpenTelemetry TracerProvider is already registered. Glasstrace will not overwrite it. To use Glasstrace alongside another tracing tool, add GlasstraceExporter as an additional span processor on your existing provider."
3790
- );
3791
- _activeExporter = null;
4403
+ setOtelState(OtelState.OWNS_PROVIDER);
4404
+ emitLifecycleEvent("otel:configured", { state: OtelState.OWNS_PROVIDER, scenario: "E" });
3792
4405
  return;
3793
4406
  }
3794
4407
  if (config.verbose) {
@@ -3810,7 +4423,29 @@ async function configureOtel(config, sessionManager) {
3810
4423
  spanProcessors: [processor]
3811
4424
  });
3812
4425
  trace.setGlobalTracerProvider(provider);
3813
- registerShutdownHooks(provider);
4426
+ registerShutdownHook({
4427
+ name: "otel-provider-shutdown",
4428
+ priority: 0,
4429
+ fn: async () => {
4430
+ await provider.shutdown();
4431
+ }
4432
+ });
4433
+ registerSignalHandlers();
4434
+ registerBeforeExitTrigger();
4435
+ const prismaModule = await tryImport("@prisma/instrumentation");
4436
+ if (prismaModule) {
4437
+ const PrismaInstrumentation = prismaModule.PrismaInstrumentation;
4438
+ if (PrismaInstrumentation) {
4439
+ try {
4440
+ const inst = new PrismaInstrumentation();
4441
+ inst.setTracerProvider(provider);
4442
+ inst.enable();
4443
+ } catch {
4444
+ }
4445
+ }
4446
+ }
4447
+ setOtelState(OtelState.OWNS_PROVIDER);
4448
+ emitLifecycleEvent("otel:configured", { state: OtelState.OWNS_PROVIDER, scenario: "A" });
3814
4449
  }
3815
4450
 
3816
4451
  // src/context-manager.ts
@@ -3855,7 +4490,7 @@ var heartbeatGeneration = 0;
3855
4490
  var backoffAttempts = 0;
3856
4491
  var backoffUntil = 0;
3857
4492
  var tickInProgress = false;
3858
- var _shutdownHandler2 = null;
4493
+ var _shutdownHandler = null;
3859
4494
  function startHeartbeat(config, anonKey, sdkVersion, generation, onClaimTransition) {
3860
4495
  if (heartbeatTimer !== null) return;
3861
4496
  heartbeatGeneration = generation;
@@ -3908,7 +4543,7 @@ async function heartbeatTick(config, anonKey, sdkVersion, generation, onClaimTra
3908
4543
  backoffUntil = 0;
3909
4544
  }
3910
4545
  if (initResult?.claimResult) {
3911
- onClaimTransition(initResult.claimResult.newApiKey);
4546
+ onClaimTransition(initResult.claimResult.newApiKey, initResult.claimResult.accountId);
3912
4547
  }
3913
4548
  if (config.verbose) {
3914
4549
  sdkLog("info", "[glasstrace] Heartbeat completed.");
@@ -3936,39 +4571,124 @@ function registerShutdownHandlers(config, anonKey, sdkVersion) {
3936
4571
  process.kill(process.pid, signal);
3937
4572
  });
3938
4573
  };
3939
- _shutdownHandler2 = handler;
3940
- process.once("SIGTERM", _shutdownHandler2);
3941
- process.once("SIGINT", _shutdownHandler2);
4574
+ _shutdownHandler = handler;
4575
+ process.once("SIGTERM", _shutdownHandler);
4576
+ process.once("SIGINT", _shutdownHandler);
3942
4577
  }
3943
4578
  function removeShutdownHandlers() {
3944
- if (_shutdownHandler2 && typeof process !== "undefined") {
3945
- process.removeListener("SIGTERM", _shutdownHandler2);
3946
- process.removeListener("SIGINT", _shutdownHandler2);
3947
- _shutdownHandler2 = null;
4579
+ if (_shutdownHandler && typeof process !== "undefined") {
4580
+ process.removeListener("SIGTERM", _shutdownHandler);
4581
+ process.removeListener("SIGINT", _shutdownHandler);
4582
+ _shutdownHandler = null;
4583
+ }
4584
+ }
4585
+
4586
+ // src/runtime-state.ts
4587
+ init_esm_shims();
4588
+ import { writeFileSync, renameSync, mkdirSync } from "fs";
4589
+ import { join } from "path";
4590
+ var _projectRoot = null;
4591
+ var _sdkVersion = "unknown";
4592
+ var _lastScenario;
4593
+ var _debounceTimer = null;
4594
+ var _started = false;
4595
+ function startRuntimeStateWriter(options) {
4596
+ if (_started) return;
4597
+ _started = true;
4598
+ _projectRoot = options.projectRoot;
4599
+ _sdkVersion = options.sdkVersion;
4600
+ onLifecycleEvent("core:state_changed", ({ to }) => {
4601
+ if (to === CoreState.SHUTDOWN) {
4602
+ writeStateNow();
4603
+ } else {
4604
+ debouncedWrite();
4605
+ }
4606
+ });
4607
+ onLifecycleEvent("otel:configured", ({ scenario }) => {
4608
+ _lastScenario = scenario;
4609
+ debouncedWrite();
4610
+ });
4611
+ onLifecycleEvent("auth:key_resolved", () => debouncedWrite());
4612
+ onLifecycleEvent("auth:claim_started", () => debouncedWrite());
4613
+ onLifecycleEvent("auth:claim_completed", () => debouncedWrite());
4614
+ writeStateNow();
4615
+ }
4616
+ function debouncedWrite() {
4617
+ if (_debounceTimer) return;
4618
+ _debounceTimer = setTimeout(() => {
4619
+ _debounceTimer = null;
4620
+ writeStateNow();
4621
+ }, 1e3);
4622
+ if (typeof _debounceTimer === "object" && "unref" in _debounceTimer) {
4623
+ _debounceTimer.unref();
4624
+ }
4625
+ }
4626
+ function writeStateNow() {
4627
+ if (!_projectRoot) return;
4628
+ try {
4629
+ const state = getSdkState();
4630
+ const runtimeState = {
4631
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
4632
+ pid: process.pid,
4633
+ sdkVersion: _sdkVersion,
4634
+ core: { state: state.core },
4635
+ auth: { state: state.auth },
4636
+ otel: { state: state.otel, scenario: _lastScenario }
4637
+ };
4638
+ const dir = join(_projectRoot, ".glasstrace");
4639
+ const filePath = join(dir, "runtime-state.json");
4640
+ const tmpPath = join(dir, "runtime-state.json.tmp");
4641
+ mkdirSync(dir, { recursive: true, mode: 448 });
4642
+ writeFileSync(tmpPath, JSON.stringify(runtimeState, null, 2) + "\n", {
4643
+ mode: 384
4644
+ });
4645
+ renameSync(tmpPath, filePath);
4646
+ } catch (err) {
4647
+ sdkLog(
4648
+ "warn",
4649
+ `[glasstrace] Failed to write runtime state: ${err instanceof Error ? err.message : String(err)}`
4650
+ );
3948
4651
  }
3949
4652
  }
3950
4653
 
3951
4654
  // src/register.ts
4655
+ function maskKey(key) {
4656
+ if (key.length <= 12) return key.slice(0, 4) + "...";
4657
+ return key.slice(0, 8) + "..." + key.slice(-4);
4658
+ }
3952
4659
  var consoleCaptureInstalled = false;
3953
4660
  var discoveryHandler = null;
3954
- var isRegistered = false;
3955
4661
  var registrationGeneration = 0;
4662
+ var _sessionManager = null;
4663
+ function getSessionManager() {
4664
+ if (!_sessionManager) {
4665
+ _sessionManager = new SessionManager();
4666
+ }
4667
+ return _sessionManager;
4668
+ }
3956
4669
  function registerGlasstrace(options) {
3957
4670
  try {
3958
- if (isRegistered) {
4671
+ if (getCoreState() !== CoreState.IDLE) {
3959
4672
  return;
3960
4673
  }
4674
+ initLifecycle({ logger: sdkLog });
3961
4675
  if (typeof process === "undefined" || typeof process.versions?.node !== "string") {
3962
4676
  console.warn(
3963
4677
  "[glasstrace] SDK requires a Node.js runtime. Edge Runtime, browser, and Deno without Node compat are not supported. Glasstrace is disabled in this environment."
3964
4678
  );
3965
4679
  return;
3966
4680
  }
4681
+ setCoreState(CoreState.REGISTERING);
4682
+ startRuntimeStateWriter({
4683
+ projectRoot: process.cwd(),
4684
+ sdkVersion: "0.14.0"
4685
+ });
3967
4686
  const config = resolveConfig(options);
3968
4687
  if (config.verbose) {
3969
4688
  console.info("[glasstrace] Config resolved.");
3970
4689
  }
3971
4690
  if (isProductionDisabled(config)) {
4691
+ setCoreState(CoreState.PRODUCTION_DISABLED);
3972
4692
  console.warn(
3973
4693
  "[glasstrace] Disabled in production. Set GLASSTRACE_FORCE_ENABLE=true to override."
3974
4694
  );
@@ -3979,8 +4699,13 @@ function registerGlasstrace(options) {
3979
4699
  }
3980
4700
  const anonymous = isAnonymousMode(config);
3981
4701
  let effectiveKey = config.apiKey;
4702
+ initAuthState(anonymous ? AuthState.ANONYMOUS : AuthState.AUTHENTICATED);
3982
4703
  if (effectiveKey) {
3983
4704
  setResolvedApiKey(effectiveKey);
4705
+ emitLifecycleEvent("auth:key_resolved", {
4706
+ key: maskKey(effectiveKey),
4707
+ mode: anonymous ? "anonymous" : "dev"
4708
+ });
3984
4709
  }
3985
4710
  if (config.verbose) {
3986
4711
  console.info(
@@ -3996,11 +4721,11 @@ function registerGlasstrace(options) {
3996
4721
  `[glasstrace] Cached config ${cachedInitResponse ? "loaded and applied" : "not found"}.`
3997
4722
  );
3998
4723
  }
3999
- const sessionManager = new SessionManager();
4724
+ const sessionManager = getSessionManager();
4000
4725
  if (config.verbose) {
4001
4726
  console.info("[glasstrace] SessionManager created.");
4002
4727
  }
4003
- isRegistered = true;
4728
+ setCoreState(CoreState.KEY_PENDING);
4004
4729
  const currentGeneration = registrationGeneration;
4005
4730
  const existingProbe = trace.getTracerProvider().getTracer("glasstrace-probe");
4006
4731
  const anotherProviderRegistered = existingProbe.constructor.name !== "ProxyTracer";
@@ -4053,6 +4778,7 @@ function registerGlasstrace(options) {
4053
4778
  resolvedAnonKey = anonKey;
4054
4779
  setResolvedApiKey(anonKey);
4055
4780
  notifyApiKeyResolved();
4781
+ emitLifecycleEvent("auth:key_resolved", { key: maskKey(anonKey), mode: "anonymous" });
4056
4782
  effectiveKey = anonKey;
4057
4783
  if (currentGeneration !== registrationGeneration) return;
4058
4784
  discoveryHandler = createDiscoveryHandler(
@@ -4074,6 +4800,7 @@ function registerGlasstrace(options) {
4074
4800
  const anonKey = await getOrCreateAnonKey();
4075
4801
  setResolvedApiKey(anonKey);
4076
4802
  notifyApiKeyResolved();
4803
+ emitLifecycleEvent("auth:key_resolved", { key: maskKey(anonKey), mode: "anonymous" });
4077
4804
  effectiveKey = anonKey;
4078
4805
  if (currentGeneration !== registrationGeneration) return;
4079
4806
  await backgroundInit(config, anonKey, currentGeneration);
@@ -4106,6 +4833,7 @@ function registerGlasstrace(options) {
4106
4833
  console.info("[glasstrace] Import graph building skipped.");
4107
4834
  }
4108
4835
  } catch (err) {
4836
+ setCoreState(CoreState.REGISTRATION_FAILED);
4109
4837
  console.warn(
4110
4838
  `[glasstrace] Registration failed: ${err instanceof Error ? err.message : String(err)}`
4111
4839
  );
@@ -4115,18 +4843,37 @@ async function backgroundInit(config, anonKeyForInit, generation) {
4115
4843
  if (config.verbose) {
4116
4844
  console.info("[glasstrace] Background init firing.");
4117
4845
  }
4118
- const healthReport = collectHealthReport("0.13.5");
4119
- const initResult = await performInit(config, anonKeyForInit, "0.13.5", healthReport);
4846
+ const healthReport = collectHealthReport("0.14.0");
4847
+ const initResult = await performInit(config, anonKeyForInit, "0.14.0", healthReport);
4120
4848
  if (generation !== registrationGeneration) return;
4849
+ const currentState = getCoreState();
4850
+ if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
4851
+ return;
4852
+ }
4853
+ if (currentState === CoreState.KEY_PENDING) {
4854
+ setCoreState(CoreState.KEY_RESOLVED);
4855
+ }
4856
+ if (getCoreState() === CoreState.KEY_RESOLVED) {
4857
+ setCoreState(didLastInitSucceed() ? CoreState.ACTIVE : CoreState.ACTIVE_DEGRADED);
4858
+ }
4121
4859
  if (initResult?.claimResult) {
4122
- setResolvedApiKey(initResult.claimResult.newApiKey);
4860
+ const { newApiKey, accountId } = initResult.claimResult;
4861
+ setAuthState(AuthState.CLAIMING);
4862
+ emitLifecycleEvent("auth:claim_started", { accountId });
4863
+ setResolvedApiKey(newApiKey);
4123
4864
  notifyApiKeyResolved();
4865
+ setAuthState(AuthState.CLAIMED);
4866
+ emitLifecycleEvent("auth:claim_completed", { newKey: maskKey(newApiKey), accountId });
4124
4867
  }
4125
4868
  maybeInstallConsoleCapture();
4126
4869
  if (didLastInitSucceed()) {
4127
- startHeartbeat(config, anonKeyForInit, "0.13.5", generation, (newApiKey) => {
4870
+ startHeartbeat(config, anonKeyForInit, "0.14.0", generation, (newApiKey, accountId) => {
4871
+ setAuthState(AuthState.CLAIMING);
4872
+ emitLifecycleEvent("auth:claim_started", { accountId });
4128
4873
  setResolvedApiKey(newApiKey);
4129
4874
  notifyApiKeyResolved();
4875
+ setAuthState(AuthState.CLAIMED);
4876
+ emitLifecycleEvent("auth:claim_completed", { newKey: maskKey(newApiKey), accountId });
4130
4877
  });
4131
4878
  }
4132
4879
  }
@@ -4197,7 +4944,7 @@ async function handleSourceMapUpload(distDir) {
4197
4944
  );
4198
4945
  return;
4199
4946
  }
4200
- const { discoverSourceMapFiles: discoverSourceMapFiles2, computeBuildHash: computeBuildHash2, uploadSourceMaps: uploadSourceMaps2 } = await import("./source-map-uploader-EWA2XQI4.js");
4947
+ const { discoverSourceMapFiles: discoverSourceMapFiles2, computeBuildHash: computeBuildHash2, uploadSourceMaps: uploadSourceMaps2 } = await import("./source-map-uploader-W6VPGY26.js");
4201
4948
  const files = await discoverSourceMapFiles2(distDir);
4202
4949
  if (files.length === 0) {
4203
4950
  console.info("[glasstrace] No source map files found. Skipping upload.");
@@ -4248,6 +4995,7 @@ export {
4248
4995
  collectSourceMaps,
4249
4996
  computeBuildHash,
4250
4997
  createDiscoveryHandler,
4998
+ createGlasstraceSpanProcessor,
4251
4999
  deriveSessionId,
4252
5000
  discoverSourceMapFiles,
4253
5001
  discoverTestFiles,
@@ -4258,8 +5006,10 @@ export {
4258
5006
  getLinkedAccountId,
4259
5007
  getOrCreateAnonKey,
4260
5008
  getOrigin,
5009
+ getStatus,
4261
5010
  isAnonymousMode,
4262
5011
  isProductionDisabled,
5012
+ isReady,
4263
5013
  loadCachedConfig,
4264
5014
  performInit,
4265
5015
  readAnonKey,
@@ -4271,6 +5021,7 @@ export {
4271
5021
  uploadSourceMaps,
4272
5022
  uploadSourceMapsAuto,
4273
5023
  uploadSourceMapsPresigned,
5024
+ waitForReady,
4274
5025
  withGlasstraceConfig
4275
5026
  };
4276
5027
  //# sourceMappingURL=index.js.map