@glasstrace/sdk 1.5.1 → 1.6.1

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 (47) 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-D3QXU2VM.js → chunk-KI7YJ7XD.js} +2 -2
  5. package/dist/{chunk-D3QXU2VM.js.map → chunk-KI7YJ7XD.js.map} +1 -1
  6. package/dist/{chunk-TANUWTFO.js → chunk-M2TLX6NM.js} +3 -3
  7. package/dist/{chunk-MMKFFF2L.js → chunk-NN5YCETI.js} +2 -2
  8. package/dist/{chunk-4WI7B5FQ.js → chunk-P45NZR4J.js} +21 -1
  9. package/dist/chunk-P45NZR4J.js.map +1 -0
  10. package/dist/{chunk-MLRQTCCK.js → chunk-SYNQJZZY.js} +205 -28
  11. package/dist/chunk-SYNQJZZY.js.map +1 -0
  12. package/dist/{chunk-QU26IKIJ.js → chunk-UQKI476D.js} +2 -2
  13. package/dist/{chunk-MFYOQOD7.js → chunk-WL6BXEJ5.js} +2 -2
  14. package/dist/cli/init.cjs +5 -5
  15. package/dist/cli/init.cjs.map +1 -1
  16. package/dist/cli/init.js +8 -8
  17. package/dist/cli/mcp-add.cjs +2 -2
  18. package/dist/cli/mcp-add.cjs.map +1 -1
  19. package/dist/cli/mcp-add.js +4 -4
  20. package/dist/cli/uninit.js +3 -3
  21. package/dist/cli/upgrade-instructions.cjs +2 -2
  22. package/dist/cli/upgrade-instructions.cjs.map +1 -1
  23. package/dist/cli/upgrade-instructions.js +4 -4
  24. package/dist/cli/validate.cjs.map +1 -1
  25. package/dist/cli/validate.js +2 -2
  26. package/dist/edge-entry.cjs +20 -0
  27. package/dist/edge-entry.cjs.map +1 -1
  28. package/dist/edge-entry.js +2 -2
  29. package/dist/index.cjs +220 -23
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.js +5 -5
  32. package/dist/node-entry.cjs +220 -23
  33. package/dist/node-entry.cjs.map +1 -1
  34. package/dist/node-entry.js +7 -7
  35. package/dist/node-subpath.cjs.map +1 -1
  36. package/dist/node-subpath.js +3 -3
  37. package/dist/{source-map-uploader-PB3M4PPP.js → source-map-uploader-XFUEVV7I.js} +3 -3
  38. package/package.json +1 -1
  39. package/dist/chunk-4WI7B5FQ.js.map +0 -1
  40. package/dist/chunk-MLRQTCCK.js.map +0 -1
  41. /package/dist/{chunk-YLY7AGLC.js.map → chunk-3PJP5Y3U.js.map} +0 -0
  42. /package/dist/{chunk-Q42BY5BA.js.map → chunk-H57MQGNU.js.map} +0 -0
  43. /package/dist/{chunk-TANUWTFO.js.map → chunk-M2TLX6NM.js.map} +0 -0
  44. /package/dist/{chunk-MMKFFF2L.js.map → chunk-NN5YCETI.js.map} +0 -0
  45. /package/dist/{chunk-QU26IKIJ.js.map → chunk-UQKI476D.js.map} +0 -0
  46. /package/dist/{chunk-MFYOQOD7.js.map → chunk-WL6BXEJ5.js.map} +0 -0
  47. /package/dist/{source-map-uploader-PB3M4PPP.js.map → source-map-uploader-XFUEVV7I.js.map} +0 -0
@@ -33,7 +33,7 @@ import {
33
33
  performInit,
34
34
  recordSpansDropped,
35
35
  recordSpansExported
36
- } from "./chunk-TANUWTFO.js";
36
+ } from "./chunk-M2TLX6NM.js";
37
37
  import {
38
38
  isAnonymousMode,
39
39
  isProductionDisabled,
@@ -44,11 +44,11 @@ import {
44
44
  getOrCreateAnonKey,
45
45
  isSyncFsAvailable,
46
46
  readAnonKey
47
- } from "./chunk-MFYOQOD7.js";
47
+ } from "./chunk-WL6BXEJ5.js";
48
48
  import {
49
49
  GLASSTRACE_ATTRIBUTE_NAMES,
50
50
  deriveSessionId
51
- } from "./chunk-4WI7B5FQ.js";
51
+ } from "./chunk-P45NZR4J.js";
52
52
  import {
53
53
  isEndMarkerLine,
54
54
  parseStartMarkerLine
@@ -269,6 +269,119 @@ function prepareErrorResponseBody(body) {
269
269
  return truncateErrorResponseBody(sanitized);
270
270
  }
271
271
 
272
+ // src/error-stack.ts
273
+ var ERROR_STACK_MAX_BYTES = 8192;
274
+ var ERROR_STACK_TRUNCATION_MARKER = "...[stack truncated]";
275
+ var PATH_REDACTED = "<path>";
276
+ var PATH_KEEP_MARKERS = [
277
+ "node_modules",
278
+ ".next",
279
+ ".glasstrace",
280
+ "src",
281
+ "dist",
282
+ "build",
283
+ "lib",
284
+ "app",
285
+ "pages"
286
+ ];
287
+ var PATH_TOKEN_RE = /(?<=^|[\s(])(\/[^\s()<>]+|[A-Za-z]:\\[^\s()<>]+|file:\/\/\/[^\s()<>]+|webpack-internal:\/\/[^\s()<>]+|node:[^\s()<>]+)/g;
288
+ var URL_QUERY_FRAGMENT_RE = /(\bhttps?:\/\/[^\s?#()<>]+)([?#][^\s()<>]*)/g;
289
+ function normalizePathToken(token) {
290
+ let work = token;
291
+ if (work.startsWith("file:///")) {
292
+ work = work.slice("file://".length);
293
+ }
294
+ if (work.startsWith("webpack-internal:") || work.startsWith("node:")) {
295
+ return { token, changed: false };
296
+ }
297
+ const isPosixAbs = work.startsWith("/");
298
+ const isWinAbs = /^[A-Za-z]:\\/.test(work);
299
+ if (!isPosixAbs && !isWinAbs) {
300
+ return { token, changed: false };
301
+ }
302
+ const sep = isWinAbs ? "\\" : "/";
303
+ let bestIdx = -1;
304
+ for (const marker of PATH_KEEP_MARKERS) {
305
+ const needle = `${sep}${marker}${sep}`;
306
+ const idx = work.lastIndexOf(needle);
307
+ if (idx >= 0) {
308
+ bestIdx = idx;
309
+ break;
310
+ }
311
+ }
312
+ if (bestIdx >= 0) {
313
+ const kept = work.slice(bestIdx + sep.length);
314
+ const rebuilt2 = `${PATH_REDACTED}/${kept.replace(/\\/g, "/")}`;
315
+ return { token: rebuilt2, changed: true };
316
+ }
317
+ const colonLineRe = /:\d+(?::\d+)?$/;
318
+ const lineMatch = colonLineRe.exec(work);
319
+ const pathBody = lineMatch ? work.slice(0, lineMatch.index) : work;
320
+ const lineSuffix = lineMatch ? work.slice(lineMatch.index) : "";
321
+ const lastSep = Math.max(pathBody.lastIndexOf("/"), pathBody.lastIndexOf("\\"));
322
+ const basename = lastSep >= 0 ? pathBody.slice(lastSep + 1) : pathBody;
323
+ const rebuilt = `${PATH_REDACTED}/${basename}${lineSuffix}`;
324
+ return { token: rebuilt, changed: true };
325
+ }
326
+ function sanitizeStack(stack) {
327
+ let changed = false;
328
+ const pathNormalized = stack.replace(PATH_TOKEN_RE, (token) => {
329
+ const out = normalizePathToken(token);
330
+ if (out.changed) changed = true;
331
+ return out.token;
332
+ });
333
+ const urlStripped = pathNormalized.replace(URL_QUERY_FRAGMENT_RE, (match, prefix) => {
334
+ if (match !== prefix) changed = true;
335
+ return prefix;
336
+ });
337
+ const credentialRedacted = sanitizeErrorResponseBody(urlStripped);
338
+ if (credentialRedacted !== urlStripped) changed = true;
339
+ return { stack: credentialRedacted, redacted: changed };
340
+ }
341
+ function truncateStack(stack) {
342
+ const encoder = new TextEncoder();
343
+ const encoded = encoder.encode(stack);
344
+ if (encoded.byteLength <= ERROR_STACK_MAX_BYTES) {
345
+ return { stack, truncated: false };
346
+ }
347
+ let cut = ERROR_STACK_MAX_BYTES;
348
+ let scan = cut - 1;
349
+ while (scan >= 0 && (encoded[scan] & 192) === 128) {
350
+ scan -= 1;
351
+ }
352
+ if (scan >= 0) {
353
+ const leading = encoded[scan];
354
+ let expected = 1;
355
+ if ((leading & 128) === 0) {
356
+ expected = 1;
357
+ } else if ((leading & 224) === 192) {
358
+ expected = 2;
359
+ } else if ((leading & 240) === 224) {
360
+ expected = 3;
361
+ } else if ((leading & 248) === 240) {
362
+ expected = 4;
363
+ }
364
+ if (scan + expected > cut) {
365
+ cut = scan;
366
+ }
367
+ }
368
+ const decoder = new TextDecoder("utf-8", { fatal: false });
369
+ const sliced = encoded.subarray(0, cut);
370
+ const decoded = decoder.decode(sliced);
371
+ return { stack: decoded + ERROR_STACK_TRUNCATION_MARKER, truncated: true };
372
+ }
373
+ function prepareStack(stack) {
374
+ if (stack.length === 0) return null;
375
+ if (stack.trim().length === 0) return null;
376
+ const sanitized = sanitizeStack(stack);
377
+ const truncated = truncateStack(sanitized.stack);
378
+ return {
379
+ stack: truncated.stack,
380
+ truncated: truncated.truncated,
381
+ redacted: sanitized.redacted
382
+ };
383
+ }
384
+
272
385
  // src/build-info.ts
273
386
  var UNSET = "";
274
387
  var SHA_SHAPE = /^[0-9a-f]{7,64}$/i;
@@ -426,10 +539,10 @@ var GlasstraceExporter = class {
426
539
  if (route) {
427
540
  extra[ATTR.ROUTE] = route;
428
541
  }
429
- const rawUrl = attrs["http.url"] ?? attrs["url.full"] ?? attrs["http.target"];
430
- const trpcUrl = typeof rawUrl === "string" ? rawUrl : void 0;
431
- if (trpcUrl) {
432
- const trpcMatch = trpcUrl.match(/\/api\/trpc\/([^/?#]+)/);
542
+ const rawUrlAttr = attrs["http.url"] ?? attrs["url.full"] ?? attrs["http.target"];
543
+ const rawHttpUrl = typeof rawUrlAttr === "string" ? rawUrlAttr : void 0;
544
+ if (rawHttpUrl) {
545
+ const trpcMatch = rawHttpUrl.match(/\/api\/trpc\/([^/?#]+)/);
433
546
  if (trpcMatch) {
434
547
  let procedure;
435
548
  try {
@@ -500,24 +613,56 @@ var GlasstraceExporter = class {
500
613
  extra[ATTR.HTTP_DURATION_MS] = durationMs;
501
614
  }
502
615
  }
503
- const eventDetails = statusNotExplicitlyOK ? getExceptionEventDetails(span) : { type: void 0, message: void 0 };
504
- const errorMessage = attrs["exception.message"];
505
- if (typeof errorMessage === "string") {
506
- extra[ATTR.ERROR_MESSAGE] = errorMessage;
507
- } else if (eventDetails.message) {
616
+ const eventDetails = statusNotExplicitlyOK ? getExceptionEventDetails(span) : { type: void 0, message: void 0, stacktrace: void 0 };
617
+ let errorSource;
618
+ const attrMessage = attrs["exception.message"];
619
+ if (eventDetails.message) {
508
620
  extra[ATTR.ERROR_MESSAGE] = eventDetails.message;
621
+ errorSource = "otel_exception";
622
+ } else if (typeof attrMessage === "string") {
623
+ extra[ATTR.ERROR_MESSAGE] = attrMessage;
624
+ errorSource = "otel_event";
509
625
  }
510
- const errorType = attrs["exception.type"];
511
- if (typeof errorType === "string") {
512
- extra[ATTR.ERROR_CODE] = errorType;
513
- extra[ATTR.ERROR_CATEGORY] = deriveErrorCategory(errorType);
514
- } else if (eventDetails.type) {
626
+ const attrType = attrs["exception.type"];
627
+ if (eventDetails.type) {
515
628
  extra[ATTR.ERROR_CODE] = eventDetails.type;
516
629
  extra[ATTR.ERROR_CATEGORY] = deriveErrorCategory(eventDetails.type);
630
+ errorSource = errorSource ?? "otel_exception";
631
+ } else if (typeof attrType === "string") {
632
+ extra[ATTR.ERROR_CODE] = attrType;
633
+ extra[ATTR.ERROR_CATEGORY] = deriveErrorCategory(attrType);
634
+ errorSource = errorSource ?? "otel_event";
635
+ }
636
+ if (statusNotExplicitlyOK) {
637
+ const rawStack = eventDetails.stacktrace ?? (typeof attrs["exception.stacktrace"] === "string" ? attrs["exception.stacktrace"] : void 0);
638
+ if (rawStack) {
639
+ const prepared = prepareStack(rawStack);
640
+ if (prepared !== null) {
641
+ extra[ATTR.ERROR_STACK] = prepared.stack;
642
+ extra[ATTR.ERROR_STACK_TRUNCATED] = prepared.truncated;
643
+ extra[ATTR.ERROR_STACK_REDACTED] = prepared.redacted;
644
+ errorSource = errorSource ?? (eventDetails.stacktrace ? "otel_exception" : "otel_event");
645
+ }
646
+ }
647
+ }
648
+ const routeIsFallback = route === "/_error" || route === "/_not-found" || route === "/_404" || route === "/_500";
649
+ if (routeIsFallback && rawHttpUrl) {
650
+ const originalPath = extractPathOnly(rawHttpUrl);
651
+ const normOriginal = stripTrailingSlash(originalPath);
652
+ const normRoute = stripTrailingSlash(route);
653
+ if (normOriginal && normOriginal !== normRoute) {
654
+ extra[ATTR.ERROR_ORIGINAL_PATH] = normOriginal;
655
+ extra[ATTR.ERROR_FALLBACK_ROUTE] = route;
656
+ extra[ATTR.ERROR_FRAMEWORK_KIND] = "fallback";
657
+ errorSource = errorSource ?? "framework_fallback";
658
+ }
659
+ }
660
+ if (errorSource !== void 0) {
661
+ extra[ATTR.ERROR_SOURCE] = errorSource;
517
662
  }
518
663
  if (this.verbose && (extra[ATTR.ERROR_MESSAGE] || extra[ATTR.ERROR_CODE])) {
519
- const msgSource = typeof errorMessage === "string" ? "attrs" : eventDetails.message ? "event" : "none";
520
- const typeSource = typeof errorType === "string" ? "attrs" : eventDetails.type ? "event" : "none";
664
+ const msgSource = eventDetails.message ? "event" : typeof attrMessage === "string" ? "attrs" : "none";
665
+ const typeSource = eventDetails.type ? "event" : typeof attrType === "string" ? "attrs" : "none";
521
666
  sdkLog(
522
667
  "info",
523
668
  `[glasstrace] enrichSpan "${name}": error.message source=${msgSource}, error.code source=${typeSource}`
@@ -663,13 +808,15 @@ function hasExceptionEvent(span) {
663
808
  function getExceptionEventDetails(span) {
664
809
  const event = span.events?.find((e) => e.name === "exception");
665
810
  if (!event?.attributes) {
666
- return { type: void 0, message: void 0 };
811
+ return { type: void 0, message: void 0, stacktrace: void 0 };
667
812
  }
668
813
  const type = event.attributes["exception.type"];
669
814
  const message = event.attributes["exception.message"];
815
+ const stacktrace = event.attributes["exception.stacktrace"];
670
816
  return {
671
817
  type: typeof type === "string" ? type : void 0,
672
- message: typeof message === "string" ? message : void 0
818
+ message: typeof message === "string" ? message : void 0,
819
+ stacktrace: typeof stacktrace === "string" ? stacktrace : void 0
673
820
  };
674
821
  }
675
822
  function extractLeadingPath(raw) {
@@ -687,6 +834,36 @@ function extractLeadingPath(raw) {
687
834
  }
688
835
  return void 0;
689
836
  }
837
+ function stripTrailingSlash(path3) {
838
+ if (!path3) return path3;
839
+ if (path3 === "/") return path3;
840
+ return path3.endsWith("/") ? path3.slice(0, -1) : path3;
841
+ }
842
+ function extractPathOnly(raw) {
843
+ if (!raw) return void 0;
844
+ const trimmed = raw.trim();
845
+ if (trimmed.length === 0) return void 0;
846
+ const isAbsoluteUrl = /^https?:\/\//i.test(trimmed);
847
+ const isProtocolRelative = trimmed.startsWith("//");
848
+ if (isAbsoluteUrl || isProtocolRelative) {
849
+ try {
850
+ const parsed = new URL(trimmed, "http://_/");
851
+ if (parsed.pathname && parsed.pathname.startsWith("/")) {
852
+ return parsed.pathname;
853
+ }
854
+ } catch {
855
+ }
856
+ }
857
+ if (trimmed.startsWith("/")) {
858
+ const queryIdx = trimmed.indexOf("?");
859
+ const fragIdx = trimmed.indexOf("#");
860
+ let cut = trimmed.length;
861
+ if (queryIdx >= 0) cut = Math.min(cut, queryIdx);
862
+ if (fragIdx >= 0) cut = Math.min(cut, fragIdx);
863
+ return trimmed.slice(0, cut);
864
+ }
865
+ return void 0;
866
+ }
690
867
  function deriveOrmProvider(instrumentationName) {
691
868
  const lower = instrumentationName.toLowerCase();
692
869
  if (lower.includes("prisma")) {
@@ -4439,11 +4616,11 @@ function registerGlasstrace(options) {
4439
4616
  setCoreState(CoreState.REGISTERING);
4440
4617
  maybeWarnStaleAgentInstructions({
4441
4618
  projectRoot: process.cwd(),
4442
- sdkVersion: "1.5.1"
4619
+ sdkVersion: "1.6.1"
4443
4620
  });
4444
4621
  startRuntimeStateWriter({
4445
4622
  projectRoot: process.cwd(),
4446
- sdkVersion: "1.5.1"
4623
+ sdkVersion: "1.6.1"
4447
4624
  });
4448
4625
  const config = resolveConfig(options);
4449
4626
  if (config.verbose) {
@@ -4610,8 +4787,8 @@ async function backgroundInit(config, anonKeyForInit, generation) {
4610
4787
  if (config.verbose) {
4611
4788
  console.info("[glasstrace] Background init firing.");
4612
4789
  }
4613
- const healthReport = collectHealthReport("1.5.1");
4614
- const initResult = await performInit(config, anonKeyForInit, "1.5.1", healthReport);
4790
+ const healthReport = collectHealthReport("1.6.1");
4791
+ const initResult = await performInit(config, anonKeyForInit, "1.6.1", healthReport);
4615
4792
  if (generation !== registrationGeneration) return;
4616
4793
  const currentState = getCoreState();
4617
4794
  if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
@@ -4634,7 +4811,7 @@ async function backgroundInit(config, anonKeyForInit, generation) {
4634
4811
  }
4635
4812
  maybeInstallConsoleCapture();
4636
4813
  if (didLastInitSucceed()) {
4637
- startHeartbeat(config, anonKeyForInit, "1.5.1", generation, (newApiKey, accountId) => {
4814
+ startHeartbeat(config, anonKeyForInit, "1.6.1", generation, (newApiKey, accountId) => {
4638
4815
  setAuthState(AuthState.CLAIMING);
4639
4816
  emitLifecycleEvent("auth:claim_started", { accountId });
4640
4817
  setResolvedApiKey(newApiKey);
@@ -4931,7 +5108,7 @@ async function handleSourceMapUpload(distDir) {
4931
5108
  );
4932
5109
  return;
4933
5110
  }
4934
- const { discoverSourceMapFiles, computeBuildHash, uploadSourceMaps } = await import("./source-map-uploader-PB3M4PPP.js");
5111
+ const { discoverSourceMapFiles, computeBuildHash, uploadSourceMaps } = await import("./source-map-uploader-XFUEVV7I.js");
4935
5112
  const files = await discoverSourceMapFiles(distDir);
4936
5113
  if (files.length === 0) {
4937
5114
  console.info("[glasstrace] No source map files found. Skipping upload.");
@@ -5034,4 +5211,4 @@ export {
5034
5211
  withGlasstraceConfig,
5035
5212
  captureError
5036
5213
  };
5037
- //# sourceMappingURL=chunk-MLRQTCCK.js.map
5214
+ //# sourceMappingURL=chunk-SYNQJZZY.js.map