@glasstrace/sdk 1.13.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.
- package/dist/{chunk-VWZMG3W2.js → chunk-E2F4S5IJ.js} +358 -7
- package/dist/chunk-E2F4S5IJ.js.map +1 -0
- package/dist/cli/init.cjs +4 -4
- package/dist/cli/init.js +2 -2
- package/dist/cli/mcp-add.cjs +1 -1
- package/dist/cli/mcp-add.js +1 -1
- package/dist/cli/upgrade-instructions.cjs +1 -1
- package/dist/cli/upgrade-instructions.js +1 -1
- package/dist/index.cjs +1016 -957
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -295
- package/dist/index.js.map +1 -1
- package/dist/node-entry.cjs +12 -5
- package/dist/node-entry.cjs.map +1 -1
- package/dist/node-entry.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-VWZMG3W2.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -24063,1081 +24063,1140 @@ function registerHeartbeatShutdownHook(config2, anonKey, sdkVersion) {
|
|
|
24063
24063
|
});
|
|
24064
24064
|
}
|
|
24065
24065
|
|
|
24066
|
-
// src/
|
|
24067
|
-
|
|
24068
|
-
var
|
|
24069
|
-
var
|
|
24070
|
-
|
|
24071
|
-
|
|
24072
|
-
|
|
24073
|
-
|
|
24074
|
-
|
|
24075
|
-
|
|
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;
|
|
24076
24115
|
}
|
|
24077
|
-
|
|
24078
|
-
|
|
24079
|
-
|
|
24080
|
-
|
|
24081
|
-
|
|
24082
|
-
var _started = false;
|
|
24083
|
-
function startRuntimeStateWriter(options) {
|
|
24084
|
-
if (_started) return;
|
|
24085
|
-
if (!isSyncFsAvailable() || fsSync === null || pathSync === null) {
|
|
24086
|
-
_started = true;
|
|
24087
|
-
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);
|
|
24088
24121
|
}
|
|
24089
|
-
|
|
24090
|
-
_projectRoot = options.projectRoot;
|
|
24091
|
-
_sdkVersion = options.sdkVersion;
|
|
24092
|
-
onLifecycleEvent("core:state_changed", ({ to }) => {
|
|
24093
|
-
if (to === CoreState.SHUTDOWN) {
|
|
24094
|
-
writeStateNow();
|
|
24095
|
-
} else {
|
|
24096
|
-
debouncedWrite();
|
|
24097
|
-
}
|
|
24098
|
-
});
|
|
24099
|
-
onLifecycleEvent("otel:configured", ({ scenario }) => {
|
|
24100
|
-
_lastScenario = scenario;
|
|
24101
|
-
debouncedWrite();
|
|
24102
|
-
});
|
|
24103
|
-
onLifecycleEvent("otel:failed", (payload) => {
|
|
24104
|
-
_lastError = { ...payload };
|
|
24105
|
-
debouncedWrite();
|
|
24106
|
-
});
|
|
24107
|
-
onLifecycleEvent("otel:circuit_opened", (payload) => {
|
|
24108
|
-
_lastError = {
|
|
24109
|
-
category: "export-circuit-open",
|
|
24110
|
-
message: payload.message,
|
|
24111
|
-
timestamp: payload.timestamp,
|
|
24112
|
-
exportCircuitCategory: payload.category
|
|
24113
|
-
};
|
|
24114
|
-
debouncedWrite();
|
|
24115
|
-
});
|
|
24116
|
-
onLifecycleEvent("otel:circuit_closed", () => {
|
|
24117
|
-
if (_lastError?.category === "export-circuit-open") {
|
|
24118
|
-
_lastError = void 0;
|
|
24119
|
-
debouncedWrite();
|
|
24120
|
-
}
|
|
24121
|
-
});
|
|
24122
|
-
onLifecycleEvent("auth:key_resolved", () => debouncedWrite());
|
|
24123
|
-
onLifecycleEvent("auth:claim_started", () => debouncedWrite());
|
|
24124
|
-
onLifecycleEvent("auth:claim_completed", () => debouncedWrite());
|
|
24125
|
-
writeStateNow();
|
|
24122
|
+
return TOKEN_REGEX.test(value);
|
|
24126
24123
|
}
|
|
24127
|
-
function
|
|
24128
|
-
if (
|
|
24129
|
-
|
|
24130
|
-
_debounceTimer = null;
|
|
24131
|
-
writeStateNow();
|
|
24132
|
-
}, 1e3);
|
|
24133
|
-
if (typeof _debounceTimer === "object" && "unref" in _debounceTimer) {
|
|
24134
|
-
_debounceTimer.unref();
|
|
24124
|
+
function checkOperationLabel(value) {
|
|
24125
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
24126
|
+
return { accepted: false, reason: "raw_payload" };
|
|
24135
24127
|
}
|
|
24136
|
-
|
|
24137
|
-
|
|
24138
|
-
|
|
24139
|
-
|
|
24140
|
-
|
|
24141
|
-
|
|
24142
|
-
|
|
24143
|
-
|
|
24144
|
-
|
|
24145
|
-
core: { state: state.core },
|
|
24146
|
-
auth: { state: state.auth },
|
|
24147
|
-
otel: { state: state.otel, scenario: _lastScenario }
|
|
24148
|
-
};
|
|
24149
|
-
if (_lastError) {
|
|
24150
|
-
runtimeState.lastError = _lastError;
|
|
24151
|
-
}
|
|
24152
|
-
const dir = pathSync.join(_projectRoot, ".glasstrace");
|
|
24153
|
-
const filePath = pathSync.join(dir, "runtime-state.json");
|
|
24154
|
-
fsSync.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
24155
|
-
atomicWriteFileSync(filePath, JSON.stringify(runtimeState, null, 2) + "\n", {
|
|
24156
|
-
mode: 384
|
|
24157
|
-
});
|
|
24158
|
-
} catch (err) {
|
|
24159
|
-
sdkLog(
|
|
24160
|
-
"warn",
|
|
24161
|
-
`[glasstrace] Failed to write runtime state: ${err instanceof Error ? err.message : String(err)}`
|
|
24162
|
-
);
|
|
24128
|
+
if (value.length > MAX_SIDE_EFFECT_OPERATION_LABEL_LENGTH) {
|
|
24129
|
+
return { accepted: false, reason: "value_too_long" };
|
|
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" };
|
|
24163
24137
|
}
|
|
24138
|
+
return { accepted: true, value };
|
|
24164
24139
|
}
|
|
24165
|
-
|
|
24166
|
-
|
|
24167
|
-
|
|
24168
|
-
var path2 = __toESM(require("node:path"), 1);
|
|
24169
|
-
|
|
24170
|
-
// src/agent-detection/inject.ts
|
|
24171
|
-
var HTML_START_RE = /^<!--\s*glasstrace:mcp:start(?:\s+v=([^\s>]+))?\s*-->$/;
|
|
24172
|
-
var HTML_END = "<!-- glasstrace:mcp:end -->";
|
|
24173
|
-
var HASH_START_RE = /^#\s*glasstrace:mcp:start(?:\s+v=(\S+))?$/;
|
|
24174
|
-
var HASH_END = "# glasstrace:mcp:end";
|
|
24175
|
-
function parseStartMarkerLine(line) {
|
|
24176
|
-
const trimmed = line.trim();
|
|
24177
|
-
const html = HTML_START_RE.exec(trimmed);
|
|
24178
|
-
if (html !== null) {
|
|
24179
|
-
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" };
|
|
24180
24143
|
}
|
|
24181
|
-
const
|
|
24182
|
-
if (
|
|
24183
|
-
return {
|
|
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" };
|
|
24184
24147
|
}
|
|
24185
|
-
|
|
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 };
|
|
24186
24156
|
}
|
|
24187
|
-
function
|
|
24188
|
-
|
|
24189
|
-
return trimmed === HTML_END || trimmed === HASH_END;
|
|
24157
|
+
function checkSemanticFieldKey(key) {
|
|
24158
|
+
return typeof key === "string" && isSideEffectSemanticFieldKey(key);
|
|
24190
24159
|
}
|
|
24191
|
-
function
|
|
24192
|
-
return
|
|
24160
|
+
function checkOperationKind(kind) {
|
|
24161
|
+
return typeof kind === "string" && OPERATION_KIND_SET.has(kind);
|
|
24193
24162
|
}
|
|
24194
|
-
|
|
24195
|
-
|
|
24196
|
-
var warningEmitted = false;
|
|
24197
|
-
var AGENT_INSTRUCTION_FILES = [
|
|
24198
|
-
"AGENTS.md",
|
|
24199
|
-
"CLAUDE.md",
|
|
24200
|
-
"GEMINI.md",
|
|
24201
|
-
".cursor/rules/glasstrace.mdc",
|
|
24202
|
-
".windsurf/rules/glasstrace.md",
|
|
24203
|
-
".cursorrules",
|
|
24204
|
-
"codex.md",
|
|
24205
|
-
".windsurfrules"
|
|
24206
|
-
];
|
|
24207
|
-
function parseSemver(input) {
|
|
24208
|
-
const plusIdx = input.indexOf("+");
|
|
24209
|
-
const core = plusIdx === -1 ? input : input.slice(0, plusIdx);
|
|
24210
|
-
const m = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(core);
|
|
24211
|
-
if (m === null) return null;
|
|
24212
|
-
return {
|
|
24213
|
-
major: Number(m[1]),
|
|
24214
|
-
minor: Number(m[2]),
|
|
24215
|
-
patch: Number(m[3]),
|
|
24216
|
-
prerelease: m[4] ?? null
|
|
24217
|
-
};
|
|
24163
|
+
function checkOperationStatus(status) {
|
|
24164
|
+
return typeof status === "string" && OPERATION_STATUS_SET.has(status);
|
|
24218
24165
|
}
|
|
24219
|
-
function
|
|
24220
|
-
|
|
24221
|
-
const bp = b.split(".");
|
|
24222
|
-
const len = Math.min(ap.length, bp.length);
|
|
24223
|
-
for (let i = 0; i < len; i++) {
|
|
24224
|
-
const x = ap[i];
|
|
24225
|
-
const y = bp[i];
|
|
24226
|
-
const xNumeric = /^\d+$/.test(x);
|
|
24227
|
-
const yNumeric = /^\d+$/.test(y);
|
|
24228
|
-
if (xNumeric && yNumeric) {
|
|
24229
|
-
const xv = Number(x);
|
|
24230
|
-
const yv = Number(y);
|
|
24231
|
-
if (xv !== yv) return xv < yv ? -1 : 1;
|
|
24232
|
-
} else if (xNumeric) {
|
|
24233
|
-
return -1;
|
|
24234
|
-
} else if (yNumeric) {
|
|
24235
|
-
return 1;
|
|
24236
|
-
} else if (x !== y) {
|
|
24237
|
-
return x < y ? -1 : 1;
|
|
24238
|
-
}
|
|
24239
|
-
}
|
|
24240
|
-
return ap.length - bp.length;
|
|
24166
|
+
function checkOperationPhase(phase) {
|
|
24167
|
+
return typeof phase === "string" && OPERATION_PHASE_SET.has(phase);
|
|
24241
24168
|
}
|
|
24242
|
-
|
|
24243
|
-
|
|
24244
|
-
|
|
24245
|
-
|
|
24246
|
-
|
|
24247
|
-
|
|
24248
|
-
|
|
24249
|
-
if (
|
|
24250
|
-
|
|
24251
|
-
|
|
24252
|
-
|
|
24253
|
-
|
|
24254
|
-
function isOptedOut() {
|
|
24255
|
-
const raw = process.env.GLASSTRACE_DISABLE_UPGRADE_NOTICE;
|
|
24256
|
-
if (typeof raw !== "string") return false;
|
|
24257
|
-
const trimmed = raw.trim().toLowerCase();
|
|
24258
|
-
return trimmed === "1" || trimmed === "true" || trimmed === "yes";
|
|
24259
|
-
}
|
|
24260
|
-
function isQuietCiContext() {
|
|
24261
|
-
const stderrIsTty = process.stderr.isTTY === true;
|
|
24262
|
-
if (stderrIsTty) return false;
|
|
24263
|
-
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;
|
|
24264
24181
|
}
|
|
24265
|
-
|
|
24266
|
-
|
|
24267
|
-
let content;
|
|
24182
|
+
function getRecordingActiveSpan() {
|
|
24183
|
+
let span;
|
|
24268
24184
|
try {
|
|
24269
|
-
|
|
24270
|
-
if (!stat2.isFile()) return "absent";
|
|
24271
|
-
if (stat2.size > MAX_AGENT_FILE_BYTES) return "absent";
|
|
24272
|
-
content = fs2.readFileSync(filePath, "utf-8");
|
|
24185
|
+
span = trace.getActiveSpan();
|
|
24273
24186
|
} catch {
|
|
24274
|
-
return
|
|
24187
|
+
return void 0;
|
|
24275
24188
|
}
|
|
24276
|
-
|
|
24277
|
-
|
|
24278
|
-
|
|
24279
|
-
|
|
24280
|
-
const parsed = parseStartMarkerLine(line);
|
|
24281
|
-
if (parsed !== null) {
|
|
24282
|
-
lastStart = parsed;
|
|
24283
|
-
continue;
|
|
24284
|
-
}
|
|
24285
|
-
if (lastStart !== null && isEndMarkerLine(line)) {
|
|
24286
|
-
foundEnd = true;
|
|
24287
|
-
break;
|
|
24189
|
+
if (!span) return void 0;
|
|
24190
|
+
try {
|
|
24191
|
+
if (typeof span.isRecording === "function" && !span.isRecording()) {
|
|
24192
|
+
return void 0;
|
|
24288
24193
|
}
|
|
24194
|
+
} catch {
|
|
24195
|
+
return void 0;
|
|
24289
24196
|
}
|
|
24290
|
-
|
|
24291
|
-
return "no-section";
|
|
24292
|
-
}
|
|
24293
|
-
if (lastStart.stamp === null) {
|
|
24294
|
-
return "no-stamp";
|
|
24295
|
-
}
|
|
24296
|
-
const cmp = compareSemver(lastStart.stamp, runningSdkVersion);
|
|
24297
|
-
if (cmp === null) {
|
|
24298
|
-
return "unknown-stamp";
|
|
24299
|
-
}
|
|
24300
|
-
return cmp < 0 ? "stale" : "current";
|
|
24197
|
+
return span;
|
|
24301
24198
|
}
|
|
24302
|
-
function
|
|
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];
|
|
24303
24210
|
try {
|
|
24304
|
-
|
|
24305
|
-
if (typeof process === "undefined" || typeof process.versions?.node !== "string" || typeof process.env !== "object" || process.env === null) {
|
|
24306
|
-
return;
|
|
24307
|
-
}
|
|
24308
|
-
if (isOptedOut()) return;
|
|
24309
|
-
if (isQuietCiContext()) return;
|
|
24310
|
-
if (parseSemver(options.sdkVersion) === null) return;
|
|
24311
|
-
const staleFiles = [];
|
|
24312
|
-
for (const fileName of AGENT_INSTRUCTION_FILES) {
|
|
24313
|
-
const fullPath = path2.join(options.projectRoot, fileName);
|
|
24314
|
-
const state = inspectFile(fullPath, options.sdkVersion);
|
|
24315
|
-
if (state === "stale") {
|
|
24316
|
-
staleFiles.push(fileName);
|
|
24317
|
-
}
|
|
24318
|
-
}
|
|
24319
|
-
if (staleFiles.length === 0) return;
|
|
24320
|
-
const fileList = staleFiles.join(", ");
|
|
24321
|
-
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).
|
|
24322
|
-
`;
|
|
24323
|
-
warningEmitted = true;
|
|
24324
|
-
if (options.stderrWrite !== void 0) {
|
|
24325
|
-
options.stderrWrite(message);
|
|
24326
|
-
return;
|
|
24327
|
-
}
|
|
24328
|
-
try {
|
|
24329
|
-
process.stderr.write(message);
|
|
24330
|
-
} catch {
|
|
24331
|
-
}
|
|
24211
|
+
span.setAttribute(attribute, next);
|
|
24332
24212
|
} catch {
|
|
24333
24213
|
}
|
|
24334
24214
|
}
|
|
24335
|
-
|
|
24336
|
-
|
|
24337
|
-
|
|
24338
|
-
|
|
24339
|
-
|
|
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}`;
|
|
24340
24240
|
}
|
|
24341
|
-
|
|
24342
|
-
|
|
24343
|
-
var registrationGeneration = 0;
|
|
24344
|
-
var _sessionManager = null;
|
|
24345
|
-
function getSessionManager() {
|
|
24346
|
-
if (!_sessionManager) {
|
|
24347
|
-
_sessionManager = new SessionManager();
|
|
24348
|
-
}
|
|
24349
|
-
return _sessionManager;
|
|
24241
|
+
function hasExplicitFieldAttribute(key) {
|
|
24242
|
+
return FIELD_ATTRIBUTE_BY_KEY[key] !== void 0;
|
|
24350
24243
|
}
|
|
24351
|
-
function
|
|
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;
|
|
24352
24252
|
try {
|
|
24353
|
-
|
|
24354
|
-
|
|
24355
|
-
|
|
24356
|
-
|
|
24357
|
-
if (typeof process === "undefined" || typeof process.versions?.node !== "string") {
|
|
24358
|
-
console.warn(
|
|
24359
|
-
"[glasstrace] SDK requires a Node.js runtime. Edge Runtime, browser, and Deno without Node compat are not supported. Glasstrace is disabled in this environment."
|
|
24360
|
-
);
|
|
24361
|
-
return;
|
|
24362
|
-
}
|
|
24363
|
-
setCoreState(CoreState.REGISTERING);
|
|
24364
|
-
maybeWarnStaleAgentInstructions({
|
|
24365
|
-
projectRoot: process.cwd(),
|
|
24366
|
-
sdkVersion: "1.13.0"
|
|
24367
|
-
});
|
|
24368
|
-
startRuntimeStateWriter({
|
|
24369
|
-
projectRoot: process.cwd(),
|
|
24370
|
-
sdkVersion: "1.13.0"
|
|
24371
|
-
});
|
|
24372
|
-
const config2 = resolveConfig(options);
|
|
24373
|
-
if (config2.verbose) {
|
|
24374
|
-
console.info("[glasstrace] Config resolved.");
|
|
24375
|
-
}
|
|
24376
|
-
if (isProductionDisabled(config2)) {
|
|
24377
|
-
setCoreState(CoreState.PRODUCTION_DISABLED);
|
|
24378
|
-
console.warn(
|
|
24379
|
-
"[glasstrace] Disabled in production. Set GLASSTRACE_FORCE_ENABLE=true to override."
|
|
24380
|
-
);
|
|
24381
|
-
return;
|
|
24382
|
-
}
|
|
24383
|
-
if (config2.verbose) {
|
|
24384
|
-
console.info("[glasstrace] Not production-disabled.");
|
|
24385
|
-
}
|
|
24386
|
-
const existingTracerProvider = trace.getTracerProvider();
|
|
24387
|
-
const existingProbe = existingTracerProvider.getTracer("glasstrace-probe");
|
|
24388
|
-
const anotherProviderRegistered = !isProxyTracerProvider(existingTracerProvider) || !isProxyTracer(existingProbe, existingTracerProvider);
|
|
24389
|
-
if (anotherProviderRegistered) {
|
|
24390
|
-
setCoexistenceState("coexisting");
|
|
24391
|
-
}
|
|
24392
|
-
registerSignalHandlers();
|
|
24393
|
-
const anonymous = isAnonymousMode(config2);
|
|
24394
|
-
let effectiveKey = config2.apiKey;
|
|
24395
|
-
initAuthState(anonymous ? AuthState.ANONYMOUS : AuthState.AUTHENTICATED);
|
|
24396
|
-
if (effectiveKey) {
|
|
24397
|
-
setResolvedApiKey(effectiveKey);
|
|
24398
|
-
emitLifecycleEvent("auth:key_resolved", {
|
|
24399
|
-
key: maskKey(effectiveKey),
|
|
24400
|
-
mode: anonymous ? "anonymous" : "dev"
|
|
24401
|
-
});
|
|
24402
|
-
}
|
|
24403
|
-
if (config2.verbose) {
|
|
24404
|
-
console.info(
|
|
24405
|
-
`[glasstrace] Auth mode = ${anonymous ? "anonymous" : "dev-key"}.`
|
|
24406
|
-
);
|
|
24407
|
-
}
|
|
24408
|
-
const cachedInitResponse = loadCachedConfig();
|
|
24409
|
-
if (cachedInitResponse) {
|
|
24410
|
-
_setCurrentConfig(cachedInitResponse);
|
|
24411
|
-
}
|
|
24412
|
-
if (config2.verbose) {
|
|
24413
|
-
console.info(
|
|
24414
|
-
`[glasstrace] Cached config ${cachedInitResponse ? "loaded and applied" : "not found"}.`
|
|
24415
|
-
);
|
|
24416
|
-
}
|
|
24417
|
-
const sessionManager = getSessionManager();
|
|
24418
|
-
if (config2.verbose) {
|
|
24419
|
-
console.info("[glasstrace] SessionManager created.");
|
|
24420
|
-
}
|
|
24421
|
-
setCoreState(CoreState.KEY_PENDING);
|
|
24422
|
-
const currentGeneration = registrationGeneration;
|
|
24423
|
-
if (anotherProviderRegistered) {
|
|
24424
|
-
if (config2.verbose) {
|
|
24425
|
-
console.info("[glasstrace] Another OTel provider detected \u2014 using existing context manager.");
|
|
24426
|
-
}
|
|
24427
|
-
} else {
|
|
24428
|
-
const contextManagerInstalled = installContextManager();
|
|
24429
|
-
if (config2.verbose) {
|
|
24430
|
-
console.info(
|
|
24431
|
-
contextManagerInstalled ? "[glasstrace] Context manager installed." : "[glasstrace] Context manager not available \u2014 trace context propagation disabled."
|
|
24432
|
-
);
|
|
24433
|
-
}
|
|
24434
|
-
}
|
|
24435
|
-
void configureOtel(config2, sessionManager).then(
|
|
24436
|
-
() => {
|
|
24437
|
-
maybeInstallConsoleCapture();
|
|
24438
|
-
if (config2.verbose) {
|
|
24439
|
-
console.info("[glasstrace] OTel configured.");
|
|
24440
|
-
}
|
|
24441
|
-
},
|
|
24442
|
-
(err) => {
|
|
24443
|
-
console.warn(
|
|
24444
|
-
`[glasstrace] Failed to configure OTel: ${err instanceof Error ? err.message : String(err)}`
|
|
24445
|
-
);
|
|
24446
|
-
}
|
|
24447
|
-
);
|
|
24448
|
-
if (anonymous) {
|
|
24449
|
-
if (isDiscoveryEnabled(config2)) {
|
|
24450
|
-
let resolvedAnonKey = null;
|
|
24451
|
-
const anonKeyPromise = getOrCreateAnonKey();
|
|
24452
|
-
const getClaimState = () => {
|
|
24453
|
-
if (getLinkedAccountId()) return { claimed: true };
|
|
24454
|
-
if (getClaimResult()) return { claimed: true };
|
|
24455
|
-
return null;
|
|
24456
|
-
};
|
|
24457
|
-
discoveryHandler = createDiscoveryHandler(
|
|
24458
|
-
async () => resolvedAnonKey,
|
|
24459
|
-
() => sessionManager.getSessionId(getResolvedApiKey()),
|
|
24460
|
-
getClaimState
|
|
24461
|
-
);
|
|
24462
|
-
if (config2.verbose) {
|
|
24463
|
-
console.info("[glasstrace] Discovery endpoint registered (key pending).");
|
|
24464
|
-
}
|
|
24465
|
-
void (async () => {
|
|
24466
|
-
try {
|
|
24467
|
-
if (currentGeneration !== registrationGeneration) return;
|
|
24468
|
-
const anonKey = await anonKeyPromise;
|
|
24469
|
-
resolvedAnonKey = anonKey;
|
|
24470
|
-
setResolvedApiKey(anonKey);
|
|
24471
|
-
notifyApiKeyResolved();
|
|
24472
|
-
emitLifecycleEvent("auth:key_resolved", { key: maskKey(anonKey), mode: "anonymous" });
|
|
24473
|
-
effectiveKey = anonKey;
|
|
24474
|
-
if (currentGeneration !== registrationGeneration) return;
|
|
24475
|
-
discoveryHandler = createDiscoveryHandler(
|
|
24476
|
-
() => Promise.resolve(anonKey),
|
|
24477
|
-
() => sessionManager.getSessionId(getResolvedApiKey()),
|
|
24478
|
-
getClaimState
|
|
24479
|
-
);
|
|
24480
|
-
await backgroundInit(config2, anonKey, currentGeneration);
|
|
24481
|
-
} catch (err) {
|
|
24482
|
-
console.warn(
|
|
24483
|
-
`[glasstrace] Background init failed: ${err instanceof Error ? err.message : String(err)}`
|
|
24484
|
-
);
|
|
24485
|
-
}
|
|
24486
|
-
})();
|
|
24487
|
-
} else {
|
|
24488
|
-
void (async () => {
|
|
24489
|
-
try {
|
|
24490
|
-
if (currentGeneration !== registrationGeneration) return;
|
|
24491
|
-
const anonKey = await getOrCreateAnonKey();
|
|
24492
|
-
setResolvedApiKey(anonKey);
|
|
24493
|
-
notifyApiKeyResolved();
|
|
24494
|
-
emitLifecycleEvent("auth:key_resolved", { key: maskKey(anonKey), mode: "anonymous" });
|
|
24495
|
-
effectiveKey = anonKey;
|
|
24496
|
-
if (currentGeneration !== registrationGeneration) return;
|
|
24497
|
-
await backgroundInit(config2, anonKey, currentGeneration);
|
|
24498
|
-
} catch (err) {
|
|
24499
|
-
console.warn(
|
|
24500
|
-
`[glasstrace] Background init failed: ${err instanceof Error ? err.message : String(err)}`
|
|
24501
|
-
);
|
|
24502
|
-
}
|
|
24503
|
-
})();
|
|
24504
|
-
}
|
|
24505
|
-
} else {
|
|
24506
|
-
void (async () => {
|
|
24507
|
-
try {
|
|
24508
|
-
if (currentGeneration !== registrationGeneration) return;
|
|
24509
|
-
let anonKeyForInit = null;
|
|
24510
|
-
try {
|
|
24511
|
-
anonKeyForInit = await readAnonKey();
|
|
24512
|
-
} catch {
|
|
24513
|
-
}
|
|
24514
|
-
if (currentGeneration !== registrationGeneration) return;
|
|
24515
|
-
await backgroundInit(config2, anonKeyForInit, currentGeneration);
|
|
24516
|
-
} catch (err) {
|
|
24517
|
-
console.warn(
|
|
24518
|
-
`[glasstrace] Background init failed: ${err instanceof Error ? err.message : String(err)}`
|
|
24519
|
-
);
|
|
24520
|
-
}
|
|
24521
|
-
})();
|
|
24522
|
-
}
|
|
24523
|
-
if (config2.coverageMapEnabled && config2.verbose) {
|
|
24524
|
-
console.info("[glasstrace] Import graph building skipped.");
|
|
24525
|
-
}
|
|
24526
|
-
} catch (err) {
|
|
24527
|
-
setCoreState(CoreState.REGISTRATION_FAILED);
|
|
24528
|
-
console.warn(
|
|
24529
|
-
`[glasstrace] Registration failed: ${err instanceof Error ? err.message : String(err)}`
|
|
24253
|
+
span.setAttribute(GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_KIND, input.kind);
|
|
24254
|
+
span.setAttribute(
|
|
24255
|
+
GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_OPERATION,
|
|
24256
|
+
input.operation
|
|
24530
24257
|
);
|
|
24258
|
+
if (input.status !== void 0) {
|
|
24259
|
+
span.setAttribute(
|
|
24260
|
+
GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_STATUS,
|
|
24261
|
+
input.status
|
|
24262
|
+
);
|
|
24263
|
+
}
|
|
24264
|
+
if (input.phase !== void 0) {
|
|
24265
|
+
span.setAttribute(
|
|
24266
|
+
GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_PHASE,
|
|
24267
|
+
input.phase
|
|
24268
|
+
);
|
|
24269
|
+
}
|
|
24270
|
+
} catch {
|
|
24531
24271
|
}
|
|
24272
|
+
return { kind: "attached", span };
|
|
24532
24273
|
}
|
|
24533
|
-
|
|
24534
|
-
|
|
24535
|
-
|
|
24536
|
-
|
|
24537
|
-
|
|
24538
|
-
const initResult = await performInit(config2, anonKeyForInit, "1.13.0", healthReport);
|
|
24539
|
-
if (generation !== registrationGeneration) return;
|
|
24540
|
-
const currentState = getCoreState();
|
|
24541
|
-
if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
|
|
24542
|
-
return;
|
|
24543
|
-
}
|
|
24544
|
-
if (currentState === CoreState.KEY_PENDING) {
|
|
24545
|
-
setCoreState(CoreState.KEY_RESOLVED);
|
|
24546
|
-
}
|
|
24547
|
-
if (getCoreState() === CoreState.KEY_RESOLVED) {
|
|
24548
|
-
setCoreState(didLastInitSucceed() ? CoreState.ACTIVE : CoreState.ACTIVE_DEGRADED);
|
|
24549
|
-
}
|
|
24550
|
-
if (initResult?.claimResult) {
|
|
24551
|
-
const { newApiKey, accountId } = initResult.claimResult;
|
|
24552
|
-
setAuthState(AuthState.CLAIMING);
|
|
24553
|
-
emitLifecycleEvent("auth:claim_started", { accountId });
|
|
24554
|
-
setResolvedApiKey(newApiKey);
|
|
24555
|
-
notifyApiKeyResolved();
|
|
24556
|
-
setAuthState(AuthState.CLAIMED);
|
|
24557
|
-
emitLifecycleEvent("auth:claim_completed", { newKey: maskKey(newApiKey), accountId });
|
|
24558
|
-
}
|
|
24559
|
-
maybeInstallConsoleCapture();
|
|
24560
|
-
if (didLastInitSucceed()) {
|
|
24561
|
-
startHeartbeat(config2, anonKeyForInit, "1.13.0", generation, (newApiKey, accountId) => {
|
|
24562
|
-
setAuthState(AuthState.CLAIMING);
|
|
24563
|
-
emitLifecycleEvent("auth:claim_started", { accountId });
|
|
24564
|
-
setResolvedApiKey(newApiKey);
|
|
24565
|
-
notifyApiKeyResolved();
|
|
24566
|
-
setAuthState(AuthState.CLAIMED);
|
|
24567
|
-
emitLifecycleEvent("auth:claim_completed", { newKey: maskKey(newApiKey), accountId });
|
|
24568
|
-
});
|
|
24569
|
-
}
|
|
24570
|
-
}
|
|
24571
|
-
function getDiscoveryHandler() {
|
|
24572
|
-
return discoveryHandler;
|
|
24573
|
-
}
|
|
24574
|
-
function maybeInstallConsoleCapture() {
|
|
24575
|
-
if (consoleCaptureInstalled) return;
|
|
24576
|
-
if (getActiveConfig().consoleErrors) {
|
|
24577
|
-
consoleCaptureInstalled = true;
|
|
24578
|
-
void installConsoleCapture();
|
|
24274
|
+
function attachField(span, key, value) {
|
|
24275
|
+
const attribute = resolveFieldAttribute(key);
|
|
24276
|
+
try {
|
|
24277
|
+
span.setAttribute(attribute, value);
|
|
24278
|
+
} catch {
|
|
24579
24279
|
}
|
|
24580
24280
|
}
|
|
24581
|
-
function
|
|
24582
|
-
|
|
24583
|
-
if (process.env.GLASSTRACE_DISCOVERY_ENABLED === "false") return false;
|
|
24584
|
-
if (config2.nodeEnv === "production") return false;
|
|
24585
|
-
if (config2.vercelEnv === "production") return false;
|
|
24586
|
-
if (config2.nodeEnv === "development" || config2.nodeEnv === void 0) return true;
|
|
24587
|
-
return false;
|
|
24281
|
+
function recordOmission(span, reason) {
|
|
24282
|
+
recordOmissionOnSpan(span, reason);
|
|
24588
24283
|
}
|
|
24589
24284
|
|
|
24590
|
-
// src/
|
|
24591
|
-
var
|
|
24592
|
-
function
|
|
24593
|
-
|
|
24594
|
-
|
|
24595
|
-
|
|
24596
|
-
|
|
24597
|
-
|
|
24598
|
-
|
|
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
|
+
);
|
|
24599
24318
|
}
|
|
24600
|
-
|
|
24601
|
-
|
|
24602
|
-
|
|
24603
|
-
|
|
24604
|
-
|
|
24605
|
-
|
|
24606
|
-
|
|
24607
|
-
|
|
24608
|
-
|
|
24609
|
-
}
|
|
24610
|
-
|
|
24611
|
-
|
|
24612
|
-
|
|
24613
|
-
|
|
24614
|
-
|
|
24615
|
-
} else {
|
|
24616
|
-
webpackConfig.externals = [existing, nodeBuiltinExternal];
|
|
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
|
+
);
|
|
24617
24334
|
}
|
|
24618
24335
|
}
|
|
24619
|
-
function
|
|
24620
|
-
|
|
24621
|
-
|
|
24622
|
-
|
|
24623
|
-
existingStable.filter((entry) => typeof entry === "string")
|
|
24624
|
-
) : [];
|
|
24625
|
-
if (!stable.includes(SDK_PACKAGE_NAME)) {
|
|
24626
|
-
stable.push(SDK_PACKAGE_NAME);
|
|
24336
|
+
function recordSideEffect(input) {
|
|
24337
|
+
try {
|
|
24338
|
+
runRecordSideEffect(input);
|
|
24339
|
+
} catch {
|
|
24627
24340
|
}
|
|
24628
|
-
config2.serverExternalPackages = stable;
|
|
24629
24341
|
}
|
|
24630
|
-
function
|
|
24631
|
-
if (
|
|
24632
|
-
|
|
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;
|
|
24633
24349
|
}
|
|
24634
|
-
|
|
24635
|
-
|
|
24636
|
-
const existingExperimental = bag.experimental ?? {};
|
|
24637
|
-
bag.experimental = {
|
|
24638
|
-
...existingExperimental,
|
|
24639
|
-
serverSourceMaps: true
|
|
24640
|
-
};
|
|
24641
|
-
ensureServerExternal(bag);
|
|
24642
|
-
if (bag.turbopack == null) {
|
|
24643
|
-
bag.turbopack = {};
|
|
24350
|
+
if (!captureEnabled) {
|
|
24351
|
+
return;
|
|
24644
24352
|
}
|
|
24645
|
-
|
|
24646
|
-
|
|
24353
|
+
const candidate = input;
|
|
24354
|
+
if (!checkOperationKind(candidate.kind)) {
|
|
24355
|
+
return;
|
|
24647
24356
|
}
|
|
24648
|
-
const
|
|
24649
|
-
|
|
24650
|
-
|
|
24651
|
-
|
|
24652
|
-
|
|
24653
|
-
|
|
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");
|
|
24654
24368
|
}
|
|
24655
|
-
|
|
24656
|
-
|
|
24657
|
-
|
|
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");
|
|
24658
24376
|
}
|
|
24659
|
-
|
|
24660
|
-
|
|
24661
|
-
|
|
24662
|
-
|
|
24663
|
-
|
|
24664
|
-
|
|
24665
|
-
|
|
24666
|
-
|
|
24667
|
-
|
|
24668
|
-
|
|
24669
|
-
|
|
24670
|
-
|
|
24671
|
-
|
|
24672
|
-
|
|
24673
|
-
|
|
24674
|
-
|
|
24377
|
+
}
|
|
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") {
|
|
24385
|
+
return;
|
|
24386
|
+
}
|
|
24387
|
+
if (outcome.kind === "over_budget") {
|
|
24388
|
+
recordOmission(outcome.span, "value_too_long");
|
|
24389
|
+
return;
|
|
24390
|
+
}
|
|
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);
|
|
24675
24409
|
}
|
|
24676
|
-
|
|
24677
|
-
};
|
|
24678
|
-
return config2;
|
|
24410
|
+
}
|
|
24679
24411
|
}
|
|
24680
|
-
|
|
24681
|
-
|
|
24682
|
-
|
|
24683
|
-
|
|
24684
|
-
|
|
24685
|
-
|
|
24686
|
-
);
|
|
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;
|
|
24423
|
+
}
|
|
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;
|
|
24435
|
+
}
|
|
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();
|
|
24444
|
+
}
|
|
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();
|
|
24467
|
+
}
|
|
24468
|
+
});
|
|
24469
|
+
onLifecycleEvent("auth:key_resolved", () => debouncedWrite());
|
|
24470
|
+
onLifecycleEvent("auth:claim_started", () => debouncedWrite());
|
|
24471
|
+
onLifecycleEvent("auth:claim_completed", () => debouncedWrite());
|
|
24472
|
+
writeStateNow();
|
|
24473
|
+
}
|
|
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
|
+
}
|
|
24687
24483
|
}
|
|
24688
|
-
|
|
24484
|
+
function writeStateNow() {
|
|
24485
|
+
if (!_projectRoot) return;
|
|
24689
24486
|
try {
|
|
24690
|
-
const
|
|
24691
|
-
const
|
|
24692
|
-
|
|
24693
|
-
|
|
24694
|
-
|
|
24695
|
-
|
|
24696
|
-
|
|
24697
|
-
|
|
24698
|
-
|
|
24699
|
-
|
|
24700
|
-
|
|
24701
|
-
console.info("[glasstrace] No source map files found. Skipping upload.");
|
|
24702
|
-
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;
|
|
24703
24498
|
}
|
|
24704
|
-
const
|
|
24705
|
-
|
|
24706
|
-
|
|
24707
|
-
|
|
24708
|
-
|
|
24709
|
-
|
|
24710
|
-
|
|
24711
|
-
|
|
24712
|
-
|
|
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)}`
|
|
24713
24509
|
);
|
|
24714
24510
|
}
|
|
24715
24511
|
}
|
|
24716
24512
|
|
|
24717
|
-
// src/
|
|
24718
|
-
|
|
24719
|
-
|
|
24720
|
-
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);
|
|
24721
24516
|
|
|
24722
|
-
// src/
|
|
24723
|
-
var
|
|
24724
|
-
var
|
|
24725
|
-
var
|
|
24726
|
-
|
|
24727
|
-
|
|
24728
|
-
|
|
24729
|
-
|
|
24730
|
-
|
|
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"
|
|
24731
24553
|
];
|
|
24732
|
-
function
|
|
24733
|
-
|
|
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
|
+
};
|
|
24734
24565
|
}
|
|
24735
|
-
function
|
|
24736
|
-
|
|
24737
|
-
|
|
24738
|
-
|
|
24739
|
-
|
|
24740
|
-
const
|
|
24741
|
-
const
|
|
24742
|
-
|
|
24743
|
-
|
|
24744
|
-
|
|
24745
|
-
|
|
24746
|
-
|
|
24747
|
-
|
|
24748
|
-
|
|
24749
|
-
|
|
24750
|
-
} else {
|
|
24751
|
-
|
|
24752
|
-
|
|
24753
|
-
|
|
24754
|
-
lineStr = bareMatch[2];
|
|
24755
|
-
}
|
|
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;
|
|
24756
24585
|
}
|
|
24757
|
-
if (!file2 || !lineStr) continue;
|
|
24758
|
-
if (isInternalFrame(file2)) continue;
|
|
24759
|
-
const lineNum = Number.parseInt(lineStr, 10);
|
|
24760
|
-
if (!Number.isFinite(lineNum) || lineNum <= 0) continue;
|
|
24761
|
-
return { file: file2, line: lineNum };
|
|
24762
24586
|
}
|
|
24763
|
-
return
|
|
24587
|
+
return ap.length - bp.length;
|
|
24764
24588
|
}
|
|
24765
|
-
|
|
24766
|
-
|
|
24767
|
-
|
|
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;
|
|
24768
24615
|
try {
|
|
24769
|
-
const
|
|
24770
|
-
if (!
|
|
24771
|
-
|
|
24772
|
-
|
|
24773
|
-
|
|
24774
|
-
|
|
24775
|
-
|
|
24776
|
-
|
|
24777
|
-
|
|
24778
|
-
|
|
24779
|
-
|
|
24780
|
-
|
|
24781
|
-
|
|
24782
|
-
|
|
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);
|
|
24783
24664
|
}
|
|
24784
24665
|
}
|
|
24785
|
-
|
|
24786
|
-
|
|
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
|
+
}
|
|
24787
24679
|
} catch {
|
|
24788
24680
|
}
|
|
24789
24681
|
}
|
|
24790
24682
|
|
|
24791
|
-
// src/
|
|
24792
|
-
|
|
24793
|
-
|
|
24794
|
-
|
|
24795
|
-
|
|
24796
|
-
var
|
|
24797
|
-
|
|
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) {
|
|
24798
24699
|
try {
|
|
24799
|
-
if (
|
|
24700
|
+
if (getCoreState() !== CoreState.IDLE) {
|
|
24800
24701
|
return;
|
|
24801
24702
|
}
|
|
24802
|
-
|
|
24803
|
-
if (
|
|
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
|
+
);
|
|
24804
24708
|
return;
|
|
24805
24709
|
}
|
|
24806
|
-
|
|
24807
|
-
|
|
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
|
+
);
|
|
24808
24729
|
return;
|
|
24809
24730
|
}
|
|
24810
|
-
|
|
24811
|
-
|
|
24812
|
-
}
|
|
24813
|
-
}
|
|
24814
|
-
function readHeader(headers) {
|
|
24815
|
-
const asFetch = headers;
|
|
24816
|
-
if (typeof asFetch.get === "function") {
|
|
24817
|
-
const raw = asFetch.get(HEADER_NAME);
|
|
24818
|
-
return firstToken(raw);
|
|
24819
|
-
}
|
|
24820
|
-
const dict = headers;
|
|
24821
|
-
const direct = dict[HEADER_NAME];
|
|
24822
|
-
if (direct !== void 0) {
|
|
24823
|
-
return firstValue(direct);
|
|
24824
|
-
}
|
|
24825
|
-
for (const key of Object.keys(dict)) {
|
|
24826
|
-
if (key.toLowerCase() === HEADER_NAME) {
|
|
24827
|
-
return firstValue(dict[key]);
|
|
24731
|
+
if (config2.verbose) {
|
|
24732
|
+
console.info("[glasstrace] Not production-disabled.");
|
|
24828
24733
|
}
|
|
24829
|
-
|
|
24830
|
-
|
|
24831
|
-
|
|
24832
|
-
|
|
24833
|
-
|
|
24834
|
-
for (const entry of value) {
|
|
24835
|
-
const token = firstToken(entry);
|
|
24836
|
-
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");
|
|
24837
24739
|
}
|
|
24838
|
-
|
|
24839
|
-
|
|
24840
|
-
|
|
24841
|
-
|
|
24842
|
-
|
|
24843
|
-
|
|
24844
|
-
|
|
24845
|
-
|
|
24846
|
-
|
|
24847
|
-
|
|
24848
|
-
|
|
24849
|
-
|
|
24850
|
-
|
|
24851
|
-
|
|
24852
|
-
|
|
24853
|
-
|
|
24854
|
-
|
|
24855
|
-
|
|
24856
|
-
|
|
24857
|
-
|
|
24858
|
-
|
|
24859
|
-
|
|
24860
|
-
|
|
24861
|
-
|
|
24862
|
-
|
|
24863
|
-
|
|
24864
|
-
|
|
24865
|
-
);
|
|
24866
|
-
|
|
24867
|
-
|
|
24868
|
-
|
|
24869
|
-
|
|
24870
|
-
|
|
24871
|
-
);
|
|
24872
|
-
|
|
24873
|
-
|
|
24874
|
-
|
|
24875
|
-
|
|
24876
|
-
|
|
24877
|
-
|
|
24878
|
-
|
|
24879
|
-
|
|
24880
|
-
|
|
24881
|
-
|
|
24882
|
-
|
|
24883
|
-
|
|
24884
|
-
|
|
24885
|
-
|
|
24886
|
-
|
|
24887
|
-
|
|
24888
|
-
|
|
24889
|
-
|
|
24890
|
-
|
|
24891
|
-
|
|
24892
|
-
|
|
24893
|
-
|
|
24894
|
-
|
|
24895
|
-
|
|
24896
|
-
|
|
24897
|
-
|
|
24898
|
-
|
|
24899
|
-
|
|
24900
|
-
|
|
24901
|
-
|
|
24902
|
-
|
|
24903
|
-
|
|
24904
|
-
|
|
24905
|
-
|
|
24906
|
-
|
|
24907
|
-
|
|
24908
|
-
|
|
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
|
+
);
|
|
24909
24879
|
}
|
|
24910
|
-
return TOKEN_REGEX.test(value);
|
|
24911
24880
|
}
|
|
24912
|
-
function
|
|
24913
|
-
if (
|
|
24914
|
-
|
|
24915
|
-
}
|
|
24916
|
-
if (value.length > MAX_SIDE_EFFECT_OPERATION_LABEL_LENGTH) {
|
|
24917
|
-
return { accepted: false, reason: "value_too_long" };
|
|
24918
|
-
}
|
|
24919
|
-
const unsafe = detectUnsafePattern(value);
|
|
24920
|
-
if (unsafe) {
|
|
24921
|
-
return { accepted: false, reason: unsafe };
|
|
24881
|
+
async function backgroundInit(config2, anonKeyForInit, generation) {
|
|
24882
|
+
if (config2.verbose) {
|
|
24883
|
+
console.info("[glasstrace] Background init firing.");
|
|
24922
24884
|
}
|
|
24923
|
-
|
|
24924
|
-
|
|
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;
|
|
24925
24891
|
}
|
|
24926
|
-
|
|
24927
|
-
|
|
24928
|
-
function checkSemanticFieldValue(key, value) {
|
|
24929
|
-
if (typeof value !== "string" || value.length === 0) {
|
|
24930
|
-
return { accepted: false, reason: "raw_payload" };
|
|
24892
|
+
if (currentState === CoreState.KEY_PENDING) {
|
|
24893
|
+
setCoreState(CoreState.KEY_RESOLVED);
|
|
24931
24894
|
}
|
|
24932
|
-
|
|
24933
|
-
|
|
24934
|
-
return { accepted: false, reason: "value_too_long" };
|
|
24895
|
+
if (getCoreState() === CoreState.KEY_RESOLVED) {
|
|
24896
|
+
setCoreState(didLastInitSucceed() ? CoreState.ACTIVE : CoreState.ACTIVE_DEGRADED);
|
|
24935
24897
|
}
|
|
24936
|
-
|
|
24937
|
-
|
|
24938
|
-
|
|
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 });
|
|
24939
24906
|
}
|
|
24940
|
-
|
|
24941
|
-
|
|
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
|
+
});
|
|
24942
24917
|
}
|
|
24943
|
-
return { accepted: true, value };
|
|
24944
|
-
}
|
|
24945
|
-
function checkSemanticFieldKey(key) {
|
|
24946
|
-
return typeof key === "string" && isSideEffectSemanticFieldKey(key);
|
|
24947
24918
|
}
|
|
24948
|
-
function
|
|
24949
|
-
return
|
|
24919
|
+
function getDiscoveryHandler() {
|
|
24920
|
+
return discoveryHandler;
|
|
24950
24921
|
}
|
|
24951
|
-
function
|
|
24952
|
-
|
|
24922
|
+
function maybeInstallConsoleCapture() {
|
|
24923
|
+
if (consoleCaptureInstalled) return;
|
|
24924
|
+
if (getActiveConfig().consoleErrors) {
|
|
24925
|
+
consoleCaptureInstalled = true;
|
|
24926
|
+
void installConsoleCapture();
|
|
24927
|
+
}
|
|
24953
24928
|
}
|
|
24954
|
-
function
|
|
24955
|
-
|
|
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;
|
|
24956
24936
|
}
|
|
24957
24937
|
|
|
24958
|
-
// src/
|
|
24959
|
-
|
|
24960
|
-
|
|
24961
|
-
|
|
24962
|
-
|
|
24963
|
-
|
|
24964
|
-
if (
|
|
24965
|
-
|
|
24966
|
-
|
|
24967
|
-
}
|
|
24968
|
-
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;
|
|
24969
24947
|
}
|
|
24970
|
-
|
|
24971
|
-
|
|
24972
|
-
|
|
24973
|
-
|
|
24974
|
-
|
|
24975
|
-
|
|
24976
|
-
|
|
24977
|
-
if (!span) return void 0;
|
|
24978
|
-
try {
|
|
24979
|
-
if (typeof span.isRecording === "function" && !span.isRecording()) {
|
|
24980
|
-
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;
|
|
24981
24955
|
}
|
|
24982
|
-
|
|
24983
|
-
|
|
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];
|
|
24984
24965
|
}
|
|
24985
|
-
return span;
|
|
24986
|
-
}
|
|
24987
|
-
function recordOmissionOnActiveSpan(reason) {
|
|
24988
|
-
const span = getRecordingActiveSpan();
|
|
24989
|
-
if (!span) return;
|
|
24990
|
-
recordOmissionOnSpan(span, reason);
|
|
24991
24966
|
}
|
|
24992
|
-
function
|
|
24993
|
-
const
|
|
24994
|
-
const
|
|
24995
|
-
|
|
24996
|
-
|
|
24997
|
-
|
|
24998
|
-
|
|
24999
|
-
|
|
25000
|
-
} catch {
|
|
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);
|
|
25001
24975
|
}
|
|
24976
|
+
config2.serverExternalPackages = stable;
|
|
25002
24977
|
}
|
|
25003
|
-
|
|
25004
|
-
|
|
25005
|
-
|
|
25006
|
-
|
|
25007
|
-
|
|
25008
|
-
|
|
25009
|
-
|
|
25010
|
-
|
|
25011
|
-
|
|
25012
|
-
|
|
25013
|
-
|
|
25014
|
-
|
|
25015
|
-
|
|
25016
|
-
|
|
25017
|
-
|
|
25018
|
-
|
|
25019
|
-
|
|
25020
|
-
|
|
25021
|
-
|
|
25022
|
-
|
|
25023
|
-
|
|
25024
|
-
|
|
25025
|
-
|
|
25026
|
-
|
|
25027
|
-
|
|
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();
|
|
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;
|
|
25028
25027
|
}
|
|
25029
|
-
|
|
25030
|
-
|
|
25031
|
-
if (
|
|
25032
|
-
|
|
25033
|
-
|
|
25034
|
-
|
|
25035
|
-
|
|
25036
|
-
|
|
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
|
+
);
|
|
25035
|
+
}
|
|
25036
|
+
async function handleSourceMapUpload(distDir) {
|
|
25037
25037
|
try {
|
|
25038
|
-
|
|
25039
|
-
|
|
25040
|
-
|
|
25041
|
-
|
|
25042
|
-
|
|
25043
|
-
if (input.status !== void 0) {
|
|
25044
|
-
span.setAttribute(
|
|
25045
|
-
GLASSTRACE_ATTRIBUTE_NAMES.SIDE_EFFECT_STATUS,
|
|
25046
|
-
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."
|
|
25047
25043
|
);
|
|
25044
|
+
return;
|
|
25048
25045
|
}
|
|
25049
|
-
|
|
25050
|
-
|
|
25051
|
-
|
|
25052
|
-
|
|
25053
|
-
|
|
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;
|
|
25054
25051
|
}
|
|
25055
|
-
|
|
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
|
+
);
|
|
25056
25062
|
}
|
|
25057
|
-
return { kind: "attached", span };
|
|
25058
25063
|
}
|
|
25059
|
-
|
|
25060
|
-
|
|
25061
|
-
|
|
25062
|
-
|
|
25063
|
-
|
|
25064
|
-
|
|
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));
|
|
25065
25082
|
}
|
|
25066
|
-
function
|
|
25067
|
-
|
|
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;
|
|
25068
25112
|
}
|
|
25069
25113
|
|
|
25070
|
-
// src/
|
|
25071
|
-
function
|
|
25114
|
+
// src/capture-error.ts
|
|
25115
|
+
function captureError(error51) {
|
|
25072
25116
|
try {
|
|
25073
|
-
|
|
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));
|
|
25074
25135
|
} catch {
|
|
25075
25136
|
}
|
|
25076
25137
|
}
|
|
25077
|
-
|
|
25078
|
-
|
|
25079
|
-
|
|
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) {
|
|
25080
25146
|
try {
|
|
25081
|
-
|
|
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);
|
|
25082
25159
|
} catch {
|
|
25083
|
-
captureEnabled = false;
|
|
25084
|
-
}
|
|
25085
|
-
if (!captureEnabled) {
|
|
25086
|
-
return;
|
|
25087
25160
|
}
|
|
25088
|
-
|
|
25089
|
-
|
|
25090
|
-
|
|
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);
|
|
25091
25167
|
}
|
|
25092
|
-
const
|
|
25093
|
-
|
|
25094
|
-
|
|
25095
|
-
return;
|
|
25168
|
+
const dict = headers;
|
|
25169
|
+
const direct = dict[HEADER_NAME];
|
|
25170
|
+
if (direct !== void 0) {
|
|
25171
|
+
return firstValue(direct);
|
|
25096
25172
|
}
|
|
25097
|
-
|
|
25098
|
-
|
|
25099
|
-
|
|
25100
|
-
acceptedStatus = candidate.status;
|
|
25101
|
-
} else {
|
|
25102
|
-
recordOmissionOnActiveSpan("unsupported_key");
|
|
25173
|
+
for (const key of Object.keys(dict)) {
|
|
25174
|
+
if (key.toLowerCase() === HEADER_NAME) {
|
|
25175
|
+
return firstValue(dict[key]);
|
|
25103
25176
|
}
|
|
25104
25177
|
}
|
|
25105
|
-
|
|
25106
|
-
|
|
25107
|
-
|
|
25108
|
-
|
|
25109
|
-
|
|
25110
|
-
|
|
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;
|
|
25111
25185
|
}
|
|
25186
|
+
return void 0;
|
|
25112
25187
|
}
|
|
25113
|
-
|
|
25114
|
-
|
|
25115
|
-
|
|
25116
|
-
|
|
25117
|
-
|
|
25118
|
-
|
|
25119
|
-
|
|
25120
|
-
|
|
25121
|
-
|
|
25122
|
-
|
|
25123
|
-
recordOmission(outcome.span, "value_too_long");
|
|
25124
|
-
return;
|
|
25125
|
-
}
|
|
25126
|
-
const fields = candidate.fields;
|
|
25127
|
-
if (fields && typeof fields === "object") {
|
|
25128
|
-
for (const [rawKey, rawValue] of Object.entries(fields)) {
|
|
25129
|
-
if (!checkSemanticFieldKey(rawKey)) {
|
|
25130
|
-
recordOmission(outcome.span, "unsupported_key");
|
|
25131
|
-
continue;
|
|
25132
|
-
}
|
|
25133
|
-
const valueOutcome = checkSemanticFieldValue(rawKey, rawValue);
|
|
25134
|
-
if (!valueOutcome.accepted) {
|
|
25135
|
-
recordOmission(outcome.span, valueOutcome.reason);
|
|
25136
|
-
continue;
|
|
25137
|
-
}
|
|
25138
|
-
attachField(outcome.span, rawKey, valueOutcome.value);
|
|
25139
|
-
}
|
|
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;
|
|
25140
25198
|
}
|
|
25199
|
+
return void 0;
|
|
25141
25200
|
}
|
|
25142
25201
|
|
|
25143
25202
|
// src/index.ts
|