@glasstrace/sdk 1.12.0 → 1.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.
Files changed (67) hide show
  1. package/README.md +55 -20
  2. package/dist/async-context/index.cjs.map +1 -1
  3. package/dist/async-context/index.js +2 -2
  4. package/dist/{capture-error-CRQSqKgd.d.cts → capture-error-03qDnC5v.d.cts} +2 -2
  5. package/dist/{capture-error-CqCbjoMq.d.ts → capture-error-CAfFUyIU.d.ts} +2 -2
  6. package/dist/{chunk-6NKMAKMI.js → chunk-6ST4QV7T.js} +3 -3
  7. package/dist/{chunk-BN5DVIUO.js → chunk-7LE2O4ZJ.js} +12 -7
  8. package/dist/{chunk-BN5DVIUO.js.map → chunk-7LE2O4ZJ.js.map} +1 -1
  9. package/dist/{chunk-CZQN6G4I.js → chunk-E2F4S5IJ.js} +362 -11
  10. package/dist/chunk-E2F4S5IJ.js.map +1 -0
  11. package/dist/{chunk-J3ZCVE67.js → chunk-F7A3QXCT.js} +2 -2
  12. package/dist/{chunk-M3ZTG4P5.js → chunk-HMEHYSTS.js} +2 -2
  13. package/dist/{chunk-4YRYR32D.js → chunk-LQZRGBN5.js} +2 -2
  14. package/dist/{chunk-ZIL2IY4C.js → chunk-MP3QNDXQ.js} +2 -2
  15. package/dist/{chunk-FFNGE5RR.js → chunk-VMK2G6QR.js} +2 -2
  16. package/dist/{chunk-KBHGPQZ2.js → chunk-XMD5OYD6.js} +2 -2
  17. package/dist/{chunk-V75ZB4G4.js → chunk-ZIYT2Y4B.js} +3 -3
  18. package/dist/cli/init.cjs +4 -4
  19. package/dist/cli/init.cjs.map +1 -1
  20. package/dist/cli/init.js +7 -7
  21. package/dist/cli/mcp-add.cjs +1 -1
  22. package/dist/cli/mcp-add.cjs.map +1 -1
  23. package/dist/cli/mcp-add.js +3 -3
  24. package/dist/cli/uninit.js +3 -3
  25. package/dist/cli/upgrade-instructions.cjs +1 -1
  26. package/dist/cli/upgrade-instructions.js +3 -3
  27. package/dist/cli/validate.cjs.map +1 -1
  28. package/dist/cli/validate.js +2 -2
  29. package/dist/{correlation-id-CFpyJsKv.d.cts → correlation-id-CZ2bstzA.d.cts} +1 -1
  30. package/dist/{correlation-id-DPXyY9-3.d.ts → correlation-id-YcfcqOru.d.ts} +1 -1
  31. package/dist/edge-entry.cjs.map +1 -1
  32. package/dist/edge-entry.d.cts +2 -2
  33. package/dist/edge-entry.d.ts +2 -2
  34. package/dist/edge-entry.js +4 -4
  35. package/dist/index.cjs +1033 -960
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/{index.d-D-jdiIPU.d.cts → index.d-BQIJ5Dvc.d.cts} +44 -9
  38. package/dist/{index.d-D-jdiIPU.d.ts → index.d-BQIJ5Dvc.d.ts} +44 -9
  39. package/dist/index.d.cts +4 -4
  40. package/dist/index.d.ts +4 -4
  41. package/dist/index.js +10 -297
  42. package/dist/index.js.map +1 -1
  43. package/dist/middleware/index.cjs.map +1 -1
  44. package/dist/middleware/index.js +2 -2
  45. package/dist/node-entry.cjs +12 -5
  46. package/dist/node-entry.cjs.map +1 -1
  47. package/dist/node-entry.d.cts +3 -3
  48. package/dist/node-entry.d.ts +3 -3
  49. package/dist/node-entry.js +7 -7
  50. package/dist/node-subpath.cjs.map +1 -1
  51. package/dist/node-subpath.d.cts +1 -1
  52. package/dist/node-subpath.d.ts +1 -1
  53. package/dist/node-subpath.js +3 -3
  54. package/dist/{source-map-uploader-K67LTPBG.js → source-map-uploader-NUONOEJG.js} +3 -3
  55. package/dist/trpc/index.cjs.map +1 -1
  56. package/dist/trpc/index.js +1 -1
  57. package/package.json +1 -1
  58. package/dist/chunk-CZQN6G4I.js.map +0 -1
  59. /package/dist/{chunk-6NKMAKMI.js.map → chunk-6ST4QV7T.js.map} +0 -0
  60. /package/dist/{chunk-J3ZCVE67.js.map → chunk-F7A3QXCT.js.map} +0 -0
  61. /package/dist/{chunk-M3ZTG4P5.js.map → chunk-HMEHYSTS.js.map} +0 -0
  62. /package/dist/{chunk-4YRYR32D.js.map → chunk-LQZRGBN5.js.map} +0 -0
  63. /package/dist/{chunk-ZIL2IY4C.js.map → chunk-MP3QNDXQ.js.map} +0 -0
  64. /package/dist/{chunk-FFNGE5RR.js.map → chunk-VMK2G6QR.js.map} +0 -0
  65. /package/dist/{chunk-KBHGPQZ2.js.map → chunk-XMD5OYD6.js.map} +0 -0
  66. /package/dist/{chunk-V75ZB4G4.js.map → chunk-ZIYT2Y4B.js.map} +0 -0
  67. /package/dist/{source-map-uploader-K67LTPBG.js.map → source-map-uploader-NUONOEJG.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -15332,7 +15332,13 @@ function deriveSessionId(apiKey, origin, date5, windowIndex) {
15332
15332
  const digest = sha256Hex(input).slice(0, 16);
15333
15333
  return SessionIdSchema.parse(digest);
15334
15334
  }
15335
- var DevApiKeySchema, AnonApiKeySchema, SessionIdSchema, BuildHashSchema, SdkDiagnosticCodeSchema, CaptureConfigSchema, SdkCachedConfigSchema, GlasstraceOptionsSchema, GlasstraceEnvVarsSchema, GLASSTRACE_ATTRIBUTE_NAMES, DEFAULT_CAPTURE_CONFIG, MAX_SOURCE_MAP_FILE_PATH_LENGTH, MAX_SOURCE_MAP_FILE_SIZE, MAX_SOURCE_MAP_FILE_COUNT, MAX_PRESIGNED_CLIENT_TOKEN_LENGTH, MAX_PRESIGNED_PATHNAME_LENGTH, ImportGraphPayloadSchema, SdkHealthReportSchema, TierLimitsSchema, SdkInitResponseSchema, DiscoveryResponseSchema, SourceMapUploadResponseSchema, PresignedUploadRequestSchema, PresignedUploadResponseSchema, SourceMapManifestRequestSchema, SourceMapManifestResponseSchema, K, SIDE_EFFECT_OPERATION_KINDS, SIDE_EFFECT_SEMANTIC_FIELD_KEYS, SIDE_EFFECT_OMISSION_REASONS, SIDE_EFFECT_OPERATION_STATUSES, SIDE_EFFECT_OPERATION_PHASES;
15335
+ function isSideEffectSemanticFieldKey(key) {
15336
+ if (key.length > MAX_SIDE_EFFECT_SEMANTIC_FIELD_KEY_LENGTH) return false;
15337
+ return SIDE_EFFECT_SEMANTIC_FIELD_STABLE_CORE_KEYS.includes(
15338
+ key
15339
+ ) || SIDE_EFFECT_SEMANTIC_FIELD_OPEN_PATTERN.test(key);
15340
+ }
15341
+ var DevApiKeySchema, AnonApiKeySchema, SessionIdSchema, BuildHashSchema, SdkDiagnosticCodeSchema, CaptureConfigSchema, SdkCachedConfigSchema, GlasstraceOptionsSchema, GlasstraceEnvVarsSchema, GLASSTRACE_ATTRIBUTE_NAMES, DEFAULT_CAPTURE_CONFIG, MAX_SOURCE_MAP_FILE_PATH_LENGTH, MAX_SOURCE_MAP_FILE_SIZE, MAX_SOURCE_MAP_FILE_COUNT, MAX_PRESIGNED_CLIENT_TOKEN_LENGTH, MAX_PRESIGNED_PATHNAME_LENGTH, ImportGraphPayloadSchema, SdkHealthReportSchema, TierLimitsSchema, SdkInitResponseSchema, DiscoveryResponseSchema, SourceMapUploadResponseSchema, PresignedUploadRequestSchema, PresignedUploadResponseSchema, SourceMapManifestRequestSchema, SourceMapManifestResponseSchema, K, SIDE_EFFECT_OPERATION_KINDS, SIDE_EFFECT_SEMANTIC_FIELD_STABLE_CORE_KEYS, SIDE_EFFECT_SEMANTIC_FIELD_OPEN_PATTERN, MAX_SIDE_EFFECT_SEMANTIC_FIELD_KEY_LENGTH, SIDE_EFFECT_OMISSION_REASONS, SIDE_EFFECT_OPERATION_STATUSES, SIDE_EFFECT_OPERATION_PHASES;
15336
15342
  var init_dist = __esm({
15337
15343
  "../protocol/dist/index.js"() {
15338
15344
  "use strict";
@@ -15769,18 +15775,17 @@ var init_dist = __esm({
15769
15775
  "queue",
15770
15776
  "after_callback"
15771
15777
  ];
15772
- SIDE_EFFECT_SEMANTIC_FIELD_KEYS = [
15778
+ SIDE_EFFECT_SEMANTIC_FIELD_STABLE_CORE_KEYS = [
15773
15779
  "templateKey",
15774
15780
  "providerOperation",
15775
15781
  "role",
15776
15782
  "locale",
15777
15783
  "timezone",
15778
15784
  "status",
15779
- "phase",
15780
- "recipientClass",
15781
- "participantCount",
15782
- "activeParticipantCount"
15785
+ "phase"
15783
15786
  ];
15787
+ SIDE_EFFECT_SEMANTIC_FIELD_OPEN_PATTERN = /^[a-z][A-Za-z0-9]*(Class|Count|Kind|Role)$/;
15788
+ MAX_SIDE_EFFECT_SEMANTIC_FIELD_KEY_LENGTH = 80;
15784
15789
  SIDE_EFFECT_OMISSION_REASONS = [
15785
15790
  "pii",
15786
15791
  "secret",
@@ -17884,6 +17889,7 @@ __export(src_exports, {
17884
17889
  isAnonymousMode: () => isAnonymousMode,
17885
17890
  isProductionDisabled: () => isProductionDisabled,
17886
17891
  isReady: () => isReady,
17892
+ isSideEffectSemanticFieldKey: () => isSideEffectSemanticFieldKey,
17887
17893
  loadCachedConfig: () => loadCachedConfig,
17888
17894
  performInit: () => performInit,
17889
17895
  readAnonKey: () => readAnonKey,
@@ -24057,1078 +24063,1144 @@ function registerHeartbeatShutdownHook(config2, anonKey, sdkVersion) {
24057
24063
  });
24058
24064
  }
24059
24065
 
24060
- // src/runtime-state.ts
24061
- init_console_capture();
24062
- var fsSync = null;
24063
- var pathSync = null;
24064
- try {
24065
- fsSync = require("node:fs");
24066
- pathSync = require("node:path");
24067
- } catch {
24068
- fsSync = null;
24069
- pathSync = null;
24066
+ // src/side-effect/allowlist.ts
24067
+ init_dist();
24068
+ var MAX_SIDE_EFFECT_OPERATION_LABEL_LENGTH = 96;
24069
+ var MAX_SIDE_EFFECT_FIELD_VALUE_LENGTH = 80;
24070
+ var MAX_SIDE_EFFECT_FIELD_COUNT_VALUE_LENGTH = 16;
24071
+ var MAX_SIDE_EFFECT_OPERATIONS_PER_SPAN = 5;
24072
+ var OPERATION_KIND_SET = new Set(
24073
+ SIDE_EFFECT_OPERATION_KINDS
24074
+ );
24075
+ var OPERATION_STATUS_SET = new Set(
24076
+ SIDE_EFFECT_OPERATION_STATUSES
24077
+ );
24078
+ var OPERATION_PHASE_SET = new Set(
24079
+ SIDE_EFFECT_OPERATION_PHASES
24080
+ );
24081
+ var OMISSION_REASON_SET = new Set(
24082
+ SIDE_EFFECT_OMISSION_REASONS
24083
+ );
24084
+ var TOKEN_REGEX = /^[A-Za-z0-9][A-Za-z0-9_.:-]*$/;
24085
+ var LOCALE_REGEX = /^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8}){0,3}$/;
24086
+ var TIMEZONE_REGEX = /^(?:UTC|GMT|[A-Za-z][A-Za-z0-9_+-]*(?:\/[A-Za-z0-9_+-]+){1,3})$/;
24087
+ var DIGIT_REGEX = /^[0-9]+$/;
24088
+ var URL_SCHEME = /:\/\//;
24089
+ var URL_SCHEME_RELATIVE = /^\/\//;
24090
+ var EMAIL_LIKE = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i;
24091
+ var QUERY_LIKE = /\?/;
24092
+ var FRAGMENT_LIKE = /#/;
24093
+ var HEADER_LIKE = /\b(authorization|set-cookie|cookie)\b\s*[:=]/i;
24094
+ var HEADER_TOKEN_LIKE = /\b(authorization|set-cookie|cookie)\b\s+\S+=/i;
24095
+ var BEARER_LIKE = /bearer\s+\S+/i;
24096
+ var TOKEN_KV_LIKE = /["']?(password|passwd|token|api[_-]?key|secret|client_secret)["']?\s*[:=]/i;
24097
+ var PROSE_LIKE = /[\r\n\t]|\s{2,}/;
24098
+ var UUID_LIKE = /[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i;
24099
+ var GT_KEY_LIKE = /gt_(dev|anon|live)_[A-Za-z0-9_-]+/;
24100
+ function detectUnsafePattern(value) {
24101
+ if (value.trim() !== value) return "raw_payload";
24102
+ if (PROSE_LIKE.test(value)) return "raw_payload";
24103
+ if (URL_SCHEME.test(value)) return "raw_payload";
24104
+ if (URL_SCHEME_RELATIVE.test(value)) return "raw_payload";
24105
+ if (QUERY_LIKE.test(value)) return "raw_payload";
24106
+ if (FRAGMENT_LIKE.test(value)) return "raw_payload";
24107
+ if (BEARER_LIKE.test(value)) return "secret";
24108
+ if (HEADER_TOKEN_LIKE.test(value)) return "secret";
24109
+ if (TOKEN_KV_LIKE.test(value)) return "secret";
24110
+ if (HEADER_LIKE.test(value)) return "secret";
24111
+ if (UUID_LIKE.test(value)) return "secret";
24112
+ if (GT_KEY_LIKE.test(value)) return "secret";
24113
+ if (EMAIL_LIKE.test(value)) return "pii";
24114
+ return null;
24070
24115
  }
24071
- var _projectRoot = null;
24072
- var _sdkVersion = "unknown";
24073
- var _lastScenario;
24074
- var _lastError;
24075
- var _debounceTimer = null;
24076
- var _started = false;
24077
- function startRuntimeStateWriter(options) {
24078
- if (_started) return;
24079
- if (!isSyncFsAvailable() || fsSync === null || pathSync === null) {
24080
- _started = true;
24081
- return;
24116
+ function passesFieldValidator(key, value) {
24117
+ if (key === "locale") return LOCALE_REGEX.test(value);
24118
+ if (key === "timezone") return TIMEZONE_REGEX.test(value);
24119
+ if (typeof key === "string" && key.endsWith("Count")) {
24120
+ return DIGIT_REGEX.test(value);
24082
24121
  }
24083
- _started = true;
24084
- _projectRoot = options.projectRoot;
24085
- _sdkVersion = options.sdkVersion;
24086
- onLifecycleEvent("core:state_changed", ({ to }) => {
24087
- if (to === CoreState.SHUTDOWN) {
24088
- writeStateNow();
24089
- } else {
24090
- debouncedWrite();
24091
- }
24092
- });
24093
- onLifecycleEvent("otel:configured", ({ scenario }) => {
24094
- _lastScenario = scenario;
24095
- debouncedWrite();
24096
- });
24097
- onLifecycleEvent("otel:failed", (payload) => {
24098
- _lastError = { ...payload };
24099
- debouncedWrite();
24100
- });
24101
- onLifecycleEvent("otel:circuit_opened", (payload) => {
24102
- _lastError = {
24103
- category: "export-circuit-open",
24104
- message: payload.message,
24105
- timestamp: payload.timestamp,
24106
- exportCircuitCategory: payload.category
24107
- };
24108
- debouncedWrite();
24109
- });
24110
- onLifecycleEvent("otel:circuit_closed", () => {
24111
- if (_lastError?.category === "export-circuit-open") {
24112
- _lastError = void 0;
24113
- debouncedWrite();
24114
- }
24115
- });
24116
- onLifecycleEvent("auth:key_resolved", () => debouncedWrite());
24117
- onLifecycleEvent("auth:claim_started", () => debouncedWrite());
24118
- onLifecycleEvent("auth:claim_completed", () => debouncedWrite());
24119
- writeStateNow();
24122
+ return TOKEN_REGEX.test(value);
24120
24123
  }
24121
- function debouncedWrite() {
24122
- if (_debounceTimer) return;
24123
- _debounceTimer = setTimeout(() => {
24124
- _debounceTimer = null;
24125
- writeStateNow();
24126
- }, 1e3);
24127
- if (typeof _debounceTimer === "object" && "unref" in _debounceTimer) {
24128
- _debounceTimer.unref();
24124
+ function checkOperationLabel(value) {
24125
+ if (typeof value !== "string" || value.length === 0) {
24126
+ return { accepted: false, reason: "raw_payload" };
24129
24127
  }
24130
- }
24131
- function writeStateNow() {
24132
- if (!_projectRoot) return;
24133
- try {
24134
- const state = getSdkState();
24135
- const runtimeState = {
24136
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
24137
- pid: process.pid,
24138
- sdkVersion: _sdkVersion,
24139
- core: { state: state.core },
24140
- auth: { state: state.auth },
24141
- otel: { state: state.otel, scenario: _lastScenario }
24142
- };
24143
- if (_lastError) {
24144
- runtimeState.lastError = _lastError;
24145
- }
24146
- const dir = pathSync.join(_projectRoot, ".glasstrace");
24147
- const filePath = pathSync.join(dir, "runtime-state.json");
24148
- fsSync.mkdirSync(dir, { recursive: true, mode: 448 });
24149
- atomicWriteFileSync(filePath, JSON.stringify(runtimeState, null, 2) + "\n", {
24150
- mode: 384
24151
- });
24152
- } catch (err) {
24153
- sdkLog(
24154
- "warn",
24155
- `[glasstrace] Failed to write runtime state: ${err instanceof Error ? err.message : String(err)}`
24156
- );
24128
+ if (value.length > MAX_SIDE_EFFECT_OPERATION_LABEL_LENGTH) {
24129
+ return { accepted: false, reason: "value_too_long" };
24157
24130
  }
24131
+ const unsafe = detectUnsafePattern(value);
24132
+ if (unsafe) {
24133
+ return { accepted: false, reason: unsafe };
24134
+ }
24135
+ if (!TOKEN_REGEX.test(value)) {
24136
+ return { accepted: false, reason: "raw_payload" };
24137
+ }
24138
+ return { accepted: true, value };
24158
24139
  }
24159
-
24160
- // src/agent-detection/upgrade-notice.ts
24161
- var fs2 = __toESM(require("node:fs"), 1);
24162
- var path2 = __toESM(require("node:path"), 1);
24163
-
24164
- // src/agent-detection/inject.ts
24165
- var HTML_START_RE = /^<!--\s*glasstrace:mcp:start(?:\s+v=([^\s>]+))?\s*-->$/;
24166
- var HTML_END = "<!-- glasstrace:mcp:end -->";
24167
- var HASH_START_RE = /^#\s*glasstrace:mcp:start(?:\s+v=(\S+))?$/;
24168
- var HASH_END = "# glasstrace:mcp:end";
24169
- function parseStartMarkerLine(line) {
24170
- const trimmed = line.trim();
24171
- const html = HTML_START_RE.exec(trimmed);
24172
- if (html !== null) {
24173
- return { kind: "html", stamp: html[1] ?? null };
24140
+ function checkSemanticFieldValue(key, value) {
24141
+ if (typeof value !== "string" || value.length === 0) {
24142
+ return { accepted: false, reason: "raw_payload" };
24174
24143
  }
24175
- const hash2 = HASH_START_RE.exec(trimmed);
24176
- if (hash2 !== null) {
24177
- return { kind: "hash", stamp: hash2[1] ?? null };
24144
+ const maxLength = typeof key === "string" && key.endsWith("Count") ? MAX_SIDE_EFFECT_FIELD_COUNT_VALUE_LENGTH : MAX_SIDE_EFFECT_FIELD_VALUE_LENGTH;
24145
+ if (value.length > maxLength) {
24146
+ return { accepted: false, reason: "value_too_long" };
24178
24147
  }
24179
- return null;
24148
+ const unsafe = detectUnsafePattern(value);
24149
+ if (unsafe) {
24150
+ return { accepted: false, reason: unsafe };
24151
+ }
24152
+ if (!passesFieldValidator(key, value)) {
24153
+ return { accepted: false, reason: "raw_payload" };
24154
+ }
24155
+ return { accepted: true, value };
24180
24156
  }
24181
- function isEndMarker(line) {
24182
- const trimmed = line.trim();
24183
- return trimmed === HTML_END || trimmed === HASH_END;
24157
+ function checkSemanticFieldKey(key) {
24158
+ return typeof key === "string" && isSideEffectSemanticFieldKey(key);
24184
24159
  }
24185
- function isEndMarkerLine(line) {
24186
- return isEndMarker(line);
24160
+ function checkOperationKind(kind) {
24161
+ return typeof kind === "string" && OPERATION_KIND_SET.has(kind);
24187
24162
  }
24188
-
24189
- // src/agent-detection/upgrade-notice.ts
24190
- var warningEmitted = false;
24191
- var AGENT_INSTRUCTION_FILES = [
24192
- "AGENTS.md",
24193
- "CLAUDE.md",
24194
- "GEMINI.md",
24195
- ".cursor/rules/glasstrace.mdc",
24196
- ".windsurf/rules/glasstrace.md",
24197
- ".cursorrules",
24198
- "codex.md",
24199
- ".windsurfrules"
24200
- ];
24201
- function parseSemver(input) {
24202
- const plusIdx = input.indexOf("+");
24203
- const core = plusIdx === -1 ? input : input.slice(0, plusIdx);
24204
- const m = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(core);
24205
- if (m === null) return null;
24206
- return {
24207
- major: Number(m[1]),
24208
- minor: Number(m[2]),
24209
- patch: Number(m[3]),
24210
- prerelease: m[4] ?? null
24211
- };
24163
+ function checkOperationStatus(status) {
24164
+ return typeof status === "string" && OPERATION_STATUS_SET.has(status);
24212
24165
  }
24213
- function comparePrerelease(a, b) {
24214
- const ap = a.split(".");
24215
- const bp = b.split(".");
24216
- const len = Math.min(ap.length, bp.length);
24217
- for (let i = 0; i < len; i++) {
24218
- const x = ap[i];
24219
- const y = bp[i];
24220
- const xNumeric = /^\d+$/.test(x);
24221
- const yNumeric = /^\d+$/.test(y);
24222
- if (xNumeric && yNumeric) {
24223
- const xv = Number(x);
24224
- const yv = Number(y);
24225
- if (xv !== yv) return xv < yv ? -1 : 1;
24226
- } else if (xNumeric) {
24227
- return -1;
24228
- } else if (yNumeric) {
24229
- return 1;
24230
- } else if (x !== y) {
24231
- return x < y ? -1 : 1;
24232
- }
24233
- }
24234
- return ap.length - bp.length;
24166
+ function checkOperationPhase(phase) {
24167
+ return typeof phase === "string" && OPERATION_PHASE_SET.has(phase);
24235
24168
  }
24236
- function compareSemver(a, b) {
24237
- const pa = parseSemver(a);
24238
- const pb = parseSemver(b);
24239
- if (pa === null || pb === null) return null;
24240
- if (pa.major !== pb.major) return pa.major - pb.major;
24241
- if (pa.minor !== pb.minor) return pa.minor - pb.minor;
24242
- if (pa.patch !== pb.patch) return pa.patch - pb.patch;
24243
- if (pa.prerelease === null && pb.prerelease === null) return 0;
24244
- if (pa.prerelease === null) return 1;
24245
- if (pb.prerelease === null) return -1;
24246
- return comparePrerelease(pa.prerelease, pb.prerelease);
24247
- }
24248
- function isOptedOut() {
24249
- const raw = process.env.GLASSTRACE_DISABLE_UPGRADE_NOTICE;
24250
- if (typeof raw !== "string") return false;
24251
- const trimmed = raw.trim().toLowerCase();
24252
- return trimmed === "1" || trimmed === "true" || trimmed === "yes";
24253
- }
24254
- function isQuietCiContext() {
24255
- const stderrIsTty = process.stderr.isTTY === true;
24256
- if (stderrIsTty) return false;
24257
- return process.env.CI === "true";
24169
+
24170
+ // src/side-effect/emit.ts
24171
+ init_esm();
24172
+ init_dist();
24173
+ var spanState = /* @__PURE__ */ new WeakMap();
24174
+ function getOrCreateState(span) {
24175
+ let state = spanState.get(span);
24176
+ if (!state) {
24177
+ state = { operationsRecorded: 0, omissions: /* @__PURE__ */ new Map() };
24178
+ spanState.set(span, state);
24179
+ }
24180
+ return state;
24258
24181
  }
24259
- var MAX_AGENT_FILE_BYTES = 5 * 1024 * 1024;
24260
- function inspectFile(filePath, runningSdkVersion) {
24261
- let content;
24182
+ function getRecordingActiveSpan() {
24183
+ let span;
24262
24184
  try {
24263
- const stat2 = fs2.statSync(filePath);
24264
- if (!stat2.isFile()) return "absent";
24265
- if (stat2.size > MAX_AGENT_FILE_BYTES) return "absent";
24266
- content = fs2.readFileSync(filePath, "utf-8");
24185
+ span = trace.getActiveSpan();
24267
24186
  } catch {
24268
- return "absent";
24187
+ return void 0;
24269
24188
  }
24270
- const lines = content.split("\n");
24271
- let lastStart = null;
24272
- let foundEnd = false;
24273
- for (const line of lines) {
24274
- const parsed = parseStartMarkerLine(line);
24275
- if (parsed !== null) {
24276
- lastStart = parsed;
24277
- continue;
24278
- }
24279
- if (lastStart !== null && isEndMarkerLine(line)) {
24280
- foundEnd = true;
24281
- break;
24189
+ if (!span) return void 0;
24190
+ try {
24191
+ if (typeof span.isRecording === "function" && !span.isRecording()) {
24192
+ return void 0;
24282
24193
  }
24194
+ } catch {
24195
+ return void 0;
24283
24196
  }
24284
- if (lastStart === null || !foundEnd) {
24285
- return "no-section";
24286
- }
24287
- if (lastStart.stamp === null) {
24288
- return "no-stamp";
24289
- }
24290
- const cmp = compareSemver(lastStart.stamp, runningSdkVersion);
24291
- if (cmp === null) {
24292
- return "unknown-stamp";
24197
+ return span;
24198
+ }
24199
+ function recordOmissionOnActiveSpan(reason) {
24200
+ const span = getRecordingActiveSpan();
24201
+ if (!span) return;
24202
+ recordOmissionOnSpan(span, reason);
24203
+ }
24204
+ function recordOmissionOnSpan(span, reason) {
24205
+ const state = getOrCreateState(span);
24206
+ const previous = state.omissions.get(reason) ?? 0;
24207
+ const next = previous + 1;
24208
+ state.omissions.set(reason, next);
24209
+ const attribute = OMISSION_ATTRIBUTE_BY_REASON[reason];
24210
+ try {
24211
+ span.setAttribute(attribute, next);
24212
+ } catch {
24293
24213
  }
24294
- return cmp < 0 ? "stale" : "current";
24295
24214
  }
24296
- function maybeWarnStaleAgentInstructions(options) {
24215
+ var OMISSION_ATTRIBUTE_BY_REASON = {
24216
+ pii: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OMITTED_PII,
24217
+ secret: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OMITTED_SECRET,
24218
+ raw_payload: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OMITTED_RAW_PAYLOAD,
24219
+ unsupported_key: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OMITTED_UNSUPPORTED_KEY,
24220
+ value_too_long: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OMITTED_VALUE_TOO_LONG,
24221
+ not_emitted: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OMITTED_NOT_EMITTED,
24222
+ capture_disabled: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OMITTED_CAPTURE_DISABLED
24223
+ };
24224
+ var FIELD_ATTRIBUTE_BY_KEY = {
24225
+ templateKey: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_TEMPLATE_KEY,
24226
+ providerOperation: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_PROVIDER_OPERATION,
24227
+ role: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_ROLE,
24228
+ locale: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_LOCALE,
24229
+ timezone: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_TIMEZONE,
24230
+ status: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_STATUS,
24231
+ phase: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_PHASE,
24232
+ recipientClass: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_RECIPIENT_CLASS,
24233
+ participantCount: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_PARTICIPANT_COUNT,
24234
+ activeParticipantCount: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_ACTIVE_PARTICIPANT_COUNT
24235
+ };
24236
+ function resolveFieldAttribute(key) {
24237
+ const explicit = FIELD_ATTRIBUTE_BY_KEY[key];
24238
+ if (explicit !== void 0) return explicit;
24239
+ return `glasstrace.side_effect.field.${key}`;
24240
+ }
24241
+ function hasExplicitFieldAttribute(key) {
24242
+ return FIELD_ATTRIBUTE_BY_KEY[key] !== void 0;
24243
+ }
24244
+ function attachOperation(input) {
24245
+ const span = getRecordingActiveSpan();
24246
+ if (!span) return { kind: "no_active_span" };
24247
+ const state = getOrCreateState(span);
24248
+ if (state.operationsRecorded >= MAX_SIDE_EFFECT_OPERATIONS_PER_SPAN) {
24249
+ return { kind: "over_budget", span };
24250
+ }
24251
+ state.operationsRecorded += 1;
24297
24252
  try {
24298
- if (warningEmitted) return;
24299
- if (typeof process === "undefined" || typeof process.versions?.node !== "string" || typeof process.env !== "object" || process.env === null) {
24300
- return;
24301
- }
24302
- if (isOptedOut()) return;
24303
- if (isQuietCiContext()) return;
24304
- if (parseSemver(options.sdkVersion) === null) return;
24305
- const staleFiles = [];
24306
- for (const fileName of AGENT_INSTRUCTION_FILES) {
24307
- const fullPath = path2.join(options.projectRoot, fileName);
24308
- const state = inspectFile(fullPath, options.sdkVersion);
24309
- if (state === "stale") {
24310
- staleFiles.push(fileName);
24311
- }
24312
- }
24313
- if (staleFiles.length === 0) return;
24314
- const fileList = staleFiles.join(", ");
24315
- const message = `[glasstrace] Glasstrace managed MCP section in ${fileList} was rendered by an older @glasstrace/sdk; run \`npx glasstrace upgrade-instructions\` to refresh (silence with GLASSTRACE_DISABLE_UPGRADE_NOTICE=1).
24316
- `;
24317
- warningEmitted = true;
24318
- if (options.stderrWrite !== void 0) {
24319
- options.stderrWrite(message);
24320
- return;
24253
+ span.setAttribute(GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_KIND, input.kind);
24254
+ span.setAttribute(
24255
+ GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OPERATION,
24256
+ input.operation
24257
+ );
24258
+ if (input.status !== void 0) {
24259
+ span.setAttribute(
24260
+ GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_STATUS,
24261
+ input.status
24262
+ );
24321
24263
  }
24322
- try {
24323
- process.stderr.write(message);
24324
- } catch {
24264
+ if (input.phase !== void 0) {
24265
+ span.setAttribute(
24266
+ GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_PHASE,
24267
+ input.phase
24268
+ );
24325
24269
  }
24326
24270
  } catch {
24327
24271
  }
24272
+ return { kind: "attached", span };
24273
+ }
24274
+ function attachField(span, key, value) {
24275
+ const attribute = resolveFieldAttribute(key);
24276
+ try {
24277
+ span.setAttribute(attribute, value);
24278
+ } catch {
24279
+ }
24280
+ }
24281
+ function recordOmission(span, reason) {
24282
+ recordOmissionOnSpan(span, reason);
24328
24283
  }
24329
24284
 
24330
- // src/register.ts
24331
- function maskKey(key) {
24332
- if (key.length <= 12) return key.slice(0, 4) + "...";
24333
- return key.slice(0, 8) + "..." + key.slice(-4);
24285
+ // src/side-effect/index.ts
24286
+ var _verbose = false;
24287
+ function setSideEffectVerboseFlag(verbose) {
24288
+ _verbose = verbose;
24289
+ }
24290
+ var _casingWarnSeen = /* @__PURE__ */ new Map();
24291
+ var _CASING_DEDUP_MAX_KEYS = 100;
24292
+ var _patternKeysSeen = /* @__PURE__ */ new Set();
24293
+ var _recentPatternKeys = [];
24294
+ var _proliferationWarned = false;
24295
+ var _PROLIFERATION_THRESHOLD = 50;
24296
+ var _RECENT_KEYS_IN_WARN = 5;
24297
+ function shouldCheckCasingConvention(key) {
24298
+ return key.endsWith("Class") || key.endsWith("Role");
24299
+ }
24300
+ function casingPattern(value) {
24301
+ return value === value.toUpperCase() ? "uppercase" : "mixed";
24302
+ }
24303
+ function maybeWarnMixedCasing(key, value) {
24304
+ if (!shouldCheckCasingConvention(key)) return;
24305
+ if (value === value.toLowerCase()) return;
24306
+ const pattern = casingPattern(value);
24307
+ let seenPatterns = _casingWarnSeen.get(key);
24308
+ if (!seenPatterns) {
24309
+ if (_casingWarnSeen.size >= _CASING_DEDUP_MAX_KEYS) return;
24310
+ seenPatterns = /* @__PURE__ */ new Set();
24311
+ _casingWarnSeen.set(key, seenPatterns);
24312
+ }
24313
+ if (seenPatterns.has(pattern)) return;
24314
+ seenPatterns.add(pattern);
24315
+ console.warn(
24316
+ `[glasstrace] side-effect field "${key}" value has ${pattern} casing; convention is lowercase-kebab. Producer should normalize.`
24317
+ );
24334
24318
  }
24335
- var consoleCaptureInstalled = false;
24336
- var discoveryHandler = null;
24337
- var registrationGeneration = 0;
24338
- var _sessionManager = null;
24339
- function getSessionManager() {
24340
- if (!_sessionManager) {
24341
- _sessionManager = new SessionManager();
24319
+ function maybeWarnPatternKeyProliferation(key) {
24320
+ if (!_verbose) return;
24321
+ if (_proliferationWarned) return;
24322
+ if (hasExplicitFieldAttribute(key)) return;
24323
+ if (_patternKeysSeen.has(key)) return;
24324
+ _patternKeysSeen.add(key);
24325
+ _recentPatternKeys.push(key);
24326
+ if (_recentPatternKeys.length > _RECENT_KEYS_IN_WARN) {
24327
+ _recentPatternKeys.shift();
24328
+ }
24329
+ if (_patternKeysSeen.size >= _PROLIFERATION_THRESHOLD) {
24330
+ _proliferationWarned = true;
24331
+ console.warn(
24332
+ `[glasstrace] side-effect emission has used ${_patternKeysSeen.size} distinct pattern-admitted field keys this process; recent: ${_recentPatternKeys.join(", ")}. Consider producer-side vocabulary review (lowercase-kebab convention; Class/Count/Kind/Role suffixes).`
24333
+ );
24342
24334
  }
24343
- return _sessionManager;
24344
24335
  }
24345
- function registerGlasstrace(options) {
24336
+ function recordSideEffect(input) {
24346
24337
  try {
24347
- if (getCoreState() !== CoreState.IDLE) {
24348
- return;
24349
- }
24350
- initLifecycle({ logger: sdkLog });
24351
- if (typeof process === "undefined" || typeof process.versions?.node !== "string") {
24352
- console.warn(
24353
- "[glasstrace] SDK requires a Node.js runtime. Edge Runtime, browser, and Deno without Node compat are not supported. Glasstrace is disabled in this environment."
24354
- );
24355
- return;
24356
- }
24357
- setCoreState(CoreState.REGISTERING);
24358
- maybeWarnStaleAgentInstructions({
24359
- projectRoot: process.cwd(),
24360
- sdkVersion: "1.12.0"
24361
- });
24362
- startRuntimeStateWriter({
24363
- projectRoot: process.cwd(),
24364
- sdkVersion: "1.12.0"
24365
- });
24366
- const config2 = resolveConfig(options);
24367
- if (config2.verbose) {
24368
- console.info("[glasstrace] Config resolved.");
24369
- }
24370
- if (isProductionDisabled(config2)) {
24371
- setCoreState(CoreState.PRODUCTION_DISABLED);
24372
- console.warn(
24373
- "[glasstrace] Disabled in production. Set GLASSTRACE_FORCE_ENABLE=true to override."
24374
- );
24375
- return;
24338
+ runRecordSideEffect(input);
24339
+ } catch {
24340
+ }
24341
+ }
24342
+ function runRecordSideEffect(input) {
24343
+ if (!input || typeof input !== "object") return;
24344
+ let captureEnabled;
24345
+ try {
24346
+ captureEnabled = getActiveConfig().sideEffectEvidence === true;
24347
+ } catch {
24348
+ captureEnabled = false;
24349
+ }
24350
+ if (!captureEnabled) {
24351
+ return;
24352
+ }
24353
+ const candidate = input;
24354
+ if (!checkOperationKind(candidate.kind)) {
24355
+ return;
24356
+ }
24357
+ const labelOutcome = checkOperationLabel(candidate.operation);
24358
+ if (!labelOutcome.accepted) {
24359
+ recordOmissionOnActiveSpan(labelOutcome.reason);
24360
+ return;
24361
+ }
24362
+ let acceptedStatus;
24363
+ if (candidate.status !== void 0) {
24364
+ if (checkOperationStatus(candidate.status)) {
24365
+ acceptedStatus = candidate.status;
24366
+ } else {
24367
+ recordOmissionOnActiveSpan("unsupported_key");
24376
24368
  }
24377
- if (config2.verbose) {
24378
- console.info("[glasstrace] Not production-disabled.");
24369
+ }
24370
+ let acceptedPhase;
24371
+ if (candidate.phase !== void 0) {
24372
+ if (checkOperationPhase(candidate.phase)) {
24373
+ acceptedPhase = candidate.phase;
24374
+ } else {
24375
+ recordOmissionOnActiveSpan("unsupported_key");
24379
24376
  }
24380
- const existingTracerProvider = trace.getTracerProvider();
24381
- const existingProbe = existingTracerProvider.getTracer("glasstrace-probe");
24382
- const anotherProviderRegistered = !isProxyTracerProvider(existingTracerProvider) || !isProxyTracer(existingProbe, existingTracerProvider);
24383
- if (anotherProviderRegistered) {
24384
- setCoexistenceState("coexisting");
24385
- }
24386
- registerSignalHandlers();
24387
- const anonymous = isAnonymousMode(config2);
24388
- let effectiveKey = config2.apiKey;
24389
- initAuthState(anonymous ? AuthState.ANONYMOUS : AuthState.AUTHENTICATED);
24390
- if (effectiveKey) {
24391
- setResolvedApiKey(effectiveKey);
24392
- emitLifecycleEvent("auth:key_resolved", {
24393
- key: maskKey(effectiveKey),
24394
- mode: anonymous ? "anonymous" : "dev"
24395
- });
24396
- }
24397
- if (config2.verbose) {
24398
- console.info(
24399
- `[glasstrace] Auth mode = ${anonymous ? "anonymous" : "dev-key"}.`
24400
- );
24401
- }
24402
- const cachedInitResponse = loadCachedConfig();
24403
- if (cachedInitResponse) {
24404
- _setCurrentConfig(cachedInitResponse);
24405
- }
24406
- if (config2.verbose) {
24407
- console.info(
24408
- `[glasstrace] Cached config ${cachedInitResponse ? "loaded and applied" : "not found"}.`
24409
- );
24410
- }
24411
- const sessionManager = getSessionManager();
24412
- if (config2.verbose) {
24413
- console.info("[glasstrace] SessionManager created.");
24414
- }
24415
- setCoreState(CoreState.KEY_PENDING);
24416
- const currentGeneration = registrationGeneration;
24417
- if (anotherProviderRegistered) {
24418
- if (config2.verbose) {
24419
- console.info("[glasstrace] Another OTel provider detected \u2014 using existing context manager.");
24420
- }
24421
- } else {
24422
- const contextManagerInstalled = installContextManager();
24423
- if (config2.verbose) {
24424
- console.info(
24425
- contextManagerInstalled ? "[glasstrace] Context manager installed." : "[glasstrace] Context manager not available \u2014 trace context propagation disabled."
24426
- );
24427
- }
24428
- }
24429
- void configureOtel(config2, sessionManager).then(
24430
- () => {
24431
- maybeInstallConsoleCapture();
24432
- if (config2.verbose) {
24433
- console.info("[glasstrace] OTel configured.");
24434
- }
24435
- },
24436
- (err) => {
24437
- console.warn(
24438
- `[glasstrace] Failed to configure OTel: ${err instanceof Error ? err.message : String(err)}`
24439
- );
24440
- }
24441
- );
24442
- if (anonymous) {
24443
- if (isDiscoveryEnabled(config2)) {
24444
- let resolvedAnonKey = null;
24445
- const anonKeyPromise = getOrCreateAnonKey();
24446
- const getClaimState = () => {
24447
- if (getLinkedAccountId()) return { claimed: true };
24448
- if (getClaimResult()) return { claimed: true };
24449
- return null;
24450
- };
24451
- discoveryHandler = createDiscoveryHandler(
24452
- async () => resolvedAnonKey,
24453
- () => sessionManager.getSessionId(getResolvedApiKey()),
24454
- getClaimState
24455
- );
24456
- if (config2.verbose) {
24457
- console.info("[glasstrace] Discovery endpoint registered (key pending).");
24458
- }
24459
- void (async () => {
24460
- try {
24461
- if (currentGeneration !== registrationGeneration) return;
24462
- const anonKey = await anonKeyPromise;
24463
- resolvedAnonKey = anonKey;
24464
- setResolvedApiKey(anonKey);
24465
- notifyApiKeyResolved();
24466
- emitLifecycleEvent("auth:key_resolved", { key: maskKey(anonKey), mode: "anonymous" });
24467
- effectiveKey = anonKey;
24468
- if (currentGeneration !== registrationGeneration) return;
24469
- discoveryHandler = createDiscoveryHandler(
24470
- () => Promise.resolve(anonKey),
24471
- () => sessionManager.getSessionId(getResolvedApiKey()),
24472
- getClaimState
24473
- );
24474
- await backgroundInit(config2, anonKey, currentGeneration);
24475
- } catch (err) {
24476
- console.warn(
24477
- `[glasstrace] Background init failed: ${err instanceof Error ? err.message : String(err)}`
24478
- );
24479
- }
24480
- })();
24481
- } else {
24482
- void (async () => {
24483
- try {
24484
- if (currentGeneration !== registrationGeneration) return;
24485
- const anonKey = await getOrCreateAnonKey();
24486
- setResolvedApiKey(anonKey);
24487
- notifyApiKeyResolved();
24488
- emitLifecycleEvent("auth:key_resolved", { key: maskKey(anonKey), mode: "anonymous" });
24489
- effectiveKey = anonKey;
24490
- if (currentGeneration !== registrationGeneration) return;
24491
- await backgroundInit(config2, anonKey, currentGeneration);
24492
- } catch (err) {
24493
- console.warn(
24494
- `[glasstrace] Background init failed: ${err instanceof Error ? err.message : String(err)}`
24495
- );
24496
- }
24497
- })();
24498
- }
24499
- } else {
24500
- void (async () => {
24501
- try {
24502
- if (currentGeneration !== registrationGeneration) return;
24503
- let anonKeyForInit = null;
24504
- try {
24505
- anonKeyForInit = await readAnonKey();
24506
- } catch {
24507
- }
24508
- if (currentGeneration !== registrationGeneration) return;
24509
- await backgroundInit(config2, anonKeyForInit, currentGeneration);
24510
- } catch (err) {
24511
- console.warn(
24512
- `[glasstrace] Background init failed: ${err instanceof Error ? err.message : String(err)}`
24513
- );
24514
- }
24515
- })();
24516
- }
24517
- if (config2.coverageMapEnabled && config2.verbose) {
24518
- console.info("[glasstrace] Import graph building skipped.");
24519
- }
24520
- } catch (err) {
24521
- setCoreState(CoreState.REGISTRATION_FAILED);
24522
- console.warn(
24523
- `[glasstrace] Registration failed: ${err instanceof Error ? err.message : String(err)}`
24524
- );
24525
- }
24526
- }
24527
- async function backgroundInit(config2, anonKeyForInit, generation) {
24528
- if (config2.verbose) {
24529
- console.info("[glasstrace] Background init firing.");
24530
24377
  }
24531
- const healthReport = collectHealthReport("1.12.0");
24532
- const initResult = await performInit(config2, anonKeyForInit, "1.12.0", healthReport);
24533
- if (generation !== registrationGeneration) return;
24534
- const currentState = getCoreState();
24535
- if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
24378
+ const outcome = attachOperation({
24379
+ kind: candidate.kind,
24380
+ operation: labelOutcome.value,
24381
+ status: acceptedStatus,
24382
+ phase: acceptedPhase
24383
+ });
24384
+ if (outcome.kind === "no_active_span") {
24536
24385
  return;
24537
24386
  }
24538
- if (currentState === CoreState.KEY_PENDING) {
24539
- setCoreState(CoreState.KEY_RESOLVED);
24540
- }
24541
- if (getCoreState() === CoreState.KEY_RESOLVED) {
24542
- setCoreState(didLastInitSucceed() ? CoreState.ACTIVE : CoreState.ACTIVE_DEGRADED);
24543
- }
24544
- if (initResult?.claimResult) {
24545
- const { newApiKey, accountId } = initResult.claimResult;
24546
- setAuthState(AuthState.CLAIMING);
24547
- emitLifecycleEvent("auth:claim_started", { accountId });
24548
- setResolvedApiKey(newApiKey);
24549
- notifyApiKeyResolved();
24550
- setAuthState(AuthState.CLAIMED);
24551
- emitLifecycleEvent("auth:claim_completed", { newKey: maskKey(newApiKey), accountId });
24552
- }
24553
- maybeInstallConsoleCapture();
24554
- if (didLastInitSucceed()) {
24555
- startHeartbeat(config2, anonKeyForInit, "1.12.0", generation, (newApiKey, accountId) => {
24556
- setAuthState(AuthState.CLAIMING);
24557
- emitLifecycleEvent("auth:claim_started", { accountId });
24558
- setResolvedApiKey(newApiKey);
24559
- notifyApiKeyResolved();
24560
- setAuthState(AuthState.CLAIMED);
24561
- emitLifecycleEvent("auth:claim_completed", { newKey: maskKey(newApiKey), accountId });
24562
- });
24563
- }
24564
- }
24565
- function getDiscoveryHandler() {
24566
- return discoveryHandler;
24567
- }
24568
- function maybeInstallConsoleCapture() {
24569
- if (consoleCaptureInstalled) return;
24570
- if (getActiveConfig().consoleErrors) {
24571
- consoleCaptureInstalled = true;
24572
- void installConsoleCapture();
24387
+ if (outcome.kind === "over_budget") {
24388
+ recordOmission(outcome.span, "value_too_long");
24389
+ return;
24573
24390
  }
24574
- }
24575
- function isDiscoveryEnabled(config2) {
24576
- if (process.env.GLASSTRACE_DISCOVERY_ENABLED === "true") return true;
24577
- if (process.env.GLASSTRACE_DISCOVERY_ENABLED === "false") return false;
24578
- if (config2.nodeEnv === "production") return false;
24579
- if (config2.vercelEnv === "production") return false;
24580
- if (config2.nodeEnv === "development" || config2.nodeEnv === void 0) return true;
24581
- return false;
24582
- }
24583
-
24584
- // src/config-wrapper.ts
24585
- var import_node_module = require("node:module");
24586
- function isTurbopackBuild() {
24587
- if (typeof process === "undefined") return false;
24588
- const argv = Array.isArray(process.argv) ? process.argv : [];
24589
- if (argv.includes("--webpack")) return false;
24590
- if (argv.includes("--turbopack")) return true;
24591
- if (process.env?.TURBOPACK === "1") return true;
24592
- return false;
24593
- }
24594
- var SDK_PACKAGE_NAME = "@glasstrace/sdk";
24595
- function appendNodeSchemeExternal(webpackConfig) {
24596
- const nodeBuiltinExternal = (data, callback) => {
24597
- const request = data.request;
24598
- if (typeof request === "string" && (0, import_node_module.isBuiltin)(request)) {
24599
- callback(null, "commonjs " + request);
24600
- return;
24391
+ const fields = candidate.fields;
24392
+ if (fields && typeof fields === "object") {
24393
+ for (const [rawKey, rawValue] of Object.entries(fields)) {
24394
+ if (!checkSemanticFieldKey(rawKey)) {
24395
+ recordOmission(outcome.span, "unsupported_key");
24396
+ continue;
24397
+ }
24398
+ const valueOutcome = checkSemanticFieldValue(rawKey, rawValue);
24399
+ if (!valueOutcome.accepted) {
24400
+ recordOmission(outcome.span, valueOutcome.reason);
24401
+ continue;
24402
+ }
24403
+ try {
24404
+ maybeWarnMixedCasing(rawKey, valueOutcome.value);
24405
+ maybeWarnPatternKeyProliferation(rawKey);
24406
+ } catch {
24407
+ }
24408
+ attachField(outcome.span, rawKey, valueOutcome.value);
24601
24409
  }
24602
- callback(null);
24603
- };
24604
- const existing = webpackConfig.externals;
24605
- if (Array.isArray(existing)) {
24606
- webpackConfig.externals = [...existing, nodeBuiltinExternal];
24607
- } else if (existing == null) {
24608
- webpackConfig.externals = [nodeBuiltinExternal];
24609
- } else {
24610
- webpackConfig.externals = [existing, nodeBuiltinExternal];
24611
24410
  }
24612
24411
  }
24613
- function ensureServerExternal(config2) {
24614
- const existingStable = config2.serverExternalPackages;
24615
- const stable = Array.isArray(existingStable) ? (
24616
- // Clone so we never mutate a caller-owned array in place.
24617
- existingStable.filter((entry) => typeof entry === "string")
24618
- ) : [];
24619
- if (!stable.includes(SDK_PACKAGE_NAME)) {
24620
- stable.push(SDK_PACKAGE_NAME);
24621
- }
24622
- config2.serverExternalPackages = stable;
24412
+
24413
+ // src/runtime-state.ts
24414
+ init_console_capture();
24415
+ var fsSync = null;
24416
+ var pathSync = null;
24417
+ try {
24418
+ fsSync = require("node:fs");
24419
+ pathSync = require("node:path");
24420
+ } catch {
24421
+ fsSync = null;
24422
+ pathSync = null;
24623
24423
  }
24624
- function withGlasstraceConfig(nextConfig) {
24625
- if (typeof process === "undefined" || typeof process.versions?.node !== "string") {
24626
- return nextConfig != null ? { ...nextConfig } : {};
24627
- }
24628
- const config2 = nextConfig != null ? { ...nextConfig } : {};
24629
- const bag = config2;
24630
- const existingExperimental = bag.experimental ?? {};
24631
- bag.experimental = {
24632
- ...existingExperimental,
24633
- serverSourceMaps: true
24634
- };
24635
- ensureServerExternal(bag);
24636
- if (bag.turbopack == null) {
24637
- bag.turbopack = {};
24638
- }
24639
- if (isTurbopackBuild()) {
24640
- warnTurbopackLimitationOnce();
24424
+ var _projectRoot = null;
24425
+ var _sdkVersion = "unknown";
24426
+ var _lastScenario;
24427
+ var _lastError;
24428
+ var _debounceTimer = null;
24429
+ var _started = false;
24430
+ function startRuntimeStateWriter(options) {
24431
+ if (_started) return;
24432
+ if (!isSyncFsAvailable() || fsSync === null || pathSync === null) {
24433
+ _started = true;
24434
+ return;
24641
24435
  }
24642
- const distDir = typeof bag.distDir === "string" ? bag.distDir : ".next";
24643
- const existingWebpack = bag.webpack;
24644
- bag.webpack = (webpackConfig, context2) => {
24645
- let result = webpackConfig;
24646
- if (typeof existingWebpack === "function") {
24647
- result = existingWebpack(webpackConfig, context2);
24648
- }
24649
- const webpackContext = context2;
24650
- if (webpackContext.isServer) {
24651
- appendNodeSchemeExternal(result);
24436
+ _started = true;
24437
+ _projectRoot = options.projectRoot;
24438
+ _sdkVersion = options.sdkVersion;
24439
+ onLifecycleEvent("core:state_changed", ({ to }) => {
24440
+ if (to === CoreState.SHUTDOWN) {
24441
+ writeStateNow();
24442
+ } else {
24443
+ debouncedWrite();
24652
24444
  }
24653
- if (!webpackContext.isServer && webpackContext.dev === false) {
24654
- const plugins = result.plugins ?? [];
24655
- plugins.push({
24656
- apply(compiler) {
24657
- const typedCompiler = compiler;
24658
- if (typedCompiler.hooks?.afterEmit?.tapPromise) {
24659
- typedCompiler.hooks.afterEmit.tapPromise(
24660
- "GlasstraceSourceMapUpload",
24661
- async () => {
24662
- await handleSourceMapUpload(distDir);
24663
- }
24664
- );
24665
- }
24666
- }
24667
- });
24668
- result.plugins = plugins;
24445
+ });
24446
+ onLifecycleEvent("otel:configured", ({ scenario }) => {
24447
+ _lastScenario = scenario;
24448
+ debouncedWrite();
24449
+ });
24450
+ onLifecycleEvent("otel:failed", (payload) => {
24451
+ _lastError = { ...payload };
24452
+ debouncedWrite();
24453
+ });
24454
+ onLifecycleEvent("otel:circuit_opened", (payload) => {
24455
+ _lastError = {
24456
+ category: "export-circuit-open",
24457
+ message: payload.message,
24458
+ timestamp: payload.timestamp,
24459
+ exportCircuitCategory: payload.category
24460
+ };
24461
+ debouncedWrite();
24462
+ });
24463
+ onLifecycleEvent("otel:circuit_closed", () => {
24464
+ if (_lastError?.category === "export-circuit-open") {
24465
+ _lastError = void 0;
24466
+ debouncedWrite();
24669
24467
  }
24670
- return result;
24671
- };
24672
- return config2;
24673
- }
24674
- var _turbopackWarningEmitted = false;
24675
- function warnTurbopackLimitationOnce() {
24676
- if (_turbopackWarningEmitted) return;
24677
- _turbopackWarningEmitted = true;
24678
- console.warn(
24679
- "[glasstrace] Turbopack detected. Source-map upload currently runs only under webpack \u2014 run `next build --webpack` to upload source maps, or wait for the Turbopack port in a future SDK release."
24680
- );
24468
+ });
24469
+ onLifecycleEvent("auth:key_resolved", () => debouncedWrite());
24470
+ onLifecycleEvent("auth:claim_started", () => debouncedWrite());
24471
+ onLifecycleEvent("auth:claim_completed", () => debouncedWrite());
24472
+ writeStateNow();
24681
24473
  }
24682
- async function handleSourceMapUpload(distDir) {
24474
+ function debouncedWrite() {
24475
+ if (_debounceTimer) return;
24476
+ _debounceTimer = setTimeout(() => {
24477
+ _debounceTimer = null;
24478
+ writeStateNow();
24479
+ }, 1e3);
24480
+ if (typeof _debounceTimer === "object" && "unref" in _debounceTimer) {
24481
+ _debounceTimer.unref();
24482
+ }
24483
+ }
24484
+ function writeStateNow() {
24485
+ if (!_projectRoot) return;
24683
24486
  try {
24684
- const apiKey = process.env.GLASSTRACE_API_KEY;
24685
- const endpoint = process.env.GLASSTRACE_ENDPOINT ?? "https://api.glasstrace.dev";
24686
- if (!apiKey || apiKey.trim() === "") {
24687
- console.info(
24688
- "[glasstrace] Source map upload skipped (no API key). Stack traces will show compiled locations."
24689
- );
24690
- return;
24691
- }
24692
- const { discoverSourceMapFiles: discoverSourceMapFiles2, computeBuildHash: computeBuildHash2, uploadSourceMaps: uploadSourceMaps2 } = await Promise.resolve().then(() => (init_source_map_uploader(), source_map_uploader_exports));
24693
- const files = await discoverSourceMapFiles2(distDir);
24694
- if (files.length === 0) {
24695
- console.info("[glasstrace] No source map files found. Skipping upload.");
24696
- return;
24487
+ const state = getSdkState();
24488
+ const runtimeState = {
24489
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
24490
+ pid: process.pid,
24491
+ sdkVersion: _sdkVersion,
24492
+ core: { state: state.core },
24493
+ auth: { state: state.auth },
24494
+ otel: { state: state.otel, scenario: _lastScenario }
24495
+ };
24496
+ if (_lastError) {
24497
+ runtimeState.lastError = _lastError;
24697
24498
  }
24698
- const buildHash = await computeBuildHash2(files);
24699
- await uploadSourceMaps2(apiKey, endpoint, buildHash, files);
24700
- console.info(
24701
- `[glasstrace] Uploaded ${String(files.length)} source map(s) for build ${buildHash}.`
24702
- );
24703
- } catch (error51) {
24704
- const message = error51 instanceof Error ? error51.message : "Unknown error";
24705
- console.warn(
24706
- `[glasstrace] Source map upload failed: ${message}. Build continues normally.`
24499
+ const dir = pathSync.join(_projectRoot, ".glasstrace");
24500
+ const filePath = pathSync.join(dir, "runtime-state.json");
24501
+ fsSync.mkdirSync(dir, { recursive: true, mode: 448 });
24502
+ atomicWriteFileSync(filePath, JSON.stringify(runtimeState, null, 2) + "\n", {
24503
+ mode: 384
24504
+ });
24505
+ } catch (err) {
24506
+ sdkLog(
24507
+ "warn",
24508
+ `[glasstrace] Failed to write runtime state: ${err instanceof Error ? err.message : String(err)}`
24707
24509
  );
24708
24510
  }
24709
24511
  }
24710
24512
 
24711
- // src/capture-error.ts
24712
- init_esm();
24713
- init_dist();
24714
- init_error_nudge();
24513
+ // src/agent-detection/upgrade-notice.ts
24514
+ var fs2 = __toESM(require("node:fs"), 1);
24515
+ var path2 = __toESM(require("node:path"), 1);
24715
24516
 
24716
- // src/stack-frame.ts
24717
- var PAREN_FRAME = /^\s*at\s+(?!eval\s+\(eval\s+at\b)(?:[^()]+\s+)?\(([^()\s]+(?:\([A-Za-z0-9_.-]+\)[^()\s]*)*):(\d+):(\d+)\)\s*$/;
24718
- var BARE_FRAME = /^\s*at\s+(?:async\s+)?([^()\s]+(?:\([A-Za-z0-9_.-]+\)[^()\s]*)*):(\d+):(\d+)\s*$/;
24719
- var INTERNAL_FRAME_PATTERNS = [
24720
- /^node:/,
24721
- /^node:internal\//,
24722
- /[/\\]node_modules[/\\]@glasstrace[/\\]sdk[/\\]/,
24723
- /[/\\]packages[/\\]sdk[/\\]src[/\\]capture-error\./,
24724
- /[/\\]packages[/\\]sdk[/\\]src[/\\]stack-frame\./
24517
+ // src/agent-detection/inject.ts
24518
+ var HTML_START_RE = /^<!--\s*glasstrace:mcp:start(?:\s+v=([^\s>]+))?\s*-->$/;
24519
+ var HTML_END = "<!-- glasstrace:mcp:end -->";
24520
+ var HASH_START_RE = /^#\s*glasstrace:mcp:start(?:\s+v=(\S+))?$/;
24521
+ var HASH_END = "# glasstrace:mcp:end";
24522
+ function parseStartMarkerLine(line) {
24523
+ const trimmed = line.trim();
24524
+ const html = HTML_START_RE.exec(trimmed);
24525
+ if (html !== null) {
24526
+ return { kind: "html", stamp: html[1] ?? null };
24527
+ }
24528
+ const hash2 = HASH_START_RE.exec(trimmed);
24529
+ if (hash2 !== null) {
24530
+ return { kind: "hash", stamp: hash2[1] ?? null };
24531
+ }
24532
+ return null;
24533
+ }
24534
+ function isEndMarker(line) {
24535
+ const trimmed = line.trim();
24536
+ return trimmed === HTML_END || trimmed === HASH_END;
24537
+ }
24538
+ function isEndMarkerLine(line) {
24539
+ return isEndMarker(line);
24540
+ }
24541
+
24542
+ // src/agent-detection/upgrade-notice.ts
24543
+ var warningEmitted = false;
24544
+ var AGENT_INSTRUCTION_FILES = [
24545
+ "AGENTS.md",
24546
+ "CLAUDE.md",
24547
+ "GEMINI.md",
24548
+ ".cursor/rules/glasstrace.mdc",
24549
+ ".windsurf/rules/glasstrace.md",
24550
+ ".cursorrules",
24551
+ "codex.md",
24552
+ ".windsurfrules"
24725
24553
  ];
24726
- function isInternalFrame(file2) {
24727
- return INTERNAL_FRAME_PATTERNS.some((re2) => re2.test(file2));
24554
+ function parseSemver(input) {
24555
+ const plusIdx = input.indexOf("+");
24556
+ const core = plusIdx === -1 ? input : input.slice(0, plusIdx);
24557
+ const m = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(core);
24558
+ if (m === null) return null;
24559
+ return {
24560
+ major: Number(m[1]),
24561
+ minor: Number(m[2]),
24562
+ patch: Number(m[3]),
24563
+ prerelease: m[4] ?? null
24564
+ };
24728
24565
  }
24729
- function parseTopStackFrame(stack) {
24730
- if (typeof stack !== "string" || stack.length === 0) return null;
24731
- let cursor = 0;
24732
- while (cursor < stack.length) {
24733
- const newlineAt = stack.indexOf("\n", cursor);
24734
- const lineEnd = newlineAt === -1 ? stack.length : newlineAt;
24735
- const line = stack.slice(cursor, lineEnd);
24736
- cursor = lineEnd + 1;
24737
- if (!/^\s*at\s/.test(line)) continue;
24738
- let file2;
24739
- let lineStr;
24740
- const parenMatch = PAREN_FRAME.exec(line);
24741
- if (parenMatch) {
24742
- file2 = parenMatch[1];
24743
- lineStr = parenMatch[2];
24744
- } else {
24745
- const bareMatch = BARE_FRAME.exec(line);
24746
- if (bareMatch) {
24747
- file2 = bareMatch[1];
24748
- lineStr = bareMatch[2];
24749
- }
24566
+ function comparePrerelease(a, b) {
24567
+ const ap = a.split(".");
24568
+ const bp = b.split(".");
24569
+ const len = Math.min(ap.length, bp.length);
24570
+ for (let i = 0; i < len; i++) {
24571
+ const x = ap[i];
24572
+ const y = bp[i];
24573
+ const xNumeric = /^\d+$/.test(x);
24574
+ const yNumeric = /^\d+$/.test(y);
24575
+ if (xNumeric && yNumeric) {
24576
+ const xv = Number(x);
24577
+ const yv = Number(y);
24578
+ if (xv !== yv) return xv < yv ? -1 : 1;
24579
+ } else if (xNumeric) {
24580
+ return -1;
24581
+ } else if (yNumeric) {
24582
+ return 1;
24583
+ } else if (x !== y) {
24584
+ return x < y ? -1 : 1;
24750
24585
  }
24751
- if (!file2 || !lineStr) continue;
24752
- if (isInternalFrame(file2)) continue;
24753
- const lineNum = Number.parseInt(lineStr, 10);
24754
- if (!Number.isFinite(lineNum) || lineNum <= 0) continue;
24755
- return { file: file2, line: lineNum };
24756
24586
  }
24757
- return null;
24587
+ return ap.length - bp.length;
24758
24588
  }
24759
-
24760
- // src/capture-error.ts
24761
- function captureError(error51) {
24589
+ function compareSemver(a, b) {
24590
+ const pa = parseSemver(a);
24591
+ const pb = parseSemver(b);
24592
+ if (pa === null || pb === null) return null;
24593
+ if (pa.major !== pb.major) return pa.major - pb.major;
24594
+ if (pa.minor !== pb.minor) return pa.minor - pb.minor;
24595
+ if (pa.patch !== pb.patch) return pa.patch - pb.patch;
24596
+ if (pa.prerelease === null && pb.prerelease === null) return 0;
24597
+ if (pa.prerelease === null) return 1;
24598
+ if (pb.prerelease === null) return -1;
24599
+ return comparePrerelease(pa.prerelease, pb.prerelease);
24600
+ }
24601
+ function isOptedOut() {
24602
+ const raw = process.env.GLASSTRACE_DISABLE_UPGRADE_NOTICE;
24603
+ if (typeof raw !== "string") return false;
24604
+ const trimmed = raw.trim().toLowerCase();
24605
+ return trimmed === "1" || trimmed === "true" || trimmed === "yes";
24606
+ }
24607
+ function isQuietCiContext() {
24608
+ const stderrIsTty = process.stderr.isTTY === true;
24609
+ if (stderrIsTty) return false;
24610
+ return process.env.CI === "true";
24611
+ }
24612
+ var MAX_AGENT_FILE_BYTES = 5 * 1024 * 1024;
24613
+ function inspectFile(filePath, runningSdkVersion) {
24614
+ let content;
24762
24615
  try {
24763
- const span = trace.getSpan(context.active());
24764
- if (!span) return;
24765
- const attributes = {
24766
- "error.message": String(error51)
24767
- };
24768
- if (error51 instanceof Error) {
24769
- attributes["error.type"] = error51.constructor.name;
24770
- if (error51.stack) {
24771
- attributes["error.stack"] = error51.stack;
24772
- const frame = parseTopStackFrame(error51.stack);
24773
- if (frame) {
24774
- attributes[GLASSTRACE_ATTRIBUTE_NAMES.SOURCE_FILE] = frame.file;
24775
- attributes[GLASSTRACE_ATTRIBUTE_NAMES.SOURCE_LINE] = frame.line;
24776
- }
24616
+ const stat2 = fs2.statSync(filePath);
24617
+ if (!stat2.isFile()) return "absent";
24618
+ if (stat2.size > MAX_AGENT_FILE_BYTES) return "absent";
24619
+ content = fs2.readFileSync(filePath, "utf-8");
24620
+ } catch {
24621
+ return "absent";
24622
+ }
24623
+ const lines = content.split("\n");
24624
+ let lastStart = null;
24625
+ let foundEnd = false;
24626
+ for (const line of lines) {
24627
+ const parsed = parseStartMarkerLine(line);
24628
+ if (parsed !== null) {
24629
+ lastStart = parsed;
24630
+ continue;
24631
+ }
24632
+ if (lastStart !== null && isEndMarkerLine(line)) {
24633
+ foundEnd = true;
24634
+ break;
24635
+ }
24636
+ }
24637
+ if (lastStart === null || !foundEnd) {
24638
+ return "no-section";
24639
+ }
24640
+ if (lastStart.stamp === null) {
24641
+ return "no-stamp";
24642
+ }
24643
+ const cmp = compareSemver(lastStart.stamp, runningSdkVersion);
24644
+ if (cmp === null) {
24645
+ return "unknown-stamp";
24646
+ }
24647
+ return cmp < 0 ? "stale" : "current";
24648
+ }
24649
+ function maybeWarnStaleAgentInstructions(options) {
24650
+ try {
24651
+ if (warningEmitted) return;
24652
+ if (typeof process === "undefined" || typeof process.versions?.node !== "string" || typeof process.env !== "object" || process.env === null) {
24653
+ return;
24654
+ }
24655
+ if (isOptedOut()) return;
24656
+ if (isQuietCiContext()) return;
24657
+ if (parseSemver(options.sdkVersion) === null) return;
24658
+ const staleFiles = [];
24659
+ for (const fileName of AGENT_INSTRUCTION_FILES) {
24660
+ const fullPath = path2.join(options.projectRoot, fileName);
24661
+ const state = inspectFile(fullPath, options.sdkVersion);
24662
+ if (state === "stale") {
24663
+ staleFiles.push(fileName);
24777
24664
  }
24778
24665
  }
24779
- span.addEvent("glasstrace.error", attributes);
24780
- maybeShowMcpNudge(String(error51));
24666
+ if (staleFiles.length === 0) return;
24667
+ const fileList = staleFiles.join(", ");
24668
+ const message = `[glasstrace] Glasstrace managed MCP section in ${fileList} was rendered by an older @glasstrace/sdk; run \`npx glasstrace upgrade-instructions\` to refresh (silence with GLASSTRACE_DISABLE_UPGRADE_NOTICE=1).
24669
+ `;
24670
+ warningEmitted = true;
24671
+ if (options.stderrWrite !== void 0) {
24672
+ options.stderrWrite(message);
24673
+ return;
24674
+ }
24675
+ try {
24676
+ process.stderr.write(message);
24677
+ } catch {
24678
+ }
24781
24679
  } catch {
24782
24680
  }
24783
24681
  }
24784
24682
 
24785
- // src/correlation-id.ts
24786
- init_esm();
24787
- init_dist();
24788
- var ATTR2 = GLASSTRACE_ATTRIBUTE_NAMES;
24789
- var HEADER_NAME = "x-gt-cid";
24790
- var MAX_CID_LENGTH = 128;
24791
- function captureCorrelationId(req) {
24683
+ // src/register.ts
24684
+ function maskKey(key) {
24685
+ if (key.length <= 12) return key.slice(0, 4) + "...";
24686
+ return key.slice(0, 8) + "..." + key.slice(-4);
24687
+ }
24688
+ var consoleCaptureInstalled = false;
24689
+ var discoveryHandler = null;
24690
+ var registrationGeneration = 0;
24691
+ var _sessionManager = null;
24692
+ function getSessionManager() {
24693
+ if (!_sessionManager) {
24694
+ _sessionManager = new SessionManager();
24695
+ }
24696
+ return _sessionManager;
24697
+ }
24698
+ function registerGlasstrace(options) {
24792
24699
  try {
24793
- if (!req || !req.headers) {
24700
+ if (getCoreState() !== CoreState.IDLE) {
24794
24701
  return;
24795
24702
  }
24796
- const value = readHeader(req.headers);
24797
- if (!value) {
24703
+ initLifecycle({ logger: sdkLog });
24704
+ if (typeof process === "undefined" || typeof process.versions?.node !== "string") {
24705
+ console.warn(
24706
+ "[glasstrace] SDK requires a Node.js runtime. Edge Runtime, browser, and Deno without Node compat are not supported. Glasstrace is disabled in this environment."
24707
+ );
24798
24708
  return;
24799
24709
  }
24800
- const span = trace.getActiveSpan();
24801
- if (!span) {
24710
+ setCoreState(CoreState.REGISTERING);
24711
+ maybeWarnStaleAgentInstructions({
24712
+ projectRoot: process.cwd(),
24713
+ sdkVersion: "1.14.0"
24714
+ });
24715
+ startRuntimeStateWriter({
24716
+ projectRoot: process.cwd(),
24717
+ sdkVersion: "1.14.0"
24718
+ });
24719
+ const config2 = resolveConfig(options);
24720
+ setSideEffectVerboseFlag(config2.verbose);
24721
+ if (config2.verbose) {
24722
+ console.info("[glasstrace] Config resolved.");
24723
+ }
24724
+ if (isProductionDisabled(config2)) {
24725
+ setCoreState(CoreState.PRODUCTION_DISABLED);
24726
+ console.warn(
24727
+ "[glasstrace] Disabled in production. Set GLASSTRACE_FORCE_ENABLE=true to override."
24728
+ );
24802
24729
  return;
24803
24730
  }
24804
- span.setAttribute(ATTR2.CORRELATION_ID, value);
24805
- } catch {
24806
- }
24807
- }
24808
- function readHeader(headers) {
24809
- const asFetch = headers;
24810
- if (typeof asFetch.get === "function") {
24811
- const raw = asFetch.get(HEADER_NAME);
24812
- return firstToken(raw);
24813
- }
24814
- const dict = headers;
24815
- const direct = dict[HEADER_NAME];
24816
- if (direct !== void 0) {
24817
- return firstValue(direct);
24818
- }
24819
- for (const key of Object.keys(dict)) {
24820
- if (key.toLowerCase() === HEADER_NAME) {
24821
- return firstValue(dict[key]);
24731
+ if (config2.verbose) {
24732
+ console.info("[glasstrace] Not production-disabled.");
24822
24733
  }
24823
- }
24824
- return void 0;
24825
- }
24826
- function firstValue(value) {
24827
- if (Array.isArray(value)) {
24828
- for (const entry of value) {
24829
- const token = firstToken(entry);
24830
- if (token) return token;
24734
+ const existingTracerProvider = trace.getTracerProvider();
24735
+ const existingProbe = existingTracerProvider.getTracer("glasstrace-probe");
24736
+ const anotherProviderRegistered = !isProxyTracerProvider(existingTracerProvider) || !isProxyTracer(existingProbe, existingTracerProvider);
24737
+ if (anotherProviderRegistered) {
24738
+ setCoexistenceState("coexisting");
24831
24739
  }
24832
- return void 0;
24833
- }
24834
- return firstToken(value);
24835
- }
24836
- function firstToken(value) {
24837
- if (typeof value !== "string") return void 0;
24838
- const parts = value.split(",");
24839
- for (const part of parts) {
24840
- const trimmed = part.trim();
24841
- if (trimmed.length === 0) continue;
24842
- if (trimmed.length > MAX_CID_LENGTH) return void 0;
24843
- return trimmed;
24844
- }
24845
- return void 0;
24846
- }
24847
-
24848
- // src/side-effect/allowlist.ts
24849
- init_dist();
24850
- var MAX_SIDE_EFFECT_OPERATION_LABEL_LENGTH = 96;
24851
- var MAX_SIDE_EFFECT_FIELD_VALUE_LENGTH = 80;
24852
- var MAX_SIDE_EFFECT_OPERATIONS_PER_SPAN = 5;
24853
- var OPERATION_KIND_SET = new Set(
24854
- SIDE_EFFECT_OPERATION_KINDS
24855
- );
24856
- var SEMANTIC_FIELD_KEY_SET = new Set(
24857
- SIDE_EFFECT_SEMANTIC_FIELD_KEYS
24858
- );
24859
- var OPERATION_STATUS_SET = new Set(
24860
- SIDE_EFFECT_OPERATION_STATUSES
24861
- );
24862
- var OPERATION_PHASE_SET = new Set(
24863
- SIDE_EFFECT_OPERATION_PHASES
24864
- );
24865
- var OMISSION_REASON_SET = new Set(
24866
- SIDE_EFFECT_OMISSION_REASONS
24867
- );
24868
- var TOKEN_REGEX = /^[A-Za-z0-9][A-Za-z0-9_.:-]*$/;
24869
- var LOCALE_REGEX = /^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8}){0,3}$/;
24870
- var TIMEZONE_REGEX = /^(?:UTC|GMT|[A-Za-z][A-Za-z0-9_+-]*(?:\/[A-Za-z0-9_+-]+){1,3})$/;
24871
- var DIGIT_REGEX = /^[0-9]+$/;
24872
- var URL_SCHEME = /:\/\//;
24873
- var URL_SCHEME_RELATIVE = /^\/\//;
24874
- var EMAIL_LIKE = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i;
24875
- var QUERY_LIKE = /\?/;
24876
- var FRAGMENT_LIKE = /#/;
24877
- var HEADER_LIKE = /\b(authorization|set-cookie|cookie)\b\s*[:=]/i;
24878
- var HEADER_TOKEN_LIKE = /\b(authorization|set-cookie|cookie)\b\s+\S+=/i;
24879
- var BEARER_LIKE = /bearer\s+\S+/i;
24880
- var TOKEN_KV_LIKE = /["']?(password|passwd|token|api[_-]?key|secret|client_secret)["']?\s*[:=]/i;
24881
- var PROSE_LIKE = /[\r\n\t]|\s{2,}/;
24882
- var UUID_LIKE = /[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i;
24883
- var GT_KEY_LIKE = /gt_(dev|anon|live)_[A-Za-z0-9_-]+/;
24884
- function detectUnsafePattern(value) {
24885
- if (value.trim() !== value) return "raw_payload";
24886
- if (PROSE_LIKE.test(value)) return "raw_payload";
24887
- if (URL_SCHEME.test(value)) return "raw_payload";
24888
- if (URL_SCHEME_RELATIVE.test(value)) return "raw_payload";
24889
- if (QUERY_LIKE.test(value)) return "raw_payload";
24890
- if (FRAGMENT_LIKE.test(value)) return "raw_payload";
24891
- if (BEARER_LIKE.test(value)) return "secret";
24892
- if (HEADER_TOKEN_LIKE.test(value)) return "secret";
24893
- if (TOKEN_KV_LIKE.test(value)) return "secret";
24894
- if (HEADER_LIKE.test(value)) return "secret";
24895
- if (UUID_LIKE.test(value)) return "secret";
24896
- if (GT_KEY_LIKE.test(value)) return "secret";
24897
- if (EMAIL_LIKE.test(value)) return "pii";
24898
- return null;
24899
- }
24900
- function passesFieldValidator(key, value) {
24901
- if (key === "locale") return LOCALE_REGEX.test(value);
24902
- if (key === "timezone") return TIMEZONE_REGEX.test(value);
24903
- if (key === "participantCount" || key === "activeParticipantCount") {
24904
- return DIGIT_REGEX.test(value);
24740
+ registerSignalHandlers();
24741
+ const anonymous = isAnonymousMode(config2);
24742
+ let effectiveKey = config2.apiKey;
24743
+ initAuthState(anonymous ? AuthState.ANONYMOUS : AuthState.AUTHENTICATED);
24744
+ if (effectiveKey) {
24745
+ setResolvedApiKey(effectiveKey);
24746
+ emitLifecycleEvent("auth:key_resolved", {
24747
+ key: maskKey(effectiveKey),
24748
+ mode: anonymous ? "anonymous" : "dev"
24749
+ });
24750
+ }
24751
+ if (config2.verbose) {
24752
+ console.info(
24753
+ `[glasstrace] Auth mode = ${anonymous ? "anonymous" : "dev-key"}.`
24754
+ );
24755
+ }
24756
+ const cachedInitResponse = loadCachedConfig();
24757
+ if (cachedInitResponse) {
24758
+ _setCurrentConfig(cachedInitResponse);
24759
+ }
24760
+ if (config2.verbose) {
24761
+ console.info(
24762
+ `[glasstrace] Cached config ${cachedInitResponse ? "loaded and applied" : "not found"}.`
24763
+ );
24764
+ }
24765
+ const sessionManager = getSessionManager();
24766
+ if (config2.verbose) {
24767
+ console.info("[glasstrace] SessionManager created.");
24768
+ }
24769
+ setCoreState(CoreState.KEY_PENDING);
24770
+ const currentGeneration = registrationGeneration;
24771
+ if (anotherProviderRegistered) {
24772
+ if (config2.verbose) {
24773
+ console.info("[glasstrace] Another OTel provider detected \u2014 using existing context manager.");
24774
+ }
24775
+ } else {
24776
+ const contextManagerInstalled = installContextManager();
24777
+ if (config2.verbose) {
24778
+ console.info(
24779
+ contextManagerInstalled ? "[glasstrace] Context manager installed." : "[glasstrace] Context manager not available \u2014 trace context propagation disabled."
24780
+ );
24781
+ }
24782
+ }
24783
+ void configureOtel(config2, sessionManager).then(
24784
+ () => {
24785
+ maybeInstallConsoleCapture();
24786
+ if (config2.verbose) {
24787
+ console.info("[glasstrace] OTel configured.");
24788
+ }
24789
+ },
24790
+ (err) => {
24791
+ console.warn(
24792
+ `[glasstrace] Failed to configure OTel: ${err instanceof Error ? err.message : String(err)}`
24793
+ );
24794
+ }
24795
+ );
24796
+ if (anonymous) {
24797
+ if (isDiscoveryEnabled(config2)) {
24798
+ let resolvedAnonKey = null;
24799
+ const anonKeyPromise = getOrCreateAnonKey();
24800
+ const getClaimState = () => {
24801
+ if (getLinkedAccountId()) return { claimed: true };
24802
+ if (getClaimResult()) return { claimed: true };
24803
+ return null;
24804
+ };
24805
+ discoveryHandler = createDiscoveryHandler(
24806
+ async () => resolvedAnonKey,
24807
+ () => sessionManager.getSessionId(getResolvedApiKey()),
24808
+ getClaimState
24809
+ );
24810
+ if (config2.verbose) {
24811
+ console.info("[glasstrace] Discovery endpoint registered (key pending).");
24812
+ }
24813
+ void (async () => {
24814
+ try {
24815
+ if (currentGeneration !== registrationGeneration) return;
24816
+ const anonKey = await anonKeyPromise;
24817
+ resolvedAnonKey = anonKey;
24818
+ setResolvedApiKey(anonKey);
24819
+ notifyApiKeyResolved();
24820
+ emitLifecycleEvent("auth:key_resolved", { key: maskKey(anonKey), mode: "anonymous" });
24821
+ effectiveKey = anonKey;
24822
+ if (currentGeneration !== registrationGeneration) return;
24823
+ discoveryHandler = createDiscoveryHandler(
24824
+ () => Promise.resolve(anonKey),
24825
+ () => sessionManager.getSessionId(getResolvedApiKey()),
24826
+ getClaimState
24827
+ );
24828
+ await backgroundInit(config2, anonKey, currentGeneration);
24829
+ } catch (err) {
24830
+ console.warn(
24831
+ `[glasstrace] Background init failed: ${err instanceof Error ? err.message : String(err)}`
24832
+ );
24833
+ }
24834
+ })();
24835
+ } else {
24836
+ void (async () => {
24837
+ try {
24838
+ if (currentGeneration !== registrationGeneration) return;
24839
+ const anonKey = await getOrCreateAnonKey();
24840
+ setResolvedApiKey(anonKey);
24841
+ notifyApiKeyResolved();
24842
+ emitLifecycleEvent("auth:key_resolved", { key: maskKey(anonKey), mode: "anonymous" });
24843
+ effectiveKey = anonKey;
24844
+ if (currentGeneration !== registrationGeneration) return;
24845
+ await backgroundInit(config2, anonKey, currentGeneration);
24846
+ } catch (err) {
24847
+ console.warn(
24848
+ `[glasstrace] Background init failed: ${err instanceof Error ? err.message : String(err)}`
24849
+ );
24850
+ }
24851
+ })();
24852
+ }
24853
+ } else {
24854
+ void (async () => {
24855
+ try {
24856
+ if (currentGeneration !== registrationGeneration) return;
24857
+ let anonKeyForInit = null;
24858
+ try {
24859
+ anonKeyForInit = await readAnonKey();
24860
+ } catch {
24861
+ }
24862
+ if (currentGeneration !== registrationGeneration) return;
24863
+ await backgroundInit(config2, anonKeyForInit, currentGeneration);
24864
+ } catch (err) {
24865
+ console.warn(
24866
+ `[glasstrace] Background init failed: ${err instanceof Error ? err.message : String(err)}`
24867
+ );
24868
+ }
24869
+ })();
24870
+ }
24871
+ if (config2.coverageMapEnabled && config2.verbose) {
24872
+ console.info("[glasstrace] Import graph building skipped.");
24873
+ }
24874
+ } catch (err) {
24875
+ setCoreState(CoreState.REGISTRATION_FAILED);
24876
+ console.warn(
24877
+ `[glasstrace] Registration failed: ${err instanceof Error ? err.message : String(err)}`
24878
+ );
24905
24879
  }
24906
- return TOKEN_REGEX.test(value);
24907
24880
  }
24908
- function checkOperationLabel(value) {
24909
- if (typeof value !== "string" || value.length === 0) {
24910
- return { accepted: false, reason: "raw_payload" };
24911
- }
24912
- if (value.length > MAX_SIDE_EFFECT_OPERATION_LABEL_LENGTH) {
24913
- return { accepted: false, reason: "value_too_long" };
24914
- }
24915
- const unsafe = detectUnsafePattern(value);
24916
- if (unsafe) {
24917
- return { accepted: false, reason: unsafe };
24881
+ async function backgroundInit(config2, anonKeyForInit, generation) {
24882
+ if (config2.verbose) {
24883
+ console.info("[glasstrace] Background init firing.");
24918
24884
  }
24919
- if (!TOKEN_REGEX.test(value)) {
24920
- return { accepted: false, reason: "raw_payload" };
24885
+ const healthReport = collectHealthReport("1.14.0");
24886
+ const initResult = await performInit(config2, anonKeyForInit, "1.14.0", healthReport);
24887
+ if (generation !== registrationGeneration) return;
24888
+ const currentState = getCoreState();
24889
+ if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
24890
+ return;
24921
24891
  }
24922
- return { accepted: true, value };
24923
- }
24924
- function checkSemanticFieldValue(key, value) {
24925
- if (typeof value !== "string" || value.length === 0) {
24926
- return { accepted: false, reason: "raw_payload" };
24892
+ if (currentState === CoreState.KEY_PENDING) {
24893
+ setCoreState(CoreState.KEY_RESOLVED);
24927
24894
  }
24928
- if (value.length > MAX_SIDE_EFFECT_FIELD_VALUE_LENGTH) {
24929
- return { accepted: false, reason: "value_too_long" };
24895
+ if (getCoreState() === CoreState.KEY_RESOLVED) {
24896
+ setCoreState(didLastInitSucceed() ? CoreState.ACTIVE : CoreState.ACTIVE_DEGRADED);
24930
24897
  }
24931
- const unsafe = detectUnsafePattern(value);
24932
- if (unsafe) {
24933
- return { accepted: false, reason: unsafe };
24898
+ if (initResult?.claimResult) {
24899
+ const { newApiKey, accountId } = initResult.claimResult;
24900
+ setAuthState(AuthState.CLAIMING);
24901
+ emitLifecycleEvent("auth:claim_started", { accountId });
24902
+ setResolvedApiKey(newApiKey);
24903
+ notifyApiKeyResolved();
24904
+ setAuthState(AuthState.CLAIMED);
24905
+ emitLifecycleEvent("auth:claim_completed", { newKey: maskKey(newApiKey), accountId });
24934
24906
  }
24935
- if (!passesFieldValidator(key, value)) {
24936
- return { accepted: false, reason: "raw_payload" };
24907
+ maybeInstallConsoleCapture();
24908
+ if (didLastInitSucceed()) {
24909
+ startHeartbeat(config2, anonKeyForInit, "1.14.0", generation, (newApiKey, accountId) => {
24910
+ setAuthState(AuthState.CLAIMING);
24911
+ emitLifecycleEvent("auth:claim_started", { accountId });
24912
+ setResolvedApiKey(newApiKey);
24913
+ notifyApiKeyResolved();
24914
+ setAuthState(AuthState.CLAIMED);
24915
+ emitLifecycleEvent("auth:claim_completed", { newKey: maskKey(newApiKey), accountId });
24916
+ });
24937
24917
  }
24938
- return { accepted: true, value };
24939
- }
24940
- function checkSemanticFieldKey(key) {
24941
- return typeof key === "string" && SEMANTIC_FIELD_KEY_SET.has(key);
24942
24918
  }
24943
- function checkOperationKind(kind) {
24944
- return typeof kind === "string" && OPERATION_KIND_SET.has(kind);
24919
+ function getDiscoveryHandler() {
24920
+ return discoveryHandler;
24945
24921
  }
24946
- function checkOperationStatus(status) {
24947
- return typeof status === "string" && OPERATION_STATUS_SET.has(status);
24922
+ function maybeInstallConsoleCapture() {
24923
+ if (consoleCaptureInstalled) return;
24924
+ if (getActiveConfig().consoleErrors) {
24925
+ consoleCaptureInstalled = true;
24926
+ void installConsoleCapture();
24927
+ }
24948
24928
  }
24949
- function checkOperationPhase(phase) {
24950
- return typeof phase === "string" && OPERATION_PHASE_SET.has(phase);
24929
+ function isDiscoveryEnabled(config2) {
24930
+ if (process.env.GLASSTRACE_DISCOVERY_ENABLED === "true") return true;
24931
+ if (process.env.GLASSTRACE_DISCOVERY_ENABLED === "false") return false;
24932
+ if (config2.nodeEnv === "production") return false;
24933
+ if (config2.vercelEnv === "production") return false;
24934
+ if (config2.nodeEnv === "development" || config2.nodeEnv === void 0) return true;
24935
+ return false;
24951
24936
  }
24952
24937
 
24953
- // src/side-effect/emit.ts
24954
- init_esm();
24955
- init_dist();
24956
- var spanState = /* @__PURE__ */ new WeakMap();
24957
- function getOrCreateState(span) {
24958
- let state = spanState.get(span);
24959
- if (!state) {
24960
- state = { operationsRecorded: 0, omissions: /* @__PURE__ */ new Map() };
24961
- spanState.set(span, state);
24962
- }
24963
- return state;
24938
+ // src/config-wrapper.ts
24939
+ var import_node_module = require("node:module");
24940
+ function isTurbopackBuild() {
24941
+ if (typeof process === "undefined") return false;
24942
+ const argv = Array.isArray(process.argv) ? process.argv : [];
24943
+ if (argv.includes("--webpack")) return false;
24944
+ if (argv.includes("--turbopack")) return true;
24945
+ if (process.env?.TURBOPACK === "1") return true;
24946
+ return false;
24964
24947
  }
24965
- function getRecordingActiveSpan() {
24966
- let span;
24967
- try {
24968
- span = trace.getActiveSpan();
24969
- } catch {
24970
- return void 0;
24971
- }
24972
- if (!span) return void 0;
24973
- try {
24974
- if (typeof span.isRecording === "function" && !span.isRecording()) {
24975
- return void 0;
24948
+ var SDK_PACKAGE_NAME = "@glasstrace/sdk";
24949
+ function appendNodeSchemeExternal(webpackConfig) {
24950
+ const nodeBuiltinExternal = (data, callback) => {
24951
+ const request = data.request;
24952
+ if (typeof request === "string" && (0, import_node_module.isBuiltin)(request)) {
24953
+ callback(null, "commonjs " + request);
24954
+ return;
24976
24955
  }
24977
- } catch {
24978
- return void 0;
24956
+ callback(null);
24957
+ };
24958
+ const existing = webpackConfig.externals;
24959
+ if (Array.isArray(existing)) {
24960
+ webpackConfig.externals = [...existing, nodeBuiltinExternal];
24961
+ } else if (existing == null) {
24962
+ webpackConfig.externals = [nodeBuiltinExternal];
24963
+ } else {
24964
+ webpackConfig.externals = [existing, nodeBuiltinExternal];
24979
24965
  }
24980
- return span;
24981
24966
  }
24982
- function recordOmissionOnActiveSpan(reason) {
24983
- const span = getRecordingActiveSpan();
24984
- if (!span) return;
24985
- recordOmissionOnSpan(span, reason);
24967
+ function ensureServerExternal(config2) {
24968
+ const existingStable = config2.serverExternalPackages;
24969
+ const stable = Array.isArray(existingStable) ? (
24970
+ // Clone so we never mutate a caller-owned array in place.
24971
+ existingStable.filter((entry) => typeof entry === "string")
24972
+ ) : [];
24973
+ if (!stable.includes(SDK_PACKAGE_NAME)) {
24974
+ stable.push(SDK_PACKAGE_NAME);
24975
+ }
24976
+ config2.serverExternalPackages = stable;
24986
24977
  }
24987
- function recordOmissionOnSpan(span, reason) {
24988
- const state = getOrCreateState(span);
24989
- const previous = state.omissions.get(reason) ?? 0;
24990
- const next = previous + 1;
24991
- state.omissions.set(reason, next);
24992
- const attribute = OMISSION_ATTRIBUTE_BY_REASON[reason];
24993
- try {
24994
- span.setAttribute(attribute, next);
24995
- } catch {
24978
+ function withGlasstraceConfig(nextConfig) {
24979
+ if (typeof process === "undefined" || typeof process.versions?.node !== "string") {
24980
+ return nextConfig != null ? { ...nextConfig } : {};
24981
+ }
24982
+ const config2 = nextConfig != null ? { ...nextConfig } : {};
24983
+ const bag = config2;
24984
+ const existingExperimental = bag.experimental ?? {};
24985
+ bag.experimental = {
24986
+ ...existingExperimental,
24987
+ serverSourceMaps: true
24988
+ };
24989
+ ensureServerExternal(bag);
24990
+ if (bag.turbopack == null) {
24991
+ bag.turbopack = {};
24992
+ }
24993
+ if (isTurbopackBuild()) {
24994
+ warnTurbopackLimitationOnce();
24996
24995
  }
24996
+ const distDir = typeof bag.distDir === "string" ? bag.distDir : ".next";
24997
+ const existingWebpack = bag.webpack;
24998
+ bag.webpack = (webpackConfig, context2) => {
24999
+ let result = webpackConfig;
25000
+ if (typeof existingWebpack === "function") {
25001
+ result = existingWebpack(webpackConfig, context2);
25002
+ }
25003
+ const webpackContext = context2;
25004
+ if (webpackContext.isServer) {
25005
+ appendNodeSchemeExternal(result);
25006
+ }
25007
+ if (!webpackContext.isServer && webpackContext.dev === false) {
25008
+ const plugins = result.plugins ?? [];
25009
+ plugins.push({
25010
+ apply(compiler) {
25011
+ const typedCompiler = compiler;
25012
+ if (typedCompiler.hooks?.afterEmit?.tapPromise) {
25013
+ typedCompiler.hooks.afterEmit.tapPromise(
25014
+ "GlasstraceSourceMapUpload",
25015
+ async () => {
25016
+ await handleSourceMapUpload(distDir);
25017
+ }
25018
+ );
25019
+ }
25020
+ }
25021
+ });
25022
+ result.plugins = plugins;
25023
+ }
25024
+ return result;
25025
+ };
25026
+ return config2;
25027
+ }
25028
+ var _turbopackWarningEmitted = false;
25029
+ function warnTurbopackLimitationOnce() {
25030
+ if (_turbopackWarningEmitted) return;
25031
+ _turbopackWarningEmitted = true;
25032
+ console.warn(
25033
+ "[glasstrace] Turbopack detected. Source-map upload currently runs only under webpack \u2014 run `next build --webpack` to upload source maps, or wait for the Turbopack port in a future SDK release."
25034
+ );
24997
25035
  }
24998
- var OMISSION_ATTRIBUTE_BY_REASON = {
24999
- pii: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OMITTED_PII,
25000
- secret: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OMITTED_SECRET,
25001
- raw_payload: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OMITTED_RAW_PAYLOAD,
25002
- unsupported_key: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OMITTED_UNSUPPORTED_KEY,
25003
- value_too_long: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OMITTED_VALUE_TOO_LONG,
25004
- not_emitted: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OMITTED_NOT_EMITTED,
25005
- capture_disabled: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OMITTED_CAPTURE_DISABLED
25006
- };
25007
- var FIELD_ATTRIBUTE_BY_KEY = {
25008
- templateKey: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_TEMPLATE_KEY,
25009
- providerOperation: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_PROVIDER_OPERATION,
25010
- role: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_ROLE,
25011
- locale: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_LOCALE,
25012
- timezone: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_TIMEZONE,
25013
- status: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_STATUS,
25014
- phase: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_PHASE,
25015
- recipientClass: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_RECIPIENT_CLASS,
25016
- participantCount: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_PARTICIPANT_COUNT,
25017
- activeParticipantCount: GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_FIELD_ACTIVE_PARTICIPANT_COUNT
25018
- };
25019
- function attachOperation(input) {
25020
- const span = getRecordingActiveSpan();
25021
- if (!span) return { kind: "no_active_span" };
25022
- const state = getOrCreateState(span);
25023
- if (state.operationsRecorded >= MAX_SIDE_EFFECT_OPERATIONS_PER_SPAN) {
25024
- return { kind: "over_budget", span };
25025
- }
25026
- state.operationsRecorded += 1;
25036
+ async function handleSourceMapUpload(distDir) {
25027
25037
  try {
25028
- span.setAttribute(GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_KIND, input.kind);
25029
- span.setAttribute(
25030
- GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OPERATION,
25031
- input.operation
25032
- );
25033
- if (input.status !== void 0) {
25034
- span.setAttribute(
25035
- GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_STATUS,
25036
- input.status
25038
+ const apiKey = process.env.GLASSTRACE_API_KEY;
25039
+ const endpoint = process.env.GLASSTRACE_ENDPOINT ?? "https://api.glasstrace.dev";
25040
+ if (!apiKey || apiKey.trim() === "") {
25041
+ console.info(
25042
+ "[glasstrace] Source map upload skipped (no API key). Stack traces will show compiled locations."
25037
25043
  );
25044
+ return;
25038
25045
  }
25039
- if (input.phase !== void 0) {
25040
- span.setAttribute(
25041
- GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_PHASE,
25042
- input.phase
25043
- );
25046
+ const { discoverSourceMapFiles: discoverSourceMapFiles2, computeBuildHash: computeBuildHash2, uploadSourceMaps: uploadSourceMaps2 } = await Promise.resolve().then(() => (init_source_map_uploader(), source_map_uploader_exports));
25047
+ const files = await discoverSourceMapFiles2(distDir);
25048
+ if (files.length === 0) {
25049
+ console.info("[glasstrace] No source map files found. Skipping upload.");
25050
+ return;
25044
25051
  }
25045
- } catch {
25052
+ const buildHash = await computeBuildHash2(files);
25053
+ await uploadSourceMaps2(apiKey, endpoint, buildHash, files);
25054
+ console.info(
25055
+ `[glasstrace] Uploaded ${String(files.length)} source map(s) for build ${buildHash}.`
25056
+ );
25057
+ } catch (error51) {
25058
+ const message = error51 instanceof Error ? error51.message : "Unknown error";
25059
+ console.warn(
25060
+ `[glasstrace] Source map upload failed: ${message}. Build continues normally.`
25061
+ );
25046
25062
  }
25047
- return { kind: "attached", span };
25048
25063
  }
25049
- function attachField(span, key, value) {
25050
- const attribute = FIELD_ATTRIBUTE_BY_KEY[key];
25051
- try {
25052
- span.setAttribute(attribute, value);
25053
- } catch {
25054
- }
25064
+
25065
+ // src/capture-error.ts
25066
+ init_esm();
25067
+ init_dist();
25068
+ init_error_nudge();
25069
+
25070
+ // src/stack-frame.ts
25071
+ var PAREN_FRAME = /^\s*at\s+(?!eval\s+\(eval\s+at\b)(?:[^()]+\s+)?\(([^()\s]+(?:\([A-Za-z0-9_.-]+\)[^()\s]*)*):(\d+):(\d+)\)\s*$/;
25072
+ var BARE_FRAME = /^\s*at\s+(?:async\s+)?([^()\s]+(?:\([A-Za-z0-9_.-]+\)[^()\s]*)*):(\d+):(\d+)\s*$/;
25073
+ var INTERNAL_FRAME_PATTERNS = [
25074
+ /^node:/,
25075
+ /^node:internal\//,
25076
+ /[/\\]node_modules[/\\]@glasstrace[/\\]sdk[/\\]/,
25077
+ /[/\\]packages[/\\]sdk[/\\]src[/\\]capture-error\./,
25078
+ /[/\\]packages[/\\]sdk[/\\]src[/\\]stack-frame\./
25079
+ ];
25080
+ function isInternalFrame(file2) {
25081
+ return INTERNAL_FRAME_PATTERNS.some((re2) => re2.test(file2));
25055
25082
  }
25056
- function recordOmission(span, reason) {
25057
- recordOmissionOnSpan(span, reason);
25083
+ function parseTopStackFrame(stack) {
25084
+ if (typeof stack !== "string" || stack.length === 0) return null;
25085
+ let cursor = 0;
25086
+ while (cursor < stack.length) {
25087
+ const newlineAt = stack.indexOf("\n", cursor);
25088
+ const lineEnd = newlineAt === -1 ? stack.length : newlineAt;
25089
+ const line = stack.slice(cursor, lineEnd);
25090
+ cursor = lineEnd + 1;
25091
+ if (!/^\s*at\s/.test(line)) continue;
25092
+ let file2;
25093
+ let lineStr;
25094
+ const parenMatch = PAREN_FRAME.exec(line);
25095
+ if (parenMatch) {
25096
+ file2 = parenMatch[1];
25097
+ lineStr = parenMatch[2];
25098
+ } else {
25099
+ const bareMatch = BARE_FRAME.exec(line);
25100
+ if (bareMatch) {
25101
+ file2 = bareMatch[1];
25102
+ lineStr = bareMatch[2];
25103
+ }
25104
+ }
25105
+ if (!file2 || !lineStr) continue;
25106
+ if (isInternalFrame(file2)) continue;
25107
+ const lineNum = Number.parseInt(lineStr, 10);
25108
+ if (!Number.isFinite(lineNum) || lineNum <= 0) continue;
25109
+ return { file: file2, line: lineNum };
25110
+ }
25111
+ return null;
25058
25112
  }
25059
25113
 
25060
- // src/side-effect/index.ts
25061
- function recordSideEffect(input) {
25114
+ // src/capture-error.ts
25115
+ function captureError(error51) {
25062
25116
  try {
25063
- runRecordSideEffect(input);
25117
+ const span = trace.getSpan(context.active());
25118
+ if (!span) return;
25119
+ const attributes = {
25120
+ "error.message": String(error51)
25121
+ };
25122
+ if (error51 instanceof Error) {
25123
+ attributes["error.type"] = error51.constructor.name;
25124
+ if (error51.stack) {
25125
+ attributes["error.stack"] = error51.stack;
25126
+ const frame = parseTopStackFrame(error51.stack);
25127
+ if (frame) {
25128
+ attributes[GLASSTRACE_ATTRIBUTE_NAMES.SOURCE_FILE] = frame.file;
25129
+ attributes[GLASSTRACE_ATTRIBUTE_NAMES.SOURCE_LINE] = frame.line;
25130
+ }
25131
+ }
25132
+ }
25133
+ span.addEvent("glasstrace.error", attributes);
25134
+ maybeShowMcpNudge(String(error51));
25064
25135
  } catch {
25065
25136
  }
25066
25137
  }
25067
- function runRecordSideEffect(input) {
25068
- if (!input || typeof input !== "object") return;
25069
- let captureEnabled;
25138
+
25139
+ // src/correlation-id.ts
25140
+ init_esm();
25141
+ init_dist();
25142
+ var ATTR2 = GLASSTRACE_ATTRIBUTE_NAMES;
25143
+ var HEADER_NAME = "x-gt-cid";
25144
+ var MAX_CID_LENGTH = 128;
25145
+ function captureCorrelationId(req) {
25070
25146
  try {
25071
- captureEnabled = getActiveConfig().sideEffectEvidence === true;
25147
+ if (!req || !req.headers) {
25148
+ return;
25149
+ }
25150
+ const value = readHeader(req.headers);
25151
+ if (!value) {
25152
+ return;
25153
+ }
25154
+ const span = trace.getActiveSpan();
25155
+ if (!span) {
25156
+ return;
25157
+ }
25158
+ span.setAttribute(ATTR2.CORRELATION_ID, value);
25072
25159
  } catch {
25073
- captureEnabled = false;
25074
25160
  }
25075
- if (!captureEnabled) {
25076
- return;
25077
- }
25078
- const candidate = input;
25079
- if (!checkOperationKind(candidate.kind)) {
25080
- return;
25161
+ }
25162
+ function readHeader(headers) {
25163
+ const asFetch = headers;
25164
+ if (typeof asFetch.get === "function") {
25165
+ const raw = asFetch.get(HEADER_NAME);
25166
+ return firstToken(raw);
25081
25167
  }
25082
- const labelOutcome = checkOperationLabel(candidate.operation);
25083
- if (!labelOutcome.accepted) {
25084
- recordOmissionOnActiveSpan(labelOutcome.reason);
25085
- return;
25168
+ const dict = headers;
25169
+ const direct = dict[HEADER_NAME];
25170
+ if (direct !== void 0) {
25171
+ return firstValue(direct);
25086
25172
  }
25087
- let acceptedStatus;
25088
- if (candidate.status !== void 0) {
25089
- if (checkOperationStatus(candidate.status)) {
25090
- acceptedStatus = candidate.status;
25091
- } else {
25092
- recordOmissionOnActiveSpan("unsupported_key");
25173
+ for (const key of Object.keys(dict)) {
25174
+ if (key.toLowerCase() === HEADER_NAME) {
25175
+ return firstValue(dict[key]);
25093
25176
  }
25094
25177
  }
25095
- let acceptedPhase;
25096
- if (candidate.phase !== void 0) {
25097
- if (checkOperationPhase(candidate.phase)) {
25098
- acceptedPhase = candidate.phase;
25099
- } else {
25100
- recordOmissionOnActiveSpan("unsupported_key");
25178
+ return void 0;
25179
+ }
25180
+ function firstValue(value) {
25181
+ if (Array.isArray(value)) {
25182
+ for (const entry of value) {
25183
+ const token = firstToken(entry);
25184
+ if (token) return token;
25101
25185
  }
25186
+ return void 0;
25102
25187
  }
25103
- const outcome = attachOperation({
25104
- kind: candidate.kind,
25105
- operation: labelOutcome.value,
25106
- status: acceptedStatus,
25107
- phase: acceptedPhase
25108
- });
25109
- if (outcome.kind === "no_active_span") {
25110
- return;
25111
- }
25112
- if (outcome.kind === "over_budget") {
25113
- recordOmission(outcome.span, "value_too_long");
25114
- return;
25115
- }
25116
- const fields = candidate.fields;
25117
- if (fields && typeof fields === "object") {
25118
- for (const [rawKey, rawValue] of Object.entries(fields)) {
25119
- if (!checkSemanticFieldKey(rawKey)) {
25120
- recordOmission(outcome.span, "unsupported_key");
25121
- continue;
25122
- }
25123
- const valueOutcome = checkSemanticFieldValue(rawKey, rawValue);
25124
- if (!valueOutcome.accepted) {
25125
- recordOmission(outcome.span, valueOutcome.reason);
25126
- continue;
25127
- }
25128
- attachField(outcome.span, rawKey, valueOutcome.value);
25129
- }
25188
+ return firstToken(value);
25189
+ }
25190
+ function firstToken(value) {
25191
+ if (typeof value !== "string") return void 0;
25192
+ const parts = value.split(",");
25193
+ for (const part of parts) {
25194
+ const trimmed = part.trim();
25195
+ if (trimmed.length === 0) continue;
25196
+ if (trimmed.length > MAX_CID_LENGTH) return void 0;
25197
+ return trimmed;
25130
25198
  }
25199
+ return void 0;
25131
25200
  }
25201
+
25202
+ // src/index.ts
25203
+ init_dist();
25132
25204
  // Annotate the CommonJS export names for ESM import in node:
25133
25205
  0 && (module.exports = {
25134
25206
  GlasstraceExporter,
@@ -25150,6 +25222,7 @@ function runRecordSideEffect(input) {
25150
25222
  isAnonymousMode,
25151
25223
  isProductionDisabled,
25152
25224
  isReady,
25225
+ isSideEffectSemanticFieldKey,
25153
25226
  loadCachedConfig,
25154
25227
  performInit,
25155
25228
  readAnonKey,