@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.cjs CHANGED
@@ -14601,7 +14601,8 @@ var init_dist = __esm({
14601
14601
  envVarValues: external_exports.boolean(),
14602
14602
  fullConsoleOutput: external_exports.boolean(),
14603
14603
  importGraph: external_exports.boolean(),
14604
- consoleErrors: external_exports.boolean().optional().default(false)
14604
+ consoleErrors: external_exports.boolean().optional().default(false),
14605
+ errorResponseBodies: external_exports.boolean().optional().default(false)
14605
14606
  });
14606
14607
  SdkCachedConfigSchema = external_exports.object({
14607
14608
  response: external_exports.record(external_exports.string(), external_exports.unknown()),
@@ -14732,6 +14733,8 @@ var init_dist = __esm({
14732
14733
  SOURCE_FILE: "glasstrace.source.file",
14733
14734
  SOURCE_LINE: "glasstrace.source.line",
14734
14735
  SOURCE_MAPPED: "glasstrace.source.mapped",
14736
+ TRPC_PROCEDURE: "glasstrace.trpc.procedure",
14737
+ ERROR_RESPONSE_BODY: "glasstrace.error.response_body",
14735
14738
  // Client-side attributes
14736
14739
  PLATFORM: "glasstrace.platform",
14737
14740
  GESTURE_TYPE: "glasstrace.gesture.type",
@@ -14746,7 +14749,8 @@ var init_dist = __esm({
14746
14749
  envVarValues: false,
14747
14750
  fullConsoleOutput: false,
14748
14751
  importGraph: false,
14749
- consoleErrors: false
14752
+ consoleErrors: false,
14753
+ errorResponseBodies: false
14750
14754
  };
14751
14755
  }
14752
14756
  });
@@ -16614,7 +16618,6 @@ async function uploadSourceMaps(apiKey, endpoint, buildHash, maps) {
16614
16618
  }
16615
16619
  }
16616
16620
  const body = {
16617
- apiKey,
16618
16621
  buildHash,
16619
16622
  files
16620
16623
  };
@@ -16836,6 +16839,7 @@ __export(src_exports, {
16836
16839
  collectSourceMaps: () => collectSourceMaps,
16837
16840
  computeBuildHash: () => computeBuildHash,
16838
16841
  createDiscoveryHandler: () => createDiscoveryHandler,
16842
+ createGlasstraceSpanProcessor: () => createGlasstraceSpanProcessor,
16839
16843
  deriveSessionId: () => deriveSessionId,
16840
16844
  discoverSourceMapFiles: () => discoverSourceMapFiles,
16841
16845
  discoverTestFiles: () => discoverTestFiles,
@@ -16846,8 +16850,10 @@ __export(src_exports, {
16846
16850
  getLinkedAccountId: () => getLinkedAccountId,
16847
16851
  getOrCreateAnonKey: () => getOrCreateAnonKey,
16848
16852
  getOrigin: () => getOrigin,
16853
+ getStatus: () => getStatus,
16849
16854
  isAnonymousMode: () => isAnonymousMode,
16850
16855
  isProductionDisabled: () => isProductionDisabled,
16856
+ isReady: () => isReady,
16851
16857
  loadCachedConfig: () => loadCachedConfig,
16852
16858
  performInit: () => performInit,
16853
16859
  readAnonKey: () => readAnonKey,
@@ -16859,6 +16865,7 @@ __export(src_exports, {
16859
16865
  uploadSourceMaps: () => uploadSourceMaps,
16860
16866
  uploadSourceMapsAuto: () => uploadSourceMapsAuto,
16861
16867
  uploadSourceMapsPresigned: () => uploadSourceMapsPresigned,
16868
+ waitForReady: () => waitForReady,
16862
16869
  withGlasstraceConfig: () => withGlasstraceConfig
16863
16870
  });
16864
16871
  module.exports = __toCommonJS(src_exports);
@@ -17229,7 +17236,6 @@ async function sendInitRequest(config2, anonKey, sdkVersion, importGraph, health
17229
17236
  throw new Error("No API key available for init request");
17230
17237
  }
17231
17238
  const payload = {
17232
- apiKey: effectiveKey,
17233
17239
  sdkVersion
17234
17240
  };
17235
17241
  if (config2.apiKey && anonKey) {
@@ -17466,7 +17472,7 @@ init_cjs_shims();
17466
17472
  var GlasstraceSpanProcessor = class {
17467
17473
  wrappedProcessor;
17468
17474
  /* eslint-disable @typescript-eslint/no-unused-vars -- backward compat signature */
17469
- constructor(wrappedProcessor, _sessionManager, _apiKey, _getConfig, _environment) {
17475
+ constructor(wrappedProcessor, _sessionManager2, _apiKey, _getConfig, _environment) {
17470
17476
  this.wrappedProcessor = wrappedProcessor;
17471
17477
  }
17472
17478
  onStart(span, parentContext) {
@@ -17498,6 +17504,7 @@ var GlasstraceExporter = class {
17498
17504
  environment;
17499
17505
  endpointUrl;
17500
17506
  createDelegateFn;
17507
+ verbose;
17501
17508
  delegate = null;
17502
17509
  delegateKey = null;
17503
17510
  pendingBatches = [];
@@ -17510,6 +17517,8 @@ var GlasstraceExporter = class {
17510
17517
  this.environment = options.environment;
17511
17518
  this.endpointUrl = options.endpointUrl;
17512
17519
  this.createDelegateFn = options.createDelegate;
17520
+ this.verbose = options.verbose ?? false;
17521
+ this[/* @__PURE__ */ Symbol.for("glasstrace.exporter")] = true;
17513
17522
  }
17514
17523
  export(spans, resultCallback) {
17515
17524
  const currentKey = this.getApiKey();
@@ -17607,6 +17616,22 @@ var GlasstraceExporter = class {
17607
17616
  if (route) {
17608
17617
  extra[ATTR.ROUTE] = route;
17609
17618
  }
17619
+ const rawUrl = attrs["http.url"] ?? attrs["url.full"] ?? attrs["http.target"];
17620
+ const trpcUrl = typeof rawUrl === "string" ? rawUrl : void 0;
17621
+ if (trpcUrl) {
17622
+ const trpcMatch = trpcUrl.match(/\/api\/trpc\/([^/?#]+)/);
17623
+ if (trpcMatch) {
17624
+ let procedure;
17625
+ try {
17626
+ procedure = decodeURIComponent(trpcMatch[1]);
17627
+ } catch {
17628
+ procedure = trpcMatch[1];
17629
+ }
17630
+ if (procedure) {
17631
+ extra[ATTR.TRPC_PROCEDURE] = procedure;
17632
+ }
17633
+ }
17634
+ }
17610
17635
  const method = attrs["http.method"] ?? attrs["http.request.method"];
17611
17636
  if (method) {
17612
17637
  extra[ATTR.HTTP_METHOD] = method;
@@ -17615,7 +17640,17 @@ var GlasstraceExporter = class {
17615
17640
  if (statusCode !== void 0) {
17616
17641
  extra[ATTR.HTTP_STATUS_CODE] = statusCode;
17617
17642
  }
17618
- if (method && span.status?.code === SpanStatusCode.ERROR) {
17643
+ const isErrorByStatus = span.status?.code === SpanStatusCode.ERROR;
17644
+ const isErrorByEvent = hasExceptionEvent(span);
17645
+ const isErrorByAttrs = typeof attrs["exception.type"] === "string" || typeof attrs["exception.message"] === "string";
17646
+ const statusNotExplicitlyOK = span.status?.code !== SpanStatusCode.OK;
17647
+ if (this.verbose && method) {
17648
+ sdkLog(
17649
+ "info",
17650
+ `[glasstrace] enrichSpan "${name}": status.code=${span.status?.code}, http.status_code=${statusCode}, isErrorByStatus=${isErrorByStatus}, isErrorByEvent=${isErrorByEvent}, isErrorByAttrs=${isErrorByAttrs}`
17651
+ );
17652
+ }
17653
+ if (method && statusNotExplicitlyOK && (isErrorByStatus || isErrorByEvent || isErrorByAttrs)) {
17619
17654
  if (statusCode === void 0 || statusCode === 0 || statusCode === 200) {
17620
17655
  const httpErrorType = attrs["error.type"];
17621
17656
  if (typeof httpErrorType === "string") {
@@ -17628,6 +17663,12 @@ var GlasstraceExporter = class {
17628
17663
  } else {
17629
17664
  extra[ATTR.HTTP_STATUS_CODE] = 500;
17630
17665
  }
17666
+ if (this.verbose) {
17667
+ sdkLog(
17668
+ "info",
17669
+ `[glasstrace] enrichSpan "${name}": inferred status_code=${extra[ATTR.HTTP_STATUS_CODE]} (was ${statusCode}), error.type=${attrs["error.type"]}`
17670
+ );
17671
+ }
17631
17672
  }
17632
17673
  }
17633
17674
  if (span.startTime && span.endTime) {
@@ -17638,19 +17679,39 @@ var GlasstraceExporter = class {
17638
17679
  extra[ATTR.HTTP_DURATION_MS] = durationMs;
17639
17680
  }
17640
17681
  }
17682
+ const eventDetails = statusNotExplicitlyOK ? getExceptionEventDetails(span) : { type: void 0, message: void 0 };
17641
17683
  const errorMessage = attrs["exception.message"];
17642
17684
  if (typeof errorMessage === "string") {
17643
17685
  extra[ATTR.ERROR_MESSAGE] = errorMessage;
17686
+ } else if (eventDetails.message) {
17687
+ extra[ATTR.ERROR_MESSAGE] = eventDetails.message;
17644
17688
  }
17645
17689
  const errorType = attrs["exception.type"];
17646
17690
  if (typeof errorType === "string") {
17647
17691
  extra[ATTR.ERROR_CODE] = errorType;
17648
17692
  extra[ATTR.ERROR_CATEGORY] = deriveErrorCategory(errorType);
17693
+ } else if (eventDetails.type) {
17694
+ extra[ATTR.ERROR_CODE] = eventDetails.type;
17695
+ extra[ATTR.ERROR_CATEGORY] = deriveErrorCategory(eventDetails.type);
17696
+ }
17697
+ if (this.verbose && (extra[ATTR.ERROR_MESSAGE] || extra[ATTR.ERROR_CODE])) {
17698
+ const msgSource = typeof errorMessage === "string" ? "attrs" : eventDetails.message ? "event" : "none";
17699
+ const typeSource = typeof errorType === "string" ? "attrs" : eventDetails.type ? "event" : "none";
17700
+ sdkLog(
17701
+ "info",
17702
+ `[glasstrace] enrichSpan "${name}": error.message source=${msgSource}, error.code source=${typeSource}`
17703
+ );
17649
17704
  }
17650
17705
  const errorField = attrs["error.field"];
17651
17706
  if (typeof errorField === "string") {
17652
17707
  extra[ATTR.ERROR_FIELD] = errorField;
17653
17708
  }
17709
+ if (this.getConfig().errorResponseBodies) {
17710
+ const responseBody = attrs["glasstrace.internal.response_body"];
17711
+ if (typeof responseBody === "string") {
17712
+ extra[ATTR.ERROR_RESPONSE_BODY] = responseBody.slice(0, 500);
17713
+ }
17714
+ }
17654
17715
  const spanAny = span;
17655
17716
  const instrumentationName = spanAny.instrumentationScope?.name ?? spanAny.instrumentationLibrary?.name ?? "";
17656
17717
  const ormProvider = deriveOrmProvider(instrumentationName);
@@ -17768,6 +17829,21 @@ function createEnrichedSpan(span, extra) {
17768
17829
  }
17769
17830
  });
17770
17831
  }
17832
+ function hasExceptionEvent(span) {
17833
+ return span.events?.some((e) => e.name === "exception") ?? false;
17834
+ }
17835
+ function getExceptionEventDetails(span) {
17836
+ const event = span.events?.find((e) => e.name === "exception");
17837
+ if (!event?.attributes) {
17838
+ return { type: void 0, message: void 0 };
17839
+ }
17840
+ const type = event.attributes["exception.type"];
17841
+ const message = event.attributes["exception.message"];
17842
+ return {
17843
+ type: typeof type === "string" ? type : void 0,
17844
+ message: typeof message === "string" ? message : void 0
17845
+ };
17846
+ }
17771
17847
  function deriveOrmProvider(instrumentationName) {
17772
17848
  const lower = instrumentationName.toLowerCase();
17773
17849
  if (lower.includes("prisma")) {
@@ -20637,9 +20713,461 @@ var BasicTracerProvider = class {
20637
20713
  // src/otel-config.ts
20638
20714
  init_esm();
20639
20715
  init_console_capture();
20716
+
20717
+ // src/lifecycle.ts
20718
+ init_cjs_shims();
20719
+ var import_node_events = require("events");
20720
+ var CoreState = {
20721
+ IDLE: "IDLE",
20722
+ REGISTERING: "REGISTERING",
20723
+ KEY_PENDING: "KEY_PENDING",
20724
+ KEY_RESOLVED: "KEY_RESOLVED",
20725
+ ACTIVE: "ACTIVE",
20726
+ ACTIVE_DEGRADED: "ACTIVE_DEGRADED",
20727
+ SHUTTING_DOWN: "SHUTTING_DOWN",
20728
+ SHUTDOWN: "SHUTDOWN",
20729
+ PRODUCTION_DISABLED: "PRODUCTION_DISABLED",
20730
+ REGISTRATION_FAILED: "REGISTRATION_FAILED"
20731
+ };
20732
+ var AuthState = {
20733
+ ANONYMOUS: "ANONYMOUS",
20734
+ AUTHENTICATED: "AUTHENTICATED",
20735
+ CLAIMING: "CLAIMING",
20736
+ CLAIMED: "CLAIMED"
20737
+ };
20738
+ var OtelState = {
20739
+ UNCONFIGURED: "UNCONFIGURED",
20740
+ CONFIGURING: "CONFIGURING",
20741
+ OWNS_PROVIDER: "OWNS_PROVIDER",
20742
+ AUTO_ATTACHED: "AUTO_ATTACHED",
20743
+ PROCESSOR_PRESENT: "PROCESSOR_PRESENT",
20744
+ COEXISTENCE_FAILED: "COEXISTENCE_FAILED"
20745
+ };
20746
+ var VALID_CORE_TRANSITIONS = {
20747
+ [CoreState.IDLE]: [CoreState.REGISTERING, CoreState.REGISTRATION_FAILED, CoreState.SHUTTING_DOWN],
20748
+ [CoreState.REGISTERING]: [
20749
+ CoreState.KEY_PENDING,
20750
+ CoreState.PRODUCTION_DISABLED,
20751
+ CoreState.REGISTRATION_FAILED,
20752
+ CoreState.SHUTTING_DOWN
20753
+ ],
20754
+ [CoreState.KEY_PENDING]: [
20755
+ CoreState.KEY_RESOLVED,
20756
+ CoreState.REGISTRATION_FAILED,
20757
+ CoreState.SHUTTING_DOWN
20758
+ ],
20759
+ [CoreState.KEY_RESOLVED]: [
20760
+ CoreState.ACTIVE,
20761
+ CoreState.ACTIVE_DEGRADED,
20762
+ CoreState.SHUTTING_DOWN
20763
+ ],
20764
+ [CoreState.ACTIVE]: [
20765
+ CoreState.ACTIVE_DEGRADED,
20766
+ CoreState.SHUTTING_DOWN
20767
+ ],
20768
+ [CoreState.ACTIVE_DEGRADED]: [
20769
+ CoreState.ACTIVE,
20770
+ CoreState.SHUTTING_DOWN
20771
+ ],
20772
+ [CoreState.SHUTTING_DOWN]: [CoreState.SHUTDOWN],
20773
+ [CoreState.SHUTDOWN]: [],
20774
+ [CoreState.PRODUCTION_DISABLED]: [],
20775
+ [CoreState.REGISTRATION_FAILED]: []
20776
+ };
20777
+ var VALID_AUTH_TRANSITIONS = {
20778
+ [AuthState.ANONYMOUS]: [AuthState.CLAIMING],
20779
+ [AuthState.AUTHENTICATED]: [AuthState.CLAIMING],
20780
+ [AuthState.CLAIMING]: [AuthState.CLAIMED],
20781
+ [AuthState.CLAIMED]: [AuthState.CLAIMING]
20782
+ };
20783
+ var VALID_OTEL_TRANSITIONS = {
20784
+ [OtelState.UNCONFIGURED]: [OtelState.CONFIGURING],
20785
+ [OtelState.CONFIGURING]: [
20786
+ OtelState.OWNS_PROVIDER,
20787
+ OtelState.AUTO_ATTACHED,
20788
+ OtelState.PROCESSOR_PRESENT,
20789
+ OtelState.COEXISTENCE_FAILED
20790
+ ],
20791
+ [OtelState.OWNS_PROVIDER]: [],
20792
+ [OtelState.AUTO_ATTACHED]: [],
20793
+ [OtelState.PROCESSOR_PRESENT]: [],
20794
+ [OtelState.COEXISTENCE_FAILED]: []
20795
+ };
20796
+ var _coreState = CoreState.IDLE;
20797
+ var _authState = AuthState.ANONYMOUS;
20798
+ var _otelState = OtelState.UNCONFIGURED;
20799
+ var _emitter = new import_node_events.EventEmitter();
20800
+ var _logger = null;
20801
+ var _initialized = false;
20802
+ var _initWarned = false;
20803
+ var _coreReadyEmitted = false;
20804
+ var _authInitialized = false;
20805
+ var _emitting = false;
20806
+ function initLifecycle(options) {
20807
+ if (_initialized) {
20808
+ options.logger("warn", "[glasstrace] initLifecycle() called twice \u2014 ignored.");
20809
+ return;
20810
+ }
20811
+ _logger = options.logger;
20812
+ _initialized = true;
20813
+ }
20814
+ function warnIfNotInitialized() {
20815
+ if (!_initialized && !_initWarned) {
20816
+ _initWarned = true;
20817
+ console.warn(
20818
+ "[glasstrace] Lifecycle state changed before initLifecycle() was called. Logger not available \u2014 errors will be silent."
20819
+ );
20820
+ }
20821
+ }
20822
+ function setCoreState(to) {
20823
+ warnIfNotInitialized();
20824
+ const from = _coreState;
20825
+ if (from === to) return;
20826
+ const valid = VALID_CORE_TRANSITIONS[from];
20827
+ if (!valid.includes(to)) {
20828
+ _logger?.(
20829
+ "warn",
20830
+ `[glasstrace] Invalid core state transition: ${from} \u2192 ${to}. Ignored.`
20831
+ );
20832
+ return;
20833
+ }
20834
+ _coreState = to;
20835
+ if (_emitting) return;
20836
+ _emitting = true;
20837
+ try {
20838
+ emitSafe("core:state_changed", { from, to });
20839
+ const current = _coreState;
20840
+ if (!_coreReadyEmitted && (current === CoreState.ACTIVE || current === CoreState.ACTIVE_DEGRADED)) {
20841
+ _coreReadyEmitted = true;
20842
+ emitSafe("core:ready", {});
20843
+ }
20844
+ if (current === CoreState.SHUTTING_DOWN) {
20845
+ emitSafe("core:shutdown_started", {});
20846
+ }
20847
+ if (current === CoreState.SHUTDOWN) {
20848
+ emitSafe("core:shutdown_completed", {});
20849
+ }
20850
+ } finally {
20851
+ _emitting = false;
20852
+ }
20853
+ }
20854
+ function initAuthState(state) {
20855
+ if (_authInitialized) {
20856
+ _logger?.(
20857
+ "warn",
20858
+ "[glasstrace] initAuthState() called after auth state already initialized. Ignored."
20859
+ );
20860
+ return;
20861
+ }
20862
+ _authInitialized = true;
20863
+ _authState = state;
20864
+ }
20865
+ function setAuthState(to) {
20866
+ warnIfNotInitialized();
20867
+ const from = _authState;
20868
+ if (from === to) return;
20869
+ const valid = VALID_AUTH_TRANSITIONS[from];
20870
+ if (!valid.includes(to)) {
20871
+ _logger?.(
20872
+ "warn",
20873
+ `[glasstrace] Invalid auth state transition: ${from} \u2192 ${to}. Ignored.`
20874
+ );
20875
+ return;
20876
+ }
20877
+ _authState = to;
20878
+ }
20879
+ function setOtelState(to) {
20880
+ warnIfNotInitialized();
20881
+ const from = _otelState;
20882
+ if (from === to) return;
20883
+ const valid = VALID_OTEL_TRANSITIONS[from];
20884
+ if (!valid.includes(to)) {
20885
+ _logger?.(
20886
+ "warn",
20887
+ `[glasstrace] Invalid OTel state transition: ${from} \u2192 ${to}. Ignored.`
20888
+ );
20889
+ return;
20890
+ }
20891
+ _otelState = to;
20892
+ }
20893
+ function getCoreState() {
20894
+ return _coreState;
20895
+ }
20896
+ function getSdkState() {
20897
+ return {
20898
+ core: _coreState,
20899
+ auth: _authState,
20900
+ otel: _otelState
20901
+ };
20902
+ }
20903
+ function onLifecycleEvent(event, listener) {
20904
+ _emitter.on(event, listener);
20905
+ }
20906
+ function emitLifecycleEvent(event, payload) {
20907
+ emitSafe(event, payload);
20908
+ }
20909
+ function offLifecycleEvent(event, listener) {
20910
+ _emitter.off(event, listener);
20911
+ }
20912
+ function emitSafe(event, payload) {
20913
+ const listeners = _emitter.listeners(event);
20914
+ for (const listener of listeners) {
20915
+ try {
20916
+ const result = listener(payload);
20917
+ if (result && typeof result.catch === "function") {
20918
+ result.catch((err) => {
20919
+ _logger?.(
20920
+ "error",
20921
+ `[glasstrace] Async error in lifecycle event listener for "${event}": ${err instanceof Error ? err.message : String(err)}`
20922
+ );
20923
+ });
20924
+ }
20925
+ } catch (err) {
20926
+ _logger?.(
20927
+ "error",
20928
+ `[glasstrace] Error in lifecycle event listener for "${event}": ${err instanceof Error ? err.message : String(err)}`
20929
+ );
20930
+ }
20931
+ }
20932
+ }
20933
+ function isReady() {
20934
+ return _coreState === CoreState.ACTIVE || _coreState === CoreState.ACTIVE_DEGRADED;
20935
+ }
20936
+ function waitForReady(timeoutMs = 3e4) {
20937
+ if (isReady()) {
20938
+ return Promise.resolve();
20939
+ }
20940
+ if (_coreState === CoreState.PRODUCTION_DISABLED || _coreState === CoreState.REGISTRATION_FAILED || _coreState === CoreState.SHUTTING_DOWN || _coreState === CoreState.SHUTDOWN) {
20941
+ return Promise.reject(new Error(`SDK is in terminal state: ${_coreState}`));
20942
+ }
20943
+ return new Promise((resolve3, reject) => {
20944
+ let settled = false;
20945
+ const listener = ({ to }) => {
20946
+ if (settled) return;
20947
+ if (to === CoreState.ACTIVE || to === CoreState.ACTIVE_DEGRADED) {
20948
+ settled = true;
20949
+ offLifecycleEvent("core:state_changed", listener);
20950
+ resolve3();
20951
+ } else if (to === CoreState.PRODUCTION_DISABLED || to === CoreState.REGISTRATION_FAILED || to === CoreState.SHUTTING_DOWN || to === CoreState.SHUTDOWN) {
20952
+ settled = true;
20953
+ offLifecycleEvent("core:state_changed", listener);
20954
+ reject(new Error(`SDK reached terminal state: ${to}`));
20955
+ }
20956
+ };
20957
+ onLifecycleEvent("core:state_changed", listener);
20958
+ if (timeoutMs > 0) {
20959
+ const timer = setTimeout(() => {
20960
+ if (settled) return;
20961
+ settled = true;
20962
+ offLifecycleEvent("core:state_changed", listener);
20963
+ reject(new Error(`waitForReady timed out after ${timeoutMs}ms (state: ${_coreState})`));
20964
+ }, timeoutMs);
20965
+ if (typeof timer === "object" && "unref" in timer) {
20966
+ timer.unref();
20967
+ }
20968
+ }
20969
+ });
20970
+ }
20971
+ function getStatus() {
20972
+ let mode;
20973
+ if (_coreState === CoreState.PRODUCTION_DISABLED) {
20974
+ mode = "disabled";
20975
+ } else if (_authState === AuthState.CLAIMING || _authState === AuthState.CLAIMED) {
20976
+ mode = "claiming";
20977
+ } else if (_authState === AuthState.AUTHENTICATED) {
20978
+ mode = "authenticated";
20979
+ } else {
20980
+ mode = "anonymous";
20981
+ }
20982
+ let tracing;
20983
+ if (_otelState === OtelState.COEXISTENCE_FAILED || _otelState === OtelState.UNCONFIGURED || _otelState === OtelState.CONFIGURING) {
20984
+ tracing = "not-configured";
20985
+ } else if (_coreState === CoreState.ACTIVE_DEGRADED) {
20986
+ tracing = "degraded";
20987
+ } else if (_otelState === OtelState.AUTO_ATTACHED || _otelState === OtelState.PROCESSOR_PRESENT) {
20988
+ tracing = "coexistence";
20989
+ } else {
20990
+ tracing = "active";
20991
+ }
20992
+ return {
20993
+ ready: isReady(),
20994
+ mode,
20995
+ tracing
20996
+ };
20997
+ }
20998
+ var _shutdownHooks = [];
20999
+ var _signalHandlersRegistered = false;
21000
+ var _signalHandler = null;
21001
+ var _beforeExitRegistered = false;
21002
+ var _beforeExitHandler = null;
21003
+ var _shutdownExecuted = false;
21004
+ function registerShutdownHook(hook) {
21005
+ _shutdownHooks.push(hook);
21006
+ _shutdownHooks.sort((a, b) => a.priority - b.priority);
21007
+ }
21008
+ async function executeShutdown(timeoutMs = 5e3) {
21009
+ if (_shutdownExecuted) return;
21010
+ _shutdownExecuted = true;
21011
+ setCoreState(CoreState.SHUTTING_DOWN);
21012
+ for (const hook of _shutdownHooks) {
21013
+ try {
21014
+ const hookPromise = hook.fn();
21015
+ hookPromise.catch(() => {
21016
+ });
21017
+ await Promise.race([
21018
+ hookPromise,
21019
+ new Promise((_, reject) => {
21020
+ const timer = setTimeout(() => reject(new Error(`Shutdown hook "${hook.name}" timed out`)), timeoutMs);
21021
+ if (typeof timer === "object" && "unref" in timer) {
21022
+ timer.unref();
21023
+ }
21024
+ })
21025
+ ]);
21026
+ } catch (err) {
21027
+ _logger?.(
21028
+ "warn",
21029
+ `[glasstrace] Shutdown hook "${hook.name}" failed: ${err instanceof Error ? err.message : String(err)}`
21030
+ );
21031
+ }
21032
+ }
21033
+ setCoreState(CoreState.SHUTDOWN);
21034
+ }
21035
+ function registerSignalHandlers() {
21036
+ if (_signalHandlersRegistered) return;
21037
+ if (typeof process === "undefined" || typeof process.once !== "function") return;
21038
+ _signalHandlersRegistered = true;
21039
+ const handler = (signal) => {
21040
+ void executeShutdown().finally(() => {
21041
+ if (_signalHandler) {
21042
+ process.removeListener("SIGTERM", _signalHandler);
21043
+ process.removeListener("SIGINT", _signalHandler);
21044
+ }
21045
+ process.kill(process.pid, signal);
21046
+ });
21047
+ };
21048
+ _signalHandler = handler;
21049
+ process.once("SIGTERM", handler);
21050
+ process.once("SIGINT", handler);
21051
+ }
21052
+ function registerBeforeExitTrigger() {
21053
+ if (_beforeExitRegistered) return;
21054
+ if (typeof process === "undefined" || typeof process.once !== "function") return;
21055
+ _beforeExitRegistered = true;
21056
+ const handler = () => {
21057
+ void executeShutdown();
21058
+ };
21059
+ _beforeExitHandler = handler;
21060
+ process.once("beforeExit", handler);
21061
+ }
21062
+
21063
+ // src/coexistence.ts
21064
+ init_cjs_shims();
21065
+ init_env_detection();
21066
+ init_console_capture();
21067
+ function createGlasstraceSpanProcessor(options) {
21068
+ const config2 = resolveConfig(options);
21069
+ const exporterUrl = `${config2.endpoint}/v1/traces`;
21070
+ const createOtlpExporter = (url2, headers) => new OTLPTraceExporter({ url: url2, headers });
21071
+ const exporter = new GlasstraceExporter({
21072
+ getApiKey: getResolvedApiKey,
21073
+ sessionManager: getSessionManager(),
21074
+ getConfig: () => getActiveConfig(),
21075
+ environment: config2.environment,
21076
+ endpointUrl: exporterUrl,
21077
+ createDelegate: createOtlpExporter
21078
+ });
21079
+ registerExporterForKeyNotification(exporter);
21080
+ return new BatchSpanProcessor(exporter, {
21081
+ scheduledDelayMillis: 1e3
21082
+ });
21083
+ }
21084
+ function emitNudgeMessage() {
21085
+ const isSentry = detectSentry();
21086
+ if (isSentry) {
21087
+ sdkLog(
21088
+ "info",
21089
+ `[glasstrace] Detected existing OTel provider \u2014 auto-attached Glasstrace span processor.
21090
+ For a cleaner setup, add Glasstrace to your Sentry config:
21091
+
21092
+ import { createGlasstraceSpanProcessor } from '@glasstrace/sdk';
21093
+
21094
+ Sentry.init({
21095
+ dsn: '...',
21096
+ openTelemetrySpanProcessors: [createGlasstraceSpanProcessor()],
21097
+ });
21098
+
21099
+ This message will not appear once Glasstrace is added to your provider config.`
21100
+ );
21101
+ } else {
21102
+ sdkLog(
21103
+ "info",
21104
+ `[glasstrace] Detected existing OTel provider \u2014 auto-attached Glasstrace span processor.
21105
+ For a cleaner setup, add Glasstrace to your provider config:
21106
+
21107
+ import { createGlasstraceSpanProcessor } from '@glasstrace/sdk';
21108
+
21109
+ const provider = new BasicTracerProvider({
21110
+ spanProcessors: [
21111
+ // ... your existing processors,
21112
+ createGlasstraceSpanProcessor(),
21113
+ ],
21114
+ });
21115
+
21116
+ This message will not appear once Glasstrace is added to your provider config.`
21117
+ );
21118
+ }
21119
+ }
21120
+ function emitGuidanceMessage() {
21121
+ const isSentry = detectSentry();
21122
+ if (isSentry) {
21123
+ sdkLog(
21124
+ "warn",
21125
+ `[glasstrace] An existing OTel TracerProvider is registered but Glasstrace could not auto-attach its span processor.
21126
+ Add Glasstrace to your Sentry config:
21127
+
21128
+ import { createGlasstraceSpanProcessor } from '@glasstrace/sdk';
21129
+
21130
+ Sentry.init({
21131
+ dsn: '...',
21132
+ openTelemetrySpanProcessors: [createGlasstraceSpanProcessor()],
21133
+ });`
21134
+ );
21135
+ } else {
21136
+ sdkLog(
21137
+ "warn",
21138
+ `[glasstrace] An existing OTel TracerProvider is registered but Glasstrace could not auto-attach its span processor.
21139
+ Add Glasstrace to your provider configuration:
21140
+
21141
+ import { createGlasstraceSpanProcessor } from '@glasstrace/sdk';
21142
+
21143
+ const provider = new BasicTracerProvider({
21144
+ spanProcessors: [
21145
+ // ... your existing processors,
21146
+ createGlasstraceSpanProcessor(),
21147
+ ],
21148
+ });`
21149
+ );
21150
+ }
21151
+ }
21152
+ function detectSentry() {
21153
+ try {
21154
+ require.resolve("@sentry/node");
21155
+ return true;
21156
+ } catch {
21157
+ try {
21158
+ require.resolve("@sentry/nextjs");
21159
+ return true;
21160
+ } catch {
21161
+ return false;
21162
+ }
21163
+ }
21164
+ }
21165
+
21166
+ // src/otel-config.ts
20640
21167
  var _resolvedApiKey = API_KEY_PENDING;
20641
21168
  var _activeExporter = null;
20642
- var _shutdownHandler = null;
21169
+ var _additionalExporters = [];
21170
+ var _injectedProcessor = null;
20643
21171
  function setResolvedApiKey(key) {
20644
21172
  _resolvedApiKey = key;
20645
21173
  }
@@ -20648,6 +21176,12 @@ function getResolvedApiKey() {
20648
21176
  }
20649
21177
  function notifyApiKeyResolved() {
20650
21178
  _activeExporter?.notifyKeyResolved();
21179
+ for (const exporter of _additionalExporters) {
21180
+ exporter.notifyKeyResolved();
21181
+ }
21182
+ }
21183
+ function registerExporterForKeyNotification(exporter) {
21184
+ _additionalExporters.push(exporter);
20651
21185
  }
20652
21186
  async function tryImport(moduleId) {
20653
21187
  try {
@@ -20656,34 +21190,65 @@ async function tryImport(moduleId) {
20656
21190
  return null;
20657
21191
  }
20658
21192
  }
20659
- function registerShutdownHooks(provider) {
20660
- if (typeof process === "undefined" || typeof process.once !== "function") {
20661
- return;
20662
- }
20663
- if (_shutdownHandler) {
20664
- process.removeListener("SIGTERM", _shutdownHandler);
20665
- process.removeListener("SIGINT", _shutdownHandler);
21193
+ function tryInjectProcessor(tracerProvider, glasstraceExporter) {
21194
+ try {
21195
+ const proxy = tracerProvider;
21196
+ const delegate = typeof proxy.getDelegate === "function" ? proxy.getDelegate() : tracerProvider;
21197
+ const withAdd = delegate;
21198
+ if (typeof withAdd.addSpanProcessor === "function") {
21199
+ if (typeof withAdd.getActiveSpanProcessor === "function") {
21200
+ const active = withAdd.getActiveSpanProcessor();
21201
+ const brand = /* @__PURE__ */ Symbol.for("glasstrace.exporter");
21202
+ const processors = active?._spanProcessors;
21203
+ if (Array.isArray(processors) && processors.some((p) => {
21204
+ const exp = p._exporter;
21205
+ return exp?.[brand] === true;
21206
+ })) {
21207
+ return "already_present";
21208
+ }
21209
+ }
21210
+ const processor2 = new BatchSpanProcessor(glasstraceExporter, {
21211
+ scheduledDelayMillis: 1e3
21212
+ });
21213
+ withAdd.addSpanProcessor(processor2);
21214
+ _injectedProcessor = processor2;
21215
+ return "v1_public";
21216
+ }
21217
+ const provider = delegate;
21218
+ const multiProcessor = provider._activeSpanProcessor;
21219
+ if (!multiProcessor || !Array.isArray(multiProcessor._spanProcessors)) {
21220
+ return null;
21221
+ }
21222
+ const processor = new BatchSpanProcessor(glasstraceExporter, {
21223
+ scheduledDelayMillis: 1e3
21224
+ });
21225
+ multiProcessor._spanProcessors.push(processor);
21226
+ _injectedProcessor = processor;
21227
+ return "v2_private";
21228
+ } catch {
21229
+ return null;
20666
21230
  }
20667
- let shutdownCalled = false;
20668
- const shutdown = (signal) => {
20669
- if (shutdownCalled) return;
20670
- shutdownCalled = true;
20671
- void provider.shutdown().catch((err) => {
20672
- console.warn(
20673
- `[glasstrace] Error during OTel shutdown: ${err instanceof Error ? err.message : String(err)}`
20674
- );
20675
- }).finally(() => {
20676
- process.removeListener("SIGTERM", _shutdownHandler);
20677
- process.removeListener("SIGINT", _shutdownHandler);
20678
- process.kill(process.pid, signal);
21231
+ }
21232
+ function isGlasstraceProcessorPresent(tracerProvider) {
21233
+ try {
21234
+ const proxy = tracerProvider;
21235
+ const delegate = typeof proxy.getDelegate === "function" ? proxy.getDelegate() : tracerProvider;
21236
+ const provider = delegate;
21237
+ const processors = provider._activeSpanProcessor?._spanProcessors;
21238
+ if (!Array.isArray(processors)) {
21239
+ return false;
21240
+ }
21241
+ const brand = /* @__PURE__ */ Symbol.for("glasstrace.exporter");
21242
+ return processors.some((p) => {
21243
+ const exporter = p._exporter;
21244
+ return exporter?.[brand] === true;
20679
21245
  });
20680
- };
20681
- const handler = (signal) => shutdown(signal);
20682
- _shutdownHandler = handler;
20683
- process.once("SIGTERM", handler);
20684
- process.once("SIGINT", handler);
21246
+ } catch {
21247
+ return false;
21248
+ }
20685
21249
  }
20686
21250
  async function configureOtel(config2, sessionManager) {
21251
+ setOtelState(OtelState.CONFIGURING);
20687
21252
  const exporterUrl = `${config2.endpoint}/v1/traces`;
20688
21253
  const createOtlpExporter = (url2, headers) => new OTLPTraceExporter({ url: url2, headers });
20689
21254
  const glasstraceExporter = new GlasstraceExporter({
@@ -20692,32 +21257,91 @@ async function configureOtel(config2, sessionManager) {
20692
21257
  getConfig: () => getActiveConfig(),
20693
21258
  environment: config2.environment,
20694
21259
  endpointUrl: exporterUrl,
20695
- createDelegate: createOtlpExporter
21260
+ createDelegate: createOtlpExporter,
21261
+ verbose: config2.verbose
20696
21262
  });
20697
21263
  _activeExporter = glasstraceExporter;
21264
+ await new Promise((resolve3) => {
21265
+ if (typeof setImmediate === "function") {
21266
+ setImmediate(resolve3);
21267
+ } else {
21268
+ setTimeout(resolve3, 0);
21269
+ }
21270
+ });
21271
+ const existingProvider = trace.getTracerProvider();
21272
+ const probeTracer = existingProvider.getTracer("glasstrace-probe");
21273
+ const anotherProviderRegistered = probeTracer.constructor.name !== "ProxyTracer";
21274
+ if (anotherProviderRegistered) {
21275
+ if (isGlasstraceProcessorPresent(existingProvider)) {
21276
+ if (config2.verbose) {
21277
+ sdkLog("info", "[glasstrace] Existing provider detected \u2014 Glasstrace processor already present.");
21278
+ }
21279
+ _activeExporter = null;
21280
+ setOtelState(OtelState.PROCESSOR_PRESENT);
21281
+ emitLifecycleEvent("otel:configured", { state: OtelState.PROCESSOR_PRESENT, scenario: "B-clean" });
21282
+ return;
21283
+ }
21284
+ const injectionMethod = tryInjectProcessor(existingProvider, glasstraceExporter);
21285
+ if (injectionMethod === "already_present") {
21286
+ if (config2.verbose) {
21287
+ sdkLog("info", "[glasstrace] Existing provider detected \u2014 Glasstrace processor already present (v1 check).");
21288
+ }
21289
+ _activeExporter = null;
21290
+ setOtelState(OtelState.PROCESSOR_PRESENT);
21291
+ emitLifecycleEvent("otel:configured", { state: OtelState.PROCESSOR_PRESENT, scenario: "B-clean" });
21292
+ return;
21293
+ }
21294
+ if (injectionMethod) {
21295
+ if (config2.verbose) {
21296
+ sdkLog("info", "[glasstrace] Existing provider detected \u2014 auto-attaching Glasstrace processor.");
21297
+ }
21298
+ registerShutdownHook({
21299
+ name: "coexistence-flush",
21300
+ priority: 5,
21301
+ fn: async () => {
21302
+ if (_injectedProcessor) {
21303
+ await _injectedProcessor.forceFlush();
21304
+ }
21305
+ }
21306
+ });
21307
+ registerBeforeExitTrigger();
21308
+ const scenario = injectionMethod === "v1_public" ? "D1" : "B-auto";
21309
+ setOtelState(OtelState.AUTO_ATTACHED);
21310
+ emitLifecycleEvent("otel:configured", { state: OtelState.AUTO_ATTACHED, scenario });
21311
+ emitLifecycleEvent("otel:injection_succeeded", { method: injectionMethod });
21312
+ emitNudgeMessage();
21313
+ return;
21314
+ }
21315
+ if (config2.verbose) {
21316
+ sdkLog("info", "[glasstrace] Existing provider detected \u2014 could not auto-attach.");
21317
+ }
21318
+ emitGuidanceMessage();
21319
+ _activeExporter = null;
21320
+ setOtelState(OtelState.COEXISTENCE_FAILED);
21321
+ emitLifecycleEvent("otel:configured", { state: OtelState.COEXISTENCE_FAILED, scenario: "C/F" });
21322
+ emitLifecycleEvent("otel:injection_failed", { reason: "provider internals inaccessible" });
21323
+ const coreState = getCoreState();
21324
+ if (coreState === CoreState.ACTIVE || coreState === CoreState.KEY_RESOLVED) {
21325
+ setCoreState(CoreState.ACTIVE_DEGRADED);
21326
+ }
21327
+ return;
21328
+ }
20698
21329
  const vercelOtel = await tryImport("@vercel/otel");
20699
21330
  if (vercelOtel && typeof vercelOtel.registerOTel === "function") {
20700
21331
  const otelConfig = {
20701
21332
  serviceName: "glasstrace-sdk",
20702
21333
  traceExporter: glasstraceExporter
20703
21334
  };
20704
- const prismaModule = await tryImport("@prisma/instrumentation");
20705
- if (prismaModule) {
20706
- const PrismaInstrumentation = prismaModule.PrismaInstrumentation;
21335
+ const prismaModule2 = await tryImport("@prisma/instrumentation");
21336
+ if (prismaModule2) {
21337
+ const PrismaInstrumentation = prismaModule2.PrismaInstrumentation;
20707
21338
  if (PrismaInstrumentation) {
20708
21339
  otelConfig.instrumentations = [new PrismaInstrumentation()];
20709
21340
  }
20710
21341
  }
20711
21342
  vercelOtel.registerOTel(otelConfig);
20712
- return;
20713
- }
20714
- const existingProvider = trace.getTracerProvider();
20715
- const probeTracer = existingProvider.getTracer("glasstrace-probe");
20716
- if (probeTracer.constructor.name !== "ProxyTracer") {
20717
- console.warn(
20718
- "[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."
20719
- );
20720
- _activeExporter = null;
21343
+ setOtelState(OtelState.OWNS_PROVIDER);
21344
+ emitLifecycleEvent("otel:configured", { state: OtelState.OWNS_PROVIDER, scenario: "E" });
20721
21345
  return;
20722
21346
  }
20723
21347
  if (config2.verbose) {
@@ -20739,7 +21363,29 @@ async function configureOtel(config2, sessionManager) {
20739
21363
  spanProcessors: [processor]
20740
21364
  });
20741
21365
  trace.setGlobalTracerProvider(provider);
20742
- registerShutdownHooks(provider);
21366
+ registerShutdownHook({
21367
+ name: "otel-provider-shutdown",
21368
+ priority: 0,
21369
+ fn: async () => {
21370
+ await provider.shutdown();
21371
+ }
21372
+ });
21373
+ registerSignalHandlers();
21374
+ registerBeforeExitTrigger();
21375
+ const prismaModule = await tryImport("@prisma/instrumentation");
21376
+ if (prismaModule) {
21377
+ const PrismaInstrumentation = prismaModule.PrismaInstrumentation;
21378
+ if (PrismaInstrumentation) {
21379
+ try {
21380
+ const inst = new PrismaInstrumentation();
21381
+ inst.setTracerProvider(provider);
21382
+ inst.enable();
21383
+ } catch {
21384
+ }
21385
+ }
21386
+ }
21387
+ setOtelState(OtelState.OWNS_PROVIDER);
21388
+ emitLifecycleEvent("otel:configured", { state: OtelState.OWNS_PROVIDER, scenario: "A" });
20743
21389
  }
20744
21390
 
20745
21391
  // src/context-manager.ts
@@ -20790,7 +21436,7 @@ var heartbeatGeneration = 0;
20790
21436
  var backoffAttempts = 0;
20791
21437
  var backoffUntil = 0;
20792
21438
  var tickInProgress = false;
20793
- var _shutdownHandler2 = null;
21439
+ var _shutdownHandler = null;
20794
21440
  function startHeartbeat(config2, anonKey, sdkVersion, generation, onClaimTransition) {
20795
21441
  if (heartbeatTimer !== null) return;
20796
21442
  heartbeatGeneration = generation;
@@ -20843,7 +21489,7 @@ async function heartbeatTick(config2, anonKey, sdkVersion, generation, onClaimTr
20843
21489
  backoffUntil = 0;
20844
21490
  }
20845
21491
  if (initResult?.claimResult) {
20846
- onClaimTransition(initResult.claimResult.newApiKey);
21492
+ onClaimTransition(initResult.claimResult.newApiKey, initResult.claimResult.accountId);
20847
21493
  }
20848
21494
  if (config2.verbose) {
20849
21495
  sdkLog("info", "[glasstrace] Heartbeat completed.");
@@ -20871,39 +21517,125 @@ function registerShutdownHandlers(config2, anonKey, sdkVersion) {
20871
21517
  process.kill(process.pid, signal);
20872
21518
  });
20873
21519
  };
20874
- _shutdownHandler2 = handler;
20875
- process.once("SIGTERM", _shutdownHandler2);
20876
- process.once("SIGINT", _shutdownHandler2);
21520
+ _shutdownHandler = handler;
21521
+ process.once("SIGTERM", _shutdownHandler);
21522
+ process.once("SIGINT", _shutdownHandler);
20877
21523
  }
20878
21524
  function removeShutdownHandlers() {
20879
- if (_shutdownHandler2 && typeof process !== "undefined") {
20880
- process.removeListener("SIGTERM", _shutdownHandler2);
20881
- process.removeListener("SIGINT", _shutdownHandler2);
20882
- _shutdownHandler2 = null;
21525
+ if (_shutdownHandler && typeof process !== "undefined") {
21526
+ process.removeListener("SIGTERM", _shutdownHandler);
21527
+ process.removeListener("SIGINT", _shutdownHandler);
21528
+ _shutdownHandler = null;
21529
+ }
21530
+ }
21531
+
21532
+ // src/runtime-state.ts
21533
+ init_cjs_shims();
21534
+ var import_node_fs = require("fs");
21535
+ var import_node_path = require("path");
21536
+ init_console_capture();
21537
+ var _projectRoot = null;
21538
+ var _sdkVersion = "unknown";
21539
+ var _lastScenario;
21540
+ var _debounceTimer = null;
21541
+ var _started = false;
21542
+ function startRuntimeStateWriter(options) {
21543
+ if (_started) return;
21544
+ _started = true;
21545
+ _projectRoot = options.projectRoot;
21546
+ _sdkVersion = options.sdkVersion;
21547
+ onLifecycleEvent("core:state_changed", ({ to }) => {
21548
+ if (to === CoreState.SHUTDOWN) {
21549
+ writeStateNow();
21550
+ } else {
21551
+ debouncedWrite();
21552
+ }
21553
+ });
21554
+ onLifecycleEvent("otel:configured", ({ scenario }) => {
21555
+ _lastScenario = scenario;
21556
+ debouncedWrite();
21557
+ });
21558
+ onLifecycleEvent("auth:key_resolved", () => debouncedWrite());
21559
+ onLifecycleEvent("auth:claim_started", () => debouncedWrite());
21560
+ onLifecycleEvent("auth:claim_completed", () => debouncedWrite());
21561
+ writeStateNow();
21562
+ }
21563
+ function debouncedWrite() {
21564
+ if (_debounceTimer) return;
21565
+ _debounceTimer = setTimeout(() => {
21566
+ _debounceTimer = null;
21567
+ writeStateNow();
21568
+ }, 1e3);
21569
+ if (typeof _debounceTimer === "object" && "unref" in _debounceTimer) {
21570
+ _debounceTimer.unref();
21571
+ }
21572
+ }
21573
+ function writeStateNow() {
21574
+ if (!_projectRoot) return;
21575
+ try {
21576
+ const state = getSdkState();
21577
+ const runtimeState = {
21578
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
21579
+ pid: process.pid,
21580
+ sdkVersion: _sdkVersion,
21581
+ core: { state: state.core },
21582
+ auth: { state: state.auth },
21583
+ otel: { state: state.otel, scenario: _lastScenario }
21584
+ };
21585
+ const dir = (0, import_node_path.join)(_projectRoot, ".glasstrace");
21586
+ const filePath = (0, import_node_path.join)(dir, "runtime-state.json");
21587
+ const tmpPath = (0, import_node_path.join)(dir, "runtime-state.json.tmp");
21588
+ (0, import_node_fs.mkdirSync)(dir, { recursive: true, mode: 448 });
21589
+ (0, import_node_fs.writeFileSync)(tmpPath, JSON.stringify(runtimeState, null, 2) + "\n", {
21590
+ mode: 384
21591
+ });
21592
+ (0, import_node_fs.renameSync)(tmpPath, filePath);
21593
+ } catch (err) {
21594
+ sdkLog(
21595
+ "warn",
21596
+ `[glasstrace] Failed to write runtime state: ${err instanceof Error ? err.message : String(err)}`
21597
+ );
20883
21598
  }
20884
21599
  }
20885
21600
 
20886
21601
  // src/register.ts
21602
+ function maskKey(key) {
21603
+ if (key.length <= 12) return key.slice(0, 4) + "...";
21604
+ return key.slice(0, 8) + "..." + key.slice(-4);
21605
+ }
20887
21606
  var consoleCaptureInstalled = false;
20888
21607
  var discoveryHandler = null;
20889
- var isRegistered = false;
20890
21608
  var registrationGeneration = 0;
21609
+ var _sessionManager = null;
21610
+ function getSessionManager() {
21611
+ if (!_sessionManager) {
21612
+ _sessionManager = new SessionManager();
21613
+ }
21614
+ return _sessionManager;
21615
+ }
20891
21616
  function registerGlasstrace(options) {
20892
21617
  try {
20893
- if (isRegistered) {
21618
+ if (getCoreState() !== CoreState.IDLE) {
20894
21619
  return;
20895
21620
  }
21621
+ initLifecycle({ logger: sdkLog });
20896
21622
  if (typeof process === "undefined" || typeof process.versions?.node !== "string") {
20897
21623
  console.warn(
20898
21624
  "[glasstrace] SDK requires a Node.js runtime. Edge Runtime, browser, and Deno without Node compat are not supported. Glasstrace is disabled in this environment."
20899
21625
  );
20900
21626
  return;
20901
21627
  }
21628
+ setCoreState(CoreState.REGISTERING);
21629
+ startRuntimeStateWriter({
21630
+ projectRoot: process.cwd(),
21631
+ sdkVersion: "0.14.0"
21632
+ });
20902
21633
  const config2 = resolveConfig(options);
20903
21634
  if (config2.verbose) {
20904
21635
  console.info("[glasstrace] Config resolved.");
20905
21636
  }
20906
21637
  if (isProductionDisabled(config2)) {
21638
+ setCoreState(CoreState.PRODUCTION_DISABLED);
20907
21639
  console.warn(
20908
21640
  "[glasstrace] Disabled in production. Set GLASSTRACE_FORCE_ENABLE=true to override."
20909
21641
  );
@@ -20914,8 +21646,13 @@ function registerGlasstrace(options) {
20914
21646
  }
20915
21647
  const anonymous = isAnonymousMode(config2);
20916
21648
  let effectiveKey = config2.apiKey;
21649
+ initAuthState(anonymous ? AuthState.ANONYMOUS : AuthState.AUTHENTICATED);
20917
21650
  if (effectiveKey) {
20918
21651
  setResolvedApiKey(effectiveKey);
21652
+ emitLifecycleEvent("auth:key_resolved", {
21653
+ key: maskKey(effectiveKey),
21654
+ mode: anonymous ? "anonymous" : "dev"
21655
+ });
20919
21656
  }
20920
21657
  if (config2.verbose) {
20921
21658
  console.info(
@@ -20931,11 +21668,11 @@ function registerGlasstrace(options) {
20931
21668
  `[glasstrace] Cached config ${cachedInitResponse ? "loaded and applied" : "not found"}.`
20932
21669
  );
20933
21670
  }
20934
- const sessionManager = new SessionManager();
21671
+ const sessionManager = getSessionManager();
20935
21672
  if (config2.verbose) {
20936
21673
  console.info("[glasstrace] SessionManager created.");
20937
21674
  }
20938
- isRegistered = true;
21675
+ setCoreState(CoreState.KEY_PENDING);
20939
21676
  const currentGeneration = registrationGeneration;
20940
21677
  const existingProbe = trace.getTracerProvider().getTracer("glasstrace-probe");
20941
21678
  const anotherProviderRegistered = existingProbe.constructor.name !== "ProxyTracer";
@@ -20988,6 +21725,7 @@ function registerGlasstrace(options) {
20988
21725
  resolvedAnonKey = anonKey;
20989
21726
  setResolvedApiKey(anonKey);
20990
21727
  notifyApiKeyResolved();
21728
+ emitLifecycleEvent("auth:key_resolved", { key: maskKey(anonKey), mode: "anonymous" });
20991
21729
  effectiveKey = anonKey;
20992
21730
  if (currentGeneration !== registrationGeneration) return;
20993
21731
  discoveryHandler = createDiscoveryHandler(
@@ -21009,6 +21747,7 @@ function registerGlasstrace(options) {
21009
21747
  const anonKey = await getOrCreateAnonKey();
21010
21748
  setResolvedApiKey(anonKey);
21011
21749
  notifyApiKeyResolved();
21750
+ emitLifecycleEvent("auth:key_resolved", { key: maskKey(anonKey), mode: "anonymous" });
21012
21751
  effectiveKey = anonKey;
21013
21752
  if (currentGeneration !== registrationGeneration) return;
21014
21753
  await backgroundInit(config2, anonKey, currentGeneration);
@@ -21041,6 +21780,7 @@ function registerGlasstrace(options) {
21041
21780
  console.info("[glasstrace] Import graph building skipped.");
21042
21781
  }
21043
21782
  } catch (err) {
21783
+ setCoreState(CoreState.REGISTRATION_FAILED);
21044
21784
  console.warn(
21045
21785
  `[glasstrace] Registration failed: ${err instanceof Error ? err.message : String(err)}`
21046
21786
  );
@@ -21050,18 +21790,37 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
21050
21790
  if (config2.verbose) {
21051
21791
  console.info("[glasstrace] Background init firing.");
21052
21792
  }
21053
- const healthReport = collectHealthReport("0.13.5");
21054
- const initResult = await performInit(config2, anonKeyForInit, "0.13.5", healthReport);
21793
+ const healthReport = collectHealthReport("0.14.0");
21794
+ const initResult = await performInit(config2, anonKeyForInit, "0.14.0", healthReport);
21055
21795
  if (generation !== registrationGeneration) return;
21796
+ const currentState = getCoreState();
21797
+ if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
21798
+ return;
21799
+ }
21800
+ if (currentState === CoreState.KEY_PENDING) {
21801
+ setCoreState(CoreState.KEY_RESOLVED);
21802
+ }
21803
+ if (getCoreState() === CoreState.KEY_RESOLVED) {
21804
+ setCoreState(didLastInitSucceed() ? CoreState.ACTIVE : CoreState.ACTIVE_DEGRADED);
21805
+ }
21056
21806
  if (initResult?.claimResult) {
21057
- setResolvedApiKey(initResult.claimResult.newApiKey);
21807
+ const { newApiKey, accountId } = initResult.claimResult;
21808
+ setAuthState(AuthState.CLAIMING);
21809
+ emitLifecycleEvent("auth:claim_started", { accountId });
21810
+ setResolvedApiKey(newApiKey);
21058
21811
  notifyApiKeyResolved();
21812
+ setAuthState(AuthState.CLAIMED);
21813
+ emitLifecycleEvent("auth:claim_completed", { newKey: maskKey(newApiKey), accountId });
21059
21814
  }
21060
21815
  maybeInstallConsoleCapture();
21061
21816
  if (didLastInitSucceed()) {
21062
- startHeartbeat(config2, anonKeyForInit, "0.13.5", generation, (newApiKey) => {
21817
+ startHeartbeat(config2, anonKeyForInit, "0.14.0", generation, (newApiKey, accountId) => {
21818
+ setAuthState(AuthState.CLAIMING);
21819
+ emitLifecycleEvent("auth:claim_started", { accountId });
21063
21820
  setResolvedApiKey(newApiKey);
21064
21821
  notifyApiKeyResolved();
21822
+ setAuthState(AuthState.CLAIMED);
21823
+ emitLifecycleEvent("auth:claim_completed", { newKey: maskKey(newApiKey), accountId });
21065
21824
  });
21066
21825
  }
21067
21826
  }
@@ -21359,6 +22118,7 @@ async function buildImportGraph(projectRoot) {
21359
22118
  collectSourceMaps,
21360
22119
  computeBuildHash,
21361
22120
  createDiscoveryHandler,
22121
+ createGlasstraceSpanProcessor,
21362
22122
  deriveSessionId,
21363
22123
  discoverSourceMapFiles,
21364
22124
  discoverTestFiles,
@@ -21369,8 +22129,10 @@ async function buildImportGraph(projectRoot) {
21369
22129
  getLinkedAccountId,
21370
22130
  getOrCreateAnonKey,
21371
22131
  getOrigin,
22132
+ getStatus,
21372
22133
  isAnonymousMode,
21373
22134
  isProductionDisabled,
22135
+ isReady,
21374
22136
  loadCachedConfig,
21375
22137
  performInit,
21376
22138
  readAnonKey,
@@ -21382,6 +22144,7 @@ async function buildImportGraph(projectRoot) {
21382
22144
  uploadSourceMaps,
21383
22145
  uploadSourceMapsAuto,
21384
22146
  uploadSourceMapsPresigned,
22147
+ waitForReady,
21385
22148
  withGlasstraceConfig
21386
22149
  });
21387
22150
  //# sourceMappingURL=index.cjs.map