@glasstrace/sdk 1.5.0 → 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-N3XIVM2U.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 +3 -2
  36. package/dist/chunk-4WI7B5FQ.js.map +0 -1
  37. package/dist/chunk-N3XIVM2U.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
@@ -2,9 +2,9 @@ import {
2
2
  GlasstraceSpanProcessor,
3
3
  SdkError,
4
4
  captureCorrelationId
5
- } from "./chunk-Q42BY5BA.js";
5
+ } from "./chunk-H57MQGNU.js";
6
6
  import "./chunk-DQ25VOKK.js";
7
- import "./chunk-4WI7B5FQ.js";
7
+ import "./chunk-P45NZR4J.js";
8
8
  import "./chunk-NSBPE2FW.js";
9
9
  export {
10
10
  GlasstraceSpanProcessor,
package/dist/index.cjs CHANGED
@@ -14639,6 +14639,26 @@ var init_dist = __esm({
14639
14639
  ERROR_CODE: "glasstrace.error.code",
14640
14640
  ERROR_CATEGORY: "glasstrace.error.category",
14641
14641
  ERROR_FIELD: "glasstrace.error.field",
14642
+ // Error evidence v1 (SDK-041 / DISC-1535).
14643
+ // Additive to the existing `glasstrace.error.*` family. Bounded
14644
+ // stacktrace input for the product-side StackSummary parser
14645
+ // (SCHEMA-033); plus framework-fallback markers so the original
14646
+ // request path is preserved when Next.js (or another framework)
14647
+ // rewrites the route to a fallback like `/_error` or `/_not-found`;
14648
+ // plus a source-provenance enum so product can tell which surface
14649
+ // emitted each error fact (`exception.message` event vs span attr
14650
+ // vs response body vs framework runtime).
14651
+ //
14652
+ // Wire keys remain in `glasstrace.error.*` for namespace consistency
14653
+ // with the Tier-1 `error.message` / `error.code` / `error.category`
14654
+ // attributes already in this registry.
14655
+ ERROR_STACK: "glasstrace.error.stack",
14656
+ ERROR_STACK_TRUNCATED: "glasstrace.error.stack.truncated",
14657
+ ERROR_STACK_REDACTED: "glasstrace.error.stack.redacted",
14658
+ ERROR_SOURCE: "glasstrace.error.source",
14659
+ ERROR_FRAMEWORK_KIND: "glasstrace.error.framework.kind",
14660
+ ERROR_ORIGINAL_PATH: "glasstrace.error.original_path",
14661
+ ERROR_FALLBACK_ROUTE: "glasstrace.error.fallback_route",
14642
14662
  ORM_PROVIDER: "glasstrace.orm.provider",
14643
14663
  ORM_MODEL: "glasstrace.orm.model",
14644
14664
  ORM_OPERATION: "glasstrace.orm.operation",
@@ -18520,6 +18540,119 @@ function prepareErrorResponseBody(body) {
18520
18540
  return truncateErrorResponseBody(sanitized);
18521
18541
  }
18522
18542
 
18543
+ // src/error-stack.ts
18544
+ var ERROR_STACK_MAX_BYTES = 8192;
18545
+ var ERROR_STACK_TRUNCATION_MARKER = "...[stack truncated]";
18546
+ var PATH_REDACTED = "<path>";
18547
+ var PATH_KEEP_MARKERS = [
18548
+ "node_modules",
18549
+ ".next",
18550
+ ".glasstrace",
18551
+ "src",
18552
+ "dist",
18553
+ "build",
18554
+ "lib",
18555
+ "app",
18556
+ "pages"
18557
+ ];
18558
+ var PATH_TOKEN_RE = /(?<=^|[\s(])(\/[^\s()<>]+|[A-Za-z]:\\[^\s()<>]+|file:\/\/\/[^\s()<>]+|webpack-internal:\/\/[^\s()<>]+|node:[^\s()<>]+)/g;
18559
+ var URL_QUERY_FRAGMENT_RE = /(\bhttps?:\/\/[^\s?#()<>]+)([?#][^\s()<>]*)/g;
18560
+ function normalizePathToken(token) {
18561
+ let work = token;
18562
+ if (work.startsWith("file:///")) {
18563
+ work = work.slice("file://".length);
18564
+ }
18565
+ if (work.startsWith("webpack-internal:") || work.startsWith("node:")) {
18566
+ return { token, changed: false };
18567
+ }
18568
+ const isPosixAbs = work.startsWith("/");
18569
+ const isWinAbs = /^[A-Za-z]:\\/.test(work);
18570
+ if (!isPosixAbs && !isWinAbs) {
18571
+ return { token, changed: false };
18572
+ }
18573
+ const sep = isWinAbs ? "\\" : "/";
18574
+ let bestIdx = -1;
18575
+ for (const marker of PATH_KEEP_MARKERS) {
18576
+ const needle = `${sep}${marker}${sep}`;
18577
+ const idx = work.lastIndexOf(needle);
18578
+ if (idx >= 0) {
18579
+ bestIdx = idx;
18580
+ break;
18581
+ }
18582
+ }
18583
+ if (bestIdx >= 0) {
18584
+ const kept = work.slice(bestIdx + sep.length);
18585
+ const rebuilt2 = `${PATH_REDACTED}/${kept.replace(/\\/g, "/")}`;
18586
+ return { token: rebuilt2, changed: true };
18587
+ }
18588
+ const colonLineRe = /:\d+(?::\d+)?$/;
18589
+ const lineMatch = colonLineRe.exec(work);
18590
+ const pathBody = lineMatch ? work.slice(0, lineMatch.index) : work;
18591
+ const lineSuffix = lineMatch ? work.slice(lineMatch.index) : "";
18592
+ const lastSep = Math.max(pathBody.lastIndexOf("/"), pathBody.lastIndexOf("\\"));
18593
+ const basename = lastSep >= 0 ? pathBody.slice(lastSep + 1) : pathBody;
18594
+ const rebuilt = `${PATH_REDACTED}/${basename}${lineSuffix}`;
18595
+ return { token: rebuilt, changed: true };
18596
+ }
18597
+ function sanitizeStack(stack) {
18598
+ let changed = false;
18599
+ const pathNormalized = stack.replace(PATH_TOKEN_RE, (token) => {
18600
+ const out = normalizePathToken(token);
18601
+ if (out.changed) changed = true;
18602
+ return out.token;
18603
+ });
18604
+ const urlStripped = pathNormalized.replace(URL_QUERY_FRAGMENT_RE, (match, prefix) => {
18605
+ if (match !== prefix) changed = true;
18606
+ return prefix;
18607
+ });
18608
+ const credentialRedacted = sanitizeErrorResponseBody(urlStripped);
18609
+ if (credentialRedacted !== urlStripped) changed = true;
18610
+ return { stack: credentialRedacted, redacted: changed };
18611
+ }
18612
+ function truncateStack(stack) {
18613
+ const encoder = new TextEncoder();
18614
+ const encoded = encoder.encode(stack);
18615
+ if (encoded.byteLength <= ERROR_STACK_MAX_BYTES) {
18616
+ return { stack, truncated: false };
18617
+ }
18618
+ let cut = ERROR_STACK_MAX_BYTES;
18619
+ let scan = cut - 1;
18620
+ while (scan >= 0 && (encoded[scan] & 192) === 128) {
18621
+ scan -= 1;
18622
+ }
18623
+ if (scan >= 0) {
18624
+ const leading = encoded[scan];
18625
+ let expected = 1;
18626
+ if ((leading & 128) === 0) {
18627
+ expected = 1;
18628
+ } else if ((leading & 224) === 192) {
18629
+ expected = 2;
18630
+ } else if ((leading & 240) === 224) {
18631
+ expected = 3;
18632
+ } else if ((leading & 248) === 240) {
18633
+ expected = 4;
18634
+ }
18635
+ if (scan + expected > cut) {
18636
+ cut = scan;
18637
+ }
18638
+ }
18639
+ const decoder = new TextDecoder("utf-8", { fatal: false });
18640
+ const sliced = encoded.subarray(0, cut);
18641
+ const decoded = decoder.decode(sliced);
18642
+ return { stack: decoded + ERROR_STACK_TRUNCATION_MARKER, truncated: true };
18643
+ }
18644
+ function prepareStack(stack) {
18645
+ if (stack.length === 0) return null;
18646
+ if (stack.trim().length === 0) return null;
18647
+ const sanitized = sanitizeStack(stack);
18648
+ const truncated = truncateStack(sanitized.stack);
18649
+ return {
18650
+ stack: truncated.stack,
18651
+ truncated: truncated.truncated,
18652
+ redacted: sanitized.redacted
18653
+ };
18654
+ }
18655
+
18523
18656
  // src/build-info.ts
18524
18657
  init_console_capture();
18525
18658
  var UNSET = "";
@@ -18678,10 +18811,10 @@ var GlasstraceExporter = class {
18678
18811
  if (route) {
18679
18812
  extra[ATTR.ROUTE] = route;
18680
18813
  }
18681
- const rawUrl = attrs["http.url"] ?? attrs["url.full"] ?? attrs["http.target"];
18682
- const trpcUrl = typeof rawUrl === "string" ? rawUrl : void 0;
18683
- if (trpcUrl) {
18684
- const trpcMatch = trpcUrl.match(/\/api\/trpc\/([^/?#]+)/);
18814
+ const rawUrlAttr = attrs["http.url"] ?? attrs["url.full"] ?? attrs["http.target"];
18815
+ const rawHttpUrl = typeof rawUrlAttr === "string" ? rawUrlAttr : void 0;
18816
+ if (rawHttpUrl) {
18817
+ const trpcMatch = rawHttpUrl.match(/\/api\/trpc\/([^/?#]+)/);
18685
18818
  if (trpcMatch) {
18686
18819
  let procedure;
18687
18820
  try {
@@ -18752,24 +18885,56 @@ var GlasstraceExporter = class {
18752
18885
  extra[ATTR.HTTP_DURATION_MS] = durationMs;
18753
18886
  }
18754
18887
  }
18755
- const eventDetails = statusNotExplicitlyOK ? getExceptionEventDetails(span) : { type: void 0, message: void 0 };
18756
- const errorMessage = attrs["exception.message"];
18757
- if (typeof errorMessage === "string") {
18758
- extra[ATTR.ERROR_MESSAGE] = errorMessage;
18759
- } else if (eventDetails.message) {
18888
+ const eventDetails = statusNotExplicitlyOK ? getExceptionEventDetails(span) : { type: void 0, message: void 0, stacktrace: void 0 };
18889
+ let errorSource;
18890
+ const attrMessage = attrs["exception.message"];
18891
+ if (eventDetails.message) {
18760
18892
  extra[ATTR.ERROR_MESSAGE] = eventDetails.message;
18893
+ errorSource = "otel_exception";
18894
+ } else if (typeof attrMessage === "string") {
18895
+ extra[ATTR.ERROR_MESSAGE] = attrMessage;
18896
+ errorSource = "otel_event";
18761
18897
  }
18762
- const errorType = attrs["exception.type"];
18763
- if (typeof errorType === "string") {
18764
- extra[ATTR.ERROR_CODE] = errorType;
18765
- extra[ATTR.ERROR_CATEGORY] = deriveErrorCategory(errorType);
18766
- } else if (eventDetails.type) {
18898
+ const attrType = attrs["exception.type"];
18899
+ if (eventDetails.type) {
18767
18900
  extra[ATTR.ERROR_CODE] = eventDetails.type;
18768
18901
  extra[ATTR.ERROR_CATEGORY] = deriveErrorCategory(eventDetails.type);
18902
+ errorSource = errorSource ?? "otel_exception";
18903
+ } else if (typeof attrType === "string") {
18904
+ extra[ATTR.ERROR_CODE] = attrType;
18905
+ extra[ATTR.ERROR_CATEGORY] = deriveErrorCategory(attrType);
18906
+ errorSource = errorSource ?? "otel_event";
18907
+ }
18908
+ if (statusNotExplicitlyOK) {
18909
+ const rawStack = eventDetails.stacktrace ?? (typeof attrs["exception.stacktrace"] === "string" ? attrs["exception.stacktrace"] : void 0);
18910
+ if (rawStack) {
18911
+ const prepared = prepareStack(rawStack);
18912
+ if (prepared !== null) {
18913
+ extra[ATTR.ERROR_STACK] = prepared.stack;
18914
+ extra[ATTR.ERROR_STACK_TRUNCATED] = prepared.truncated;
18915
+ extra[ATTR.ERROR_STACK_REDACTED] = prepared.redacted;
18916
+ errorSource = errorSource ?? (eventDetails.stacktrace ? "otel_exception" : "otel_event");
18917
+ }
18918
+ }
18919
+ }
18920
+ const routeIsFallback = route === "/_error" || route === "/_not-found" || route === "/_404" || route === "/_500";
18921
+ if (routeIsFallback && rawHttpUrl) {
18922
+ const originalPath = extractPathOnly(rawHttpUrl);
18923
+ const normOriginal = stripTrailingSlash(originalPath);
18924
+ const normRoute = stripTrailingSlash(route);
18925
+ if (normOriginal && normOriginal !== normRoute) {
18926
+ extra[ATTR.ERROR_ORIGINAL_PATH] = normOriginal;
18927
+ extra[ATTR.ERROR_FALLBACK_ROUTE] = route;
18928
+ extra[ATTR.ERROR_FRAMEWORK_KIND] = "fallback";
18929
+ errorSource = errorSource ?? "framework_fallback";
18930
+ }
18931
+ }
18932
+ if (errorSource !== void 0) {
18933
+ extra[ATTR.ERROR_SOURCE] = errorSource;
18769
18934
  }
18770
18935
  if (this.verbose && (extra[ATTR.ERROR_MESSAGE] || extra[ATTR.ERROR_CODE])) {
18771
- const msgSource = typeof errorMessage === "string" ? "attrs" : eventDetails.message ? "event" : "none";
18772
- const typeSource = typeof errorType === "string" ? "attrs" : eventDetails.type ? "event" : "none";
18936
+ const msgSource = eventDetails.message ? "event" : typeof attrMessage === "string" ? "attrs" : "none";
18937
+ const typeSource = eventDetails.type ? "event" : typeof attrType === "string" ? "attrs" : "none";
18773
18938
  sdkLog(
18774
18939
  "info",
18775
18940
  `[glasstrace] enrichSpan "${name}": error.message source=${msgSource}, error.code source=${typeSource}`
@@ -18915,13 +19080,15 @@ function hasExceptionEvent(span) {
18915
19080
  function getExceptionEventDetails(span) {
18916
19081
  const event = span.events?.find((e) => e.name === "exception");
18917
19082
  if (!event?.attributes) {
18918
- return { type: void 0, message: void 0 };
19083
+ return { type: void 0, message: void 0, stacktrace: void 0 };
18919
19084
  }
18920
19085
  const type = event.attributes["exception.type"];
18921
19086
  const message = event.attributes["exception.message"];
19087
+ const stacktrace = event.attributes["exception.stacktrace"];
18922
19088
  return {
18923
19089
  type: typeof type === "string" ? type : void 0,
18924
- message: typeof message === "string" ? message : void 0
19090
+ message: typeof message === "string" ? message : void 0,
19091
+ stacktrace: typeof stacktrace === "string" ? stacktrace : void 0
18925
19092
  };
18926
19093
  }
18927
19094
  function extractLeadingPath(raw) {
@@ -18939,6 +19106,36 @@ function extractLeadingPath(raw) {
18939
19106
  }
18940
19107
  return void 0;
18941
19108
  }
19109
+ function stripTrailingSlash(path4) {
19110
+ if (!path4) return path4;
19111
+ if (path4 === "/") return path4;
19112
+ return path4.endsWith("/") ? path4.slice(0, -1) : path4;
19113
+ }
19114
+ function extractPathOnly(raw) {
19115
+ if (!raw) return void 0;
19116
+ const trimmed = raw.trim();
19117
+ if (trimmed.length === 0) return void 0;
19118
+ const isAbsoluteUrl = /^https?:\/\//i.test(trimmed);
19119
+ const isProtocolRelative = trimmed.startsWith("//");
19120
+ if (isAbsoluteUrl || isProtocolRelative) {
19121
+ try {
19122
+ const parsed = new URL(trimmed, "http://_/");
19123
+ if (parsed.pathname && parsed.pathname.startsWith("/")) {
19124
+ return parsed.pathname;
19125
+ }
19126
+ } catch {
19127
+ }
19128
+ }
19129
+ if (trimmed.startsWith("/")) {
19130
+ const queryIdx = trimmed.indexOf("?");
19131
+ const fragIdx = trimmed.indexOf("#");
19132
+ let cut = trimmed.length;
19133
+ if (queryIdx >= 0) cut = Math.min(cut, queryIdx);
19134
+ if (fragIdx >= 0) cut = Math.min(cut, fragIdx);
19135
+ return trimmed.slice(0, cut);
19136
+ }
19137
+ return void 0;
19138
+ }
18942
19139
  function deriveOrmProvider(instrumentationName) {
18943
19140
  const lower = instrumentationName.toLowerCase();
18944
19141
  if (lower.includes("prisma")) {
@@ -22924,11 +23121,11 @@ function registerGlasstrace(options) {
22924
23121
  setCoreState(CoreState.REGISTERING);
22925
23122
  maybeWarnStaleAgentInstructions({
22926
23123
  projectRoot: process.cwd(),
22927
- sdkVersion: "1.5.0"
23124
+ sdkVersion: "1.6.0"
22928
23125
  });
22929
23126
  startRuntimeStateWriter({
22930
23127
  projectRoot: process.cwd(),
22931
- sdkVersion: "1.5.0"
23128
+ sdkVersion: "1.6.0"
22932
23129
  });
22933
23130
  const config2 = resolveConfig(options);
22934
23131
  if (config2.verbose) {
@@ -23095,8 +23292,8 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
23095
23292
  if (config2.verbose) {
23096
23293
  console.info("[glasstrace] Background init firing.");
23097
23294
  }
23098
- const healthReport = collectHealthReport("1.5.0");
23099
- const initResult = await performInit(config2, anonKeyForInit, "1.5.0", healthReport);
23295
+ const healthReport = collectHealthReport("1.6.0");
23296
+ const initResult = await performInit(config2, anonKeyForInit, "1.6.0", healthReport);
23100
23297
  if (generation !== registrationGeneration) return;
23101
23298
  const currentState = getCoreState();
23102
23299
  if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
@@ -23119,7 +23316,7 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
23119
23316
  }
23120
23317
  maybeInstallConsoleCapture();
23121
23318
  if (didLastInitSucceed()) {
23122
- startHeartbeat(config2, anonKeyForInit, "1.5.0", generation, (newApiKey, accountId) => {
23319
+ startHeartbeat(config2, anonKeyForInit, "1.6.0", generation, (newApiKey, accountId) => {
23123
23320
  setAuthState(AuthState.CLAIMING);
23124
23321
  emitLifecycleEvent("auth:claim_started", { accountId });
23125
23322
  setResolvedApiKey(newApiKey);