@glasstrace/sdk 1.5.1 → 1.6.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.
Files changed (44) hide show
  1. package/README.md +108 -0
  2. package/dist/{chunk-YLY7AGLC.js → chunk-3PJP5Y3U.js} +3 -3
  3. package/dist/{chunk-Q42BY5BA.js → chunk-H57MQGNU.js} +2 -2
  4. package/dist/{chunk-TANUWTFO.js → chunk-M2TLX6NM.js} +3 -3
  5. package/dist/{chunk-MMKFFF2L.js → chunk-NN5YCETI.js} +2 -2
  6. package/dist/{chunk-4WI7B5FQ.js → chunk-P45NZR4J.js} +21 -1
  7. package/dist/chunk-P45NZR4J.js.map +1 -0
  8. package/dist/{chunk-QU26IKIJ.js → chunk-UQKI476D.js} +2 -2
  9. package/dist/{chunk-MFYOQOD7.js → chunk-WL6BXEJ5.js} +2 -2
  10. package/dist/{chunk-MLRQTCCK.js → chunk-ZU5XO77C.js} +205 -28
  11. package/dist/chunk-ZU5XO77C.js.map +1 -0
  12. package/dist/cli/init.cjs +4 -4
  13. package/dist/cli/init.cjs.map +1 -1
  14. package/dist/cli/init.js +7 -7
  15. package/dist/cli/mcp-add.cjs +1 -1
  16. package/dist/cli/mcp-add.cjs.map +1 -1
  17. package/dist/cli/mcp-add.js +3 -3
  18. package/dist/cli/uninit.js +3 -3
  19. package/dist/cli/upgrade-instructions.cjs +1 -1
  20. package/dist/cli/upgrade-instructions.js +3 -3
  21. package/dist/cli/validate.cjs.map +1 -1
  22. package/dist/cli/validate.js +2 -2
  23. package/dist/edge-entry.cjs +20 -0
  24. package/dist/edge-entry.cjs.map +1 -1
  25. package/dist/edge-entry.js +2 -2
  26. package/dist/index.cjs +220 -23
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.js +5 -5
  29. package/dist/node-entry.cjs +220 -23
  30. package/dist/node-entry.cjs.map +1 -1
  31. package/dist/node-entry.js +7 -7
  32. package/dist/node-subpath.cjs.map +1 -1
  33. package/dist/node-subpath.js +3 -3
  34. package/dist/{source-map-uploader-PB3M4PPP.js → source-map-uploader-XFUEVV7I.js} +3 -3
  35. package/package.json +1 -1
  36. package/dist/chunk-4WI7B5FQ.js.map +0 -1
  37. package/dist/chunk-MLRQTCCK.js.map +0 -1
  38. /package/dist/{chunk-YLY7AGLC.js.map → chunk-3PJP5Y3U.js.map} +0 -0
  39. /package/dist/{chunk-Q42BY5BA.js.map → chunk-H57MQGNU.js.map} +0 -0
  40. /package/dist/{chunk-TANUWTFO.js.map → chunk-M2TLX6NM.js.map} +0 -0
  41. /package/dist/{chunk-MMKFFF2L.js.map → chunk-NN5YCETI.js.map} +0 -0
  42. /package/dist/{chunk-QU26IKIJ.js.map → chunk-UQKI476D.js.map} +0 -0
  43. /package/dist/{chunk-MFYOQOD7.js.map → chunk-WL6BXEJ5.js.map} +0 -0
  44. /package/dist/{source-map-uploader-PB3M4PPP.js.map → source-map-uploader-XFUEVV7I.js.map} +0 -0
package/dist/index.js CHANGED
@@ -12,12 +12,12 @@ import {
12
12
  registerGlasstrace,
13
13
  waitForReady,
14
14
  withGlasstraceConfig
15
- } from "./chunk-MLRQTCCK.js";
15
+ } from "./chunk-ZU5XO77C.js";
16
16
  import {
17
17
  GlasstraceSpanProcessor,
18
18
  SdkError,
19
19
  captureCorrelationId
20
- } from "./chunk-Q42BY5BA.js";
20
+ } from "./chunk-H57MQGNU.js";
21
21
  import {
22
22
  trace
23
23
  } from "./chunk-DQ25VOKK.js";
@@ -29,7 +29,7 @@ import {
29
29
  performInit,
30
30
  saveCachedConfig,
31
31
  sendInitRequest
32
- } from "./chunk-TANUWTFO.js";
32
+ } from "./chunk-M2TLX6NM.js";
33
33
  import {
34
34
  isAnonymousMode,
35
35
  isProductionDisabled,
@@ -39,7 +39,7 @@ import {
39
39
  import {
40
40
  getOrCreateAnonKey,
41
41
  readAnonKey
42
- } from "./chunk-MFYOQOD7.js";
42
+ } from "./chunk-WL6BXEJ5.js";
43
43
  import {
44
44
  GLASSTRACE_ATTRIBUTE_NAMES,
45
45
  SIDE_EFFECT_OMISSION_REASONS,
@@ -48,7 +48,7 @@ import {
48
48
  SIDE_EFFECT_OPERATION_STATUSES,
49
49
  SIDE_EFFECT_SEMANTIC_FIELD_KEYS,
50
50
  deriveSessionId
51
- } from "./chunk-4WI7B5FQ.js";
51
+ } from "./chunk-P45NZR4J.js";
52
52
  import "./chunk-ZBQQXVHD.js";
53
53
  import "./chunk-NSBPE2FW.js";
54
54
 
@@ -14642,6 +14642,26 @@ var init_dist = __esm({
14642
14642
  ERROR_CODE: "glasstrace.error.code",
14643
14643
  ERROR_CATEGORY: "glasstrace.error.category",
14644
14644
  ERROR_FIELD: "glasstrace.error.field",
14645
+ // Error evidence v1 (SDK-041 / DISC-1535).
14646
+ // Additive to the existing `glasstrace.error.*` family. Bounded
14647
+ // stacktrace input for the product-side StackSummary parser
14648
+ // (SCHEMA-033); plus framework-fallback markers so the original
14649
+ // request path is preserved when Next.js (or another framework)
14650
+ // rewrites the route to a fallback like `/_error` or `/_not-found`;
14651
+ // plus a source-provenance enum so product can tell which surface
14652
+ // emitted each error fact (`exception.message` event vs span attr
14653
+ // vs response body vs framework runtime).
14654
+ //
14655
+ // Wire keys remain in `glasstrace.error.*` for namespace consistency
14656
+ // with the Tier-1 `error.message` / `error.code` / `error.category`
14657
+ // attributes already in this registry.
14658
+ ERROR_STACK: "glasstrace.error.stack",
14659
+ ERROR_STACK_TRUNCATED: "glasstrace.error.stack.truncated",
14660
+ ERROR_STACK_REDACTED: "glasstrace.error.stack.redacted",
14661
+ ERROR_SOURCE: "glasstrace.error.source",
14662
+ ERROR_FRAMEWORK_KIND: "glasstrace.error.framework.kind",
14663
+ ERROR_ORIGINAL_PATH: "glasstrace.error.original_path",
14664
+ ERROR_FALLBACK_ROUTE: "glasstrace.error.fallback_route",
14645
14665
  ORM_PROVIDER: "glasstrace.orm.provider",
14646
14666
  ORM_MODEL: "glasstrace.orm.model",
14647
14667
  ORM_OPERATION: "glasstrace.orm.operation",
@@ -18556,6 +18576,119 @@ function prepareErrorResponseBody(body) {
18556
18576
  return truncateErrorResponseBody(sanitized);
18557
18577
  }
18558
18578
 
18579
+ // src/error-stack.ts
18580
+ var ERROR_STACK_MAX_BYTES = 8192;
18581
+ var ERROR_STACK_TRUNCATION_MARKER = "...[stack truncated]";
18582
+ var PATH_REDACTED = "<path>";
18583
+ var PATH_KEEP_MARKERS = [
18584
+ "node_modules",
18585
+ ".next",
18586
+ ".glasstrace",
18587
+ "src",
18588
+ "dist",
18589
+ "build",
18590
+ "lib",
18591
+ "app",
18592
+ "pages"
18593
+ ];
18594
+ var PATH_TOKEN_RE = /(?<=^|[\s(])(\/[^\s()<>]+|[A-Za-z]:\\[^\s()<>]+|file:\/\/\/[^\s()<>]+|webpack-internal:\/\/[^\s()<>]+|node:[^\s()<>]+)/g;
18595
+ var URL_QUERY_FRAGMENT_RE = /(\bhttps?:\/\/[^\s?#()<>]+)([?#][^\s()<>]*)/g;
18596
+ function normalizePathToken(token) {
18597
+ let work = token;
18598
+ if (work.startsWith("file:///")) {
18599
+ work = work.slice("file://".length);
18600
+ }
18601
+ if (work.startsWith("webpack-internal:") || work.startsWith("node:")) {
18602
+ return { token, changed: false };
18603
+ }
18604
+ const isPosixAbs = work.startsWith("/");
18605
+ const isWinAbs = /^[A-Za-z]:\\/.test(work);
18606
+ if (!isPosixAbs && !isWinAbs) {
18607
+ return { token, changed: false };
18608
+ }
18609
+ const sep = isWinAbs ? "\\" : "/";
18610
+ let bestIdx = -1;
18611
+ for (const marker of PATH_KEEP_MARKERS) {
18612
+ const needle = `${sep}${marker}${sep}`;
18613
+ const idx = work.lastIndexOf(needle);
18614
+ if (idx >= 0) {
18615
+ bestIdx = idx;
18616
+ break;
18617
+ }
18618
+ }
18619
+ if (bestIdx >= 0) {
18620
+ const kept = work.slice(bestIdx + sep.length);
18621
+ const rebuilt2 = `${PATH_REDACTED}/${kept.replace(/\\/g, "/")}`;
18622
+ return { token: rebuilt2, changed: true };
18623
+ }
18624
+ const colonLineRe = /:\d+(?::\d+)?$/;
18625
+ const lineMatch = colonLineRe.exec(work);
18626
+ const pathBody = lineMatch ? work.slice(0, lineMatch.index) : work;
18627
+ const lineSuffix = lineMatch ? work.slice(lineMatch.index) : "";
18628
+ const lastSep = Math.max(pathBody.lastIndexOf("/"), pathBody.lastIndexOf("\\"));
18629
+ const basename = lastSep >= 0 ? pathBody.slice(lastSep + 1) : pathBody;
18630
+ const rebuilt = `${PATH_REDACTED}/${basename}${lineSuffix}`;
18631
+ return { token: rebuilt, changed: true };
18632
+ }
18633
+ function sanitizeStack(stack) {
18634
+ let changed = false;
18635
+ const pathNormalized = stack.replace(PATH_TOKEN_RE, (token) => {
18636
+ const out = normalizePathToken(token);
18637
+ if (out.changed) changed = true;
18638
+ return out.token;
18639
+ });
18640
+ const urlStripped = pathNormalized.replace(URL_QUERY_FRAGMENT_RE, (match, prefix) => {
18641
+ if (match !== prefix) changed = true;
18642
+ return prefix;
18643
+ });
18644
+ const credentialRedacted = sanitizeErrorResponseBody(urlStripped);
18645
+ if (credentialRedacted !== urlStripped) changed = true;
18646
+ return { stack: credentialRedacted, redacted: changed };
18647
+ }
18648
+ function truncateStack(stack) {
18649
+ const encoder = new TextEncoder();
18650
+ const encoded = encoder.encode(stack);
18651
+ if (encoded.byteLength <= ERROR_STACK_MAX_BYTES) {
18652
+ return { stack, truncated: false };
18653
+ }
18654
+ let cut = ERROR_STACK_MAX_BYTES;
18655
+ let scan = cut - 1;
18656
+ while (scan >= 0 && (encoded[scan] & 192) === 128) {
18657
+ scan -= 1;
18658
+ }
18659
+ if (scan >= 0) {
18660
+ const leading = encoded[scan];
18661
+ let expected = 1;
18662
+ if ((leading & 128) === 0) {
18663
+ expected = 1;
18664
+ } else if ((leading & 224) === 192) {
18665
+ expected = 2;
18666
+ } else if ((leading & 240) === 224) {
18667
+ expected = 3;
18668
+ } else if ((leading & 248) === 240) {
18669
+ expected = 4;
18670
+ }
18671
+ if (scan + expected > cut) {
18672
+ cut = scan;
18673
+ }
18674
+ }
18675
+ const decoder = new TextDecoder("utf-8", { fatal: false });
18676
+ const sliced = encoded.subarray(0, cut);
18677
+ const decoded = decoder.decode(sliced);
18678
+ return { stack: decoded + ERROR_STACK_TRUNCATION_MARKER, truncated: true };
18679
+ }
18680
+ function prepareStack(stack) {
18681
+ if (stack.length === 0) return null;
18682
+ if (stack.trim().length === 0) return null;
18683
+ const sanitized = sanitizeStack(stack);
18684
+ const truncated = truncateStack(sanitized.stack);
18685
+ return {
18686
+ stack: truncated.stack,
18687
+ truncated: truncated.truncated,
18688
+ redacted: sanitized.redacted
18689
+ };
18690
+ }
18691
+
18559
18692
  // src/build-info.ts
18560
18693
  init_console_capture();
18561
18694
  var UNSET = "";
@@ -18714,10 +18847,10 @@ var GlasstraceExporter = class {
18714
18847
  if (route) {
18715
18848
  extra[ATTR2.ROUTE] = route;
18716
18849
  }
18717
- const rawUrl = attrs["http.url"] ?? attrs["url.full"] ?? attrs["http.target"];
18718
- const trpcUrl = typeof rawUrl === "string" ? rawUrl : void 0;
18719
- if (trpcUrl) {
18720
- const trpcMatch = trpcUrl.match(/\/api\/trpc\/([^/?#]+)/);
18850
+ const rawUrlAttr = attrs["http.url"] ?? attrs["url.full"] ?? attrs["http.target"];
18851
+ const rawHttpUrl = typeof rawUrlAttr === "string" ? rawUrlAttr : void 0;
18852
+ if (rawHttpUrl) {
18853
+ const trpcMatch = rawHttpUrl.match(/\/api\/trpc\/([^/?#]+)/);
18721
18854
  if (trpcMatch) {
18722
18855
  let procedure;
18723
18856
  try {
@@ -18788,24 +18921,56 @@ var GlasstraceExporter = class {
18788
18921
  extra[ATTR2.HTTP_DURATION_MS] = durationMs;
18789
18922
  }
18790
18923
  }
18791
- const eventDetails = statusNotExplicitlyOK ? getExceptionEventDetails(span) : { type: void 0, message: void 0 };
18792
- const errorMessage = attrs["exception.message"];
18793
- if (typeof errorMessage === "string") {
18794
- extra[ATTR2.ERROR_MESSAGE] = errorMessage;
18795
- } else if (eventDetails.message) {
18924
+ const eventDetails = statusNotExplicitlyOK ? getExceptionEventDetails(span) : { type: void 0, message: void 0, stacktrace: void 0 };
18925
+ let errorSource;
18926
+ const attrMessage = attrs["exception.message"];
18927
+ if (eventDetails.message) {
18796
18928
  extra[ATTR2.ERROR_MESSAGE] = eventDetails.message;
18929
+ errorSource = "otel_exception";
18930
+ } else if (typeof attrMessage === "string") {
18931
+ extra[ATTR2.ERROR_MESSAGE] = attrMessage;
18932
+ errorSource = "otel_event";
18797
18933
  }
18798
- const errorType = attrs["exception.type"];
18799
- if (typeof errorType === "string") {
18800
- extra[ATTR2.ERROR_CODE] = errorType;
18801
- extra[ATTR2.ERROR_CATEGORY] = deriveErrorCategory(errorType);
18802
- } else if (eventDetails.type) {
18934
+ const attrType = attrs["exception.type"];
18935
+ if (eventDetails.type) {
18803
18936
  extra[ATTR2.ERROR_CODE] = eventDetails.type;
18804
18937
  extra[ATTR2.ERROR_CATEGORY] = deriveErrorCategory(eventDetails.type);
18938
+ errorSource = errorSource ?? "otel_exception";
18939
+ } else if (typeof attrType === "string") {
18940
+ extra[ATTR2.ERROR_CODE] = attrType;
18941
+ extra[ATTR2.ERROR_CATEGORY] = deriveErrorCategory(attrType);
18942
+ errorSource = errorSource ?? "otel_event";
18943
+ }
18944
+ if (statusNotExplicitlyOK) {
18945
+ const rawStack = eventDetails.stacktrace ?? (typeof attrs["exception.stacktrace"] === "string" ? attrs["exception.stacktrace"] : void 0);
18946
+ if (rawStack) {
18947
+ const prepared = prepareStack(rawStack);
18948
+ if (prepared !== null) {
18949
+ extra[ATTR2.ERROR_STACK] = prepared.stack;
18950
+ extra[ATTR2.ERROR_STACK_TRUNCATED] = prepared.truncated;
18951
+ extra[ATTR2.ERROR_STACK_REDACTED] = prepared.redacted;
18952
+ errorSource = errorSource ?? (eventDetails.stacktrace ? "otel_exception" : "otel_event");
18953
+ }
18954
+ }
18955
+ }
18956
+ const routeIsFallback = route === "/_error" || route === "/_not-found" || route === "/_404" || route === "/_500";
18957
+ if (routeIsFallback && rawHttpUrl) {
18958
+ const originalPath = extractPathOnly(rawHttpUrl);
18959
+ const normOriginal = stripTrailingSlash(originalPath);
18960
+ const normRoute = stripTrailingSlash(route);
18961
+ if (normOriginal && normOriginal !== normRoute) {
18962
+ extra[ATTR2.ERROR_ORIGINAL_PATH] = normOriginal;
18963
+ extra[ATTR2.ERROR_FALLBACK_ROUTE] = route;
18964
+ extra[ATTR2.ERROR_FRAMEWORK_KIND] = "fallback";
18965
+ errorSource = errorSource ?? "framework_fallback";
18966
+ }
18967
+ }
18968
+ if (errorSource !== void 0) {
18969
+ extra[ATTR2.ERROR_SOURCE] = errorSource;
18805
18970
  }
18806
18971
  if (this.verbose && (extra[ATTR2.ERROR_MESSAGE] || extra[ATTR2.ERROR_CODE])) {
18807
- const msgSource = typeof errorMessage === "string" ? "attrs" : eventDetails.message ? "event" : "none";
18808
- const typeSource = typeof errorType === "string" ? "attrs" : eventDetails.type ? "event" : "none";
18972
+ const msgSource = eventDetails.message ? "event" : typeof attrMessage === "string" ? "attrs" : "none";
18973
+ const typeSource = eventDetails.type ? "event" : typeof attrType === "string" ? "attrs" : "none";
18809
18974
  sdkLog(
18810
18975
  "info",
18811
18976
  `[glasstrace] enrichSpan "${name}": error.message source=${msgSource}, error.code source=${typeSource}`
@@ -18951,13 +19116,15 @@ function hasExceptionEvent(span) {
18951
19116
  function getExceptionEventDetails(span) {
18952
19117
  const event = span.events?.find((e) => e.name === "exception");
18953
19118
  if (!event?.attributes) {
18954
- return { type: void 0, message: void 0 };
19119
+ return { type: void 0, message: void 0, stacktrace: void 0 };
18955
19120
  }
18956
19121
  const type = event.attributes["exception.type"];
18957
19122
  const message = event.attributes["exception.message"];
19123
+ const stacktrace = event.attributes["exception.stacktrace"];
18958
19124
  return {
18959
19125
  type: typeof type === "string" ? type : void 0,
18960
- message: typeof message === "string" ? message : void 0
19126
+ message: typeof message === "string" ? message : void 0,
19127
+ stacktrace: typeof stacktrace === "string" ? stacktrace : void 0
18961
19128
  };
18962
19129
  }
18963
19130
  function extractLeadingPath(raw) {
@@ -18975,6 +19142,36 @@ function extractLeadingPath(raw) {
18975
19142
  }
18976
19143
  return void 0;
18977
19144
  }
19145
+ function stripTrailingSlash(path5) {
19146
+ if (!path5) return path5;
19147
+ if (path5 === "/") return path5;
19148
+ return path5.endsWith("/") ? path5.slice(0, -1) : path5;
19149
+ }
19150
+ function extractPathOnly(raw) {
19151
+ if (!raw) return void 0;
19152
+ const trimmed = raw.trim();
19153
+ if (trimmed.length === 0) return void 0;
19154
+ const isAbsoluteUrl = /^https?:\/\//i.test(trimmed);
19155
+ const isProtocolRelative = trimmed.startsWith("//");
19156
+ if (isAbsoluteUrl || isProtocolRelative) {
19157
+ try {
19158
+ const parsed = new URL(trimmed, "http://_/");
19159
+ if (parsed.pathname && parsed.pathname.startsWith("/")) {
19160
+ return parsed.pathname;
19161
+ }
19162
+ } catch {
19163
+ }
19164
+ }
19165
+ if (trimmed.startsWith("/")) {
19166
+ const queryIdx = trimmed.indexOf("?");
19167
+ const fragIdx = trimmed.indexOf("#");
19168
+ let cut = trimmed.length;
19169
+ if (queryIdx >= 0) cut = Math.min(cut, queryIdx);
19170
+ if (fragIdx >= 0) cut = Math.min(cut, fragIdx);
19171
+ return trimmed.slice(0, cut);
19172
+ }
19173
+ return void 0;
19174
+ }
18978
19175
  function deriveOrmProvider(instrumentationName) {
18979
19176
  const lower = instrumentationName.toLowerCase();
18980
19177
  if (lower.includes("prisma")) {
@@ -22960,11 +23157,11 @@ function registerGlasstrace(options) {
22960
23157
  setCoreState(CoreState.REGISTERING);
22961
23158
  maybeWarnStaleAgentInstructions({
22962
23159
  projectRoot: process.cwd(),
22963
- sdkVersion: "1.5.1"
23160
+ sdkVersion: "1.6.0"
22964
23161
  });
22965
23162
  startRuntimeStateWriter({
22966
23163
  projectRoot: process.cwd(),
22967
- sdkVersion: "1.5.1"
23164
+ sdkVersion: "1.6.0"
22968
23165
  });
22969
23166
  const config2 = resolveConfig(options);
22970
23167
  if (config2.verbose) {
@@ -23131,8 +23328,8 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
23131
23328
  if (config2.verbose) {
23132
23329
  console.info("[glasstrace] Background init firing.");
23133
23330
  }
23134
- const healthReport = collectHealthReport("1.5.1");
23135
- const initResult = await performInit(config2, anonKeyForInit, "1.5.1", healthReport);
23331
+ const healthReport = collectHealthReport("1.6.0");
23332
+ const initResult = await performInit(config2, anonKeyForInit, "1.6.0", healthReport);
23136
23333
  if (generation !== registrationGeneration) return;
23137
23334
  const currentState = getCoreState();
23138
23335
  if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
@@ -23155,7 +23352,7 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
23155
23352
  }
23156
23353
  maybeInstallConsoleCapture();
23157
23354
  if (didLastInitSucceed()) {
23158
- startHeartbeat(config2, anonKeyForInit, "1.5.1", generation, (newApiKey, accountId) => {
23355
+ startHeartbeat(config2, anonKeyForInit, "1.6.0", generation, (newApiKey, accountId) => {
23159
23356
  setAuthState(AuthState.CLAIMING);
23160
23357
  emitLifecycleEvent("auth:claim_started", { accountId });
23161
23358
  setResolvedApiKey(newApiKey);