@glasstrace/sdk 1.3.2 → 1.3.4

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 (51) hide show
  1. package/README.md +126 -0
  2. package/dist/{chunk-REEU6CNO.js → chunk-3HWBR7XM.js} +3 -3
  3. package/dist/chunk-3HWBR7XM.js.map +1 -0
  4. package/dist/{chunk-XS3BO7RY.js → chunk-BQKPRFLF.js} +3 -3
  5. package/dist/{chunk-GCFOY7T2.js → chunk-E62DL2H4.js} +3 -3
  6. package/dist/{chunk-UFZEISZB.js → chunk-LQKJ27LO.js} +2 -2
  7. package/dist/chunk-LQKJ27LO.js.map +1 -0
  8. package/dist/{chunk-MQHLWSIX.js → chunk-M4ZI7J3N.js} +100 -62
  9. package/dist/{chunk-MQHLWSIX.js.map → chunk-M4ZI7J3N.js.map} +1 -1
  10. package/dist/{chunk-JFR42QG5.js → chunk-QJVAKVQJ.js} +2 -2
  11. package/dist/{chunk-CRM3EYOL.js → chunk-WKOQJCFN.js} +2 -2
  12. package/dist/{chunk-DQGNUENK.js → chunk-XFNK4YEW.js} +58 -16
  13. package/dist/chunk-XFNK4YEW.js.map +1 -0
  14. package/dist/{chunk-3TU62WD6.js → chunk-YG3X7TUI.js} +1 -1
  15. package/dist/chunk-YG3X7TUI.js.map +1 -0
  16. package/dist/cli/init.cjs +51 -13
  17. package/dist/cli/init.cjs.map +1 -1
  18. package/dist/cli/init.js +6 -6
  19. package/dist/cli/mcp-add.cjs +49 -11
  20. package/dist/cli/mcp-add.cjs.map +1 -1
  21. package/dist/cli/mcp-add.js +2 -2
  22. package/dist/cli/uninit.cjs.map +1 -1
  23. package/dist/cli/uninit.js +3 -3
  24. package/dist/cli/validate.cjs +49 -11
  25. package/dist/cli/validate.cjs.map +1 -1
  26. package/dist/cli/validate.js +2 -2
  27. package/dist/edge-entry.cjs +88 -50
  28. package/dist/edge-entry.cjs.map +1 -1
  29. package/dist/edge-entry.js +2 -2
  30. package/dist/index.cjs +151 -70
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +19 -0
  33. package/dist/index.d.ts +19 -0
  34. package/dist/index.js +6 -6
  35. package/dist/node-entry.cjs +151 -70
  36. package/dist/node-entry.cjs.map +1 -1
  37. package/dist/node-entry.js +8 -8
  38. package/dist/node-subpath.cjs +49 -11
  39. package/dist/node-subpath.cjs.map +1 -1
  40. package/dist/node-subpath.js +4 -4
  41. package/dist/{source-map-uploader-LACAGKIW.js → source-map-uploader-JAD3XM4F.js} +4 -4
  42. package/package.json +1 -1
  43. package/dist/chunk-3TU62WD6.js.map +0 -1
  44. package/dist/chunk-DQGNUENK.js.map +0 -1
  45. package/dist/chunk-REEU6CNO.js.map +0 -1
  46. package/dist/chunk-UFZEISZB.js.map +0 -1
  47. /package/dist/{chunk-XS3BO7RY.js.map → chunk-BQKPRFLF.js.map} +0 -0
  48. /package/dist/{chunk-GCFOY7T2.js.map → chunk-E62DL2H4.js.map} +0 -0
  49. /package/dist/{chunk-JFR42QG5.js.map → chunk-QJVAKVQJ.js.map} +0 -0
  50. /package/dist/{chunk-CRM3EYOL.js.map → chunk-WKOQJCFN.js.map} +0 -0
  51. /package/dist/{source-map-uploader-LACAGKIW.js.map → source-map-uploader-JAD3XM4F.js.map} +0 -0
@@ -6,15 +6,15 @@ import {
6
6
  uploadSourceMaps,
7
7
  uploadSourceMapsAuto,
8
8
  uploadSourceMapsPresigned
9
- } from "./chunk-XS3BO7RY.js";
10
- import "./chunk-3TU62WD6.js";
9
+ } from "./chunk-BQKPRFLF.js";
10
+ import "./chunk-YG3X7TUI.js";
11
11
  import {
12
12
  buildImportGraph,
13
13
  discoverTestFiles,
14
14
  extractImports
15
- } from "./chunk-JFR42QG5.js";
15
+ } from "./chunk-QJVAKVQJ.js";
16
16
  import "./chunk-VUZCLMIX.js";
17
- import "./chunk-MQHLWSIX.js";
17
+ import "./chunk-M4ZI7J3N.js";
18
18
  import "./chunk-NSBPE2FW.js";
19
19
  export {
20
20
  PRESIGNED_THRESHOLD_BYTES,
@@ -11,10 +11,10 @@ import {
11
11
  uploadSourceMapsAuto,
12
12
  uploadSourceMapsPresigned,
13
13
  uploadToBlob
14
- } from "./chunk-XS3BO7RY.js";
15
- import "./chunk-3TU62WD6.js";
14
+ } from "./chunk-BQKPRFLF.js";
15
+ import "./chunk-YG3X7TUI.js";
16
16
  import "./chunk-VUZCLMIX.js";
17
- import "./chunk-MQHLWSIX.js";
17
+ import "./chunk-M4ZI7J3N.js";
18
18
  import "./chunk-NSBPE2FW.js";
19
19
  export {
20
20
  PRESIGNED_THRESHOLD_BYTES,
@@ -30,4 +30,4 @@ export {
30
30
  uploadSourceMapsPresigned,
31
31
  uploadToBlob
32
32
  };
33
- //# sourceMappingURL=source-map-uploader-LACAGKIW.js.map
33
+ //# sourceMappingURL=source-map-uploader-JAD3XM4F.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glasstrace/sdk",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "description": "Glasstrace server-side debugging SDK for AI coding agents",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/nudge/error-nudge.ts","../src/console-capture.ts"],"sourcesContent":["import { resolveConfig, isProductionDisabled } from \"../env-detection.js\";\n\n/**\n * Module-level flag ensuring the MCP-connection nudge fires at most once\n * per process.\n */\nlet hasFired = false;\n\n/**\n * Module-level flag ensuring the Server Action nudge fires at most once\n * per process (DISC-1253).\n */\nlet hasFiredServerAction = false;\n\n/**\n * Strips control characters (except space) from a string to prevent\n * terminal escape sequence injection via error summaries written to stderr.\n */\nfunction sanitize(input: string): string {\n // eslint-disable-next-line no-control-regex\n return input.replace(/[\\x00-\\x1f\\x7f]/g, \"\");\n}\n\n/**\n * Checks whether the MCP marker file exists using synchronous filesystem\n * APIs. Returns `false` when `node:fs` or `node:path` cannot be resolved\n * (non-Node environments) or on any I/O error.\n */\nfunction markerFileExists(): boolean {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const fs = require(\"node:fs\") as typeof import(\"node:fs\");\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const path = require(\"node:path\") as typeof import(\"node:path\");\n const markerPath = path.join(process.cwd(), \".glasstrace\", \"mcp-connected\");\n return fs.existsSync(markerPath);\n } catch {\n // node:fs/node:path unavailable, permission denied, ENOENT from\n // cwd(), or other error — treat as not connected\n return false;\n }\n}\n\n/**\n * Shows a one-time stderr nudge when the SDK captures its first error\n * and the MCP connection marker file is absent.\n *\n * The nudge is suppressed when:\n * - It has already fired in this process\n * - The `.glasstrace/mcp-connected` marker file exists at the project root\n * - The environment is detected as production (and force-enable is off)\n *\n * Uses `process.stderr.write()` instead of `console.error()` to avoid\n * being captured by OpenTelemetry console instrumentation.\n */\nexport function maybeShowMcpNudge(errorSummary: string): void {\n if (hasFired) {\n return;\n }\n\n // Production check — suppress silently, but remember the decision\n // so subsequent calls fast-exit via hasFired without re-running I/O.\n const config = resolveConfig();\n if (isProductionDisabled(config)) {\n hasFired = true;\n return;\n }\n\n // Check for MCP connection marker file.\n if (markerFileExists()) {\n hasFired = true;\n return;\n }\n\n // Fire the nudge exactly once\n hasFired = true;\n\n const safe = sanitize(errorSummary);\n process.stderr.write(\n `[glasstrace] Error captured: ${safe}\\n` +\n ` Debug with AI: ask your agent \"What's the latest Glasstrace error?\"\\n` +\n ` Not connected? Run: npx glasstrace mcp add\\n`,\n );\n}\n\n/**\n * Shows a one-time stderr nudge when the SDK detects a Next.js Server\n * Action trace whose originating request had no Glasstrace browser\n * extension correlation header (`x-gt-cid`) — meaning the extension was\n * not active for that request and the specific Server Action identifier\n * could not be captured (DISC-1253).\n *\n * The nudge is suppressed when:\n * - It has already fired in this process\n * - The environment is detected as production (and force-enable is off)\n * - `GLASSTRACE_SUPPRESS_ACTION_NUDGE=1` is set\n *\n * Routes through `process.stderr.write()` — identical transport to the\n * existing MCP nudge — so it is not captured by OpenTelemetry console\n * instrumentation and plays nicely with existing error-nudge tests.\n */\nexport function maybeShowServerActionNudge(): void {\n if (hasFiredServerAction) {\n return;\n }\n\n // User opt-out takes precedence over every other check so we never\n // re-run I/O when silenced.\n if (process.env.GLASSTRACE_SUPPRESS_ACTION_NUDGE === \"1\") {\n hasFiredServerAction = true;\n return;\n }\n\n // Production check — suppress silently, but remember the decision so\n // subsequent calls fast-exit via hasFiredServerAction without re-running\n // resolveConfig.\n const config = resolveConfig();\n if (isProductionDisabled(config)) {\n hasFiredServerAction = true;\n return;\n }\n\n hasFiredServerAction = true;\n\n process.stderr.write(\n `[glasstrace] Detected a Next.js Server Action trace. Install the ` +\n `Glasstrace browser extension to capture the Server Action identifier ` +\n `for precise action-level debugging. https://glasstrace.dev/ext\\n`,\n );\n}\n\n/**\n * Test-only hook: resets both nudge guards so independent tests can\n * reload module state without relying on `vi.resetModules()` side effects.\n * Kept internal — not exported from the SDK barrel.\n */\nexport function __resetNudgeStateForTests(): void {\n hasFired = false;\n hasFiredServerAction = false;\n}\n","/**\n * Console error/warn capture module.\n *\n * When enabled, monkey-patches `console.error` and `console.warn` to record\n * their output as OTel span events on the currently active span. SDK-internal\n * log messages (prefixed with \"[glasstrace]\") are never captured.\n */\n\nimport { maybeShowMcpNudge } from \"./nudge/error-nudge.js\";\n\n/**\n * Module-level flag to suppress capture of SDK-internal log messages.\n * Set to `true` before calling `console.warn`/`console.error` from SDK code,\n * then reset to `false` immediately after.\n */\nexport let isGlasstraceLog = false;\n\n/** Saved reference to the original `console.error`. */\nlet originalError: typeof console.error | null = null;\n\n/** Saved reference to the original `console.warn`. */\nlet originalWarn: typeof console.warn | null = null;\n\n/** Whether the console capture is currently installed. */\nlet installed = false;\n\n/** Cached OTel API module reference, resolved at install time. */\nlet otelApi: typeof import(\"@opentelemetry/api\") | null = null;\n\n/**\n * Formats console arguments into a single string for span event attributes.\n * Uses best-effort serialization: strings pass through, Errors preserve their\n * stack trace, and other values are JSON-stringified with a String() fallback.\n */\nfunction formatArgs(args: unknown[]): string {\n return args\n .map((arg) => {\n if (typeof arg === \"string\") return arg;\n if (arg instanceof Error) return arg.stack ?? arg.message;\n try {\n return JSON.stringify(arg);\n } catch {\n return String(arg);\n }\n })\n .join(\" \");\n}\n\n/**\n * Returns `true` if the first argument is a string starting with \"[glasstrace]\".\n * Used to skip capture of SDK-internal log messages without requiring every\n * call site to set the `isGlasstraceLog` flag.\n */\nfunction isSdkMessage(args: unknown[]): boolean {\n return typeof args[0] === \"string\" && args[0].startsWith(\"[glasstrace]\");\n}\n\n/**\n * Installs console capture by replacing `console.error` and `console.warn`\n * with wrappers that record span events on the active OTel span.\n *\n * Must be called after OTel is configured so the API module is available.\n * Safe to call multiple times; subsequent calls are no-ops.\n */\nexport async function installConsoleCapture(): Promise<void> {\n if (installed) return;\n\n // Resolve OTel API at install time via dynamic import so that:\n // 1. tsup inlines @opentelemetry/api into the bundle (it's in noExternal)\n // 2. vitest's vi.doMock can intercept this import for testing\n try {\n otelApi = await import(\"@opentelemetry/api\");\n } catch {\n otelApi = null;\n }\n\n originalError = console.error;\n originalWarn = console.warn;\n installed = true;\n\n console.error = (...args: unknown[]) => {\n // Always call the original first to preserve developer experience\n originalError!.apply(console, args);\n\n // Skip SDK-internal messages and flagged messages\n if (isGlasstraceLog || isSdkMessage(args)) return;\n\n if (otelApi) {\n const span = otelApi.trace.getSpan(otelApi.context.active());\n if (span) {\n const formattedMessage = formatArgs(args);\n span.addEvent(\"console.error\", {\n \"console.message\": formattedMessage,\n });\n // Show one-time MCP connection nudge on first captured error\n try {\n maybeShowMcpNudge(formattedMessage);\n } catch {\n // Never allow the monkey-patched console.error wrapper to throw\n }\n }\n }\n };\n\n console.warn = (...args: unknown[]) => {\n originalWarn!.apply(console, args);\n\n if (isGlasstraceLog || isSdkMessage(args)) return;\n\n if (otelApi) {\n const span = otelApi.trace.getSpan(otelApi.context.active());\n if (span) {\n span.addEvent(\"console.warn\", {\n \"console.message\": formatArgs(args),\n });\n }\n }\n };\n}\n\n/**\n * Restores the original `console.error` and `console.warn` methods.\n * Primarily intended for use in tests.\n */\nexport function uninstallConsoleCapture(): void {\n if (!installed) return;\n\n if (originalError) console.error = originalError;\n if (originalWarn) console.warn = originalWarn;\n\n originalError = null;\n originalWarn = null;\n otelApi = null;\n installed = false;\n}\n\n/**\n * Logs a message from SDK-internal code without triggering console capture.\n *\n * Use this helper in new SDK code instead of bare `console.warn(...)` calls\n * to prevent SDK log messages from being recorded as user-facing span events.\n *\n * @param level - The console log level to use.\n * @param message - The message to log.\n */\nexport function sdkLog(level: \"warn\" | \"info\" | \"error\", message: string): void {\n isGlasstraceLog = true;\n try {\n console[level](message);\n } finally {\n isGlasstraceLog = false;\n }\n}\n"],"mappings":"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","names":[]}